From 3ee88b08b31639af2878db8286454e98681c0a99 Mon Sep 17 00:00:00 2001 From: py2cn Date: Fri, 3 Sep 2021 10:49:16 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=EF=BC=8C=E5=B0=86=E4=B8=BB?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E7=9B=B8=E5=85=B3=E6=96=87=E4=BB=B6=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E5=88=B0lib=E7=9B=AE=E5=BD=95=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyminer/__latest.json | 2 +- pyminer/app2.py | 17 +- .../algorithms/pyminer_util/communication.py | 28 +- pyminer/features/README.md | 60 - pyminer/features/auth/__init__.py | 0 pyminer/features/auth/authlocalserver.py | 18 - pyminer/features/auth/authmanager.py | 42 - pyminer/features/auth/templates/login.html | 127 - pyminer/features/auth/templates/register.html | 207 - pyminer/features/extensions/__init__.py | 0 .../extensions/extensionlib/__init__.py | 3 - .../extensions/extensionlib/baseext.py | 61 - .../extensions/extensionlib/extension_lib.py | 553 - .../extensions/extensionlib/extensionlib.md | 397 - .../extensions/extensionlib/readme.md | 31 - .../extensions_manager/ExtensionLoader.py | 199 - .../extensions/extensions_manager/README.md | 39 - .../extensions_manager/UIInserter.py | 154 - .../extensions/extensions_manager/__init__.py | 0 .../extensions/extensions_manager/log.py | 99 - .../extensions/extensions_manager/manager.py | 206 - .../extensions_manager/readme.drawio | 1 - .../extensions_manager/vermanager/__init__.py | 1 - .../vermanager/vermanager.py | 138 - pyminer/features/extensions/index.rst | 25 - pyminer/features/feedback.py | 48 - pyminer/features/index.rst | 167 - .../features/interpretermanager/__init__.py | 0 .../interpretermanager/interpretermanager.py | 204 - .../interpretermanager/packagemanager.py | 200 - pyminer/features/io/__init__.py | 0 pyminer/features/io/database.py | 155 - pyminer/features/io/dbConn.py | 131 - pyminer/features/io/dbConnectAccount.pkl | Bin 208 -> 0 bytes pyminer/features/io/encoding.py | 66 - pyminer/features/io/exceptions.py | 49 - pyminer/features/io/settings.py | 175 - pyminer/features/main_window/base.py | 731 -- pyminer/features/openprocess.py | 108 - pyminer/features/pluginsmanager/__init__.py | 0 .../features/pluginsmanager/pluginsmanager.py | 15 - .../project/template/Basic-Template.py | 14 - .../project/template/Empty-Template.py | 10 - .../project/template/Plot-Template.py | 36 - .../project/template/PyQt-Template.py | 16 - .../PySide2Template/PySide2_Template.py | 49 - .../PySide2Template/PySide2_Template.ui | 46 - .../template/PySide2Template/__init__.py | 0 .../project/template/PySide2Template/main.py | 26 - pyminer/features/project/template/__init__.py | 0 pyminer/features/settings.py | 35 - pyminer/features/ui/__init__.py | 0 pyminer/features/ui/common/__init__.py | 0 .../ui/common/debug_process_with_pyqt.py | 324 - .../ui/common/open_process_with_pyqt.py | 249 - pyminer/features/ui/common/openprocess.py | 109 - pyminer/features/ui/common/platformutil.py | 37 - pyminer/features/ui/common/pmlocale.py | 47 - pyminer/features/ui/common/test_open_app.py | 12 - pyminer/features/ui/main.py | 88 - .../features/ui/pm_marketplace/__init__.py | 0 pyminer/features/ui/pm_marketplace/install.py | 212 - pyminer/features/ui/pm_marketplace/install.ui | 307 - pyminer/features/ui/pm_marketplace/main.py | 137 - pyminer/features/ui/pm_marketplace/main.ui | 10157 ---------------- .../ui/pm_marketplace/package_manager_main.py | 110 - .../ui/pm_marketplace/package_manager_main.ui | 231 - .../features/ui/pm_marketplace/uninstall.py | 66 - .../features/ui/pm_marketplace/uninstall.ui | 79 - pyminer/features/ui/pmwidgets/__init__.py | 3 - pyminer/features/ui/pmwidgets/dockwidget.py | 21 - pyminer/features/ui/pmwidgets/pmmainwindow.py | 373 - pyminer/features/ui/pmwidgets/toplevel.py | 53 - pyminer/features/ui/ui_aboutme.py | 186 - pyminer/features/ui/ui_aboutme.ui | 310 - pyminer/features/ui/ui_appstore.py | 154 - pyminer/features/ui/ui_appstore.ui | 273 - pyminer/features/ui/ui_check_update.py | 85 - pyminer/features/ui/ui_check_update.ui | 96 - pyminer/features/ui/ui_data_normal.py | 101 - pyminer/features/ui/ui_data_normal.ui | 94 - pyminer/features/ui/ui_first_form.py | 444 - pyminer/features/ui/ui_first_form.ui | 788 -- pyminer/features/ui/ui_login.py | 204 - pyminer/features/ui/ui_login.ui | 376 - pyminer/features/ui/ui_logined.py | 112 - pyminer/features/ui/ui_logined.ui | 174 - pyminer/features/ui/ui_option.py | 441 - pyminer/features/ui/ui_option.ui | 585 - pyminer/features/ui/ui_preferences.py | 641 - pyminer/features/ui/ui_preferences.ui | 857 -- pyminer/features/ui/ui_project_wizard.py | 358 - pyminer/features/ui/ui_project_wizard.ui | 543 - pyminer/features/ui/ui_workspace_launcher.py | 121 - pyminer/features/ui/ui_workspace_launcher.ui | 139 - pyminer/features/ui/widgets/README.md | 3 - pyminer/features/ui/widgets/__init__.py | 2 - pyminer/features/ui/widgets/controlpanel.py | 164 - .../features/ui/widgets/notificationwidget.py | 224 - pyminer/features/ui/widgets/reportwidget.py | 37 - pyminer/features/ui/widgets/resources.py | 380 - pyminer/features/util/__init__.py | 0 pyminer/features/util/check_update_ui.py | 85 - pyminer/features/util/check_update_ui.ui | 96 - pyminer/features/util/make_update.py | 96 - pyminer/features/util/openprocess.py | 108 - pyminer/features/util/update.py | 364 - pyminer/features/workspace/__init__.py | 0 .../features/workspace/blinker/__init__.py | 22 - .../features/workspace/blinker/_saferef.py | 234 - .../features/workspace/blinker/_utilities.py | 163 - pyminer/features/workspace/blinker/base.py | 455 - pyminer/features/workspace/data/__init__.py | 0 .../workspace/data_adapter/__init__.py | 8 - .../features/workspace/data_adapter/array.py | 67 - .../features/workspace/data_adapter/base.py | 174 - .../workspace/data_adapter/data_frame.py | 41 - .../workspace/data_adapter/detector.py | 121 - .../features/workspace/data_adapter/index.rst | 20 - .../workspace/data_adapter/universal.py | 47 - pyminer/features/workspace/data_manager.py | 226 - pyminer/features/workspace/index.rst | 31 - pyminer/features/workspace/signals.py | 9 - pyminer/features/workspace/signals.rst | 66 - pyminer/features/workspace_old/__init__.py | 0 .../workspace_old/datamanager/__init__.py | 0 .../workspace_old/datamanager/converter.py | 73 - .../workspace_old/datamanager/datamanager.py | 77 - .../workspace_old/datamanager/dataset.py | 130 - .../workspace_old/datamanager/exceptions.py | 18 - .../workspace_old/datamanager/historyset.py | 59 - .../workspace_old/datamanager/metadataset.py | 81 - .../workspace_old/datamanager/recyclebin.py | 35 - .../workspace_old/datamanager/variable.py | 29 - .../workspace_old/datamanager/varset.py | 31 - pyminer/features/workspace_old/history.md | 151 - pyminer/features/workspace_old/index.rst | 17 - pyminer/languages/en/en.ts | 16 +- pyminer/languages/zh_CN/zh_CN.ts | 22 +- pyminer/languages/zh_TW/zh_TW.ts | 22 +- pyminer/lib/auth/authmanager.py | 2 +- pyminer/{ => lib}/check_dependency.py | 6 +- .../{pyminer_comm => lib/comm}/__init__.py | 4 +- .../comm}/base/__init__.py | 0 .../comm}/base/datadesc.py | 0 .../comm}/base/encode_decode.py | 0 .../comm}/base/network.py | 0 .../comm}/base/sys_utils.py | 2 +- .../comm/data_client/__init__.py} | 3 +- .../comm}/data_client/unittest_data_client.py | 2 +- .../comm}/pyminer_client/__init__.py | 0 .../comm}/pyminer_client/pm_client.py | 2 +- pyminer/{pyminer_comm => lib/comm}/readme.md | 0 .../{features => lib/comm/tests}/__init__.py | 0 .../comm}/tests/test_communication.py | 7 +- .../extensions/extensionlib/extension_lib.py | 2 +- .../localserver}/readme.md | 4 +- .../localserver}/server.py | 0 pyminer/lib/main_window/base.py | 2 +- .../workspace_old/datamanager/datamanager.py | 2 +- .../advanced_drawings_toolbar/main.py | 2 +- .../apps/cftool/GUI_QT.py | 2 +- .../apps/demo_app/main.py | 2 +- .../apps/flowchart/plugin_nodes/nodes.py | 6 +- .../applications_toolbar/source/app_main.py | 2 +- pyminer/packages/dataio/export.py | 2 +- pyminer/packages/dataio/sample.py | 2 +- .../packages/drawings_toolbar/fastui/base.py | 2 +- .../drawings_toolbar/fastui/draw_boxplot.py | 2 +- .../drawings_toolbar/fastui/draw_hist.py | 2 +- .../drawings_toolbar/fastui/functions.py | 2 +- .../packages/drawings_toolbar/fastui/plot.py | 2 +- pyminer/packages/drawings_toolbar/main.py | 2 +- .../packages/ipython_console/initialize.py | 4 +- .../ipython_data_show.py | 7 +- .../packages/jupyter_notebook_support/main.py | 7 +- .../scripts/pyminer_ipython_node.py | 13 +- pyminer/packages/pm_calc/fastui/base.py | 2 +- .../pm_calc/fastui/create_random_variable.py | 2 +- .../packages/pm_calc/fastui/create_tensor.py | 2 +- .../packages/pm_calc/fastui/create_vector.py | 2 +- .../packages/pm_calc/fastui/equation_solve.py | 2 +- .../packages/pm_calc/fastui/matrix_calc.py | 2 +- pyminer/packages/pm_calc/fastui/matrix_inv.py | 2 +- .../packages/pm_calc/fastui/matrix_numbers.py | 2 +- .../pm_calc/fastui/numerical_integration.py | 2 +- .../packages/pm_calc/fastui/reshape_tensor.py | 2 +- pyminer/packages/pm_preprocess/base.py | 2 +- pyminer/packages/pm_preprocess/datareplace.py | 2 +- pyminer/packages/pm_preprocess/fastui/base.py | 7 +- .../pm_preprocess/fastui/datamerge.py | 10 +- .../packages/pm_preprocess/fastui/fillna.py | 8 +- .../pm_preprocess/fastui/templates/dropna.py | 13 +- .../fastui/templates/template.py | 4 +- pyminer/packages/qt_vditor/main.py | 2 +- .../socket_server/server_by_socket.py | 2 +- .../workspace_inspector/data_viewer.py | 7 +- .../workspace_inspector/inspectortable.py | 9 +- pyminer/pmgwidgets/display/__init__.py | 10 - .../pmgwidgets/display/browser/__init__.py | 0 pyminer/pmgwidgets/display/browser/browser.py | 82 - pyminer/pmgwidgets/display/browser/get_ipy.py | 48 - pyminer/pmgwidgets/display/browser/handler.py | 109 - .../display/dynamicgraph/__init__.py | 0 .../display/dynamicgraph/base/__init__.py | 0 .../dynamicgraph/base/basetimeseries.py | 210 - .../display/dynamicgraph/mplplots/__init__.py | 0 .../display/dynamicgraph/pgexample.py | 6 - .../display/dynamicgraph/pgplots/__init__.py | 0 pyminer/pmgwidgets/display/examples.py | 4 - .../pmgwidgets/display/matplotlib/__init__.py | 0 .../pmgwidgets/display/matplotlib/pmagg.py | 36 - .../display/matplotlib/pyqtgraph/__init__.py | 0 .../matplotlib/pyqtgraph/pyqtgraphwidget.py | 69 - .../pmgwidgets/display/matplotlib/qt5agg.py | 50 - pyminer/pmgwidgets/display/vtk/__init__.py | 0 .../nested_lists_to_place_widgets.png | Bin 3438 -> 0 bytes .../pmgwidgets/doc_figures/pmflowarea_1.png | Bin 3961 -> 0 bytes .../pmgwidgets/doc_figures/pmflowarea_2.png | Bin 3959 -> 0 bytes .../pmgwidgets/doc_figures/settings_panel.png | Bin 6119 -> 0 bytes .../docs/doc_figures/pmflowarea_2.png | Bin 3959 -> 0 bytes .../pmgwidgets/docs/threading_and_tasking.md | 218 - pyminer/pmgwidgets/elements/__init__.py | 2 - pyminer/pmgwidgets/elements/dockobject.py | 62 - pyminer/pmgwidgets/elements/toolbar.py | 200 - pyminer/pmgwidgets/examples/__init__.py | 0 .../pmgwidgets/examples/utilities/__init__.py | 0 .../pmgwidgets/examples/utilities/examples.py | 21 - .../examples/utilities/long_conn.py | 5 - pyminer/pmgwidgets/flowchart/__init__.py | 3 - pyminer/pmgwidgets/flowchart/core/__init__.py | 2 - .../pmgwidgets/flowchart/core/flow_content.py | 391 - .../pmgwidgets/flowchart/core/flow_items.py | 685 -- .../pmgwidgets/flowchart/core/flow_node.py | 438 - .../flowchart/core/flowchart_scene.py | 368 - .../flowchart/core/flowchart_widget.py | 250 - .../pmgwidgets/flowchart/core/nodemanager.py | 283 - pyminer/pmgwidgets/flowchart/core/utils.py | 13 - .../flowchart/create_node_content_class.md | 86 - .../pmgwidgets/flowchart/dataprocesswidget.py | 209 - .../flowchart/doc_figures/before_run.png | Bin 23979 -> 0 bytes .../flowchart/doc_figures/check_json.png | Bin 19866 -> 0 bytes .../doc_figures/click_edit_button.png | Bin 4992 -> 0 bytes .../click_right_top_add_button.png | Bin 46479 -> 0 bytes .../doc_figures/composition_structure.png | Bin 6415 -> 0 bytes .../flowchart/doc_figures/configure_panel.png | Bin 11283 -> 0 bytes .../flowchart/doc_figures/create.png | Bin 4838 -> 0 bytes .../doc_figures/create_new_content_Mul.png | Bin 15782 -> 0 bytes .../flowchart/doc_figures/create_node.png | Bin 11546 -> 0 bytes .../flowchart/doc_figures/custom_node.png | Bin 6221 -> 0 bytes .../flowchart/doc_figures/edit_node.png | Bin 11421 -> 0 bytes .../doc_figures/edit_panel_meaning.png | Bin 19871 -> 0 bytes .../doc_figures/popup_edit_panel.png | Bin 8469 -> 0 bytes .../doc_figures/sketch_after_edit.png | Bin 15351 -> 0 bytes pyminer/pmgwidgets/flowchart/icons/down.png | Bin 584 -> 0 bytes pyminer/pmgwidgets/flowchart/icons/logo.png | Bin 1657 -> 0 bytes .../pmgwidgets/flowchart/nodes/__init__.py | 0 .../nodes/dataframeoperation/__init__.py | 2 - .../dataframeoperation/dropduplicated.py | 64 - .../dataframeoperation/randomrowsample.py | 68 - .../pmgwidgets/flowchart/nodes/dfoperation.py | 118 - .../pmgwidgets/flowchart/nodes/docparser.py | 35 - .../pmgwidgets/flowchart/nodes/io/__init__.py | 3 - .../pmgwidgets/flowchart/nodes/io/iterator.py | 68 - .../pmgwidgets/flowchart/nodes/io/listdir.py | 81 - .../pmgwidgets/flowchart/nodes/io/pdimport.py | 194 - pyminer/pmgwidgets/flowchart/nodes/plots.py | 100 - pyminer/pmgwidgets/flowchart/nodes/random.py | 74 - .../flowchart/nodes/reliabilities.py | 19 - .../pmgwidgets/flowchart/nodes/simplecalc.py | 78 - pyminer/pmgwidgets/flowchart/readme.md | 136 - pyminer/pmgwidgets/flowchart/readme_arch.md | 29 - .../pmgwidgets/flowchart/simulationwidget.py | 149 - .../pmgwidgets/flowchart/tests/__init__.py | 0 .../tests/continously_data_process.py | 40 - .../flowchart/tests/database_import.py | 16 - .../pmgwidgets/flowchart/tests/fault_tree.py | 46 - .../pmgwidgets/flowchart/tests/node_test.py | 22 - ...60\350\212\202\347\202\271(deprecated).md" | 54 - pyminer/pmgwidgets/utilities/__init__.py | 3 - .../pmgwidgets/utilities/network/__init__.py | 5 - .../utilities/network/baseclient.py | 289 - .../utilities/network/generalclient.py | 94 - .../pmgwidgets/utilities/network/qtclient.py | 125 - .../pmgwidgets/utilities/network/server.py | 215 - pyminer/pmgwidgets/utilities/network/util.py | 95 - .../pmgwidgets/utilities/platform/__init__.py | 11 - .../utilities/platform/commandutils.py | 167 - .../utilities/platform/filemanager.py | 26 - .../utilities/platform/filesyswatchdog.py | 57 - .../utilities/platform/fileutils.py | 134 - .../utilities/platform/openprocess.py | 51 - .../pmgwidgets/utilities/platform/pmdebug.py | 37 - .../utilities/platform/test/__init__.py | 0 .../platform/test/python_file_test.py | 10 - .../utilities/platform/translation.py | 12 - .../pmgwidgets/utilities/source/__init__.py | 3 - .../pmgwidgets/utilities/source/colorutils.py | 42 - .../utilities/source/graphicsitemutils.py | 93 - .../pmgwidgets/utilities/source/iconutils.py | 16 - .../utilities/source/translation.py | 22 - .../pmgwidgets/utilities/uilogics/__init__.py | 5 - .../utilities/uilogics/codechecking.py | 72 - .../pmgwidgets/utilities/uilogics/drags.py | 39 - .../utilities/uilogics/tasks/__init__.py | 4 - .../uilogics/tasks/loop_background.py | 168 - .../uilogics/tasks/minimal_thread.py | 127 - .../uilogics/tasks/one_shot_background.py | 103 - .../utilities/uilogics/tasks/threads.py | 108 - .../utilities/uilogics/uidisplay.py | 27 - .../utilities/uilogics/undomanager.py | 65 - .../utilities/uilogics/windowutils.py | 35 - pyminer/pmgwidgets/widgets/__init__.py | 6 - pyminer/pmgwidgets/widgets/basic/__init__.py | 10 - .../widgets/basic/browsers/__init__.py | 7 - .../widgets/basic/browsers/browser.py | 84 - .../basic/browsers/translations/qt_zh_CN.ts | 3 - .../widgets/basic/buttons/__init__.py | 2 - .../widgets/basic/buttons/button/__init__.py | 1 - .../basic/buttons/button/toolbutton.py | 69 - .../basic/buttons/buttonpane/__init__.py | 1 - .../buttons/buttonpane/pushbuttonpane.py | 78 - .../basic/buttons/translations/qt_zh_CN.ts | 3 - .../widgets/basic/containers/PMTab.py | 22 - .../widgets/basic/containers/__init__.py | 6 - .../widgets/basic/containers/flowarea.py | 93 - .../widgets/basic/containers/flowlayout.py | 113 - .../widgets/basic/containers/pmdockwidget.py | 21 - .../widgets/basic/containers/pmscrollarea.py | 13 - .../widgets/basic/containers/pmtoolbox.py | 31 - .../basic/containers/translations/qt_zh_CN.ts | 3 - .../widgets/basic/dialogs/__init__.py | 6 - .../widgets/basic/dialogs/textdialog.py | 22 - .../widgets/basic/images/__init__.py | 0 .../widgets/basic/images/imageview.py | 95 - .../widgets/basic/images/imageviewitem.py | 87 - .../widgets/basic/labels/__init__.py | 1 - .../widgets/basic/labels/scrolllabel.py | 34 - .../basic/labels/translations/qt_zh_CN.ts | 3 - .../widgets/basic/lists/__init__.py | 0 .../widgets/basic/lists/combobasic.py | 62 - .../basic/lists/translations/qt_zh_CN.ts | 3 - .../basic/others/ConsoleHistoryDialog.py | 97 - .../basic/others/ConsoleHistoryDialog.ui | 158 - .../basic/others/Ui_ConsoleHistoryDialog.py | 115 - .../widgets/basic/others/__init__.py | 16 - .../pmgwidgets/widgets/basic/others/gauge.py | 223 - .../basic/others/instantbootconsole.py | 287 - .../widgets/basic/others/processconsole.py | 319 - .../widgets/basic/others/source/clear.png | Bin 10255 -> 0 bytes .../widgets/basic/others/source/run.png | Bin 7956 -> 0 bytes .../widgets/basic/others/source/stop.png | Bin 5258 -> 0 bytes .../basic/others/translations/qt_zh_CN.ts | 69 - .../widgets/basic/plots/__init__.py | 4 - .../widgets/basic/plots/bars/__init__.py | 0 .../widgets/basic/plots/bars/histogram.py | 33 - .../widgets/basic/plots/lines/__init__.py | 6 - .../widgets/basic/plots/lines/timeseries.py | 193 - .../basic/plots/matplotlib/__init__.py | 7 - .../basic/plots/matplotlib/base/__init__.py | 1 - .../basic/plots/matplotlib/base/pmaggplot.py | 46 - .../basic/plots/matplotlib/base/qt5aggplot.py | 50 - .../widgets/basic/plots/pyqtgraph/__init__.py | 7 - .../basic/plots/pyqtgraph/base/__init__.py | 1 - .../basic/plots/pyqtgraph/base/pgplot.py | 83 - .../widgets/basic/plots/scatters/__init__.py | 0 .../widgets/basic/plots/scatters/scatters.py | 34 - .../basic/plots/translations/qt_zh_CN.ts | 3 - .../widgets/basic/quick/__init__.py | 0 .../pmgwidgets/widgets/basic/quick/demo1.py | 34 - .../widgets/basic/tables/__init__.py | 2 - .../widgets/basic/tables/help/help.md | 44 - .../widgets/basic/tables/tableviews.py | 680 -- .../widgets/basic/tables/tablewidgets.py | 106 - .../basic/tables/translations/qt_zh_CN.ts | 89 - .../widgets/basic/texts/__init__.py | 2 - .../basic/texts/statusreport/__init__.py | 1 - .../basic/texts/statusreport/errroreport.py | 31 - .../basic/texts/webeditors/__init__.py | 0 .../widgets/basic/texts/webeditors/editor.py | 412 - .../widgets/basic/trees/__init__.py | 3 - .../widgets/basic/trees/filetree.py | 564 - .../widgets/basic/trees/jsontree.py | 233 - .../basic/trees/translations/qt_zh_CN.ts | 257 - .../widgets/basic/trees/treecheck.py | 88 - .../widgets/basic/trees/varattrtree.py | 218 - .../pmgwidgets/widgets/composited/__init__.py | 5 - .../widgets/composited/buttonpanel.py | 18 - .../pmgwidgets/widgets/composited/fastui.py | 273 - .../widgets/composited/generalpanel.py | 458 - .../pmgwidgets/widgets/extended/__init__.py | 13 - .../widgets/extended/base/__init__.py | 1 - .../extended/base/baseextendedwidget.py | 95 - .../widgets/extended/checkbuttons/__init__.py | 1 - .../widgets/extended/checkbuttons/check.py | 30 - .../widgets/extended/comboboxes/__init__.py | 2 - .../widgets/extended/comboboxes/combo.py | 62 - .../extended/comboboxes/variables_combo.py | 28 - .../widgets/extended/entries/__init__.py | 8 - .../widgets/extended/entries/baseentryctrl.py | 14 - .../widgets/extended/entries/colorctrl.py | 91 - .../widgets/extended/entries/evalctrl.py | 64 - .../widgets/extended/entries/filectrl.py | 65 - .../widgets/extended/entries/folderctrl.py | 35 - .../widgets/extended/entries/funcctrl.py | 101 - .../extended/entries/keymappingctrl.py | 46 - .../widgets/extended/entries/linectrl.py | 33 - .../widgets/extended/entries/numctrl.py | 73 - .../widgets/extended/entries/passwordctrl.py | 34 - .../widgets/extended/labels/__init__.py | 1 - .../widgets/extended/labels/label.py | 23 - .../widgets/extended/lists/__init__.py | 1 - .../widgets/extended/lists/listwgt.py | 109 - .../widgets/extended/others/__init__.py | 1 - .../extended/others/monitors/__init__.py | 0 .../extended/others/multitypeparaminput.py | 103 - .../widgets/extended/plots/__init__.py | 5 - .../widgets/extended/plots/lines/__init__.py | 1 - .../extended/plots/lines/timeseries.py | 64 - .../widgets/extended/radiobuttons/__init__.py | 0 .../extended/radiobuttons/radiobuttonctrl.py | 63 - .../widgets/extended/spins/__init__.py | 2 - .../widgets/extended/spins/datetime.py | 114 - .../widgets/extended/spins/numberspin.py | 53 - .../widgets/extended/tables/__init__.py | 2 - .../widgets/extended/tables/rulesctrl.py | 124 - .../widgets/extended/tables/tableshow.py | 119 - .../widgets/extended/texts/__init__.py | 2 - .../widgets/extended/texts/htmlshow.py | 0 .../widgets/extended/texts/markdownshow.py | 0 .../widgets/extended/trees/__init__.py | 0 pyminer/pyminer.pro | 20 +- pyminer/pyminer_comm/data_client/__init__.py | 2 - pyminer/resources/README.md | 1 + .../{static => resources}/css/iview.min.css | 0 .../{static => resources}/js/echarts.min.js | 0 .../js/element-ui/CHANGELOG.en-US.md | 0 .../js/element-ui/CHANGELOG.es.md | 0 .../js/element-ui/CHANGELOG.fr-FR.md | 0 .../js/element-ui/CHANGELOG.zh-CN.md | 0 .../js/element-ui/README.md | 0 .../js/element-ui/lib/alert.js | 0 .../js/element-ui/lib/aside.js | 0 .../js/element-ui/lib/autocomplete.js | 0 .../js/element-ui/lib/avatar.js | 0 .../js/element-ui/lib/backtop.js | 0 .../js/element-ui/lib/badge.js | 0 .../js/element-ui/lib/breadcrumb-item.js | 0 .../js/element-ui/lib/breadcrumb.js | 0 .../js/element-ui/lib/button-group.js | 0 .../js/element-ui/lib/button.js | 0 .../js/element-ui/lib/calendar.js | 0 .../js/element-ui/lib/card.js | 0 .../js/element-ui/lib/carousel-item.js | 0 .../js/element-ui/lib/carousel.js | 0 .../js/element-ui/lib/cascader-panel.js | 0 .../js/element-ui/lib/cascader.js | 0 .../js/element-ui/lib/checkbox-button.js | 0 .../js/element-ui/lib/checkbox-group.js | 0 .../js/element-ui/lib/checkbox.js | 0 .../js/element-ui/lib/col.js | 0 .../js/element-ui/lib/collapse-item.js | 0 .../js/element-ui/lib/collapse.js | 0 .../js/element-ui/lib/color-picker.js | 0 .../js/element-ui/lib/container.js | 0 .../js/element-ui/lib/date-picker.js | 0 .../js/element-ui/lib/dialog.js | 0 .../element-ui/lib/directives/mousewheel.js | 0 .../element-ui/lib/directives/repeat-click.js | 0 .../js/element-ui/lib/divider.js | 0 .../js/element-ui/lib/drawer.js | 0 .../js/element-ui/lib/dropdown-item.js | 0 .../js/element-ui/lib/dropdown-menu.js | 0 .../js/element-ui/lib/dropdown.js | 0 .../js/element-ui/lib/element-ui.common.js | 0 .../js/element-ui/lib/footer.js | 0 .../js/element-ui/lib/form-item.js | 0 .../js/element-ui/lib/form.js | 0 .../js/element-ui/lib/header.js | 0 .../js/element-ui/lib/icon.js | 0 .../js/element-ui/lib/image.js | 0 .../js/element-ui/lib/index.js | 0 .../js/element-ui/lib/infinite-scroll.js | 0 .../js/element-ui/lib/input-number.js | 0 .../js/element-ui/lib/input.js | 0 .../js/element-ui/lib/link.js | 0 .../js/element-ui/lib/loading.js | 0 .../js/element-ui/lib/locale/format.js | 0 .../js/element-ui/lib/locale/index.js | 0 .../js/element-ui/lib/locale/lang/af-ZA.js | 0 .../js/element-ui/lib/locale/lang/ar.js | 0 .../js/element-ui/lib/locale/lang/bg.js | 0 .../js/element-ui/lib/locale/lang/ca.js | 0 .../js/element-ui/lib/locale/lang/cs-CZ.js | 0 .../js/element-ui/lib/locale/lang/da.js | 0 .../js/element-ui/lib/locale/lang/de.js | 0 .../js/element-ui/lib/locale/lang/ee.js | 0 .../js/element-ui/lib/locale/lang/el.js | 0 .../js/element-ui/lib/locale/lang/en.js | 0 .../js/element-ui/lib/locale/lang/eo.js | 0 .../js/element-ui/lib/locale/lang/es.js | 0 .../js/element-ui/lib/locale/lang/eu.js | 0 .../js/element-ui/lib/locale/lang/fa.js | 0 .../js/element-ui/lib/locale/lang/fi.js | 0 .../js/element-ui/lib/locale/lang/fr.js | 0 .../js/element-ui/lib/locale/lang/he.js | 0 .../js/element-ui/lib/locale/lang/hr.js | 0 .../js/element-ui/lib/locale/lang/hu.js | 0 .../js/element-ui/lib/locale/lang/hy-AM.js | 0 .../js/element-ui/lib/locale/lang/id.js | 0 .../js/element-ui/lib/locale/lang/it.js | 0 .../js/element-ui/lib/locale/lang/ja.js | 0 .../js/element-ui/lib/locale/lang/kg.js | 0 .../js/element-ui/lib/locale/lang/km.js | 0 .../js/element-ui/lib/locale/lang/ko.js | 0 .../js/element-ui/lib/locale/lang/ku.js | 0 .../js/element-ui/lib/locale/lang/kz.js | 0 .../js/element-ui/lib/locale/lang/lt.js | 0 .../js/element-ui/lib/locale/lang/lv.js | 0 .../js/element-ui/lib/locale/lang/mn.js | 0 .../js/element-ui/lib/locale/lang/nb-NO.js | 0 .../js/element-ui/lib/locale/lang/nl.js | 0 .../js/element-ui/lib/locale/lang/pl.js | 0 .../js/element-ui/lib/locale/lang/pt-br.js | 0 .../js/element-ui/lib/locale/lang/pt.js | 0 .../js/element-ui/lib/locale/lang/ro.js | 0 .../js/element-ui/lib/locale/lang/ru-RU.js | 0 .../js/element-ui/lib/locale/lang/sk.js | 0 .../js/element-ui/lib/locale/lang/sl.js | 0 .../js/element-ui/lib/locale/lang/sr.js | 0 .../js/element-ui/lib/locale/lang/sv-SE.js | 0 .../js/element-ui/lib/locale/lang/ta.js | 0 .../js/element-ui/lib/locale/lang/th.js | 0 .../js/element-ui/lib/locale/lang/tk.js | 0 .../js/element-ui/lib/locale/lang/tr-TR.js | 0 .../js/element-ui/lib/locale/lang/ua.js | 0 .../js/element-ui/lib/locale/lang/ug-CN.js | 0 .../js/element-ui/lib/locale/lang/uz-UZ.js | 0 .../js/element-ui/lib/locale/lang/vi.js | 0 .../js/element-ui/lib/locale/lang/zh-CN.js | 0 .../js/element-ui/lib/locale/lang/zh-TW.js | 0 .../js/element-ui/lib/main.js | 0 .../js/element-ui/lib/menu-item-group.js | 0 .../js/element-ui/lib/menu-item.js | 0 .../js/element-ui/lib/menu.js | 0 .../js/element-ui/lib/message-box.js | 0 .../js/element-ui/lib/message.js | 0 .../js/element-ui/lib/mixins/emitter.js | 0 .../js/element-ui/lib/mixins/focus.js | 0 .../js/element-ui/lib/mixins/locale.js | 0 .../js/element-ui/lib/mixins/migrating.js | 0 .../js/element-ui/lib/notification.js | 0 .../js/element-ui/lib/option-group.js | 0 .../js/element-ui/lib/option.js | 0 .../js/element-ui/lib/page-header.js | 0 .../js/element-ui/lib/pagination.js | 0 .../js/element-ui/lib/popconfirm.js | 0 .../js/element-ui/lib/popover.js | 0 .../js/element-ui/lib/progress.js | 0 .../js/element-ui/lib/radio-button.js | 0 .../js/element-ui/lib/radio-group.js | 0 .../js/element-ui/lib/radio.js | 0 .../js/element-ui/lib/rate.js | 0 .../js/element-ui/lib/row.js | 0 .../js/element-ui/lib/scrollbar.js | 0 .../js/element-ui/lib/select.js | 0 .../js/element-ui/lib/slider.js | 0 .../js/element-ui/lib/spinner.js | 0 .../js/element-ui/lib/step.js | 0 .../js/element-ui/lib/steps.js | 0 .../js/element-ui/lib/submenu.js | 0 .../js/element-ui/lib/switch.js | 0 .../js/element-ui/lib/tab-pane.js | 0 .../js/element-ui/lib/table-column.js | 0 .../js/element-ui/lib/table.js | 0 .../js/element-ui/lib/tabs.js | 0 .../js/element-ui/lib/tag.js | 0 .../js/element-ui/lib/theme-chalk/alert.css | 0 .../js/element-ui/lib/theme-chalk/aside.css | 0 .../lib/theme-chalk/autocomplete.css | 0 .../js/element-ui/lib/theme-chalk/avatar.css | 0 .../js/element-ui/lib/theme-chalk/backtop.css | 0 .../js/element-ui/lib/theme-chalk/badge.css | 0 .../js/element-ui/lib/theme-chalk/base.css | 0 .../lib/theme-chalk/breadcrumb-item.css | 0 .../element-ui/lib/theme-chalk/breadcrumb.css | 0 .../lib/theme-chalk/button-group.css | 0 .../js/element-ui/lib/theme-chalk/button.css | 0 .../element-ui/lib/theme-chalk/calendar.css | 0 .../js/element-ui/lib/theme-chalk/card.css | 0 .../lib/theme-chalk/carousel-item.css | 0 .../element-ui/lib/theme-chalk/carousel.css | 0 .../lib/theme-chalk/cascader-panel.css | 0 .../element-ui/lib/theme-chalk/cascader.css | 0 .../lib/theme-chalk/checkbox-button.css | 0 .../lib/theme-chalk/checkbox-group.css | 0 .../element-ui/lib/theme-chalk/checkbox.css | 0 .../js/element-ui/lib/theme-chalk/col.css | 0 .../lib/theme-chalk/collapse-item.css | 0 .../element-ui/lib/theme-chalk/collapse.css | 0 .../lib/theme-chalk/color-picker.css | 0 .../element-ui/lib/theme-chalk/container.css | 0 .../lib/theme-chalk/date-picker.css | 0 .../js/element-ui/lib/theme-chalk/dialog.css | 0 .../js/element-ui/lib/theme-chalk/display.css | 0 .../js/element-ui/lib/theme-chalk/divider.css | 0 .../js/element-ui/lib/theme-chalk/drawer.css | 0 .../lib/theme-chalk/dropdown-item.css | 0 .../lib/theme-chalk/dropdown-menu.css | 0 .../element-ui/lib/theme-chalk/dropdown.css | 0 .../lib/theme-chalk/fonts/element-icons.ttf | Bin .../lib/theme-chalk/fonts/element-icons.woff | Bin .../js/element-ui/lib/theme-chalk/footer.css | 0 .../element-ui/lib/theme-chalk/form-item.css | 0 .../js/element-ui/lib/theme-chalk/form.css | 0 .../js/element-ui/lib/theme-chalk/header.css | 0 .../js/element-ui/lib/theme-chalk/icon.css | 0 .../js/element-ui/lib/theme-chalk/image.css | 0 .../js/element-ui/lib/theme-chalk/index.css | 0 .../lib/theme-chalk/infinite-scroll.css | 0 .../lib/theme-chalk/infiniteScroll.css | 0 .../lib/theme-chalk/input-number.css | 0 .../js/element-ui/lib/theme-chalk/input.css | 0 .../js/element-ui/lib/theme-chalk/link.css | 0 .../js/element-ui/lib/theme-chalk/loading.css | 0 .../js/element-ui/lib/theme-chalk/main.css | 0 .../lib/theme-chalk/menu-item-group.css | 0 .../element-ui/lib/theme-chalk/menu-item.css | 0 .../js/element-ui/lib/theme-chalk/menu.css | 0 .../lib/theme-chalk/message-box.css | 0 .../js/element-ui/lib/theme-chalk/message.css | 0 .../lib/theme-chalk/notification.css | 0 .../lib/theme-chalk/option-group.css | 0 .../js/element-ui/lib/theme-chalk/option.css | 0 .../lib/theme-chalk/page-header.css | 0 .../element-ui/lib/theme-chalk/pagination.css | 0 .../element-ui/lib/theme-chalk/popconfirm.css | 0 .../js/element-ui/lib/theme-chalk/popover.css | 0 .../js/element-ui/lib/theme-chalk/popper.css | 0 .../element-ui/lib/theme-chalk/progress.css | 0 .../lib/theme-chalk/radio-button.css | 0 .../lib/theme-chalk/radio-group.css | 0 .../js/element-ui/lib/theme-chalk/radio.css | 0 .../js/element-ui/lib/theme-chalk/rate.css | 0 .../js/element-ui/lib/theme-chalk/reset.css | 0 .../js/element-ui/lib/theme-chalk/row.css | 0 .../element-ui/lib/theme-chalk/scrollbar.css | 0 .../lib/theme-chalk/select-dropdown.css | 0 .../js/element-ui/lib/theme-chalk/select.css | 0 .../js/element-ui/lib/theme-chalk/slider.css | 0 .../js/element-ui/lib/theme-chalk/spinner.css | 0 .../js/element-ui/lib/theme-chalk/step.css | 0 .../js/element-ui/lib/theme-chalk/steps.css | 0 .../js/element-ui/lib/theme-chalk/submenu.css | 0 .../js/element-ui/lib/theme-chalk/switch.css | 0 .../element-ui/lib/theme-chalk/tab-pane.css | 0 .../lib/theme-chalk/table-column.css | 0 .../js/element-ui/lib/theme-chalk/table.css | 0 .../js/element-ui/lib/theme-chalk/tabs.css | 0 .../js/element-ui/lib/theme-chalk/tag.css | 0 .../lib/theme-chalk/time-picker.css | 0 .../lib/theme-chalk/time-select.css | 0 .../lib/theme-chalk/timeline-item.css | 0 .../element-ui/lib/theme-chalk/timeline.css | 0 .../js/element-ui/lib/theme-chalk/tooltip.css | 0 .../element-ui/lib/theme-chalk/transfer.css | 0 .../js/element-ui/lib/theme-chalk/tree.css | 0 .../js/element-ui/lib/theme-chalk/upload.css | 0 .../js/element-ui/lib/time-picker.js | 0 .../js/element-ui/lib/time-select.js | 0 .../js/element-ui/lib/timeline-item.js | 0 .../js/element-ui/lib/timeline.js | 0 .../js/element-ui/lib/tooltip.js | 0 .../js/element-ui/lib/transfer.js | 0 .../lib/transitions/collapse-transition.js | 0 .../js/element-ui/lib/tree.js | 0 .../js/element-ui/lib/umd/locale/af-ZA.js | 0 .../js/element-ui/lib/umd/locale/ar.js | 0 .../js/element-ui/lib/umd/locale/bg.js | 0 .../js/element-ui/lib/umd/locale/ca.js | 0 .../js/element-ui/lib/umd/locale/cs-CZ.js | 0 .../js/element-ui/lib/umd/locale/da.js | 0 .../js/element-ui/lib/umd/locale/de.js | 0 .../js/element-ui/lib/umd/locale/ee.js | 0 .../js/element-ui/lib/umd/locale/el.js | 0 .../js/element-ui/lib/umd/locale/en.js | 0 .../js/element-ui/lib/umd/locale/eo.js | 0 .../js/element-ui/lib/umd/locale/es.js | 0 .../js/element-ui/lib/umd/locale/eu.js | 0 .../js/element-ui/lib/umd/locale/fa.js | 0 .../js/element-ui/lib/umd/locale/fi.js | 0 .../js/element-ui/lib/umd/locale/fr.js | 0 .../js/element-ui/lib/umd/locale/he.js | 0 .../js/element-ui/lib/umd/locale/hr.js | 0 .../js/element-ui/lib/umd/locale/hu.js | 0 .../js/element-ui/lib/umd/locale/hy-AM.js | 0 .../js/element-ui/lib/umd/locale/id.js | 0 .../js/element-ui/lib/umd/locale/it.js | 0 .../js/element-ui/lib/umd/locale/ja.js | 0 .../js/element-ui/lib/umd/locale/kg.js | 0 .../js/element-ui/lib/umd/locale/km.js | 0 .../js/element-ui/lib/umd/locale/ko.js | 0 .../js/element-ui/lib/umd/locale/ku.js | 0 .../js/element-ui/lib/umd/locale/kz.js | 0 .../js/element-ui/lib/umd/locale/lt.js | 0 .../js/element-ui/lib/umd/locale/lv.js | 0 .../js/element-ui/lib/umd/locale/mn.js | 0 .../js/element-ui/lib/umd/locale/nb-NO.js | 0 .../js/element-ui/lib/umd/locale/nl.js | 0 .../js/element-ui/lib/umd/locale/pl.js | 0 .../js/element-ui/lib/umd/locale/pt-br.js | 0 .../js/element-ui/lib/umd/locale/pt.js | 0 .../js/element-ui/lib/umd/locale/ro.js | 0 .../js/element-ui/lib/umd/locale/ru-RU.js | 0 .../js/element-ui/lib/umd/locale/sk.js | 0 .../js/element-ui/lib/umd/locale/sl.js | 0 .../js/element-ui/lib/umd/locale/sr.js | 0 .../js/element-ui/lib/umd/locale/sv-SE.js | 0 .../js/element-ui/lib/umd/locale/ta.js | 0 .../js/element-ui/lib/umd/locale/th.js | 0 .../js/element-ui/lib/umd/locale/tk.js | 0 .../js/element-ui/lib/umd/locale/tr-TR.js | 0 .../js/element-ui/lib/umd/locale/ua.js | 0 .../js/element-ui/lib/umd/locale/ug-CN.js | 0 .../js/element-ui/lib/umd/locale/uz-UZ.js | 0 .../js/element-ui/lib/umd/locale/vi.js | 0 .../js/element-ui/lib/umd/locale/zh-CN.js | 0 .../js/element-ui/lib/umd/locale/zh-TW.js | 0 .../js/element-ui/lib/upload.js | 0 .../js/element-ui/lib/utils/after-leave.js | 0 .../js/element-ui/lib/utils/aria-dialog.js | 0 .../js/element-ui/lib/utils/aria-utils.js | 0 .../js/element-ui/lib/utils/clickoutside.js | 0 .../js/element-ui/lib/utils/date-util.js | 0 .../js/element-ui/lib/utils/date.js | 0 .../js/element-ui/lib/utils/dom.js | 0 .../element-ui/lib/utils/menu/aria-menubar.js | 0 .../lib/utils/menu/aria-menuitem.js | 0 .../element-ui/lib/utils/menu/aria-submenu.js | 0 .../js/element-ui/lib/utils/merge.js | 0 .../js/element-ui/lib/utils/popper.js | 0 .../js/element-ui/lib/utils/popup/index.js | 0 .../lib/utils/popup/popup-manager.js | 0 .../js/element-ui/lib/utils/resize-event.js | 0 .../element-ui/lib/utils/scroll-into-view.js | 0 .../element-ui/lib/utils/scrollbar-width.js | 0 .../js/element-ui/lib/utils/shared.js | 0 .../js/element-ui/lib/utils/types.js | 0 .../js/element-ui/lib/utils/util.js | 0 .../js/element-ui/lib/utils/vdom.js | 0 .../js/element-ui/lib/utils/vue-popper.js | 0 .../js/element-ui/package.json | 0 .../js/form-create.min.js | 0 pyminer/{static => resources}/js/iview.min.js | 0 .../js/jquery-3.5.1.min.js | 0 pyminer/{static => resources}/js/vue.min.js | 0 .../{static => resources}/tutorials_page.html | 0 pyminer/static/README.md | 1 - pyminer/utils/debug/pmdebug.py | 2 +- pyminer/utils/ui/uiutil/workspaceutil.py | 6 +- pyminer/utils/ui/variableselect.py | 2 +- pyminer/widgets/utilities/platform/pmdebug.py | 2 +- pyminer/widgets/widgets/composited/fastui.py | 2 +- 763 files changed, 151 insertions(+), 43710 deletions(-) delete mode 100644 pyminer/features/README.md delete mode 100644 pyminer/features/auth/__init__.py delete mode 100644 pyminer/features/auth/authlocalserver.py delete mode 100644 pyminer/features/auth/authmanager.py delete mode 100644 pyminer/features/auth/templates/login.html delete mode 100644 pyminer/features/auth/templates/register.html delete mode 100644 pyminer/features/extensions/__init__.py delete mode 100644 pyminer/features/extensions/extensionlib/__init__.py delete mode 100644 pyminer/features/extensions/extensionlib/baseext.py delete mode 100644 pyminer/features/extensions/extensionlib/extension_lib.py delete mode 100644 pyminer/features/extensions/extensionlib/extensionlib.md delete mode 100644 pyminer/features/extensions/extensionlib/readme.md delete mode 100644 pyminer/features/extensions/extensions_manager/ExtensionLoader.py delete mode 100644 pyminer/features/extensions/extensions_manager/README.md delete mode 100644 pyminer/features/extensions/extensions_manager/UIInserter.py delete mode 100644 pyminer/features/extensions/extensions_manager/__init__.py delete mode 100644 pyminer/features/extensions/extensions_manager/log.py delete mode 100644 pyminer/features/extensions/extensions_manager/manager.py delete mode 100644 pyminer/features/extensions/extensions_manager/readme.drawio delete mode 100644 pyminer/features/extensions/extensions_manager/vermanager/__init__.py delete mode 100644 pyminer/features/extensions/extensions_manager/vermanager/vermanager.py delete mode 100644 pyminer/features/extensions/index.rst delete mode 100644 pyminer/features/feedback.py delete mode 100644 pyminer/features/index.rst delete mode 100644 pyminer/features/interpretermanager/__init__.py delete mode 100644 pyminer/features/interpretermanager/interpretermanager.py delete mode 100644 pyminer/features/interpretermanager/packagemanager.py delete mode 100644 pyminer/features/io/__init__.py delete mode 100644 pyminer/features/io/database.py delete mode 100644 pyminer/features/io/dbConn.py delete mode 100644 pyminer/features/io/dbConnectAccount.pkl delete mode 100644 pyminer/features/io/encoding.py delete mode 100644 pyminer/features/io/exceptions.py delete mode 100644 pyminer/features/io/settings.py delete mode 100644 pyminer/features/main_window/base.py delete mode 100644 pyminer/features/openprocess.py delete mode 100644 pyminer/features/pluginsmanager/__init__.py delete mode 100644 pyminer/features/pluginsmanager/pluginsmanager.py delete mode 100644 pyminer/features/project/template/Basic-Template.py delete mode 100644 pyminer/features/project/template/Empty-Template.py delete mode 100644 pyminer/features/project/template/Plot-Template.py delete mode 100644 pyminer/features/project/template/PyQt-Template.py delete mode 100644 pyminer/features/project/template/PySide2Template/PySide2_Template.py delete mode 100644 pyminer/features/project/template/PySide2Template/PySide2_Template.ui delete mode 100644 pyminer/features/project/template/PySide2Template/__init__.py delete mode 100644 pyminer/features/project/template/PySide2Template/main.py delete mode 100644 pyminer/features/project/template/__init__.py delete mode 100644 pyminer/features/settings.py delete mode 100644 pyminer/features/ui/__init__.py delete mode 100644 pyminer/features/ui/common/__init__.py delete mode 100644 pyminer/features/ui/common/debug_process_with_pyqt.py delete mode 100644 pyminer/features/ui/common/open_process_with_pyqt.py delete mode 100644 pyminer/features/ui/common/openprocess.py delete mode 100644 pyminer/features/ui/common/platformutil.py delete mode 100644 pyminer/features/ui/common/pmlocale.py delete mode 100644 pyminer/features/ui/common/test_open_app.py delete mode 100644 pyminer/features/ui/main.py delete mode 100644 pyminer/features/ui/pm_marketplace/__init__.py delete mode 100644 pyminer/features/ui/pm_marketplace/install.py delete mode 100644 pyminer/features/ui/pm_marketplace/install.ui delete mode 100644 pyminer/features/ui/pm_marketplace/main.py delete mode 100644 pyminer/features/ui/pm_marketplace/main.ui delete mode 100644 pyminer/features/ui/pm_marketplace/package_manager_main.py delete mode 100644 pyminer/features/ui/pm_marketplace/package_manager_main.ui delete mode 100644 pyminer/features/ui/pm_marketplace/uninstall.py delete mode 100644 pyminer/features/ui/pm_marketplace/uninstall.ui delete mode 100644 pyminer/features/ui/pmwidgets/__init__.py delete mode 100644 pyminer/features/ui/pmwidgets/dockwidget.py delete mode 100644 pyminer/features/ui/pmwidgets/pmmainwindow.py delete mode 100644 pyminer/features/ui/pmwidgets/toplevel.py delete mode 100644 pyminer/features/ui/ui_aboutme.py delete mode 100644 pyminer/features/ui/ui_aboutme.ui delete mode 100644 pyminer/features/ui/ui_appstore.py delete mode 100644 pyminer/features/ui/ui_appstore.ui delete mode 100644 pyminer/features/ui/ui_check_update.py delete mode 100644 pyminer/features/ui/ui_check_update.ui delete mode 100644 pyminer/features/ui/ui_data_normal.py delete mode 100644 pyminer/features/ui/ui_data_normal.ui delete mode 100644 pyminer/features/ui/ui_first_form.py delete mode 100644 pyminer/features/ui/ui_first_form.ui delete mode 100644 pyminer/features/ui/ui_login.py delete mode 100644 pyminer/features/ui/ui_login.ui delete mode 100644 pyminer/features/ui/ui_logined.py delete mode 100644 pyminer/features/ui/ui_logined.ui delete mode 100644 pyminer/features/ui/ui_option.py delete mode 100644 pyminer/features/ui/ui_option.ui delete mode 100644 pyminer/features/ui/ui_preferences.py delete mode 100644 pyminer/features/ui/ui_preferences.ui delete mode 100644 pyminer/features/ui/ui_project_wizard.py delete mode 100644 pyminer/features/ui/ui_project_wizard.ui delete mode 100644 pyminer/features/ui/ui_workspace_launcher.py delete mode 100644 pyminer/features/ui/ui_workspace_launcher.ui delete mode 100644 pyminer/features/ui/widgets/README.md delete mode 100644 pyminer/features/ui/widgets/__init__.py delete mode 100644 pyminer/features/ui/widgets/controlpanel.py delete mode 100644 pyminer/features/ui/widgets/notificationwidget.py delete mode 100644 pyminer/features/ui/widgets/reportwidget.py delete mode 100644 pyminer/features/ui/widgets/resources.py delete mode 100644 pyminer/features/util/__init__.py delete mode 100644 pyminer/features/util/check_update_ui.py delete mode 100644 pyminer/features/util/check_update_ui.ui delete mode 100644 pyminer/features/util/make_update.py delete mode 100644 pyminer/features/util/openprocess.py delete mode 100644 pyminer/features/util/update.py delete mode 100644 pyminer/features/workspace/__init__.py delete mode 100644 pyminer/features/workspace/blinker/__init__.py delete mode 100644 pyminer/features/workspace/blinker/_saferef.py delete mode 100644 pyminer/features/workspace/blinker/_utilities.py delete mode 100644 pyminer/features/workspace/blinker/base.py delete mode 100644 pyminer/features/workspace/data/__init__.py delete mode 100644 pyminer/features/workspace/data_adapter/__init__.py delete mode 100644 pyminer/features/workspace/data_adapter/array.py delete mode 100644 pyminer/features/workspace/data_adapter/base.py delete mode 100644 pyminer/features/workspace/data_adapter/data_frame.py delete mode 100644 pyminer/features/workspace/data_adapter/detector.py delete mode 100644 pyminer/features/workspace/data_adapter/index.rst delete mode 100644 pyminer/features/workspace/data_adapter/universal.py delete mode 100644 pyminer/features/workspace/data_manager.py delete mode 100644 pyminer/features/workspace/index.rst delete mode 100644 pyminer/features/workspace/signals.py delete mode 100644 pyminer/features/workspace/signals.rst delete mode 100644 pyminer/features/workspace_old/__init__.py delete mode 100644 pyminer/features/workspace_old/datamanager/__init__.py delete mode 100644 pyminer/features/workspace_old/datamanager/converter.py delete mode 100644 pyminer/features/workspace_old/datamanager/datamanager.py delete mode 100644 pyminer/features/workspace_old/datamanager/dataset.py delete mode 100644 pyminer/features/workspace_old/datamanager/exceptions.py delete mode 100644 pyminer/features/workspace_old/datamanager/historyset.py delete mode 100644 pyminer/features/workspace_old/datamanager/metadataset.py delete mode 100644 pyminer/features/workspace_old/datamanager/recyclebin.py delete mode 100644 pyminer/features/workspace_old/datamanager/variable.py delete mode 100644 pyminer/features/workspace_old/datamanager/varset.py delete mode 100644 pyminer/features/workspace_old/history.md delete mode 100644 pyminer/features/workspace_old/index.rst rename pyminer/{ => lib}/check_dependency.py (98%) rename pyminer/{pyminer_comm => lib/comm}/__init__.py (78%) rename pyminer/{pyminer_comm => lib/comm}/base/__init__.py (100%) rename pyminer/{pyminer_comm => lib/comm}/base/datadesc.py (100%) rename pyminer/{pyminer_comm => lib/comm}/base/encode_decode.py (100%) rename pyminer/{pyminer_comm => lib/comm}/base/network.py (100%) rename pyminer/{pyminer_comm => lib/comm}/base/sys_utils.py (98%) rename pyminer/{pyminer_comm/data_client/data_client.py => lib/comm/data_client/__init__.py} (98%) rename pyminer/{pyminer_comm => lib/comm}/data_client/unittest_data_client.py (87%) rename pyminer/{pyminer_comm => lib/comm}/pyminer_client/__init__.py (100%) rename pyminer/{pyminer_comm => lib/comm}/pyminer_client/pm_client.py (97%) rename pyminer/{pyminer_comm => lib/comm}/readme.md (100%) rename pyminer/{features => lib/comm/tests}/__init__.py (100%) rename pyminer/{pyminer_comm => lib/comm}/tests/test_communication.py (85%) rename pyminer/{pmlocalserver => lib/localserver}/readme.md (87%) rename pyminer/{pmlocalserver => lib/localserver}/server.py (100%) delete mode 100644 pyminer/pmgwidgets/display/__init__.py delete mode 100644 pyminer/pmgwidgets/display/browser/__init__.py delete mode 100644 pyminer/pmgwidgets/display/browser/browser.py delete mode 100644 pyminer/pmgwidgets/display/browser/get_ipy.py delete mode 100644 pyminer/pmgwidgets/display/browser/handler.py delete mode 100644 pyminer/pmgwidgets/display/dynamicgraph/__init__.py delete mode 100644 pyminer/pmgwidgets/display/dynamicgraph/base/__init__.py delete mode 100644 pyminer/pmgwidgets/display/dynamicgraph/base/basetimeseries.py delete mode 100644 pyminer/pmgwidgets/display/dynamicgraph/mplplots/__init__.py delete mode 100644 pyminer/pmgwidgets/display/dynamicgraph/pgexample.py delete mode 100644 pyminer/pmgwidgets/display/dynamicgraph/pgplots/__init__.py delete mode 100644 pyminer/pmgwidgets/display/examples.py delete mode 100644 pyminer/pmgwidgets/display/matplotlib/__init__.py delete mode 100644 pyminer/pmgwidgets/display/matplotlib/pmagg.py delete mode 100644 pyminer/pmgwidgets/display/matplotlib/pyqtgraph/__init__.py delete mode 100644 pyminer/pmgwidgets/display/matplotlib/pyqtgraph/pyqtgraphwidget.py delete mode 100644 pyminer/pmgwidgets/display/matplotlib/qt5agg.py delete mode 100644 pyminer/pmgwidgets/display/vtk/__init__.py delete mode 100644 pyminer/pmgwidgets/doc_figures/nested_lists_to_place_widgets.png delete mode 100644 pyminer/pmgwidgets/doc_figures/pmflowarea_1.png delete mode 100644 pyminer/pmgwidgets/doc_figures/pmflowarea_2.png delete mode 100644 pyminer/pmgwidgets/doc_figures/settings_panel.png delete mode 100644 pyminer/pmgwidgets/docs/doc_figures/pmflowarea_2.png delete mode 100644 pyminer/pmgwidgets/docs/threading_and_tasking.md delete mode 100644 pyminer/pmgwidgets/elements/__init__.py delete mode 100644 pyminer/pmgwidgets/elements/dockobject.py delete mode 100644 pyminer/pmgwidgets/elements/toolbar.py delete mode 100644 pyminer/pmgwidgets/examples/__init__.py delete mode 100644 pyminer/pmgwidgets/examples/utilities/__init__.py delete mode 100644 pyminer/pmgwidgets/examples/utilities/examples.py delete mode 100644 pyminer/pmgwidgets/examples/utilities/long_conn.py delete mode 100644 pyminer/pmgwidgets/flowchart/__init__.py delete mode 100644 pyminer/pmgwidgets/flowchart/core/__init__.py delete mode 100644 pyminer/pmgwidgets/flowchart/core/flow_content.py delete mode 100644 pyminer/pmgwidgets/flowchart/core/flow_items.py delete mode 100644 pyminer/pmgwidgets/flowchart/core/flow_node.py delete mode 100644 pyminer/pmgwidgets/flowchart/core/flowchart_scene.py delete mode 100644 pyminer/pmgwidgets/flowchart/core/flowchart_widget.py delete mode 100644 pyminer/pmgwidgets/flowchart/core/nodemanager.py delete mode 100644 pyminer/pmgwidgets/flowchart/core/utils.py delete mode 100644 pyminer/pmgwidgets/flowchart/create_node_content_class.md delete mode 100644 pyminer/pmgwidgets/flowchart/dataprocesswidget.py delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/before_run.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/check_json.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/click_edit_button.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/click_right_top_add_button.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/composition_structure.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/configure_panel.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/create.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/create_new_content_Mul.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/create_node.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/custom_node.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/edit_node.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/edit_panel_meaning.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/popup_edit_panel.png delete mode 100644 pyminer/pmgwidgets/flowchart/doc_figures/sketch_after_edit.png delete mode 100644 pyminer/pmgwidgets/flowchart/icons/down.png delete mode 100644 pyminer/pmgwidgets/flowchart/icons/logo.png delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/__init__.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/dataframeoperation/__init__.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/dataframeoperation/dropduplicated.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/dataframeoperation/randomrowsample.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/dfoperation.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/docparser.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/io/__init__.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/io/iterator.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/io/listdir.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/io/pdimport.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/plots.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/random.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/reliabilities.py delete mode 100644 pyminer/pmgwidgets/flowchart/nodes/simplecalc.py delete mode 100644 pyminer/pmgwidgets/flowchart/readme.md delete mode 100644 pyminer/pmgwidgets/flowchart/readme_arch.md delete mode 100644 pyminer/pmgwidgets/flowchart/simulationwidget.py delete mode 100644 pyminer/pmgwidgets/flowchart/tests/__init__.py delete mode 100644 pyminer/pmgwidgets/flowchart/tests/continously_data_process.py delete mode 100644 pyminer/pmgwidgets/flowchart/tests/database_import.py delete mode 100644 pyminer/pmgwidgets/flowchart/tests/fault_tree.py delete mode 100644 pyminer/pmgwidgets/flowchart/tests/node_test.py delete mode 100644 "pyminer/pmgwidgets/flowchart/\345\210\233\345\273\272\346\226\260\350\212\202\347\202\271(deprecated).md" delete mode 100644 pyminer/pmgwidgets/utilities/__init__.py delete mode 100644 pyminer/pmgwidgets/utilities/network/__init__.py delete mode 100644 pyminer/pmgwidgets/utilities/network/baseclient.py delete mode 100644 pyminer/pmgwidgets/utilities/network/generalclient.py delete mode 100644 pyminer/pmgwidgets/utilities/network/qtclient.py delete mode 100644 pyminer/pmgwidgets/utilities/network/server.py delete mode 100644 pyminer/pmgwidgets/utilities/network/util.py delete mode 100644 pyminer/pmgwidgets/utilities/platform/__init__.py delete mode 100644 pyminer/pmgwidgets/utilities/platform/commandutils.py delete mode 100644 pyminer/pmgwidgets/utilities/platform/filemanager.py delete mode 100644 pyminer/pmgwidgets/utilities/platform/filesyswatchdog.py delete mode 100644 pyminer/pmgwidgets/utilities/platform/fileutils.py delete mode 100644 pyminer/pmgwidgets/utilities/platform/openprocess.py delete mode 100644 pyminer/pmgwidgets/utilities/platform/pmdebug.py delete mode 100644 pyminer/pmgwidgets/utilities/platform/test/__init__.py delete mode 100644 pyminer/pmgwidgets/utilities/platform/test/python_file_test.py delete mode 100644 pyminer/pmgwidgets/utilities/platform/translation.py delete mode 100644 pyminer/pmgwidgets/utilities/source/__init__.py delete mode 100644 pyminer/pmgwidgets/utilities/source/colorutils.py delete mode 100644 pyminer/pmgwidgets/utilities/source/graphicsitemutils.py delete mode 100644 pyminer/pmgwidgets/utilities/source/iconutils.py delete mode 100644 pyminer/pmgwidgets/utilities/source/translation.py delete mode 100644 pyminer/pmgwidgets/utilities/uilogics/__init__.py delete mode 100644 pyminer/pmgwidgets/utilities/uilogics/codechecking.py delete mode 100644 pyminer/pmgwidgets/utilities/uilogics/drags.py delete mode 100644 pyminer/pmgwidgets/utilities/uilogics/tasks/__init__.py delete mode 100644 pyminer/pmgwidgets/utilities/uilogics/tasks/loop_background.py delete mode 100644 pyminer/pmgwidgets/utilities/uilogics/tasks/minimal_thread.py delete mode 100644 pyminer/pmgwidgets/utilities/uilogics/tasks/one_shot_background.py delete mode 100644 pyminer/pmgwidgets/utilities/uilogics/tasks/threads.py delete mode 100644 pyminer/pmgwidgets/utilities/uilogics/uidisplay.py delete mode 100644 pyminer/pmgwidgets/utilities/uilogics/undomanager.py delete mode 100644 pyminer/pmgwidgets/utilities/uilogics/windowutils.py delete mode 100644 pyminer/pmgwidgets/widgets/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/browsers/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/browsers/browser.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/browsers/translations/qt_zh_CN.ts delete mode 100644 pyminer/pmgwidgets/widgets/basic/buttons/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/buttons/button/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/buttons/button/toolbutton.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/buttons/buttonpane/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/buttons/buttonpane/pushbuttonpane.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/buttons/translations/qt_zh_CN.ts delete mode 100644 pyminer/pmgwidgets/widgets/basic/containers/PMTab.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/containers/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/containers/flowarea.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/containers/flowlayout.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/containers/pmdockwidget.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/containers/pmscrollarea.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/containers/pmtoolbox.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/containers/translations/qt_zh_CN.ts delete mode 100644 pyminer/pmgwidgets/widgets/basic/dialogs/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/dialogs/textdialog.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/images/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/images/imageview.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/images/imageviewitem.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/labels/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/labels/scrolllabel.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/labels/translations/qt_zh_CN.ts delete mode 100644 pyminer/pmgwidgets/widgets/basic/lists/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/lists/combobasic.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/lists/translations/qt_zh_CN.ts delete mode 100644 pyminer/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui delete mode 100644 pyminer/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/others/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/others/gauge.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/others/instantbootconsole.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/others/processconsole.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/others/source/clear.png delete mode 100644 pyminer/pmgwidgets/widgets/basic/others/source/run.png delete mode 100644 pyminer/pmgwidgets/widgets/basic/others/source/stop.png delete mode 100644 pyminer/pmgwidgets/widgets/basic/others/translations/qt_zh_CN.ts delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/bars/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/bars/histogram.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/lines/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/lines/timeseries.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/matplotlib/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/matplotlib/base/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/matplotlib/base/pmaggplot.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/matplotlib/base/qt5aggplot.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/pyqtgraph/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/pyqtgraph/base/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/pyqtgraph/base/pgplot.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/scatters/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/scatters/scatters.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/plots/translations/qt_zh_CN.ts delete mode 100644 pyminer/pmgwidgets/widgets/basic/quick/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/quick/demo1.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/tables/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/tables/help/help.md delete mode 100644 pyminer/pmgwidgets/widgets/basic/tables/tableviews.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/tables/tablewidgets.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/tables/translations/qt_zh_CN.ts delete mode 100644 pyminer/pmgwidgets/widgets/basic/texts/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/texts/statusreport/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/texts/statusreport/errroreport.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/texts/webeditors/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/texts/webeditors/editor.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/trees/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/trees/filetree.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/trees/jsontree.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/trees/translations/qt_zh_CN.ts delete mode 100644 pyminer/pmgwidgets/widgets/basic/trees/treecheck.py delete mode 100644 pyminer/pmgwidgets/widgets/basic/trees/varattrtree.py delete mode 100644 pyminer/pmgwidgets/widgets/composited/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/composited/buttonpanel.py delete mode 100644 pyminer/pmgwidgets/widgets/composited/fastui.py delete mode 100644 pyminer/pmgwidgets/widgets/composited/generalpanel.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/base/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/base/baseextendedwidget.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/checkbuttons/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/checkbuttons/check.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/comboboxes/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/comboboxes/combo.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/comboboxes/variables_combo.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/entries/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/entries/baseentryctrl.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/entries/colorctrl.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/entries/evalctrl.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/entries/filectrl.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/entries/folderctrl.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/entries/funcctrl.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/entries/keymappingctrl.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/entries/linectrl.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/entries/numctrl.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/entries/passwordctrl.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/labels/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/labels/label.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/lists/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/lists/listwgt.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/others/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/others/monitors/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/others/multitypeparaminput.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/plots/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/plots/lines/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/plots/lines/timeseries.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/radiobuttons/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/radiobuttons/radiobuttonctrl.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/spins/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/spins/datetime.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/spins/numberspin.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/tables/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/tables/rulesctrl.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/tables/tableshow.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/texts/__init__.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/texts/htmlshow.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/texts/markdownshow.py delete mode 100644 pyminer/pmgwidgets/widgets/extended/trees/__init__.py delete mode 100644 pyminer/pyminer_comm/data_client/__init__.py create mode 100644 pyminer/resources/README.md rename pyminer/{static => resources}/css/iview.min.css (100%) rename pyminer/{static => resources}/js/echarts.min.js (100%) rename pyminer/{static => resources}/js/element-ui/CHANGELOG.en-US.md (100%) rename pyminer/{static => resources}/js/element-ui/CHANGELOG.es.md (100%) rename pyminer/{static => resources}/js/element-ui/CHANGELOG.fr-FR.md (100%) rename pyminer/{static => resources}/js/element-ui/CHANGELOG.zh-CN.md (100%) rename pyminer/{static => resources}/js/element-ui/README.md (100%) rename pyminer/{static => resources}/js/element-ui/lib/alert.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/aside.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/autocomplete.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/avatar.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/backtop.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/badge.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/breadcrumb-item.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/breadcrumb.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/button-group.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/button.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/calendar.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/card.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/carousel-item.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/carousel.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/cascader-panel.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/cascader.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/checkbox-button.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/checkbox-group.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/checkbox.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/col.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/collapse-item.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/collapse.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/color-picker.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/container.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/date-picker.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/dialog.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/directives/mousewheel.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/directives/repeat-click.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/divider.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/drawer.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/dropdown-item.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/dropdown-menu.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/dropdown.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/element-ui.common.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/footer.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/form-item.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/form.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/header.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/icon.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/image.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/index.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/infinite-scroll.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/input-number.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/input.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/link.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/loading.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/format.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/index.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/af-ZA.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/ar.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/bg.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/ca.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/cs-CZ.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/da.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/de.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/ee.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/el.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/en.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/eo.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/es.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/eu.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/fa.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/fi.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/fr.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/he.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/hr.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/hu.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/hy-AM.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/id.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/it.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/ja.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/kg.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/km.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/ko.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/ku.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/kz.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/lt.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/lv.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/mn.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/nb-NO.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/nl.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/pl.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/pt-br.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/pt.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/ro.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/ru-RU.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/sk.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/sl.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/sr.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/sv-SE.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/ta.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/th.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/tk.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/tr-TR.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/ua.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/ug-CN.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/uz-UZ.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/vi.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/zh-CN.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/locale/lang/zh-TW.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/main.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/menu-item-group.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/menu-item.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/menu.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/message-box.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/message.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/mixins/emitter.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/mixins/focus.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/mixins/locale.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/mixins/migrating.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/notification.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/option-group.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/option.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/page-header.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/pagination.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/popconfirm.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/popover.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/progress.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/radio-button.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/radio-group.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/radio.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/rate.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/row.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/scrollbar.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/select.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/slider.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/spinner.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/step.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/steps.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/submenu.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/switch.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/tab-pane.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/table-column.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/table.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/tabs.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/tag.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/alert.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/aside.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/autocomplete.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/avatar.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/backtop.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/badge.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/base.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/breadcrumb-item.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/breadcrumb.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/button-group.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/button.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/calendar.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/card.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/carousel-item.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/carousel.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/cascader-panel.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/cascader.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/checkbox-button.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/checkbox-group.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/checkbox.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/col.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/collapse-item.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/collapse.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/color-picker.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/container.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/date-picker.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/dialog.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/display.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/divider.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/drawer.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/dropdown-item.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/dropdown-menu.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/dropdown.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/fonts/element-icons.ttf (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/fonts/element-icons.woff (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/footer.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/form-item.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/form.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/header.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/icon.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/image.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/index.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/infinite-scroll.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/infiniteScroll.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/input-number.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/input.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/link.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/loading.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/main.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/menu-item-group.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/menu-item.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/menu.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/message-box.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/message.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/notification.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/option-group.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/option.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/page-header.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/pagination.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/popconfirm.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/popover.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/popper.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/progress.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/radio-button.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/radio-group.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/radio.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/rate.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/reset.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/row.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/scrollbar.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/select-dropdown.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/select.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/slider.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/spinner.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/step.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/steps.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/submenu.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/switch.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/tab-pane.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/table-column.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/table.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/tabs.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/tag.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/time-picker.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/time-select.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/timeline-item.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/timeline.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/tooltip.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/transfer.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/tree.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/theme-chalk/upload.css (100%) rename pyminer/{static => resources}/js/element-ui/lib/time-picker.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/time-select.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/timeline-item.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/timeline.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/tooltip.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/transfer.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/transitions/collapse-transition.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/tree.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/af-ZA.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/ar.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/bg.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/ca.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/cs-CZ.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/da.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/de.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/ee.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/el.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/en.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/eo.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/es.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/eu.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/fa.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/fi.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/fr.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/he.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/hr.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/hu.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/hy-AM.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/id.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/it.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/ja.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/kg.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/km.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/ko.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/ku.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/kz.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/lt.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/lv.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/mn.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/nb-NO.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/nl.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/pl.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/pt-br.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/pt.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/ro.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/ru-RU.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/sk.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/sl.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/sr.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/sv-SE.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/ta.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/th.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/tk.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/tr-TR.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/ua.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/ug-CN.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/uz-UZ.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/vi.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/zh-CN.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/umd/locale/zh-TW.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/upload.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/after-leave.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/aria-dialog.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/aria-utils.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/clickoutside.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/date-util.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/date.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/dom.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/menu/aria-menubar.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/menu/aria-menuitem.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/menu/aria-submenu.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/merge.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/popper.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/popup/index.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/popup/popup-manager.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/resize-event.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/scroll-into-view.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/scrollbar-width.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/shared.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/types.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/util.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/vdom.js (100%) rename pyminer/{static => resources}/js/element-ui/lib/utils/vue-popper.js (100%) rename pyminer/{static => resources}/js/element-ui/package.json (100%) rename pyminer/{static => resources}/js/form-create.min.js (100%) rename pyminer/{static => resources}/js/iview.min.js (100%) rename pyminer/{static => resources}/js/jquery-3.5.1.min.js (100%) rename pyminer/{static => resources}/js/vue.min.js (100%) rename pyminer/{static => resources}/tutorials_page.html (100%) delete mode 100644 pyminer/static/README.md diff --git a/pyminer/__latest.json b/pyminer/__latest.json index 5d56a4f8..2bc9f582 100644 --- a/pyminer/__latest.json +++ b/pyminer/__latest.json @@ -1 +1 @@ -{"files": {"app2.py": "c7e061a1c028e828cb2bd76c46a7a858", "check_dependency.py": "35b3112cf9cb50d31be5f45c8ae3d179", "config.ini": "7f83e4b78df1a293343baeaaf5881203", "dist.py": "e3b17ce9bea81da8f9b4582ee78fe6cd", "LICENSE": "b5b6bed06dd8ed68f00c26d0b4cede89", "load_modules.py": "6bfcd0281e7ab654b27851cc25c2a31f", "pmgui.py": "54472e38004442ee8209f732e013e09a", "pyminer.pro": "148c684e721b44a4a29ec4c700e95c49", "pyminer.py": "8676961ecd2c4d293db44b2e8e962315", "pytest.ini": "7e1ac696b90974c21fcaed50d881ebf1", "README.md": "618338896f514c4f446bd0142edce65a", "requirements.txt": "bdc7ed15fe5b96b65882b02a3ce91877", "requirements_dev.txt": "6e23539b6bc3cd698e6f9713e598e2a9", "requirements_linux.txt": "32193efcf05f692095c24da7263ea8de", "requirements_mac.txt": "a1fdae24ed40656c9879626a8130c59c", "run_before_commit.py": "067f08926721cb4679e63604fa3528c4", "update_translation.py": "afcbf3f7c930b65e44c1bed2430d4284", "\u5f00\u53d1\u6307\u5357.md": "791025c5ef81f9b6a334e4f6d39e9cb6", "\u5f00\u53d1\u8fdb\u5ea6.url": "e47baa8f175a5766ae709b9e8d951b53", "configuration/config.ini": "56859fc0e799ae26d49fd7a41cfe0532", "configuration/default_settings.json": "7bdc7e60ac0fe14d849afb297fb9db2f", "configuration/extensions.json": "cb8f6f2bf8cdccae988f3cb589282f7c", "configuration/settings.json": "81f0b5a2f4f719f23e247b92ee72fff7", "core/__init__.py": "f0d32e8fca7a2398789eb9b0537057ce", "core/algorithms/index.rst": "493e85a5e6744431a7755a7d33f9979d", "core/algorithms/__init__.py": "489b6a395b7e79f2cab1f8c46eec73e1", "core/algorithms/calculation/digits.py": "b14e19d1913de492b116201b5f5c6c27", "core/algorithms/calculation/__init__.py": "6fb7087712399aff01a8a820cd77a474", "core/algorithms/linear_algebra/array.py": "f1e96ef9af8aaf15aaef29c863b3663c", "core/algorithms/linear_algebra/exceptions.py": "cc1a682728cd86a67aaf4b03a27c3e8a", "core/algorithms/linear_algebra/linear_space.py": "0d12ac5250106fc5fd0270b502ceb6e1", "core/algorithms/linear_algebra/matrix_cross.py": "ba1e06a57db80bcaa9509d6e733c1df9", "core/algorithms/linear_algebra/matrix_determinant.py": "23a47100204fd2f73f43cc201113f5e5", "core/algorithms/linear_algebra/matrix_diagonal.py": "ab7c7e101f46ebe7ed4bc73f542f111a", "core/algorithms/linear_algebra/matrix_divide.py": "01ec01fbb97bca37f22f719f3dc3d089", "core/algorithms/linear_algebra/matrix_dot.py": "67d721785420cd3f3344ac69bdb6ac32", "core/algorithms/linear_algebra/matrix_eigenvalue.py": "43b83077241aa32acdff04c8489363f5", "core/algorithms/linear_algebra/matrix_inverse.py": "f4c6ec6129a07ea821aff5b6b84f2aa6", "core/algorithms/linear_algebra/matrix_multiply.py": "067a30b30ff9be6d9b9123a75a30abc9", "core/algorithms/linear_algebra/matrix_transpose.py": "d63b39c00f437fab1540f331876444ab", "core/algorithms/linear_algebra/ones.py": "f7c3f42cde513ec5e91bc24dbc068d62", "core/algorithms/linear_algebra/reshape.py": "54f0d073af724f1c3c474e59940c6f72", "core/algorithms/linear_algebra/shape.py": "863cf7a043ab1d82f02a3a1279632b57", "core/algorithms/linear_algebra/zeros.py": "161e8f970d39d7bb2135852051a18005", "core/algorithms/linear_algebra/_utils.py": "8864ac424626bc7804d31b3e0ef3905f", "core/algorithms/linear_algebra/__init__.py": "a1ff4909241d1462727c33e5a8038cbd", "core/algorithms/linear_algebra/\u5f00\u53d1\u6d41\u7a0b.md": "54daed08712378a9ad4208884b65088b", "core/algorithms/linear_algebra/assets/code_hint.png": "013aecfff792430d0d3fac227bfcaaf4", "core/algorithms/linear_algebra/assets/configure_test_utils.png": "952e07a65e50b2fbd9666f8544ac20fa", "core/algorithms/linear_algebra/assets/define_function_framework.png": "4c921fffe0c7b10e5fb01e02d8f7a353", "core/algorithms/linear_algebra/assets/demand_change_file_change.png": "537d6591e1833d43c9fd6fc30cd1b2f6", "core/algorithms/linear_algebra/assets/finish.png": "d4c5fb995d723b15072691707b0ed72e", "core/algorithms/linear_algebra/assets/fix_testcase.png": "b1f4c682efcfb3f23e32ab085cc85b50", "core/algorithms/linear_algebra/assets/function_explanation.png": "c7bc75487b2abe6a536fc91a880d5f44", "core/algorithms/linear_algebra/assets/function_explanation_file_change": "15ade2607376365bb31c38a79d46ea89", "core/algorithms/linear_algebra/assets/function_file_change.png": "5b961672e09adba22805a5098e1bbbd1", "core/algorithms/linear_algebra/assets/function_workspace.png": "2bf5321cda6e0e1ac939895233e7a833", "core/algorithms/linear_algebra/assets/help_doc.png": "0e2f87b116e1fcb517cc63d5aa8e3d21", "core/algorithms/linear_algebra/assets/import_in_global.png": "259b30531b0ab509d4b93acec5cf3db1", "core/algorithms/linear_algebra/assets/import_in_sub_pkg.png": "622f44c6ec4738254d8585ae341b945e", "core/algorithms/linear_algebra/assets/run_in_pm.png": "4a64482cdd2125276501a4190848352c", "core/algorithms/linear_algebra/assets/run_test.png": "0d9abff3ca8a85fa0c3f58aef6ffd2d3", "core/algorithms/linear_algebra/assets/testcase_file_change.png": "caeda394883222a82b6dabd224fe0f0c", "core/algorithms/linear_algebra/assets/test_error.png": "a6b5a1a95cdc1fc21ce522f35da111aa", "core/algorithms/linear_algebra/assets/test_pass.png": "7792d7ee583bdb629ea41cec3a5cbf07", "core/algorithms/linear_algebra/assets/write_doc.png": "5349a5f4df8ed7a982ac5c86298ce715", "core/algorithms/linear_algebra/assets/write_doc_file_change.png": "34753c6a77cc470710669f518cfb3055", "core/algorithms/linear_algebra/assets/write_function_file_change.png": "2f5d964072df62b5a915fc14a41597b9", "core/algorithms/plotting/graph.py": "1728aea4907b92b67fe91ad742a3083f", "core/algorithms/plotting/graph_configs.py": "614cbeae8b696da2e8fe983e3c87a5f9", "core/algorithms/plotting/__init__.py": "9f90fe07592b24c4a09ed9230b6c093d", "core/algorithms/pyminer_util/communication.py": "216e0f4b1c8b00d535f0585c7fa1add3", "core/algorithms/pyminer_util/__init__.py": "de143e26c42af15d96c77f52383561a0", "core/algorithms/statistics/__init__.py": "4bba02c1df562ce45ccf5dfc988ab576", "core/evaluation/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "core/evaluation/woe/config.py": "9ac12638758e61c547224a0b4cc5e5f8", "core/evaluation/woe/eval.py": "62ab9836e64b475b07e0ea5cccf3aeb0", "core/evaluation/woe/feature_process.py": "e12d77b446b6a75746499d909ca22ae8", "core/evaluation/woe/ftrl.py": "1e6dad2dfc172413104ef5b3fb25e88d", "core/evaluation/woe/GridSearch.py": "8b92ecf1226fa81972510b17aa4cc2c4", "core/evaluation/woe/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "core/evaluation/woe/tests/config.csv": "66f330fdc285911a52c4a65166eab04f", "core/evaluation/woe/tests/HereWeGo.py": "94d48377d8292b80d8f4929cf9162004", "core/evaluation/woe/tests/README.rst": "8f72b661abc5eaf059d05e603b1c705c", "core/evaluation/woe/tests/UCI_Credit_Card.csv": "afd3af2602d66d6ceb36cb04216f0ed2", "core/io/postgresql/psycopg2/compat.py": "7abef6e4534c7b625057e37289bc8c27", "core/io/postgresql/psycopg2/errorcodes.py": "b2346a81ec49de54caa4e32a5360076e", "core/io/postgresql/psycopg2/errors.py": "316dfc64e89c95715e974a31f96e18fe", "core/io/postgresql/psycopg2/extensions.py": "d7fc21cf847f2d12a60f56097e3eca2f", "core/io/postgresql/psycopg2/extras.py": "4d79c51ba46dc3285d9faf8789a37369", "core/io/postgresql/psycopg2/pool.py": "1b0403b2597557108c4c35a9bc568834", "core/io/postgresql/psycopg2/sql.py": "1b8ad7b5746ad2f514cbdd678954fee2", "core/io/postgresql/psycopg2/tz.py": "b70b2abdc56dc05e9c28993934bed8f4", "core/io/postgresql/psycopg2/_ipaddress.py": "e0ff64e2ae604224c8cd11d1bdb27003", "core/io/postgresql/psycopg2/_json.py": "38e03cf8ae626f8fa028ceb48dcdb960", "core/io/postgresql/psycopg2/_lru_cache.py": "5e2bc12517950812ccac51af1d61d8a5", "core/io/postgresql/psycopg2/_range.py": "46ff7ab96f96d7db81eee160f666cfa4", "core/io/postgresql/psycopg2/__init__.py": "36fa5f3355c7d7ea36b87d1cdda6afe4", "core/modelling/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "core/modelling/regression/base_regression.py": "461cde16f7769d88c386f6f142ec233a", "core/modelling/regression/knn.py": "9f0c137ed701a2d11325ae1c9da23caa", "core/modelling/regression/linear.py": "a7936db33b1faa26cdbdc53a4bb81dfc", "core/modelling/regression/linear_bfgs.py": "031491ee5d158dcc8d506458fd10dbdf", "core/modelling/regression/mean.py": "c494d914a7be950f81b073dcad1e8bdf", "core/modelling/regression/neural_network.py": "571fa4e8bdc730c503cda08b0afd1d41", "core/modelling/regression/random_forest.py": "33c3aa9f1300b805ef13dd96866ea114", "core/modelling/regression/simple_random_forest.py": "e8c180090ce051d2f57e94b98e30b3c3", "core/modelling/regression/svm.py": "f5547c9da4c71d06a1df162be1e51885", "core/modelling/regression/tree.py": "0bd5b05a252b233597b6ff7453881ebd", "core/modelling/regression/__init__.py": "5b1908d95bc0ac027b22c337ea12f21b", "core/preprocess/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "docs/make.bat": "0d5c4de56de1ea8fa10468d561de4d77", "docs/Makefile": "45ecc4dd568420521f285e291939ecf1", "docs/make_doc.py": "3710c825012f1dc2e8d4f5854622e186", "docs/PyMiner\u4ecb\u7ecd.md": "56012d9e37961de92ea165d227e8707b", "docs/THANKS": "ad97f1302bcf00e26a219a0801a0b34d", "docs/upload.py": "10534ab4011a82607ef2b0c2f6c1b599", "docs/source/conf.py": "86928f87e5b0a03cbdd58f6f8a87f55b", "docs/source/contents.rst": "cd9756a400d0aa68ef85e92394c58b25", "docs/source/contribute/index.md": "260363f4717c8db812dc5d9c2c5723f8", "docs/source/_static/css/pyminer.css": "4a98b74c6e7893114cabc72ef5c6b81d", "docs/source/_static/css/pyminer.css.map": "e82da77c9ca623f0acbf4cbc62d78cbd", "docs/source/_static/css/pyminer.sass": "e5940574b2a7af7e3b7c01c2fc600354", "docs/source/_static/css/README.txt": "6e9ef1827e9eaea7ca3831685d830c7d", "docs/source/_static/index_files/all.css": "242611f34a440c48c2e6405e91e01a71", "docs/source/_static/index_files/all.js(1).download": "d7b3138b22aac6df42d86c92e36763ba", "docs/source/_static/index_files/all.js(2).download": "83006561af55b7a96dd7e17d34ebfe8a", "docs/source/_static/index_files/all.js.download": "39bebcf34d45ccab4d08bfb31b684294", "docs/source/_static/index_files/check_data.png": "e44471c2514f8a048df2a89a9df2e795", "docs/source/_static/index_files/code.png": "814df667bb94b7d2ae844d938ec916b7", "docs/source/_static/index_files/font-awesome.min.css": "ea6cc550de5339fc787f1e041363e544", "docs/source/_static/index_files/ico_mailme_01.png": "c40acf63e04064714b98a30a92984868", "docs/source/_static/index_files/main.png": "1b6f8a5331f0c5954a86b9024f070568", "docs/source/_static/index_files/modernizr.js.download": "4fae2a90728c528aa148c31466b7ed39", "docs/source/_static/index_files/normalize.css": "ed3146b9b1ec5eecb132a21916d0afe5", "docs/source/_static/index_files/robot.svg": "ba2b8a892fc5457a02829ba0b2caf3da", "docs/source/_templates/index.html": "66315ce66e29f04ce356a9b8b0d41ac8", "examples/HereWeGo.py": "d94883e4b2545ccfec29c1e76aebb982", "examples/README.md": "d49b56a1fe9a7ef2530943a5848fac88", "examples/README_ZH.md": "ac49a6e35c2518cac510ee6920c840da", "examples/UCI_Credit_Card.csv": "afd3af2602d66d6ceb36cb04216f0ed2", "examples/woe_rule.pkl": "cc2695e5f41ac2679a2040e15ff9463e", "examples/datasets/air_quality_no2.csv": "c27e6437bf25787c881d0d5f57e10233", "examples/datasets/bankloan.sav": "b5e78f9be79d7ba44c4fe5ac69cddc02", "examples/datasets/boston_house_prices.csv": "6454dba73c425c66b50d5206ed45f1a0", "examples/datasets/brown-selected.tab": "9e43112b53c6f6c78fa0b2645ace506d", "examples/datasets/brown-selected.tab.metadata": "337569fc2132e37108b428b9b082cfe9", "examples/datasets/cars.sas7bdat": "073898a0487cde27abd7155461c564be", "examples/datasets/car_sales.sav": "7b2487624eb4ffb893812706d30b0542", "examples/datasets/ccpp.csv": "20372480cb1e06f4cb99e46a0bd759a4", "examples/datasets/class.sas7bdat": "6e69aeb1f12de8d3fc46a64cbd4dc786", "examples/datasets/conferences.dst": "78dc681ceec57ee82dbf1951f11fa758", "examples/datasets/datasets.info": "19934e0d167a3128a09c493b9aeb031e", "examples/datasets/diabetes.csv": "8523f75b2f041c08542910b7ea3a8e84", "examples/datasets/heart_disease.tab": "859a303f42efd8b2a1bd0f2e33fedf71", "examples/datasets/heart_disease.tab.metadata": "ed45f5da717ba279094a29f33a4b263d", "examples/datasets/housing.tab": "e0eda02af8c85dd28b21620ee5c74552", "examples/datasets/housing.tab.metadata": "9d88fcbc612a9928d951ceb5f22b04c9", "examples/datasets/iris.csv": "ffd137d9c66a717d061b9fa5831000b1", "examples/datasets/iris.tab": "bbf17c5ae7e81aeb2ad7694648a6b2e1", "examples/datasets/iris.tab.metadata": "e1d89c7e7561bcc716dafd546058196e", "examples/datasets/list_update.py": "737978a6df832d796431df3b048b051a", "examples/datasets/mushrooms.csv": "2007f683881ecd4febc1b7674c5751a8", "examples/datasets/slovenian-towns.dst": "e6c7acf1cb81c6d71523d0e7b3ea6f41", "examples/datasets/titanic.tab": "4291853e1bf953ef2c0c1e39653a0f80", "examples/datasets/titanic.tab.metadata": "5074c723c0342fa64396739eb0480d33", "examples/datasets/TitanicData.xls": "7afb9b02b50c902fd364364f7d2e49be", "examples/datasets/UCI_Credit_Card.csv": "afd3af2602d66d6ceb36cb04216f0ed2", "examples/datasets/zoo.tab": "90a455135a6a8822f1200630270bdcb0", "examples/datasets/zoo.tab.metadata": "1b824e81f9e8969228e01e460d6b05e6", "features/feedback.py": "2fed1192b08f982e19b6cb75f40c7f10", "features/index.rst": "caf9be56f3fc9b08f569abee024f6cf2", "features/openprocess.py": "539c43bc37743144d9216715b8fad57f", "features/README.md": "eed382b7fe1775f4b6b875d4b564ae50", "features/settings.py": "a7c36fc21234c3a23c7663e1b248e60b", "features/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/auth/authlocalserver.py": "1a7bd0455dc04627bdb5367c7ebc9c2a", "features/auth/authmanager.py": "06a45267063200c67104786db5cff4e1", "features/auth/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/auth/templates/login.html": "446aac7443cc70f43e46753092445aef", "features/auth/templates/register.html": "3a424e8c3bdf1eb6043e0ab9ca34acff", "features/extensions/index.rst": "01d20711a991f116e372db6fb72c96df", "features/extensions/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/extensions/extensionlib/baseext.py": "677942d6d94defa454ec27b173d582db", "features/extensions/extensionlib/extensionlib.md": "aacae615d8f781c275ac79c22fae5678", "features/extensions/extensionlib/extension_lib.py": "e48b16cc626c5001355438e28f00d219", "features/extensions/extensionlib/readme.md": "00629cf6b22e95200c530ea6d512057f", "features/extensions/extensionlib/__init__.py": "2dc050a0d3da896f4b39681a6e057f63", "features/extensions/extensions_manager/ExtensionLoader.py": "aee9c0b155f0bade604e41d3a38efa36", "features/extensions/extensions_manager/log.py": "6e8bd61219f2ff606b58c1399d322ddf", "features/extensions/extensions_manager/manager.py": "a7fa22dd5ba1fc531f31b0741f12c61e", "features/extensions/extensions_manager/readme.drawio": "4bafe50e30ca4be5cdef34e1e657f7a6", "features/extensions/extensions_manager/README.md": "97b9464ed10af4ad3015ac7f38e6cf99", "features/extensions/extensions_manager/UIInserter.py": "e66518eebc812a4f5b94997351fe1b0b", "features/extensions/extensions_manager/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/extensions/extensions_manager/vermanager/vermanager.py": "01c76efe94e29a53138a670f909f2d52", "features/extensions/extensions_manager/vermanager/__init__.py": "03f044152b579a37841af43eae7f2389", "features/interpretermanager/interpretermanager.py": "f444a2a4cebc7ae225cf46f61ae7950b", "features/interpretermanager/packagemanager.py": "573cf34280aff9d22775f692e63cbb8c", "features/interpretermanager/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/io/database.py": "567325cf72a6f4564a4a0f27326f1b25", "features/io/dbConn.py": "50780c5805a79cb1934b2d7e0d8c0ab6", "features/io/dbConnectAccount.pkl": "5d9291410939747f2c8c07dd81222283", "features/io/encoding.py": "3d17abe6b8042115f6e15b869aff7c44", "features/io/exceptions.py": "72dcca0f3371e119d43e9827e73528b0", "features/io/settings.py": "a3234ca4ddc2f8b0e0e62450756c1e56", "features/io/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/main_window/base.py": "aab682344cfc58317a1413203ebd6261", "features/pluginsmanager/pluginsmanager.py": "f7dc55bb96470571a9a6558cb3962591", "features/pluginsmanager/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/project/template/Basic-Template.py": "4204e7ce0f6309fd93535659c3c466c8", "features/project/template/Empty-Template.py": "18dc747535104b7c6ef67b21c97069f1", "features/project/template/Plot-Template.py": "b688a56819d86c6eb44ff9e72b809091", "features/project/template/PyQt-Template.py": "8a64552bb7be154721ceeaf50f4e8673", "features/project/template/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/project/template/PySide2Template/main.py": "ed912fbf0fc0c20fcacb81bd19800c14", "features/project/template/PySide2Template/PySide2_Template.py": "ac93a3b7fc512f9c0afa7f00a2643674", "features/project/template/PySide2Template/PySide2_Template.ui": "c8cd27a3e0b5cb1c9936603328d7b732", "features/project/template/PySide2Template/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/ui/main.py": "2d7d5d9496b9208ddb27e60f708a1a4d", "features/ui/ui_aboutme.py": "c79955815de4013a7a64d690f94febbc", "features/ui/ui_aboutme.ui": "160718ccbd19dc35a00aaeee6faffaa2", "features/ui/ui_appstore.py": "256f2fd75ad7ffdf667c13bf7a3b5128", "features/ui/ui_appstore.ui": "a7e7317eca4ee6311e41968445e1fa81", "features/ui/ui_check_update.py": "8226a48eb517b9da8cf425b809ff3c8a", "features/ui/ui_check_update.ui": "0766a087aa5b8e4a5e46f4211055aa9b", "features/ui/ui_data_normal.py": "d9971d97184ade3f9c405f061dd22231", "features/ui/ui_data_normal.ui": "c8a3e10c4487ce5a2774ca8ea5a5905a", "features/ui/ui_first_form.py": "cbbf26db8887e60df0dd7ce0713a5a54", "features/ui/ui_first_form.ui": "1b5d9231837a421c9b77382b3f6f1719", "features/ui/ui_login.py": "2fe8d95e4257473abea1549e127f7ede", "features/ui/ui_login.ui": "58916dfb5dd1dfab103fa4f15882a282", "features/ui/ui_logined.py": "668bf0e57ec258d1ee0b7bfac2abe1b5", "features/ui/ui_logined.ui": "e6d6f9d467a6b8a24336713481e9a6f6", "features/ui/ui_option.py": "12491a3f32f99d3bb7833291c5402cfa", "features/ui/ui_option.ui": "9cf7b928ccf449e096586e949cd7dd95", "features/ui/ui_preferences.py": "d925283bad5dc99d85a90798cb86c6ce", "features/ui/ui_preferences.ui": "4336a5c78eef921b047e1c86c49650f5", "features/ui/ui_project_wizard.py": "65f0c2afe19b349e8b63b57a941c4db1", "features/ui/ui_project_wizard.ui": "9d21051c8df87eb832bdf8a5470f1c8c", "features/ui/ui_workspace_launcher.py": "594f60adb389355ef83a5bca20eafb5a", "features/ui/ui_workspace_launcher.ui": "fd4e48c43a6d35a209c2696942f0927f", "features/ui/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/ui/common/debug_process_with_pyqt.py": "2971e07b890f1872c7f7009c4d2b44fe", "features/ui/common/openprocess.py": "3d1aeb10bde66329d7126840466ba6df", "features/ui/common/open_process_with_pyqt.py": "851480f8440b2f81033a319b5f32f465", "features/ui/common/platformutil.py": "070ffc4eaea4cb0c4b6dcca39fe4035f", "features/ui/common/pmlocale.py": "f7ca747cc3dedc2b6cf03c7b5f9ec121", "features/ui/common/test_open_app.py": "5f56a2266c07dd652659c949b297f498", "features/ui/common/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/ui/pmwidgets/dockwidget.py": "cb0c4fe5642dda21f5692ecce49eed95", "features/ui/pmwidgets/pmmainwindow.py": "5f3887a06e377de92251c6b49853cddb", "features/ui/pmwidgets/toplevel.py": "8700605abc51c422a5a1588dc80a8bfd", "features/ui/pmwidgets/__init__.py": "dbd5c209ff332a55a7e483fcb686421f", "features/ui/pm_marketplace/install.py": "54117accb9d426c89b751355b7e73f0b", "features/ui/pm_marketplace/install.ui": "22c1cb1d2e58f0e6e63d3c199af96edd", "features/ui/pm_marketplace/main.py": "1fea599f650efa60951f3029d940d73e", "features/ui/pm_marketplace/main.ui": "76b3d012f1742eeb8cb85a0ee9ec5680", "features/ui/pm_marketplace/package_manager_main.py": "0ab9760f90d31f8f0eb3287bdf530891", "features/ui/pm_marketplace/package_manager_main.ui": "8dba9def55b1ea06d6c953f33e875cb9", "features/ui/pm_marketplace/uninstall.py": "292fa58f6d05fc584029fb0650702aa3", "features/ui/pm_marketplace/uninstall.ui": "c1160fc571c23573e4bfb4ada3807edc", "features/ui/pm_marketplace/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/ui/widgets/controlpanel.py": "d5fceeb26a8878ff80d6339895dbb5cd", "features/ui/widgets/notificationwidget.py": "3c6d71d757c8a0e3a11b9e48ca7108eb", "features/ui/widgets/README.md": "9f7d88859d291d2f64cba1b6ba49a59e", "features/ui/widgets/reportwidget.py": "1f00f377fe6cfc610cf58e68462307e6", "features/ui/widgets/resources.py": "14a758e941b459f8b23704065f1e8639", "features/ui/widgets/__init__.py": "77b4a6a8852c7103e7525d3955c40358", "features/util/check_update_ui.py": "5bfc0584c45856ace75efedafd677436", "features/util/check_update_ui.ui": "0766a087aa5b8e4a5e46f4211055aa9b", "features/util/make_update.py": "17f81b28bdc7a353dac1d7b45ed762cf", "features/util/openprocess.py": "539c43bc37743144d9216715b8fad57f", "features/util/update.py": "896e76ccbae9ae36c17d14515b6fafa5", "features/util/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/workspace/data_manager.py": "d7b5e29419b744fad86e6245018de1e8", "features/workspace/index.rst": "3ce5d474607ba614ba9f6afc772e7bc2", "features/workspace/signals.py": "d950f3f33fd821323d95ece2b8d90e84", "features/workspace/signals.rst": "3618e25aa7f77f05142dc84a96eaf45c", "features/workspace/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/workspace/blinker/base.py": "83733f47cb03be3713ce7a5860612e96", "features/workspace/blinker/_saferef.py": "ced62e1fda983045da2076064a7db34d", "features/workspace/blinker/_utilities.py": "1aeb68e85d8ad0aa80295e5f29f42d18", "features/workspace/blinker/__init__.py": "464a73bb96572aaf6c2ed191676d40a4", "features/workspace/data/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/workspace/data_adapter/array.py": "2891617cd8d0eb1cd3780258212ce847", "features/workspace/data_adapter/base.py": "8d176a5909da92fbbfdade7ecd040127", "features/workspace/data_adapter/data_frame.py": "d71dc9d36194663b154bbb13eb1bf8a9", "features/workspace/data_adapter/detector.py": "af748d211285fe07fa56bf2b21e4d60e", "features/workspace/data_adapter/index.rst": "1d16f21a65dadb51dc1ecc68d9cad119", "features/workspace/data_adapter/universal.py": "49603cc94bc554bdb8456a1cdbdd39b1", "features/workspace/data_adapter/__init__.py": "b9da2c81695eae92f9748a4a59cd0c29", "features/workspace_old/history.md": "ab52fc7f26dff2cecf2f2f704844db56", "features/workspace_old/index.rst": "961579c17854f0d0d7b9f4e0bb6b1621", "features/workspace_old/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/workspace_old/datamanager/converter.py": "0cddb9d818f283a125bf534c3633f2b7", "features/workspace_old/datamanager/datamanager.py": "a2025c72d71aaf79728c54bfaf9dc3d3", "features/workspace_old/datamanager/dataset.py": "5d0b8678f8a53db8d8c9a483b90c79aa", "features/workspace_old/datamanager/exceptions.py": "6ed4da7a9003f12c756366cf67d87027", "features/workspace_old/datamanager/historyset.py": "85f91eac3f692ce44ed011647d319bac", "features/workspace_old/datamanager/metadataset.py": "9047c690af46c4db5b0501fdc25f975b", "features/workspace_old/datamanager/recyclebin.py": "c9effef9419e3be130a027f116761881", "features/workspace_old/datamanager/variable.py": "d35eb9e5fea49eaf5899d7315caa582a", "features/workspace_old/datamanager/varset.py": "54e77b59c43212ef22b4e271b8893953", "features/workspace_old/datamanager/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "languages/en.ts": "64307a7a6a8a2bc627ecbfaf2fc0e805", "languages/en/en.ts": "a426bc922ab99d1920e790b890d1b386", "languages/zh_CN/widgets_qt_zh_CN.qm": "cbaaec13dd22418095f6c7a9122926cc", "languages/zh_CN/widgets_qt_zh_CN.ts": "d81ecd8ec48ae725c76eba4f09ee9ecb", "languages/zh_CN/pmtoolbox_qt_zh_CN.ts": "95510ea97a650faeba03d155b1c81cbf", "languages/zh_CN/qt_zh_CN.ts": "bf9e10698c9cef267c344f73e30789e6", "languages/zh_CN/zh_CN.qm": "941aa53373af233466a16d682d7e625a", "languages/zh_CN/zh_CN.ts": "1be0a3147fea71527d4e17065a66d482", "languages/zh_CN/zh_CN.ts.bak": "c916a039d8a676ad891150786e9b1185", "languages/zh_TW/zh_TW.ts": "a426bc922ab99d1920e790b890d1b386", "packages/index.rst": "60e962032576844618f7a1448880b8fd", "packages/__init__.py": "a248423783ba8e03c638b996a91de109", "packages/advanced_drawings_toolbar/group_chart.py": "846a72c9e0303f8ef4b5c6b809f07db7", "packages/advanced_drawings_toolbar/ipython_console.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/advanced_drawings_toolbar/main.py": "78b220f88ba07d759c9f0722f6fc0306", "packages/advanced_drawings_toolbar/map_var.json": "91324fe1e6b292ebc2d548f3ae7d49b7", "packages/advanced_drawings_toolbar/map_var.py": "46e4e76e96cb5691754e4b63a38b67d9", "packages/advanced_drawings_toolbar/package.json": "3483b83687dfaf5bb4410107b04fdfd0", "packages/advanced_drawings_toolbar/radar_chart.py": "67ea13759ea77d67006df488c9fde4e0", "packages/advanced_drawings_toolbar/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/advanced_drawings_toolbar/pmmap/china/all/01-beijing.npy": "05fc6e35605340ef6e4d62af9770ef7a", "packages/advanced_drawings_toolbar/pmmap/china/all/02-shanghai.npy": "dbd37714da88edf44df7a2642ce2c14f", "packages/advanced_drawings_toolbar/pmmap/china/all/03-tianjin.npy": "e767b1d0810acfd174d4b52586441de1", "packages/advanced_drawings_toolbar/pmmap/china/all/04-chongqing.npy": "1980444de2496af7ae7b11cae9372d2c", "packages/advanced_drawings_toolbar/pmmap/china/all/05-heilongjiang.npy": "f369a349db31ac0636e625737802922e", "packages/advanced_drawings_toolbar/pmmap/china/all/06-neimeng.npy": "0366d9f95bfe2e0768a6491f8f5e27cc", "packages/advanced_drawings_toolbar/pmmap/china/all/07-xinjiang.npy": "201b3ff97375ae9ba6e9fc9c7b0eed1e", "packages/advanced_drawings_toolbar/pmmap/china/all/08-jilin.npy": "0ed85b6d84b877cf07154e1b54db0bdd", "packages/advanced_drawings_toolbar/pmmap/china/all/09-gansu.npy": "08c6e4437a0fc5d19d6c655a14a7df2e", "packages/advanced_drawings_toolbar/pmmap/china/all/10-liaoning.npy": "542d598f5c39b363738b0b753d8318d1", "packages/advanced_drawings_toolbar/pmmap/china/all/11-hebei.npy": "5a7ce525859caabaffad0fe1c11cb26f", "packages/advanced_drawings_toolbar/pmmap/china/all/12-shanxi.npy": "5ebb5347431393d599f5f0d36a31dd07", "packages/advanced_drawings_toolbar/pmmap/china/all/13-shan3xi.npy": "71944b8eea6caa0b7e4138063d6e8945", "packages/advanced_drawings_toolbar/pmmap/china/all/14-ningxia.npy": "dc0660ac4216cb4e928fb08dba5e36fb", "packages/advanced_drawings_toolbar/pmmap/china/all/15-qinghai.npy": "46f4e9bf9a47734d0cfbef0916e6cec1", "packages/advanced_drawings_toolbar/pmmap/china/all/16-shandong.npy": "b3eee97751e252f1c729b20cde81220c", "packages/advanced_drawings_toolbar/pmmap/china/all/17-henan.npy": "530d73e54901bf816e61c86bafb97219", "packages/advanced_drawings_toolbar/pmmap/china/all/18-xizang.npy": "83c873032100d735d2a3c1becb4e4ee5", "packages/advanced_drawings_toolbar/pmmap/china/all/19-jiangsu.npy": "33051765300de0a9d003ea91c3846cc6", "packages/advanced_drawings_toolbar/pmmap/china/all/20-anhui.npy": "d80f40e27c3a60188547d058c827eae0", "packages/advanced_drawings_toolbar/pmmap/china/all/21-sichuan.npy": "115e4b1abbc6df1f862095e94cacb8b5", "packages/advanced_drawings_toolbar/pmmap/china/all/22-hubei.npy": "065b61ce8a2728be70d0e726990e42c2", "packages/advanced_drawings_toolbar/pmmap/china/all/23-zhejiang.npy": "6910df476893b4e5a84689094203b724", "packages/advanced_drawings_toolbar/pmmap/china/all/24-jiangxi.npy": "2d4e166cd8d9371a1c6d01848ece3301", "packages/advanced_drawings_toolbar/pmmap/china/all/25-hunan.npy": "ddbce0334a1f79bd77f7b0ae582dd28e", "packages/advanced_drawings_toolbar/pmmap/china/all/26-guizhou.npy": "4d23f4f330203b61c6f8cca0ac764819", "packages/advanced_drawings_toolbar/pmmap/china/all/27-yunnan.npy": "1d1c9378c8427667dbf0b8948c36b484", "packages/advanced_drawings_toolbar/pmmap/china/all/28-fujian.npy": "77270ff92f0d67f0123672527b70772a", "packages/advanced_drawings_toolbar/pmmap/china/all/29-guangxi.npy": "3862d0becc054fe754ae71c111c583ad", "packages/advanced_drawings_toolbar/pmmap/china/all/30-guangdong.npy": "7d7f1392cc01a22d4503354ce7c729b1", "packages/advanced_drawings_toolbar/pmmap/china/all/31-taiwan.npy": "2f398da02605db2be30751dedb92ea90", "packages/advanced_drawings_toolbar/pmmap/china/all/32-xianggang.npy": "b3cf9d637c7d87e82a86174f99be74da", "packages/advanced_drawings_toolbar/pmmap/china/all/33-aomen.npy": "68e3c682aef3e25cf873878a19df5361", "packages/advanced_drawings_toolbar/pmmap/china/all/34-hainan.npy": "a67e27cc4f68d566f6977580d95b006c", "packages/advanced_drawings_toolbar/pmmap/china/all/39-jiuduan.npy": "35fbdcbb72d2c22caab9b1bfd2eba401", "packages/advanced_drawings_toolbar/pmmap/china/small/30-guangdong.npy": "7d7f1392cc01a22d4503354ce7c729b1", "packages/advanced_drawings_toolbar/pmmap/china/small/31-taiwan.npy": "2f398da02605db2be30751dedb92ea90", "packages/advanced_drawings_toolbar/pmmap/china/small/32-xianggang.npy": "b3cf9d637c7d87e82a86174f99be74da", "packages/advanced_drawings_toolbar/pmmap/china/small/33-aomen.npy": "68e3c682aef3e25cf873878a19df5361", "packages/advanced_drawings_toolbar/pmmap/china/small/34-hainan.npy": "a67e27cc4f68d566f6977580d95b006c", "packages/advanced_drawings_toolbar/pmmap/china/small/39-jiuduan.npy": "35fbdcbb72d2c22caab9b1bfd2eba401", "packages/advanced_drawings_toolbar/source/down.svg": "fe6b296aa4020dda5c5a870bb7596235", "packages/advanced_drawings_toolbar/source/plot.svg": "05fd271af6c134f6872c80c489064d60", "packages/advanced_drawings_toolbar/source/\u5730\u56fe.png": "eca50b3207a973738145d1cf12ca0c34", "packages/advanced_drawings_toolbar/source/\u6298\u7ebf\u56fe.png": "1bde0eca8cfa880452accf56ca925866", "packages/advanced_drawings_toolbar/source/\u6563\u70b9\u56fe.png": "78c432bb278d8ea5c9587f23ffdd5f82", "packages/advanced_drawings_toolbar/source/\u6761\u5f62\u56fe.png": "b07f4db5b1785376f97636fc6963234e", "packages/advanced_drawings_toolbar/source/\u67f1\u5f62\u56fe.png": "d6cba37e00bf9bbeb65235897a7b90b9", "packages/advanced_drawings_toolbar/source/\u6c14\u6ce1\u56fe.png": "d6784d4c53145cce1fde17f673b76984", "packages/advanced_drawings_toolbar/source/\u70ed\u529b\u56fe.png": "566d7c6ad396084ca6b7d490868fdc2c", "packages/advanced_drawings_toolbar/source/\u76f4\u65b9\u56fe.png": "a9b01bca53610b2c03f7ea2331c91cc3", "packages/advanced_drawings_toolbar/source/\u7bb1\u7ebf\u56fe.png": "ba733c4c1a0979ab5bc838149490e915", "packages/advanced_drawings_toolbar/source/\u7ec4\u5408\u56fe.png": "c5bea73cff095ad47bd07e1e81921ab2", "packages/advanced_drawings_toolbar/source/\u96f7\u8fbe\u56fe.png": "5aa1a48424b30a157a2bca181c9be2d0", "packages/advanced_drawings_toolbar/source/\u9762\u79ef\u56fe.png": "69682cc944d7afdd5c1f2019bf6ca21c", "packages/advanced_drawings_toolbar/source/\u997c\u56fe.png": "862b6c81a5752ee7d53500ce9064c10d", "packages/advanced_drawings_toolbar/translations/qt_zh_CN.qm": "cd23a7e488d169790b204929188d78e7", "packages/advanced_drawings_toolbar/translations/qt_zh_CN.ts": "ce76ad850f047e2cea0440e4dab7c7d4", "packages/applications_toolbar/applications_toolbar.py": "1c7db3beb99333a43fcbc29f2b628117", "packages/applications_toolbar/dev_tools.py": "32396eb367e2f40a2ca41bbf1c122380", "packages/applications_toolbar/ipyinterface.py": "b52686fd36bd819d65916f6c70a135e9", "packages/applications_toolbar/ipython_console.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/applications_toolbar/main.py": "1d6fa534839be7a73ed71881a9fb166e", "packages/applications_toolbar/manage_apps.py": "88d58bae208874c4973e22165f112675", "packages/applications_toolbar/package.json": "b6e6fae7a7650f3a94327d27f4fd4f9c", "packages/applications_toolbar/process_monitor.py": "86f69fb10c7ef7ba19504b418e8851f5", "packages/applications_toolbar/README.md": "500119ec92d71af8ac97e7246e30342e", "packages/applications_toolbar/settings_apps.json": "4182a1dc3f6489bca92a7eb123a85b6c", "packages/applications_toolbar/apps/cftool/algorithm.py": "253d3d8c4d7fcebe0018d65511e03ae9", "packages/applications_toolbar/apps/cftool/GUI_QT.py": "81a8a4dbbb41799c196129cb7b98247c", "packages/applications_toolbar/apps/cftool/main.py": "386bb5ebf2b5d8ad609ecd2be95bb607", "packages/applications_toolbar/apps/cftool/package.json": "ef90cc084c17151e6db5f1a4bb170897", "packages/applications_toolbar/apps/cftool/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/applications_toolbar/apps/cftool/README.md": "82a32691c1f8296f6fe73faebc1ddf89", "packages/applications_toolbar/apps/cftool/regexvalidifyer.py": "f7b28de6b75b89f19078a3e2e10d9818", "packages/applications_toolbar/apps/cftool/test1.py": "d8b7b73613a84a9044721403a1e8042a", "packages/applications_toolbar/apps/cftool/test_file.py": "dc6b5c9b40404d62209e36daf7b4819e", "packages/applications_toolbar/apps/cftool/src/cftool.png": "04975fa7979a56ac4dabea313cc7c004", "packages/applications_toolbar/apps/cftool/src/\u66f2\u7ebf\u62df\u5408.png": "d7ccf65e6d59dfd63507f1432454a943", "packages/applications_toolbar/apps/demo_app/default.png": "b58b2daf9a2a44726b678f235aed41e6", "packages/applications_toolbar/apps/demo_app/demo_app.py": "931bb2658ec5554a4f1cbb7424736f5a", "packages/applications_toolbar/apps/demo_app/main.py": "63ffc303fd56ba7d882fe108cd44efeb", "packages/applications_toolbar/apps/demo_app/package.json": "24bd9031b9afde16470332c19333c0bb", "packages/applications_toolbar/apps/demo_app/README.md": "ddb8b30770b3972dee69051c99026d1f", "packages/applications_toolbar/apps/demo_app/settings.json": "e4385e0a6554dfe40b3696f328f5edd1", "packages/applications_toolbar/apps/flowchart/flowchart.png": "e419f05974065c85c4c7b56604ce920a", "packages/applications_toolbar/apps/flowchart/main.py": "3288fef7caa83b16745351634f1c5e13", "packages/applications_toolbar/apps/flowchart/package.json": "bfe315ff8f31d2c4699a560608a5b973", "packages/applications_toolbar/apps/flowchart/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/applications_toolbar/apps/flowchart/README.md": "9b53d15d3e33ddba31de6b5f4e684c1b", "packages/applications_toolbar/apps/flowchart/examples/drop_duplicated.pmfc": "be5c44289f838b15d93c1b227b657091", "packages/applications_toolbar/apps/flowchart/examples/read_all_csv_files.pmfc": "4b1e9884b118c9dfa1e855f55178fad5", "packages/applications_toolbar/apps/flowchart/plugin_nodes/nodes.py": "92702a3afc444e8ce17b53314722eff6", "packages/applications_toolbar/apps/flowchart/plugin_nodes/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/applications_toolbar/apps/flowchart/resources/flowchartwindow.jpg": "d91093a77c5746982f7575081674e05b", "packages/applications_toolbar/apps/flowchart/resources/nodeports.jpg": "fddd899d2618662bb2b61d7e09680ad2", "packages/applications_toolbar/apps/flowchart/test_files/test_drop_duplicated.csv": "0574869eff0b86a260260b72cf53bb4a", "packages/applications_toolbar/apps/ligralpy/chart_server.py": "b3dc9a23925b30a73ac974f7a8123689", "packages/applications_toolbar/apps/ligralpy/Data.csv": "5fdba74629c5a0b1a5a6be20a3a19688", "packages/applications_toolbar/apps/ligralpy/flowchart.png": "e419f05974065c85c4c7b56604ce920a", "packages/applications_toolbar/apps/ligralpy/img.png": "8408ad879fe242ed82c30adbc3694d46", "packages/applications_toolbar/apps/ligralpy/main.py": "59a370745781b14b673f52ef392a5108", "packages/applications_toolbar/apps/ligralpy/package.json": "9e7eeab6e86f652142ae125bec65e71d", "packages/applications_toolbar/apps/ligralpy/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/applications_toolbar/apps/ligralpy/README.md": "9b53d15d3e33ddba31de6b5f4e684c1b", "packages/applications_toolbar/apps/ligralpy/examples/flowchart_stat_demo.json": "2d91e5c4fff5494f14dbb88a8b5f5031", "packages/applications_toolbar/apps/ligralpy/examples/second_ordered.lig.json": "86a67bc8b6402059ff6f15ef83722705", "packages/applications_toolbar/apps/ligralpy/nodes/nodes.py": "a08108573e2ace0e04dc0551da7653a6", "packages/applications_toolbar/apps/ligralpy/nodes/simulation.py": "043e5c86cf3c147d23cda2a2cf589395", "packages/applications_toolbar/apps/ligralpy/nodes/__init__.py": "06133052eded73b0d4be7b4719d5a3fc", "packages/applications_toolbar/apps/ligralpy/nodes/tools/gen_classes.py": "976b6416996c3bd2ce0c811b68175d60", "packages/applications_toolbar/apps/ligralpy/resources/flowchartwindow.jpg": "d91093a77c5746982f7575081674e05b", "packages/applications_toolbar/apps/ligralpy/resources/nodeports.jpg": "fddd899d2618662bb2b61d7e09680ad2", "packages/applications_toolbar/source/appstore.svg": "e2a48d1643f244e957ce9dba9e55a72f", "packages/applications_toolbar/source/app_main.py": "d8797ef1c2c1506b14b24a3602d4f929", "packages/applications_toolbar/source/background.png": "2a3f6737ddbb2a0314cdf2f640b0e929", "packages/applications_toolbar/source/default.png": "b58b2daf9a2a44726b678f235aed41e6", "packages/applications_toolbar/source/down.svg": "fe6b296aa4020dda5c5a870bb7596235", "packages/applications_toolbar/source/install.svg": "699200cfd59967ff740f1e3076795f0f", "packages/applications_toolbar/source/lightening.png": "844cc073cae34c193f3f39335146c955", "packages/applications_toolbar/source/main.py": "f7c06af5e03add541ee260a6224af05a", "packages/applications_toolbar/source/package.svg": "db8542fb863117d5d74f7a6676ab419e", "packages/applications_toolbar/source/qt-logo.png": "9a2446007bbc869ee1ef00479fc73872", "packages/applications_toolbar/source/run.png": "fcf7e23f264801b79df841dabdab9417", "packages/applications_toolbar/source/run.py": "931bb2658ec5554a4f1cbb7424736f5a", "packages/applications_toolbar/source/settings.png": "b9f8edfca0a36df8f3d445f61683511d", "packages/applications_toolbar/translations/qt_zh_CN.qm": "e613b5296764ff24e04450243de3e383", "packages/applications_toolbar/translations/qt_zh_CN.ts": "242fdca10f7405da10eae48f2244e13f", "packages/applications_toolbar/ui/app_designer.py": "b90e5fb6a0430ceb7bb74533ca4d198a", "packages/applications_toolbar/ui/app_designer.ui": "363e995f6861e7817a27e577d236233c", "packages/code_editor/debugger.py": "a19f564dddb9df36cfd14779dfea943c", "packages/code_editor/main.py": "0b3fc0dfb3c49a9dbe74a02f881b36a7", "packages/code_editor/package.json": "f529dee72a413f5d0d92b62ffeaad59b", "packages/code_editor/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/code_editor/README.md": "2918b5e59be436e278047961adb8afeb", "packages/code_editor/toolbar.py": "26ea5eb990d08893ee848dd86768aaba", "packages/code_editor/codeeditor/abstracteditor.py": "b1556e7c0b64c122e8dc6b295b9d9cc9", "packages/code_editor/codeeditor/autocomplete.py": "85443f0a05636004d73019442ca2d628", "packages/code_editor/codeeditor/flake8_trans.json": "745c056024e394cd874a60a0569de1b3", "packages/code_editor/codeeditor/infer.py": "7a9c311fd78ce3afe093bced75ff8fb0", "packages/code_editor/codeeditor/markdowneditor.py": "710b73d04dbf40dbda4c8a9516f1cdb9", "packages/code_editor/codeeditor/pythoneditor.py": "6eb09191f31b0d9a3752e13e3cef6098", "packages/code_editor/codeeditor/syntaxana.py": "b41485288a49c5e9dff3babfdbaa3a3b", "packages/code_editor/codeeditor/tabwidget.py": "e8c6177923b12a377116f65e2045fac3", "packages/code_editor/codeeditor/__init__.py": "de948222f3aba39724a6583a7c1d818f", "packages/code_editor/codeeditor/config/.flake8": "5706c8ed878411a63a6dd9827224e010", "packages/code_editor/codeeditor/config/.style.yapf": "0d898fa79efa8db79c72c151658d26aa", "packages/code_editor/codeeditor/config/.style.yapf.zh": "3f98dd47e54c916665839ab5fe9c5b8c", "packages/code_editor/codeeditor/errors_translation/translate.py": "750d35adf1c925d4e54c5afc6bd4471b", "packages/code_editor/codeeditor/errors_translation/translations.txt": "ec6b11469cf13cc49f53f144a3048952", "packages/code_editor/codeeditor/qtpyeditor/find_gotoline.py": "98a1a7fd1e0b447a55ce0941984ef809", "packages/code_editor/codeeditor/qtpyeditor/linenumber.py": "0dbc3249db663a0d338ec4630a8b857a", "packages/code_editor/codeeditor/qtpyeditor/syntaxana.py": "ccfed05306fc8e31513e4138fc6cb197", "packages/code_editor/codeeditor/qtpyeditor/__init__.py": "750c4f8fd3d0708b965ba5b6349201df", "packages/code_editor/codeeditor/qtpyeditor/codeedit/basecodeedit.py": "1f47f04069d87c1e49eadcac64e0c546", "packages/code_editor/codeeditor/qtpyeditor/codeedit/pythonedit.py": "1bd34b84907bd2cb9602b28ff87aae23", "packages/code_editor/codeeditor/qtpyeditor/codeedit/__init__.py": "49be4addcaeff7654aa0d9770649c359", "packages/code_editor/codeeditor/qtpyeditor/codeeditor/abstracteditor.py": "ae34418002a69d7872496eb5007842c0", "packages/code_editor/codeeditor/qtpyeditor/codeeditor/baseeditor.py": "81adc6aff2de98db56eb88c22fbea69f", "packages/code_editor/codeeditor/qtpyeditor/codeeditor/pythoneditor.py": "5458fc8ab2d05929fa3a9b6790125554", "packages/code_editor/codeeditor/qtpyeditor/codeeditor/__init__.py": "2d1f567a03ae3b14864c5807c2ecfd90", "packages/code_editor/codeeditor/qtpyeditor/highlighters/python.py": "30f29dea3c0261d114038d049dcb8b9b", "packages/code_editor/codeeditor/qtpyeditor/highlighters/__init__.py": "274aab5f8155ea49df8cc33689fe427a", "packages/code_editor/codeeditor/qtpyeditor/icons/breakpoint.svg": "5225dadbedc9f7bda4bb94fecc75ad53", "packages/code_editor/codeeditor/qtpyeditor/icons/copy.svg": "1c800d6346207003b4d7dc70a11e433f", "packages/code_editor/codeeditor/qtpyeditor/icons/debug.svg": "b931caeb19e4cc175cec44fd8af719f5", "packages/code_editor/codeeditor/qtpyeditor/icons/format.svg": "dccd4600d9450bfe4deb9b244c41e85f", "packages/code_editor/codeeditor/qtpyeditor/icons/help.svg": "edfdb212fdcae3ece7e7c58950a35645", "packages/code_editor/codeeditor/qtpyeditor/icons/python.svg": "d17b75c2256afc9b2beb64afeafbc3e0", "packages/code_editor/codeeditor/qtpyeditor/icons/run.svg": "e00087c6bd323d47d4f70a32a25b5667", "packages/code_editor/codeeditor/qtpyeditor/icons/save.svg": "750627b83e976365fb2d80529cb84a2d", "packages/code_editor/codeeditor/qtpyeditor/icons/spate.svg": "13ab9e2e9d07edf5f7c9cd73560141a7", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/class.png": "c64837c614c385630f360831492d8eb9", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/function.png": "7ee29ba9761700d9c9312f95ab6c799e", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/instance.png": "7ccdeda9723de6cbf234c333abe1d244", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/keyword.png": "babe443bc1400af18df2d5a6cc11cec4", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/module.png": "86eaece57974e3d10eb6e175d650abf6", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/param.png": "74e736a865157eb31e015effb34df17b", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/path.png": "7e01e98822f89b5e7bb64c2ead585aa0", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/property.png": "3f6aebb5a4862a8adca6d82dc724ab5e", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/statement.png": "d16ab05b46ff0f6ed3b6421a2a66dab0", "packages/code_editor/codeeditor/qtpyeditor/translations/qt_zh_CN.qm": "2c896338c3b1b75508a842cf534d7cbf", "packages/code_editor/codeeditor/qtpyeditor/translations/qt_zh_CN.ts": "5382de30cc1e09a23252d66ca93b27db", "packages/code_editor/codeeditor/qtpyeditor/ui/findinpath.py": "14fa54fbcf8cb34804f6ef075c4267e6", "packages/code_editor/codeeditor/qtpyeditor/ui/formeditor.py": "1da95795442e26ab7bb522dc811aae50", "packages/code_editor/codeeditor/qtpyeditor/ui/gotoline.py": "609b6fb7d45a04b898878cab26938277", "packages/code_editor/codeeditor/qtpyeditor/ui/ui_formeditor.py": "2d559bafc1b0d8819e62eea2f875de8d", "packages/code_editor/codeeditor/qtpyeditor/ui/ui_gotoline.py": "1827eee50b32b313d397027c46dc020b", "packages/code_editor/codeeditor/qtpyeditor/ui/__init__.py": "de948222f3aba39724a6583a7c1d818f", "packages/code_editor/codeeditor/qtpyeditor/Utilities/autocomp.py": "7adde398458535177d586db7da6eb151", "packages/code_editor/codeeditor/qtpyeditor/Utilities/__init__.py": "d7a23951afba6034e252ea600119c242", "packages/code_editor/codeeditor/simpleeditor/lexer": "d41d8cd98f00b204e9800998ecf8427e", "packages/code_editor/codeeditor/simpleeditor/__init__.py": "fbc8e0505acbb7662554aa0ebf010dd8", "packages/code_editor/codeeditor/tests/get_flake8_output.py": "d6a5545ac0b49483aed41b5059276d1e", "packages/code_editor/codeeditor/tests/get_yapf_output.py": "f6a13da53a21f87d7f5d9fbd0e9a22fa", "packages/code_editor/codeeditor/tests/test_file.py": "4ed78c29dfa08ff34bff564bd39545c4", "packages/code_editor/codeeditor/tests/theme_xml_json.py": "86f8b53c91b4d974acafc78c7a9e399c", "packages/code_editor/codeeditor/themes/Material-Dark.xml": "32f09404512dea8a892ef0095e659ae3", "packages/code_editor/codeeditor/themes/Obsidian PyCs.xml": "934cfd0236acebfaa37bc76516e4cc12", "packages/code_editor/codeeditor/themes/tomorrow.xml": "4f226a7b073ea417d6eca69bdf0e999a", "packages/code_editor/codeeditor/themes/tomorrow_night.xml": "5b7770abad7ab117727e91351140724f", "packages/code_editor/codeeditor/themes/tomorrow_night_bright.xml": "ba3f13a083f3b0aa8f8332e90b4fbb86", "packages/code_editor/codeeditor/tools/eric6_api.py": "72d2e6ee453be1f17e6c0382eb99d344", "packages/code_editor/codeeditor/tools/__init__.py": "9aa13d467aa7ca6ca94b283dea7e5c22", "packages/code_editor/codeeditor/tools/DocumentationTools/APIGenerator.py": "a725a1b2ffcbc8fc98f9e69b252f73ae", "packages/code_editor/codeeditor/tools/DocumentationTools/__init__.py": "f5dba5378fa551d11f098318de65a4a1", "packages/code_editor/codeeditor/tools/QScintilla/Editor.py": "3e5f9b7d8c00734ed27c85bd1de63906", "packages/code_editor/codeeditor/tools/QScintilla/__init__.py": "e58d1155053d6b3763c2ed9f92ca9e57", "packages/code_editor/codeeditor/tools/Utilities/ModuleParser.py": "be326e07e15841196ec7d752417cc6e2", "packages/code_editor/codeeditor/tools/Utilities/__init__.py": "65ffafe4bc9cd6a17832f441036cdb63", "packages/code_editor/codeeditor/ui/formeditor.py": "1da95795442e26ab7bb522dc811aae50", "packages/code_editor/codeeditor/ui/gotoline.py": "2ea843566488cd151da2f6cab335625f", "packages/code_editor/icons/breakpoint.svg": "5225dadbedc9f7bda4bb94fecc75ad53", "packages/code_editor/icons/copy.svg": "1c800d6346207003b4d7dc70a11e433f", "packages/code_editor/icons/debug.svg": "b931caeb19e4cc175cec44fd8af719f5", "packages/code_editor/icons/format.svg": "dccd4600d9450bfe4deb9b244c41e85f", "packages/code_editor/icons/help.svg": "edfdb212fdcae3ece7e7c58950a35645", "packages/code_editor/icons/python.svg": "d17b75c2256afc9b2beb64afeafbc3e0", "packages/code_editor/icons/run.svg": "e00087c6bd323d47d4f70a32a25b5667", "packages/code_editor/icons/save.svg": "750627b83e976365fb2d80529cb84a2d", "packages/code_editor/icons/spate.svg": "13ab9e2e9d07edf5f7c9cd73560141a7", "packages/code_editor/source/lightening.png": "844cc073cae34c193f3f39335146c955", "packages/code_editor/translations/qt_zh_CN.qm": "8e43fef9f53d43e8b693fc52984742d6", "packages/code_editor/translations/qt_zh_CN.ts": "20d10e3f79c729e1c90cbc88858cfd36", "packages/dataio/accountutil.py": "98a4758a6a1b11f7ee17f08e8b6c03d8", "packages/dataio/database_sample.py": "40b1c25397f6ddea9fb38029ee97eaea", "packages/dataio/dataImportModel.py": "88792dc540a80f0a5b22a7de6f3f1b12", "packages/dataio/dbimport.py": "6e4e64e8277a17c0fd21748ee7612b9a", "packages/dataio/dbindexing.py": "8d8d88e3a62cd935519aa4716218fac9", "packages/dataio/export.py": "ba01392157f6058a0d3a2a6f65a82b46", "packages/dataio/exportutils.py": "71a15223db0b6f6ef4bbe7e5ad31a4b6", "packages/dataio/importutils.py": "138d86b798b92d45639791ef57285981", "packages/dataio/main.py": "194549d322dbcea58329cff2cd5d7104", "packages/dataio/package.json": "a857dcfa80f7bbe16b29d447684fede6", "packages/dataio/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/dataio/README.md": "2918b5e59be436e278047961adb8afeb", "packages/dataio/sample.py": "346de2707ffbf2cd036b19b6911be5ff", "packages/dataio/settings.json": "d41d8cd98f00b204e9800998ecf8427e", "packages/dataio/dataUI/data_import_csv.py": "6b0ffb99fdb1d3bc68a61ca6a9169063", "packages/dataio/dataUI/data_import_csv.ui": "47c21370141a61960861b65836e7287b", "packages/dataio/dataUI/data_import_excel.py": "17b37971c44f89cdc5cef09c4ae742ef", "packages/dataio/dataUI/data_import_excel.ui": "2038dabc9e1caea8e1328b64fb10dc89", "packages/dataio/dataUI/data_import_matlab.py": "eccad7dc8726499702e75adcb6eb64d4", "packages/dataio/dataUI/data_import_matlab.ui": "4ae19c223a9d60139a73f2b1c553c64a", "packages/dataio/dataUI/data_import_model.py": "6732462f2b28d1228e6b6429d8f820cb", "packages/dataio/dataUI/data_import_model.ui": "6c61ace6854928adfb4c6ea8eff19fb5", "packages/dataio/dataUI/data_import_mysql.py": "10024040b895e1f7a0761cf41ed569aa", "packages/dataio/dataUI/data_import_mysql.ui": "bab2eaf2057d9175638198f14fb5f599", "packages/dataio/dataUI/data_import_oracle.py": "8068996f5d6395e95e878c341273ceb2", "packages/dataio/dataUI/data_import_oracle.ui": "c7d90bb98b8d4c0d5401eca7bcabe7ec", "packages/dataio/dataUI/data_import_postgresql.py": "c5404dc63e987cd2ed07d2b2424d5dac", "packages/dataio/dataUI/data_import_postgresql.ui": "b9a515989b036b7466bc2edd325b6eb1", "packages/dataio/dataUI/data_import_sas.py": "428fd62424d9e21c3d5bdc67ad2474a2", "packages/dataio/dataUI/data_import_sas.ui": "1f8667b3667d2baba53533b938b1a6a9", "packages/dataio/dataUI/data_import_spss.py": "8a1154c9315758ad9fa8bc96bfa1a367", "packages/dataio/dataUI/data_import_spss.ui": "35e2eb820c7e69bef4f06bbce6344c19", "packages/dataio/dataUI/data_import_stata.py": "102a879258cfbb70afc5815684e53b93", "packages/dataio/dataUI/data_import_stata.ui": "fd01ec0806b50f0dbbe7df3ae5578bcb", "packages/dataio/dataUI/data_import_text.py": "347f0183bb4055c43993f5ed84ae3d6c", "packages/dataio/dataUI/data_import_text.ui": "c8cc49a3ee1b2c4209c5c9ffe92fcfd8", "packages/dataio/dataUI/display.png": "38a696b77d8e89b1f24e3077184f3588", "packages/dataio/dataUI/hide.png": "80009586668a32b1a0bcdc5fb1854ac4", "packages/dataio/dataUI/password.py": "c174715c922460e682382cc1a4c9076f", "packages/dataio/dataUI/__init__.py": "cddad8a43ae85331e7fc60b6c4783a14", "packages/document_server/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/document_server/index.rst": "de08e1d943a610a1d4b61de487fc9606", "packages/document_server/main.py": "8e52c195bd0de7649b208fe9431fac90", "packages/document_server/package.json": "d552267ae466f74d360aa2dde9707999", "packages/document_server/settings.json": "ac084b924952c4c88e397f5c1f64c893", "packages/document_server/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/document_server/docserver/renderer.py": "0d2b8fa90287c98d2b2ea47893d902fd", "packages/document_server/docserver/server.py": "b525026a556b339079d30c4294e7fd60", "packages/document_server/docserver/__init__.py": "f64b6b6963038b02a0fafec97cb826da", "packages/document_server/docserver/static/css/main.css": "514ba05b769e4a20a328f77267aeb3a0", "packages/document_server/docserver/static/css/main.css.map": "db360aa1e642da89de3240fed50e4432", "packages/document_server/docserver/static/css/main.sass": "7b0d06ed553c19887a7dcad5bb97e954", "packages/document_server/docserver/static/js/main.js": "52a8a678ac589478f5b97e88066109c6", "packages/document_server/docserver/static/mathjax/tex-mml-svg.js": "2ac6956d3f16edb119f3b5686ef933d5", "packages/document_server/docserver/templates/content.html": "7420679eb81eea0ca7b9e98972b49160", "packages/document_server/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/document_server/translations/zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/drawings_toolbar/group_chart.py": "846a72c9e0303f8ef4b5c6b809f07db7", "packages/drawings_toolbar/ipython_console.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/drawings_toolbar/main.py": "6d8e3f8e511fa3ec1186e59c68487b69", "packages/drawings_toolbar/map_var.json": "91324fe1e6b292ebc2d548f3ae7d49b7", "packages/drawings_toolbar/map_var.py": "46e4e76e96cb5691754e4b63a38b67d9", "packages/drawings_toolbar/package.json": "95e01099cdd1f73595c179112383e45a", "packages/drawings_toolbar/radar_chart.py": "67ea13759ea77d67006df488c9fde4e0", "packages/drawings_toolbar/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/drawings_toolbar/fastui/base.py": "5aabafefad5433391c67bf5f5749141f", "packages/drawings_toolbar/fastui/draw_boxplot.py": "54cc901679b29dc27fbaa8c12a458daf", "packages/drawings_toolbar/fastui/draw_hist.py": "97f5fd773217c53c26c9d44c6905f8cf", "packages/drawings_toolbar/fastui/functions.py": "2756f0633851f7605644c78de2f9e7b6", "packages/drawings_toolbar/fastui/plot.py": "c52ba2a8e3dc27b6397480b316f3f745", "packages/drawings_toolbar/fastui/__init__.py": "b3f689f89235e0fd970023fb1910ebaa", "packages/drawings_toolbar/fastui/helps/boxplot.md": "c28b070128b33660fd657c82d7bd2d54", "packages/drawings_toolbar/fastui/helps/markers.md": "35a158b4cb160219a0d5f4c89025f50c", "packages/drawings_toolbar/fastui/helps/plot.md": "9a819ab6bdf462d779ff742d77e49526", "packages/drawings_toolbar/pmmap/china/all/01-beijing.npy": "05fc6e35605340ef6e4d62af9770ef7a", "packages/drawings_toolbar/pmmap/china/all/02-shanghai.npy": "dbd37714da88edf44df7a2642ce2c14f", "packages/drawings_toolbar/pmmap/china/all/03-tianjin.npy": "e767b1d0810acfd174d4b52586441de1", "packages/drawings_toolbar/pmmap/china/all/04-chongqing.npy": "1980444de2496af7ae7b11cae9372d2c", "packages/drawings_toolbar/pmmap/china/all/05-heilongjiang.npy": "f369a349db31ac0636e625737802922e", "packages/drawings_toolbar/pmmap/china/all/06-neimeng.npy": "0366d9f95bfe2e0768a6491f8f5e27cc", "packages/drawings_toolbar/pmmap/china/all/07-xinjiang.npy": "201b3ff97375ae9ba6e9fc9c7b0eed1e", "packages/drawings_toolbar/pmmap/china/all/08-jilin.npy": "0ed85b6d84b877cf07154e1b54db0bdd", "packages/drawings_toolbar/pmmap/china/all/09-gansu.npy": "08c6e4437a0fc5d19d6c655a14a7df2e", "packages/drawings_toolbar/pmmap/china/all/10-liaoning.npy": "542d598f5c39b363738b0b753d8318d1", "packages/drawings_toolbar/pmmap/china/all/11-hebei.npy": "5a7ce525859caabaffad0fe1c11cb26f", "packages/drawings_toolbar/pmmap/china/all/12-shanxi.npy": "5ebb5347431393d599f5f0d36a31dd07", "packages/drawings_toolbar/pmmap/china/all/13-shan3xi.npy": "71944b8eea6caa0b7e4138063d6e8945", "packages/drawings_toolbar/pmmap/china/all/14-ningxia.npy": "dc0660ac4216cb4e928fb08dba5e36fb", "packages/drawings_toolbar/pmmap/china/all/15-qinghai.npy": "46f4e9bf9a47734d0cfbef0916e6cec1", "packages/drawings_toolbar/pmmap/china/all/16-shandong.npy": "b3eee97751e252f1c729b20cde81220c", "packages/drawings_toolbar/pmmap/china/all/17-henan.npy": "530d73e54901bf816e61c86bafb97219", "packages/drawings_toolbar/pmmap/china/all/18-xizang.npy": "83c873032100d735d2a3c1becb4e4ee5", "packages/drawings_toolbar/pmmap/china/all/19-jiangsu.npy": "33051765300de0a9d003ea91c3846cc6", "packages/drawings_toolbar/pmmap/china/all/20-anhui.npy": "d80f40e27c3a60188547d058c827eae0", "packages/drawings_toolbar/pmmap/china/all/21-sichuan.npy": "115e4b1abbc6df1f862095e94cacb8b5", "packages/drawings_toolbar/pmmap/china/all/22-hubei.npy": "065b61ce8a2728be70d0e726990e42c2", "packages/drawings_toolbar/pmmap/china/all/23-zhejiang.npy": "6910df476893b4e5a84689094203b724", "packages/drawings_toolbar/pmmap/china/all/24-jiangxi.npy": "2d4e166cd8d9371a1c6d01848ece3301", "packages/drawings_toolbar/pmmap/china/all/25-hunan.npy": "ddbce0334a1f79bd77f7b0ae582dd28e", "packages/drawings_toolbar/pmmap/china/all/26-guizhou.npy": "4d23f4f330203b61c6f8cca0ac764819", "packages/drawings_toolbar/pmmap/china/all/27-yunnan.npy": "1d1c9378c8427667dbf0b8948c36b484", "packages/drawings_toolbar/pmmap/china/all/28-fujian.npy": "77270ff92f0d67f0123672527b70772a", "packages/drawings_toolbar/pmmap/china/all/29-guangxi.npy": "3862d0becc054fe754ae71c111c583ad", "packages/drawings_toolbar/pmmap/china/all/30-guangdong.npy": "7d7f1392cc01a22d4503354ce7c729b1", "packages/drawings_toolbar/pmmap/china/all/31-taiwan.npy": "2f398da02605db2be30751dedb92ea90", "packages/drawings_toolbar/pmmap/china/all/32-xianggang.npy": "b3cf9d637c7d87e82a86174f99be74da", "packages/drawings_toolbar/pmmap/china/all/33-aomen.npy": "68e3c682aef3e25cf873878a19df5361", "packages/drawings_toolbar/pmmap/china/all/34-hainan.npy": "a67e27cc4f68d566f6977580d95b006c", "packages/drawings_toolbar/pmmap/china/all/39-jiuduan.npy": "35fbdcbb72d2c22caab9b1bfd2eba401", "packages/drawings_toolbar/pmmap/china/small/30-guangdong.npy": "7d7f1392cc01a22d4503354ce7c729b1", "packages/drawings_toolbar/pmmap/china/small/31-taiwan.npy": "2f398da02605db2be30751dedb92ea90", "packages/drawings_toolbar/pmmap/china/small/32-xianggang.npy": "b3cf9d637c7d87e82a86174f99be74da", "packages/drawings_toolbar/pmmap/china/small/33-aomen.npy": "68e3c682aef3e25cf873878a19df5361", "packages/drawings_toolbar/pmmap/china/small/34-hainan.npy": "a67e27cc4f68d566f6977580d95b006c", "packages/drawings_toolbar/pmmap/china/small/39-jiuduan.npy": "35fbdcbb72d2c22caab9b1bfd2eba401", "packages/drawings_toolbar/source/down.svg": "fe6b296aa4020dda5c5a870bb7596235", "packages/drawings_toolbar/source/erase.png": "68beac11764738b4fd52d367e5ad8223", "packages/drawings_toolbar/source/grid.png": "a39688f7d385bf86ba28eaf9d63a286d", "packages/drawings_toolbar/source/label.png": "2289b06fad4b39ea868450cdfbdc5eea", "packages/drawings_toolbar/source/monitor.png": "7272e1f62681d4200a2d778ec3df27e5", "packages/drawings_toolbar/source/plot.svg": "05fd271af6c134f6872c80c489064d60", "packages/drawings_toolbar/source/split.png": "d3cdd812358fd82f19500d8ac1bbc3be", "packages/drawings_toolbar/source/ticks.png": "2165ab858f8de60f5132e861740f7699", "packages/drawings_toolbar/source/\u5730\u56fe.png": "eca50b3207a973738145d1cf12ca0c34", "packages/drawings_toolbar/source/\u6298\u7ebf\u56fe.png": "1bde0eca8cfa880452accf56ca925866", "packages/drawings_toolbar/source/\u6563\u70b9\u56fe.png": "78c432bb278d8ea5c9587f23ffdd5f82", "packages/drawings_toolbar/source/\u6761\u5f62\u56fe.png": "b07f4db5b1785376f97636fc6963234e", "packages/drawings_toolbar/source/\u67f1\u5f62\u56fe.png": "d6cba37e00bf9bbeb65235897a7b90b9", "packages/drawings_toolbar/source/\u6c14\u6ce1\u56fe.png": "d6784d4c53145cce1fde17f673b76984", "packages/drawings_toolbar/source/\u70ed\u529b\u56fe.png": "566d7c6ad396084ca6b7d490868fdc2c", "packages/drawings_toolbar/source/\u76f4\u65b9\u56fe.png": "87113fa7353e0342248a7c953949079e", "packages/drawings_toolbar/source/\u7bb1\u7ebf\u56fe.png": "ba733c4c1a0979ab5bc838149490e915", "packages/drawings_toolbar/source/\u7ec4\u5408\u56fe.png": "c5bea73cff095ad47bd07e1e81921ab2", "packages/drawings_toolbar/source/\u96f7\u8fbe\u56fe.png": "5aa1a48424b30a157a2bca181c9be2d0", "packages/drawings_toolbar/source/\u9762\u79ef\u56fe.png": "69682cc944d7afdd5c1f2019bf6ca21c", "packages/drawings_toolbar/source/\u997c\u56fe.png": "862b6c81a5752ee7d53500ce9064c10d", "packages/drawings_toolbar/translations/qt_zh_CN.qm": "cd23a7e488d169790b204929188d78e7", "packages/drawings_toolbar/translations/qt_zh_CN.ts": "ce76ad850f047e2cea0440e4dab7c7d4", "packages/embedded_browser/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/embedded_browser/index.rst": "f1825ba1705fc05e593342e0eb4d2800", "packages/embedded_browser/main.py": "23ad2b340856b4ee181f560c6234655c", "packages/embedded_browser/package.json": "662baeb4c74d3c20f8a4604a7a9922df", "packages/embedded_browser/settings.json": "ac084b924952c4c88e397f5c1f64c893", "packages/embedded_browser/webbrowser.py": "d9038ba9457b984e37a4ae1e19ab636a", "packages/embedded_browser/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/embedded_browser/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/embedded_browser/translations/zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/extension_demo/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/extension_demo/main.py": "b776c52a5c366b88629c1c12a0c4da57", "packages/extension_demo/package.json": "fe0c68ec838785d4f8ae971ce415f6db", "packages/extension_demo/settings.json": "ac084b924952c4c88e397f5c1f64c893", "packages/extension_demo/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/extension_demo/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/extension_demo/translations/zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/file_tree/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/file_tree/file_tree.py": "b65b3a68d28d55db5bfc3bfb1adecee2", "packages/file_tree/main.py": "210493015e96aecac98bba55bd57674b", "packages/file_tree/package.json": "0e08e253fce09755a4d9758cb55b3900", "packages/file_tree/settings.json": "5502d6d53ce7276a7cdaa1ef54315efb", "packages/file_tree/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/file_tree/src/up.svg": "cef12db3d43301347f3d556eb9499a6c", "packages/file_tree/translations/qt_zh_CN.qm": "76f4ace00b4ef9e66503cb39d5c9ab5d", "packages/file_tree/translations/qt_zh_CN.ts": "eefaa8ed0d5717aab5253c74ea7d6a3a", "packages/graph_agg/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/graph_agg/graph_agg.py": "7ebd645f566d7412c3af7de2865d2896", "packages/graph_agg/graph_agg_ui.py": "61edf67aebb1d89f92d604a8d22c1200", "packages/graph_agg/graph_agg_ui.ui": "45c54e740ed679ebcdc66594709eaf9f", "packages/graph_agg/main.py": "3399d8c6899a36a92b1910d55d05ea96", "packages/graph_agg/package.json": "b2bfcc74063422e491d0c3df279bbc38", "packages/graph_agg/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/ipython_console/commandparser.py": "8df507247c3112a5a164a961f8b154b5", "packages/ipython_console/index.rst": "de4df58d8cb7a27038ea01f08d3e74c9", "packages/ipython_console/initialize.py": "f75a73ebb2b6af4e198d47cb326ac8c6", "packages/ipython_console/ipythonqtconsole.py": "715c9c195c300400bd24375a2c0f2cac", "packages/ipython_console/ipython_console.jpg": "e2c98aceacdcf9370be0234c1ae56660", "packages/ipython_console/main.py": "764879652c234804c28091c167e8506f", "packages/ipython_console/package.json": "330d1b64fd0fa236f68e4e9148d7f2ff", "packages/ipython_console/README.md": "d91f325d8113d754239f36ebf6211e2d", "packages/ipython_console/requirements_ipython_node.txt": "7e2992fb7c705a5cc8a817af37b0b890", "packages/ipython_console/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/ipython_console/translations/qt_zh_CN.qm": "d32941bf701e20d30c70b509e3421f26", "packages/ipython_console/translations/qt_zh_CN.ts": "ae95465c0df4254a53d4144fd5a90148", "packages/jupyter_notebook_support/client.py": "64707c4c5af928668dfe5624020ab381", "packages/jupyter_notebook_support/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/jupyter_notebook_support/ipython_data_show.py": "ba5fafcca30e9db07a1330fb143b539d", "packages/jupyter_notebook_support/main.py": "1961046decf8e842648695f64f4a951a", "packages/jupyter_notebook_support/package.json": "8f1bbf103ab237adf5e932d77304bab6", "packages/jupyter_notebook_support/route.py": "d63fb2946b16cecd4c03b63b96b417fa", "packages/jupyter_notebook_support/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/jupyter_notebook_support/scripts/pyminer_ipython_node.py": "5afb85f04995a313be86875d55896b8f", "packages/jupyter_notebook_support/tests/exec_api_test.py": "db3498a3620bc730a093106024c3d895", "packages/jupyter_notebook_support/tests/find_free_port.py": "7519a17439dd072a5f5609dccf71acff", "packages/jupyter_notebook_support/tests/find_kernel_spec.py": "5e494c2592bc747a166f3e5eb1fdb0d2", "packages/jupyter_notebook_support/tests/jupyter_client_test.py": "cd2193f167111e6f74a51ce27671b6e0", "packages/jupyter_notebook_support/tests/list_running_jupyter_servers.py": "decfc524233da897d5ae4e0896ad42bf", "packages/jupyter_notebook_support/tests/test.json": "fd0693bed89aa001426c855cf60719da", "packages/jupyter_notebook_support/tests/Untitled.ipynb": "0eca040919ec50b82d4197e13564f3f8", "packages/jupyter_notebook_support/tests/.ipynb_checkpoints/Untitled-checkpoint.ipynb": "2f6cceae1d861df553a6ebb64b6862ef", "packages/jupyter_notebook_support/translations/qt_zh_CN.qm": "910b1a4eece778fe19eb8c37d856219b", "packages/jupyter_notebook_support/translations/qt_zh_CN.ts": "a52f5f65e0ebc5ef1c4c205d8b977e5b", "packages/pmagg/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/pmagg/LICENSE": "e49f4652534af377a713df3d9dec60cb", "packages/pmagg/main.py": "26f2abd09259651ad17e35b24de5a097", "packages/pmagg/package.json": "3f5b1d4110de43c171ec51876448d516", "packages/pmagg/PMAgg.py": "51be8eab2ca29167621904193a7d94e0", "packages/pmagg/Readme_CN.md": "b120eff0eec50462b099a5afc44e8135", "packages/pmagg/setup.py": "c819982245570068aeff72f2c4925d3c", "packages/pmagg/unit_test.py": "6cc0c2b57eebac72cb159bdb73dae6dd", "packages/pmagg/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pmagg/icons/annotation.png": "41abc31827d980673cb4b774d9cfc589", "packages/pmagg/icons/arrow.png": "faea79dbbe13b73b2b6b2d381d3f0b04", "packages/pmagg/icons/axis.png": "8aad7c4a25caea1eab5e00416383fe87", "packages/pmagg/icons/back.png": "7e3a69ff1b93c0d922903ca9753d9413", "packages/pmagg/icons/colorbar.png": "51edcf418f2920bcc55e703956345d22", "packages/pmagg/icons/figure.png": "6c84c49ce26f638a352654df89ee3d35", "packages/pmagg/icons/front.png": "b3675ce85ff0c87602fcee821606b376", "packages/pmagg/icons/grid.png": "f495112a5ee666819bccc792ac9ab480", "packages/pmagg/icons/home.png": "e4a7f4019b4ea9cb1f375da78a2e5adf", "packages/pmagg/icons/Icon.ico": "3fe019a16833a4b89743e829706a22a6", "packages/pmagg/icons/image.png": "9a685d94a08e6dab95ab996ac36c3019", "packages/pmagg/icons/layout.png": "113fcb65d470b3c44eca07a69883b067", "packages/pmagg/icons/legend.png": "4554646775b8caab3af239051e231530", "packages/pmagg/icons/line.png": "0ad86f368735816bb25dae9a6037d042", "packages/pmagg/icons/oval.png": "bf5e995685d6bd1758ddc56db9a706c1", "packages/pmagg/icons/pan.png": "d31d48619f6187a992f8bc51f4bbbf31", "packages/pmagg/icons/point.png": "6ea950ae1d8f16fc9d364dea468e1bf6", "packages/pmagg/icons/polygon.png": "a7d892e0a3ca8e00aefc73211cc211aa", "packages/pmagg/icons/rect.png": "9088ab4129c08c3370675a27c5af7f76", "packages/pmagg/icons/rotate.png": "b058a0e469a679d752ea393eb8b94204", "packages/pmagg/icons/save.png": "1f019d1efc880a99aa0d6c413d4b1672", "packages/pmagg/icons/setting.png": "2ca8a4d585232a124bc8f8bbaf913eec", "packages/pmagg/icons/space.png": "a63438f63e5c9a61ae377f92e4638427", "packages/pmagg/icons/style.png": "5479b633bfd95b75aca566d283f90f2d", "packages/pmagg/icons/text.png": "2d058b7289a520eb1087ea7957e85a18", "packages/pmagg/icons/X_axis.png": "81b2fbfd328ea56e03bbac9d98f54bd0", "packages/pmagg/icons/Y_axis.png": "dec07bca2db81b7a13d05cf63147042c", "packages/pmagg/icons/zoom.png": "624d6036e5af3901a672926eed0cfd74", "packages/pmagg/icons/Z_axis.png": "4ef63246be7447c74de3fc6352f56782", "packages/pmagg/langs/en_axes_control.qm": "3e31bb846d2075752f2083796bbab081", "packages/pmagg/langs/en_axes_control.ts": "e3f2a95ffc1ee822600420487fc64497", "packages/pmagg/langs/en_pmagg_ui.qm": "0d72b1e6a3868f6a9d7f4353dc49da57", "packages/pmagg/langs/en_pmagg_ui.ts": "c40ed0942c1fc822cbfdac7d51728e15", "packages/pmagg/langs/zh_CN_axes_control.qm": "43c4b723bf698383102abf57ae7ff375", "packages/pmagg/langs/zh_CN_axes_control.ts": "b69e3a2583aab4d47e9042151ddd4431", "packages/pmagg/langs/zh_CN_pmagg_ui.qm": "bcebcf42735c6849bdecbb77451021dd", "packages/pmagg/langs/zh_CN_pmagg_ui.ts": "a924984618a9687fe9bed9cd1ab3e8bd", "packages/pmagg/pictures/pmagg_api.mmd": "3c46f4d87fb3706b4b1bd70b7e442a5d", "packages/pmagg/pictures/pmagg_api.png": "822f49430932514591eda54acfc10a1f", "packages/pmagg/pictures/pmagg_show.png": "5dc944f02aa22177c5c24ab1f71a391d", "packages/pmagg/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/pmagg/translations/zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/pmagg/ui/arrow_setting.py": "d8e8f2f7101729c6ced2cd4f4dd0ee6d", "packages/pmagg/ui/axes_control.py": "b232825bef4aa017e9bbf92b57640f49", "packages/pmagg/ui/axis_edit.py": "4875d36d29871c4d87c05108117d9f9f", "packages/pmagg/ui/axis_edit.ui": "f7b92a8a5d9b4ca769bf42ebdb34577a", "packages/pmagg/ui/axis_edit_manager.py": "e2245787fc389cb116ca56c37131addd", "packages/pmagg/ui/colorbar_setting.py": "46a557021eeeefe8c56bf5f9e26629cd", "packages/pmagg/ui/color_table.py": "e209c8c3d24f582978ca33100de623a5", "packages/pmagg/ui/default_setting.py": "5846b7322727ee4b19dc7b6c336d1947", "packages/pmagg/ui/default_setting.ui": "b93e791244d7912a51bbaf75a2deff38", "packages/pmagg/ui/default_setting_manager.py": "c06f05023a1bbd6eb754b0e68209fca6", "packages/pmagg/ui/ellipse_setting.py": "4d24440e44796ada3a73a387600899fc", "packages/pmagg/ui/image_setting.py": "6e909b7852eb02a52455a9aa36da7bed", "packages/pmagg/ui/legend_setting.py": "6e3a19772353cdf39944df1e4faa17dd", "packages/pmagg/ui/line2d_setting.py": "470ef26ff8d454e8247f37277d5a785a", "packages/pmagg/ui/linestyles.py": "648f0a673e71e4d08c98e0cc6864202e", "packages/pmagg/ui/pmagg_ui.py": "0ac0c186e7177a3a9c6aee2d9d409177", "packages/pmagg/ui/pmagg_ui.ui": "f1a0f6ff01e632a4994f00258356911f", "packages/pmagg/ui/rectangle_setting.py": "3080ff255cfe2378777f68025e61f2c4", "packages/pmagg/ui/save_image_setting.py": "16036a37904ffa3f20fecc7d004b009f", "packages/pmagg/ui/text_setting.py": "34de8bed7cf453d59fe938be0fbfe92c", "packages/pmagg/ui/title_setting.py": "ebdf8cbd5684278ec81c9cdde176b684", "packages/pmagg/ui/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pm_calc/ipython_console.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/pm_calc/main.py": "83b0f01515be0f4f76da807e9cb61125", "packages/pm_calc/package.json": "9fdd3a4c9b4a20d39944e5f390642e1e", "packages/pm_calc/preprocess.py": "a8c8d1cb131393e4bf0a6e43503f5c7b", "packages/pm_calc/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pm_calc/fastui/base.py": "76ac4b617688dfeb97d75c73803dcd44", "packages/pm_calc/fastui/create_random_variable.py": "fa6d77ce65a13e4974da9f5a33516d2a", "packages/pm_calc/fastui/create_tensor.py": "bde0d9952e2ab26e9fb5f47cf8fff98a", "packages/pm_calc/fastui/create_vector.py": "cb707dcfefc1f308d25c17d6a034cdfc", "packages/pm_calc/fastui/dblquad.py": "5e4c5b60231b67cbe5233de0b555f308", "packages/pm_calc/fastui/equation_solve.py": "6fdb3b720ad9547553938a3b735bf970", "packages/pm_calc/fastui/matrix_calc.py": "fc4dbc1ce3af2ae26125d1adb7f8f690", "packages/pm_calc/fastui/matrix_inv.py": "bd826082ba2b3c8775563da8c3ee6321", "packages/pm_calc/fastui/matrix_numbers.py": "b9bc2f888b2c98743072fc686e07751f", "packages/pm_calc/fastui/numerical_integration.py": "57edb1443625bdc5d990aa4d99f6272e", "packages/pm_calc/fastui/reshape_tensor.py": "0647e734b05f39cef659c82c315fb023", "packages/pm_calc/fastui/__init__.py": "b3f689f89235e0fd970023fb1910ebaa", "packages/pm_calc/fastui/helps/numerical_integration.md": "df25b4e7795b58e927c62368d814f0ab", "packages/pm_calc/fastui/helps/reshape_tensor.md": "96a600a163541231dc71d43438de0ab4", "packages/pm_calc/icons/create.png": "d94320bc7e7a4dded74f4eda5b6d1c3e", "packages/pm_calc/icons/eigen.png": "97048cae872a927137f5b7295828c5c2", "packages/pm_calc/icons/equation_solve.png": "af3de472d63ef0e8e6005c153d29ad0b", "packages/pm_calc/icons/flip.png": "e769eeaa1f423de72f34dda86f088540", "packages/pm_calc/icons/integrate.png": "0d3a7f301fa771ee8ef56b10541551d9", "packages/pm_calc/icons/matrix.png": "5b97eee2dae1233c831daae04c5dd98f", "packages/pm_calc/icons/matrix_calc.png": "151e56c9e82870f7cf9783971ee37782", "packages/pm_calc/icons/reshape.png": "3ee90fbdcf09e1bcf3f24e13be041530", "packages/pm_calc/icons/rvs.png": "da077db4d3d834bb311f445e6a9a07c7", "packages/pm_calc/translations/qt_zh_CN.qm": "38862557de320f2ff74455ab1c059a5a", "packages/pm_calc/translations/qt_zh_CN.ts": "c17e3ce1dd88a0cfc45d42cd1f706361", "packages/pm_helpLinkEngine/helpLinkEngine.py": "8e712a1e13bd4d0dd0a5f3cbb59212e0", "packages/pm_helpLinkEngine/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pm_marketplace/env_manager.py": "b3d1a95732a2b9c9af7ebb3f2d919f08", "packages/pm_marketplace/env_manager.ui": "c910e7c1fdb7d4931ae6395f32fdb06f", "packages/pm_marketplace/Icon.ico": "3fe019a16833a4b89743e829706a22a6", "packages/pm_marketplace/package_install.py": "3b2122f43e471ed12022254a633e93ea", "packages/pm_marketplace/package_install.ui": "58c036d918d493749750442a6dd6e56c", "packages/pm_marketplace/package_manager.py": "9bc3ebc8d0896b8c90661b5e3e0bab5b", "packages/pm_marketplace/package_remove.py": "2882477a6acf357e401983e64a9e5b3d", "packages/pm_marketplace/package_remove.ui": "cd82652c1c18ce309b7b39f64eb1eb93", "packages/pm_marketplace/package_setting.py": "0900c75df4d09edb2df07df0d40b3893", "packages/pm_marketplace/package_setting.ui": "7294066d39daafe32bfb6e14dc9bd4b2", "packages/pm_marketplace/package_update.py": "7bb12094c0e57a557e2e1d104300e910", "packages/pm_marketplace/package_update.ui": "73dd8b7e55bd1dc9730991b5b9a06fd4", "packages/pm_marketplace/pm_marketplace.py": "c00744c2f27e852e4ad0d2d37df043f7", "packages/pm_marketplace/pm_marketplace.ui": "72b055181d7bd41dbfdd06feac750245", "packages/pm_marketplace/pth_modifier.py": "330f9dce62a058e767c9654020ff2012", "packages/pm_marketplace/__init__.py": "e4e5f41117ada3d729f55649c34a3932", "packages/pm_modelling/default.png": "b58b2daf9a2a44726b678f235aed41e6", "packages/pm_modelling/main.py": "936de10bd651db7f14815477894bed86", "packages/pm_modelling/package.json": "ce1142cf81e5d40919fcce5ebe2ae4f9", "packages/pm_modelling/settings.json": "e4385e0a6554dfe40b3696f328f5edd1", "packages/pm_modelling/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pm_modelling/source/down.svg": "fe6b296aa4020dda5c5a870bb7596235", "packages/pm_modelling/source/plot.svg": "05fd271af6c134f6872c80c489064d60", "packages/pm_modelling/source/\u5730\u56fe.png": "eca50b3207a973738145d1cf12ca0c34", "packages/pm_modelling/source/\u6298\u7ebf\u56fe.png": "1bde0eca8cfa880452accf56ca925866", "packages/pm_modelling/source/\u6563\u70b9\u56fe.png": "78c432bb278d8ea5c9587f23ffdd5f82", "packages/pm_modelling/source/\u6761\u5f62\u56fe.png": "b07f4db5b1785376f97636fc6963234e", "packages/pm_modelling/source/\u67f1\u5f62\u56fe.png": "d6cba37e00bf9bbeb65235897a7b90b9", "packages/pm_modelling/source/\u6c14\u6ce1\u56fe.png": "d6784d4c53145cce1fde17f673b76984", "packages/pm_modelling/source/\u70ed\u529b\u56fe.png": "566d7c6ad396084ca6b7d490868fdc2c", "packages/pm_modelling/source/\u76f4\u65b9\u56fe.png": "a9b01bca53610b2c03f7ea2331c91cc3", "packages/pm_modelling/source/\u7bb1\u7ebf\u56fe.png": "ba733c4c1a0979ab5bc838149490e915", "packages/pm_modelling/source/\u7ec4\u5408\u56fe.png": "c5bea73cff095ad47bd07e1e81921ab2", "packages/pm_modelling/source/\u96f7\u8fbe\u56fe.png": "5aa1a48424b30a157a2bca181c9be2d0", "packages/pm_modelling/source/\u9762\u79ef\u56fe.png": "69682cc944d7afdd5c1f2019bf6ca21c", "packages/pm_modelling/source/\u997c\u56fe.png": "862b6c81a5752ee7d53500ce9064c10d", "packages/pm_modelling/translations/qt_zh_CN.qm": "8a5de3a24facfac59b9b7a95ab7937d7", "packages/pm_modelling/translations/qt_zh_CN.ts": "611800964b03dfef8c1cbc1dc4a0bd9c", "packages/pm_preprocess/base.py": "731a2f17cc570b8b92e5da9e323e07f9", "packages/pm_preprocess/datafilter.py": "ac09562b0e7a6b9094225e01bc70e08c", "packages/pm_preprocess/datamissingvalue.py": "51a2e07966da2b720141bd8cb4721678", "packages/pm_preprocess/datareplace.py": "3cce7391493a104a2fc59a7f792a1883", "packages/pm_preprocess/data_filter.py": "102b1b8071747d6d8ed25530e206c5e7", "packages/pm_preprocess/ipython_console.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/pm_preprocess/main.py": "dd006452670a44799031989f21730175", "packages/pm_preprocess/package.json": "c27f88add11891797e8564867f94abfe", "packages/pm_preprocess/preprocess.py": "a8c8d1cb131393e4bf0a6e43503f5c7b", "packages/pm_preprocess/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pm_preprocess/fastui/base.py": "97be57a24cb88f7de7aee11e768364ab", "packages/pm_preprocess/fastui/datamerge.py": "c11ecb39655996d441747c93d3a82a0a", "packages/pm_preprocess/fastui/dropna.py": "44a433355c6732b5c9a2ceebd2fed587", "packages/pm_preprocess/fastui/fillna.py": "fe5d6a6f14f21db63116e5ece2dcb9c6", "packages/pm_preprocess/fastui/pivot.py": "dc302f4e2a9a0a03f035cb04452dc978", "packages/pm_preprocess/fastui/transpose.py": "b9873caa7d3d698221fcd590eb848e27", "packages/pm_preprocess/fastui/__init__.py": "5774d567a5ade4656321f056692ecf7c", "packages/pm_preprocess/fastui/templates/dropna.json": "2135651085e530edc3555862c807e8a2", "packages/pm_preprocess/fastui/templates/dropna.py": "818d27872b51cabc824f36545e848dc2", "packages/pm_preprocess/fastui/templates/template.py": "ab8ca29cb2d8a0116de63f411ad08729", "packages/pm_preprocess/translations/qt_zh_CN.qm": "38862557de320f2ff74455ab1c059a5a", "packages/pm_preprocess/translations/qt_zh_CN.ts": "c17e3ce1dd88a0cfc45d42cd1f706361", "packages/pm_preprocess/ui/data_column_desc.py": "50e1de93cb2b5af92ef9f70ec61b28ae", "packages/pm_preprocess/ui/data_column_desc.ui": "2e4ff14a2934d2e461967f4adf57d096", "packages/pm_preprocess/ui/data_column_encode.py": "addb53a419ba7aad0c822918bd164584", "packages/pm_preprocess/ui/data_column_encode.ui": "83585c68a1b5f10c8cb5c8f979fc069a", "packages/pm_preprocess/ui/data_column_name.py": "ab1343d7eb25ba61ff00653dc727dcd2", "packages/pm_preprocess/ui/data_column_name.ui": "290d0f3b71254001a41ed5419cfc2aa7", "packages/pm_preprocess/ui/data_delete_column.py": "96cc3bb3a839bf327be48c5b8bcf7b4f", "packages/pm_preprocess/ui/data_delete_column.ui": "eb9f4daa76ea45a80897c7d699f0223a", "packages/pm_preprocess/ui/data_delete_row.py": "302569fa225a51a1f63cc8fd740532f2", "packages/pm_preprocess/ui/data_delete_row.ui": "a2bef2e740f12897748cb3ab8942c994", "packages/pm_preprocess/ui/data_filter.py": "18e9c3b6ec4a59ee18b9304234354fee", "packages/pm_preprocess/ui/data_filter.ui": "6b68ea20099eb2657a83277c2b35c5e2", "packages/pm_preprocess/ui/data_import_database.py": "aa8f2c175707416490b15c5b8a5f91b1", "packages/pm_preprocess/ui/data_import_database.ui": "70081a8159869c52d03f42ff96198bcd", "packages/pm_preprocess/ui/data_import_excel.py": "50eab4e5f295ac1e36b415bc1fc4ce17", "packages/pm_preprocess/ui/data_import_excel.ui": "8e4fad97836b5ade1bcf623df4019354", "packages/pm_preprocess/ui/data_import_sas.py": "b46b3a739487b88044585b81d8e1e6c3", "packages/pm_preprocess/ui/data_import_sas.ui": "3a238589200dae2ca6d95b9f76658bd4", "packages/pm_preprocess/ui/data_import_spss.py": "f2429d58b23aca160b2652423d57c491", "packages/pm_preprocess/ui/data_import_spss.ui": "02e6076ba3dba639a81488f57a779acd", "packages/pm_preprocess/ui/data_import_text.py": "72839d8f4905a64c72e3e1ef25f0e084", "packages/pm_preprocess/ui/data_import_text.ui": "42ff2c69c472636f51e11b1d26162306", "packages/pm_preprocess/ui/data_info.py": "9be5f4ff591e53d622773a0323d00195", "packages/pm_preprocess/ui/data_info.ui": "d4fcd989ceba0f39012093152207d598", "packages/pm_preprocess/ui/data_merge.py": "22e207fe8f408b7c558e4f9231c2812b", "packages/pm_preprocess/ui/data_merge.ui": "9cacfe18fc7720477acc7a53b46dd35f", "packages/pm_preprocess/ui/data_merge_horizontal.py": "af3de8607ed351d77daa6213fb2828bc", "packages/pm_preprocess/ui/data_merge_horizontal.ui": "d61611fdb4e9cde0fbc2e2c332f48bf5", "packages/pm_preprocess/ui/data_merge_vertical.py": "ef03b6681fd55cf8eb42138024ad1a4e", "packages/pm_preprocess/ui/data_merge_vertical.ui": "59f79c7fa7b08e5ae1e1aeb83eb05987", "packages/pm_preprocess/ui/data_missing_value.py": "81f362bf96738d9138b85a3d1a2dd9e2", "packages/pm_preprocess/ui/data_missing_value.ui": "14e0e959934e191ca4ecc2b65342864f", "packages/pm_preprocess/ui/data_new_column.py": "e079cabae617aeb3ba5fab8656bc79d6", "packages/pm_preprocess/ui/data_new_column.ui": "8d83bde6b1701635d9266ff9fe8047d6", "packages/pm_preprocess/ui/data_partition.py": "6f723fbf5b83bc18194b0e9242d08177", "packages/pm_preprocess/ui/data_partition.ui": "bb426c3df5bd8e2300a6fce26f0acb45", "packages/pm_preprocess/ui/data_repace.py": "76d5e5f3168158c6527adbc1c1b1d309", "packages/pm_preprocess/ui/data_repace.ui": "853b6f43d364faaae3d6f2ed484681ea", "packages/pm_preprocess/ui/data_role.py": "698c50eb2a907f5e517454a28d610daf", "packages/pm_preprocess/ui/data_role.ui": "9b659e8e2accf1bf76fe39efa74152ff", "packages/pm_preprocess/ui/data_role_edit.py": "f93e00c6adfd65e436630e4c5c097d3c", "packages/pm_preprocess/ui/data_role_edit.ui": "18a531771deee0c25777880c0f0894e6", "packages/pm_preprocess/ui/data_row_filter.py": "32baeee9b80430448f0e1f8af96a60e2", "packages/pm_preprocess/ui/data_row_filter.ui": "7a9b909a49af56c8f2916bf4c3f186f5", "packages/pm_preprocess/ui/data_sample.py": "a4919fe81ffbd64838ed0b84b924d36b", "packages/pm_preprocess/ui/data_sample.ui": "f43301f891fd0450fe7800cb81ff4af0", "packages/pm_preprocess/ui/data_sort.py": "fc051898a3fd9a70ff38fe8ff1d3106c", "packages/pm_preprocess/ui/data_sort.ui": "674a1b2eb62111b5c5134b01ed6d684e", "packages/pm_preprocess/ui/data_standard.py": "822ec20008baf2b82b8ee00ea1711933", "packages/pm_preprocess/ui/data_standard.ui": "65a2eca4b0f6ea65a6edf0c9b6f1628f", "packages/pm_preprocess/ui/data_transpose.py": "97b688d1ca7fb74f5bd72a615eac397e", "packages/pm_preprocess/ui/data_transpose.ui": "d5b50013e984a0f56af8b45aa213fd20", "packages/pm_statistics/default.png": "b58b2daf9a2a44726b678f235aed41e6", "packages/pm_statistics/describe.py": "d48a7e2d4573eec5ea2d6b78f6d518cf", "packages/pm_statistics/main.py": "35a51268c3d516d91f75fd155981327e", "packages/pm_statistics/package.json": "b0cfa0a43b9b4ceffef50955bc142708", "packages/pm_statistics/settings.json": "e4385e0a6554dfe40b3696f328f5edd1", "packages/pm_statistics/stat_desc.py": "1d1af20f21d51a2c4c937b583fa1c1e0", "packages/pm_statistics/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pm_statistics/source/add.svg": "abddfead93cdf1feeff13e0fb361b2bc", "packages/pm_statistics/source/collect.svg": "df376dc82733ce771785e80417b5730c", "packages/pm_statistics/source/comment.svg": "17b32e5429d0af97cb4b0cb0b878301a", "packages/pm_statistics/source/descending.svg": "4c0294dcdbb972f6f7e7daae9ca3695e", "packages/pm_statistics/source/down.svg": "cf38a40a26932f5d960da15d8bbcb9f5", "packages/pm_statistics/source/history.svg": "f5e2890d446cc530e8505c2a8bcbeb4c", "packages/pm_statistics/source/left(1).svg": "195de59f0ae8946bbdad79b1e6211c13", "packages/pm_statistics/source/left.svg": "5e2fab4fbb3002791406ffb7d4f24552", "packages/pm_statistics/source/like(1).svg": "be280f55711fe37711710d66cc6de07f", "packages/pm_statistics/source/like.svg": "cd5a555d5aeb29ea51c2d4c411a8e2f7", "packages/pm_statistics/source/offline.svg": "864ab749688d77a17dd418ddd12f613f", "packages/pm_statistics/source/print.svg": "58e74f093ab0f76d7a5f4827139d8202", "packages/pm_statistics/source/reduce.svg": "d3a4d2cb5e65462b6e488f9008101095", "packages/pm_statistics/source/replace.svg": "2c9371c33c45026339f8f0a0fad242bb", "packages/pm_statistics/source/right(1).svg": "6ab0334feba1ebc9fe424a408dbeb053", "packages/pm_statistics/source/right.svg": "0d34209038963d8520605c2945a4aea5", "packages/pm_statistics/source/up.svg": "bfc6c9a4e8afe014a9ef2a3a2eaac829", "packages/pm_statistics/source/user.svg": "03789a31cc8d77164ee5e38758be9fed", "packages/pm_statistics/source/view.svg": "404b787576ea5ee3fb77e219a4020739", "packages/pm_statistics/translations/qt_zh_CN.qm": "27c309c51dd6a9b4453805a9d57314d8", "packages/pm_statistics/translations/qt_zh_CN.ts": "6f69f9df98fc80ba305d1ce1bc850e9a", "packages/pm_statistics/ui/stats.qrc": "9e88108821db568452feff5c52cd51bf", "packages/pm_statistics/ui/stats_rc.py": "aed3f3d5bd2699a234c5b87a8c90c27a", "packages/pm_statistics/ui/stat_base.py": "16ff0fac4ad347a51cb36503ddabc76b", "packages/pm_statistics/ui/stat_base.ui": "5b3601a91453d85b8ba247fac1772a85", "packages/qt_vditor/client.py": "b5f987d7265282647636753bb1992169", "packages/qt_vditor/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/qt_vditor/main.py": "43f5ca83b9b8de08a4b08f98c8d5b12c", "packages/qt_vditor/package.json": "a6ea48177df90bd33e6d9ef571715434", "packages/qt_vditor/route.py": "81e4d783b1ee5662a42175044860ac97", "packages/qt_vditor/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/qt_vditor/examples/sample.md": "6d463f26da3f758e8f8cd73d2f07a013", "packages/qt_vditor/templates/index.html": "ed4bff205de492bd9a445b878941ab98", "packages/setting_manager/main.py": "5e25055f2748fd8f2e16ef6cd438cbfe", "packages/setting_manager/package.json": "7b1091e765c316eb4602acbff21a7b5b", "packages/setting_manager/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/setting_manager/settings.json": "d41d8cd98f00b204e9800998ecf8427e", "packages/setting_manager/settings.py": "f60620c0bbfe1bc061bfc00759107674", "packages/setting_manager/ui_inputs.py": "16c170ac829957e8bd4f3b02f4375472", "packages/setting_manager/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/setting_manager/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/setting_manager/translations/zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/socket_server/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/socket_server/index.rst": "e1840535bf3051014eab7bb2c76fbc10", "packages/socket_server/main.py": "a032c7a064b344e47dd998c545feb38f", "packages/socket_server/package.json": "12d6c14b45eb86427e311e31d005fa20", "packages/socket_server/server_by_socket.py": "77e46bf007fd51f41471b7901bc4b7e1", "packages/socket_server/settings.json": "ac084b924952c4c88e397f5c1f64c893", "packages/socket_server/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/socket_server/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/socket_server/translations/zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/workspace_inspector/data_viewer.py": "96d8e120289b60f4fe6a4877c807a12e", "packages/workspace_inspector/inspectortable.py": "7e88412960946a64afcdaee6b3bf1902", "packages/workspace_inspector/main.py": "4d6088b006fe4b09815eb34cfad86dcb", "packages/workspace_inspector/package.json": "9ed3843023e8b054420bd126866d6962", "packages/workspace_inspector/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/workspace_inspector/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/workspace_inspector/translations/qt_zh_CN.qm": "4c1aa1fdb602f504983cfc1f303fdb4b", "packages/workspace_inspector/translations/qt_zh_CN.ts": "0176607ae0f96037d5b756be88615f76", "widgets/get_time_consuming_classes.py": "b1cc4fe83988288288bb4d46a55297e8", "widgets/__init__.py": "d4a51fe0c972d4f917c7c2029f6d83f5", "widgets/display/examples.py": "ed6581d11a7624a45e76a0c214abb6e4", "widgets/display/__init__.py": "de9a0f70e421564574c3c849d8c9cbcd", "widgets/display/browser/browser.py": "6471eef6706c84e33e915d2539d7ad74", "widgets/display/browser/get_ipy.py": "fdcef50d9c3d562c0c1a01a07fffac29", "widgets/display/browser/handler.py": "8360907d55237220c8409d02896e1630", "widgets/display/browser/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/dynamicgraph/pgexample.py": "3fd8ccf52c92ebeb164ca3b048b657bc", "widgets/display/dynamicgraph/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/dynamicgraph/base/basetimeseries.py": "5c6cef4a05d653d276681d9281ea7eb3", "widgets/display/dynamicgraph/base/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/dynamicgraph/mplplots/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/dynamicgraph/pgplots/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/matplotlib/pmagg.py": "bbee7bf2140f5b9e7d0f2bd3f9f1dd53", "widgets/display/matplotlib/qt5agg.py": "33f10a259f5fa8973c6cb863ef117285", "widgets/display/matplotlib/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/matplotlib/pyqtgraph/pyqtgraphwidget.py": "c260badf3dd0ad2f2e3bcd0ae107dcd3", "widgets/display/matplotlib/pyqtgraph/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/vtk/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/docs/threading_and_tasking.md": "803fb7aad9cbd712229fa089727d2aae", "widgets/docs/doc_figures/pmflowarea_2.png": "4c5b6d091ae5fdc685e94c64a3561218", "widgets/doc_figures/nested_lists_to_place_widgets.png": "3b3dfe1437591299762a3307ba9880a0", "widgets/doc_figures/pmflowarea_1.png": "aeef39398e583540e55a87c04fcb19fc", "widgets/doc_figures/pmflowarea_2.png": "4c5b6d091ae5fdc685e94c64a3561218", "widgets/doc_figures/settings_panel.png": "d1e20e63c914275463ed75740228e7b6", "widgets/elements/dockobject.py": "bbad65e7b1f0304112a70c28917c4fe4", "widgets/elements/toolbar.py": "adb36bf834bbb12c5baabfb323dc5297", "widgets/elements/__init__.py": "5d3ff4be23732caafec3725aacfd2bb1", "widgets/examples/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/examples/utilities/examples.py": "4b738678a2cec6ca81f038d2aad1ebc4", "widgets/examples/utilities/long_conn.py": "a7fb1b9aac35414235ef80dbd1715812", "widgets/examples/utilities/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/flowchart/create_node_content_class.md": "e15251c3574ee6f3472cb32984007f1c", "widgets/flowchart/dataprocesswidget.py": "5830d35615c1b8e05555d4005089f1dd", "widgets/flowchart/readme.md": "13c783b72c01bbef6fd2462deb54d1e1", "widgets/flowchart/readme_arch.md": "15760931b08a70d8257b8e3695f06105", "widgets/flowchart/simulationwidget.py": "17b7dadaf18e84f2d359f2e24571cbe4", "widgets/flowchart/__init__.py": "1ec9907600bd333efbac93fb205ba8d7", "widgets/flowchart/\u521b\u5efa\u65b0\u8282\u70b9(deprecated).md": "c9a0c64e31e69a6c2b226590bf174049", "widgets/flowchart/core/flowchart_scene.py": "8e6b923663fb49519f6555d181c6bc2b", "widgets/flowchart/core/flowchart_widget.py": "6e61a893445b0c08e6bb4fc04f5c9663", "widgets/flowchart/core/flow_content.py": "9f7f15c45ea181fa9390cac06823cca6", "widgets/flowchart/core/flow_items.py": "45810b572b64dfb46b1dbafc4c8391bb", "widgets/flowchart/core/flow_node.py": "426bd423a15ea028aae608489bf27c2f", "widgets/flowchart/core/nodemanager.py": "22f10c693caabc1a588658af292a8238", "widgets/flowchart/core/utils.py": "5e2a38303e8fd30ed7ce3131d99ee4ae", "widgets/flowchart/core/__init__.py": "33d597a87ce723d432ee101bfea5933c", "widgets/flowchart/doc_figures/before_run.png": "56d3c6e2d043d5be501d27a016bf2eb0", "widgets/flowchart/doc_figures/check_json.png": "98dcb1514c6a63b37820704c3ff76ce3", "widgets/flowchart/doc_figures/click_edit_button.png": "1a6625861a3fbd71cf14aa948b16eced", "widgets/flowchart/doc_figures/click_right_top_add_button.png": "116cc66ea7f7a01621afa2bceeefde15", "widgets/flowchart/doc_figures/composition_structure.png": "8a898076c0aa77e7cfe627a933d29c73", "widgets/flowchart/doc_figures/configure_panel.png": "6fc3b5d60c9df7dc4b7ae1ca73162e0a", "widgets/flowchart/doc_figures/create.png": "77d2839be9232d6923e99ac372f1bdd5", "widgets/flowchart/doc_figures/create_new_content_Mul.png": "7d8073ceafe5de7b52cc99b7b0f83b70", "widgets/flowchart/doc_figures/create_node.png": "5defabfa57656965e0ce99fe418d9559", "widgets/flowchart/doc_figures/custom_node.png": "98076ecba04484ffb0f68bc1d3ebe506", "widgets/flowchart/doc_figures/edit_node.png": "5bab19f7eb2b5794e85edaaac6ac8f9f", "widgets/flowchart/doc_figures/edit_panel_meaning.png": "fc03b61991304dbc4b9757420d4853d3", "widgets/flowchart/doc_figures/popup_edit_panel.png": "a069ec207a2060649079a5876ef785e1", "widgets/flowchart/doc_figures/sketch_after_edit.png": "562a4f15b3d808e34ed205ba4859c66d", "widgets/flowchart/icons/down.png": "fe8105e197d1a8dbb7c3f4d04605cc94", "widgets/flowchart/icons/logo.png": "3ba1fce2f5b57a2ab16287e9d0784702", "widgets/flowchart/nodes/dfoperation.py": "3ea5a1b70fc51b363cd8d6ea029aa64f", "widgets/flowchart/nodes/docparser.py": "97e1297436001fc6d447a957799d56d6", "widgets/flowchart/nodes/plots.py": "1423de8473b088b0cf15fada6cebffdc", "widgets/flowchart/nodes/random.py": "bbab2dc862413421cfec6c250f5f04cf", "widgets/flowchart/nodes/reliabilities.py": "834359f014c3618af22987679829df79", "widgets/flowchart/nodes/simplecalc.py": "75c69d36c3813ee5e6b7f98c8c1893e2", "widgets/flowchart/nodes/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/flowchart/nodes/dataframeoperation/dropduplicated.py": "5db7eb9383b7e18a6e6b185b657c2f4e", "widgets/flowchart/nodes/dataframeoperation/randomrowsample.py": "594931f937571051aaa08115303f9b9d", "widgets/flowchart/nodes/dataframeoperation/__init__.py": "590a3c48436d17b168ab491e3d5ef71d", "widgets/flowchart/nodes/io/iterator.py": "d41401063ca9a942416f0f057de62c29", "widgets/flowchart/nodes/io/listdir.py": "8c5903f20f49659f9af2a7ec201d96b3", "widgets/flowchart/nodes/io/pdimport.py": "c32294f54f65a3f25ba6fd1cdabef0ea", "widgets/flowchart/nodes/io/__init__.py": "e6a014f94141e383286a37068a446b4d", "widgets/flowchart/tests/continously_data_process.py": "8f7cbef680438882a373a1a98b6f763c", "widgets/flowchart/tests/database_import.py": "ac1bb7f644465845aac15203b459813a", "widgets/flowchart/tests/fault_tree.py": "4e7a094f1bf83835627c17ecf51eec0a", "widgets/flowchart/tests/node_test.py": "49436316b4bcffa573c07cf714f61d29", "widgets/flowchart/tests/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/utilities/__init__.py": "846122683610ac9a3a02228d40c893d8", "widgets/utilities/network/baseclient.py": "025302351202482cdb67961418a21dda", "widgets/utilities/network/generalclient.py": "57523e2dfe953db9e48e0b2e887f9aea", "widgets/utilities/network/qtclient.py": "c136486e5d7ce14a760e68b5cef5eac9", "widgets/utilities/network/server.py": "36c357391ae6077674c686159e9adc0d", "widgets/utilities/network/util.py": "6d82debc837372e82a42af901dbd8d18", "widgets/utilities/network/__init__.py": "8dd261a5fd464d78930e554a3c71ca0e", "widgets/utilities/platform/commandutils.py": "c534c45682925de3a9ef097bc5e9738f", "widgets/utilities/platform/filemanager.py": "a7ed6bb8a48dc0a631c676b70618b727", "widgets/utilities/platform/filesyswatchdog.py": "c0a2bf1c91a21a5dcf23e31bfeecb70a", "widgets/utilities/platform/fileutils.py": "3ca5537cb60e43a1357e9681b7ac7792", "widgets/utilities/platform/openprocess.py": "1d61b9d4e3ad65e71005b378f25c556c", "widgets/utilities/platform/pmdebug.py": "d0ec593f50f535adc1d9c48c79ea00d7", "widgets/utilities/platform/translation.py": "c4309549c4c11558fdbc3b7491ed64f6", "widgets/utilities/platform/__init__.py": "7fd20799d245559b3722b2688b40aada", "widgets/utilities/platform/test/python_file_test.py": "0c4bff9ef948dbcc88ea0532ae0beb44", "widgets/utilities/platform/test/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/utilities/source/colorutils.py": "fde6914451c075a3e0428f2cce1d0882", "widgets/utilities/source/graphicsitemutils.py": "30395a5a9829eee910c69eca95aa649b", "widgets/utilities/source/iconutils.py": "e83075c233b7ce3290f0e37ded6fba94", "widgets/utilities/source/translation.py": "bb3c8fbd3051b640ed77d30ab718dc32", "widgets/utilities/source/__init__.py": "5b8008b3309c862942604991569b19f0", "widgets/utilities/uilogics/codechecking.py": "48560fbdbd7cf04f3461587b90a12872", "widgets/utilities/uilogics/drags.py": "857f251d9e621005afd8be2c3bf62708", "widgets/utilities/uilogics/uidisplay.py": "f4ee6b2b8695f77551bb4d7e5ff7ad39", "widgets/utilities/uilogics/undomanager.py": "df9dc910b24d09c49e9726420fdeee10", "widgets/utilities/uilogics/windowutils.py": "8372420c42f626d39d9eb193296cb900", "widgets/utilities/uilogics/__init__.py": "645e7a6c9bf8432d1c1ba5e333c362c2", "widgets/utilities/uilogics/tasks/loop_background.py": "4a363d514a49b3d142dd111f957b4a0a", "widgets/utilities/uilogics/tasks/minimal_thread.py": "94f8326dbba36d11f6e45fb79bb2697c", "widgets/utilities/uilogics/tasks/one_shot_background.py": "0075eafe0b95ef10ec9e382917867f7b", "widgets/utilities/uilogics/tasks/threads.py": "380066964983e4398279b18f1cb4c2a5", "widgets/utilities/uilogics/tasks/__init__.py": "2a83611ec96538dd91f878617b4cc882", "widgets/widgets/__init__.py": "dace0c2123dda2b5cf61bfbe954f76e4", "widgets/widgets/basic/__init__.py": "fd2926ad171e35c84c8e34ddc341a15a", "widgets/widgets/basic/browsers/browser.py": "db4472da3e421edae53084e2f60f8531", "widgets/widgets/basic/browsers/__init__.py": "f2ca69c55dd6dd321eb50715d281d85f", "widgets/widgets/basic/browsers/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "widgets/widgets/basic/buttons/__init__.py": "900cfebb524cf4f7d2a311ba7376744c", "widgets/widgets/basic/buttons/button/toolbutton.py": "078234cbde02a9528c683296768c716a", "widgets/widgets/basic/buttons/button/__init__.py": "0c609746f7319525ec3b9a95478be7e1", "widgets/widgets/basic/buttons/buttonpane/pushbuttonpane.py": "b4b83976fd0b594799dc95bc3c577433", "widgets/widgets/basic/buttons/buttonpane/__init__.py": "1e6ab09b63582d591d9c9fbb95d77d25", "widgets/widgets/basic/buttons/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "widgets/widgets/basic/containers/flowarea.py": "3465e9353838239b7a85503bdb348eb6", "widgets/widgets/basic/containers/flowlayout.py": "e7722b3b344fb1966513920657c3ab9e", "widgets/widgets/basic/containers/pmdockwidget.py": "264fd97a9b774531ee722a2c561c9eb1", "widgets/widgets/basic/containers/pmscrollarea.py": "d4474ecaf4ebe7ef1bc33646f9776c74", "widgets/widgets/basic/containers/PMTab.py": "69bc55a23c66f5aeefd57c00c54daf9f", "widgets/widgets/basic/containers/pmtoolbox.py": "aaa8b73936ef32a4c48d3c6dbb4a1edc", "widgets/widgets/basic/containers/__init__.py": "edcf475260eaebb0aababd31515f66a6", "widgets/widgets/basic/containers/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "widgets/widgets/basic/dialogs/textdialog.py": "02c8803b009663537eadcf6d1a1708c0", "widgets/widgets/basic/dialogs/__init__.py": "b05f556cffa689fce8ecf11590d5073d", "widgets/widgets/basic/images/imageview.py": "677c40cd96057c84dbb37592daef0af2", "widgets/widgets/basic/images/imageviewitem.py": "7f4c1d86ca85188970310d26c26d30a8", "widgets/widgets/basic/images/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/basic/labels/scrolllabel.py": "f6bd03763bb1f04990b20b3a1a9b1c90", "widgets/widgets/basic/labels/__init__.py": "37e333e93bd172534e76cd5e850f58f1", "widgets/widgets/basic/labels/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "widgets/widgets/basic/lists/combobasic.py": "0e7fbf8724164af3e7b8b9933df4729c", "widgets/widgets/basic/lists/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/basic/lists/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "widgets/widgets/basic/others/console.py": "5905c89de68775fd568577969e593f3a", "widgets/widgets/basic/others/ConsoleHistoryDialog.py": "2d4f0c82d296813c5a578cc906ae9424", "widgets/widgets/basic/others/ConsoleHistoryDialog.ui": "3ae43f1f52ed4f7dc414a4e522c76122", "widgets/widgets/basic/others/gauge.py": "16159230eebfc9f1be3ff0c4c5d555e1", "widgets/widgets/basic/others/instantbootconsole.py": "5633bce9595e8b8e509431e3d3ce5f09", "widgets/widgets/basic/others/processconsole.py": "adf620b42500885f8252657aefcc701e", "widgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py": "22769bd93d86bf8129ca0fa03b9af12b", "widgets/widgets/basic/others/__init__.py": "fbcfcf98fbfcfb8625281748544e5194", "widgets/widgets/basic/others/source/clear.png": "d00b30caeba4e133a503c28d29484cd6", "widgets/widgets/basic/others/source/run.png": "a7ad927c1b15a7fd5a3a228991d6b778", "widgets/widgets/basic/others/source/stop.png": "db32ac51e103396c0758faa7ca39df7d", "widgets/widgets/basic/others/translations/qt_zh_CN.ts": "efbc0c2de628506b1cd2528e85110912", "widgets/widgets/basic/plots/__init__.py": "29b430ab74236a99e749c91f4a7a4d8d", "widgets/widgets/basic/plots/bars/histogram.py": "57fe8015a7abe33f76965ffb405a1ba1", "widgets/widgets/basic/plots/bars/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/basic/plots/lines/timeseries.py": "7a1877123a6d38adb06b3b9f43a6bb73", "widgets/widgets/basic/plots/lines/__init__.py": "d8f241f084bf5d4a8f4efd5b51d7e94f", "widgets/widgets/basic/plots/matplotlib/__init__.py": "2ac44857cafb53b120d44169c3c34f04", "widgets/widgets/basic/plots/matplotlib/base/pmaggplot.py": "c1882247f0027b2b962ba7a5ea3ca7c7", "widgets/widgets/basic/plots/matplotlib/base/qt5aggplot.py": "33f10a259f5fa8973c6cb863ef117285", "widgets/widgets/basic/plots/matplotlib/base/__init__.py": "f0e054fea02ba6ad51bf06d2a311e39b", "widgets/widgets/basic/plots/pyqtgraph/__init__.py": "2be8e98cb7ca94374b5168f14d00b359", "widgets/widgets/basic/plots/pyqtgraph/base/pgplot.py": "8c38a37cb08c0b54300704a0d1b0f10b", "widgets/widgets/basic/plots/pyqtgraph/base/__init__.py": "81087fce1382395cd3c04360a691bd99", "widgets/widgets/basic/plots/scatters/scatters.py": "450136b97d71bbca2ac809b4b7541a7c", "widgets/widgets/basic/plots/scatters/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/basic/plots/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "widgets/widgets/basic/quick/demo1.py": "353264297eedb94ef52af4c181c79e4e", "widgets/widgets/basic/quick/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/basic/tables/tableviews.py": "a2111346680c2af8ab00f8588191e07a", "widgets/widgets/basic/tables/tablewidgets.py": "890007b4bf1e6e2a38673614f324168d", "widgets/widgets/basic/tables/__init__.py": "84da0cb7f378bbf1ea095d6b8ccaf66d", "widgets/widgets/basic/tables/help/help.md": "803db01c2a1acf0f80d479042ecaff99", "widgets/widgets/basic/tables/translations/qt_zh_CN.ts": "147dcbf56740cccf27dc99dcec3b5b6a", "widgets/widgets/basic/texts/__init__.py": "e1c06d85ae7b8b032bef47e42e4c08f9", "widgets/widgets/basic/texts/statusreport/errroreport.py": "a7f14a40ca0be66bd12ac1084f1976f1", "widgets/widgets/basic/texts/statusreport/__init__.py": "b2b898748d695f952a3838cd8289bfbe", "widgets/widgets/basic/texts/webeditors/editor.py": "34336ae67d3efda5060edffa2982d941", "widgets/widgets/basic/texts/webeditors/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/basic/trees/filetree.py": "f2f05c9657978a587295f5a4f09ed1fb", "widgets/widgets/basic/trees/jsontree.py": "b91dc6b98e5561f0f9988051371101c6", "widgets/widgets/basic/trees/treecheck.py": "f29b4c69b3f30b99da28eb79bcf1c068", "widgets/widgets/basic/trees/varattrtree.py": "3f6d8812f23ab42247ee5185e8c8c57c", "widgets/widgets/basic/trees/__init__.py": "2dc6f31ca28c563654578e8b821f06bd", "widgets/widgets/basic/trees/translations/qt_zh_CN.ts": "14da9ce6253397bf6c0fcc1c4c004a01", "widgets/widgets/composited/buttonpanel.py": "a7323ff16ef179e89c39c3253667aafc", "widgets/widgets/composited/fastui.py": "8b604fc24975c5c7ba2de067065a363f", "widgets/widgets/composited/generalpanel.py": "b6be00c44a6e382aae0453e133e84d01", "widgets/widgets/composited/__init__.py": "d13563610fa6f243f2d973dd42a6f6df", "widgets/widgets/extended/__init__.py": "cc16561fe162128cca4c778f11263487", "widgets/widgets/extended/base/baseextendedwidget.py": "378fdef54ba10e68ed5cb276a5624c31", "widgets/widgets/extended/base/__init__.py": "d7d1b8939cf2c630235925abcb5a2ee2", "widgets/widgets/extended/checkbuttons/check.py": "d8b6cbe579ad2161bce135f2925313c4", "widgets/widgets/extended/checkbuttons/__init__.py": "a5c9c5ecdc69c4139ecd15de439b2e0b", "widgets/widgets/extended/comboboxes/combo.py": "ebf75f80630cac67f9642f5372097df4", "widgets/widgets/extended/comboboxes/variables_combo.py": "371fd0d84768be8a624dac87979e1f1b", "widgets/widgets/extended/comboboxes/__init__.py": "58edc6def91691d42263e0d79deec2c0", "widgets/widgets/extended/entries/baseentryctrl.py": "e752e2c6a708b1a435a84473bba154d8", "widgets/widgets/extended/entries/colorctrl.py": "16f70e0d829af6c89fcab387dd6f1442", "widgets/widgets/extended/entries/evalctrl.py": "de708611514272173a02f047b7e5fc68", "widgets/widgets/extended/entries/filectrl.py": "d11a9711cb319e2131464baa2a6a8d84", "widgets/widgets/extended/entries/folderctrl.py": "ff904108b13cddf3b6c7837cb60aa847", "widgets/widgets/extended/entries/funcctrl.py": "f308b1b347c7d44a4efe36b4e8a73ec3", "widgets/widgets/extended/entries/keymappingctrl.py": "2a50527522468cd00f3d7ccb99a02a7d", "widgets/widgets/extended/entries/linectrl.py": "626be1e4169342de4027f902779d9e19", "widgets/widgets/extended/entries/numctrl.py": "3739731735cc0520c4f45d1b0429297a", "widgets/widgets/extended/entries/passwordctrl.py": "85a3604a10ba51e5aaddfd269a8f1317", "widgets/widgets/extended/entries/__init__.py": "a87b64affd6a8b87f14caa030b1d7196", "widgets/widgets/extended/labels/label.py": "e12d3eaafac1b29d87b6b83cb5ca46c9", "widgets/widgets/extended/labels/__init__.py": "5d5fadd87777a0ecdf64ec91c7af5fb1", "widgets/widgets/extended/lists/listwgt.py": "52cf01737cab419a302a61a2fc22dd7d", "widgets/widgets/extended/lists/__init__.py": "fe79c30d2106faff8c630bec7e79ce37", "widgets/widgets/extended/others/multitypeparaminput.py": "f22495e2e29d29843c3888a21abd43a0", "widgets/widgets/extended/others/__init__.py": "372dfdcc25b8f846d64b77bea41535b8", "widgets/widgets/extended/others/monitors/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/extended/plots/__init__.py": "56a6f2c973e69ed27c3021de7b28e035", "widgets/widgets/extended/plots/lines/timeseries.py": "d0b20cb0ea7e4a6ccafc47d9b16e6fc9", "widgets/widgets/extended/plots/lines/__init__.py": "bc396f8083302203baaf5d23065c33ca", "widgets/widgets/extended/radiobuttons/radiobuttonctrl.py": "113268756d9f5bb930230e4f8824ec67", "widgets/widgets/extended/radiobuttons/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/extended/spins/datetime.py": "e6a555a3bf8d0a57b98d8926ec6684c7", "widgets/widgets/extended/spins/numberspin.py": "74160a8031c42d2f5ea87cc4a5be3272", "widgets/widgets/extended/spins/__init__.py": "cfa6752de3dc824468eaaec6166fb3d4", "widgets/widgets/extended/tables/rulesctrl.py": "6d2fda81132490482c0fdc5263cb5190", "widgets/widgets/extended/tables/tableshow.py": "100223049815e42adb4fd3c74753dda7", "widgets/widgets/extended/tables/__init__.py": "2945023ce1794015105e1aba6213136d", "widgets/widgets/extended/texts/htmlshow.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/extended/texts/markdownshow.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/extended/texts/__init__.py": "4ab23c644c97003b968443d8a2f4a584", "widgets/widgets/extended/trees/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "pmlocalserver/readme.md": "6e10586e731f6fdc871441974934b006", "pmlocalserver/server.py": "d29fca0da053832fcbaec4788889674c", "pyminer_comm/readme.md": "d41d8cd98f00b204e9800998ecf8427e", "pyminer_comm/__init__.py": "f6b46f7aedc9dd22d9cdaf15d1be08c2", "pyminer_comm/base/datadesc.py": "1f068e02ef48771fb3499b5b27ff058b", "pyminer_comm/base/encode_decode.py": "42188f6322e17da29d8d1cfb54ebc75a", "pyminer_comm/base/network.py": "1b0fbd15a289297b65698b2139724741", "pyminer_comm/base/sys_utils.py": "4b9c387c0926aa2bec713ba5560c68f1", "pyminer_comm/base/__init__.py": "036632e2718a53fdcd02a87492de0963", "pyminer_comm/data_client/data_client.py": "613aeac2716a0ec38b3f5db2c38080b4", "pyminer_comm/data_client/unittest_data_client.py": "cd4366d90aeca0639432273292da8efe", "pyminer_comm/data_client/__init__.py": "8159a5a2b762aa7581a92517146bd002", "pyminer_comm/pyminer_client/pm_client.py": "5e7ff88e50112aac1f639a7301404218", "pyminer_comm/pyminer_client/__init__.py": "fa7dd1f47a04d6515681315870a12899", "pyminer_comm/tests/test_communication.py": "95fa83a3686c8ea7bfc4736220e3bbdb", "resources/pyqtsource.qrc": "8a3a6b55a64fa60f8c58f49d2d7eb949", "resources/pyqtsource_rc.py": "1cdc5870d3e5107926e57d15c7fa63ea", "resources/fonts/Cascadia.ttf": "717e365c4a4c1478f8208a5ab33ee26b", "resources/fonts/CascadiaMono.ttf": "66c917f89d707ba0b41d5a1619c1e03e", "resources/fonts/Deng.ttf": "15c8b490227909f31d456ee9d11521e5", "resources/fonts/Dengb.ttf": "2d690e1656db754bc4ce63531223d007", "resources/fonts/Dengl.ttf": "1ddcd772ff1d04a2d545434b47ae4782", "resources/fonts/SourceCodePro-Bold.ttf": "458f0d7c492182d4c1b08621518689c0", "resources/fonts/SourceCodePro-BoldIt.ttf": "0cddef66936155d98aaa0d2a71d609c1", "resources/fonts/SourceCodePro-It.ttf": "df1343e44ce0fd5eb8c09ce8995966c8", "resources/fonts/SourceCodePro-Regular.ttf": "fedb9984186419a66cf725a38b6703ca", "resources/icons/logo.ico": "f1eb0f12aa600bd5638cd6fbca4b978f", "resources/icons/logo.png": "30e040dea91eb5edc95a2ab16c895324", "resources/images/bg.png": "931fe255dbcec81b94c2cd692fa1ff01", "resources/images/left.bmp": "d9daee9f12d8d45832a5f85fb79733cd", "resources/images/PyMiner\u6846\u67b6\u8bf4\u660e.jpg": "02eecc71bfee918d5a559501aa8b1334", "resources/images/splash.jpg": "d093033402635cffde8ae0d4840e46c4", "resources/images/splash_v2.png": "8de3454d0a7ea72b2ddbe2b242ebc535", "resources/images/weixin.png": "9fd2526c405766beb714515a07571c44", "resources/images/xmind.png": "9f0ef2b1b83dee369f38600bbdbf44bb", "resources/images/zhifubao.png": "2b957fd623e55d473c9c1eb81ce7ecd8", "resources/qss/Fusion.qss": "e3b35eb107311192c3d6a1b6512da0a0", "resources/qss/index.rst": "6000f5eae1ed6f0e434e0001675bf8a2", "resources/qss/Qdarkstyle.qss": "1d5438b0c29ab46529c7d38a976dbf62", "resources/qss/standard.ini": "ee661fb8f5a4a0852389e31a11c71001", "resources/qss/standard.qss": "1c1672f58d85af0e6211b6c144987974", "resources/qss/Windows.qss": "70481f2ea4c380995271f4b338da0968", "resources/qss/windowsvista.qss": "80e75b0e7ec8b7dd7a23b4bf75ab8ef4", "resources/screenshot/check_data.png": "e44471c2514f8a048df2a89a9df2e795", "resources/screenshot/code.png": "814df667bb94b7d2ae844d938ec916b7", "resources/screenshot/group.jpg": "0b3959e958742a35baeaec5044a95584", "resources/screenshot/main.png": "1b6f8a5331f0c5954a86b9024f070568", "resources/theme/default/icons/3d.svg": "61157c75fbfde955215c93e2daf93551", "resources/theme/default/icons/action.svg": "61ef2e8adb0b2bfe5928aa14b376fec3", "resources/theme/default/icons/addannotation.svg": "503b6bffffae70dfe67068cd24f5d88e", "resources/theme/default/icons/added.png": "2acf12376249833027eadb29c9e8a58f", "resources/theme/default/icons/addFeature.svg": "bcc4056d0d52f3cb44acbc81858b6099", "resources/theme/default/icons/addnode.svg": "763e098d49dec789969c25b7e69ab629", "resources/theme/default/icons/addpath.svg": "e700804c812dfe2bdc54798b11814924", "resources/theme/default/icons/add_col.svg": "eee7249c440e048cb1796d3e8d1c949b", "resources/theme/default/icons/add_row.svg": "620b902ccebc31be4d270e7124fb2e48", "resources/theme/default/icons/align_bottom.svg": "f4fb3a0c1bb022440e3489f75e69c390", "resources/theme/default/icons/align_horCenter.svg": "cef02a64b8f66064fc237ea34b41536f", "resources/theme/default/icons/align_left.svg": "2275c71a5bd808f0379098e0663c1aee", "resources/theme/default/icons/align_right.svg": "aeb304bf474f3402804c6c113d197101", "resources/theme/default/icons/align_top.svg": "621e60f54d5dcd50a28aa7aa3be3ffe4", "resources/theme/default/icons/align_verCenter.svg": "a8ea8b762c89efcbeeb78f3c3f72b4dc", "resources/theme/default/icons/allowedit.svg": "3c2b136910b2403dc0da5cd1a54fba0c", "resources/theme/default/icons/allowedit_layer.svg": "fe3079b3a271ac07bea92c298fe75452", "resources/theme/default/icons/allowsearch.svg": "1504eb4f1da9532cbb86754b39c0f410", "resources/theme/default/icons/allowsearch_layer.svg": "e126ff953c35229e30444c8d6e4ae2e8", "resources/theme/default/icons/allowselect.svg": "5b3dbfe62ddbf003af7efb4f429cb0fe", "resources/theme/default/icons/allowselect_layer.svg": "62cbf0796e8e284f4df30d1575d4c16c", "resources/theme/default/icons/allrecords.svg": "75b5c30ce3932f21ae7b16013ffc4c8c", "resources/theme/default/icons/annotation.svg": "1ae382f88b44847332e9826ba46c5397", "resources/theme/default/icons/annotation_no.svg": "c3e5a2d3179e075c49b13015eb5b7e52", "resources/theme/default/icons/anova.svg": "14b71522f19c12ffde5e46202fcf6bc3", "resources/theme/default/icons/appstore.svg": "e2a48d1643f244e957ce9dba9e55a72f", "resources/theme/default/icons/app_down.svg": "5af2c894a37156084df6218bf562c626", "resources/theme/default/icons/attributerender.svg": "216c03c70731a3d0936649486d1ac943", "resources/theme/default/icons/attributes.png": "5a9ddb1cb0d0b3e35bb8f5bec3c7c511", "resources/theme/default/icons/basicStatistic.svg": "e84a179215a06d27e8547e52620a4859", "resources/theme/default/icons/beginfly.svg": "260f78da60b0d46b64fdd9b942167066", "resources/theme/default/icons/bottom.svg": "6fbc8f02bc979600df8a6a8d24bd3ae8", "resources/theme/default/icons/camera.svg": "27ae116857da0dc4bc1bf2a45a899dd9", "resources/theme/default/icons/canshu.svg": "3dd688f4c48e9c5e32ea9ef81ac8ac86", "resources/theme/default/icons/catalogAttributeTablePageFirst.svg": "0872ecfef2107aeaafbcdf0959d1a21f", "resources/theme/default/icons/catalogAttributeTablePageLast.svg": "18d9cf57a8fa52b6fabb08565ba0177f", "resources/theme/default/icons/catalogAttributeTablePageNext.svg": "ceeedf9b8523a724ea5cd524fa733211", "resources/theme/default/icons/catalogAttributeTablePagePrevious.svg": "164f4dc04bc3e9e8c508505027d408fd", "resources/theme/default/icons/catchline.svg": "6b4ee518bf6ba27bdd6cf44188ca864c", "resources/theme/default/icons/catchpoint.svg": "8191852167c41f1408891d74f233110c", "resources/theme/default/icons/centerpointlinkage.svg": "8fe7f934cfdca995811c3170017607d1", "resources/theme/default/icons/changeAttribute.svg": "a1b9c1ff1e2f6d7dad0a3873a52ce13f", "resources/theme/default/icons/changeFeature.svg": "556de2ee6e10e39b6e369c6c7a271be3", "resources/theme/default/icons/changeGeometry.svg": "1628a5992db6891c26741e3356817473", "resources/theme/default/icons/chartStatistic.svg": "30047525eb626a274f074399334f4b30", "resources/theme/default/icons/check_update.svg": "d6e33e022ada06b9b3abf33de637a573", "resources/theme/default/icons/Classification.svg": "658e28143d9a717f0e2b951cc67111ae", "resources/theme/default/icons/clear.svg": "1d841dcc502211799d9055a87cf3c55d", "resources/theme/default/icons/close.png": "20780f1ae86a0f942f448f69e16dbd3c", "resources/theme/default/icons/close_white.png": "7b567f8cd3293ae156df417e5a21dc6b", "resources/theme/default/icons/Clustering.svg": "012392d9351d8983b29e99b42145c77b", "resources/theme/default/icons/cmd.svg": "0ea2aa79bb81ae297c97d356072745bc", "resources/theme/default/icons/column.svg": "006f3f2cbba5c9fc0fcc223883b00fc7", "resources/theme/default/icons/column_2.svg": "4a2981704a879a016c4a8dc88710b5f2", "resources/theme/default/icons/community.svg": "3cdd0bf3826dfc1ad073d7ad449bc93e", "resources/theme/default/icons/compare.svg": "ddc98ac27fe119cb0d4acbf6a04affdc", "resources/theme/default/icons/conflict.svg": "ffe7f2d515ba91b5920547c0193b6474", "resources/theme/default/icons/conflicted.png": "1f83c2acd291df5d1d10ea67930145fe", "resources/theme/default/icons/continuefly.svg": "4346811bddecadf1ff6db3d87c1447d6", "resources/theme/default/icons/copy.svg": "9ad66acb6dcb55bf923628b188ff5f64", "resources/theme/default/icons/copyElement.svg": "cbe746ec2f6abd3a4b5a020943acf0a1", "resources/theme/default/icons/csv.svg": "9867d63fe22cc88b9c47159b0fd04791", "resources/theme/default/icons/csv_gray.svg": "16c6562ded6d0f6e0ee26005b9bc4c7f", "resources/theme/default/icons/currentindex.png": "dc987f99c44a68ca57c15dd784babc24", "resources/theme/default/icons/database_config.svg": "fa799903a0c570e3a09fe7efa6d3a276", "resources/theme/default/icons/dataSourceConfig.svg": "6a3bd375f33fe348498e053f3bcae8f5", "resources/theme/default/icons/dataspecification.svg": "1e6d1fcac3f8dc14a0daffc947c4d14a", "resources/theme/default/icons/data_desc.svg": "5913822d76a61455714c15e6132eb3e6", "resources/theme/default/icons/data_desc_2.svg": "1f51941660ac732dda207d022c26ee04", "resources/theme/default/icons/data_info.svg": "9ead14ad7a1cdf63b5702c48e05e78d3", "resources/theme/default/icons/data_join.svg": "406e169ebb9b8af93d286581f59f0245", "resources/theme/default/icons/data_missing.svg": "c7f2e5a1dc938edae131a30c6b56b711", "resources/theme/default/icons/data_partition.svg": "d8cbc4400259d84850ec97154dacd688", "resources/theme/default/icons/data_role.svg": "5002bd4ed773126cf2d4c34c4bb4541d", "resources/theme/default/icons/debug.svg": "e2ca8b334c69f413637945ebe871d696", "resources/theme/default/icons/debug_red.svg": "ab77c95b9f382e8f6fdb09da83795dfc", "resources/theme/default/icons/deleted.png": "99073a344eb6184343073b14eb3b4338", "resources/theme/default/icons/deletedata.svg": "0809bd41dd7489df3a1dc2a8e976f888", "resources/theme/default/icons/deleteFeature.svg": "5acc1452971d56857d219e9906341904", "resources/theme/default/icons/delete_col.svg": "c64463979c0dabb232a424810a41fad0", "resources/theme/default/icons/delete_row.svg": "28c35f8dae78bb25a1d8b4981996ec5d", "resources/theme/default/icons/dependencies.svg": "150af39be2e05f96916e16c20f7eacbc", "resources/theme/default/icons/diagram.svg": "93a8d692b994662c68e9374ca42fbfe0", "resources/theme/default/icons/disallowedit.svg": "1d2ea40eb876a1b57edfab5937150a23", "resources/theme/default/icons/disallowsearch.svg": "48d814b63bb64b53e1bbe5a745ad2efa", "resources/theme/default/icons/disallowselect.svg": "780b169700eec6b08dc575e3a0d01275", "resources/theme/default/icons/display.svg": "a370d879c046105fa360f2bee6809a10", "resources/theme/default/icons/distribution.svg": "53e6bcf151c4cb9f89f80093c256ea62", "resources/theme/default/icons/donate.svg": "f72f24a7e8db14c7c98394d6c8dfc860", "resources/theme/default/icons/down.png": "303cd2548ab3be7109c7fbab16730725", "resources/theme/default/icons/downWard.svg": "0bf14903bcbdef20890f936ac7855c61", "resources/theme/default/icons/drawline3d.svg": "64fc6cdf5c361bb7a6f2b5c7dadc3934", "resources/theme/default/icons/drawpoint3d.svg": "452946e331372a97bdd09df9f5f86a71", "resources/theme/default/icons/drawpolygon.svg": "e54865783b8e639d6b8aef7f0eb0597f", "resources/theme/default/icons/drawpolygon3d.svg": "4dd900f92c31b8254c18371b72532011", "resources/theme/default/icons/duoyuan.svg": "5d84f2bcfc84ae85a6fb1a7a5ee08b28", "resources/theme/default/icons/E-matlab.svg": "11fb165a87912c326ba2a5f27d4971b8", "resources/theme/default/icons/earth3d.svg": "2bbc786eaadf43a74a592ec82b14ba03", "resources/theme/default/icons/editannotation.svg": "e73609dbea16a474b62e07344a34264d", "resources/theme/default/icons/editConfig.svg": "2e65b8ba1573593af29ee2fcf1a54288", "resources/theme/default/icons/editmetadata.svg": "c89258a047ac04855464e0a2cb883f8e", "resources/theme/default/icons/endadding.svg": "ba25cd175a3a98a0d2c7b81f125975df", "resources/theme/default/icons/endfly.svg": "8aa793c8cc77046cdfd7d70307c83731", "resources/theme/default/icons/errorInfo.svg": "b8d8db18986b89bf3b1b980fa613462b", "resources/theme/default/icons/excel(1).svg": "9eb4ba787a3e62e477772f0c4a93f366", "resources/theme/default/icons/excel.svg": "ea00b0b78bb93119c7eafe98a79a8988", "resources/theme/default/icons/ExcelFile.png": "c488f98763fb577be56bc955c928c947", "resources/theme/default/icons/excel_gray.svg": "a1135950f1896aa177e00eb10f44f910", "resources/theme/default/icons/expendDown.svg": "fe6b296aa4020dda5c5a870bb7596235", "resources/theme/default/icons/expire.svg": "b7055d451d7bf23ddffcd974ceb39225", "resources/theme/default/icons/fastCollect.svg": "b929bc85fd17ba612275008238d70e53", "resources/theme/default/icons/favorites.svg": "589f0e80dde61b86c2470b3799f8f860", "resources/theme/default/icons/feedback.svg": "f695df9b7313ab60be2c3c46b4fc7468", "resources/theme/default/icons/field.svg": "d168f3a212323820267956d6de9ca9d7", "resources/theme/default/icons/file.svg": "58f428cb524544f4f3993bb37f2ef1ba", "resources/theme/default/icons/file_gray.svg": "fe90e95c15020d95c8f5690f3cb5fae3", "resources/theme/default/icons/filter.svg": "e87a00609c494f030812f3c00a2e6e35", "resources/theme/default/icons/final.png": "87457d3035ab89d82a6b57976e9b0245", "resources/theme/default/icons/find_replace.svg": "665177ccc10ce22b469a118beec97dd6", "resources/theme/default/icons/first.png": "f0edce38b01be51e2dfea42df74d8f23", "resources/theme/default/icons/flight.svg": "8857e62ab11e2cd3ae039db12d61b0d4", "resources/theme/default/icons/float.png": "5f31043d787d15eab504b59bef221e6d", "resources/theme/default/icons/float_white.png": "89609a354d4d717f4e578528dfd5547c", "resources/theme/default/icons/fly.svg": "9761c5cef3b2a4a59ef4ed762c62ad7a", "resources/theme/default/icons/flyaround.svg": "c8a2ba65a3a3ea28c710727327b062b6", "resources/theme/default/icons/folder.svg": "b7e11fde0a4f073c8255d911214aecd3", "resources/theme/default/icons/folder_yellow.svg": "9d3d6d38fa617dfeedec734a5c5c13e1", "resources/theme/default/icons/foundrecords.svg": "aeb3afe2862d00fdeaf810cc479a9704", "resources/theme/default/icons/general.svg": "8d0ffe48967c6985486949410f399c74", "resources/theme/default/icons/generalConfig.svg": "ce54c065114cc47016cd6a382457c1b8", "resources/theme/default/icons/GeneratingAdministrativeRegion.svg": "444cf5e4f7daa640706014ae3f55e307", "resources/theme/default/icons/geodbms.ico": "fef8bfe0713f757762dd9ce837b48c1c", "resources/theme/default/icons/geomap.ico": "dd4b17c0ec69f51b039c51b6e0887c31", "resources/theme/default/icons/gotoview.svg": "da5e78b70c58d112189832fd5cdad9d9", "resources/theme/default/icons/help.svg": "6c9e88b86a30ea8df99ecb75891990d2", "resources/theme/default/icons/help_doc.svg": "1491066f6ba737fb319d4b3aeec96402", "resources/theme/default/icons/histogram.png": "334c464f233edaf5d54c0e1a78289559", "resources/theme/default/icons/home_site.svg": "a9fdb97167551132fe16dd05e7668643", "resources/theme/default/icons/html.ico": "ef2d86df09c9fc6d671e12b5deaf49e6", "resources/theme/default/icons/html.svg": "8158b710d8854547cfe6e2ece1ab3e22", "resources/theme/default/icons/import.svg": "e38ca75a6ffcf334ea461b245f523444", "resources/theme/default/icons/importConfig.svg": "f60db217ccfce27088257eeb9b39d236", "resources/theme/default/icons/import_database.svg": "42ae4560410eb3b900a99360d0019fba", "resources/theme/default/icons/indent_left.svg": "13d4c1ee641fc364bf20be31e9c277a7", "resources/theme/default/icons/indent_right.svg": "a9bc26d41494a2760b186614cc5a177d", "resources/theme/default/icons/index.svg": "63797de724460b5527354bcc9df5d79d", "resources/theme/default/icons/info.svg": "59366b0c10bbce5c3dd9dfec1860d32c", "resources/theme/default/icons/install.svg": "699200cfd59967ff740f1e3076795f0f", "resources/theme/default/icons/invisibleMap.svg": "f5e5e045de80b10006eca992d6f156c1", "resources/theme/default/icons/javascript.ico": "237b59ab21d39cbf9d56481abd6ea724", "resources/theme/default/icons/jiashe.svg": "6195487f581d0b17bf8bd5e440ac3152", "resources/theme/default/icons/join.png": "ae8569cf1fc1762af272861ffbf1a16f", "resources/theme/default/icons/JoinMapTable.svg": "c7277790649b9dafcba2531c8ec43630", "resources/theme/default/icons/jump_line.svg": "36d10e5f905da4134c668d1baa7b0eff", "resources/theme/default/icons/jupyter.ico": "fcd12a895e826c9bf68ec69a3801a6b5", "resources/theme/default/icons/Jupyter.svg": "5e31f82bc08dff94a0f7a19492ae3e57", "resources/theme/default/icons/lab.svg": "bb81cefd8b4592063bf604536517bbe4", "resources/theme/default/icons/labelingMultiple.svg": "60b47ac95c42db86f0a1996619aa5710", "resources/theme/default/icons/labelingNone.svg": "aec873e7c3a156d25d90ba14332250fe", "resources/theme/default/icons/labelingSingle.svg": "4eb6031628115e94af14c75ed7743277", "resources/theme/default/icons/labels.svg": "2f07179dee5125cdc7720364cc83fa4d", "resources/theme/default/icons/LandSurveyAutoNumber.svg": "d4fa015fe319301146a20d569319d197", "resources/theme/default/icons/layerBrush.svg": "30f0e853f0588bb65f58b6e407f26e73", "resources/theme/default/icons/layerConfig.svg": "ca61ff1339a5aab82167c3b3834f6fc8", "resources/theme/default/icons/legend.svg": "d34ddf6094becbbd0c65321a1f154bfd", "resources/theme/default/icons/lockorthoview.svg": "39417a4ce7986b55c908a36268185ca3", "resources/theme/default/icons/lockview.svg": "89f5b906db5c12867af42e06ccb1d18e", "resources/theme/default/icons/lost.png": "e5f28a07326ba62314e4964833d853c8", "resources/theme/default/icons/mActionAbout.png": "1b50df16c376e6e78454236403627aeb", "resources/theme/default/icons/mActionAbout.svg": "1e1360e32f95eee26b8f41e69339cab8", "resources/theme/default/icons/mActionActiveStyle.svg": "302386637bb5cd7bf856ad1ce6ea42fe", "resources/theme/default/icons/mActionAdd.svg": "340f3bb6a7682527aae76150aabff11b", "resources/theme/default/icons/mActionAddArrow.png": "95e75cb331f8ff2ae412b474db6f55bb", "resources/theme/default/icons/mActionAddArrow.svg": "06246d25e27308ad26aac55af7eb9713", "resources/theme/default/icons/mActionAddBasicCircle.svg": "f8a5e280035bbfaa025028e4eed1c703", "resources/theme/default/icons/mActionAddBasicRectangle.svg": "85605dbd86923fbed31379f828d995bc", "resources/theme/default/icons/mActionAddClassification.svg": "5d91e7c199fdfc94b71882b743e084f8", "resources/theme/default/icons/mActionAddClassificationCode.svg": "71811be70f15711a0890b9f6a407dab5", "resources/theme/default/icons/mActionAddCustom.svg": "cc118673a1e3b2e74fc57da54a9aa35e", "resources/theme/default/icons/mActionAddDataSet.svg": "e15df2fe98dfcddd91f6edc44b17f719", "resources/theme/default/icons/mActionAddDataTable.svg": "3944027676b922267a24159091390090", "resources/theme/default/icons/mActionAddDicItem.svg": "d71bb80327c14ba5e06e965b15864b48", "resources/theme/default/icons/mActionAddDirectory.svg": "f4a64c10d63eb102b6088281748dedf5", "resources/theme/default/icons/mActionAddEnumRange.svg": "9969caf289186d9cd546400aa5f16079", "resources/theme/default/icons/mActionAddGroup.svg": "f308932c912ab0483324f89d5ecce6c0", "resources/theme/default/icons/mActionAddImage.png": "94e43a1d6b956c2b35625a5ea760261e", "resources/theme/default/icons/mActionAddImage.svg": "28bb04fd672efe9f1a52f2901f54de6f", "resources/theme/default/icons/mActionAddLayer.svg": "840395598b646deb2c747f78d305e324", "resources/theme/default/icons/mActionAddLegend.png": "8349d32174a82160f1c812641855fbb9", "resources/theme/default/icons/mActionAddLegend.svg": "d756c3c84d9a1e613341676f8c3e8965", "resources/theme/default/icons/mActionAddMultiPoint.svg": "f9ade46e1458d5942ae557420592f836", "resources/theme/default/icons/mactionaddordergroup.svg": "a7e40299ca8607fd8ec9573f66cb95a5", "resources/theme/default/icons/mActionAddPoint.svg": "c85722428ece40150082f3d81bf170f3", "resources/theme/default/icons/mActionAddPolygon.svg": "83662dc01e024450dce5ecfaf1514edc", "resources/theme/default/icons/mActionAddPolyline.svg": "5d61a265d4c1e899cd171721d3b006ce", "resources/theme/default/icons/mActionAddRangeRange.svg": "99b93618e2906303244bc6a2ed20d3e0", "resources/theme/default/icons/mActionAddResourceWizard.svg": "9318a164ee340e04da837175aeea8820", "resources/theme/default/icons/mActionAddScaleBar.svg": "43afed23afb8200c15a543df1a450f3c", "resources/theme/default/icons/mActionAddSchemeData.svg": "c86e2f3e2356fd1ad82cdda941a9ad7b", "resources/theme/default/icons/mActionAddStyle.svg": "c60df25cbed4067a5ac0bc320463b816", "resources/theme/default/icons/mActionAddText.svg": "b6e185e764c5da36528cd7a83654d17d", "resources/theme/default/icons/mActionAddToCanvas.svg": "4f222a6648efa565f051aa2617caca5e", "resources/theme/default/icons/mActionAddVertexTool.svg": "73d0e0aa645810d8737db7604fb48d98", "resources/theme/default/icons/mActionAdjustLayers.svg": "42d197117a2af9818fcbefc935e03fa2", "resources/theme/default/icons/mActionAggregateNode.svg": "0e8e850ce17baa5e7c7aa3b238279790", "resources/theme/default/icons/mActionAligningToLine.svg": "6844c8fc2e7d023ebd31bfb23c907a9e", "resources/theme/default/icons/mActionAllEdits.svg": "1a13a6fe0c38adcdbbc315b963805233", "resources/theme/default/icons/mActionAnnotationImport.svg": "ed08c23f1bb2ea1dc03aee1496693ec6", "resources/theme/default/icons/mActionAnyDLAnalyze.svg": "cbcf45db82108f1e0ec97691d2b021ed", "resources/theme/default/icons/mActionAttributeBatchTool.svg": "f8853792345634f2ccbf3d5b3cc2ae9f", "resources/theme/default/icons/mActionAttributeBrush.svg": "bc8e8e7de8a8b5c4d75891072f58a9c9", "resources/theme/default/icons/mActionAttributeIndexManager.svg": "de8c1f6a81ef7a0dc047131f2b3bccca", "resources/theme/default/icons/mActionAttributeSelect.svg": "0a0e325e465cfcd8eb9a502e4fc9aac2", "resources/theme/default/icons/mActionAutoChange.svg": "2add0a98ec45eb1f992348a61b77107c", "resources/theme/default/icons/mActionAutoCutPolygon.svg": "5142adcd7b3d1702cc05eb4732bda7a5", "resources/theme/default/icons/mActionAutomaticClosure.svg": "100464d989b5520597726da001d2e6b7", "resources/theme/default/icons/mActionAutoParallelPolygon.svg": "d301512aec2983ee3fa88426f2c0583d", "resources/theme/default/icons/mActionAutoParallelPolyline.svg": "419b2e6153752735a075f87b2c6976af", "resources/theme/default/icons/mActionAutoProjection.svg": "1cfe66813280c607e1afc8715fa98983", "resources/theme/default/icons/mActionBackLastLevel.png": "0e06243d91122f7a759af354689e786c", "resources/theme/default/icons/mActionBackupDatabase.svg": "ab331f009a206badb5b6eb214ad0e555", "resources/theme/default/icons/mActionbatcgSetUniqueCode.svg": "3d5f12cd66429d20dc6b16d2e4af6a27", "resources/theme/default/icons/mActionBorderPolygon.svg": "70dd6b1cafe2eb371c897c2509ec0406", "resources/theme/default/icons/mActionBreakBySinglePoint.svg": "a4f86b74ab5d94b4bf90c8678155c8de", "resources/theme/default/icons/mActionBreakByTwoPoints.svg": "9faa1aeaf46c1a8a5f1a39a8f077293d", "resources/theme/default/icons/mActionBreakIntersectantPolyline.svg": "5891ffbba64c08cf4db8760d782465b1", "resources/theme/default/icons/mActionBreakWeld.svg": "f7f43dad61d9c4e3322eca488da3ab92", "resources/theme/default/icons/mActionBrush.svg": "e66b98adb06f1d8d702edb7f9ec5546f", "resources/theme/default/icons/mActionBufferAnalysis.svg": "d80ab987bd4a1fc371e2776e66425406", "resources/theme/default/icons/mActionCalculateField.svg": "f32837750c5840f154a2a749c8aade44", "resources/theme/default/icons/mActionCatalogManager.svg": "99e161a7b7367a9fa2929009134a653a", "resources/theme/default/icons/mActionChangePolylineByExitline.svg": "e08d8787b31f2c90f7378b382311f23a", "resources/theme/default/icons/mActionCheckAll.svg": "438f359d854c7ebedf6be6b88f7d0f6c", "resources/theme/default/icons/mActionCheckAndMaintain.svg": "a7e9601b46669c45f9096f011ab41bd1", "resources/theme/default/icons/mActionCheckNode.svg": "b14495714a6c980374bb8482d3211444", "resources/theme/default/icons/mActionCheckResult.svg": "2cf1b01c206622535c1e1825eb2b69cf", "resources/theme/default/icons/mActionCircularStringCurvePoint.svg": "310cea9398a663a4d4b13e528fa7ce5d", "resources/theme/default/icons/mActionClassification.svg": "995a538a5a6002821d6c50dc9a81fe63", "resources/theme/default/icons/mActionClearEdit.svg": "1c5a1c68aac83d68129868577ea30f7e", "resources/theme/default/icons/mActionClearLayer.svg": "32eba1e6735860eb142fff43a48eed54", "resources/theme/default/icons/mActionClearSelect.svg": "acc58e9be78e0153b7d7d1ed921b6230", "resources/theme/default/icons/mActionClose.svg": "e85dae4f037b08290dd34d668bcf06b3", "resources/theme/default/icons/mActionCollapse.svg": "3d2eba0c9ca35b25ec706a3e970a8b44", "resources/theme/default/icons/mActionCollapseTree.svg": "b39d593ea4774c1238ed6cd69f12b11f", "resources/theme/default/icons/mActionCommit.svg": "f354d7a233e4a5923580acbe25264d1f", "resources/theme/default/icons/mActionCommonNode.svg": "f2ab046d5257ee17f76363de01472e36", "resources/theme/default/icons/mActionComposeExport.svg": "53d0f2eaa80a97421ea812d32f5d9670", "resources/theme/default/icons/mActionConfigProperties.svg": "aa6aa2c381d8636a19e815a347831ed2", "resources/theme/default/icons/mActionConnectToFolder.png": "84a044edac968fdf06ecc30455f9b57d", "resources/theme/default/icons/mActionCopyMapImage.svg": "18260fca2fda975633899e07772ec225", "resources/theme/default/icons/mActionCreateDbConnection.png": "1194f60c3604a75a234b7c5829a9f623", "resources/theme/default/icons/mActionCreateInterNode.svg": "7d8cbee95202587a4593044f752438d2", "resources/theme/default/icons/mActionCreatePolygonBySnap.svg": "afd2ee4841eb4162f6d40825768359ee", "resources/theme/default/icons/mActionCreatePolylineBySnap.svg": "e80bb5083740e9bbf248b9ba3b28c988", "resources/theme/default/icons/mActionCreateProject.svg": "0d1f6ed64f39f7f3e3cacaeb376ac952", "resources/theme/default/icons/mActionCreateSpatialIndex.svg": "19063ef92e585e6b89139b95d8bc4ebc", "resources/theme/default/icons/mActionCurrentTask.svg": "37591573decfe551c7cb7418e2e8acad", "resources/theme/default/icons/mActionCustom.svg": "4f20d0450747420cbd2e9c9269193bee", "resources/theme/default/icons/mActionDatabase.svg": "5356e364576af2c38e4216283342db4f", "resources/theme/default/icons/mActionDataComparisons.svg": "05fd271af6c134f6872c80c489064d60", "resources/theme/default/icons/mActionDataExport.svg": "a4adf859430ab231122e24d6d6140459", "resources/theme/default/icons/mActionDataset.svg": "a06eea07e31055fe638120092fd03fed", "resources/theme/default/icons/mActionDataSource.svg": "899c06c28703ea8b15798c799a97cb02", "resources/theme/default/icons/mActionDataSourceManager.svg": "e265e51dc79a614afbba2d9a03eca71c", "resources/theme/default/icons/mActionDeleteAttribute.svg": "f487f09dcfad1b19da3cd46ff020c8aa", "resources/theme/default/icons/mActionDeleteBookmark.svg": "63a5159656718a85300368e95a87c965", "resources/theme/default/icons/mActionDeleteClassification.svg": "328e502956af43b1506928b8e03fc496", "resources/theme/default/icons/mActionDeleteClassificationCode.svg": "7cb7a62ac5e8be4028316c1c3e8836bc", "resources/theme/default/icons/mActionDeleteCustom.svg": "2c3e544e2be400c9f1fc224eb19baa6c", "resources/theme/default/icons/mActionDeleteDataSet.svg": "cf05da90c76989fe5796f0bfa9c69fd6", "resources/theme/default/icons/mActionDeleteDataSpecification.svg": "f4e03936c7564d14d752c7b9570726df", "resources/theme/default/icons/mActionDeleteDataTable.svg": "79ff705674f36ee519327ae6c51ae3d8", "resources/theme/default/icons/mActionDeleteDicItem.svg": "40f4b24ebc5ee91d2a05b715dc5ef94e", "resources/theme/default/icons/mActionDeleteLayer.svg": "10c565c23727bc79f0a3b3653c539e27", "resources/theme/default/icons/mActionDeleteLink.svg": "2d21c91ca791aed38b8135cf405fada5", "resources/theme/default/icons/mActionDeleteRange.svg": "f26af8d0a9917bb3d33bdbdd7665f2b9", "resources/theme/default/icons/mActionDeleteRevision.svg": "7f32ea7fb09ffa5851f57a64b548cf76", "resources/theme/default/icons/mActionDeleteSelected.svg": "27cc93f001805b310dd17a6cd761417f", "resources/theme/default/icons/mActionDeleteStyle.svg": "e8529586cd6c6c35725ae9ddf42678f8", "resources/theme/default/icons/mActionDeselectAll.svg": "acc58e9be78e0153b7d7d1ed921b6230", "resources/theme/default/icons/mActionDiagramStatistic.svg": "ba795b1a3c88b9ecc48bf3533793084b", "resources/theme/default/icons/mActionDicManage.svg": "5711827d34bf8c7f45bb9473339c9d5d", "resources/theme/default/icons/mActionDictionary.svg": "9f3227fd9fd4856b21ed0203f57d462e", "resources/theme/default/icons/mActionDictionaryManager.svg": "31af9da87c0ef66edf88279dc0979691", "resources/theme/default/icons/mActionDirectImport.svg": "2705f7d2b595f44bf7d41ba5469f8ecf", "resources/theme/default/icons/mActionDirectory.svg": "543010d3f4891a87337ea4a0553b6cc4", "resources/theme/default/icons/mActionDisperseLegends.svg": "44e0028546a1d892193bf85c1fc9ee68", "resources/theme/default/icons/mActionDownloadData.svg": "73cf487f43c6c67708755c77d1031b16", "resources/theme/default/icons/mActionDraw.svg": "79d6fde375c1d3a7c8be1e8ec5fc02d2", "resources/theme/default/icons/mActionDrawAnnotation.svg": "1ead0a1082e9fbae833bcfdd520f1f6f", "resources/theme/default/icons/mActionDropSpatialIndex.svg": "b22f1baf81a17fdc104b1bf05fd5c5ca", "resources/theme/default/icons/mActionEdgeTool.svg": "e51484e30111c77e3f34a0e367340041", "resources/theme/default/icons/mActionEditConnection.svg": "b0f644dd694a0c6554d1e1dcac139845", "resources/theme/default/icons/mActionEditCopy.svg": "83c8c2506e3d53b1b0b7865d1873a633", "resources/theme/default/icons/mActionEditCut.svg": "23ce1b2d297515aefe2dea9533184fab", "resources/theme/default/icons/mActionEditPaste.svg": "e59391b2630274e267ad10bb0a40a30d", "resources/theme/default/icons/mActionEditPolyline.svg": "4a3413a2c400b402733577b00c4e4a57", "resources/theme/default/icons/mActionEditSelect.svg": "20ed9f0380e99e271ccc04bf8590d084", "resources/theme/default/icons/mActionElementAlignment.svg": "da6e0b52d636403003a8bf06d81426bd", "resources/theme/default/icons/mActionElementOrder.svg": "9a4846b8d8c64c5a6b839fb5f5f2acab", "resources/theme/default/icons/mActionEmpty.svg": "7d03c7a62ba3b69a498063a52e7a0480", "resources/theme/default/icons/mActionExpandAll.svg": "5ce3b9872728fe1ab2db08881b6696e0", "resources/theme/default/icons/mActionExpandTree.svg": "8df56726928510b542d479f9d65bf2a4", "resources/theme/default/icons/mActionExport.svg": "9262fbccd6dce910b05542130d5b5d3d", "resources/theme/default/icons/mActionExportFont.svg": "fc19d534b16e7e87d74304dc9206913d", "resources/theme/default/icons/mActionExportGeometry.svg": "490f60da490788568dfcc1fb3ab8d57a", "resources/theme/default/icons/mActionExportPDF.svg": "7079bf9f8c4d4ef7ebf3fc26895c651a", "resources/theme/default/icons/mActionExportStyle.svg": "c3ebc4b4d9eef274c460e40db01734e1", "resources/theme/default/icons/mActionExtensionIntersect.svg": "b2b45155b3775a6082f0432db8667476", "resources/theme/default/icons/mActionExtensionPolyline.svg": "e5fdd4473d3a496bd3a0e67dfafc9902", "resources/theme/default/icons/mActionExtractFeatures.svg": "d756e45f408817a284947e1dc2015564", "resources/theme/default/icons/mActionFastScan.svg": "4a055d8089b712ba73b61939c3248f14", "resources/theme/default/icons/mActionFeatureClass.svg": "12960e7e5a7abafae89f6c75fe250172", "resources/theme/default/icons/mActionFeatureImport.svg": "bc1bf048cb86d53ee263523e8d49a33e", "resources/theme/default/icons/mActionFieldAssignment.svg": "55face7af26423b494df7490d9c9a1ef", "resources/theme/default/icons/mActionFileExit.svg": "014da3686c1d21b0df59f2b6d70e5a69", "resources/theme/default/icons/mActionFileNew.svg": "359e36e8c6e7793d550a4050765a169d", "resources/theme/default/icons/mActionFileOpen.svg": "d80181aaa8aa890cb0b7e48319a8d085", "resources/theme/default/icons/mActionFileOpen_small.svg": "e2471acb5d431a1203fe3c3956a4db79", "resources/theme/default/icons/mActionFileSave.svg": "68f08f30bdd326df72b092be223a0d70", "resources/theme/default/icons/mActionFileSaveAs.svg": "9836c3f4771b653b1ee967cae793b742", "resources/theme/default/icons/mActionFillHoll.svg": "7ef3bcc1919ef6f9f132ece12e007827", "resources/theme/default/icons/mActionFilter2.svg": "3ec913bd01c74a188cb4c055fbc03c14", "resources/theme/default/icons/mActionFlash.svg": "9bfe496e74b6e9a43be5908d499af2be", "resources/theme/default/icons/mActionFoldAll.svg": "740369ae0104d790e9d5fd18edd3f159", "resources/theme/default/icons/mActionFolder.svg": "1d4ea7410800af4f5b979135c4d14529", "resources/theme/default/icons/mActionFormView.svg": "f7e61b110fffd58a3803cba75c95aa40", "resources/theme/default/icons/mActionFull.svg": "de410eb887d59537eb5a97991fc1eebd", "resources/theme/default/icons/mActionGJB50000FFT.svg": "26fd67a57ea8dbbf034212047cd73c2e", "resources/theme/default/icons/mActionGoto.svg": "4cc2023f7b3f7813af02c1bcaf11ef9d", "resources/theme/default/icons/mActionGrid.svg": "305cb21216f9e8638e5521ba83f54ff2", "resources/theme/default/icons/mActionGridCheck.svg": "5cd471cd29ff479f87c6aac170c2c117", "resources/theme/default/icons/mActionGroup.svg": "30e60e1533289e2052cf4928583757c8", "resources/theme/default/icons/mActionGroupLayer.svg": "71a8905d793790d9303f2d32815c9079", "resources/theme/default/icons/mActionGroupLine.svg": "a3f83d7e3afba41c961550d99ef97136", "resources/theme/default/icons/mActionHelpContents.svg": "dfcc6f3e7a95c9fa377a24306877dda6", "resources/theme/default/icons/mActionHideAllLayers.svg": "16f373cad1b7b644477951a7ed66351b", "resources/theme/default/icons/mActionHidenFromBrowser.svg": "d38d6063e070d2d61dd6f55713896ab9", "resources/theme/default/icons/mActionHideResults.svg": "3eaa5c01dc7b1bacd0a6e5db58d1fdeb", "resources/theme/default/icons/mActionHideSelectedLayers.svg": "9d5f022d1375227b18a4fe01c6bcdb30", "resources/theme/default/icons/mActionIdentify.svg": "752e8589c7c43e261247a04eebfd130d", "resources/theme/default/icons/mActionImport.svg": "eccb61c61f90c7dd5be6f82059c499c1", "resources/theme/default/icons/mActionImportGeometry.svg": "18642deca79e43f652442d195b59fca3", "resources/theme/default/icons/mActionInspect.svg": "4f20d0450747420cbd2e9c9269193bee", "resources/theme/default/icons/mActionInverseCheck.svg": "9115eb0e5c06d728cf83af898f4a3f79", "resources/theme/default/icons/mActionInvertSelect.svg": "8f2be589133713a5d3ff36e50c1f01c0", "resources/theme/default/icons/mActionInvertSelectedLayers.svg": "9752a3091fe12e8fa6c6c07a53eb96b4", "resources/theme/default/icons/mActionInvertSelection.svg": "6149896f7ea1dbdade1677b31fcf5016", "resources/theme/default/icons/mActionLabelManager.svg": "d5d5d38222a6f64eca412317a25f962f", "resources/theme/default/icons/mActionLayer.svg": "f156bfe69e1e2508e5f0bf15db9ba44e", "resources/theme/default/icons/mActionLayerClassification.svg": "6aec85cd21332ccce4de83dcbc78a0c0", "resources/theme/default/icons/mActionLayerManager.svg": "add1fed077998d1e15ea21b0476024a9", "resources/theme/default/icons/mActionLayerSaveAs.svg": "baf726688146979e6d52548de7214a3d", "resources/theme/default/icons/mActionLayerSaveAsFile.svg": "b17ac7d94a0994f542a783cf8fb0d33b", "resources/theme/default/icons/mActionLayersOverview.svg": "4813c1d18f037f63dae432d4ef253cfe", "resources/theme/default/icons/mActionLayerTreeView.svg": "be643367e7ffd5de10d0dcb108e4c3a1", "resources/theme/default/icons/mActionLayout.svg": "28f9190ac68a00b0d7f6e04170d31cee", "resources/theme/default/icons/mActionLayoutManager.svg": "31be4d584dfc1ccafd8d01cdcd164fc8", "resources/theme/default/icons/mActionlinkage.svg": "b3ce4171038f9d82c8d04ea9cb3ad2d0", "resources/theme/default/icons/mActionLoadData.svg": "684e514f1cff1d2c9e95dd55a858df9f", "resources/theme/default/icons/mActionLoadLayerFile.svg": "f305a0ff3392689c805ce7984044289c", "resources/theme/default/icons/mActionLoadProjects.svg": "65d677b31784876d2af6e7c1fbf57b8a", "resources/theme/default/icons/mActionLoadRevision.svg": "874fed75579a074e530d87b91ad2ff07", "resources/theme/default/icons/mActionLocate.svg": "52f9968f5e0a6392c5f0a58db02b0825", "resources/theme/default/icons/mActionLock.svg": "26131931765f2aec7cc4bd0443f8f2ac", "resources/theme/default/icons/mActionLog.svg": "155acdfdf0f50cc1488483bb2eb844c1", "resources/theme/default/icons/mActionMaintain.svg": "ba47b24e4af73b927909cc5348f7bec8", "resources/theme/default/icons/mActionMaintainBSM.svg": "7acf0cf2e793fb29050771698c22b2e3", "resources/theme/default/icons/mActionMapsheetManage.svg": "1fd72e8c7b4d1b68cdfc45b6a1587ffc", "resources/theme/default/icons/mActionMapsheetNode.svg": "45219d3849e361f574ca86fcda80b3a1", "resources/theme/default/icons/mActionMapStyleManage.svg": "cf9354021a4a5b26ad660525ece1edff", "resources/theme/default/icons/mActionMeasure.svg": "a62f37b1ec481f1c2bab829f83849396", "resources/theme/default/icons/mActionMeasureAngle.svg": "5edcf784a0e8807d14944cce68a1a014", "resources/theme/default/icons/mActionMeasureArea.svg": "3ccde2a2802aac9ed7677d5c92bb3a0c", "resources/theme/default/icons/mActionMergeFeatures.svg": "58fca120fbe1d8ed6fd3a2dee1f90422", "resources/theme/default/icons/mActionMiddleLine.svg": "30f0034bc7c043e397e3f2ddc0ffc345", "resources/theme/default/icons/mActionMirrorTool.svg": "786dda30a600b3326b3ae42402dc443e", "resources/theme/default/icons/mActionModifyElements.svg": "59d8bbab970228ddbf2537c23da41ed3", "resources/theme/default/icons/mActionMosaic.svg": "34c034a1e13abe0d007225fbded76d7a", "resources/theme/default/icons/mActionMoveDown.svg": "e69d25c8b849110e43023f18f68c0bcd", "resources/theme/default/icons/mActionMoveElementBottom.svg": "5c963ec211036b7012aaab490bcb3741", "resources/theme/default/icons/mActionMoveElementDown.svg": "ed84988b86b920d732c1cc2c922e52a8", "resources/theme/default/icons/mActionMoveElementTop.svg": "8d5251c95c7b8b51c06719aed5991511", "resources/theme/default/icons/mActionMoveElementUp.svg": "0f2bae29c5c6a245ef7a1ef79d01d970", "resources/theme/default/icons/mActionMoveFeature.svg": "46a3b71b7e3282a07bcc8fe11a20916f", "resources/theme/default/icons/mActionMoveUp.svg": "c09793cc8b982dfc7160ca61174aa3af", "resources/theme/default/icons/mActionMoveVertexTool.svg": "fd8cdb5ff4b54efded668628786520da", "resources/theme/default/icons/mActionMultiEdit.svg": "1b4e305d58dbf3793eab33d6b474c28a", "resources/theme/default/icons/mActionNetworkStorage.svg": "e62bba269bce3c8ea8c4cf96e11bdd7c", "resources/theme/default/icons/mActionNew.svg": "c04a77f3fadc8f682577a4a1ffa31ea6", "resources/theme/default/icons/mActionNewAttribute.svg": "286fff33a3eb371889d740ae643cf9c4", "resources/theme/default/icons/mActionNewBookmark.svg": "5b5885cbdcefd11ac0e9d54461cfd914", "resources/theme/default/icons/mActionNewConn.svg": "4113d50441e7461c420e93a0b59d9bbf", "resources/theme/default/icons/mActionNewDataSpecification.svg": "c9c120156d64453162f017b2a4abbee7", "resources/theme/default/icons/mActionNewFileGdb.svg": "f5721d9a6558d415f3a67c63b78a95cc", "resources/theme/default/icons/mActionNewFolder.svg": "d7afc17f864be5b81aae706f5bb9141e", "resources/theme/default/icons/mActionNewMapElement.svg": "6566f4e1671d310ab3ed30117c44e5ef", "resources/theme/default/icons/mActionNewPKG.svg": "4156b6fbf9e9a09e8889e1ae0b0330e4", "resources/theme/default/icons/mActionNewSchemeData.svg": "7807bb77c398afb16afd46463672f893", "resources/theme/default/icons/mActionNewTableRow.svg": "f2fd0ead19625b325f33359e6f12a55f", "resources/theme/default/icons/mActionNewTask.svg": "7618baf3704550ed1ae0505eb74d1037", "resources/theme/default/icons/mActionNewTileClass.svg": "0166b686d417d0a81b5ae5b1791b4169", "resources/theme/default/icons/mActionNodeDiluting.svg": "6a864c4a9ce1fdd07ba68f132c980643", "resources/theme/default/icons/mActionOpenData.svg": "8cdca77f195e267228b878d1d7d82fe4", "resources/theme/default/icons/mActionOpenDirectory.svg": "d37744c14f87326d779ce634086a4a9b", "resources/theme/default/icons/mActionOpenJS.svg": "de439993a9ab1770b8e2fb17f5a8d0e1", "resources/theme/default/icons/mActionOpenLayout.svg": "da607b272ab28493f7b354a684388bae", "resources/theme/default/icons/mActionOpenScheme.svg": "781accf4794f648dcf2f8c4097ff8fa7", "resources/theme/default/icons/mActionOpenTable.svg": "b1bdd4c59286ff406b8262f1b61d54e2", "resources/theme/default/icons/mActionOptions.svg": "50f9ee8b59e5e364ba52222d2c55a8fb", "resources/theme/default/icons/mActionOraganizationManager.svg": "d386d4dc75ac892a620c5f726295214e", "resources/theme/default/icons/mActionOverView.svg": "c8df9418bb2d3606aa53e30ab4daa93f", "resources/theme/default/icons/mActionPan.svg": "98a5dbf4184531ba2a2c68db92806456", "resources/theme/default/icons/mActionPanToSelected.svg": "974a9cf2f5750b418b474942b5dcb2a1", "resources/theme/default/icons/mActionParamSetting.svg": "10cb60a011e7788aac961c212e1c8608", "resources/theme/default/icons/mActionPolygonIncise.svg": "2d82c0b0f5739c6bf787c4eab8064a6a", "resources/theme/default/icons/mActionPolygonInterattraction.svg": "622f8a50bc5ceb068e484420b9241020", "resources/theme/default/icons/mActionPolygonOverlay.svg": "95411d192cad3e679a01556a44ba29d5", "resources/theme/default/icons/mActionPolygonToPolyline.svg": "22b2360fe102a0c1d93c7c387aa86026", "resources/theme/default/icons/mActionPolylineToPolygon.svg": "c08885aa366dc2ec78104616d564ec31", "resources/theme/default/icons/mActionPreprocessingScheme.svg": "2cce25bc39ad3c0e64e4ede8a7dbf790", "resources/theme/default/icons/mActionPreprovessingTB.svg": "f8c7613e852b0c9af5f8e3038fd4b73f", "resources/theme/default/icons/mActionPrint.svg": "31c995fa5d814d9746b94d0e3780260b", "resources/theme/default/icons/mActionPrivilegeManager.svg": "d406a3ea8e70ac6188f7ff6cda412fdf", "resources/theme/default/icons/mActionProperties.svg": "643c2dbf159641c13a90dd282c750b66", "resources/theme/default/icons/mActionPropertiesWidget.svg": "7b8bdc3ad81fe89c339754370467ef05", "resources/theme/default/icons/mActionProperty.svg": "0f5fd9de9f38273462de2ef945b9a3ca", "resources/theme/default/icons/mActionQgsAddView.svg": "77154a2bd7a278ec5417f54bea869039", "resources/theme/default/icons/mActionQueryByLine.svg": "100a77b190342c4f4d612d2f4db8964c", "resources/theme/default/icons/mActionQueryByPoint.svg": "15630a334591356d90a90216319a3d48", "resources/theme/default/icons/mActionQueryByPolygon.svg": "6a70cc390d0f99105123a68aac36ee17", "resources/theme/default/icons/mActionQueryRoot.svg": "f442d02fb5ef3741fdf1624a3f02f5d7", "resources/theme/default/icons/mActionRasterImport.svg": "2417938f794ce78543633dc544bca4d0", "resources/theme/default/icons/mActionRedo.svg": "8c028f9ef70e474d7387f9b460a65eb6", "resources/theme/default/icons/mActionRefresh.svg": "52fa4b4278264c367eda284c53d15f89", "resources/theme/default/icons/mActionRegionExport.svg": "845dd15fd40ad4f743623469b5b3fdb4", "resources/theme/default/icons/mActionRegionImport.svg": "8dbd184a3b428ce6e102f7056e116f8b", "resources/theme/default/icons/mActionReload.svg": "43784ed0de3112c14d5921b6303d63a3", "resources/theme/default/icons/mActionRemove.svg": "e6754b6e1d730a5c882c2db92eea2950", "resources/theme/default/icons/mActionRemoveAllLayer.svg": "a6da6d6063b7329140356336a91090cf", "resources/theme/default/icons/mActionRemoveLayer.svg": "1c49ecbc2147eba97ec8aad9633f7ccd", "resources/theme/default/icons/mActionRemoveRepeatData.svg": "95b636aa514362fb03154a017f8eadc9", "resources/theme/default/icons/mActionRemoveRepeatedPoints.svg": "f3559b1f0ead7a72c40d87131c92acd8", "resources/theme/default/icons/mActionRemoveSchemeData.svg": "9194bf7bea36f62dc7dc2f3b30b90cbc", "resources/theme/default/icons/mActionRemoveVertexTool.svg": "8ae82b51d34a411968de1a9d97307367", "resources/theme/default/icons/mActionReName.svg": "2f4f8cbcf71196f22f219881f3e971d4", "resources/theme/default/icons/mActionReset.svg": "741f7fb42d42849d612fc20b12b7cd35", "resources/theme/default/icons/mActionResetDirPath.svg": "c344596ea4ddfc767152bdeb7c02ed27", "resources/theme/default/icons/mActionResolveSharePointError.svg": "f59d218ed27b3d3e93b66853590a8e94", "resources/theme/default/icons/mActionResultExport.svg": "e05fe9e6f120fff6f9fe567427d73eae", "resources/theme/default/icons/mActionResultPreprocessing.svg": "d915ed03dcd61c0d516c76a4b87d0aa4", "resources/theme/default/icons/mActionReversePolyline.svg": "d55a0018bb397763cc96e462198fdbe2", "resources/theme/default/icons/mActionRevertToRevision.svg": "0392f2d180aee9d9365959f9245e265b", "resources/theme/default/icons/mActionRightAngle.svg": "4c55097541c57f3764ca125d0920ef85", "resources/theme/default/icons/mActionRotateFeature.svg": "3e22ce01e2c0c965d96fc17ccf57f686", "resources/theme/default/icons/mActionRuleManage.svg": "15482f473e3fe2874ab18f9f2e8fbadb", "resources/theme/default/icons/mActionSaveAllEdits.svg": "94a89bc9b11cb90a59fc8f044c0a5936", "resources/theme/default/icons/mActionSaveAsScheme.svg": "13d249919c23815a608a9ff5d28846d6", "resources/theme/default/icons/mActionSaveEdits.svg": "777486ea8c29a2a365dfe80977fa17c1", "resources/theme/default/icons/mActionSaveLayout.svg": "8b3789e6e0dd8223130b84000d3ed79f", "resources/theme/default/icons/mActionSaveScheme.svg": "4f281e045c96432fd1cd7a82ca6f606b", "resources/theme/default/icons/mActionScaleBar.svg": "537d6a364f6c093e6b585b7e049b29af", "resources/theme/default/icons/mActionScaleNode.svg": "50f99f8accdc8751b270032cb556b39f", "resources/theme/default/icons/mActionSchemeBatch.svg": "dc5b9b397f9281a476733882693b6c47", "resources/theme/default/icons/mActionSchemeFilter.svg": "717cb0048b15305a8cadd452718d340c", "resources/theme/default/icons/mActionSchemeFit.svg": "43ce16a7914f0ed136fb52182040b068", "resources/theme/default/icons/mActionSchemeManage.svg": "c3514670076c47f378bf24f59d007e43", "resources/theme/default/icons/mActionSchemeNoFit.svg": "ddb52d6845b46bb2da8f44d6515c48ad", "resources/theme/default/icons/mActionSchemeShow.svg": "bd93bfc5885d5307f38203892ee44ef2", "resources/theme/default/icons/mActionSchemeSourceManage.svg": "49f8d190098edf63f5afa2a4fcb1b343", "resources/theme/default/icons/mActionSchemeTargetRoot.svg": "4c51b15a288a6857cb595ca87badc50d", "resources/theme/default/icons/mActionSearch.svg": "c53fee0f34c42a7a9d8e898532a3b86d", "resources/theme/default/icons/mActionSelect.svg": "af097cfbf7068555e0316d56705f153a", "resources/theme/default/icons/mActionSelectAll.svg": "05fe2f51d3089764d072f9ace468d8b4", "resources/theme/default/icons/mActionSelectAllLayers.svg": "fc3274b291accf2f3c94e7b6d21b496d", "resources/theme/default/icons/mActionSelectPolygon.svg": "de8682bdb5e3b611224a6ee8b52515ab", "resources/theme/default/icons/mActionSelectRadius.svg": "06c743aeea2546796c169625cdbfeb0c", "resources/theme/default/icons/mActionSeparateFeatures.svg": "47a255fe5cc8c8cd23a512e458ccf01a", "resources/theme/default/icons/mActionSeparateLayer.svg": "dca40eff33ddc48a7c0a1221c0aae739", "resources/theme/default/icons/mActionServer.svg": "1ab2380a5b5e7915e80d6b7f232d3bd2", "resources/theme/default/icons/mActionSetBottom.svg": "efce405a42a008cf74a9663e46362ab0", "resources/theme/default/icons/mActionSetClipEnv.svg": "cfc446c1a8ce1801fb3682f4caf2185b", "resources/theme/default/icons/mActionSetClipPolygon.svg": "0fc055217ef4255c7e588f08e3edf780", "resources/theme/default/icons/mActionSetDataSource.svg": "92fea7f7b80c74bb4f22cbedbd160e81", "resources/theme/default/icons/mActionSetNoClip.svg": "729fd670d5e947741b64c6ed7ee385b7", "resources/theme/default/icons/mActionSetNull.svg": "33deea05fa20968c10a0c3123e47c0d6", "resources/theme/default/icons/mActionSetSpatialReference.svg": "64f9c175f0e21d1128c10aa08dbcad85", "resources/theme/default/icons/mActionSetting.svg": "2c6d37e1466939c8e16f1cd04ff48d24", "resources/theme/default/icons/mActionSettings.svg": "98160adbf1b7bc7dfa0064d5da680278", "resources/theme/default/icons/mActionSetTop.svg": "57517e5161ba671327848c4c2495ce56", "resources/theme/default/icons/mActionSharing.svg": "8f5e6dffd6231a6858fc5f56ce1a60b2", "resources/theme/default/icons/mActionSharingExport.svg": "10de78f4fe80a0cef1a3609dd40a67f0", "resources/theme/default/icons/mActionSharingImport.svg": "9bed0a42714abdd71b65742d1ca1b26b", "resources/theme/default/icons/mActionShowAllHide.svg": "f6dea326e1c06484a7dbaa3a1c2313fe", "resources/theme/default/icons/mActionShowAllLayers.svg": "1069904cfba0dbc27c02e6659bacbc49", "resources/theme/default/icons/mActionShowBookmarks.svg": "18aa642ffd432316af2e4410f4b29d7d", "resources/theme/default/icons/mActionShowFilter.svg": "ace4d7974edfb60aca730fd5095c3259", "resources/theme/default/icons/mActionShowGridTool.svg": "682e24e73864e87cfdb33e9bd3e9809f", "resources/theme/default/icons/mActionShowLayersSet.svg": "2ac82d593bce15962b546a4aebe8fe48", "resources/theme/default/icons/mActionShowPluginManager.svg": "99436035696bb2cb8f10f5c098c4b44f", "resources/theme/default/icons/mActionShowResults.svg": "f56c5cd78219b41cd930774bb121024b", "resources/theme/default/icons/mActionShowSelectedLayers.svg": "a838ae1987783d19767e54228de05aa1", "resources/theme/default/icons/mActionSimplify.svg": "9c03c4c49fcd354e04832dd253c880a1", "resources/theme/default/icons/mActionSmoothTool.svg": "707f96d7e602170da613f80b679c8905", "resources/theme/default/icons/mActionSpatial.svg": "bef0b6a230ff89396636be69e8b40ef7", "resources/theme/default/icons/mActionSpecialAttributeBrush.svg": "24fc0d1c64c25fe84b8b2cfe896141cd", "resources/theme/default/icons/mActionSplitByPolygon.svg": "538583d5099e9abc25d5b1a9268e10e7", "resources/theme/default/icons/mActionSplitByPolyLine.svg": "8701b4efde0bae3ed46376ef173e4787", "resources/theme/default/icons/mActionSplitBySelect.svg": "26580003f206a37877bd8d4fb7c7e83a", "resources/theme/default/icons/mActionSplitFeatures.svg": "58f0d4717c6590d5116d6c4e3cf6661a", "resources/theme/default/icons/mActionSql.svg": "19852025b86712876a6f8722151414af", "resources/theme/default/icons/mActionStartCheck.svg": "36f7176cf331fccd0b34d63d0ea1330a", "resources/theme/default/icons/mActionStartImport.svg": "c6016f45b0af8a4852c51b94390c8226", "resources/theme/default/icons/mActionStreamline.svg": "e5cbf8db4c102b2afb6c8231f59b5c17", "resources/theme/default/icons/mActionStyleView.svg": "730e0af4ddac5a0fb1f5f539fd30622b", "resources/theme/default/icons/mActionSum.svg": "d017046d48ce90ed5bceab7d3e6d6f1f", "resources/theme/default/icons/mActionSwipe.svg": "12847b35a09965af255f83f9b227e3f0", "resources/theme/default/icons/mActionSysSwitch.svg": "34367f856ddc6239e12d778c5a19b816", "resources/theme/default/icons/mActionTableImport.svg": "8deaa47f6625c021e0fe3236c1d7b94d", "resources/theme/default/icons/mActionTaskManage.svg": "970769a0f3cd8be7dd294a765ab2187e", "resources/theme/default/icons/mActionTeamConfig.svg": "e84b0043b2cb13f560f94a0d6721e07c", "resources/theme/default/icons/mActionTeamEdit.svg": "b0114a6fc46120440e19c53730a0581c", "resources/theme/default/icons/mActionTeamProjectInfoStatistic.svg": "3129a2940c9803c5ca6ba12bef78cb00", "resources/theme/default/icons/mActionTeamRevisionSlider.svg": "5f1ab9a8ba1f48f0fcb3cfd5984862cc", "resources/theme/default/icons/mActionTeamServer.svg": "fecca577325287d69541a40ded17fadb", "resources/theme/default/icons/mActionTeamTimingAcquireLog.svg": "48487ce93bfd8cd3d0aa77a2c26ce9cd", "resources/theme/default/icons/mActionTeamTool.svg": "fc55777995fd4de917463da7c9f5424b", "resources/theme/default/icons/mActionTemplate.svg": "01927217e00be004e12f16b651440359", "resources/theme/default/icons/mActionTemplateCompose.svg": "af1adc1a48861d24dc688b9778d3d80e", "resources/theme/default/icons/mActionTemporaryLayer.svg": "68e4b5c61088a15f89d939c81ff86b87", "resources/theme/default/icons/mActionThematicAttributes.svg": "6b6ee135eedc395c6eb8e04b92a5cab0", "resources/theme/default/icons/mActionTileImport.svg": "903e13e6c35e1ee083a61b23918688de", "resources/theme/default/icons/mActionTiling.svg": "c8e25a3eda0bc19b9778168ecf753375", "resources/theme/default/icons/mActionTimeSlider.svg": "30df8efe796c12114471323077bca30c", "resources/theme/default/icons/mActionTimingAcquire.svg": "489dd9a97dffb720b3162dc14bc86a9e", "resources/theme/default/icons/mActionTimingAcquireSetting.svg": "7ecabd8416d95df2f92da8ff60d44da9", "resources/theme/default/icons/mActionToggleEditing.svg": "29723b6d47441f7bb494714ea429edde", "resources/theme/default/icons/mActionToolBox.svg": "2c9169fc1c7e50f15b84f71bafd17a6d", "resources/theme/default/icons/mActionTrim.svg": "225c5b9cc91e4f5e8ca4aaf8787780c6", "resources/theme/default/icons/mActionUndo.svg": "ec0a88d3076c323ae59118eca56b8163", "resources/theme/default/icons/mActionUngroup.svg": "7bc078804d80699dc8cc91e2082f84d4", "resources/theme/default/icons/mActionUp.svg": "7999c9a02eda90ac2f42b6c3641e904b", "resources/theme/default/icons/mActionUpdate.svg": "40ba9725c8cdd5e1fe69108bb6f8525d", "resources/theme/default/icons/mActionUpdateRecords.svg": "5a46d098c69fbf39923ffe3178018278", "resources/theme/default/icons/mActionUpdateToRevision.svg": "80e6f808eeb64d71829e44a827b9b51f", "resources/theme/default/icons/mActionUploadData.svg": "4817a531daa8606bc9531d50957971c6", "resources/theme/default/icons/mActionUserRoleManager.svg": "e3e59465ff0ccfc907414df8628b5723", "resources/theme/default/icons/mActionVertexTool.svg": "daa8e981408b835ddbe36af3bed62e19", "resources/theme/default/icons/mActionVTSPreview.svg": "f9c9643fd1b174e56abae7e8a5ffe7ba", "resources/theme/default/icons/mActionWeldPolyline.svg": "35c012816b7f000837e465109dcb1f95", "resources/theme/default/icons/mActionYearChangeNavigation.svg": "943edf66d680b0ee7fc4a2d68504b6ab", "resources/theme/default/icons/mActionYearChangeRegression.svg": "b4f5be92104d693da3a88a817166c20e", "resources/theme/default/icons/mActionZoomFullExtent.svg": "6f21d610891d2924bcfe88c73fb764f5", "resources/theme/default/icons/mActionZoomIn.svg": "1042c451e38bbbdea2736329514618a0", "resources/theme/default/icons/mActionZoomInCenter.svg": "f02ed86aaccae6e9a97ecbb852a0b224", "resources/theme/default/icons/mActionZoomLast.svg": "5c42ac5098f8e0f648dbe3de9bb4bad8", "resources/theme/default/icons/mActionZoomNext.svg": "a9fa6a5c006dd0c0840aa4e1774de19d", "resources/theme/default/icons/mActionZoomOut.svg": "7a84e09a885a48b381d69d0b5d3ff69a", "resources/theme/default/icons/mActionZoomOutCenter.svg": "c84df5bb54c1fc4da3656025dd3bd6bd", "resources/theme/default/icons/mActionZoomToBookmark.svg": "9073facd9ee913217bed1c2093a4e098", "resources/theme/default/icons/mActionZoomToLayer.svg": "82c760fa362ccf923603a9ab657d737f", "resources/theme/default/icons/mActionZoomToSelected.svg": "e934636f2b504da8ab0e4e6d3e859bac", "resources/theme/default/icons/MaintainRegionDic.svg": "e220cc3e4c97e63296684f3d9e38d5f8", "resources/theme/default/icons/mapConfig.png": "f7b863779cc89c8be7605bc56a65703c", "resources/theme/default/icons/mapConfig.svg": "c7a0b74014cc0599c1e82c0c8b8be1f1", "resources/theme/default/icons/markdown.svg": "b1318f7383ab486afa82e4568aa58185", "resources/theme/default/icons/matlab.svg": "8d5f10b9fb25f9df14e71d6e4eda19a7", "resources/theme/default/icons/mAutoChangePolygon.svg": "4aed8b896926a1d832f64933d1257f52", "resources/theme/default/icons/mAutoCompletePolygon.svg": "3c11c43f10997872241c257e9987d46c", "resources/theme/default/icons/mComposeSchemeManage.svg": "d352afeceb179d2d645026aa873c5b92", "resources/theme/default/icons/mDataExportSchemeManage.svg": "a7e3c9f7ad828fb76c0cf4cfb13c097b", "resources/theme/default/icons/mDataImportSchemeManage.svg": "fc35fcdf359f9f81fa2ae510ab87c4c1", "resources/theme/default/icons/mDataTransSchemeManage.svg": "c9bf6fa291e4976bf0983bd5288934ab", "resources/theme/default/icons/measureConfig.svg": "903161e927f84e5613a6dd4c9922a1bd", "resources/theme/default/icons/merge_h.svg": "e18a2b6bbdb4a1e6d8a95644122e60d9", "resources/theme/default/icons/merge_v.svg": "a8527f6026fe7118c129f5cba6fb1016", "resources/theme/default/icons/metadata.svg": "b2e273799dbfa6dbc52e8228f5bdbdd9", "resources/theme/default/icons/mGeneratingDLJX.svg": "4c69197baf2338313faf3993d6b115e8", "resources/theme/default/icons/mGeoPackage.svg": "7c73ffb090a38af7feab29aa12152423", "resources/theme/default/icons/mIconAddDBServer.svg": "8c825e00c2816ab43183b541733d71f8", "resources/theme/default/icons/mIconAddServer.svg": "7112be64f8be6720026bc2a8bf9c625d", "resources/theme/default/icons/mIconAfs.svg": "26bc632ff2d7c289e202f6c8f61e1c03", "resources/theme/default/icons/mIconAms.svg": "630bac3c1a415087351fe6492e4bb83d", "resources/theme/default/icons/mIconAnalyseFlow.svg": "ea21512744b1a11c266e5b9d1520389a", "resources/theme/default/icons/mIconAnnotationLayer.svg": "fbe179641e24ec8c54a302265cca4f2f", "resources/theme/default/icons/mIconAnnotationMLayer.svg": "68d1aa7332c4c52ba3e969a14417ae19", "resources/theme/default/icons/mIconApplication.svg": "94bea3681edb4be10e23727c67923918", "resources/theme/default/icons/mIconApply.svg": "51876eb236913705ce2756c72b7fb49a", "resources/theme/default/icons/mIconAttirbuteAssign.svg": "b93e85f9184b920d402f862abf94357b", "resources/theme/default/icons/mIconAttributeTable.svg": "e7db893217b5b1baac3961b549108479", "resources/theme/default/icons/mIconAuxiliaryStorage.svg": "424505094deccde793bb07080494a9b1", "resources/theme/default/icons/mIconCad.svg": "fef13370469b1722e4dcc26d46a89f57", "resources/theme/default/icons/mIconCalEllipsoid.svg": "823474172c2ccec64f5adaee114fd82a", "resources/theme/default/icons/mIconCatalogResource.svg": "6c8e7c6dfd9c958328f27092fb00c3c3", "resources/theme/default/icons/mIconCatalogRoot.svg": "01afcfbe57ea1a4a90b6daf78af9a2a9", "resources/theme/default/icons/mIconChange.svg": "7cc1b16efb9fcf0c8144b9c1e86d258e", "resources/theme/default/icons/mIconCheckLayer.svg": "841eb956c21eb7f7557937b56648eea2", "resources/theme/default/icons/mIconClearText.svg": "f20b46fc4f835d7d636f97f1d7770c63", "resources/theme/default/icons/mIconClearTextHover.svg": "6bf93a9f31af24cc804503c71aadbfa7", "resources/theme/default/icons/mIconClose.svg": "7787829dfdddf0c0ff3306e96b5998fe", "resources/theme/default/icons/mIconCode.svg": "e6351f72e8d1f68207c574af6f6557ad", "resources/theme/default/icons/mIconCodeSpecifiation.svg": "e0a81b82fa77022b5850eb16a0382690", "resources/theme/default/icons/mIconCodingScheme.svg": "654f59de125796f54e270e6278e60d34", "resources/theme/default/icons/mIconCodingSchemeRoot.svg": "06c8ad7cf27e496674ed6bdc31db1ba7", "resources/theme/default/icons/mIconCompoundLayer.svg": "d1026c32abaa5a0591f7a5c7b693eac8", "resources/theme/default/icons/mIconConnect.png": "c4d29a2a304cc265c34def6e2a1cc7ed", "resources/theme/default/icons/mIconCritical.svg": "479fc5b611396c2c535a2bc18a808ef6", "resources/theme/default/icons/mIconDaMeng.svg": "74e85fd3c915ccc760b40a05f961bae5", "resources/theme/default/icons/mIconDataSet.svg": "cb718d909534dadd72d4b72dbddb1a4a", "resources/theme/default/icons/mIconDataStructure.svg": "fd89f1f6fae2b928a841aea919995f34", "resources/theme/default/icons/mIconDbSchema.png": "1b79c7357dd1f0e5eb1f4d47f759b4f6", "resources/theme/default/icons/mIconDelete.svg": "b7645486da851a6b3272d304f2a6dd86", "resources/theme/default/icons/mIconDeselected.svg": "75733116db9e219b0f4382385342b511", "resources/theme/default/icons/mIconDicItem.svg": "68e57fc565b36ae2e1d060ce6dc8c964", "resources/theme/default/icons/mIconEditableEdits.svg": "455990cd70b279a43e6fe1483ef47b3b", "resources/theme/default/icons/mIconError.svg": "affb8053194df39dda4f105433c209d7", "resources/theme/default/icons/mIconExportCatalogDataNode.svg": "66c846fd3b5f7a771e834b12555d546e", "resources/theme/default/icons/mIconExportCatalogFileNode.svg": "719a5a83513ddb084966a21c3909092a", "resources/theme/default/icons/mIconExportCatalogRootNode.svg": "51d5c34391a171eed24ebfc860fc710b", "resources/theme/default/icons/mIconExportSchemeNode.svg": "810c27933bac0c415bba59ad0e28619a", "resources/theme/default/icons/mIconExportSchemeRootNode.svg": "cd1a0f9d1adc73d30ad78f03e26e3125", "resources/theme/default/icons/mIconExpression.svg": "4a7c9010d4faef5cb7dd50d4b063bf1d", "resources/theme/default/icons/mIconExpressionSelect.svg": "d5a11b917f78b8963933e25463ed3f13", "resources/theme/default/icons/mIconExternApplication.svg": "76860ff954accd3d41779f1b13614a03", "resources/theme/default/icons/mIconFcs.svg": "842114c237df2e6488115f32bf6179a0", "resources/theme/default/icons/mIconFifthLevel.svg": "64fd05b7bc8fcc3d5613bff14477230b", "resources/theme/default/icons/mIconFile.svg": "3047ab35641e5516a3eb281bada2613a", "resources/theme/default/icons/mIconFirstLevel.svg": "411ddf0a99c68e8adf1c08389bd2ea10", "resources/theme/default/icons/mIconFolder.svg": "cf1ca6b8396b31dcca5b8f33eb43ceb4", "resources/theme/default/icons/mIconFolderCatalog.svg": "4eb1ba9a379ada6a5d6bdb205259bb04", "resources/theme/default/icons/mIconFourthLevel.svg": "638de27d6466f21ec317cb203840ae5d", "resources/theme/default/icons/mIconFtp.svg": "a199167e87d48e535a28a0f1bba7b62b", "resources/theme/default/icons/mIconFtpConnection.svg": "8a392e40f69a0f418fdbdd881165da08", "resources/theme/default/icons/mIconFtpFile.svg": "dd9f4404c69b29266260a9a9d8df269b", "resources/theme/default/icons/mIconGBase.svg": "fb1586a853c2904b60aaae867f76c85a", "resources/theme/default/icons/mIconGdb.svg": "faf3ba5fe031bfdce3aed9a3f46f078f", "resources/theme/default/icons/mIconGeoMap.svg": "5fddaa3bf5d340522608d62df060290f", "resources/theme/default/icons/mIconGeoModel.svg": "1062170310062340d8e756bf956bc804", "resources/theme/default/icons/mIconImage.svg": "d7d21b7fb0e283fcf8411c03f3e31845", "resources/theme/default/icons/mIconInfo.svg": "3c0cf72d3f29ee6108e7d408a9103694", "resources/theme/default/icons/mIconInnerLayer.svg": "8191e0d1b9834eec58a8ee696da1ceeb", "resources/theme/default/icons/mIconKingBase.svg": "8ad55c2113ceee058166bdd7da6fd468", "resources/theme/default/icons/mIconLayer.png": "21cf151b551b35eed6e034ed7112dbc0", "resources/theme/default/icons/mIconLayer.svg": "9540c68b59d83e5f407a81cb364fe39e", "resources/theme/default/icons/mIconLayoutTemplate.svg": "215df0affb2b3b0d8895161fcc9bdafa", "resources/theme/default/icons/mIconLayoutTemplateRoot.svg": "99d5dce6929dd587527835636b774346", "resources/theme/default/icons/mIconLineLayer.svg": "4c69197baf2338313faf3993d6b115e8", "resources/theme/default/icons/mIconLineMLayer.svg": "fe6b4178b48f8999d83c10155c1a0b0e", "resources/theme/default/icons/mIconLoading.gif": "8fa9058348a86d759eb315dd66de2714", "resources/theme/default/icons/mIconLocalServer.svg": "f890500950ee4e3e5468082e57eabcf9", "resources/theme/default/icons/mIconMapFile.svg": "627ca8d2c2c1796f646e9216d9349bea", "resources/theme/default/icons/mIconMapStyle.svg": "b6356008ed553c02b7a31e7be2b3289f", "resources/theme/default/icons/mIconMixCatalog.svg": "4eb1ba9a379ada6a5d6bdb205259bb04", "resources/theme/default/icons/mIconModelLayer.svg": "72f4b78bf3b06435aef0e06e5ca151e2", "resources/theme/default/icons/mIconModifyServer.svg": "c7d9ee62d4aa9720f2f15a3f22e86b3e", "resources/theme/default/icons/mIconMySQL.svg": "a99effe63b8a0afe08ca87c291451c6e", "resources/theme/default/icons/mIconNewGroup.svg": "e27402c3f3b6866ea996eff280c1329d", "resources/theme/default/icons/mIconNow.svg": "6a8ae624d3a553b4db8d03e60170fee0", "resources/theme/default/icons/mIconOffice.png": "6303c5abbdcdd3a24281007c3f75910e", "resources/theme/default/icons/mIconOracleSpatial.svg": "96b27c5bb382407c8fbb3f1d5cdfbb45", "resources/theme/default/icons/mIconOutsideLayer.svg": "2e84bf82fd9ba6d6d3b170ff227e43b7", "resources/theme/default/icons/mIconOws.svg": "861d35b91c66a25907dd731a522795fd", "resources/theme/default/icons/mIconPg.svg": "870e241bd22d89b83aa26e69b79e44d9", "resources/theme/default/icons/mIconPhysicalTable.svg": "62556fe79abc5c1aa1b139a4caab4f97", "resources/theme/default/icons/mIconPhysicalTenseTable.svg": "8495bd64272f9519ba3639bb108ce6a1", "resources/theme/default/icons/mIconPointLayer.svg": "95251fc052d089796b41a46072661ad2", "resources/theme/default/icons/mIconPointMLayer.svg": "3ace9ed797c1cd91848f6e75df4ce5cf", "resources/theme/default/icons/mIconPolygonLayer.svg": "da646fa3fef5ce81f9f0e9ace1d0be1e", "resources/theme/default/icons/mIconPolygonMLayer.svg": "b76b1c64744e78f711a6ed163b6fbf29", "resources/theme/default/icons/mIconPostgis.svg": "d95101a8f8b9eaa80083d646e5383659", "resources/theme/default/icons/mIconProjectionEnabled.svg": "820493124a75fe953400f9f2ceba9d34", "resources/theme/default/icons/mIconProperties.svg": "b57f75b3eccce67243c8143fc010f052", "resources/theme/default/icons/mIconRaster.svg": "a65c7579f3849569b88caa69d46d6d1c", "resources/theme/default/icons/mIconRasterGroup.svg": "b22c2b30b5b48777566a041b02ca20d7", "resources/theme/default/icons/mIconRasterLayer.svg": "37358bd2779dd20a7580a1b4b354913b", "resources/theme/default/icons/mIconRegionItemNode.svg": "0c892403655a142a739da4a445f10d69", "resources/theme/default/icons/mIconRegionNode.svg": "2b8d8fcdb3054ca0b50d165d76a0e529", "resources/theme/default/icons/mIconRegionRoot.svg": "a05b73abd59d65752a387c0887afeaa1", "resources/theme/default/icons/mIconRegionRootNode.svg": "b7b0001fe203a7c6e9bfaf88d2f2db4c", "resources/theme/default/icons/mIconRegionTree.svg": "981c3314204c6c2ddb53e50da0181732", "resources/theme/default/icons/mIconReload.svg": "4ee18f3e56c0a3ce09a1cc261ca9d12d", "resources/theme/default/icons/mIconRemoveServer.svg": "1644b9d1c6aa137862d1ae8788374b3e", "resources/theme/default/icons/mIconReportWizard.svg": "fc1234e9224f00f23323c50723568edb", "resources/theme/default/icons/mIconReserveSelection.svg": "8ab255dc5906d1cf88675446c3e09240", "resources/theme/default/icons/mIconResourceCatalog.svg": "4eb1ba9a379ada6a5d6bdb205259bb04", "resources/theme/default/icons/mIconRule.svg": "5115e07bbedf98741550b7db9dae61a4", "resources/theme/default/icons/mIconRuleGroup.svg": "99610d48d732d9f76ad9dd28fba1bb1d", "resources/theme/default/icons/mIconRuleRoot.svg": "013cdba55f00d20c4d9d1429a33d3981", "resources/theme/default/icons/mIconSave.svg": "5e0bcceceac29567885531806f0df5eb", "resources/theme/default/icons/mIconSaveAs.svg": "92eae31b2324f5a7b3fc959de7858a54", "resources/theme/default/icons/mIconSecondLevel.svg": "f830a82f170fdc417e8243e99f6463ef", "resources/theme/default/icons/mIconSelectAll.svg": "2c19a865fc8951dc6b0d76e03192fa57", "resources/theme/default/icons/mIconSelectNone.svg": "728e2fbb4f50cd340e739df3efa98505", "resources/theme/default/icons/mIconSelectServer.svg": "7a40c874356f04dfcf9dc16631b01e36", "resources/theme/default/icons/mIconServer.svg": "b037d88ce726e5e2e9022bcfccf1ab1d", "resources/theme/default/icons/mIconServerManager.svg": "db323ee83983521b1fe55d718137118b", "resources/theme/default/icons/mIconSetColor.svg": "04cd244f3efa35e3e49c3d15a41dfd8b", "resources/theme/default/icons/mIconShowStyle.svg": "82e6f287175dfa2492b04316a1001113", "resources/theme/default/icons/mIconShp.svg": "d4b18ad9e5808b63b022799c9b9ad7fe", "resources/theme/default/icons/mIconSixthLevel.svg": "e7553e75a3071065b15b6bcf2bdc8e96", "resources/theme/default/icons/mIconSnapping.svg": "63f355964cf029d5dcaf7181384b8762", "resources/theme/default/icons/mIconSqlite.svg": "aaa168559302aad794f38c3eba3bddd4", "resources/theme/default/icons/mIconSuccess.svg": "2d9a7e0389e29ef07f2f881f478acc57", "resources/theme/default/icons/mIconSystem.svg": "fa75b6702dfc9a38d955c4db45bce8de", "resources/theme/default/icons/mIconTable.svg": "21615bcc2dab3f7d81b36b7267d5c003", "resources/theme/default/icons/mIconTableLayer.svg": "f097c9a2709c4bb46a5c69edcaeb877d", "resources/theme/default/icons/mIconTableMLayer.svg": "3777b46cbf789491572e2ab6c3841384", "resources/theme/default/icons/mIconTense.svg": "a9506e8a7e783d03a27c777d50f639c5", "resources/theme/default/icons/mIconThirdLevel.svg": "1b82d2a307fc30d45b11ea616c7b5c10", "resources/theme/default/icons/mIconTile.svg": "b73d838ec69991e754f3cb8eb1f47366", "resources/theme/default/icons/mIconTileLayer.svg": "e65e45cc49d05e235d10096ad817fc82", "resources/theme/default/icons/mIconTimerContinue.svg": "cfd5c0fdbd6fdcd6a414dac9c092a633", "resources/theme/default/icons/mIconTimerPause.svg": "56f9fb6e1a8b29efb238c60c7abb2682", "resources/theme/default/icons/mIconTxt.svg": "2a5d39dfd28028ea033bbe28e5e5bfad", "resources/theme/default/icons/mIconType.svg": "652794ba38eacdf6364786d77e138b92", "resources/theme/default/icons/mIconValueRangDic.svg": "b5fbdf278321d22243dcc2a0dfa25e72", "resources/theme/default/icons/mIconValueRange.svg": "3656fff54e067f46659582350822c3bd", "resources/theme/default/icons/mIconValueRangeRange.svg": "2b8d8fcdb3054ca0b50d165d76a0e529", "resources/theme/default/icons/mIconVCT.svg": "9de1e1bdb8620f90226157e87ff08f35", "resources/theme/default/icons/mIconWarning.svg": "469d5f397cb89f1768473b9fc065cb1f", "resources/theme/default/icons/mIconWcs.svg": "d50746b54aaf55fe0f070cd61f42b589", "resources/theme/default/icons/mIconWfs.svg": "4bb63bff96c7076f1372a1a21fc746a3", "resources/theme/default/icons/mIconWms.svg": "ff83723069a766205aaeedbd335906dc", "resources/theme/default/icons/mIconWmts.svg": "ad3fe79ff517b26bf49f6ee5d6a31b17", "resources/theme/default/icons/mIconXYZTile.svg": "d0c0b73adfc969f20bf96165e9581276", "resources/theme/default/icons/mIconYearChangeDataInittail.svg": "53d895ee3af75bc504e52de69b648768", "resources/theme/default/icons/missing_value.svg": "864863c0054f6b72766d2f8a3e030f30", "resources/theme/default/icons/mLayerSaveAs.svg": "42e4a4ffc0342a7cc626cc2df0f4748e", "resources/theme/default/icons/model_selection.svg": "222c717feb5de2c675cfb7c85c41b9b4", "resources/theme/default/icons/modified.png": "430719999ef1aad4e546d47662f64a82", "resources/theme/default/icons/Mouse.svg": "87a75d7d8243dad6fd65d9815db3e7c0", "resources/theme/default/icons/mPolygonDifference.svg": "c7fcfd8353e8661aade6824f2f946878", "resources/theme/default/icons/mPolygonIntersection.svg": "8a8cef3083c30309df6946d6ccd660b7", "resources/theme/default/icons/mPubLayerRoot.svg": "5073514803a9dc01c5c70c3c18305ffc", "resources/theme/default/icons/mPubLayerSet.svg": "a64220d6ecb203571ef6f1d8b0bbe5c2", "resources/theme/default/icons/mPubLayerSimple.svg": "40a8f32e0ec29323c176effbab6a1199", "resources/theme/default/icons/mPyramidManage.svg": "f50928a886510ab2489f3875930c252a", "resources/theme/default/icons/mRefreshErrorStatus.svg": "07bf753129c84e7d476e939ee906c4cd", "resources/theme/default/icons/mReportExport.svg": "e4c0687252e51c27e8967b033352b09e", "resources/theme/default/icons/mReportSetting.svg": "9f12bcd4a448ceeed1ddfa07a289d712", "resources/theme/default/icons/mSourceFields.svg": "c29a122376138fa67964299e1cd554dc", "resources/theme/default/icons/mStartCheckProcess.svg": "1a43b916dc8effdee18fbc2126c77714", "resources/theme/default/icons/multieditChangedValues.svg": "fa2114de837cf105940390a270ca0fbb", "resources/theme/default/icons/multieditMixedValues.svg": "41e09b3a0af251bf17d9283b8f81a577", "resources/theme/default/icons/multieditSameValues.svg": "f280c0cd500fd7679b7bc4cc7abec436", "resources/theme/default/icons/mvectorlayercache.svg": "52656796a777dcd29c43e584de7e40ca", "resources/theme/default/icons/MySQL.svg": "b4b89c2f14fe912b9acc90c32f1b3dc8", "resources/theme/default/icons/nActionBasicStatistic.svg": "f58a64edfbcc2a499d017d021caa854f", "resources/theme/default/icons/net.svg": "01609ed2d769c8d7ad4c97460cac8f69", "resources/theme/default/icons/New post.svg": "0faf63c8a6a31411cfedca48447870cd", "resources/theme/default/icons/new.svg": "f39a9d36090c7cad6757b3621aea0dbf", "resources/theme/default/icons/newvectorfile.svg": "56abc8aa55c3e2143c78b52af8a364d9", "resources/theme/default/icons/new_project.svg": "3cd72c019015b461870f3ad6e871aca1", "resources/theme/default/icons/next.png": "ff36945b6427eb8226bec7fe2743af70", "resources/theme/default/icons/nextConflict.svg": "a086d4b6331680eeb568a4df98937305", "resources/theme/default/icons/non_versioned.png": "25ba46f98f7aee7477ffb7d7fc1a7d62", "resources/theme/default/icons/normal.png": "795d679579e414fd37489f552b604b94", "resources/theme/default/icons/numpy.svg": "f36ed6c85013eb6f6bb3e49a8a9ee713", "resources/theme/default/icons/open.svg": "200a281b71b9104332781e9eb2fcc6de", "resources/theme/default/icons/open_folder.svg": "4aac2ccabd5e0ee6afe3286e61b8c85a", "resources/theme/default/icons/oracle.svg": "62030f9604e445ac5ef6b9edc94da181", "resources/theme/default/icons/orderlayergroup.svg": "2dd8c13c7243f17d69087176d29ddbb3", "resources/theme/default/icons/overlay.png": "17f28aabcf682bbf6a22d0a80070b1ce", "resources/theme/default/icons/package.svg": "db8542fb863117d5d74f7a6676ab419e", "resources/theme/default/icons/pagesetup.svg": "b25656114dc0af77191a6d7b206c7e91", "resources/theme/default/icons/paste.svg": "02b0ecdb9e40d6e9a3a589be40ea0790", "resources/theme/default/icons/pasteElement.svg": "deede2c394febaf7818a5a74220adb58", "resources/theme/default/icons/pausefly.svg": "aec4d2aee5c1a96174b7d0efbb654d35", "resources/theme/default/icons/plugin-installed.svg": "715e5c20df916d7d0a959ef6a6efbc40", "resources/theme/default/icons/plugin.svg": "c5c2d3092b1c2958aae669b0ce891492", "resources/theme/default/icons/plugins.svg": "e04bad7db3b8435bff70fd5ebbebc369", "resources/theme/default/icons/postgresql.svg": "5c2c9989c1a23c934678119d55c088b8", "resources/theme/default/icons/previous.png": "af4d639c2ccefd5b57d4772e3cc3bb62", "resources/theme/default/icons/previousConflict.svg": "099b009a440d54790c0cda1d60842134", "resources/theme/default/icons/print.svg": "3ba6cb43288c30503450361636fae5aa", "resources/theme/default/icons/processingAlgorithm.svg": "5acd3a3ea3ac4302ebed7d35fc1f16ae", "resources/theme/default/icons/project.svg": "72a57d9485a1a0a78e977a2f472e2213", "resources/theme/default/icons/projectDataTree.svg": "23c638ad38fe4f0dc6a4661730f24081", "resources/theme/default/icons/providerQGeomap.svg": "2c9169fc1c7e50f15b84f71bafd17a6d", "resources/theme/default/icons/pypi.svg": "6b9ea3945cf090b33076ea91ce2e9612", "resources/theme/default/icons/pypi_color.svg": "aefe42c944201ae3a898d71d5ec62075", "resources/theme/default/icons/pyramids.png": "051b61faa344c78af9a059e9cfc78dae", "resources/theme/default/icons/python.svg": "cdf88def02be5b2ce0e4c40b89d2c6ce", "resources/theme/default/icons/python_gray.svg": "b0b260fbbaa0b24915e46e80a5d7af9d", "resources/theme/default/icons/qgeodataspecificationmanagertool.ico": "c86f314e1777d0e7541709d50f9d726c", "resources/theme/default/icons/R.svg": "c27cc0791576e0ca3616b76731907b9e", "resources/theme/default/icons/reduce.svg": "1e88d456b31261ed99c18414a5c47671", "resources/theme/default/icons/regression.svg": "ea2efc714a40dfba39ecbd5218268fa6", "resources/theme/default/icons/remove.svg": "a6328dbd354bd5965aae818d26b273da", "resources/theme/default/icons/removeElement.svg": "7f477ed033b711e6e3b96f9bf22c79e1", "resources/theme/default/icons/rendering.svg": "55bdf00e277bc65c5639e48f8d9f42d2", "resources/theme/default/icons/replace.svg": "fbba9c3ecb7acb6dc76d5fc36cb03302", "resources/theme/default/icons/resolved.svg": "4a3f747ccc1459e54666994682080e38", "resources/theme/default/icons/ribbonMaximize.png": "e5dc4278826e32c25a4723fc87b943b2", "resources/theme/default/icons/ribbonMinimize.png": "42094d61d30e8a72a1a2cbff7a0df598", "resources/theme/default/icons/right.svg": "5dca8df9c3b66d4d1449494b34f936fe", "resources/theme/default/icons/roaming.svg": "4db76c4b080e95322cde6b52d36cfcfb", "resources/theme/default/icons/rubberBandConfig.svg": "9dd7c66dd566eaabd42ab2edd443654c", "resources/theme/default/icons/run.svg": "ec156027329d2c13877625ff3fcbee01", "resources/theme/default/icons/sample.svg": "59c88431eeb5015338430a9b7d1be8c5", "resources/theme/default/icons/sas.ico": "c4c83c2060701e0389262d9d07362896", "resources/theme/default/icons/save.svg": "89eafd6a566e859840d717e73872df13", "resources/theme/default/icons/save_layout.svg": "de4fd322d23ce467c2d30c2f2cb4fec0", "resources/theme/default/icons/scale.svg": "6b074bd9946d667c2f3e6502e634ecd2", "resources/theme/default/icons/scaleAdd.svg": "1724ab174f6709f9485d555a2d372639", "resources/theme/default/icons/scalebartext.svg": "1c6d5b3e2d85f1cbfb7305ebc7c2ee94", "resources/theme/default/icons/scaleClear.svg": "c62dd67d91bfb849c20eb5a1bd37e215", "resources/theme/default/icons/scaleRemove.svg": "0fb15d6df30ef9a5248804f9d082ad04", "resources/theme/default/icons/scaleReset.svg": "c69773f8695e60c85c82f65bfb44a29e", "resources/theme/default/icons/scorecard.svg": "9919e029f7566ce49fbe7338493e0473", "resources/theme/default/icons/script.svg": "cb1493bb56cd8d924de2516d7dbb5187", "resources/theme/default/icons/search.svg": "b116a8aa818d1cd7ec41752a0c29816b", "resources/theme/default/icons/section.svg": "aea2b044eb14c55452bc8172df030f92", "resources/theme/default/icons/selectedrecords.svg": "171b3d8de98149a3675b853745105c22", "resources/theme/default/icons/setExtent.svg": "7080d56468833b423897465aeca93138", "resources/theme/default/icons/setting.svg": "41cf928d70d4e8ed012cc2d15d224ed2", "resources/theme/default/icons/shengcunfenxi.svg": "5ae32cbb038032ed1443b8005baff03c", "resources/theme/default/icons/shortcutsConfig.svg": "4cb9c5a2687e14ba17d7ad9f4dcbfea9", "resources/theme/default/icons/simplearrow.svg": "157c76b4552215d148febb98baf92b1d", "resources/theme/default/icons/situationpoint.svg": "af69811bf86271d54800957689c28aec", "resources/theme/default/icons/skip_line.svg": "eedc935dd2773c44ff7e54a50811030a", "resources/theme/default/icons/slider_close.svg": "3402865a23ff073e953448e3d2480c24", "resources/theme/default/icons/slider_lasttime.svg": "da6ead6853a3db08a482f28ceaf933e3", "resources/theme/default/icons/slider_lastversion.svg": "3d10f7b5692a9ea4b8929e5a65528bfb", "resources/theme/default/icons/slider_nexttime.svg": "b54ce11ec64888d09640861fcc2ed0a5", "resources/theme/default/icons/slider_nextversion.svg": "54213dc4e51bccdd8348bcbdc0102d7b", "resources/theme/default/icons/slider_zoomin.svg": "abeda64aa9f3fa4e6d3bb2eefe65a89e", "resources/theme/default/icons/slider_zoomout.svg": "b9a24b973053cf1d836872b788180f00", "resources/theme/default/icons/sloperuler.svg": "16d462cb766b85c0ec907ce5c529bb02", "resources/theme/default/icons/spss.svg": "4d8cb6044137301a4101755e43b83fc1", "resources/theme/default/icons/sql.svg": "a0997f68ee9c263ffecd0efbaa524236", "resources/theme/default/icons/stata.svg": "a62e991cde9e8389dea6bf46b0bccb43", "resources/theme/default/icons/sun.svg": "e98cbd692ec62d35d27c78c31d91f86f", "resources/theme/default/icons/symbology.svg": "062e0ba664ee2320d21cda33ddaf3525", "resources/theme/default/icons/symbolreorder.svg": "062e0ba664ee2320d21cda33ddaf3525", "resources/theme/default/icons/system.svg": "c76354112390bc2f9151b4baf729ccfc", "resources/theme/default/icons/table.svg": "21615bcc2dab3f7d81b36b7267d5c003", "resources/theme/default/icons/tablegroup.svg": "b9a57bb1b7a98b1ea2220552ae77f576", "resources/theme/default/icons/task.svg": "1223b13e13ffccea138013fd33b71775", "resources/theme/default/icons/teamEditProject.svg": "35828465cb83319c8579c9cb9a904481", "resources/theme/default/icons/terrain.svg": "5e2ccfec44e7d6a40320912b4137615e", "resources/theme/default/icons/threenorth.svg": "96eada7b3eeebdca632533988e617717", "resources/theme/default/icons/time_series.svg": "94fd406769655b721b17f4cb17bc673f", "resources/theme/default/icons/top.svg": "22d2fefe180a699944a6a5ab545ab5a9", "resources/theme/default/icons/topologyConfig.svg": "2af77dff1d80bcccdefd9079ed4d68b6", "resources/theme/default/icons/transformed.svg": "5b98c431c64bf1f5697a2c63cab6ca11", "resources/theme/default/icons/transparency.png": "17c24a4daf81d8d7f8b9c7642e2fa7e7", "resources/theme/default/icons/transposition.svg": "07d926b580577fcc30c3a709cbde68bc", "resources/theme/default/icons/tree.svg": "14ae56a092c0268672520520ffc4443a", "resources/theme/default/icons/txt.svg": "867501b0b384f46cf6d4f225605995c1", "resources/theme/default/icons/undo.svg": "5484c93bf4a89654d20a2ba6bb66d912", "resources/theme/default/icons/uploaddata.svg": "e2a9a1ccdb820364d99b96d1a3ab39b6", "resources/theme/default/icons/upWard.svg": "b1c72b33367343316cc888d977ebb43d", "resources/theme/default/icons/useLeftAll.svg": "fddc9b7c0d601a881ab55af95659d3cd", "resources/theme/default/icons/useLeftSelected.svg": "1764c036105882a4743fc4e34e384404", "resources/theme/default/icons/useRightAll.svg": "c7020f993a82c847054dadf2b5709a5a", "resources/theme/default/icons/useRightSelected.svg": "18d35ec89cbb795bb88449c8859b3d81", "resources/theme/default/icons/var.svg": "c3d9e7461e40e74c17f3ce5873905f51", "resources/theme/default/icons/var_open.svg": "b023934e733448d74563926e0d5f9a1f", "resources/theme/default/icons/vectorTileStyle.svg": "670fc3779ea1e4b103aa75efd3832baf", "resources/theme/default/icons/view_var.svg": "a495e2e336064e1549622b87c69dd649", "resources/theme/default/icons/visibleMap.svg": "7ec32396ae7a2da699cf55929aed4f98", "resources/theme/default/icons/walking.svg": "790a25d6b2f642d0e2c04e5f5e5efd01", "resources/theme/default/icons/website.svg": "c789f48d1f500ad317ef3cde4818b240", "resources/theme/default/icons/windowicon.ico": "dd4b17c0ec69f51b039c51b6e0887c31", "resources/theme/default/images/addNode.svg": "d11d5a3ce54b3a864281b2f5f3311e36", "resources/theme/default/images/attributeBrush.svg": "ddeee5f9e2e1e63792eff8cbbb840164", "resources/theme/default/images/background.png": "ddf7168c491dac078b9b0c7c6771d602", "resources/theme/default/images/breakByOnePoint.svg": "ed5c5d11f74011fcb4c8a027eeb31599", "resources/theme/default/images/breakByTwoPoints.svg": "ce13a12a1afde966f284661dfdb1471f", "resources/theme/default/images/copyFeature.svg": "0293921cdf1de395e600349621565051", "resources/theme/default/images/cursor_leftbottom.svg": "3e9b60706a3f0bf7d729c48bd440cdc7", "resources/theme/default/images/cursor_leftright.svg": "418f31c70c594b53922604cdddb036e5", "resources/theme/default/images/cursor_lefttop.svg": "c364223abf37f51dd7def7162d9be9af", "resources/theme/default/images/cursor_move.svg": "8a82e82a355f18c8f410bd9bbf0c5f8e", "resources/theme/default/images/cursor_topbottom.svg": "ec0ad72e180c458e3155a88a2db6c023", "resources/theme/default/images/deleteNode.svg": "2aae237e59216f92c6b87dd7757c1a95", "resources/theme/default/images/editDraw.svg": "23e810e15d33b68a03427f8a40a408a1", "resources/theme/default/images/editSelect.svg": "8859783cdb6f54f380faadc8ad60c3c0", "resources/theme/default/images/error.png": "450eb59729737d72ceb03818c43ffcc9", "resources/theme/default/images/extensionPolyline.svg": "91c86deac1a658ed6b928487fb076723", "resources/theme/default/images/identify.svg": "ac8cb0d555021521270e9e6cc0d8ce59", "resources/theme/default/images/information.png": "423578ade54524e34a95580788d7729d", "resources/theme/default/images/mCapturePoint.svg": "5caf3405335284af6d880495b01d5776", "resources/theme/default/images/measure.svg": "23e810e15d33b68a03427f8a40a408a1", "resources/theme/default/images/mIconDeselected.svg": "75733116db9e219b0f4382385342b511", "resources/theme/default/images/mIconSelected.svg": "cc341d78f94f446e0e6ca672482edd15", "resources/theme/default/images/move.svg": "8a82e82a355f18c8f410bd9bbf0c5f8e", "resources/theme/default/images/moveFeature.svg": "8a82e82a355f18c8f410bd9bbf0c5f8e", "resources/theme/default/images/moveNode.svg": "84a9570e8f6d04cd64c450c1523aad4f", "resources/theme/default/images/mPageLayoutPan.svg": "67a143805264211f1031ebb79eb356a4", "resources/theme/default/images/mPageLayoutZoomIn.svg": "0d4e308d01775da24950c7c7869cadc2", "resources/theme/default/images/mPageLayoutZoomOut.svg": "ffa286230cff03f5bf4003a7f2e77a94", "resources/theme/default/images/mPanClose.svg": "a0603e76de7727c6a3a524adec772f49", "resources/theme/default/images/overlayUpdates.png": "75a5188a1a36b3e55a0c26bf0692ec3c", "resources/theme/default/images/pan.svg": "8fa8827e723ea97094655ce0ab60bcbb", "resources/theme/default/images/pyramidfirst.png": "6336d1c87d3a53c59f42ab682a7ef68d", "resources/theme/default/images/pyramidfourth.png": "3ca3b9cdbb6b88a50f6a270c24504df2", "resources/theme/default/images/pyramidsecond.png": "d8eb0fae632533ce16178629a61e77d6", "resources/theme/default/images/pyramidthird.png": "2dba3fd37994c231b6fe468f5922144a", "resources/theme/default/images/rotateFeature.svg": "d47a6e3f34dd3d3484440c7e4a96b58c", "resources/theme/default/images/select.svg": "128d8d763c91a71599ad86fcc069ad63", "resources/theme/default/images/selectbypolygon.svg": "5efdd8dc872ba52a262b939cfcd70515", "resources/theme/default/images/selectbyradius.svg": "c2d9e4efd0649941dfee9a843284ccca", "resources/theme/default/images/splitBySelect.svg": "021d0ae70cb8157d9d6f18feef0db270", "resources/theme/default/images/SwipeDown.svg": "21f3775a767d4cfb81d748276baf522a", "resources/theme/default/images/SwipeLeft.svg": "457aac45411c29aa4d6f1b63e6d999ba", "resources/theme/default/images/SwipeLeftRight.svg": "21193a1f1446c5c392d7a3807427e25a", "resources/theme/default/images/SwipeRight.svg": "cc700b8a09d58417f17496738db67404", "resources/theme/default/images/SwipeUp.svg": "b440961cee34d1649815aa594a896318", "resources/theme/default/images/SwipeUpDown.svg": "e21665a6f5d712ab4b25022ddb738ca5", "resources/theme/default/images/systemabout.png": "067610e0d804b16c75496b4ed77005dd", "resources/theme/default/images/thematicAttributes.svg": "ac8cb0d555021521270e9e6cc0d8ce59", "resources/theme/default/images/warning.png": "9323d69c25b6f79fc974023fee921af0", "resources/theme/default/images/zoomin.svg": "6bf9cf3ff08b719f4f872977e7ee201f", "resources/theme/default/images/zoomout.svg": "debcf4106754577838008ca423288371", "static/README.md": "2b883d8ed7e177b421e29625caf11a10", "static/tutorials_page.html": "7e6350719caf6a92de7a495441cd65ed", "static/css/iview.min.css": "b56ab90b84c3ac9f460f50906cbf5ae8", "static/js/echarts.min.js": "40874546a400f6e1b358c0495998a43f", "static/js/form-create.min.js": "5b2e899b103ec5bade920ac909268db4", "static/js/iview.min.js": "cb94a058fc714808d440d2b9835fed0d", "static/js/jquery-3.5.1.min.js": "dc5e7f18c8d36ac1d3d4753a87c98d0a", "static/js/vue.min.js": "b0473a59bd7e655c4da3d26f50dbba1e", "static/js/element-ui/CHANGELOG.en-US.md": "f90a50248e8a935d4bf94939b2b83bc1", "static/js/element-ui/CHANGELOG.es.md": "cd352a41d428cfe359e2dd25b3e69216", "static/js/element-ui/CHANGELOG.fr-FR.md": "2a5cb94c1cc391f95705a822c50906d2", "static/js/element-ui/CHANGELOG.zh-CN.md": "fae21798d847ea9bd4827f78766d634e", "static/js/element-ui/package.json": "ed15655a88db7bf4e42f2879000f0241", "static/js/element-ui/README.md": "29e235e7c8cba854610d2faa0424c5a0", "static/js/element-ui/lib/alert.js": "44bd2ce7e47fc65112066ebe354ceaca", "static/js/element-ui/lib/aside.js": "6af3243f56f6c0bda3eba64e2cd8078a", "static/js/element-ui/lib/autocomplete.js": "8cfc24a3a0f63f57b0bbefd1d43150b1", "static/js/element-ui/lib/avatar.js": "0c3f24bdffc3f4c3016149e5b589bf58", "static/js/element-ui/lib/backtop.js": "4ba1079d79f186a4b73395ab8048ce30", "static/js/element-ui/lib/badge.js": "d124ddea127b3b87fb7fc0e3d28f976e", "static/js/element-ui/lib/breadcrumb-item.js": "3ee84610ae6e927194916dc1850be078", "static/js/element-ui/lib/breadcrumb.js": "3b696a8b4d753bce1c9a42f1f2f2e559", "static/js/element-ui/lib/button-group.js": "c13e97a9b747982a6fe3475ce0963202", "static/js/element-ui/lib/button.js": "db479a095696d3b41e4e8e5ca573b2d9", "static/js/element-ui/lib/calendar.js": "78b60123511490a4957bb7ecc90ca562", "static/js/element-ui/lib/card.js": "a63bc5d2a60ecffc3fe581d2b9a86b19", "static/js/element-ui/lib/carousel-item.js": "24398b44ec0a885f9f7dcf7b4511b140", "static/js/element-ui/lib/carousel.js": "dc86769400de82ac847dfe71d278331a", "static/js/element-ui/lib/cascader-panel.js": "400c0c6ad5bb41a6d0aa489f027a849c", "static/js/element-ui/lib/cascader.js": "a97cc547f182cb959ff0af6d31f0769c", "static/js/element-ui/lib/checkbox-button.js": "e867a0fcfa56c197d8cbbcd8000ae723", "static/js/element-ui/lib/checkbox-group.js": "81593c2eeeee70e69fff71af4dfe212c", "static/js/element-ui/lib/checkbox.js": "09780b33e4add1d32b2b870c8ccc5a4b", "static/js/element-ui/lib/col.js": "227c1189111f2dfbada9a8f26e1433ed", "static/js/element-ui/lib/collapse-item.js": "0ef8b7bea75fa2d185730fa809d86148", "static/js/element-ui/lib/collapse.js": "8cc69b5cbaefb354e3fa19e748a54118", "static/js/element-ui/lib/color-picker.js": "25752f575ad81607f8b3b4652e1e1790", "static/js/element-ui/lib/container.js": "f2118022ef7e900503a8028e72a47bf2", "static/js/element-ui/lib/date-picker.js": "160c4f0f12cc50d77eeff03eb3e2abce", "static/js/element-ui/lib/dialog.js": "3446278e381ae6162bfc309cd883b84a", "static/js/element-ui/lib/divider.js": "ce49dbf8658355e06eb9ca852acd98e0", "static/js/element-ui/lib/drawer.js": "2a4f53c5e574a8fbe04eb528ccdb4e6b", "static/js/element-ui/lib/dropdown-item.js": "1c440ab125200ed27bb4402f26ae6edf", "static/js/element-ui/lib/dropdown-menu.js": "51e13aaf4f6dea2a6ec4eb6a06f49c1a", "static/js/element-ui/lib/dropdown.js": "02786a92e4ed20d950ad7d09e6dd03e7", "static/js/element-ui/lib/element-ui.common.js": "b6b435a52f5cdc204fb8a023bc856a16", "static/js/element-ui/lib/footer.js": "4d392ecf90fa43ebf25caa31e1783354", "static/js/element-ui/lib/form-item.js": "98d4dd1fa2c81e68ff40dc3344620df9", "static/js/element-ui/lib/form.js": "88eeb8b813539099fec26e9993789af8", "static/js/element-ui/lib/header.js": "9c9ab6bc2af99e67eee8367ab3ed855b", "static/js/element-ui/lib/icon.js": "658fcece90b39788b763c25f17d60207", "static/js/element-ui/lib/image.js": "650a56522f7a590b8fca25fdfb09690a", "static/js/element-ui/lib/index.js": "28fb829b428bc14fe9d26f852dbc11a9", "static/js/element-ui/lib/infinite-scroll.js": "3c09c5248512b2f0281e8e8bf4ecee8c", "static/js/element-ui/lib/input-number.js": "3dd23cc075c49822fe68366cef6f09a3", "static/js/element-ui/lib/input.js": "bb52be1067cfd9b1dd8ded0b664f5605", "static/js/element-ui/lib/link.js": "312480ee5f2292f314346434faa3518f", "static/js/element-ui/lib/loading.js": "9bb5753b57ee274668c5748d38eac2ab", "static/js/element-ui/lib/main.js": "92a26937eaac62367d2b81ebec36d9f0", "static/js/element-ui/lib/menu-item-group.js": "2098666a7bbd0c271cc084c3924d4ec3", "static/js/element-ui/lib/menu-item.js": "bf8db518c9b73c9cd3771dabf91bcaca", "static/js/element-ui/lib/menu.js": "0188cd906e1159936cbee28980fbec39", "static/js/element-ui/lib/message-box.js": "e275b026ca058dff799673d5740b6e22", "static/js/element-ui/lib/message.js": "0f64248045730556999011fa779d1dfa", "static/js/element-ui/lib/notification.js": "6190c53c839faa5b01a815de6769c899", "static/js/element-ui/lib/option-group.js": "f2759330e59d0518f60a6c5547d3c827", "static/js/element-ui/lib/option.js": "1c418a74feafdc73cfa5360764f1b90a", "static/js/element-ui/lib/page-header.js": "6a9f088700adf20d389cc542e6a0deaf", "static/js/element-ui/lib/pagination.js": "17b696cc294ca8bbc37af7b1c5968f7a", "static/js/element-ui/lib/popconfirm.js": "6bcceddbd44e456d716b66a018beaf7c", "static/js/element-ui/lib/popover.js": "a5cf39911205f08d5e5691a158bd81c6", "static/js/element-ui/lib/progress.js": "6f206f6d72b0622ea6a6c2fccd062bb5", "static/js/element-ui/lib/radio-button.js": "efdf34b9f8c565b99aeae587e11eb87a", "static/js/element-ui/lib/radio-group.js": "93003dbff84a768dbb1a12e7d6e7796a", "static/js/element-ui/lib/radio.js": "66201ad4319bcf5330d5711537cb85c6", "static/js/element-ui/lib/rate.js": "d57f0eede17b4ff2c80fbc3a5899d030", "static/js/element-ui/lib/row.js": "4d92917609e4db63a0acc64bca5d9ab4", "static/js/element-ui/lib/scrollbar.js": "76120f65f535b535d19fc1e820e959d5", "static/js/element-ui/lib/select.js": "5e900a932de2f3be38ef8f436fa201e4", "static/js/element-ui/lib/slider.js": "faf0a48d331a5c869c7bf7c8a07abe58", "static/js/element-ui/lib/spinner.js": "83f0cb9cc66bba831681c58c230890fd", "static/js/element-ui/lib/step.js": "cd744e288e5eeb55dde52cbe0909016d", "static/js/element-ui/lib/steps.js": "7cb3835a98f56194a2ca85cbeb197bf2", "static/js/element-ui/lib/submenu.js": "07584a153decdad6f82fe2de4e565f15", "static/js/element-ui/lib/switch.js": "aa60bca689f5db14f3bad0fcd8cb3ece", "static/js/element-ui/lib/tab-pane.js": "9cba2ce5089e06c7a6f9560687e0e150", "static/js/element-ui/lib/table-column.js": "bcf79a6f1de840db943cdee7c4e41921", "static/js/element-ui/lib/table.js": "f017fc250b36fbfebeef1b462b6984f8", "static/js/element-ui/lib/tabs.js": "f19f934d0ee0cb9b4234c9d81301f0b7", "static/js/element-ui/lib/tag.js": "66492bd336c57f37bbd9da3cac97b51c", "static/js/element-ui/lib/time-picker.js": "d2561b513c3dfdbb57f34f3f6855bd5b", "static/js/element-ui/lib/time-select.js": "c562bd018cb94d0a5f993a23bdb2e687", "static/js/element-ui/lib/timeline-item.js": "84ce5c070a064909355b56610bd8ff2f", "static/js/element-ui/lib/timeline.js": "e66393cdd8e7a22413acad9ab1f6f8af", "static/js/element-ui/lib/tooltip.js": "7f6a6999519c70a0485d2ae7d03ea6ab", "static/js/element-ui/lib/transfer.js": "b5825b45e447c403e3b0833e7975fa96", "static/js/element-ui/lib/tree.js": "16346c71a54ffbaddc37b635296704ed", "static/js/element-ui/lib/upload.js": "1682818d886774e15dd8267e40d81ecb", "static/js/element-ui/lib/directives/mousewheel.js": "d57acb00ba5ec4322dd7b4e37dedbb69", "static/js/element-ui/lib/directives/repeat-click.js": "ee7cb0bb5822588e21af009528f04490", "static/js/element-ui/lib/locale/format.js": "471399a5f5d8d53d46cb7e2fcad68d0d", "static/js/element-ui/lib/locale/index.js": "7f48cd4280e7b5be536b37a33af7a441", "static/js/element-ui/lib/locale/lang/af-ZA.js": "1cab2e3d954eaf982bff6464654f162a", "static/js/element-ui/lib/locale/lang/ar.js": "a973ecdc856fa1ea02fc3a1f1d436ddb", "static/js/element-ui/lib/locale/lang/bg.js": "100d5a70d89307668e0a512d953bbbd3", "static/js/element-ui/lib/locale/lang/ca.js": "f85b7ef8722b22ab636c540dc90c9aae", "static/js/element-ui/lib/locale/lang/cs-CZ.js": "5b0aeb0ab3f5177a7d2ae975db11ff20", "static/js/element-ui/lib/locale/lang/da.js": "7b04b9b382da5785b105084c0b1895fc", "static/js/element-ui/lib/locale/lang/de.js": "165678f7ff2d5c05c1b196c1fe36919f", "static/js/element-ui/lib/locale/lang/ee.js": "77cab864f3b5c0d02700606da528e0c9", "static/js/element-ui/lib/locale/lang/el.js": "1ab144c6f49d289c320e8672fdd78d05", "static/js/element-ui/lib/locale/lang/en.js": "fbea06cf549fdf1bc8107e258676825d", "static/js/element-ui/lib/locale/lang/eo.js": "91b4bd398fd27e80d331675e0567eae8", "static/js/element-ui/lib/locale/lang/es.js": "e1845d63e50ee4f117aa16c8b7756cc7", "static/js/element-ui/lib/locale/lang/eu.js": "6851cf67a17a2988f1e905557ebba981", "static/js/element-ui/lib/locale/lang/fa.js": "67763039da687c77702e59237ce66e04", "static/js/element-ui/lib/locale/lang/fi.js": "0b35a1d0fb672b74e243a5f41defdd70", "static/js/element-ui/lib/locale/lang/fr.js": "64c0cbb50596da4841223e8c85c34c1b", "static/js/element-ui/lib/locale/lang/he.js": "2a3719ffb84a33ed3dd1e9799c03a3dd", "static/js/element-ui/lib/locale/lang/hr.js": "81661a420afc076d1792c21f0432a50e", "static/js/element-ui/lib/locale/lang/hu.js": "0fa9fc603c3f5ad1bbbab426db5fa3cf", "static/js/element-ui/lib/locale/lang/hy-AM.js": "a6d88e26e14fd663a5aebe98623b1e5d", "static/js/element-ui/lib/locale/lang/id.js": "ace3933e6fba75bf17787c34580d1430", "static/js/element-ui/lib/locale/lang/it.js": "ddbaa0c9de79f04c13510abf9e9fe347", "static/js/element-ui/lib/locale/lang/ja.js": "927e2dbb268276b854f4ab58486c029d", "static/js/element-ui/lib/locale/lang/kg.js": "321e5d0e5cd78eb71baeea679f9866ad", "static/js/element-ui/lib/locale/lang/km.js": "712afcf5ce5bd04235c9da5cabd3211c", "static/js/element-ui/lib/locale/lang/ko.js": "a1462b4c5f54be3312a11745525baf79", "static/js/element-ui/lib/locale/lang/ku.js": "0843793ace9f2be0d749f90ae499fd25", "static/js/element-ui/lib/locale/lang/kz.js": "7da2b07e5b87618e3a7176ddfe04887a", "static/js/element-ui/lib/locale/lang/lt.js": "9525aa7bd194094651d15525bd32d060", "static/js/element-ui/lib/locale/lang/lv.js": "6a911e229e2501001d303a8fdf425d32", "static/js/element-ui/lib/locale/lang/mn.js": "2b91da6fd41d16584339b227082dd47f", "static/js/element-ui/lib/locale/lang/nb-NO.js": "91463e2c92f200c50e1dccd73e03695f", "static/js/element-ui/lib/locale/lang/nl.js": "feab63aa44ae350f99f1d484a91d942c", "static/js/element-ui/lib/locale/lang/pl.js": "a27556391421cdbf5d2424d38955b645", "static/js/element-ui/lib/locale/lang/pt-br.js": "1a7d47d3cca171739de21a0cc99387f1", "static/js/element-ui/lib/locale/lang/pt.js": "87ef9e7ed1f27c582e7faabc406cf483", "static/js/element-ui/lib/locale/lang/ro.js": "b608c43b34a6975d98e4b7b2b7295402", "static/js/element-ui/lib/locale/lang/ru-RU.js": "0504c7d75043cb31bcb692a689743cef", "static/js/element-ui/lib/locale/lang/sk.js": "3dd18f7fd8a017f994feba8b6d9a0890", "static/js/element-ui/lib/locale/lang/sl.js": "9ce57a4806c0740551d7dc51e786c86e", "static/js/element-ui/lib/locale/lang/sr.js": "d2ff6141f3ecd471a8cf846a24d7a8ed", "static/js/element-ui/lib/locale/lang/sv-SE.js": "3ca29384088f1f47398278654fa3011c", "static/js/element-ui/lib/locale/lang/ta.js": "b4de5e6d6863d34dfa6e98ccf495d504", "static/js/element-ui/lib/locale/lang/th.js": "cf6e83d1c133279705c8296ef90e775b", "static/js/element-ui/lib/locale/lang/tk.js": "7c799830a4ba20120bc2e7bccf3419d8", "static/js/element-ui/lib/locale/lang/tr-TR.js": "061e2668858c3654f3bf6750276546be", "static/js/element-ui/lib/locale/lang/ua.js": "399ff5fe5470ec3e4a57f88d1ae6fe6b", "static/js/element-ui/lib/locale/lang/ug-CN.js": "fa8d94b219647056165f1baaa843b5e6", "static/js/element-ui/lib/locale/lang/uz-UZ.js": "3607e6bf57b1d37e917736c460d7dd63", "static/js/element-ui/lib/locale/lang/vi.js": "3c54c8dec1d0c8afccd03efb53a0b53c", "static/js/element-ui/lib/locale/lang/zh-CN.js": "0b60542152156fa18a045d408bed61ea", "static/js/element-ui/lib/locale/lang/zh-TW.js": "d886891267165c838c345606c972856e", "static/js/element-ui/lib/mixins/emitter.js": "f38340cf5d69582efda171286efafa65", "static/js/element-ui/lib/mixins/focus.js": "b113513900bcf212968edd814c163760", "static/js/element-ui/lib/mixins/locale.js": "9b538e9a7f8d56c2c1f85984a9d4b2d2", "static/js/element-ui/lib/mixins/migrating.js": "7774a8a036683cd8b2b3340e0a63b132", "static/js/element-ui/lib/theme-chalk/alert.css": "4a233d163ac6641263075f6e7c4821db", "static/js/element-ui/lib/theme-chalk/aside.css": "edcc490fb0053f1cce4a71a5c047bdf9", "static/js/element-ui/lib/theme-chalk/autocomplete.css": "47ce2bcdfb1b1b08f5c623f9387391ff", "static/js/element-ui/lib/theme-chalk/avatar.css": "58a5fedd9b307c75a19c3b0533d813b8", "static/js/element-ui/lib/theme-chalk/backtop.css": "8b2ca61408dad479b881960763d3db98", "static/js/element-ui/lib/theme-chalk/badge.css": "ea8bfd89345e13ad428bdfb5574237b4", "static/js/element-ui/lib/theme-chalk/base.css": "f25cc484087487b1e1ef6ce8bf62ca44", "static/js/element-ui/lib/theme-chalk/breadcrumb-item.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/breadcrumb.css": "16d9a27c1cd682756f3173c95a83d0ed", "static/js/element-ui/lib/theme-chalk/button-group.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/button.css": "41b0f4e08fdd9eedc5a38b9713ddd904", "static/js/element-ui/lib/theme-chalk/calendar.css": "982528766ad2393b8617dbbf05dfaa7f", "static/js/element-ui/lib/theme-chalk/card.css": "48a5b07b8b0a6fb0c5eb6eafacdd0cd5", "static/js/element-ui/lib/theme-chalk/carousel-item.css": "6c97d1a467ad4b215ee69ed21754a728", "static/js/element-ui/lib/theme-chalk/carousel.css": "53761931f0070d80e77e2073f18b1d23", "static/js/element-ui/lib/theme-chalk/cascader-panel.css": "d897ade7fa060cfb4a7fc14503e61a44", "static/js/element-ui/lib/theme-chalk/cascader.css": "bdded6ec78f1471b771f1c4e4e07b596", "static/js/element-ui/lib/theme-chalk/checkbox-button.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/checkbox-group.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/checkbox.css": "515b3e4a1c684ea0538292380b38ca5f", "static/js/element-ui/lib/theme-chalk/col.css": "cd14b27ef81a2fc60079ecf869bca3cd", "static/js/element-ui/lib/theme-chalk/collapse-item.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/collapse.css": "9b8b3424302f453728fe80719c97de40", "static/js/element-ui/lib/theme-chalk/color-picker.css": "083fba820bd7440f18cf93af1d6a31dd", "static/js/element-ui/lib/theme-chalk/container.css": "e79009df433ab4403029e519ddc3340d", "static/js/element-ui/lib/theme-chalk/date-picker.css": "bd299472f79e6132d0dc6845176cadbe", "static/js/element-ui/lib/theme-chalk/dialog.css": "d30bf0818a97168906dc243c0e04a1bf", "static/js/element-ui/lib/theme-chalk/display.css": "c110a2385504d5ee6adb4377365270d7", "static/js/element-ui/lib/theme-chalk/divider.css": "6e52365004d46117ecfb085bc38479b0", "static/js/element-ui/lib/theme-chalk/drawer.css": "6ba86d8fe04df4d3549e4b3fc950bcb4", "static/js/element-ui/lib/theme-chalk/dropdown-item.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/dropdown-menu.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/dropdown.css": "246cd4c0d0f8d4493c5e987d0e330925", "static/js/element-ui/lib/theme-chalk/footer.css": "0a75eee620a1eec96cf1718047bde916", "static/js/element-ui/lib/theme-chalk/form-item.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/form.css": "8521897ad3a147046fd049b37f6775c8", "static/js/element-ui/lib/theme-chalk/header.css": "4bf1a1be0a4af7778c092b276458787a", "static/js/element-ui/lib/theme-chalk/icon.css": "83dc46b9fc11c99b5c0511d0a9a9987e", "static/js/element-ui/lib/theme-chalk/image.css": "32f4b078377ca3c364767e55bba62ede", "static/js/element-ui/lib/theme-chalk/index.css": "2414fd307c22e07b681e50e0720cbc23", "static/js/element-ui/lib/theme-chalk/infinite-scroll.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/infiniteScroll.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/input-number.css": "a30d3d47860db05882de8597cbb35a3f", "static/js/element-ui/lib/theme-chalk/input.css": "88d9749aad3cfd64720e1090474a8573", "static/js/element-ui/lib/theme-chalk/link.css": "b29ddaa7be960e0dabeee5b23fed982c", "static/js/element-ui/lib/theme-chalk/loading.css": "ee99b8ad8874ed9e7df64b7dab4159a6", "static/js/element-ui/lib/theme-chalk/main.css": "9923eb608c01cf001501708e1c8df0bc", "static/js/element-ui/lib/theme-chalk/menu-item-group.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/menu-item.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/menu.css": "30fa354841214de1919e49d8e831a5bf", "static/js/element-ui/lib/theme-chalk/message-box.css": "6fe773d1292f0acbc9ddad9153548c58", "static/js/element-ui/lib/theme-chalk/message.css": "6ab057c82772aa70e8ecc9902d4284ec", "static/js/element-ui/lib/theme-chalk/notification.css": "875a37cf12d647c1dee9e7e467ea01fb", "static/js/element-ui/lib/theme-chalk/option-group.css": "b3a13247682f590bb17b55517326ec39", "static/js/element-ui/lib/theme-chalk/option.css": "1698a68c50ff2618face813daa89982e", "static/js/element-ui/lib/theme-chalk/page-header.css": "3508c570c80476d68b49a13d4c14e27c", "static/js/element-ui/lib/theme-chalk/pagination.css": "93a1866f64772a9d877796cc27f59e2b", "static/js/element-ui/lib/theme-chalk/popconfirm.css": "24183a243d4c79db8c383f296300a5be", "static/js/element-ui/lib/theme-chalk/popover.css": "4d19d78df7b0a3157772b86018648ee9", "static/js/element-ui/lib/theme-chalk/popper.css": "36fcdf5712174c8177fe2fcb73977ed5", "static/js/element-ui/lib/theme-chalk/progress.css": "a3d92e7241d275e11982945ad7c7e284", "static/js/element-ui/lib/theme-chalk/radio-button.css": "d126d35d880b72736a6d24b94170b9eb", "static/js/element-ui/lib/theme-chalk/radio-group.css": "86af00fe6b72f9005bf39e3481691586", "static/js/element-ui/lib/theme-chalk/radio.css": "a3110894bf315e7eedf9111a951840f6", "static/js/element-ui/lib/theme-chalk/rate.css": "0f33a694a0e389f05cd24aeec4b1765e", "static/js/element-ui/lib/theme-chalk/reset.css": "3db1afd65a0400d0d643f705d44250f5", "static/js/element-ui/lib/theme-chalk/row.css": "b1ac86fc178549496bb90eec4ba5da5e", "static/js/element-ui/lib/theme-chalk/scrollbar.css": "23449b1c81727518ce5d914579ee6174", "static/js/element-ui/lib/theme-chalk/select-dropdown.css": "f95dc3aef5e200e495d51f00a81b4e20", "static/js/element-ui/lib/theme-chalk/select.css": "d16e8c09f8fa26ec7d03b5652cdbb797", "static/js/element-ui/lib/theme-chalk/slider.css": "c7db7b54589f0ba57dd2b3a1057bfb90", "static/js/element-ui/lib/theme-chalk/spinner.css": "5b5d1e5f3e4422c063adc569a8346fca", "static/js/element-ui/lib/theme-chalk/step.css": "cf252484e262941d6d6c081042e38074", "static/js/element-ui/lib/theme-chalk/steps.css": "ac6f8637955a659b97ea3548a20fcfba", "static/js/element-ui/lib/theme-chalk/submenu.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/switch.css": "dbe3a9344c8c3594fce88715c118edf9", "static/js/element-ui/lib/theme-chalk/tab-pane.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/table-column.css": "e11267cebea4826211fbfbc1f88c6ec8", "static/js/element-ui/lib/theme-chalk/table.css": "facf1d994f3fda680e22163b2e4148c2", "static/js/element-ui/lib/theme-chalk/tabs.css": "ec342796738d9d1a87137c0451c6b784", "static/js/element-ui/lib/theme-chalk/tag.css": "52178a68247a9fe015ccb5e965ce3fd3", "static/js/element-ui/lib/theme-chalk/time-picker.css": "7a25549a612c52a82dcc265f20566f0c", "static/js/element-ui/lib/theme-chalk/time-select.css": "a230a27e1eae140dc38e608de2651ba6", "static/js/element-ui/lib/theme-chalk/timeline-item.css": "743e68350200b578c75506697a7f5789", "static/js/element-ui/lib/theme-chalk/timeline.css": "b5d2b9a92b38005cff9a5752246992e1", "static/js/element-ui/lib/theme-chalk/tooltip.css": "4722109edb63d5c732ca61ecb3d47175", "static/js/element-ui/lib/theme-chalk/transfer.css": "14928e12a3985c3d0e516e6799601d65", "static/js/element-ui/lib/theme-chalk/tree.css": "5f5d85942e52967f08d4f1698cee2683", "static/js/element-ui/lib/theme-chalk/upload.css": "077d8dc834e6d88194879db89ff54bc5", "static/js/element-ui/lib/theme-chalk/fonts/element-icons.ttf": "4b1a4d348209ad29243b0a042de1b557", "static/js/element-ui/lib/theme-chalk/fonts/element-icons.woff": "f717deee44e7fcc757c6c1ade5cce443", "static/js/element-ui/lib/transitions/collapse-transition.js": "354e780b8a86771cd737928485f7d798", "static/js/element-ui/lib/umd/locale/af-ZA.js": "0fc2ac6b8936f2cd76256d2672b8b426", "static/js/element-ui/lib/umd/locale/ar.js": "18bbfc189ca1a3da137e560c112e0aba", "static/js/element-ui/lib/umd/locale/bg.js": "2c6245f699c62437fa7ee0d163cdd65c", "static/js/element-ui/lib/umd/locale/ca.js": "f494da9c984efa37bb7aff8be66d026e", "static/js/element-ui/lib/umd/locale/cs-CZ.js": "6554aa484f5ec7b4d1e3ad176cc69b71", "static/js/element-ui/lib/umd/locale/da.js": "0fb807a6d9d65b4d438c1e8563e369c4", "static/js/element-ui/lib/umd/locale/de.js": "835ff2b17f107ff50be524805b201f3c", "static/js/element-ui/lib/umd/locale/ee.js": "a363d6f90a0acfea8f31f1a6be49aeee", "static/js/element-ui/lib/umd/locale/el.js": "e9b50aee66128071682125d1e9d98c23", "static/js/element-ui/lib/umd/locale/en.js": "eccc9db8251b0ef6f69337f39234d423", "static/js/element-ui/lib/umd/locale/eo.js": "373c79e4396edec41165343f5a889f99", "static/js/element-ui/lib/umd/locale/es.js": "f33d213c3974b2acdc167886b61f2e47", "static/js/element-ui/lib/umd/locale/eu.js": "62bcc16524b72c7094a20162832b36b5", "static/js/element-ui/lib/umd/locale/fa.js": "273a1e35316564355fed5eb3bfeb2ab8", "static/js/element-ui/lib/umd/locale/fi.js": "9f9889caf4adcffc6cc78c229c457a7a", "static/js/element-ui/lib/umd/locale/fr.js": "ecd5286ed9b8faf83a56bbe449df9e00", "static/js/element-ui/lib/umd/locale/he.js": "db9119fe9dc05c872421bf4758de2eca", "static/js/element-ui/lib/umd/locale/hr.js": "9396ffd6cc82eeb3a09ce0d8ed1dd483", "static/js/element-ui/lib/umd/locale/hu.js": "1e6962cb413392e68dae16680bcd6370", "static/js/element-ui/lib/umd/locale/hy-AM.js": "85701cecfaf21f5813aeebe91b2b7560", "static/js/element-ui/lib/umd/locale/id.js": "1b99f644e81cf63fc7cecd34746dc66e", "static/js/element-ui/lib/umd/locale/it.js": "4fd6e8ba9c2d5fe7c9e74f753b95379c", "static/js/element-ui/lib/umd/locale/ja.js": "567701dd5feb9804153acefabfaa44b9", "static/js/element-ui/lib/umd/locale/kg.js": "4b4067ad2fb93f84a6c9e8c35de483e9", "static/js/element-ui/lib/umd/locale/km.js": "c69fc83984c03a7a4f04cdc6967cca58", "static/js/element-ui/lib/umd/locale/ko.js": "9bdf5bf54251017cb60636c8b4fe0ecf", "static/js/element-ui/lib/umd/locale/ku.js": "581e50d5471c9ec4c535ebcdb5ba68c8", "static/js/element-ui/lib/umd/locale/kz.js": "3113fafaec1e5f4ae75275df004a438f", "static/js/element-ui/lib/umd/locale/lt.js": "1f9ab75d239d73dd6450d20719d14e4c", "static/js/element-ui/lib/umd/locale/lv.js": "06ed0fdc7d15aaaa254ddafd5cc2d984", "static/js/element-ui/lib/umd/locale/mn.js": "a30050261567e96fcae3eb8184077738", "static/js/element-ui/lib/umd/locale/nb-NO.js": "8f696776c06ee3e12e43a4cdd6cce736", "static/js/element-ui/lib/umd/locale/nl.js": "99258a51fa6d3bb2eaf24687b08681b6", "static/js/element-ui/lib/umd/locale/pl.js": "727bf2dd0d8c2917c7d7b67651fa4e2c", "static/js/element-ui/lib/umd/locale/pt-br.js": "9b175360cb8d7199055506a7f57e7d4b", "static/js/element-ui/lib/umd/locale/pt.js": "1626947603ba9812628e5388526e02e7", "static/js/element-ui/lib/umd/locale/ro.js": "fb9eef3d28ce9ecc7ad83b41caf17864", "static/js/element-ui/lib/umd/locale/ru-RU.js": "02776c80fbb8f65298ef9156d79d11ee", "static/js/element-ui/lib/umd/locale/sk.js": "34457b2d2b6c75a8025a0eba36931523", "static/js/element-ui/lib/umd/locale/sl.js": "2d186805c45ce5292f9dfa2f2255677f", "static/js/element-ui/lib/umd/locale/sr.js": "57009e2dc4bc4de61794b29c659a132d", "static/js/element-ui/lib/umd/locale/sv-SE.js": "315c4a945b2b89e206ade38990a7e9f9", "static/js/element-ui/lib/umd/locale/ta.js": "da94b97bf773e49867bdd4c91b738cdf", "static/js/element-ui/lib/umd/locale/th.js": "76dde843e7f874f2e45cc1ea1dadc638", "static/js/element-ui/lib/umd/locale/tk.js": "710dfdc6ba97ebc5b6ed5e5c6ba40c79", "static/js/element-ui/lib/umd/locale/tr-TR.js": "2af8060b6746a342827a94ee1d45972c", "static/js/element-ui/lib/umd/locale/ua.js": "c2240b43e3d70e4b2c25db2580d5b9ad", "static/js/element-ui/lib/umd/locale/ug-CN.js": "6ddaea800aed2638e2d02b06322ceb07", "static/js/element-ui/lib/umd/locale/uz-UZ.js": "ddb5d919cc3756722a2980f995086225", "static/js/element-ui/lib/umd/locale/vi.js": "764578d2497752bec40d8cf3982501d5", "static/js/element-ui/lib/umd/locale/zh-CN.js": "af0b3424682dedebc3064a17c8c8f047", "static/js/element-ui/lib/umd/locale/zh-TW.js": "ee9c9d202116bd367a54b6542b41e9ac", "static/js/element-ui/lib/utils/after-leave.js": "5b6eab2e19137f22b7f155c64c127b5a", "static/js/element-ui/lib/utils/aria-dialog.js": "584e07ba3bcd14fe02d84d456461a381", "static/js/element-ui/lib/utils/aria-utils.js": "bccd0c0998fa688607a28aef5d3954be", "static/js/element-ui/lib/utils/clickoutside.js": "1d2c86f338286924e65ba0beb1e9275b", "static/js/element-ui/lib/utils/date-util.js": "f7bc86e6068c4c4f23c86f7d6fafce77", "static/js/element-ui/lib/utils/date.js": "63bca9e7033fcf66fa9b93ccaf4dad0f", "static/js/element-ui/lib/utils/dom.js": "7a5bf584e8d01360f759c1a78305219c", "static/js/element-ui/lib/utils/merge.js": "48d430909e3583f3010bf4e844bd1163", "static/js/element-ui/lib/utils/popper.js": "f90f278e90fdff8f4afd382145b2db9b", "static/js/element-ui/lib/utils/resize-event.js": "96628f5f98b18fee3c4972e8f39b6481", "static/js/element-ui/lib/utils/scroll-into-view.js": "a2847b7f5d7ae6860f66669f645ce861", "static/js/element-ui/lib/utils/scrollbar-width.js": "6dd9aafa50bf2028e1fa542feb995f89", "static/js/element-ui/lib/utils/shared.js": "e9becb8ca1ad71a5d64d989e28778b11", "static/js/element-ui/lib/utils/types.js": "b76cda09d6b97c9598681b372f3efd6e", "static/js/element-ui/lib/utils/util.js": "c4013004a996dd7d030f779c721c7c2d", "static/js/element-ui/lib/utils/vdom.js": "a72f60b0134bd47f49c537ad28982bad", "static/js/element-ui/lib/utils/vue-popper.js": "ea42e858259fa582acfadc15265b1d30", "static/js/element-ui/lib/utils/menu/aria-menubar.js": "172afd68add2537d32f299e5369c8ad8", "static/js/element-ui/lib/utils/menu/aria-menuitem.js": "2c51a053252827845cce692634443771", "static/js/element-ui/lib/utils/menu/aria-submenu.js": "2d5f39c9bc644388bc57563ee8ecae87", "static/js/element-ui/lib/utils/popup/index.js": "8df7b5c153e9187359c20ab602ad6740", "static/js/element-ui/lib/utils/popup/popup-manager.js": "68856d04bb10de1e999fc10693a73999", "tests/README.md": "bad9b5c1d18429a006532bb7faebd117", "tests/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/assets/\u5168\u90e8\u6d4b\u8bd5.png": "dbed30a78bcec42c7523471fcf514700", "tests/assets/\u6253\u5f00pycharm\u7684pytest\u529f\u80fd.png": "b849c96411e8d82fc8a50f0ff816c1f7", "tests/assets/\u6267\u884c\u6d4b\u8bd5\u7528\u4f8b.png": "39116cca185c73ae3d4517ee0f84133a", "tests/assets/\u6d4b\u8bd5\u5931\u8d25.png": "d04228741f3da0b6e977211fe41c6438", "tests/assets/\u6d4b\u8bd5\u6210\u529f.png": "6669c0c45442db35ab92b06bf9993c06", "tests/test_algorithms/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_algorithms/test_linear_algebra/test_linear_space.py": "6df796d85cb787fd7f045a0ab5c63a1c", "tests/test_algorithms/test_linear_algebra/test_matrix_cross.py": "4b574f0a6131847d802761bd83a6d6ae", "tests/test_algorithms/test_linear_algebra/test_matrix_determinant.py": "041bf9f620c2dcb093bf20cf4ed20c72", "tests/test_algorithms/test_linear_algebra/test_matrix_diagonal.py": "b8afb32ca59752683d9c605a9885e2f5", "tests/test_algorithms/test_linear_algebra/test_matrix_divide.py": "2b63a05c372c145b05920fe5c8e7ee1d", "tests/test_algorithms/test_linear_algebra/test_matrix_dot.py": "3f80ff34c4b639fc33344ce8c23ab153", "tests/test_algorithms/test_linear_algebra/test_matrix_eigenvalue.py": "0edcf7066a5e3143d089a0222d8659be", "tests/test_algorithms/test_linear_algebra/test_matrix_inverse.py": "8f502aabb41e4faaae06663c45fe52a9", "tests/test_algorithms/test_linear_algebra/test_matrix_multiply.py": "45423c811a4db180b269945908595383", "tests/test_algorithms/test_linear_algebra/test_matrix_transpose.py": "d92dc7600a77f090f5f897dff9d099e4", "tests/test_algorithms/test_linear_algebra/test_ones.py": "faa005c5fce0def31dcc4aa83861f4de", "tests/test_algorithms/test_linear_algebra/test_reshape.py": "ff0f15e2ba03d7bd3ee086deab31f9d0", "tests/test_algorithms/test_linear_algebra/test_shape.py": "29a411d526e34d9070155e1a198195db", "tests/test_algorithms/test_linear_algebra/test_zeros.py": "5c8802a5d2bd87dc00e67e7f2f892c9e", "tests/test_algorithms/test_linear_algebra/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_algorithms/test_statistics/run_distribution.py": "fd81a148edd8cb40ed4390dde9c9af9d", "tests/test_algorithms/test_statistics/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_data_adapter/run_dump_load.py": "4b7572b7ce9b3c6ce0ed6d6811b64e6b", "tests/test_data_adapter/test_array.py": "717162f0f2da526e3a18456b12dfbd10", "tests/test_data_adapter/test_data_frame.py": "e56b02672c2d979b495c24fdc113eafc", "tests/test_data_adapter/test_detector.py": "92495e21a9b05068d73833d4d6a8f3f9", "tests/test_data_adapter/test_universal.py": "f69c1055e69f2e844596a3b80ab20c88", "tests/test_data_adapter/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/__init__.py": "4277383d96a0b390d7299069af45c987", "tests/test_dev/test_doc/test_file_tree_node.py": "362ef3dedb9be7eca57248be44f93e3f", "tests/test_dev/test_doc/__init__.py": "d2b42ea8d4d60b51c772335633e18078", "tests/test_dev/test_doc/test_case_for_file_tree_node/main.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/README.md": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/_exclude.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir/core1.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir/test1.txt": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir2/test2.txt": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir2/__init__.pyw": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir3/core3.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir3/test3.txt": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_widgets/test_maccabe/mccaberun.py": "17cdb5bf5d1157aeba779172c294ad95", "tests/test_widgets/test_maccabe/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_widgets/test_normal/test_display.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_widgets/test_util/test_util.py": "8db14adf951ddecf73952d6841b2aa93", "tests/test_pmtoolbox/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_ui/test_ipython_support.py": "4e109800eedb8113b7da674b05e08bac", "tests/test_ui/test_pmgpanel.py": "a8d7ede78b58ae7be4f738f322f9be98", "tests/test_workspace2/test_data_manager.py": "bcf209b27357532443d75b3c368e68c7", "tests/test_workspace2/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "utils/environ.py": "b8bfeb3f35922c0337c197abea87829f", "utils/http_client.py": "3a5ced47c6f09803ad68b4da5b59d7f1", "utils/path.py": "93a5404fabe530d18791aaafecfd1b40", "utils/platform.py": "2da872dbe9abece68ed95e204c2ff655", "utils/__init__.py": "7e6452c9cf8ce5c4c856dcbdd3cf6b2f", "utils/debug/debuggerprocess.py": "0fe81aa6f61d81df42ef9afcc2d25bd5", "utils/debug/pdbtest.py": "b79fc6b32634f06788247e8d58402d41", "utils/debug/pmdebug.py": "d384421931a8e48e26cab0fba3c4241c", "utils/debug/test2.py": "b53f37a4994356be41f962afcb0a0b10", "utils/debug/__init__.py": "350446184463764465845852bd3ef50e", "utils/doc/file_tree.py": "36bd540c3b4c32b184dee9f2182f0819", "utils/doc/index.rst": "2488cd21dbd21544665f802ab3f0045e", "utils/doc/rst_generator.py": "fca7802a37b44b4a62924aa7521d6a2a", "utils/doc/__init__.py": "892fd1aca5b1cae0f580cd809094dad2", "utils/doc/doc_guide/choose_position.md": "482843264c94f2bd50c448fec43a3cc3", "utils/doc/doc_guide/compile.md": "eeee41c8eefce5234f176c76a0b15ee9", "utils/doc/doc_guide/index.rst": "0f1e7af0e52ee3073edf77f0eb9b0de6", "utils/doc/doc_guide/md_guide.rst": "809611fdb43d6b05edfadf5cc3a8c7c7", "utils/doc/doc_guide/rst_guide.rst": "8fa7462d9a5b56d6c5a67646e2ba4acc", "utils/doc/doc_guide/use_chevereto.rst": "3cb77997069a4c98b34360c9490f5733", "utils/doc/template/module.rst_t": "3af408a56d3d4adb3acfe09f653128ac", "utils/doc/template/package.rst_t": "801c621e304bc973e95f2e2519de04f8", "utils/doc/template/toc.rst_t": "a7cf368655e8fd91249cee24406aaff8", "utils/doc_figures/\u5e15\u7d2f\u6258\u56fe.jpg": "17c5690d782d1554a0eee747b496dcac", "utils/doc_figures/\u5e94\u7528\u5de5\u5177\u680f.png": "52d6b3bbabc43c2d368ce7748e8a9c7d", "utils/doc_figures/\u5f02\u5e38\u503c\u68c0\u6d4b": "49f442e7d72e05764e8353e36a824637", "utils/doc_figures/\u6807\u51c6\u79d1\u5b66\u8ba1\u7b97app\u754c\u9762\u539f\u578b.png": "5a6aa5719ae6d2ab0a3e2deeb4d9f841", "utils/doc_figures/\u9879\u76ee\u7ec4\u6210\u7ed3\u6784.png": "7d7896300a5e62d2fad7062bcba88aee", "utils/io/file_import.py": "d41d8cd98f00b204e9800998ecf8427e", "utils/io/piputil.py": "d45b0ab10e658c8bd1a260e7a7b0daca", "utils/io/__init__.py": "e9846ca05e2cf2393e2d36e130f7e84f", "utils/io/dbconnect/dbBaseTool.py": "964e1d0151fac429242dfdd163d6693b", "utils/io/dbconnect/dbConnectAccount.pkl": "410722595449e489f364425f6cd8c240", "utils/io/dbconnect/dbutils.py": "a83eac2b48d43e4bbb144b6ee30ac5a6", "utils/io/dbconnect/test_dbBaseTool_add_connection.py": "9777701d02960adae45e4ebc5afdabbc", "utils/io/dbconnect/test_dbBaseTool_query.py": "637037577573d38544ed3a801e4a8238", "utils/io/dbconnect/__init__.py": "5111d7ba85f86397e7318a88362fd502", "utils/io/fileutil/compressutils.py": "d79d280d2f6ddc66de6687a7b8201338", "utils/io/fileutil/encoding.py": "f70ddeb46e587c343134428e3a1d9b6c", "utils/io/fileutil/search_in_path.py": "3a369957683bec55df7e6e63cb3ce499", "utils/io/fileutil/variableutils.py": "e980e969d1f33da86e71e1207f282fe5", "utils/io/fileutil/__init__.py": "86e37c6a62dd940b6add84e2f3464697", "utils/io/fileutil/source/encoding/test_ascii.csv": "930b9d198c8fe4cf62cb40bf86deb059", "utils/io/fileutil/source/encoding/test_gb2312.csv": "b78fff031a5e71e40eaa348a628dd45e", "utils/io/fileutil/source/encoding/test_gbk.csv": "b78fff031a5e71e40eaa348a628dd45e", "utils/io/fileutil/source/encoding/test_utf8.csv": "b3c2e6ec634b81b2ebd348a3983fc165", "utils/io/fileutil/test/test_word_in_line.py": "0e2699f99428b73b86fdeb3fca2ee3b3", "utils/io/pmserial/pmqtreadserial.py": "7f31cf4aa590690a8c9e53b4d3599ce8", "utils/io/pmserial/readserial.py": "5cafed26a707eecdac54883dca6d2c33", "utils/io/pmserial/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "utils/settings/settings.py": "a65d80cc4a777b526b057b8efebd6989", "utils/settings/__init__.py": "43d16a290ee34cb378a6c6244e8c0a32", "utils/ui/translation.py": "a75ca908fa328d348adc9106554e35d7", "utils/ui/variableselect.py": "6623e3057f2291f6ad61ee1e55ac58c4", "utils/ui/__init__.py": "05099d0c6cd09966cb7621c9e57c2f13", "utils/ui/app/pmbasicapp.py": "a8cf494179389639ee3a68e39167cdc1", "utils/ui/app/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "utils/ui/app/test/basicapp_abnormal.py": "74d0fab0335ac9847dd589275e304c64", "utils/ui/app/test/basicapp_pareto.py": "522a51d208d3d32c68e9de0267a9f1fb", "utils/ui/src/balance.png": "0e13e9c8fd6853eedef19ac2ca0d9f01", "utils/ui/src/chemestry.png": "be3234787dcd5ad6b8c03cce7d142dfd", "utils/ui/src/electricity.png": "390b497d0687540630694599edc71dac", "utils/ui/src/engineering machinery.png": "099cdd52b97926617032ff66487cc311", "utils/ui/src/fracture.png": "e2dcccc7d7751d10b0e439a9a8b8f7d3", "utils/ui/src/function.png": "0a6dd73740c6800c913a5dc8556539cb", "utils/ui/src/gauge.png": "167e1ea4af8c9e504c30e734e7761488", "utils/ui/src/histogram.png": "231deddcfe9222512173e3d0b7829728", "utils/ui/src/ic_common_\u751f\u7269&\u81ea\u7136.png": "351343f4046d6d2c7a3405065d3a66a2", "utils/ui/src/loadwave.png": "95280a0b2dbc61a6c817d40e705f0379", "utils/ui/src/log.png": "117ef9da5ed765f2cc31f65bd2a49db9", "utils/ui/src/math_1.png": "a62c3b980b0f9332c56452c2dfac5a8c", "utils/ui/src/math_2.png": "d98240ad143bbc7cc739cac16b18e60a", "utils/ui/src/math_3.png": "0dbbea9ccc5e7cfa409a65e7ab0d16c4", "utils/ui/src/mechanics.png": "e730af4dc4083d52675826590d05dfa8", "utils/ui/src/money.png": "078a6fec99543566f7abd7f9d235cfc1", "utils/ui/src/motor.png": "cb1071e863f9d4108d509a1f0a29ce8e", "utils/ui/src/motor_2.png": "b71bdb729289a54a9330af929f477b39", "utils/ui/src/normal_distribution.png": "18785959972c6076e3201e41ba68d971", "utils/ui/src/physics.png": "67a6b64cee517d8678e2001ebd2af37d", "utils/ui/src/physics_2.png": "75796555027a4edc1bf441a69800de78", "utils/ui/src/plot_1.png": "484e1553dbd4d3b51dc986af7da9126d", "utils/ui/src/plot_2.png": "fa13d212836a556060df8fbee4dd8593", "utils/ui/src/plot_3.png": "bf548bcb5eba63b655fcaafa9af1e50e", "utils/ui/src/plot_4.png": "63658bb0aa5e10850d4cbcefb31bc5ec", "utils/ui/src/roboarm.png": "adc612a5fbe26cbc1ef9964078be30d0", "utils/ui/src/run.png": "fcf7e23f264801b79df841dabdab9417", "utils/ui/src/run_cell.png": "e40eb239205653b61fa2ba5a57f8d378", "utils/ui/src/settings_1.png": "4dc1f5c80740868b1cf0a4f50909dc20", "utils/ui/src/settings_2.png": "e8cd30a0264a6ee00fbe461e72a9fb6e", "utils/ui/src/settings_3.png": "2917d7c1b222d2e235a85f7e677935ca", "utils/ui/src/sinsidual.png": "371e0fdb35b52764d7d9c17774c36a07", "utils/ui/src/statistics.png": "3e1dd67456f93098bc0276c3b37e1b45", "utils/ui/src/statistics_2.png": "524756b6420d9a60cec2212e23112dbc", "utils/ui/src/statistics_3.png": "737c1756516487220aafa992210374bb", "utils/ui/src/viberation.png": "49ccb24861c08a92834e814bf8ea4767", "utils/ui/src/wave.png": "402b0e16aaf792596c734ee454ba25dd", "utils/ui/src/wave_2.png": "ce59ead6a036cca68b02950c9bdcb91a", "utils/ui/src/wave_history.png": "566e2a0ac92bf12f6291e0dd4d272091", "utils/ui/src/\u5206\u5b50\u751f\u7269\u5b66\u5e73\u53f0-\u7070.png": "6a5127ef0f94e54506455e0dd5d8d712", "utils/ui/src/\u751f\u547d\u5065\u5eb7\u4ea7\u4e1a_2\u751f\u7269\u533b\u836f.png": "c6f652bcc942e7c3c244d06726fcf063", "utils/ui/src/\u751f\u7269 (1).png": "9f4b502be694761d44c106a09a61be19", "utils/ui/src/\u751f\u7269 (2).png": "58da036ee4e5ead077590ebb65b80460", "utils/ui/src/\u751f\u7269 (3).png": "9cf816bfb76439a5f366e9beca9bea92", "utils/ui/src/\u751f\u7269 (4).png": "3b699f6ca234d635a8bc3274a7b44020", "utils/ui/src/\u751f\u7269.png": "4bcc3068ba68359848f293c23ac0b670", "utils/ui/src/\u751f\u7269\u8bc6\u522b (1).png": "021f770979cb264bc827ac041bab972b", "utils/ui/src/\u751f\u7269\u8bc6\u522b.png": "d73c19821dbdc9b46facd404afda33f4", "utils/ui/uiutil/datashowutil.py": "a88e7ef43145082c8278f6273e1bfb05", "utils/ui/uiutil/workspaceutil.py": "4a74ba5a7a176257d0e659d4be892301", "utils/ui/uiutil/__init__.py": "d611c6031ffff2a4570872c525a95660", "utils/ui/uiutil/formatting/textformat.py": "dee7f3523b301ceb8bdb0b35da44e456", "utils/ui/uiutil/formatting/__init__.py": "73a717186f47f07e16e0dcb8ed4ed76d", "widgets/frame_less_window.py": "e2a0208d327013c21bd75c71535d05af"}} \ No newline at end of file +{"files": {"app2.py": "c7e061a1c028e828cb2bd76c46a7a858", "lib/check_dependency.py": "35b3112cf9cb50d31be5f45c8ae3d179", "config.ini": "7f83e4b78df1a293343baeaaf5881203", "dist.py": "e3b17ce9bea81da8f9b4582ee78fe6cd", "LICENSE": "b5b6bed06dd8ed68f00c26d0b4cede89", "load_modules.py": "6bfcd0281e7ab654b27851cc25c2a31f", "pmgui.py": "54472e38004442ee8209f732e013e09a", "pyminer.pro": "148c684e721b44a4a29ec4c700e95c49", "pyminer.py": "8676961ecd2c4d293db44b2e8e962315", "pytest.ini": "7e1ac696b90974c21fcaed50d881ebf1", "README.md": "618338896f514c4f446bd0142edce65a", "requirements.txt": "bdc7ed15fe5b96b65882b02a3ce91877", "requirements_dev.txt": "6e23539b6bc3cd698e6f9713e598e2a9", "requirements_linux.txt": "32193efcf05f692095c24da7263ea8de", "requirements_mac.txt": "a1fdae24ed40656c9879626a8130c59c", "run_before_commit.py": "067f08926721cb4679e63604fa3528c4", "update_translation.py": "afcbf3f7c930b65e44c1bed2430d4284", "\u5f00\u53d1\u6307\u5357.md": "791025c5ef81f9b6a334e4f6d39e9cb6", "\u5f00\u53d1\u8fdb\u5ea6.url": "e47baa8f175a5766ae709b9e8d951b53", "configuration/config.ini": "56859fc0e799ae26d49fd7a41cfe0532", "configuration/default_settings.json": "7bdc7e60ac0fe14d849afb297fb9db2f", "configuration/extensions.json": "cb8f6f2bf8cdccae988f3cb589282f7c", "configuration/settings.json": "81f0b5a2f4f719f23e247b92ee72fff7", "core/__init__.py": "f0d32e8fca7a2398789eb9b0537057ce", "core/algorithms/index.rst": "493e85a5e6744431a7755a7d33f9979d", "core/algorithms/__init__.py": "489b6a395b7e79f2cab1f8c46eec73e1", "core/algorithms/calculation/digits.py": "b14e19d1913de492b116201b5f5c6c27", "core/algorithms/calculation/__init__.py": "6fb7087712399aff01a8a820cd77a474", "core/algorithms/linear_algebra/array.py": "f1e96ef9af8aaf15aaef29c863b3663c", "core/algorithms/linear_algebra/exceptions.py": "cc1a682728cd86a67aaf4b03a27c3e8a", "core/algorithms/linear_algebra/linear_space.py": "0d12ac5250106fc5fd0270b502ceb6e1", "core/algorithms/linear_algebra/matrix_cross.py": "ba1e06a57db80bcaa9509d6e733c1df9", "core/algorithms/linear_algebra/matrix_determinant.py": "23a47100204fd2f73f43cc201113f5e5", "core/algorithms/linear_algebra/matrix_diagonal.py": "ab7c7e101f46ebe7ed4bc73f542f111a", "core/algorithms/linear_algebra/matrix_divide.py": "01ec01fbb97bca37f22f719f3dc3d089", "core/algorithms/linear_algebra/matrix_dot.py": "67d721785420cd3f3344ac69bdb6ac32", "core/algorithms/linear_algebra/matrix_eigenvalue.py": "43b83077241aa32acdff04c8489363f5", "core/algorithms/linear_algebra/matrix_inverse.py": "f4c6ec6129a07ea821aff5b6b84f2aa6", "core/algorithms/linear_algebra/matrix_multiply.py": "067a30b30ff9be6d9b9123a75a30abc9", "core/algorithms/linear_algebra/matrix_transpose.py": "d63b39c00f437fab1540f331876444ab", "core/algorithms/linear_algebra/ones.py": "f7c3f42cde513ec5e91bc24dbc068d62", "core/algorithms/linear_algebra/reshape.py": "54f0d073af724f1c3c474e59940c6f72", "core/algorithms/linear_algebra/shape.py": "863cf7a043ab1d82f02a3a1279632b57", "core/algorithms/linear_algebra/zeros.py": "161e8f970d39d7bb2135852051a18005", "core/algorithms/linear_algebra/_utils.py": "8864ac424626bc7804d31b3e0ef3905f", "core/algorithms/linear_algebra/__init__.py": "a1ff4909241d1462727c33e5a8038cbd", "core/algorithms/linear_algebra/\u5f00\u53d1\u6d41\u7a0b.md": "54daed08712378a9ad4208884b65088b", "core/algorithms/linear_algebra/assets/code_hint.png": "013aecfff792430d0d3fac227bfcaaf4", "core/algorithms/linear_algebra/assets/configure_test_utils.png": "952e07a65e50b2fbd9666f8544ac20fa", "core/algorithms/linear_algebra/assets/define_function_framework.png": "4c921fffe0c7b10e5fb01e02d8f7a353", "core/algorithms/linear_algebra/assets/demand_change_file_change.png": "537d6591e1833d43c9fd6fc30cd1b2f6", "core/algorithms/linear_algebra/assets/finish.png": "d4c5fb995d723b15072691707b0ed72e", "core/algorithms/linear_algebra/assets/fix_testcase.png": "b1f4c682efcfb3f23e32ab085cc85b50", "core/algorithms/linear_algebra/assets/function_explanation.png": "c7bc75487b2abe6a536fc91a880d5f44", "core/algorithms/linear_algebra/assets/function_explanation_file_change": "15ade2607376365bb31c38a79d46ea89", "core/algorithms/linear_algebra/assets/function_file_change.png": "5b961672e09adba22805a5098e1bbbd1", "core/algorithms/linear_algebra/assets/function_workspace.png": "2bf5321cda6e0e1ac939895233e7a833", "core/algorithms/linear_algebra/assets/help_doc.png": "0e2f87b116e1fcb517cc63d5aa8e3d21", "core/algorithms/linear_algebra/assets/import_in_global.png": "259b30531b0ab509d4b93acec5cf3db1", "core/algorithms/linear_algebra/assets/import_in_sub_pkg.png": "622f44c6ec4738254d8585ae341b945e", "core/algorithms/linear_algebra/assets/run_in_pm.png": "4a64482cdd2125276501a4190848352c", "core/algorithms/linear_algebra/assets/run_test.png": "0d9abff3ca8a85fa0c3f58aef6ffd2d3", "core/algorithms/linear_algebra/assets/testcase_file_change.png": "caeda394883222a82b6dabd224fe0f0c", "core/algorithms/linear_algebra/assets/test_error.png": "a6b5a1a95cdc1fc21ce522f35da111aa", "core/algorithms/linear_algebra/assets/test_pass.png": "7792d7ee583bdb629ea41cec3a5cbf07", "core/algorithms/linear_algebra/assets/write_doc.png": "5349a5f4df8ed7a982ac5c86298ce715", "core/algorithms/linear_algebra/assets/write_doc_file_change.png": "34753c6a77cc470710669f518cfb3055", "core/algorithms/linear_algebra/assets/write_function_file_change.png": "2f5d964072df62b5a915fc14a41597b9", "core/algorithms/plotting/graph.py": "1728aea4907b92b67fe91ad742a3083f", "core/algorithms/plotting/graph_configs.py": "614cbeae8b696da2e8fe983e3c87a5f9", "core/algorithms/plotting/__init__.py": "9f90fe07592b24c4a09ed9230b6c093d", "core/algorithms/pyminer_util/communication.py": "216e0f4b1c8b00d535f0585c7fa1add3", "core/algorithms/pyminer_util/__init__.py": "de143e26c42af15d96c77f52383561a0", "core/algorithms/statistics/__init__.py": "4bba02c1df562ce45ccf5dfc988ab576", "core/evaluation/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "core/evaluation/woe/config.py": "9ac12638758e61c547224a0b4cc5e5f8", "core/evaluation/woe/eval.py": "62ab9836e64b475b07e0ea5cccf3aeb0", "core/evaluation/woe/feature_process.py": "e12d77b446b6a75746499d909ca22ae8", "core/evaluation/woe/ftrl.py": "1e6dad2dfc172413104ef5b3fb25e88d", "core/evaluation/woe/GridSearch.py": "8b92ecf1226fa81972510b17aa4cc2c4", "core/evaluation/woe/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "core/evaluation/woe/tests/config.csv": "66f330fdc285911a52c4a65166eab04f", "core/evaluation/woe/tests/HereWeGo.py": "94d48377d8292b80d8f4929cf9162004", "core/evaluation/woe/tests/README.rst": "8f72b661abc5eaf059d05e603b1c705c", "core/evaluation/woe/tests/UCI_Credit_Card.csv": "afd3af2602d66d6ceb36cb04216f0ed2", "core/io/postgresql/psycopg2/compat.py": "7abef6e4534c7b625057e37289bc8c27", "core/io/postgresql/psycopg2/errorcodes.py": "b2346a81ec49de54caa4e32a5360076e", "core/io/postgresql/psycopg2/errors.py": "316dfc64e89c95715e974a31f96e18fe", "core/io/postgresql/psycopg2/extensions.py": "d7fc21cf847f2d12a60f56097e3eca2f", "core/io/postgresql/psycopg2/extras.py": "4d79c51ba46dc3285d9faf8789a37369", "core/io/postgresql/psycopg2/pool.py": "1b0403b2597557108c4c35a9bc568834", "core/io/postgresql/psycopg2/sql.py": "1b8ad7b5746ad2f514cbdd678954fee2", "core/io/postgresql/psycopg2/tz.py": "b70b2abdc56dc05e9c28993934bed8f4", "core/io/postgresql/psycopg2/_ipaddress.py": "e0ff64e2ae604224c8cd11d1bdb27003", "core/io/postgresql/psycopg2/_json.py": "38e03cf8ae626f8fa028ceb48dcdb960", "core/io/postgresql/psycopg2/_lru_cache.py": "5e2bc12517950812ccac51af1d61d8a5", "core/io/postgresql/psycopg2/_range.py": "46ff7ab96f96d7db81eee160f666cfa4", "core/io/postgresql/psycopg2/__init__.py": "36fa5f3355c7d7ea36b87d1cdda6afe4", "core/modelling/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "core/modelling/regression/base_regression.py": "461cde16f7769d88c386f6f142ec233a", "core/modelling/regression/knn.py": "9f0c137ed701a2d11325ae1c9da23caa", "core/modelling/regression/linear.py": "a7936db33b1faa26cdbdc53a4bb81dfc", "core/modelling/regression/linear_bfgs.py": "031491ee5d158dcc8d506458fd10dbdf", "core/modelling/regression/mean.py": "c494d914a7be950f81b073dcad1e8bdf", "core/modelling/regression/neural_network.py": "571fa4e8bdc730c503cda08b0afd1d41", "core/modelling/regression/random_forest.py": "33c3aa9f1300b805ef13dd96866ea114", "core/modelling/regression/simple_random_forest.py": "e8c180090ce051d2f57e94b98e30b3c3", "core/modelling/regression/svm.py": "f5547c9da4c71d06a1df162be1e51885", "core/modelling/regression/tree.py": "0bd5b05a252b233597b6ff7453881ebd", "core/modelling/regression/__init__.py": "5b1908d95bc0ac027b22c337ea12f21b", "core/preprocess/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "docs/make.bat": "0d5c4de56de1ea8fa10468d561de4d77", "docs/Makefile": "45ecc4dd568420521f285e291939ecf1", "docs/make_doc.py": "3710c825012f1dc2e8d4f5854622e186", "docs/PyMiner\u4ecb\u7ecd.md": "56012d9e37961de92ea165d227e8707b", "docs/THANKS": "ad97f1302bcf00e26a219a0801a0b34d", "docs/upload.py": "10534ab4011a82607ef2b0c2f6c1b599", "docs/source/conf.py": "86928f87e5b0a03cbdd58f6f8a87f55b", "docs/source/contents.rst": "cd9756a400d0aa68ef85e92394c58b25", "docs/source/contribute/index.md": "260363f4717c8db812dc5d9c2c5723f8", "docs/source/_static/css/pyminer.css": "4a98b74c6e7893114cabc72ef5c6b81d", "docs/source/_static/css/pyminer.css.map": "e82da77c9ca623f0acbf4cbc62d78cbd", "docs/source/_static/css/pyminer.sass": "e5940574b2a7af7e3b7c01c2fc600354", "docs/source/_static/css/README.txt": "6e9ef1827e9eaea7ca3831685d830c7d", "docs/source/_static/index_files/all.css": "242611f34a440c48c2e6405e91e01a71", "docs/source/_static/index_files/all.js(1).download": "d7b3138b22aac6df42d86c92e36763ba", "docs/source/_static/index_files/all.js(2).download": "83006561af55b7a96dd7e17d34ebfe8a", "docs/source/_static/index_files/all.js.download": "39bebcf34d45ccab4d08bfb31b684294", "docs/source/_static/index_files/check_data.png": "e44471c2514f8a048df2a89a9df2e795", "docs/source/_static/index_files/code.png": "814df667bb94b7d2ae844d938ec916b7", "docs/source/_static/index_files/font-awesome.min.css": "ea6cc550de5339fc787f1e041363e544", "docs/source/_static/index_files/ico_mailme_01.png": "c40acf63e04064714b98a30a92984868", "docs/source/_static/index_files/main.png": "1b6f8a5331f0c5954a86b9024f070568", "docs/source/_static/index_files/modernizr.js.download": "4fae2a90728c528aa148c31466b7ed39", "docs/source/_static/index_files/normalize.css": "ed3146b9b1ec5eecb132a21916d0afe5", "docs/source/_static/index_files/robot.svg": "ba2b8a892fc5457a02829ba0b2caf3da", "docs/source/_templates/index.html": "66315ce66e29f04ce356a9b8b0d41ac8", "examples/HereWeGo.py": "d94883e4b2545ccfec29c1e76aebb982", "examples/README.md": "d49b56a1fe9a7ef2530943a5848fac88", "examples/README_ZH.md": "ac49a6e35c2518cac510ee6920c840da", "examples/UCI_Credit_Card.csv": "afd3af2602d66d6ceb36cb04216f0ed2", "examples/woe_rule.pkl": "cc2695e5f41ac2679a2040e15ff9463e", "examples/datasets/air_quality_no2.csv": "c27e6437bf25787c881d0d5f57e10233", "examples/datasets/bankloan.sav": "b5e78f9be79d7ba44c4fe5ac69cddc02", "examples/datasets/boston_house_prices.csv": "6454dba73c425c66b50d5206ed45f1a0", "examples/datasets/brown-selected.tab": "9e43112b53c6f6c78fa0b2645ace506d", "examples/datasets/brown-selected.tab.metadata": "337569fc2132e37108b428b9b082cfe9", "examples/datasets/cars.sas7bdat": "073898a0487cde27abd7155461c564be", "examples/datasets/car_sales.sav": "7b2487624eb4ffb893812706d30b0542", "examples/datasets/ccpp.csv": "20372480cb1e06f4cb99e46a0bd759a4", "examples/datasets/class.sas7bdat": "6e69aeb1f12de8d3fc46a64cbd4dc786", "examples/datasets/conferences.dst": "78dc681ceec57ee82dbf1951f11fa758", "examples/datasets/datasets.info": "19934e0d167a3128a09c493b9aeb031e", "examples/datasets/diabetes.csv": "8523f75b2f041c08542910b7ea3a8e84", "examples/datasets/heart_disease.tab": "859a303f42efd8b2a1bd0f2e33fedf71", "examples/datasets/heart_disease.tab.metadata": "ed45f5da717ba279094a29f33a4b263d", "examples/datasets/housing.tab": "e0eda02af8c85dd28b21620ee5c74552", "examples/datasets/housing.tab.metadata": "9d88fcbc612a9928d951ceb5f22b04c9", "examples/datasets/iris.csv": "ffd137d9c66a717d061b9fa5831000b1", "examples/datasets/iris.tab": "bbf17c5ae7e81aeb2ad7694648a6b2e1", "examples/datasets/iris.tab.metadata": "e1d89c7e7561bcc716dafd546058196e", "examples/datasets/list_update.py": "737978a6df832d796431df3b048b051a", "examples/datasets/mushrooms.csv": "2007f683881ecd4febc1b7674c5751a8", "examples/datasets/slovenian-towns.dst": "e6c7acf1cb81c6d71523d0e7b3ea6f41", "examples/datasets/titanic.tab": "4291853e1bf953ef2c0c1e39653a0f80", "examples/datasets/titanic.tab.metadata": "5074c723c0342fa64396739eb0480d33", "examples/datasets/TitanicData.xls": "7afb9b02b50c902fd364364f7d2e49be", "examples/datasets/UCI_Credit_Card.csv": "afd3af2602d66d6ceb36cb04216f0ed2", "examples/datasets/zoo.tab": "90a455135a6a8822f1200630270bdcb0", "examples/datasets/zoo.tab.metadata": "1b824e81f9e8969228e01e460d6b05e6", "features/feedback.py": "2fed1192b08f982e19b6cb75f40c7f10", "features/index.rst": "caf9be56f3fc9b08f569abee024f6cf2", "features/openprocess.py": "539c43bc37743144d9216715b8fad57f", "features/README.md": "eed382b7fe1775f4b6b875d4b564ae50", "features/settings.py": "a7c36fc21234c3a23c7663e1b248e60b", "features/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/auth/authlocalserver.py": "1a7bd0455dc04627bdb5367c7ebc9c2a", "features/auth/authmanager.py": "06a45267063200c67104786db5cff4e1", "features/auth/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/auth/templates/login.html": "446aac7443cc70f43e46753092445aef", "features/auth/templates/register.html": "3a424e8c3bdf1eb6043e0ab9ca34acff", "features/extensions/index.rst": "01d20711a991f116e372db6fb72c96df", "features/extensions/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/extensions/extensionlib/baseext.py": "677942d6d94defa454ec27b173d582db", "features/extensions/extensionlib/extensionlib.md": "aacae615d8f781c275ac79c22fae5678", "features/extensions/extensionlib/extension_lib.py": "e48b16cc626c5001355438e28f00d219", "features/extensions/extensionlib/readme.md": "00629cf6b22e95200c530ea6d512057f", "features/extensions/extensionlib/__init__.py": "2dc050a0d3da896f4b39681a6e057f63", "features/extensions/extensions_manager/ExtensionLoader.py": "aee9c0b155f0bade604e41d3a38efa36", "features/extensions/extensions_manager/log.py": "6e8bd61219f2ff606b58c1399d322ddf", "features/extensions/extensions_manager/manager.py": "a7fa22dd5ba1fc531f31b0741f12c61e", "features/extensions/extensions_manager/readme.drawio": "4bafe50e30ca4be5cdef34e1e657f7a6", "features/extensions/extensions_manager/README.md": "97b9464ed10af4ad3015ac7f38e6cf99", "features/extensions/extensions_manager/UIInserter.py": "e66518eebc812a4f5b94997351fe1b0b", "features/extensions/extensions_manager/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/extensions/extensions_manager/vermanager/vermanager.py": "01c76efe94e29a53138a670f909f2d52", "features/extensions/extensions_manager/vermanager/__init__.py": "03f044152b579a37841af43eae7f2389", "features/interpretermanager/interpretermanager.py": "f444a2a4cebc7ae225cf46f61ae7950b", "features/interpretermanager/packagemanager.py": "573cf34280aff9d22775f692e63cbb8c", "features/interpretermanager/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/io/database.py": "567325cf72a6f4564a4a0f27326f1b25", "features/io/dbConn.py": "50780c5805a79cb1934b2d7e0d8c0ab6", "features/io/dbConnectAccount.pkl": "5d9291410939747f2c8c07dd81222283", "features/io/encoding.py": "3d17abe6b8042115f6e15b869aff7c44", "features/io/exceptions.py": "72dcca0f3371e119d43e9827e73528b0", "features/io/settings.py": "a3234ca4ddc2f8b0e0e62450756c1e56", "features/io/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/main_window/base.py": "aab682344cfc58317a1413203ebd6261", "features/pluginsmanager/pluginsmanager.py": "f7dc55bb96470571a9a6558cb3962591", "features/pluginsmanager/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/project/template/Basic-Template.py": "4204e7ce0f6309fd93535659c3c466c8", "features/project/template/Empty-Template.py": "18dc747535104b7c6ef67b21c97069f1", "features/project/template/Plot-Template.py": "b688a56819d86c6eb44ff9e72b809091", "features/project/template/PyQt-Template.py": "8a64552bb7be154721ceeaf50f4e8673", "features/project/template/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/project/template/PySide2Template/main.py": "ed912fbf0fc0c20fcacb81bd19800c14", "features/project/template/PySide2Template/PySide2_Template.py": "ac93a3b7fc512f9c0afa7f00a2643674", "features/project/template/PySide2Template/PySide2_Template.ui": "c8cd27a3e0b5cb1c9936603328d7b732", "features/project/template/PySide2Template/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/ui/main.py": "2d7d5d9496b9208ddb27e60f708a1a4d", "features/ui/ui_aboutme.py": "c79955815de4013a7a64d690f94febbc", "features/ui/ui_aboutme.ui": "160718ccbd19dc35a00aaeee6faffaa2", "features/ui/ui_appstore.py": "256f2fd75ad7ffdf667c13bf7a3b5128", "features/ui/ui_appstore.ui": "a7e7317eca4ee6311e41968445e1fa81", "features/ui/ui_check_update.py": "8226a48eb517b9da8cf425b809ff3c8a", "features/ui/ui_check_update.ui": "0766a087aa5b8e4a5e46f4211055aa9b", "features/ui/ui_data_normal.py": "d9971d97184ade3f9c405f061dd22231", "features/ui/ui_data_normal.ui": "c8a3e10c4487ce5a2774ca8ea5a5905a", "features/ui/ui_first_form.py": "cbbf26db8887e60df0dd7ce0713a5a54", "features/ui/ui_first_form.ui": "1b5d9231837a421c9b77382b3f6f1719", "features/ui/ui_login.py": "2fe8d95e4257473abea1549e127f7ede", "features/ui/ui_login.ui": "58916dfb5dd1dfab103fa4f15882a282", "features/ui/ui_logined.py": "668bf0e57ec258d1ee0b7bfac2abe1b5", "features/ui/ui_logined.ui": "e6d6f9d467a6b8a24336713481e9a6f6", "features/ui/ui_option.py": "12491a3f32f99d3bb7833291c5402cfa", "features/ui/ui_option.ui": "9cf7b928ccf449e096586e949cd7dd95", "features/ui/ui_preferences.py": "d925283bad5dc99d85a90798cb86c6ce", "features/ui/ui_preferences.ui": "4336a5c78eef921b047e1c86c49650f5", "features/ui/ui_project_wizard.py": "65f0c2afe19b349e8b63b57a941c4db1", "features/ui/ui_project_wizard.ui": "9d21051c8df87eb832bdf8a5470f1c8c", "features/ui/ui_workspace_launcher.py": "594f60adb389355ef83a5bca20eafb5a", "features/ui/ui_workspace_launcher.ui": "fd4e48c43a6d35a209c2696942f0927f", "features/ui/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/ui/common/debug_process_with_pyqt.py": "2971e07b890f1872c7f7009c4d2b44fe", "features/ui/common/openprocess.py": "3d1aeb10bde66329d7126840466ba6df", "features/ui/common/open_process_with_pyqt.py": "851480f8440b2f81033a319b5f32f465", "features/ui/common/platformutil.py": "070ffc4eaea4cb0c4b6dcca39fe4035f", "features/ui/common/pmlocale.py": "f7ca747cc3dedc2b6cf03c7b5f9ec121", "features/ui/common/test_open_app.py": "5f56a2266c07dd652659c949b297f498", "features/ui/common/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/ui/pmwidgets/dockwidget.py": "cb0c4fe5642dda21f5692ecce49eed95", "features/ui/pmwidgets/pmmainwindow.py": "5f3887a06e377de92251c6b49853cddb", "features/ui/pmwidgets/toplevel.py": "8700605abc51c422a5a1588dc80a8bfd", "features/ui/pmwidgets/__init__.py": "dbd5c209ff332a55a7e483fcb686421f", "features/ui/pm_marketplace/install.py": "54117accb9d426c89b751355b7e73f0b", "features/ui/pm_marketplace/install.ui": "22c1cb1d2e58f0e6e63d3c199af96edd", "features/ui/pm_marketplace/main.py": "1fea599f650efa60951f3029d940d73e", "features/ui/pm_marketplace/main.ui": "76b3d012f1742eeb8cb85a0ee9ec5680", "features/ui/pm_marketplace/package_manager_main.py": "0ab9760f90d31f8f0eb3287bdf530891", "features/ui/pm_marketplace/package_manager_main.ui": "8dba9def55b1ea06d6c953f33e875cb9", "features/ui/pm_marketplace/uninstall.py": "292fa58f6d05fc584029fb0650702aa3", "features/ui/pm_marketplace/uninstall.ui": "c1160fc571c23573e4bfb4ada3807edc", "features/ui/pm_marketplace/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/ui/widgets/controlpanel.py": "d5fceeb26a8878ff80d6339895dbb5cd", "features/ui/widgets/notificationwidget.py": "3c6d71d757c8a0e3a11b9e48ca7108eb", "features/ui/widgets/README.md": "9f7d88859d291d2f64cba1b6ba49a59e", "features/ui/widgets/reportwidget.py": "1f00f377fe6cfc610cf58e68462307e6", "features/ui/widgets/resources.py": "14a758e941b459f8b23704065f1e8639", "features/ui/widgets/__init__.py": "77b4a6a8852c7103e7525d3955c40358", "features/util/check_update_ui.py": "5bfc0584c45856ace75efedafd677436", "features/util/check_update_ui.ui": "0766a087aa5b8e4a5e46f4211055aa9b", "features/util/make_update.py": "17f81b28bdc7a353dac1d7b45ed762cf", "features/util/openprocess.py": "539c43bc37743144d9216715b8fad57f", "features/util/update.py": "896e76ccbae9ae36c17d14515b6fafa5", "features/util/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/workspace/data_manager.py": "d7b5e29419b744fad86e6245018de1e8", "features/workspace/index.rst": "3ce5d474607ba614ba9f6afc772e7bc2", "features/workspace/signals.py": "d950f3f33fd821323d95ece2b8d90e84", "features/workspace/signals.rst": "3618e25aa7f77f05142dc84a96eaf45c", "features/workspace/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/workspace/blinker/base.py": "83733f47cb03be3713ce7a5860612e96", "features/workspace/blinker/_saferef.py": "ced62e1fda983045da2076064a7db34d", "features/workspace/blinker/_utilities.py": "1aeb68e85d8ad0aa80295e5f29f42d18", "features/workspace/blinker/__init__.py": "464a73bb96572aaf6c2ed191676d40a4", "features/workspace/data/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/workspace/data_adapter/array.py": "2891617cd8d0eb1cd3780258212ce847", "features/workspace/data_adapter/base.py": "8d176a5909da92fbbfdade7ecd040127", "features/workspace/data_adapter/data_frame.py": "d71dc9d36194663b154bbb13eb1bf8a9", "features/workspace/data_adapter/detector.py": "af748d211285fe07fa56bf2b21e4d60e", "features/workspace/data_adapter/index.rst": "1d16f21a65dadb51dc1ecc68d9cad119", "features/workspace/data_adapter/universal.py": "49603cc94bc554bdb8456a1cdbdd39b1", "features/workspace/data_adapter/__init__.py": "b9da2c81695eae92f9748a4a59cd0c29", "features/workspace_old/history.md": "ab52fc7f26dff2cecf2f2f704844db56", "features/workspace_old/index.rst": "961579c17854f0d0d7b9f4e0bb6b1621", "features/workspace_old/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "features/workspace_old/datamanager/converter.py": "0cddb9d818f283a125bf534c3633f2b7", "features/workspace_old/datamanager/datamanager.py": "a2025c72d71aaf79728c54bfaf9dc3d3", "features/workspace_old/datamanager/dataset.py": "5d0b8678f8a53db8d8c9a483b90c79aa", "features/workspace_old/datamanager/exceptions.py": "6ed4da7a9003f12c756366cf67d87027", "features/workspace_old/datamanager/historyset.py": "85f91eac3f692ce44ed011647d319bac", "features/workspace_old/datamanager/metadataset.py": "9047c690af46c4db5b0501fdc25f975b", "features/workspace_old/datamanager/recyclebin.py": "c9effef9419e3be130a027f116761881", "features/workspace_old/datamanager/variable.py": "d35eb9e5fea49eaf5899d7315caa582a", "features/workspace_old/datamanager/varset.py": "54e77b59c43212ef22b4e271b8893953", "features/workspace_old/datamanager/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "languages/en.ts": "64307a7a6a8a2bc627ecbfaf2fc0e805", "languages/en/en.ts": "a426bc922ab99d1920e790b890d1b386", "languages/zh_CN/widgets_qt_zh_CN.qm": "cbaaec13dd22418095f6c7a9122926cc", "languages/zh_CN/widgets_qt_zh_CN.ts": "d81ecd8ec48ae725c76eba4f09ee9ecb", "languages/zh_CN/pmtoolbox_qt_zh_CN.ts": "95510ea97a650faeba03d155b1c81cbf", "languages/zh_CN/qt_zh_CN.ts": "bf9e10698c9cef267c344f73e30789e6", "languages/zh_CN/zh_CN.qm": "941aa53373af233466a16d682d7e625a", "languages/zh_CN/zh_CN.ts": "1be0a3147fea71527d4e17065a66d482", "languages/zh_CN/zh_CN.ts.bak": "c916a039d8a676ad891150786e9b1185", "languages/zh_TW/zh_TW.ts": "a426bc922ab99d1920e790b890d1b386", "packages/index.rst": "60e962032576844618f7a1448880b8fd", "packages/__init__.py": "a248423783ba8e03c638b996a91de109", "packages/advanced_drawings_toolbar/group_chart.py": "846a72c9e0303f8ef4b5c6b809f07db7", "packages/advanced_drawings_toolbar/ipython_console.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/advanced_drawings_toolbar/main.py": "78b220f88ba07d759c9f0722f6fc0306", "packages/advanced_drawings_toolbar/map_var.json": "91324fe1e6b292ebc2d548f3ae7d49b7", "packages/advanced_drawings_toolbar/map_var.py": "46e4e76e96cb5691754e4b63a38b67d9", "packages/advanced_drawings_toolbar/package.json": "3483b83687dfaf5bb4410107b04fdfd0", "packages/advanced_drawings_toolbar/radar_chart.py": "67ea13759ea77d67006df488c9fde4e0", "packages/advanced_drawings_toolbar/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/advanced_drawings_toolbar/pmmap/china/all/01-beijing.npy": "05fc6e35605340ef6e4d62af9770ef7a", "packages/advanced_drawings_toolbar/pmmap/china/all/02-shanghai.npy": "dbd37714da88edf44df7a2642ce2c14f", "packages/advanced_drawings_toolbar/pmmap/china/all/03-tianjin.npy": "e767b1d0810acfd174d4b52586441de1", "packages/advanced_drawings_toolbar/pmmap/china/all/04-chongqing.npy": "1980444de2496af7ae7b11cae9372d2c", "packages/advanced_drawings_toolbar/pmmap/china/all/05-heilongjiang.npy": "f369a349db31ac0636e625737802922e", "packages/advanced_drawings_toolbar/pmmap/china/all/06-neimeng.npy": "0366d9f95bfe2e0768a6491f8f5e27cc", "packages/advanced_drawings_toolbar/pmmap/china/all/07-xinjiang.npy": "201b3ff97375ae9ba6e9fc9c7b0eed1e", "packages/advanced_drawings_toolbar/pmmap/china/all/08-jilin.npy": "0ed85b6d84b877cf07154e1b54db0bdd", "packages/advanced_drawings_toolbar/pmmap/china/all/09-gansu.npy": "08c6e4437a0fc5d19d6c655a14a7df2e", "packages/advanced_drawings_toolbar/pmmap/china/all/10-liaoning.npy": "542d598f5c39b363738b0b753d8318d1", "packages/advanced_drawings_toolbar/pmmap/china/all/11-hebei.npy": "5a7ce525859caabaffad0fe1c11cb26f", "packages/advanced_drawings_toolbar/pmmap/china/all/12-shanxi.npy": "5ebb5347431393d599f5f0d36a31dd07", "packages/advanced_drawings_toolbar/pmmap/china/all/13-shan3xi.npy": "71944b8eea6caa0b7e4138063d6e8945", "packages/advanced_drawings_toolbar/pmmap/china/all/14-ningxia.npy": "dc0660ac4216cb4e928fb08dba5e36fb", "packages/advanced_drawings_toolbar/pmmap/china/all/15-qinghai.npy": "46f4e9bf9a47734d0cfbef0916e6cec1", "packages/advanced_drawings_toolbar/pmmap/china/all/16-shandong.npy": "b3eee97751e252f1c729b20cde81220c", "packages/advanced_drawings_toolbar/pmmap/china/all/17-henan.npy": "530d73e54901bf816e61c86bafb97219", "packages/advanced_drawings_toolbar/pmmap/china/all/18-xizang.npy": "83c873032100d735d2a3c1becb4e4ee5", "packages/advanced_drawings_toolbar/pmmap/china/all/19-jiangsu.npy": "33051765300de0a9d003ea91c3846cc6", "packages/advanced_drawings_toolbar/pmmap/china/all/20-anhui.npy": "d80f40e27c3a60188547d058c827eae0", "packages/advanced_drawings_toolbar/pmmap/china/all/21-sichuan.npy": "115e4b1abbc6df1f862095e94cacb8b5", "packages/advanced_drawings_toolbar/pmmap/china/all/22-hubei.npy": "065b61ce8a2728be70d0e726990e42c2", "packages/advanced_drawings_toolbar/pmmap/china/all/23-zhejiang.npy": "6910df476893b4e5a84689094203b724", "packages/advanced_drawings_toolbar/pmmap/china/all/24-jiangxi.npy": "2d4e166cd8d9371a1c6d01848ece3301", "packages/advanced_drawings_toolbar/pmmap/china/all/25-hunan.npy": "ddbce0334a1f79bd77f7b0ae582dd28e", "packages/advanced_drawings_toolbar/pmmap/china/all/26-guizhou.npy": "4d23f4f330203b61c6f8cca0ac764819", "packages/advanced_drawings_toolbar/pmmap/china/all/27-yunnan.npy": "1d1c9378c8427667dbf0b8948c36b484", "packages/advanced_drawings_toolbar/pmmap/china/all/28-fujian.npy": "77270ff92f0d67f0123672527b70772a", "packages/advanced_drawings_toolbar/pmmap/china/all/29-guangxi.npy": "3862d0becc054fe754ae71c111c583ad", "packages/advanced_drawings_toolbar/pmmap/china/all/30-guangdong.npy": "7d7f1392cc01a22d4503354ce7c729b1", "packages/advanced_drawings_toolbar/pmmap/china/all/31-taiwan.npy": "2f398da02605db2be30751dedb92ea90", "packages/advanced_drawings_toolbar/pmmap/china/all/32-xianggang.npy": "b3cf9d637c7d87e82a86174f99be74da", "packages/advanced_drawings_toolbar/pmmap/china/all/33-aomen.npy": "68e3c682aef3e25cf873878a19df5361", "packages/advanced_drawings_toolbar/pmmap/china/all/34-hainan.npy": "a67e27cc4f68d566f6977580d95b006c", "packages/advanced_drawings_toolbar/pmmap/china/all/39-jiuduan.npy": "35fbdcbb72d2c22caab9b1bfd2eba401", "packages/advanced_drawings_toolbar/pmmap/china/small/30-guangdong.npy": "7d7f1392cc01a22d4503354ce7c729b1", "packages/advanced_drawings_toolbar/pmmap/china/small/31-taiwan.npy": "2f398da02605db2be30751dedb92ea90", "packages/advanced_drawings_toolbar/pmmap/china/small/32-xianggang.npy": "b3cf9d637c7d87e82a86174f99be74da", "packages/advanced_drawings_toolbar/pmmap/china/small/33-aomen.npy": "68e3c682aef3e25cf873878a19df5361", "packages/advanced_drawings_toolbar/pmmap/china/small/34-hainan.npy": "a67e27cc4f68d566f6977580d95b006c", "packages/advanced_drawings_toolbar/pmmap/china/small/39-jiuduan.npy": "35fbdcbb72d2c22caab9b1bfd2eba401", "packages/advanced_drawings_toolbar/source/down.svg": "fe6b296aa4020dda5c5a870bb7596235", "packages/advanced_drawings_toolbar/source/plot.svg": "05fd271af6c134f6872c80c489064d60", "packages/advanced_drawings_toolbar/source/\u5730\u56fe.png": "eca50b3207a973738145d1cf12ca0c34", "packages/advanced_drawings_toolbar/source/\u6298\u7ebf\u56fe.png": "1bde0eca8cfa880452accf56ca925866", "packages/advanced_drawings_toolbar/source/\u6563\u70b9\u56fe.png": "78c432bb278d8ea5c9587f23ffdd5f82", "packages/advanced_drawings_toolbar/source/\u6761\u5f62\u56fe.png": "b07f4db5b1785376f97636fc6963234e", "packages/advanced_drawings_toolbar/source/\u67f1\u5f62\u56fe.png": "d6cba37e00bf9bbeb65235897a7b90b9", "packages/advanced_drawings_toolbar/source/\u6c14\u6ce1\u56fe.png": "d6784d4c53145cce1fde17f673b76984", "packages/advanced_drawings_toolbar/source/\u70ed\u529b\u56fe.png": "566d7c6ad396084ca6b7d490868fdc2c", "packages/advanced_drawings_toolbar/source/\u76f4\u65b9\u56fe.png": "a9b01bca53610b2c03f7ea2331c91cc3", "packages/advanced_drawings_toolbar/source/\u7bb1\u7ebf\u56fe.png": "ba733c4c1a0979ab5bc838149490e915", "packages/advanced_drawings_toolbar/source/\u7ec4\u5408\u56fe.png": "c5bea73cff095ad47bd07e1e81921ab2", "packages/advanced_drawings_toolbar/source/\u96f7\u8fbe\u56fe.png": "5aa1a48424b30a157a2bca181c9be2d0", "packages/advanced_drawings_toolbar/source/\u9762\u79ef\u56fe.png": "69682cc944d7afdd5c1f2019bf6ca21c", "packages/advanced_drawings_toolbar/source/\u997c\u56fe.png": "862b6c81a5752ee7d53500ce9064c10d", "packages/advanced_drawings_toolbar/translations/qt_zh_CN.qm": "cd23a7e488d169790b204929188d78e7", "packages/advanced_drawings_toolbar/translations/qt_zh_CN.ts": "ce76ad850f047e2cea0440e4dab7c7d4", "packages/applications_toolbar/applications_toolbar.py": "1c7db3beb99333a43fcbc29f2b628117", "packages/applications_toolbar/dev_tools.py": "32396eb367e2f40a2ca41bbf1c122380", "packages/applications_toolbar/ipyinterface.py": "b52686fd36bd819d65916f6c70a135e9", "packages/applications_toolbar/ipython_console.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/applications_toolbar/main.py": "1d6fa534839be7a73ed71881a9fb166e", "packages/applications_toolbar/manage_apps.py": "88d58bae208874c4973e22165f112675", "packages/applications_toolbar/package.json": "b6e6fae7a7650f3a94327d27f4fd4f9c", "packages/applications_toolbar/process_monitor.py": "86f69fb10c7ef7ba19504b418e8851f5", "packages/applications_toolbar/README.md": "500119ec92d71af8ac97e7246e30342e", "packages/applications_toolbar/settings_apps.json": "4182a1dc3f6489bca92a7eb123a85b6c", "packages/applications_toolbar/apps/cftool/algorithm.py": "253d3d8c4d7fcebe0018d65511e03ae9", "packages/applications_toolbar/apps/cftool/GUI_QT.py": "81a8a4dbbb41799c196129cb7b98247c", "packages/applications_toolbar/apps/cftool/main.py": "386bb5ebf2b5d8ad609ecd2be95bb607", "packages/applications_toolbar/apps/cftool/package.json": "ef90cc084c17151e6db5f1a4bb170897", "packages/applications_toolbar/apps/cftool/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/applications_toolbar/apps/cftool/README.md": "82a32691c1f8296f6fe73faebc1ddf89", "packages/applications_toolbar/apps/cftool/regexvalidifyer.py": "f7b28de6b75b89f19078a3e2e10d9818", "packages/applications_toolbar/apps/cftool/test1.py": "d8b7b73613a84a9044721403a1e8042a", "packages/applications_toolbar/apps/cftool/test_file.py": "dc6b5c9b40404d62209e36daf7b4819e", "packages/applications_toolbar/apps/cftool/src/cftool.png": "04975fa7979a56ac4dabea313cc7c004", "packages/applications_toolbar/apps/cftool/src/\u66f2\u7ebf\u62df\u5408.png": "d7ccf65e6d59dfd63507f1432454a943", "packages/applications_toolbar/apps/demo_app/default.png": "b58b2daf9a2a44726b678f235aed41e6", "packages/applications_toolbar/apps/demo_app/demo_app.py": "931bb2658ec5554a4f1cbb7424736f5a", "packages/applications_toolbar/apps/demo_app/main.py": "63ffc303fd56ba7d882fe108cd44efeb", "packages/applications_toolbar/apps/demo_app/package.json": "24bd9031b9afde16470332c19333c0bb", "packages/applications_toolbar/apps/demo_app/README.md": "ddb8b30770b3972dee69051c99026d1f", "packages/applications_toolbar/apps/demo_app/settings.json": "e4385e0a6554dfe40b3696f328f5edd1", "packages/applications_toolbar/apps/flowchart/flowchart.png": "e419f05974065c85c4c7b56604ce920a", "packages/applications_toolbar/apps/flowchart/main.py": "3288fef7caa83b16745351634f1c5e13", "packages/applications_toolbar/apps/flowchart/package.json": "bfe315ff8f31d2c4699a560608a5b973", "packages/applications_toolbar/apps/flowchart/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/applications_toolbar/apps/flowchart/README.md": "9b53d15d3e33ddba31de6b5f4e684c1b", "packages/applications_toolbar/apps/flowchart/examples/drop_duplicated.pmfc": "be5c44289f838b15d93c1b227b657091", "packages/applications_toolbar/apps/flowchart/examples/read_all_csv_files.pmfc": "4b1e9884b118c9dfa1e855f55178fad5", "packages/applications_toolbar/apps/flowchart/plugin_nodes/nodes.py": "92702a3afc444e8ce17b53314722eff6", "packages/applications_toolbar/apps/flowchart/plugin_nodes/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/applications_toolbar/apps/flowchart/resources/flowchartwindow.jpg": "d91093a77c5746982f7575081674e05b", "packages/applications_toolbar/apps/flowchart/resources/nodeports.jpg": "fddd899d2618662bb2b61d7e09680ad2", "packages/applications_toolbar/apps/flowchart/test_files/test_drop_duplicated.csv": "0574869eff0b86a260260b72cf53bb4a", "packages/applications_toolbar/apps/ligralpy/chart_server.py": "b3dc9a23925b30a73ac974f7a8123689", "packages/applications_toolbar/apps/ligralpy/Data.csv": "5fdba74629c5a0b1a5a6be20a3a19688", "packages/applications_toolbar/apps/ligralpy/flowchart.png": "e419f05974065c85c4c7b56604ce920a", "packages/applications_toolbar/apps/ligralpy/img.png": "8408ad879fe242ed82c30adbc3694d46", "packages/applications_toolbar/apps/ligralpy/main.py": "59a370745781b14b673f52ef392a5108", "packages/applications_toolbar/apps/ligralpy/package.json": "9e7eeab6e86f652142ae125bec65e71d", "packages/applications_toolbar/apps/ligralpy/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/applications_toolbar/apps/ligralpy/README.md": "9b53d15d3e33ddba31de6b5f4e684c1b", "packages/applications_toolbar/apps/ligralpy/examples/flowchart_stat_demo.json": "2d91e5c4fff5494f14dbb88a8b5f5031", "packages/applications_toolbar/apps/ligralpy/examples/second_ordered.lig.json": "86a67bc8b6402059ff6f15ef83722705", "packages/applications_toolbar/apps/ligralpy/nodes/nodes.py": "a08108573e2ace0e04dc0551da7653a6", "packages/applications_toolbar/apps/ligralpy/nodes/simulation.py": "043e5c86cf3c147d23cda2a2cf589395", "packages/applications_toolbar/apps/ligralpy/nodes/__init__.py": "06133052eded73b0d4be7b4719d5a3fc", "packages/applications_toolbar/apps/ligralpy/nodes/tools/gen_classes.py": "976b6416996c3bd2ce0c811b68175d60", "packages/applications_toolbar/apps/ligralpy/resources/flowchartwindow.jpg": "d91093a77c5746982f7575081674e05b", "packages/applications_toolbar/apps/ligralpy/resources/nodeports.jpg": "fddd899d2618662bb2b61d7e09680ad2", "packages/applications_toolbar/source/appstore.svg": "e2a48d1643f244e957ce9dba9e55a72f", "packages/applications_toolbar/source/app_main.py": "d8797ef1c2c1506b14b24a3602d4f929", "packages/applications_toolbar/source/background.png": "2a3f6737ddbb2a0314cdf2f640b0e929", "packages/applications_toolbar/source/default.png": "b58b2daf9a2a44726b678f235aed41e6", "packages/applications_toolbar/source/down.svg": "fe6b296aa4020dda5c5a870bb7596235", "packages/applications_toolbar/source/install.svg": "699200cfd59967ff740f1e3076795f0f", "packages/applications_toolbar/source/lightening.png": "844cc073cae34c193f3f39335146c955", "packages/applications_toolbar/source/main.py": "f7c06af5e03add541ee260a6224af05a", "packages/applications_toolbar/source/package.svg": "db8542fb863117d5d74f7a6676ab419e", "packages/applications_toolbar/source/qt-logo.png": "9a2446007bbc869ee1ef00479fc73872", "packages/applications_toolbar/source/run.png": "fcf7e23f264801b79df841dabdab9417", "packages/applications_toolbar/source/run.py": "931bb2658ec5554a4f1cbb7424736f5a", "packages/applications_toolbar/source/settings.png": "b9f8edfca0a36df8f3d445f61683511d", "packages/applications_toolbar/translations/qt_zh_CN.qm": "e613b5296764ff24e04450243de3e383", "packages/applications_toolbar/translations/qt_zh_CN.ts": "242fdca10f7405da10eae48f2244e13f", "packages/applications_toolbar/ui/app_designer.py": "b90e5fb6a0430ceb7bb74533ca4d198a", "packages/applications_toolbar/ui/app_designer.ui": "363e995f6861e7817a27e577d236233c", "packages/code_editor/debugger.py": "a19f564dddb9df36cfd14779dfea943c", "packages/code_editor/main.py": "0b3fc0dfb3c49a9dbe74a02f881b36a7", "packages/code_editor/package.json": "f529dee72a413f5d0d92b62ffeaad59b", "packages/code_editor/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/code_editor/README.md": "2918b5e59be436e278047961adb8afeb", "packages/code_editor/toolbar.py": "26ea5eb990d08893ee848dd86768aaba", "packages/code_editor/codeeditor/abstracteditor.py": "b1556e7c0b64c122e8dc6b295b9d9cc9", "packages/code_editor/codeeditor/autocomplete.py": "85443f0a05636004d73019442ca2d628", "packages/code_editor/codeeditor/flake8_trans.json": "745c056024e394cd874a60a0569de1b3", "packages/code_editor/codeeditor/infer.py": "7a9c311fd78ce3afe093bced75ff8fb0", "packages/code_editor/codeeditor/markdowneditor.py": "710b73d04dbf40dbda4c8a9516f1cdb9", "packages/code_editor/codeeditor/pythoneditor.py": "6eb09191f31b0d9a3752e13e3cef6098", "packages/code_editor/codeeditor/syntaxana.py": "b41485288a49c5e9dff3babfdbaa3a3b", "packages/code_editor/codeeditor/tabwidget.py": "e8c6177923b12a377116f65e2045fac3", "packages/code_editor/codeeditor/__init__.py": "de948222f3aba39724a6583a7c1d818f", "packages/code_editor/codeeditor/config/.flake8": "5706c8ed878411a63a6dd9827224e010", "packages/code_editor/codeeditor/config/.style.yapf": "0d898fa79efa8db79c72c151658d26aa", "packages/code_editor/codeeditor/config/.style.yapf.zh": "3f98dd47e54c916665839ab5fe9c5b8c", "packages/code_editor/codeeditor/errors_translation/translate.py": "750d35adf1c925d4e54c5afc6bd4471b", "packages/code_editor/codeeditor/errors_translation/translations.txt": "ec6b11469cf13cc49f53f144a3048952", "packages/code_editor/codeeditor/qtpyeditor/find_gotoline.py": "98a1a7fd1e0b447a55ce0941984ef809", "packages/code_editor/codeeditor/qtpyeditor/linenumber.py": "0dbc3249db663a0d338ec4630a8b857a", "packages/code_editor/codeeditor/qtpyeditor/syntaxana.py": "ccfed05306fc8e31513e4138fc6cb197", "packages/code_editor/codeeditor/qtpyeditor/__init__.py": "750c4f8fd3d0708b965ba5b6349201df", "packages/code_editor/codeeditor/qtpyeditor/codeedit/basecodeedit.py": "1f47f04069d87c1e49eadcac64e0c546", "packages/code_editor/codeeditor/qtpyeditor/codeedit/pythonedit.py": "1bd34b84907bd2cb9602b28ff87aae23", "packages/code_editor/codeeditor/qtpyeditor/codeedit/__init__.py": "49be4addcaeff7654aa0d9770649c359", "packages/code_editor/codeeditor/qtpyeditor/codeeditor/abstracteditor.py": "ae34418002a69d7872496eb5007842c0", "packages/code_editor/codeeditor/qtpyeditor/codeeditor/baseeditor.py": "81adc6aff2de98db56eb88c22fbea69f", "packages/code_editor/codeeditor/qtpyeditor/codeeditor/pythoneditor.py": "5458fc8ab2d05929fa3a9b6790125554", "packages/code_editor/codeeditor/qtpyeditor/codeeditor/__init__.py": "2d1f567a03ae3b14864c5807c2ecfd90", "packages/code_editor/codeeditor/qtpyeditor/highlighters/python.py": "30f29dea3c0261d114038d049dcb8b9b", "packages/code_editor/codeeditor/qtpyeditor/highlighters/__init__.py": "274aab5f8155ea49df8cc33689fe427a", "packages/code_editor/codeeditor/qtpyeditor/icons/breakpoint.svg": "5225dadbedc9f7bda4bb94fecc75ad53", "packages/code_editor/codeeditor/qtpyeditor/icons/copy.svg": "1c800d6346207003b4d7dc70a11e433f", "packages/code_editor/codeeditor/qtpyeditor/icons/debug.svg": "b931caeb19e4cc175cec44fd8af719f5", "packages/code_editor/codeeditor/qtpyeditor/icons/format.svg": "dccd4600d9450bfe4deb9b244c41e85f", "packages/code_editor/codeeditor/qtpyeditor/icons/help.svg": "edfdb212fdcae3ece7e7c58950a35645", "packages/code_editor/codeeditor/qtpyeditor/icons/python.svg": "d17b75c2256afc9b2beb64afeafbc3e0", "packages/code_editor/codeeditor/qtpyeditor/icons/run.svg": "e00087c6bd323d47d4f70a32a25b5667", "packages/code_editor/codeeditor/qtpyeditor/icons/save.svg": "750627b83e976365fb2d80529cb84a2d", "packages/code_editor/codeeditor/qtpyeditor/icons/spate.svg": "13ab9e2e9d07edf5f7c9cd73560141a7", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/class.png": "c64837c614c385630f360831492d8eb9", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/function.png": "7ee29ba9761700d9c9312f95ab6c799e", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/instance.png": "7ccdeda9723de6cbf234c333abe1d244", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/keyword.png": "babe443bc1400af18df2d5a6cc11cec4", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/module.png": "86eaece57974e3d10eb6e175d650abf6", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/param.png": "74e736a865157eb31e015effb34df17b", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/path.png": "7e01e98822f89b5e7bb64c2ead585aa0", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/property.png": "3f6aebb5a4862a8adca6d82dc724ab5e", "packages/code_editor/codeeditor/qtpyeditor/icons/autocomp/statement.png": "d16ab05b46ff0f6ed3b6421a2a66dab0", "packages/code_editor/codeeditor/qtpyeditor/translations/qt_zh_CN.qm": "2c896338c3b1b75508a842cf534d7cbf", "packages/code_editor/codeeditor/qtpyeditor/translations/qt_zh_CN.ts": "5382de30cc1e09a23252d66ca93b27db", "packages/code_editor/codeeditor/qtpyeditor/ui/findinpath.py": "14fa54fbcf8cb34804f6ef075c4267e6", "packages/code_editor/codeeditor/qtpyeditor/ui/formeditor.py": "1da95795442e26ab7bb522dc811aae50", "packages/code_editor/codeeditor/qtpyeditor/ui/gotoline.py": "609b6fb7d45a04b898878cab26938277", "packages/code_editor/codeeditor/qtpyeditor/ui/ui_formeditor.py": "2d559bafc1b0d8819e62eea2f875de8d", "packages/code_editor/codeeditor/qtpyeditor/ui/ui_gotoline.py": "1827eee50b32b313d397027c46dc020b", "packages/code_editor/codeeditor/qtpyeditor/ui/__init__.py": "de948222f3aba39724a6583a7c1d818f", "packages/code_editor/codeeditor/qtpyeditor/Utilities/autocomp.py": "7adde398458535177d586db7da6eb151", "packages/code_editor/codeeditor/qtpyeditor/Utilities/__init__.py": "d7a23951afba6034e252ea600119c242", "packages/code_editor/codeeditor/simpleeditor/lexer": "d41d8cd98f00b204e9800998ecf8427e", "packages/code_editor/codeeditor/simpleeditor/__init__.py": "fbc8e0505acbb7662554aa0ebf010dd8", "packages/code_editor/codeeditor/tests/get_flake8_output.py": "d6a5545ac0b49483aed41b5059276d1e", "packages/code_editor/codeeditor/tests/get_yapf_output.py": "f6a13da53a21f87d7f5d9fbd0e9a22fa", "packages/code_editor/codeeditor/tests/test_file.py": "4ed78c29dfa08ff34bff564bd39545c4", "packages/code_editor/codeeditor/tests/theme_xml_json.py": "86f8b53c91b4d974acafc78c7a9e399c", "packages/code_editor/codeeditor/themes/Material-Dark.xml": "32f09404512dea8a892ef0095e659ae3", "packages/code_editor/codeeditor/themes/Obsidian PyCs.xml": "934cfd0236acebfaa37bc76516e4cc12", "packages/code_editor/codeeditor/themes/tomorrow.xml": "4f226a7b073ea417d6eca69bdf0e999a", "packages/code_editor/codeeditor/themes/tomorrow_night.xml": "5b7770abad7ab117727e91351140724f", "packages/code_editor/codeeditor/themes/tomorrow_night_bright.xml": "ba3f13a083f3b0aa8f8332e90b4fbb86", "packages/code_editor/codeeditor/tools/eric6_api.py": "72d2e6ee453be1f17e6c0382eb99d344", "packages/code_editor/codeeditor/tools/__init__.py": "9aa13d467aa7ca6ca94b283dea7e5c22", "packages/code_editor/codeeditor/tools/DocumentationTools/APIGenerator.py": "a725a1b2ffcbc8fc98f9e69b252f73ae", "packages/code_editor/codeeditor/tools/DocumentationTools/__init__.py": "f5dba5378fa551d11f098318de65a4a1", "packages/code_editor/codeeditor/tools/QScintilla/Editor.py": "3e5f9b7d8c00734ed27c85bd1de63906", "packages/code_editor/codeeditor/tools/QScintilla/__init__.py": "e58d1155053d6b3763c2ed9f92ca9e57", "packages/code_editor/codeeditor/tools/Utilities/ModuleParser.py": "be326e07e15841196ec7d752417cc6e2", "packages/code_editor/codeeditor/tools/Utilities/__init__.py": "65ffafe4bc9cd6a17832f441036cdb63", "packages/code_editor/codeeditor/ui/formeditor.py": "1da95795442e26ab7bb522dc811aae50", "packages/code_editor/codeeditor/ui/gotoline.py": "2ea843566488cd151da2f6cab335625f", "packages/code_editor/icons/breakpoint.svg": "5225dadbedc9f7bda4bb94fecc75ad53", "packages/code_editor/icons/copy.svg": "1c800d6346207003b4d7dc70a11e433f", "packages/code_editor/icons/debug.svg": "b931caeb19e4cc175cec44fd8af719f5", "packages/code_editor/icons/format.svg": "dccd4600d9450bfe4deb9b244c41e85f", "packages/code_editor/icons/help.svg": "edfdb212fdcae3ece7e7c58950a35645", "packages/code_editor/icons/python.svg": "d17b75c2256afc9b2beb64afeafbc3e0", "packages/code_editor/icons/run.svg": "e00087c6bd323d47d4f70a32a25b5667", "packages/code_editor/icons/save.svg": "750627b83e976365fb2d80529cb84a2d", "packages/code_editor/icons/spate.svg": "13ab9e2e9d07edf5f7c9cd73560141a7", "packages/code_editor/source/lightening.png": "844cc073cae34c193f3f39335146c955", "packages/code_editor/translations/qt_zh_CN.qm": "8e43fef9f53d43e8b693fc52984742d6", "packages/code_editor/translations/qt_zh_CN.ts": "20d10e3f79c729e1c90cbc88858cfd36", "packages/dataio/accountutil.py": "98a4758a6a1b11f7ee17f08e8b6c03d8", "packages/dataio/database_sample.py": "40b1c25397f6ddea9fb38029ee97eaea", "packages/dataio/dataImportModel.py": "88792dc540a80f0a5b22a7de6f3f1b12", "packages/dataio/dbimport.py": "6e4e64e8277a17c0fd21748ee7612b9a", "packages/dataio/dbindexing.py": "8d8d88e3a62cd935519aa4716218fac9", "packages/dataio/export.py": "ba01392157f6058a0d3a2a6f65a82b46", "packages/dataio/exportutils.py": "71a15223db0b6f6ef4bbe7e5ad31a4b6", "packages/dataio/importutils.py": "138d86b798b92d45639791ef57285981", "packages/dataio/main.py": "194549d322dbcea58329cff2cd5d7104", "packages/dataio/package.json": "a857dcfa80f7bbe16b29d447684fede6", "packages/dataio/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/dataio/README.md": "2918b5e59be436e278047961adb8afeb", "packages/dataio/sample.py": "346de2707ffbf2cd036b19b6911be5ff", "packages/dataio/settings.json": "d41d8cd98f00b204e9800998ecf8427e", "packages/dataio/dataUI/data_import_csv.py": "6b0ffb99fdb1d3bc68a61ca6a9169063", "packages/dataio/dataUI/data_import_csv.ui": "47c21370141a61960861b65836e7287b", "packages/dataio/dataUI/data_import_excel.py": "17b37971c44f89cdc5cef09c4ae742ef", "packages/dataio/dataUI/data_import_excel.ui": "2038dabc9e1caea8e1328b64fb10dc89", "packages/dataio/dataUI/data_import_matlab.py": "eccad7dc8726499702e75adcb6eb64d4", "packages/dataio/dataUI/data_import_matlab.ui": "4ae19c223a9d60139a73f2b1c553c64a", "packages/dataio/dataUI/data_import_model.py": "6732462f2b28d1228e6b6429d8f820cb", "packages/dataio/dataUI/data_import_model.ui": "6c61ace6854928adfb4c6ea8eff19fb5", "packages/dataio/dataUI/data_import_mysql.py": "10024040b895e1f7a0761cf41ed569aa", "packages/dataio/dataUI/data_import_mysql.ui": "bab2eaf2057d9175638198f14fb5f599", "packages/dataio/dataUI/data_import_oracle.py": "8068996f5d6395e95e878c341273ceb2", "packages/dataio/dataUI/data_import_oracle.ui": "c7d90bb98b8d4c0d5401eca7bcabe7ec", "packages/dataio/dataUI/data_import_postgresql.py": "c5404dc63e987cd2ed07d2b2424d5dac", "packages/dataio/dataUI/data_import_postgresql.ui": "b9a515989b036b7466bc2edd325b6eb1", "packages/dataio/dataUI/data_import_sas.py": "428fd62424d9e21c3d5bdc67ad2474a2", "packages/dataio/dataUI/data_import_sas.ui": "1f8667b3667d2baba53533b938b1a6a9", "packages/dataio/dataUI/data_import_spss.py": "8a1154c9315758ad9fa8bc96bfa1a367", "packages/dataio/dataUI/data_import_spss.ui": "35e2eb820c7e69bef4f06bbce6344c19", "packages/dataio/dataUI/data_import_stata.py": "102a879258cfbb70afc5815684e53b93", "packages/dataio/dataUI/data_import_stata.ui": "fd01ec0806b50f0dbbe7df3ae5578bcb", "packages/dataio/dataUI/data_import_text.py": "347f0183bb4055c43993f5ed84ae3d6c", "packages/dataio/dataUI/data_import_text.ui": "c8cc49a3ee1b2c4209c5c9ffe92fcfd8", "packages/dataio/dataUI/display.png": "38a696b77d8e89b1f24e3077184f3588", "packages/dataio/dataUI/hide.png": "80009586668a32b1a0bcdc5fb1854ac4", "packages/dataio/dataUI/password.py": "c174715c922460e682382cc1a4c9076f", "packages/dataio/dataUI/__init__.py": "cddad8a43ae85331e7fc60b6c4783a14", "packages/document_server/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/document_server/index.rst": "de08e1d943a610a1d4b61de487fc9606", "packages/document_server/main.py": "8e52c195bd0de7649b208fe9431fac90", "packages/document_server/package.json": "d552267ae466f74d360aa2dde9707999", "packages/document_server/settings.json": "ac084b924952c4c88e397f5c1f64c893", "packages/document_server/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/document_server/docserver/renderer.py": "0d2b8fa90287c98d2b2ea47893d902fd", "packages/document_server/docserver/server.py": "b525026a556b339079d30c4294e7fd60", "packages/document_server/docserver/__init__.py": "f64b6b6963038b02a0fafec97cb826da", "packages/document_server/docserver/static/css/main.css": "514ba05b769e4a20a328f77267aeb3a0", "packages/document_server/docserver/static/css/main.css.map": "db360aa1e642da89de3240fed50e4432", "packages/document_server/docserver/static/css/main.sass": "7b0d06ed553c19887a7dcad5bb97e954", "packages/document_server/docserver/static/js/main.js": "52a8a678ac589478f5b97e88066109c6", "packages/document_server/docserver/static/mathjax/tex-mml-svg.js": "2ac6956d3f16edb119f3b5686ef933d5", "packages/document_server/docserver/templates/content.html": "7420679eb81eea0ca7b9e98972b49160", "packages/document_server/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/document_server/translations/zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/drawings_toolbar/group_chart.py": "846a72c9e0303f8ef4b5c6b809f07db7", "packages/drawings_toolbar/ipython_console.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/drawings_toolbar/main.py": "6d8e3f8e511fa3ec1186e59c68487b69", "packages/drawings_toolbar/map_var.json": "91324fe1e6b292ebc2d548f3ae7d49b7", "packages/drawings_toolbar/map_var.py": "46e4e76e96cb5691754e4b63a38b67d9", "packages/drawings_toolbar/package.json": "95e01099cdd1f73595c179112383e45a", "packages/drawings_toolbar/radar_chart.py": "67ea13759ea77d67006df488c9fde4e0", "packages/drawings_toolbar/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/drawings_toolbar/fastui/base.py": "5aabafefad5433391c67bf5f5749141f", "packages/drawings_toolbar/fastui/draw_boxplot.py": "54cc901679b29dc27fbaa8c12a458daf", "packages/drawings_toolbar/fastui/draw_hist.py": "97f5fd773217c53c26c9d44c6905f8cf", "packages/drawings_toolbar/fastui/functions.py": "2756f0633851f7605644c78de2f9e7b6", "packages/drawings_toolbar/fastui/plot.py": "c52ba2a8e3dc27b6397480b316f3f745", "packages/drawings_toolbar/fastui/__init__.py": "b3f689f89235e0fd970023fb1910ebaa", "packages/drawings_toolbar/fastui/helps/boxplot.md": "c28b070128b33660fd657c82d7bd2d54", "packages/drawings_toolbar/fastui/helps/markers.md": "35a158b4cb160219a0d5f4c89025f50c", "packages/drawings_toolbar/fastui/helps/plot.md": "9a819ab6bdf462d779ff742d77e49526", "packages/drawings_toolbar/pmmap/china/all/01-beijing.npy": "05fc6e35605340ef6e4d62af9770ef7a", "packages/drawings_toolbar/pmmap/china/all/02-shanghai.npy": "dbd37714da88edf44df7a2642ce2c14f", "packages/drawings_toolbar/pmmap/china/all/03-tianjin.npy": "e767b1d0810acfd174d4b52586441de1", "packages/drawings_toolbar/pmmap/china/all/04-chongqing.npy": "1980444de2496af7ae7b11cae9372d2c", "packages/drawings_toolbar/pmmap/china/all/05-heilongjiang.npy": "f369a349db31ac0636e625737802922e", "packages/drawings_toolbar/pmmap/china/all/06-neimeng.npy": "0366d9f95bfe2e0768a6491f8f5e27cc", "packages/drawings_toolbar/pmmap/china/all/07-xinjiang.npy": "201b3ff97375ae9ba6e9fc9c7b0eed1e", "packages/drawings_toolbar/pmmap/china/all/08-jilin.npy": "0ed85b6d84b877cf07154e1b54db0bdd", "packages/drawings_toolbar/pmmap/china/all/09-gansu.npy": "08c6e4437a0fc5d19d6c655a14a7df2e", "packages/drawings_toolbar/pmmap/china/all/10-liaoning.npy": "542d598f5c39b363738b0b753d8318d1", "packages/drawings_toolbar/pmmap/china/all/11-hebei.npy": "5a7ce525859caabaffad0fe1c11cb26f", "packages/drawings_toolbar/pmmap/china/all/12-shanxi.npy": "5ebb5347431393d599f5f0d36a31dd07", "packages/drawings_toolbar/pmmap/china/all/13-shan3xi.npy": "71944b8eea6caa0b7e4138063d6e8945", "packages/drawings_toolbar/pmmap/china/all/14-ningxia.npy": "dc0660ac4216cb4e928fb08dba5e36fb", "packages/drawings_toolbar/pmmap/china/all/15-qinghai.npy": "46f4e9bf9a47734d0cfbef0916e6cec1", "packages/drawings_toolbar/pmmap/china/all/16-shandong.npy": "b3eee97751e252f1c729b20cde81220c", "packages/drawings_toolbar/pmmap/china/all/17-henan.npy": "530d73e54901bf816e61c86bafb97219", "packages/drawings_toolbar/pmmap/china/all/18-xizang.npy": "83c873032100d735d2a3c1becb4e4ee5", "packages/drawings_toolbar/pmmap/china/all/19-jiangsu.npy": "33051765300de0a9d003ea91c3846cc6", "packages/drawings_toolbar/pmmap/china/all/20-anhui.npy": "d80f40e27c3a60188547d058c827eae0", "packages/drawings_toolbar/pmmap/china/all/21-sichuan.npy": "115e4b1abbc6df1f862095e94cacb8b5", "packages/drawings_toolbar/pmmap/china/all/22-hubei.npy": "065b61ce8a2728be70d0e726990e42c2", "packages/drawings_toolbar/pmmap/china/all/23-zhejiang.npy": "6910df476893b4e5a84689094203b724", "packages/drawings_toolbar/pmmap/china/all/24-jiangxi.npy": "2d4e166cd8d9371a1c6d01848ece3301", "packages/drawings_toolbar/pmmap/china/all/25-hunan.npy": "ddbce0334a1f79bd77f7b0ae582dd28e", "packages/drawings_toolbar/pmmap/china/all/26-guizhou.npy": "4d23f4f330203b61c6f8cca0ac764819", "packages/drawings_toolbar/pmmap/china/all/27-yunnan.npy": "1d1c9378c8427667dbf0b8948c36b484", "packages/drawings_toolbar/pmmap/china/all/28-fujian.npy": "77270ff92f0d67f0123672527b70772a", "packages/drawings_toolbar/pmmap/china/all/29-guangxi.npy": "3862d0becc054fe754ae71c111c583ad", "packages/drawings_toolbar/pmmap/china/all/30-guangdong.npy": "7d7f1392cc01a22d4503354ce7c729b1", "packages/drawings_toolbar/pmmap/china/all/31-taiwan.npy": "2f398da02605db2be30751dedb92ea90", "packages/drawings_toolbar/pmmap/china/all/32-xianggang.npy": "b3cf9d637c7d87e82a86174f99be74da", "packages/drawings_toolbar/pmmap/china/all/33-aomen.npy": "68e3c682aef3e25cf873878a19df5361", "packages/drawings_toolbar/pmmap/china/all/34-hainan.npy": "a67e27cc4f68d566f6977580d95b006c", "packages/drawings_toolbar/pmmap/china/all/39-jiuduan.npy": "35fbdcbb72d2c22caab9b1bfd2eba401", "packages/drawings_toolbar/pmmap/china/small/30-guangdong.npy": "7d7f1392cc01a22d4503354ce7c729b1", "packages/drawings_toolbar/pmmap/china/small/31-taiwan.npy": "2f398da02605db2be30751dedb92ea90", "packages/drawings_toolbar/pmmap/china/small/32-xianggang.npy": "b3cf9d637c7d87e82a86174f99be74da", "packages/drawings_toolbar/pmmap/china/small/33-aomen.npy": "68e3c682aef3e25cf873878a19df5361", "packages/drawings_toolbar/pmmap/china/small/34-hainan.npy": "a67e27cc4f68d566f6977580d95b006c", "packages/drawings_toolbar/pmmap/china/small/39-jiuduan.npy": "35fbdcbb72d2c22caab9b1bfd2eba401", "packages/drawings_toolbar/source/down.svg": "fe6b296aa4020dda5c5a870bb7596235", "packages/drawings_toolbar/source/erase.png": "68beac11764738b4fd52d367e5ad8223", "packages/drawings_toolbar/source/grid.png": "a39688f7d385bf86ba28eaf9d63a286d", "packages/drawings_toolbar/source/label.png": "2289b06fad4b39ea868450cdfbdc5eea", "packages/drawings_toolbar/source/monitor.png": "7272e1f62681d4200a2d778ec3df27e5", "packages/drawings_toolbar/source/plot.svg": "05fd271af6c134f6872c80c489064d60", "packages/drawings_toolbar/source/split.png": "d3cdd812358fd82f19500d8ac1bbc3be", "packages/drawings_toolbar/source/ticks.png": "2165ab858f8de60f5132e861740f7699", "packages/drawings_toolbar/source/\u5730\u56fe.png": "eca50b3207a973738145d1cf12ca0c34", "packages/drawings_toolbar/source/\u6298\u7ebf\u56fe.png": "1bde0eca8cfa880452accf56ca925866", "packages/drawings_toolbar/source/\u6563\u70b9\u56fe.png": "78c432bb278d8ea5c9587f23ffdd5f82", "packages/drawings_toolbar/source/\u6761\u5f62\u56fe.png": "b07f4db5b1785376f97636fc6963234e", "packages/drawings_toolbar/source/\u67f1\u5f62\u56fe.png": "d6cba37e00bf9bbeb65235897a7b90b9", "packages/drawings_toolbar/source/\u6c14\u6ce1\u56fe.png": "d6784d4c53145cce1fde17f673b76984", "packages/drawings_toolbar/source/\u70ed\u529b\u56fe.png": "566d7c6ad396084ca6b7d490868fdc2c", "packages/drawings_toolbar/source/\u76f4\u65b9\u56fe.png": "87113fa7353e0342248a7c953949079e", "packages/drawings_toolbar/source/\u7bb1\u7ebf\u56fe.png": "ba733c4c1a0979ab5bc838149490e915", "packages/drawings_toolbar/source/\u7ec4\u5408\u56fe.png": "c5bea73cff095ad47bd07e1e81921ab2", "packages/drawings_toolbar/source/\u96f7\u8fbe\u56fe.png": "5aa1a48424b30a157a2bca181c9be2d0", "packages/drawings_toolbar/source/\u9762\u79ef\u56fe.png": "69682cc944d7afdd5c1f2019bf6ca21c", "packages/drawings_toolbar/source/\u997c\u56fe.png": "862b6c81a5752ee7d53500ce9064c10d", "packages/drawings_toolbar/translations/qt_zh_CN.qm": "cd23a7e488d169790b204929188d78e7", "packages/drawings_toolbar/translations/qt_zh_CN.ts": "ce76ad850f047e2cea0440e4dab7c7d4", "packages/embedded_browser/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/embedded_browser/index.rst": "f1825ba1705fc05e593342e0eb4d2800", "packages/embedded_browser/main.py": "23ad2b340856b4ee181f560c6234655c", "packages/embedded_browser/package.json": "662baeb4c74d3c20f8a4604a7a9922df", "packages/embedded_browser/settings.json": "ac084b924952c4c88e397f5c1f64c893", "packages/embedded_browser/webbrowser.py": "d9038ba9457b984e37a4ae1e19ab636a", "packages/embedded_browser/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/embedded_browser/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/embedded_browser/translations/zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/extension_demo/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/extension_demo/main.py": "b776c52a5c366b88629c1c12a0c4da57", "packages/extension_demo/package.json": "fe0c68ec838785d4f8ae971ce415f6db", "packages/extension_demo/settings.json": "ac084b924952c4c88e397f5c1f64c893", "packages/extension_demo/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/extension_demo/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/extension_demo/translations/zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/file_tree/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/file_tree/file_tree.py": "b65b3a68d28d55db5bfc3bfb1adecee2", "packages/file_tree/main.py": "210493015e96aecac98bba55bd57674b", "packages/file_tree/package.json": "0e08e253fce09755a4d9758cb55b3900", "packages/file_tree/settings.json": "5502d6d53ce7276a7cdaa1ef54315efb", "packages/file_tree/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/file_tree/src/up.svg": "cef12db3d43301347f3d556eb9499a6c", "packages/file_tree/translations/qt_zh_CN.qm": "76f4ace00b4ef9e66503cb39d5c9ab5d", "packages/file_tree/translations/qt_zh_CN.ts": "eefaa8ed0d5717aab5253c74ea7d6a3a", "packages/graph_agg/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/graph_agg/graph_agg.py": "7ebd645f566d7412c3af7de2865d2896", "packages/graph_agg/graph_agg_ui.py": "61edf67aebb1d89f92d604a8d22c1200", "packages/graph_agg/graph_agg_ui.ui": "45c54e740ed679ebcdc66594709eaf9f", "packages/graph_agg/main.py": "3399d8c6899a36a92b1910d55d05ea96", "packages/graph_agg/package.json": "b2bfcc74063422e491d0c3df279bbc38", "packages/graph_agg/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/ipython_console/commandparser.py": "8df507247c3112a5a164a961f8b154b5", "packages/ipython_console/index.rst": "de4df58d8cb7a27038ea01f08d3e74c9", "packages/ipython_console/initialize.py": "f75a73ebb2b6af4e198d47cb326ac8c6", "packages/ipython_console/ipythonqtconsole.py": "715c9c195c300400bd24375a2c0f2cac", "packages/ipython_console/ipython_console.jpg": "e2c98aceacdcf9370be0234c1ae56660", "packages/ipython_console/main.py": "764879652c234804c28091c167e8506f", "packages/ipython_console/package.json": "330d1b64fd0fa236f68e4e9148d7f2ff", "packages/ipython_console/README.md": "d91f325d8113d754239f36ebf6211e2d", "packages/ipython_console/requirements_ipython_node.txt": "7e2992fb7c705a5cc8a817af37b0b890", "packages/ipython_console/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/ipython_console/translations/qt_zh_CN.qm": "d32941bf701e20d30c70b509e3421f26", "packages/ipython_console/translations/qt_zh_CN.ts": "ae95465c0df4254a53d4144fd5a90148", "packages/jupyter_notebook_support/client.py": "64707c4c5af928668dfe5624020ab381", "packages/jupyter_notebook_support/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/jupyter_notebook_support/ipython_data_show.py": "ba5fafcca30e9db07a1330fb143b539d", "packages/jupyter_notebook_support/main.py": "1961046decf8e842648695f64f4a951a", "packages/jupyter_notebook_support/package.json": "8f1bbf103ab237adf5e932d77304bab6", "packages/jupyter_notebook_support/route.py": "d63fb2946b16cecd4c03b63b96b417fa", "packages/jupyter_notebook_support/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/jupyter_notebook_support/scripts/pyminer_ipython_node.py": "5afb85f04995a313be86875d55896b8f", "packages/jupyter_notebook_support/tests/exec_api_test.py": "db3498a3620bc730a093106024c3d895", "packages/jupyter_notebook_support/tests/find_free_port.py": "7519a17439dd072a5f5609dccf71acff", "packages/jupyter_notebook_support/tests/find_kernel_spec.py": "5e494c2592bc747a166f3e5eb1fdb0d2", "packages/jupyter_notebook_support/tests/jupyter_client_test.py": "cd2193f167111e6f74a51ce27671b6e0", "packages/jupyter_notebook_support/tests/list_running_jupyter_servers.py": "decfc524233da897d5ae4e0896ad42bf", "packages/jupyter_notebook_support/tests/test.json": "fd0693bed89aa001426c855cf60719da", "packages/jupyter_notebook_support/tests/Untitled.ipynb": "0eca040919ec50b82d4197e13564f3f8", "packages/jupyter_notebook_support/tests/.ipynb_checkpoints/Untitled-checkpoint.ipynb": "2f6cceae1d861df553a6ebb64b6862ef", "packages/jupyter_notebook_support/translations/qt_zh_CN.qm": "910b1a4eece778fe19eb8c37d856219b", "packages/jupyter_notebook_support/translations/qt_zh_CN.ts": "a52f5f65e0ebc5ef1c4c205d8b977e5b", "packages/pmagg/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/pmagg/LICENSE": "e49f4652534af377a713df3d9dec60cb", "packages/pmagg/main.py": "26f2abd09259651ad17e35b24de5a097", "packages/pmagg/package.json": "3f5b1d4110de43c171ec51876448d516", "packages/pmagg/PMAgg.py": "51be8eab2ca29167621904193a7d94e0", "packages/pmagg/Readme_CN.md": "b120eff0eec50462b099a5afc44e8135", "packages/pmagg/setup.py": "c819982245570068aeff72f2c4925d3c", "packages/pmagg/unit_test.py": "6cc0c2b57eebac72cb159bdb73dae6dd", "packages/pmagg/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pmagg/icons/annotation.png": "41abc31827d980673cb4b774d9cfc589", "packages/pmagg/icons/arrow.png": "faea79dbbe13b73b2b6b2d381d3f0b04", "packages/pmagg/icons/axis.png": "8aad7c4a25caea1eab5e00416383fe87", "packages/pmagg/icons/back.png": "7e3a69ff1b93c0d922903ca9753d9413", "packages/pmagg/icons/colorbar.png": "51edcf418f2920bcc55e703956345d22", "packages/pmagg/icons/figure.png": "6c84c49ce26f638a352654df89ee3d35", "packages/pmagg/icons/front.png": "b3675ce85ff0c87602fcee821606b376", "packages/pmagg/icons/grid.png": "f495112a5ee666819bccc792ac9ab480", "packages/pmagg/icons/home.png": "e4a7f4019b4ea9cb1f375da78a2e5adf", "packages/pmagg/icons/Icon.ico": "3fe019a16833a4b89743e829706a22a6", "packages/pmagg/icons/image.png": "9a685d94a08e6dab95ab996ac36c3019", "packages/pmagg/icons/layout.png": "113fcb65d470b3c44eca07a69883b067", "packages/pmagg/icons/legend.png": "4554646775b8caab3af239051e231530", "packages/pmagg/icons/line.png": "0ad86f368735816bb25dae9a6037d042", "packages/pmagg/icons/oval.png": "bf5e995685d6bd1758ddc56db9a706c1", "packages/pmagg/icons/pan.png": "d31d48619f6187a992f8bc51f4bbbf31", "packages/pmagg/icons/point.png": "6ea950ae1d8f16fc9d364dea468e1bf6", "packages/pmagg/icons/polygon.png": "a7d892e0a3ca8e00aefc73211cc211aa", "packages/pmagg/icons/rect.png": "9088ab4129c08c3370675a27c5af7f76", "packages/pmagg/icons/rotate.png": "b058a0e469a679d752ea393eb8b94204", "packages/pmagg/icons/save.png": "1f019d1efc880a99aa0d6c413d4b1672", "packages/pmagg/icons/setting.png": "2ca8a4d585232a124bc8f8bbaf913eec", "packages/pmagg/icons/space.png": "a63438f63e5c9a61ae377f92e4638427", "packages/pmagg/icons/style.png": "5479b633bfd95b75aca566d283f90f2d", "packages/pmagg/icons/text.png": "2d058b7289a520eb1087ea7957e85a18", "packages/pmagg/icons/X_axis.png": "81b2fbfd328ea56e03bbac9d98f54bd0", "packages/pmagg/icons/Y_axis.png": "dec07bca2db81b7a13d05cf63147042c", "packages/pmagg/icons/zoom.png": "624d6036e5af3901a672926eed0cfd74", "packages/pmagg/icons/Z_axis.png": "4ef63246be7447c74de3fc6352f56782", "packages/pmagg/langs/en_axes_control.qm": "3e31bb846d2075752f2083796bbab081", "packages/pmagg/langs/en_axes_control.ts": "e3f2a95ffc1ee822600420487fc64497", "packages/pmagg/langs/en_pmagg_ui.qm": "0d72b1e6a3868f6a9d7f4353dc49da57", "packages/pmagg/langs/en_pmagg_ui.ts": "c40ed0942c1fc822cbfdac7d51728e15", "packages/pmagg/langs/zh_CN_axes_control.qm": "43c4b723bf698383102abf57ae7ff375", "packages/pmagg/langs/zh_CN_axes_control.ts": "b69e3a2583aab4d47e9042151ddd4431", "packages/pmagg/langs/zh_CN_pmagg_ui.qm": "bcebcf42735c6849bdecbb77451021dd", "packages/pmagg/langs/zh_CN_pmagg_ui.ts": "a924984618a9687fe9bed9cd1ab3e8bd", "packages/pmagg/pictures/pmagg_api.mmd": "3c46f4d87fb3706b4b1bd70b7e442a5d", "packages/pmagg/pictures/pmagg_api.png": "822f49430932514591eda54acfc10a1f", "packages/pmagg/pictures/pmagg_show.png": "5dc944f02aa22177c5c24ab1f71a391d", "packages/pmagg/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/pmagg/translations/zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/pmagg/ui/arrow_setting.py": "d8e8f2f7101729c6ced2cd4f4dd0ee6d", "packages/pmagg/ui/axes_control.py": "b232825bef4aa017e9bbf92b57640f49", "packages/pmagg/ui/axis_edit.py": "4875d36d29871c4d87c05108117d9f9f", "packages/pmagg/ui/axis_edit.ui": "f7b92a8a5d9b4ca769bf42ebdb34577a", "packages/pmagg/ui/axis_edit_manager.py": "e2245787fc389cb116ca56c37131addd", "packages/pmagg/ui/colorbar_setting.py": "46a557021eeeefe8c56bf5f9e26629cd", "packages/pmagg/ui/color_table.py": "e209c8c3d24f582978ca33100de623a5", "packages/pmagg/ui/default_setting.py": "5846b7322727ee4b19dc7b6c336d1947", "packages/pmagg/ui/default_setting.ui": "b93e791244d7912a51bbaf75a2deff38", "packages/pmagg/ui/default_setting_manager.py": "c06f05023a1bbd6eb754b0e68209fca6", "packages/pmagg/ui/ellipse_setting.py": "4d24440e44796ada3a73a387600899fc", "packages/pmagg/ui/image_setting.py": "6e909b7852eb02a52455a9aa36da7bed", "packages/pmagg/ui/legend_setting.py": "6e3a19772353cdf39944df1e4faa17dd", "packages/pmagg/ui/line2d_setting.py": "470ef26ff8d454e8247f37277d5a785a", "packages/pmagg/ui/linestyles.py": "648f0a673e71e4d08c98e0cc6864202e", "packages/pmagg/ui/pmagg_ui.py": "0ac0c186e7177a3a9c6aee2d9d409177", "packages/pmagg/ui/pmagg_ui.ui": "f1a0f6ff01e632a4994f00258356911f", "packages/pmagg/ui/rectangle_setting.py": "3080ff255cfe2378777f68025e61f2c4", "packages/pmagg/ui/save_image_setting.py": "16036a37904ffa3f20fecc7d004b009f", "packages/pmagg/ui/text_setting.py": "34de8bed7cf453d59fe938be0fbfe92c", "packages/pmagg/ui/title_setting.py": "ebdf8cbd5684278ec81c9cdde176b684", "packages/pmagg/ui/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pm_calc/ipython_console.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/pm_calc/main.py": "83b0f01515be0f4f76da807e9cb61125", "packages/pm_calc/package.json": "9fdd3a4c9b4a20d39944e5f390642e1e", "packages/pm_calc/preprocess.py": "a8c8d1cb131393e4bf0a6e43503f5c7b", "packages/pm_calc/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pm_calc/fastui/base.py": "76ac4b617688dfeb97d75c73803dcd44", "packages/pm_calc/fastui/create_random_variable.py": "fa6d77ce65a13e4974da9f5a33516d2a", "packages/pm_calc/fastui/create_tensor.py": "bde0d9952e2ab26e9fb5f47cf8fff98a", "packages/pm_calc/fastui/create_vector.py": "cb707dcfefc1f308d25c17d6a034cdfc", "packages/pm_calc/fastui/dblquad.py": "5e4c5b60231b67cbe5233de0b555f308", "packages/pm_calc/fastui/equation_solve.py": "6fdb3b720ad9547553938a3b735bf970", "packages/pm_calc/fastui/matrix_calc.py": "fc4dbc1ce3af2ae26125d1adb7f8f690", "packages/pm_calc/fastui/matrix_inv.py": "bd826082ba2b3c8775563da8c3ee6321", "packages/pm_calc/fastui/matrix_numbers.py": "b9bc2f888b2c98743072fc686e07751f", "packages/pm_calc/fastui/numerical_integration.py": "57edb1443625bdc5d990aa4d99f6272e", "packages/pm_calc/fastui/reshape_tensor.py": "0647e734b05f39cef659c82c315fb023", "packages/pm_calc/fastui/__init__.py": "b3f689f89235e0fd970023fb1910ebaa", "packages/pm_calc/fastui/helps/numerical_integration.md": "df25b4e7795b58e927c62368d814f0ab", "packages/pm_calc/fastui/helps/reshape_tensor.md": "96a600a163541231dc71d43438de0ab4", "packages/pm_calc/icons/create.png": "d94320bc7e7a4dded74f4eda5b6d1c3e", "packages/pm_calc/icons/eigen.png": "97048cae872a927137f5b7295828c5c2", "packages/pm_calc/icons/equation_solve.png": "af3de472d63ef0e8e6005c153d29ad0b", "packages/pm_calc/icons/flip.png": "e769eeaa1f423de72f34dda86f088540", "packages/pm_calc/icons/integrate.png": "0d3a7f301fa771ee8ef56b10541551d9", "packages/pm_calc/icons/matrix.png": "5b97eee2dae1233c831daae04c5dd98f", "packages/pm_calc/icons/matrix_calc.png": "151e56c9e82870f7cf9783971ee37782", "packages/pm_calc/icons/reshape.png": "3ee90fbdcf09e1bcf3f24e13be041530", "packages/pm_calc/icons/rvs.png": "da077db4d3d834bb311f445e6a9a07c7", "packages/pm_calc/translations/qt_zh_CN.qm": "38862557de320f2ff74455ab1c059a5a", "packages/pm_calc/translations/qt_zh_CN.ts": "c17e3ce1dd88a0cfc45d42cd1f706361", "packages/pm_helpLinkEngine/helpLinkEngine.py": "8e712a1e13bd4d0dd0a5f3cbb59212e0", "packages/pm_helpLinkEngine/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pm_marketplace/env_manager.py": "b3d1a95732a2b9c9af7ebb3f2d919f08", "packages/pm_marketplace/env_manager.ui": "c910e7c1fdb7d4931ae6395f32fdb06f", "packages/pm_marketplace/Icon.ico": "3fe019a16833a4b89743e829706a22a6", "packages/pm_marketplace/package_install.py": "3b2122f43e471ed12022254a633e93ea", "packages/pm_marketplace/package_install.ui": "58c036d918d493749750442a6dd6e56c", "packages/pm_marketplace/package_manager.py": "9bc3ebc8d0896b8c90661b5e3e0bab5b", "packages/pm_marketplace/package_remove.py": "2882477a6acf357e401983e64a9e5b3d", "packages/pm_marketplace/package_remove.ui": "cd82652c1c18ce309b7b39f64eb1eb93", "packages/pm_marketplace/package_setting.py": "0900c75df4d09edb2df07df0d40b3893", "packages/pm_marketplace/package_setting.ui": "7294066d39daafe32bfb6e14dc9bd4b2", "packages/pm_marketplace/package_update.py": "7bb12094c0e57a557e2e1d104300e910", "packages/pm_marketplace/package_update.ui": "73dd8b7e55bd1dc9730991b5b9a06fd4", "packages/pm_marketplace/pm_marketplace.py": "c00744c2f27e852e4ad0d2d37df043f7", "packages/pm_marketplace/pm_marketplace.ui": "72b055181d7bd41dbfdd06feac750245", "packages/pm_marketplace/pth_modifier.py": "330f9dce62a058e767c9654020ff2012", "packages/pm_marketplace/__init__.py": "e4e5f41117ada3d729f55649c34a3932", "packages/pm_modelling/default.png": "b58b2daf9a2a44726b678f235aed41e6", "packages/pm_modelling/main.py": "936de10bd651db7f14815477894bed86", "packages/pm_modelling/package.json": "ce1142cf81e5d40919fcce5ebe2ae4f9", "packages/pm_modelling/settings.json": "e4385e0a6554dfe40b3696f328f5edd1", "packages/pm_modelling/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pm_modelling/source/down.svg": "fe6b296aa4020dda5c5a870bb7596235", "packages/pm_modelling/source/plot.svg": "05fd271af6c134f6872c80c489064d60", "packages/pm_modelling/source/\u5730\u56fe.png": "eca50b3207a973738145d1cf12ca0c34", "packages/pm_modelling/source/\u6298\u7ebf\u56fe.png": "1bde0eca8cfa880452accf56ca925866", "packages/pm_modelling/source/\u6563\u70b9\u56fe.png": "78c432bb278d8ea5c9587f23ffdd5f82", "packages/pm_modelling/source/\u6761\u5f62\u56fe.png": "b07f4db5b1785376f97636fc6963234e", "packages/pm_modelling/source/\u67f1\u5f62\u56fe.png": "d6cba37e00bf9bbeb65235897a7b90b9", "packages/pm_modelling/source/\u6c14\u6ce1\u56fe.png": "d6784d4c53145cce1fde17f673b76984", "packages/pm_modelling/source/\u70ed\u529b\u56fe.png": "566d7c6ad396084ca6b7d490868fdc2c", "packages/pm_modelling/source/\u76f4\u65b9\u56fe.png": "a9b01bca53610b2c03f7ea2331c91cc3", "packages/pm_modelling/source/\u7bb1\u7ebf\u56fe.png": "ba733c4c1a0979ab5bc838149490e915", "packages/pm_modelling/source/\u7ec4\u5408\u56fe.png": "c5bea73cff095ad47bd07e1e81921ab2", "packages/pm_modelling/source/\u96f7\u8fbe\u56fe.png": "5aa1a48424b30a157a2bca181c9be2d0", "packages/pm_modelling/source/\u9762\u79ef\u56fe.png": "69682cc944d7afdd5c1f2019bf6ca21c", "packages/pm_modelling/source/\u997c\u56fe.png": "862b6c81a5752ee7d53500ce9064c10d", "packages/pm_modelling/translations/qt_zh_CN.qm": "8a5de3a24facfac59b9b7a95ab7937d7", "packages/pm_modelling/translations/qt_zh_CN.ts": "611800964b03dfef8c1cbc1dc4a0bd9c", "packages/pm_preprocess/base.py": "731a2f17cc570b8b92e5da9e323e07f9", "packages/pm_preprocess/datafilter.py": "ac09562b0e7a6b9094225e01bc70e08c", "packages/pm_preprocess/datamissingvalue.py": "51a2e07966da2b720141bd8cb4721678", "packages/pm_preprocess/datareplace.py": "3cce7391493a104a2fc59a7f792a1883", "packages/pm_preprocess/data_filter.py": "102b1b8071747d6d8ed25530e206c5e7", "packages/pm_preprocess/ipython_console.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/pm_preprocess/main.py": "dd006452670a44799031989f21730175", "packages/pm_preprocess/package.json": "c27f88add11891797e8564867f94abfe", "packages/pm_preprocess/preprocess.py": "a8c8d1cb131393e4bf0a6e43503f5c7b", "packages/pm_preprocess/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pm_preprocess/fastui/base.py": "97be57a24cb88f7de7aee11e768364ab", "packages/pm_preprocess/fastui/datamerge.py": "c11ecb39655996d441747c93d3a82a0a", "packages/pm_preprocess/fastui/dropna.py": "44a433355c6732b5c9a2ceebd2fed587", "packages/pm_preprocess/fastui/fillna.py": "fe5d6a6f14f21db63116e5ece2dcb9c6", "packages/pm_preprocess/fastui/pivot.py": "dc302f4e2a9a0a03f035cb04452dc978", "packages/pm_preprocess/fastui/transpose.py": "b9873caa7d3d698221fcd590eb848e27", "packages/pm_preprocess/fastui/__init__.py": "5774d567a5ade4656321f056692ecf7c", "packages/pm_preprocess/fastui/templates/dropna.json": "2135651085e530edc3555862c807e8a2", "packages/pm_preprocess/fastui/templates/dropna.py": "818d27872b51cabc824f36545e848dc2", "packages/pm_preprocess/fastui/templates/template.py": "ab8ca29cb2d8a0116de63f411ad08729", "packages/pm_preprocess/translations/qt_zh_CN.qm": "38862557de320f2ff74455ab1c059a5a", "packages/pm_preprocess/translations/qt_zh_CN.ts": "c17e3ce1dd88a0cfc45d42cd1f706361", "packages/pm_preprocess/ui/data_column_desc.py": "50e1de93cb2b5af92ef9f70ec61b28ae", "packages/pm_preprocess/ui/data_column_desc.ui": "2e4ff14a2934d2e461967f4adf57d096", "packages/pm_preprocess/ui/data_column_encode.py": "addb53a419ba7aad0c822918bd164584", "packages/pm_preprocess/ui/data_column_encode.ui": "83585c68a1b5f10c8cb5c8f979fc069a", "packages/pm_preprocess/ui/data_column_name.py": "ab1343d7eb25ba61ff00653dc727dcd2", "packages/pm_preprocess/ui/data_column_name.ui": "290d0f3b71254001a41ed5419cfc2aa7", "packages/pm_preprocess/ui/data_delete_column.py": "96cc3bb3a839bf327be48c5b8bcf7b4f", "packages/pm_preprocess/ui/data_delete_column.ui": "eb9f4daa76ea45a80897c7d699f0223a", "packages/pm_preprocess/ui/data_delete_row.py": "302569fa225a51a1f63cc8fd740532f2", "packages/pm_preprocess/ui/data_delete_row.ui": "a2bef2e740f12897748cb3ab8942c994", "packages/pm_preprocess/ui/data_filter.py": "18e9c3b6ec4a59ee18b9304234354fee", "packages/pm_preprocess/ui/data_filter.ui": "6b68ea20099eb2657a83277c2b35c5e2", "packages/pm_preprocess/ui/data_import_database.py": "aa8f2c175707416490b15c5b8a5f91b1", "packages/pm_preprocess/ui/data_import_database.ui": "70081a8159869c52d03f42ff96198bcd", "packages/pm_preprocess/ui/data_import_excel.py": "50eab4e5f295ac1e36b415bc1fc4ce17", "packages/pm_preprocess/ui/data_import_excel.ui": "8e4fad97836b5ade1bcf623df4019354", "packages/pm_preprocess/ui/data_import_sas.py": "b46b3a739487b88044585b81d8e1e6c3", "packages/pm_preprocess/ui/data_import_sas.ui": "3a238589200dae2ca6d95b9f76658bd4", "packages/pm_preprocess/ui/data_import_spss.py": "f2429d58b23aca160b2652423d57c491", "packages/pm_preprocess/ui/data_import_spss.ui": "02e6076ba3dba639a81488f57a779acd", "packages/pm_preprocess/ui/data_import_text.py": "72839d8f4905a64c72e3e1ef25f0e084", "packages/pm_preprocess/ui/data_import_text.ui": "42ff2c69c472636f51e11b1d26162306", "packages/pm_preprocess/ui/data_info.py": "9be5f4ff591e53d622773a0323d00195", "packages/pm_preprocess/ui/data_info.ui": "d4fcd989ceba0f39012093152207d598", "packages/pm_preprocess/ui/data_merge.py": "22e207fe8f408b7c558e4f9231c2812b", "packages/pm_preprocess/ui/data_merge.ui": "9cacfe18fc7720477acc7a53b46dd35f", "packages/pm_preprocess/ui/data_merge_horizontal.py": "af3de8607ed351d77daa6213fb2828bc", "packages/pm_preprocess/ui/data_merge_horizontal.ui": "d61611fdb4e9cde0fbc2e2c332f48bf5", "packages/pm_preprocess/ui/data_merge_vertical.py": "ef03b6681fd55cf8eb42138024ad1a4e", "packages/pm_preprocess/ui/data_merge_vertical.ui": "59f79c7fa7b08e5ae1e1aeb83eb05987", "packages/pm_preprocess/ui/data_missing_value.py": "81f362bf96738d9138b85a3d1a2dd9e2", "packages/pm_preprocess/ui/data_missing_value.ui": "14e0e959934e191ca4ecc2b65342864f", "packages/pm_preprocess/ui/data_new_column.py": "e079cabae617aeb3ba5fab8656bc79d6", "packages/pm_preprocess/ui/data_new_column.ui": "8d83bde6b1701635d9266ff9fe8047d6", "packages/pm_preprocess/ui/data_partition.py": "6f723fbf5b83bc18194b0e9242d08177", "packages/pm_preprocess/ui/data_partition.ui": "bb426c3df5bd8e2300a6fce26f0acb45", "packages/pm_preprocess/ui/data_repace.py": "76d5e5f3168158c6527adbc1c1b1d309", "packages/pm_preprocess/ui/data_repace.ui": "853b6f43d364faaae3d6f2ed484681ea", "packages/pm_preprocess/ui/data_role.py": "698c50eb2a907f5e517454a28d610daf", "packages/pm_preprocess/ui/data_role.ui": "9b659e8e2accf1bf76fe39efa74152ff", "packages/pm_preprocess/ui/data_role_edit.py": "f93e00c6adfd65e436630e4c5c097d3c", "packages/pm_preprocess/ui/data_role_edit.ui": "18a531771deee0c25777880c0f0894e6", "packages/pm_preprocess/ui/data_row_filter.py": "32baeee9b80430448f0e1f8af96a60e2", "packages/pm_preprocess/ui/data_row_filter.ui": "7a9b909a49af56c8f2916bf4c3f186f5", "packages/pm_preprocess/ui/data_sample.py": "a4919fe81ffbd64838ed0b84b924d36b", "packages/pm_preprocess/ui/data_sample.ui": "f43301f891fd0450fe7800cb81ff4af0", "packages/pm_preprocess/ui/data_sort.py": "fc051898a3fd9a70ff38fe8ff1d3106c", "packages/pm_preprocess/ui/data_sort.ui": "674a1b2eb62111b5c5134b01ed6d684e", "packages/pm_preprocess/ui/data_standard.py": "822ec20008baf2b82b8ee00ea1711933", "packages/pm_preprocess/ui/data_standard.ui": "65a2eca4b0f6ea65a6edf0c9b6f1628f", "packages/pm_preprocess/ui/data_transpose.py": "97b688d1ca7fb74f5bd72a615eac397e", "packages/pm_preprocess/ui/data_transpose.ui": "d5b50013e984a0f56af8b45aa213fd20", "packages/pm_statistics/default.png": "b58b2daf9a2a44726b678f235aed41e6", "packages/pm_statistics/describe.py": "d48a7e2d4573eec5ea2d6b78f6d518cf", "packages/pm_statistics/main.py": "35a51268c3d516d91f75fd155981327e", "packages/pm_statistics/package.json": "b0cfa0a43b9b4ceffef50955bc142708", "packages/pm_statistics/settings.json": "e4385e0a6554dfe40b3696f328f5edd1", "packages/pm_statistics/stat_desc.py": "1d1af20f21d51a2c4c937b583fa1c1e0", "packages/pm_statistics/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/pm_statistics/source/add.svg": "abddfead93cdf1feeff13e0fb361b2bc", "packages/pm_statistics/source/collect.svg": "df376dc82733ce771785e80417b5730c", "packages/pm_statistics/source/comment.svg": "17b32e5429d0af97cb4b0cb0b878301a", "packages/pm_statistics/source/descending.svg": "4c0294dcdbb972f6f7e7daae9ca3695e", "packages/pm_statistics/source/down.svg": "cf38a40a26932f5d960da15d8bbcb9f5", "packages/pm_statistics/source/history.svg": "f5e2890d446cc530e8505c2a8bcbeb4c", "packages/pm_statistics/source/left(1).svg": "195de59f0ae8946bbdad79b1e6211c13", "packages/pm_statistics/source/left.svg": "5e2fab4fbb3002791406ffb7d4f24552", "packages/pm_statistics/source/like(1).svg": "be280f55711fe37711710d66cc6de07f", "packages/pm_statistics/source/like.svg": "cd5a555d5aeb29ea51c2d4c411a8e2f7", "packages/pm_statistics/source/offline.svg": "864ab749688d77a17dd418ddd12f613f", "packages/pm_statistics/source/print.svg": "58e74f093ab0f76d7a5f4827139d8202", "packages/pm_statistics/source/reduce.svg": "d3a4d2cb5e65462b6e488f9008101095", "packages/pm_statistics/source/replace.svg": "2c9371c33c45026339f8f0a0fad242bb", "packages/pm_statistics/source/right(1).svg": "6ab0334feba1ebc9fe424a408dbeb053", "packages/pm_statistics/source/right.svg": "0d34209038963d8520605c2945a4aea5", "packages/pm_statistics/source/up.svg": "bfc6c9a4e8afe014a9ef2a3a2eaac829", "packages/pm_statistics/source/user.svg": "03789a31cc8d77164ee5e38758be9fed", "packages/pm_statistics/source/view.svg": "404b787576ea5ee3fb77e219a4020739", "packages/pm_statistics/translations/qt_zh_CN.qm": "27c309c51dd6a9b4453805a9d57314d8", "packages/pm_statistics/translations/qt_zh_CN.ts": "6f69f9df98fc80ba305d1ce1bc850e9a", "packages/pm_statistics/ui/stats.qrc": "9e88108821db568452feff5c52cd51bf", "packages/pm_statistics/ui/stats_rc.py": "aed3f3d5bd2699a234c5b87a8c90c27a", "packages/pm_statistics/ui/stat_base.py": "16ff0fac4ad347a51cb36503ddabc76b", "packages/pm_statistics/ui/stat_base.ui": "5b3601a91453d85b8ba247fac1772a85", "packages/qt_vditor/client.py": "b5f987d7265282647636753bb1992169", "packages/qt_vditor/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/qt_vditor/main.py": "43f5ca83b9b8de08a4b08f98c8d5b12c", "packages/qt_vditor/package.json": "a6ea48177df90bd33e6d9ef571715434", "packages/qt_vditor/route.py": "81e4d783b1ee5662a42175044860ac97", "packages/qt_vditor/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/qt_vditor/examples/sample.md": "6d463f26da3f758e8f8cd73d2f07a013", "packages/qt_vditor/templates/index.html": "ed4bff205de492bd9a445b878941ab98", "packages/setting_manager/main.py": "5e25055f2748fd8f2e16ef6cd438cbfe", "packages/setting_manager/package.json": "7b1091e765c316eb4602acbff21a7b5b", "packages/setting_manager/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/setting_manager/settings.json": "d41d8cd98f00b204e9800998ecf8427e", "packages/setting_manager/settings.py": "f60620c0bbfe1bc061bfc00759107674", "packages/setting_manager/ui_inputs.py": "16c170ac829957e8bd4f3b02f4375472", "packages/setting_manager/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/setting_manager/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/setting_manager/translations/zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/socket_server/extension_demo.jpg": "d138a0042696fac046fa3b8a05d5d674", "packages/socket_server/index.rst": "e1840535bf3051014eab7bb2c76fbc10", "packages/socket_server/main.py": "a032c7a064b344e47dd998c545feb38f", "packages/socket_server/package.json": "12d6c14b45eb86427e311e31d005fa20", "packages/socket_server/server_by_socket.py": "77e46bf007fd51f41471b7901bc4b7e1", "packages/socket_server/settings.json": "ac084b924952c4c88e397f5c1f64c893", "packages/socket_server/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/socket_server/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/socket_server/translations/zh_CN.ts": "023045a080a9a26547219f054c272d80", "packages/workspace_inspector/data_viewer.py": "96d8e120289b60f4fe6a4877c807a12e", "packages/workspace_inspector/inspectortable.py": "7e88412960946a64afcdaee6b3bf1902", "packages/workspace_inspector/main.py": "4d6088b006fe4b09815eb34cfad86dcb", "packages/workspace_inspector/package.json": "9ed3843023e8b054420bd126866d6962", "packages/workspace_inspector/python.jpg": "81740ef62fda1acb2905ad8dedb96385", "packages/workspace_inspector/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "packages/workspace_inspector/translations/qt_zh_CN.qm": "4c1aa1fdb602f504983cfc1f303fdb4b", "packages/workspace_inspector/translations/qt_zh_CN.ts": "0176607ae0f96037d5b756be88615f76", "widgets/get_time_consuming_classes.py": "b1cc4fe83988288288bb4d46a55297e8", "widgets/__init__.py": "d4a51fe0c972d4f917c7c2029f6d83f5", "widgets/display/examples.py": "ed6581d11a7624a45e76a0c214abb6e4", "widgets/display/__init__.py": "de9a0f70e421564574c3c849d8c9cbcd", "widgets/display/browser/browser.py": "6471eef6706c84e33e915d2539d7ad74", "widgets/display/browser/get_ipy.py": "fdcef50d9c3d562c0c1a01a07fffac29", "widgets/display/browser/handler.py": "8360907d55237220c8409d02896e1630", "widgets/display/browser/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/dynamicgraph/pgexample.py": "3fd8ccf52c92ebeb164ca3b048b657bc", "widgets/display/dynamicgraph/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/dynamicgraph/base/basetimeseries.py": "5c6cef4a05d653d276681d9281ea7eb3", "widgets/display/dynamicgraph/base/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/dynamicgraph/mplplots/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/dynamicgraph/pgplots/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/matplotlib/pmagg.py": "bbee7bf2140f5b9e7d0f2bd3f9f1dd53", "widgets/display/matplotlib/qt5agg.py": "33f10a259f5fa8973c6cb863ef117285", "widgets/display/matplotlib/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/matplotlib/pyqtgraph/pyqtgraphwidget.py": "c260badf3dd0ad2f2e3bcd0ae107dcd3", "widgets/display/matplotlib/pyqtgraph/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/display/vtk/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/docs/threading_and_tasking.md": "803fb7aad9cbd712229fa089727d2aae", "widgets/docs/doc_figures/pmflowarea_2.png": "4c5b6d091ae5fdc685e94c64a3561218", "widgets/doc_figures/nested_lists_to_place_widgets.png": "3b3dfe1437591299762a3307ba9880a0", "widgets/doc_figures/pmflowarea_1.png": "aeef39398e583540e55a87c04fcb19fc", "widgets/doc_figures/pmflowarea_2.png": "4c5b6d091ae5fdc685e94c64a3561218", "widgets/doc_figures/settings_panel.png": "d1e20e63c914275463ed75740228e7b6", "widgets/elements/dockobject.py": "bbad65e7b1f0304112a70c28917c4fe4", "widgets/elements/toolbar.py": "adb36bf834bbb12c5baabfb323dc5297", "widgets/elements/__init__.py": "5d3ff4be23732caafec3725aacfd2bb1", "widgets/examples/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/examples/utilities/examples.py": "4b738678a2cec6ca81f038d2aad1ebc4", "widgets/examples/utilities/long_conn.py": "a7fb1b9aac35414235ef80dbd1715812", "widgets/examples/utilities/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/flowchart/create_node_content_class.md": "e15251c3574ee6f3472cb32984007f1c", "widgets/flowchart/dataprocesswidget.py": "5830d35615c1b8e05555d4005089f1dd", "widgets/flowchart/readme.md": "13c783b72c01bbef6fd2462deb54d1e1", "widgets/flowchart/readme_arch.md": "15760931b08a70d8257b8e3695f06105", "widgets/flowchart/simulationwidget.py": "17b7dadaf18e84f2d359f2e24571cbe4", "widgets/flowchart/__init__.py": "1ec9907600bd333efbac93fb205ba8d7", "widgets/flowchart/\u521b\u5efa\u65b0\u8282\u70b9(deprecated).md": "c9a0c64e31e69a6c2b226590bf174049", "widgets/flowchart/core/flowchart_scene.py": "8e6b923663fb49519f6555d181c6bc2b", "widgets/flowchart/core/flowchart_widget.py": "6e61a893445b0c08e6bb4fc04f5c9663", "widgets/flowchart/core/flow_content.py": "9f7f15c45ea181fa9390cac06823cca6", "widgets/flowchart/core/flow_items.py": "45810b572b64dfb46b1dbafc4c8391bb", "widgets/flowchart/core/flow_node.py": "426bd423a15ea028aae608489bf27c2f", "widgets/flowchart/core/nodemanager.py": "22f10c693caabc1a588658af292a8238", "widgets/flowchart/core/utils.py": "5e2a38303e8fd30ed7ce3131d99ee4ae", "widgets/flowchart/core/__init__.py": "33d597a87ce723d432ee101bfea5933c", "widgets/flowchart/doc_figures/before_run.png": "56d3c6e2d043d5be501d27a016bf2eb0", "widgets/flowchart/doc_figures/check_json.png": "98dcb1514c6a63b37820704c3ff76ce3", "widgets/flowchart/doc_figures/click_edit_button.png": "1a6625861a3fbd71cf14aa948b16eced", "widgets/flowchart/doc_figures/click_right_top_add_button.png": "116cc66ea7f7a01621afa2bceeefde15", "widgets/flowchart/doc_figures/composition_structure.png": "8a898076c0aa77e7cfe627a933d29c73", "widgets/flowchart/doc_figures/configure_panel.png": "6fc3b5d60c9df7dc4b7ae1ca73162e0a", "widgets/flowchart/doc_figures/create.png": "77d2839be9232d6923e99ac372f1bdd5", "widgets/flowchart/doc_figures/create_new_content_Mul.png": "7d8073ceafe5de7b52cc99b7b0f83b70", "widgets/flowchart/doc_figures/create_node.png": "5defabfa57656965e0ce99fe418d9559", "widgets/flowchart/doc_figures/custom_node.png": "98076ecba04484ffb0f68bc1d3ebe506", "widgets/flowchart/doc_figures/edit_node.png": "5bab19f7eb2b5794e85edaaac6ac8f9f", "widgets/flowchart/doc_figures/edit_panel_meaning.png": "fc03b61991304dbc4b9757420d4853d3", "widgets/flowchart/doc_figures/popup_edit_panel.png": "a069ec207a2060649079a5876ef785e1", "widgets/flowchart/doc_figures/sketch_after_edit.png": "562a4f15b3d808e34ed205ba4859c66d", "widgets/flowchart/icons/down.png": "fe8105e197d1a8dbb7c3f4d04605cc94", "widgets/flowchart/icons/logo.png": "3ba1fce2f5b57a2ab16287e9d0784702", "widgets/flowchart/nodes/dfoperation.py": "3ea5a1b70fc51b363cd8d6ea029aa64f", "widgets/flowchart/nodes/docparser.py": "97e1297436001fc6d447a957799d56d6", "widgets/flowchart/nodes/plots.py": "1423de8473b088b0cf15fada6cebffdc", "widgets/flowchart/nodes/random.py": "bbab2dc862413421cfec6c250f5f04cf", "widgets/flowchart/nodes/reliabilities.py": "834359f014c3618af22987679829df79", "widgets/flowchart/nodes/simplecalc.py": "75c69d36c3813ee5e6b7f98c8c1893e2", "widgets/flowchart/nodes/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/flowchart/nodes/dataframeoperation/dropduplicated.py": "5db7eb9383b7e18a6e6b185b657c2f4e", "widgets/flowchart/nodes/dataframeoperation/randomrowsample.py": "594931f937571051aaa08115303f9b9d", "widgets/flowchart/nodes/dataframeoperation/__init__.py": "590a3c48436d17b168ab491e3d5ef71d", "widgets/flowchart/nodes/io/iterator.py": "d41401063ca9a942416f0f057de62c29", "widgets/flowchart/nodes/io/listdir.py": "8c5903f20f49659f9af2a7ec201d96b3", "widgets/flowchart/nodes/io/pdimport.py": "c32294f54f65a3f25ba6fd1cdabef0ea", "widgets/flowchart/nodes/io/__init__.py": "e6a014f94141e383286a37068a446b4d", "widgets/flowchart/tests/continously_data_process.py": "8f7cbef680438882a373a1a98b6f763c", "widgets/flowchart/tests/database_import.py": "ac1bb7f644465845aac15203b459813a", "widgets/flowchart/tests/fault_tree.py": "4e7a094f1bf83835627c17ecf51eec0a", "widgets/flowchart/tests/node_test.py": "49436316b4bcffa573c07cf714f61d29", "widgets/flowchart/tests/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/utilities/__init__.py": "846122683610ac9a3a02228d40c893d8", "widgets/utilities/network/baseclient.py": "025302351202482cdb67961418a21dda", "widgets/utilities/network/generalclient.py": "57523e2dfe953db9e48e0b2e887f9aea", "widgets/utilities/network/qtclient.py": "c136486e5d7ce14a760e68b5cef5eac9", "widgets/utilities/network/server.py": "36c357391ae6077674c686159e9adc0d", "widgets/utilities/network/util.py": "6d82debc837372e82a42af901dbd8d18", "widgets/utilities/network/__init__.py": "8dd261a5fd464d78930e554a3c71ca0e", "widgets/utilities/platform/commandutils.py": "c534c45682925de3a9ef097bc5e9738f", "widgets/utilities/platform/filemanager.py": "a7ed6bb8a48dc0a631c676b70618b727", "widgets/utilities/platform/filesyswatchdog.py": "c0a2bf1c91a21a5dcf23e31bfeecb70a", "widgets/utilities/platform/fileutils.py": "3ca5537cb60e43a1357e9681b7ac7792", "widgets/utilities/platform/openprocess.py": "1d61b9d4e3ad65e71005b378f25c556c", "widgets/utilities/platform/pmdebug.py": "d0ec593f50f535adc1d9c48c79ea00d7", "widgets/utilities/platform/translation.py": "c4309549c4c11558fdbc3b7491ed64f6", "widgets/utilities/platform/__init__.py": "7fd20799d245559b3722b2688b40aada", "widgets/utilities/platform/test/python_file_test.py": "0c4bff9ef948dbcc88ea0532ae0beb44", "widgets/utilities/platform/test/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/utilities/source/colorutils.py": "fde6914451c075a3e0428f2cce1d0882", "widgets/utilities/source/graphicsitemutils.py": "30395a5a9829eee910c69eca95aa649b", "widgets/utilities/source/iconutils.py": "e83075c233b7ce3290f0e37ded6fba94", "widgets/utilities/source/translation.py": "bb3c8fbd3051b640ed77d30ab718dc32", "widgets/utilities/source/__init__.py": "5b8008b3309c862942604991569b19f0", "widgets/utilities/uilogics/codechecking.py": "48560fbdbd7cf04f3461587b90a12872", "widgets/utilities/uilogics/drags.py": "857f251d9e621005afd8be2c3bf62708", "widgets/utilities/uilogics/uidisplay.py": "f4ee6b2b8695f77551bb4d7e5ff7ad39", "widgets/utilities/uilogics/undomanager.py": "df9dc910b24d09c49e9726420fdeee10", "widgets/utilities/uilogics/windowutils.py": "8372420c42f626d39d9eb193296cb900", "widgets/utilities/uilogics/__init__.py": "645e7a6c9bf8432d1c1ba5e333c362c2", "widgets/utilities/uilogics/tasks/loop_background.py": "4a363d514a49b3d142dd111f957b4a0a", "widgets/utilities/uilogics/tasks/minimal_thread.py": "94f8326dbba36d11f6e45fb79bb2697c", "widgets/utilities/uilogics/tasks/one_shot_background.py": "0075eafe0b95ef10ec9e382917867f7b", "widgets/utilities/uilogics/tasks/threads.py": "380066964983e4398279b18f1cb4c2a5", "widgets/utilities/uilogics/tasks/__init__.py": "2a83611ec96538dd91f878617b4cc882", "widgets/widgets/__init__.py": "dace0c2123dda2b5cf61bfbe954f76e4", "widgets/widgets/basic/__init__.py": "fd2926ad171e35c84c8e34ddc341a15a", "widgets/widgets/basic/browsers/browser.py": "db4472da3e421edae53084e2f60f8531", "widgets/widgets/basic/browsers/__init__.py": "f2ca69c55dd6dd321eb50715d281d85f", "widgets/widgets/basic/browsers/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "widgets/widgets/basic/buttons/__init__.py": "900cfebb524cf4f7d2a311ba7376744c", "widgets/widgets/basic/buttons/button/toolbutton.py": "078234cbde02a9528c683296768c716a", "widgets/widgets/basic/buttons/button/__init__.py": "0c609746f7319525ec3b9a95478be7e1", "widgets/widgets/basic/buttons/buttonpane/pushbuttonpane.py": "b4b83976fd0b594799dc95bc3c577433", "widgets/widgets/basic/buttons/buttonpane/__init__.py": "1e6ab09b63582d591d9c9fbb95d77d25", "widgets/widgets/basic/buttons/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "widgets/widgets/basic/containers/flowarea.py": "3465e9353838239b7a85503bdb348eb6", "widgets/widgets/basic/containers/flowlayout.py": "e7722b3b344fb1966513920657c3ab9e", "widgets/widgets/basic/containers/pmdockwidget.py": "264fd97a9b774531ee722a2c561c9eb1", "widgets/widgets/basic/containers/pmscrollarea.py": "d4474ecaf4ebe7ef1bc33646f9776c74", "widgets/widgets/basic/containers/PMTab.py": "69bc55a23c66f5aeefd57c00c54daf9f", "widgets/widgets/basic/containers/pmtoolbox.py": "aaa8b73936ef32a4c48d3c6dbb4a1edc", "widgets/widgets/basic/containers/__init__.py": "edcf475260eaebb0aababd31515f66a6", "widgets/widgets/basic/containers/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "widgets/widgets/basic/dialogs/textdialog.py": "02c8803b009663537eadcf6d1a1708c0", "widgets/widgets/basic/dialogs/__init__.py": "b05f556cffa689fce8ecf11590d5073d", "widgets/widgets/basic/images/imageview.py": "677c40cd96057c84dbb37592daef0af2", "widgets/widgets/basic/images/imageviewitem.py": "7f4c1d86ca85188970310d26c26d30a8", "widgets/widgets/basic/images/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/basic/labels/scrolllabel.py": "f6bd03763bb1f04990b20b3a1a9b1c90", "widgets/widgets/basic/labels/__init__.py": "37e333e93bd172534e76cd5e850f58f1", "widgets/widgets/basic/labels/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "widgets/widgets/basic/lists/combobasic.py": "0e7fbf8724164af3e7b8b9933df4729c", "widgets/widgets/basic/lists/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/basic/lists/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "widgets/widgets/basic/others/console.py": "5905c89de68775fd568577969e593f3a", "widgets/widgets/basic/others/ConsoleHistoryDialog.py": "2d4f0c82d296813c5a578cc906ae9424", "widgets/widgets/basic/others/ConsoleHistoryDialog.ui": "3ae43f1f52ed4f7dc414a4e522c76122", "widgets/widgets/basic/others/gauge.py": "16159230eebfc9f1be3ff0c4c5d555e1", "widgets/widgets/basic/others/instantbootconsole.py": "5633bce9595e8b8e509431e3d3ce5f09", "widgets/widgets/basic/others/processconsole.py": "adf620b42500885f8252657aefcc701e", "widgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py": "22769bd93d86bf8129ca0fa03b9af12b", "widgets/widgets/basic/others/__init__.py": "fbcfcf98fbfcfb8625281748544e5194", "widgets/widgets/basic/others/source/clear.png": "d00b30caeba4e133a503c28d29484cd6", "widgets/widgets/basic/others/source/run.png": "a7ad927c1b15a7fd5a3a228991d6b778", "widgets/widgets/basic/others/source/stop.png": "db32ac51e103396c0758faa7ca39df7d", "widgets/widgets/basic/others/translations/qt_zh_CN.ts": "efbc0c2de628506b1cd2528e85110912", "widgets/widgets/basic/plots/__init__.py": "29b430ab74236a99e749c91f4a7a4d8d", "widgets/widgets/basic/plots/bars/histogram.py": "57fe8015a7abe33f76965ffb405a1ba1", "widgets/widgets/basic/plots/bars/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/basic/plots/lines/timeseries.py": "7a1877123a6d38adb06b3b9f43a6bb73", "widgets/widgets/basic/plots/lines/__init__.py": "d8f241f084bf5d4a8f4efd5b51d7e94f", "widgets/widgets/basic/plots/matplotlib/__init__.py": "2ac44857cafb53b120d44169c3c34f04", "widgets/widgets/basic/plots/matplotlib/base/pmaggplot.py": "c1882247f0027b2b962ba7a5ea3ca7c7", "widgets/widgets/basic/plots/matplotlib/base/qt5aggplot.py": "33f10a259f5fa8973c6cb863ef117285", "widgets/widgets/basic/plots/matplotlib/base/__init__.py": "f0e054fea02ba6ad51bf06d2a311e39b", "widgets/widgets/basic/plots/pyqtgraph/__init__.py": "2be8e98cb7ca94374b5168f14d00b359", "widgets/widgets/basic/plots/pyqtgraph/base/pgplot.py": "8c38a37cb08c0b54300704a0d1b0f10b", "widgets/widgets/basic/plots/pyqtgraph/base/__init__.py": "81087fce1382395cd3c04360a691bd99", "widgets/widgets/basic/plots/scatters/scatters.py": "450136b97d71bbca2ac809b4b7541a7c", "widgets/widgets/basic/plots/scatters/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/basic/plots/translations/qt_zh_CN.ts": "023045a080a9a26547219f054c272d80", "widgets/widgets/basic/quick/demo1.py": "353264297eedb94ef52af4c181c79e4e", "widgets/widgets/basic/quick/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/basic/tables/tableviews.py": "a2111346680c2af8ab00f8588191e07a", "widgets/widgets/basic/tables/tablewidgets.py": "890007b4bf1e6e2a38673614f324168d", "widgets/widgets/basic/tables/__init__.py": "84da0cb7f378bbf1ea095d6b8ccaf66d", "widgets/widgets/basic/tables/help/help.md": "803db01c2a1acf0f80d479042ecaff99", "widgets/widgets/basic/tables/translations/qt_zh_CN.ts": "147dcbf56740cccf27dc99dcec3b5b6a", "widgets/widgets/basic/texts/__init__.py": "e1c06d85ae7b8b032bef47e42e4c08f9", "widgets/widgets/basic/texts/statusreport/errroreport.py": "a7f14a40ca0be66bd12ac1084f1976f1", "widgets/widgets/basic/texts/statusreport/__init__.py": "b2b898748d695f952a3838cd8289bfbe", "widgets/widgets/basic/texts/webeditors/editor.py": "34336ae67d3efda5060edffa2982d941", "widgets/widgets/basic/texts/webeditors/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/basic/trees/filetree.py": "f2f05c9657978a587295f5a4f09ed1fb", "widgets/widgets/basic/trees/jsontree.py": "b91dc6b98e5561f0f9988051371101c6", "widgets/widgets/basic/trees/treecheck.py": "f29b4c69b3f30b99da28eb79bcf1c068", "widgets/widgets/basic/trees/varattrtree.py": "3f6d8812f23ab42247ee5185e8c8c57c", "widgets/widgets/basic/trees/__init__.py": "2dc6f31ca28c563654578e8b821f06bd", "widgets/widgets/basic/trees/translations/qt_zh_CN.ts": "14da9ce6253397bf6c0fcc1c4c004a01", "widgets/widgets/composited/buttonpanel.py": "a7323ff16ef179e89c39c3253667aafc", "widgets/widgets/composited/fastui.py": "8b604fc24975c5c7ba2de067065a363f", "widgets/widgets/composited/generalpanel.py": "b6be00c44a6e382aae0453e133e84d01", "widgets/widgets/composited/__init__.py": "d13563610fa6f243f2d973dd42a6f6df", "widgets/widgets/extended/__init__.py": "cc16561fe162128cca4c778f11263487", "widgets/widgets/extended/base/baseextendedwidget.py": "378fdef54ba10e68ed5cb276a5624c31", "widgets/widgets/extended/base/__init__.py": "d7d1b8939cf2c630235925abcb5a2ee2", "widgets/widgets/extended/checkbuttons/check.py": "d8b6cbe579ad2161bce135f2925313c4", "widgets/widgets/extended/checkbuttons/__init__.py": "a5c9c5ecdc69c4139ecd15de439b2e0b", "widgets/widgets/extended/comboboxes/combo.py": "ebf75f80630cac67f9642f5372097df4", "widgets/widgets/extended/comboboxes/variables_combo.py": "371fd0d84768be8a624dac87979e1f1b", "widgets/widgets/extended/comboboxes/__init__.py": "58edc6def91691d42263e0d79deec2c0", "widgets/widgets/extended/entries/baseentryctrl.py": "e752e2c6a708b1a435a84473bba154d8", "widgets/widgets/extended/entries/colorctrl.py": "16f70e0d829af6c89fcab387dd6f1442", "widgets/widgets/extended/entries/evalctrl.py": "de708611514272173a02f047b7e5fc68", "widgets/widgets/extended/entries/filectrl.py": "d11a9711cb319e2131464baa2a6a8d84", "widgets/widgets/extended/entries/folderctrl.py": "ff904108b13cddf3b6c7837cb60aa847", "widgets/widgets/extended/entries/funcctrl.py": "f308b1b347c7d44a4efe36b4e8a73ec3", "widgets/widgets/extended/entries/keymappingctrl.py": "2a50527522468cd00f3d7ccb99a02a7d", "widgets/widgets/extended/entries/linectrl.py": "626be1e4169342de4027f902779d9e19", "widgets/widgets/extended/entries/numctrl.py": "3739731735cc0520c4f45d1b0429297a", "widgets/widgets/extended/entries/passwordctrl.py": "85a3604a10ba51e5aaddfd269a8f1317", "widgets/widgets/extended/entries/__init__.py": "a87b64affd6a8b87f14caa030b1d7196", "widgets/widgets/extended/labels/label.py": "e12d3eaafac1b29d87b6b83cb5ca46c9", "widgets/widgets/extended/labels/__init__.py": "5d5fadd87777a0ecdf64ec91c7af5fb1", "widgets/widgets/extended/lists/listwgt.py": "52cf01737cab419a302a61a2fc22dd7d", "widgets/widgets/extended/lists/__init__.py": "fe79c30d2106faff8c630bec7e79ce37", "widgets/widgets/extended/others/multitypeparaminput.py": "f22495e2e29d29843c3888a21abd43a0", "widgets/widgets/extended/others/__init__.py": "372dfdcc25b8f846d64b77bea41535b8", "widgets/widgets/extended/others/monitors/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/extended/plots/__init__.py": "56a6f2c973e69ed27c3021de7b28e035", "widgets/widgets/extended/plots/lines/timeseries.py": "d0b20cb0ea7e4a6ccafc47d9b16e6fc9", "widgets/widgets/extended/plots/lines/__init__.py": "bc396f8083302203baaf5d23065c33ca", "widgets/widgets/extended/radiobuttons/radiobuttonctrl.py": "113268756d9f5bb930230e4f8824ec67", "widgets/widgets/extended/radiobuttons/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/extended/spins/datetime.py": "e6a555a3bf8d0a57b98d8926ec6684c7", "widgets/widgets/extended/spins/numberspin.py": "74160a8031c42d2f5ea87cc4a5be3272", "widgets/widgets/extended/spins/__init__.py": "cfa6752de3dc824468eaaec6166fb3d4", "widgets/widgets/extended/tables/rulesctrl.py": "6d2fda81132490482c0fdc5263cb5190", "widgets/widgets/extended/tables/tableshow.py": "100223049815e42adb4fd3c74753dda7", "widgets/widgets/extended/tables/__init__.py": "2945023ce1794015105e1aba6213136d", "widgets/widgets/extended/texts/htmlshow.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/extended/texts/markdownshow.py": "d41d8cd98f00b204e9800998ecf8427e", "widgets/widgets/extended/texts/__init__.py": "4ab23c644c97003b968443d8a2f4a584", "widgets/widgets/extended/trees/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "lib/localserver/readme.md": "6e10586e731f6fdc871441974934b006", "lib/localserver/server.py": "d29fca0da053832fcbaec4788889674c", "lib/comm/readme.md": "d41d8cd98f00b204e9800998ecf8427e", "pyminer_comm/__init__.py": "f6b46f7aedc9dd22d9cdaf15d1be08c2", "pyminer_comm/base/datadesc.py": "1f068e02ef48771fb3499b5b27ff058b", "pyminer_comm/base/encode_decode.py": "42188f6322e17da29d8d1cfb54ebc75a", "pyminer_comm/base/network.py": "1b0fbd15a289297b65698b2139724741", "pyminer_comm/base/sys_utils.py": "4b9c387c0926aa2bec713ba5560c68f1", "pyminer_comm/base/__init__.py": "036632e2718a53fdcd02a87492de0963", "pyminer_comm/data_client/data_client.py": "613aeac2716a0ec38b3f5db2c38080b4", "pyminer_comm/data_client/unittest_data_client.py": "cd4366d90aeca0639432273292da8efe", "pyminer_comm/data_client/__init__.py": "8159a5a2b762aa7581a92517146bd002", "pyminer_comm/pyminer_client/pm_client.py": "5e7ff88e50112aac1f639a7301404218", "pyminer_comm/pyminer_client/__init__.py": "fa7dd1f47a04d6515681315870a12899", "pyminer_comm/tests/test_communication.py": "95fa83a3686c8ea7bfc4736220e3bbdb", "resources/pyqtsource.qrc": "8a3a6b55a64fa60f8c58f49d2d7eb949", "resources/pyqtsource_rc.py": "1cdc5870d3e5107926e57d15c7fa63ea", "resources/fonts/Cascadia.ttf": "717e365c4a4c1478f8208a5ab33ee26b", "resources/fonts/CascadiaMono.ttf": "66c917f89d707ba0b41d5a1619c1e03e", "resources/fonts/Deng.ttf": "15c8b490227909f31d456ee9d11521e5", "resources/fonts/Dengb.ttf": "2d690e1656db754bc4ce63531223d007", "resources/fonts/Dengl.ttf": "1ddcd772ff1d04a2d545434b47ae4782", "resources/fonts/SourceCodePro-Bold.ttf": "458f0d7c492182d4c1b08621518689c0", "resources/fonts/SourceCodePro-BoldIt.ttf": "0cddef66936155d98aaa0d2a71d609c1", "resources/fonts/SourceCodePro-It.ttf": "df1343e44ce0fd5eb8c09ce8995966c8", "resources/fonts/SourceCodePro-Regular.ttf": "fedb9984186419a66cf725a38b6703ca", "resources/icons/logo.ico": "f1eb0f12aa600bd5638cd6fbca4b978f", "resources/icons/logo.png": "30e040dea91eb5edc95a2ab16c895324", "resources/images/bg.png": "931fe255dbcec81b94c2cd692fa1ff01", "resources/images/left.bmp": "d9daee9f12d8d45832a5f85fb79733cd", "resources/images/PyMiner\u6846\u67b6\u8bf4\u660e.jpg": "02eecc71bfee918d5a559501aa8b1334", "resources/images/splash.jpg": "d093033402635cffde8ae0d4840e46c4", "resources/images/splash_v2.png": "8de3454d0a7ea72b2ddbe2b242ebc535", "resources/images/weixin.png": "9fd2526c405766beb714515a07571c44", "resources/images/xmind.png": "9f0ef2b1b83dee369f38600bbdbf44bb", "resources/images/zhifubao.png": "2b957fd623e55d473c9c1eb81ce7ecd8", "resources/qss/Fusion.qss": "e3b35eb107311192c3d6a1b6512da0a0", "resources/qss/index.rst": "6000f5eae1ed6f0e434e0001675bf8a2", "resources/qss/Qdarkstyle.qss": "1d5438b0c29ab46529c7d38a976dbf62", "resources/qss/standard.ini": "ee661fb8f5a4a0852389e31a11c71001", "resources/qss/standard.qss": "1c1672f58d85af0e6211b6c144987974", "resources/qss/Windows.qss": "70481f2ea4c380995271f4b338da0968", "resources/qss/windowsvista.qss": "80e75b0e7ec8b7dd7a23b4bf75ab8ef4", "resources/screenshot/check_data.png": "e44471c2514f8a048df2a89a9df2e795", "resources/screenshot/code.png": "814df667bb94b7d2ae844d938ec916b7", "resources/screenshot/group.jpg": "0b3959e958742a35baeaec5044a95584", "resources/screenshot/main.png": "1b6f8a5331f0c5954a86b9024f070568", "resources/theme/default/icons/3d.svg": "61157c75fbfde955215c93e2daf93551", "resources/theme/default/icons/action.svg": "61ef2e8adb0b2bfe5928aa14b376fec3", "resources/theme/default/icons/addannotation.svg": "503b6bffffae70dfe67068cd24f5d88e", "resources/theme/default/icons/added.png": "2acf12376249833027eadb29c9e8a58f", "resources/theme/default/icons/addFeature.svg": "bcc4056d0d52f3cb44acbc81858b6099", "resources/theme/default/icons/addnode.svg": "763e098d49dec789969c25b7e69ab629", "resources/theme/default/icons/addpath.svg": "e700804c812dfe2bdc54798b11814924", "resources/theme/default/icons/add_col.svg": "eee7249c440e048cb1796d3e8d1c949b", "resources/theme/default/icons/add_row.svg": "620b902ccebc31be4d270e7124fb2e48", "resources/theme/default/icons/align_bottom.svg": "f4fb3a0c1bb022440e3489f75e69c390", "resources/theme/default/icons/align_horCenter.svg": "cef02a64b8f66064fc237ea34b41536f", "resources/theme/default/icons/align_left.svg": "2275c71a5bd808f0379098e0663c1aee", "resources/theme/default/icons/align_right.svg": "aeb304bf474f3402804c6c113d197101", "resources/theme/default/icons/align_top.svg": "621e60f54d5dcd50a28aa7aa3be3ffe4", "resources/theme/default/icons/align_verCenter.svg": "a8ea8b762c89efcbeeb78f3c3f72b4dc", "resources/theme/default/icons/allowedit.svg": "3c2b136910b2403dc0da5cd1a54fba0c", "resources/theme/default/icons/allowedit_layer.svg": "fe3079b3a271ac07bea92c298fe75452", "resources/theme/default/icons/allowsearch.svg": "1504eb4f1da9532cbb86754b39c0f410", "resources/theme/default/icons/allowsearch_layer.svg": "e126ff953c35229e30444c8d6e4ae2e8", "resources/theme/default/icons/allowselect.svg": "5b3dbfe62ddbf003af7efb4f429cb0fe", "resources/theme/default/icons/allowselect_layer.svg": "62cbf0796e8e284f4df30d1575d4c16c", "resources/theme/default/icons/allrecords.svg": "75b5c30ce3932f21ae7b16013ffc4c8c", "resources/theme/default/icons/annotation.svg": "1ae382f88b44847332e9826ba46c5397", "resources/theme/default/icons/annotation_no.svg": "c3e5a2d3179e075c49b13015eb5b7e52", "resources/theme/default/icons/anova.svg": "14b71522f19c12ffde5e46202fcf6bc3", "resources/theme/default/icons/appstore.svg": "e2a48d1643f244e957ce9dba9e55a72f", "resources/theme/default/icons/app_down.svg": "5af2c894a37156084df6218bf562c626", "resources/theme/default/icons/attributerender.svg": "216c03c70731a3d0936649486d1ac943", "resources/theme/default/icons/attributes.png": "5a9ddb1cb0d0b3e35bb8f5bec3c7c511", "resources/theme/default/icons/basicStatistic.svg": "e84a179215a06d27e8547e52620a4859", "resources/theme/default/icons/beginfly.svg": "260f78da60b0d46b64fdd9b942167066", "resources/theme/default/icons/bottom.svg": "6fbc8f02bc979600df8a6a8d24bd3ae8", "resources/theme/default/icons/camera.svg": "27ae116857da0dc4bc1bf2a45a899dd9", "resources/theme/default/icons/canshu.svg": "3dd688f4c48e9c5e32ea9ef81ac8ac86", "resources/theme/default/icons/catalogAttributeTablePageFirst.svg": "0872ecfef2107aeaafbcdf0959d1a21f", "resources/theme/default/icons/catalogAttributeTablePageLast.svg": "18d9cf57a8fa52b6fabb08565ba0177f", "resources/theme/default/icons/catalogAttributeTablePageNext.svg": "ceeedf9b8523a724ea5cd524fa733211", "resources/theme/default/icons/catalogAttributeTablePagePrevious.svg": "164f4dc04bc3e9e8c508505027d408fd", "resources/theme/default/icons/catchline.svg": "6b4ee518bf6ba27bdd6cf44188ca864c", "resources/theme/default/icons/catchpoint.svg": "8191852167c41f1408891d74f233110c", "resources/theme/default/icons/centerpointlinkage.svg": "8fe7f934cfdca995811c3170017607d1", "resources/theme/default/icons/changeAttribute.svg": "a1b9c1ff1e2f6d7dad0a3873a52ce13f", "resources/theme/default/icons/changeFeature.svg": "556de2ee6e10e39b6e369c6c7a271be3", "resources/theme/default/icons/changeGeometry.svg": "1628a5992db6891c26741e3356817473", "resources/theme/default/icons/chartStatistic.svg": "30047525eb626a274f074399334f4b30", "resources/theme/default/icons/check_update.svg": "d6e33e022ada06b9b3abf33de637a573", "resources/theme/default/icons/Classification.svg": "658e28143d9a717f0e2b951cc67111ae", "resources/theme/default/icons/clear.svg": "1d841dcc502211799d9055a87cf3c55d", "resources/theme/default/icons/close.png": "20780f1ae86a0f942f448f69e16dbd3c", "resources/theme/default/icons/close_white.png": "7b567f8cd3293ae156df417e5a21dc6b", "resources/theme/default/icons/Clustering.svg": "012392d9351d8983b29e99b42145c77b", "resources/theme/default/icons/cmd.svg": "0ea2aa79bb81ae297c97d356072745bc", "resources/theme/default/icons/column.svg": "006f3f2cbba5c9fc0fcc223883b00fc7", "resources/theme/default/icons/column_2.svg": "4a2981704a879a016c4a8dc88710b5f2", "resources/theme/default/icons/community.svg": "3cdd0bf3826dfc1ad073d7ad449bc93e", "resources/theme/default/icons/compare.svg": "ddc98ac27fe119cb0d4acbf6a04affdc", "resources/theme/default/icons/conflict.svg": "ffe7f2d515ba91b5920547c0193b6474", "resources/theme/default/icons/conflicted.png": "1f83c2acd291df5d1d10ea67930145fe", "resources/theme/default/icons/continuefly.svg": "4346811bddecadf1ff6db3d87c1447d6", "resources/theme/default/icons/copy.svg": "9ad66acb6dcb55bf923628b188ff5f64", "resources/theme/default/icons/copyElement.svg": "cbe746ec2f6abd3a4b5a020943acf0a1", "resources/theme/default/icons/csv.svg": "9867d63fe22cc88b9c47159b0fd04791", "resources/theme/default/icons/csv_gray.svg": "16c6562ded6d0f6e0ee26005b9bc4c7f", "resources/theme/default/icons/currentindex.png": "dc987f99c44a68ca57c15dd784babc24", "resources/theme/default/icons/database_config.svg": "fa799903a0c570e3a09fe7efa6d3a276", "resources/theme/default/icons/dataSourceConfig.svg": "6a3bd375f33fe348498e053f3bcae8f5", "resources/theme/default/icons/dataspecification.svg": "1e6d1fcac3f8dc14a0daffc947c4d14a", "resources/theme/default/icons/data_desc.svg": "5913822d76a61455714c15e6132eb3e6", "resources/theme/default/icons/data_desc_2.svg": "1f51941660ac732dda207d022c26ee04", "resources/theme/default/icons/data_info.svg": "9ead14ad7a1cdf63b5702c48e05e78d3", "resources/theme/default/icons/data_join.svg": "406e169ebb9b8af93d286581f59f0245", "resources/theme/default/icons/data_missing.svg": "c7f2e5a1dc938edae131a30c6b56b711", "resources/theme/default/icons/data_partition.svg": "d8cbc4400259d84850ec97154dacd688", "resources/theme/default/icons/data_role.svg": "5002bd4ed773126cf2d4c34c4bb4541d", "resources/theme/default/icons/debug.svg": "e2ca8b334c69f413637945ebe871d696", "resources/theme/default/icons/debug_red.svg": "ab77c95b9f382e8f6fdb09da83795dfc", "resources/theme/default/icons/deleted.png": "99073a344eb6184343073b14eb3b4338", "resources/theme/default/icons/deletedata.svg": "0809bd41dd7489df3a1dc2a8e976f888", "resources/theme/default/icons/deleteFeature.svg": "5acc1452971d56857d219e9906341904", "resources/theme/default/icons/delete_col.svg": "c64463979c0dabb232a424810a41fad0", "resources/theme/default/icons/delete_row.svg": "28c35f8dae78bb25a1d8b4981996ec5d", "resources/theme/default/icons/dependencies.svg": "150af39be2e05f96916e16c20f7eacbc", "resources/theme/default/icons/diagram.svg": "93a8d692b994662c68e9374ca42fbfe0", "resources/theme/default/icons/disallowedit.svg": "1d2ea40eb876a1b57edfab5937150a23", "resources/theme/default/icons/disallowsearch.svg": "48d814b63bb64b53e1bbe5a745ad2efa", "resources/theme/default/icons/disallowselect.svg": "780b169700eec6b08dc575e3a0d01275", "resources/theme/default/icons/display.svg": "a370d879c046105fa360f2bee6809a10", "resources/theme/default/icons/distribution.svg": "53e6bcf151c4cb9f89f80093c256ea62", "resources/theme/default/icons/donate.svg": "f72f24a7e8db14c7c98394d6c8dfc860", "resources/theme/default/icons/down.png": "303cd2548ab3be7109c7fbab16730725", "resources/theme/default/icons/downWard.svg": "0bf14903bcbdef20890f936ac7855c61", "resources/theme/default/icons/drawline3d.svg": "64fc6cdf5c361bb7a6f2b5c7dadc3934", "resources/theme/default/icons/drawpoint3d.svg": "452946e331372a97bdd09df9f5f86a71", "resources/theme/default/icons/drawpolygon.svg": "e54865783b8e639d6b8aef7f0eb0597f", "resources/theme/default/icons/drawpolygon3d.svg": "4dd900f92c31b8254c18371b72532011", "resources/theme/default/icons/duoyuan.svg": "5d84f2bcfc84ae85a6fb1a7a5ee08b28", "resources/theme/default/icons/E-matlab.svg": "11fb165a87912c326ba2a5f27d4971b8", "resources/theme/default/icons/earth3d.svg": "2bbc786eaadf43a74a592ec82b14ba03", "resources/theme/default/icons/editannotation.svg": "e73609dbea16a474b62e07344a34264d", "resources/theme/default/icons/editConfig.svg": "2e65b8ba1573593af29ee2fcf1a54288", "resources/theme/default/icons/editmetadata.svg": "c89258a047ac04855464e0a2cb883f8e", "resources/theme/default/icons/endadding.svg": "ba25cd175a3a98a0d2c7b81f125975df", "resources/theme/default/icons/endfly.svg": "8aa793c8cc77046cdfd7d70307c83731", "resources/theme/default/icons/errorInfo.svg": "b8d8db18986b89bf3b1b980fa613462b", "resources/theme/default/icons/excel(1).svg": "9eb4ba787a3e62e477772f0c4a93f366", "resources/theme/default/icons/excel.svg": "ea00b0b78bb93119c7eafe98a79a8988", "resources/theme/default/icons/ExcelFile.png": "c488f98763fb577be56bc955c928c947", "resources/theme/default/icons/excel_gray.svg": "a1135950f1896aa177e00eb10f44f910", "resources/theme/default/icons/expendDown.svg": "fe6b296aa4020dda5c5a870bb7596235", "resources/theme/default/icons/expire.svg": "b7055d451d7bf23ddffcd974ceb39225", "resources/theme/default/icons/fastCollect.svg": "b929bc85fd17ba612275008238d70e53", "resources/theme/default/icons/favorites.svg": "589f0e80dde61b86c2470b3799f8f860", "resources/theme/default/icons/feedback.svg": "f695df9b7313ab60be2c3c46b4fc7468", "resources/theme/default/icons/field.svg": "d168f3a212323820267956d6de9ca9d7", "resources/theme/default/icons/file.svg": "58f428cb524544f4f3993bb37f2ef1ba", "resources/theme/default/icons/file_gray.svg": "fe90e95c15020d95c8f5690f3cb5fae3", "resources/theme/default/icons/filter.svg": "e87a00609c494f030812f3c00a2e6e35", "resources/theme/default/icons/final.png": "87457d3035ab89d82a6b57976e9b0245", "resources/theme/default/icons/find_replace.svg": "665177ccc10ce22b469a118beec97dd6", "resources/theme/default/icons/first.png": "f0edce38b01be51e2dfea42df74d8f23", "resources/theme/default/icons/flight.svg": "8857e62ab11e2cd3ae039db12d61b0d4", "resources/theme/default/icons/float.png": "5f31043d787d15eab504b59bef221e6d", "resources/theme/default/icons/float_white.png": "89609a354d4d717f4e578528dfd5547c", "resources/theme/default/icons/fly.svg": "9761c5cef3b2a4a59ef4ed762c62ad7a", "resources/theme/default/icons/flyaround.svg": "c8a2ba65a3a3ea28c710727327b062b6", "resources/theme/default/icons/folder.svg": "b7e11fde0a4f073c8255d911214aecd3", "resources/theme/default/icons/folder_yellow.svg": "9d3d6d38fa617dfeedec734a5c5c13e1", "resources/theme/default/icons/foundrecords.svg": "aeb3afe2862d00fdeaf810cc479a9704", "resources/theme/default/icons/general.svg": "8d0ffe48967c6985486949410f399c74", "resources/theme/default/icons/generalConfig.svg": "ce54c065114cc47016cd6a382457c1b8", "resources/theme/default/icons/GeneratingAdministrativeRegion.svg": "444cf5e4f7daa640706014ae3f55e307", "resources/theme/default/icons/geodbms.ico": "fef8bfe0713f757762dd9ce837b48c1c", "resources/theme/default/icons/geomap.ico": "dd4b17c0ec69f51b039c51b6e0887c31", "resources/theme/default/icons/gotoview.svg": "da5e78b70c58d112189832fd5cdad9d9", "resources/theme/default/icons/help.svg": "6c9e88b86a30ea8df99ecb75891990d2", "resources/theme/default/icons/help_doc.svg": "1491066f6ba737fb319d4b3aeec96402", "resources/theme/default/icons/histogram.png": "334c464f233edaf5d54c0e1a78289559", "resources/theme/default/icons/home_site.svg": "a9fdb97167551132fe16dd05e7668643", "resources/theme/default/icons/html.ico": "ef2d86df09c9fc6d671e12b5deaf49e6", "resources/theme/default/icons/html.svg": "8158b710d8854547cfe6e2ece1ab3e22", "resources/theme/default/icons/import.svg": "e38ca75a6ffcf334ea461b245f523444", "resources/theme/default/icons/importConfig.svg": "f60db217ccfce27088257eeb9b39d236", "resources/theme/default/icons/import_database.svg": "42ae4560410eb3b900a99360d0019fba", "resources/theme/default/icons/indent_left.svg": "13d4c1ee641fc364bf20be31e9c277a7", "resources/theme/default/icons/indent_right.svg": "a9bc26d41494a2760b186614cc5a177d", "resources/theme/default/icons/index.svg": "63797de724460b5527354bcc9df5d79d", "resources/theme/default/icons/info.svg": "59366b0c10bbce5c3dd9dfec1860d32c", "resources/theme/default/icons/install.svg": "699200cfd59967ff740f1e3076795f0f", "resources/theme/default/icons/invisibleMap.svg": "f5e5e045de80b10006eca992d6f156c1", "resources/theme/default/icons/javascript.ico": "237b59ab21d39cbf9d56481abd6ea724", "resources/theme/default/icons/jiashe.svg": "6195487f581d0b17bf8bd5e440ac3152", "resources/theme/default/icons/join.png": "ae8569cf1fc1762af272861ffbf1a16f", "resources/theme/default/icons/JoinMapTable.svg": "c7277790649b9dafcba2531c8ec43630", "resources/theme/default/icons/jump_line.svg": "36d10e5f905da4134c668d1baa7b0eff", "resources/theme/default/icons/jupyter.ico": "fcd12a895e826c9bf68ec69a3801a6b5", "resources/theme/default/icons/Jupyter.svg": "5e31f82bc08dff94a0f7a19492ae3e57", "resources/theme/default/icons/lab.svg": "bb81cefd8b4592063bf604536517bbe4", "resources/theme/default/icons/labelingMultiple.svg": "60b47ac95c42db86f0a1996619aa5710", "resources/theme/default/icons/labelingNone.svg": "aec873e7c3a156d25d90ba14332250fe", "resources/theme/default/icons/labelingSingle.svg": "4eb6031628115e94af14c75ed7743277", "resources/theme/default/icons/labels.svg": "2f07179dee5125cdc7720364cc83fa4d", "resources/theme/default/icons/LandSurveyAutoNumber.svg": "d4fa015fe319301146a20d569319d197", "resources/theme/default/icons/layerBrush.svg": "30f0e853f0588bb65f58b6e407f26e73", "resources/theme/default/icons/layerConfig.svg": "ca61ff1339a5aab82167c3b3834f6fc8", "resources/theme/default/icons/legend.svg": "d34ddf6094becbbd0c65321a1f154bfd", "resources/theme/default/icons/lockorthoview.svg": "39417a4ce7986b55c908a36268185ca3", "resources/theme/default/icons/lockview.svg": "89f5b906db5c12867af42e06ccb1d18e", "resources/theme/default/icons/lost.png": "e5f28a07326ba62314e4964833d853c8", "resources/theme/default/icons/mActionAbout.png": "1b50df16c376e6e78454236403627aeb", "resources/theme/default/icons/mActionAbout.svg": "1e1360e32f95eee26b8f41e69339cab8", "resources/theme/default/icons/mActionActiveStyle.svg": "302386637bb5cd7bf856ad1ce6ea42fe", "resources/theme/default/icons/mActionAdd.svg": "340f3bb6a7682527aae76150aabff11b", "resources/theme/default/icons/mActionAddArrow.png": "95e75cb331f8ff2ae412b474db6f55bb", "resources/theme/default/icons/mActionAddArrow.svg": "06246d25e27308ad26aac55af7eb9713", "resources/theme/default/icons/mActionAddBasicCircle.svg": "f8a5e280035bbfaa025028e4eed1c703", "resources/theme/default/icons/mActionAddBasicRectangle.svg": "85605dbd86923fbed31379f828d995bc", "resources/theme/default/icons/mActionAddClassification.svg": "5d91e7c199fdfc94b71882b743e084f8", "resources/theme/default/icons/mActionAddClassificationCode.svg": "71811be70f15711a0890b9f6a407dab5", "resources/theme/default/icons/mActionAddCustom.svg": "cc118673a1e3b2e74fc57da54a9aa35e", "resources/theme/default/icons/mActionAddDataSet.svg": "e15df2fe98dfcddd91f6edc44b17f719", "resources/theme/default/icons/mActionAddDataTable.svg": "3944027676b922267a24159091390090", "resources/theme/default/icons/mActionAddDicItem.svg": "d71bb80327c14ba5e06e965b15864b48", "resources/theme/default/icons/mActionAddDirectory.svg": "f4a64c10d63eb102b6088281748dedf5", "resources/theme/default/icons/mActionAddEnumRange.svg": "9969caf289186d9cd546400aa5f16079", "resources/theme/default/icons/mActionAddGroup.svg": "f308932c912ab0483324f89d5ecce6c0", "resources/theme/default/icons/mActionAddImage.png": "94e43a1d6b956c2b35625a5ea760261e", "resources/theme/default/icons/mActionAddImage.svg": "28bb04fd672efe9f1a52f2901f54de6f", "resources/theme/default/icons/mActionAddLayer.svg": "840395598b646deb2c747f78d305e324", "resources/theme/default/icons/mActionAddLegend.png": "8349d32174a82160f1c812641855fbb9", "resources/theme/default/icons/mActionAddLegend.svg": "d756c3c84d9a1e613341676f8c3e8965", "resources/theme/default/icons/mActionAddMultiPoint.svg": "f9ade46e1458d5942ae557420592f836", "resources/theme/default/icons/mactionaddordergroup.svg": "a7e40299ca8607fd8ec9573f66cb95a5", "resources/theme/default/icons/mActionAddPoint.svg": "c85722428ece40150082f3d81bf170f3", "resources/theme/default/icons/mActionAddPolygon.svg": "83662dc01e024450dce5ecfaf1514edc", "resources/theme/default/icons/mActionAddPolyline.svg": "5d61a265d4c1e899cd171721d3b006ce", "resources/theme/default/icons/mActionAddRangeRange.svg": "99b93618e2906303244bc6a2ed20d3e0", "resources/theme/default/icons/mActionAddResourceWizard.svg": "9318a164ee340e04da837175aeea8820", "resources/theme/default/icons/mActionAddScaleBar.svg": "43afed23afb8200c15a543df1a450f3c", "resources/theme/default/icons/mActionAddSchemeData.svg": "c86e2f3e2356fd1ad82cdda941a9ad7b", "resources/theme/default/icons/mActionAddStyle.svg": "c60df25cbed4067a5ac0bc320463b816", "resources/theme/default/icons/mActionAddText.svg": "b6e185e764c5da36528cd7a83654d17d", "resources/theme/default/icons/mActionAddToCanvas.svg": "4f222a6648efa565f051aa2617caca5e", "resources/theme/default/icons/mActionAddVertexTool.svg": "73d0e0aa645810d8737db7604fb48d98", "resources/theme/default/icons/mActionAdjustLayers.svg": "42d197117a2af9818fcbefc935e03fa2", "resources/theme/default/icons/mActionAggregateNode.svg": "0e8e850ce17baa5e7c7aa3b238279790", "resources/theme/default/icons/mActionAligningToLine.svg": "6844c8fc2e7d023ebd31bfb23c907a9e", "resources/theme/default/icons/mActionAllEdits.svg": "1a13a6fe0c38adcdbbc315b963805233", "resources/theme/default/icons/mActionAnnotationImport.svg": "ed08c23f1bb2ea1dc03aee1496693ec6", "resources/theme/default/icons/mActionAnyDLAnalyze.svg": "cbcf45db82108f1e0ec97691d2b021ed", "resources/theme/default/icons/mActionAttributeBatchTool.svg": "f8853792345634f2ccbf3d5b3cc2ae9f", "resources/theme/default/icons/mActionAttributeBrush.svg": "bc8e8e7de8a8b5c4d75891072f58a9c9", "resources/theme/default/icons/mActionAttributeIndexManager.svg": "de8c1f6a81ef7a0dc047131f2b3bccca", "resources/theme/default/icons/mActionAttributeSelect.svg": "0a0e325e465cfcd8eb9a502e4fc9aac2", "resources/theme/default/icons/mActionAutoChange.svg": "2add0a98ec45eb1f992348a61b77107c", "resources/theme/default/icons/mActionAutoCutPolygon.svg": "5142adcd7b3d1702cc05eb4732bda7a5", "resources/theme/default/icons/mActionAutomaticClosure.svg": "100464d989b5520597726da001d2e6b7", "resources/theme/default/icons/mActionAutoParallelPolygon.svg": "d301512aec2983ee3fa88426f2c0583d", "resources/theme/default/icons/mActionAutoParallelPolyline.svg": "419b2e6153752735a075f87b2c6976af", "resources/theme/default/icons/mActionAutoProjection.svg": "1cfe66813280c607e1afc8715fa98983", "resources/theme/default/icons/mActionBackLastLevel.png": "0e06243d91122f7a759af354689e786c", "resources/theme/default/icons/mActionBackupDatabase.svg": "ab331f009a206badb5b6eb214ad0e555", "resources/theme/default/icons/mActionbatcgSetUniqueCode.svg": "3d5f12cd66429d20dc6b16d2e4af6a27", "resources/theme/default/icons/mActionBorderPolygon.svg": "70dd6b1cafe2eb371c897c2509ec0406", "resources/theme/default/icons/mActionBreakBySinglePoint.svg": "a4f86b74ab5d94b4bf90c8678155c8de", "resources/theme/default/icons/mActionBreakByTwoPoints.svg": "9faa1aeaf46c1a8a5f1a39a8f077293d", "resources/theme/default/icons/mActionBreakIntersectantPolyline.svg": "5891ffbba64c08cf4db8760d782465b1", "resources/theme/default/icons/mActionBreakWeld.svg": "f7f43dad61d9c4e3322eca488da3ab92", "resources/theme/default/icons/mActionBrush.svg": "e66b98adb06f1d8d702edb7f9ec5546f", "resources/theme/default/icons/mActionBufferAnalysis.svg": "d80ab987bd4a1fc371e2776e66425406", "resources/theme/default/icons/mActionCalculateField.svg": "f32837750c5840f154a2a749c8aade44", "resources/theme/default/icons/mActionCatalogManager.svg": "99e161a7b7367a9fa2929009134a653a", "resources/theme/default/icons/mActionChangePolylineByExitline.svg": "e08d8787b31f2c90f7378b382311f23a", "resources/theme/default/icons/mActionCheckAll.svg": "438f359d854c7ebedf6be6b88f7d0f6c", "resources/theme/default/icons/mActionCheckAndMaintain.svg": "a7e9601b46669c45f9096f011ab41bd1", "resources/theme/default/icons/mActionCheckNode.svg": "b14495714a6c980374bb8482d3211444", "resources/theme/default/icons/mActionCheckResult.svg": "2cf1b01c206622535c1e1825eb2b69cf", "resources/theme/default/icons/mActionCircularStringCurvePoint.svg": "310cea9398a663a4d4b13e528fa7ce5d", "resources/theme/default/icons/mActionClassification.svg": "995a538a5a6002821d6c50dc9a81fe63", "resources/theme/default/icons/mActionClearEdit.svg": "1c5a1c68aac83d68129868577ea30f7e", "resources/theme/default/icons/mActionClearLayer.svg": "32eba1e6735860eb142fff43a48eed54", "resources/theme/default/icons/mActionClearSelect.svg": "acc58e9be78e0153b7d7d1ed921b6230", "resources/theme/default/icons/mActionClose.svg": "e85dae4f037b08290dd34d668bcf06b3", "resources/theme/default/icons/mActionCollapse.svg": "3d2eba0c9ca35b25ec706a3e970a8b44", "resources/theme/default/icons/mActionCollapseTree.svg": "b39d593ea4774c1238ed6cd69f12b11f", "resources/theme/default/icons/mActionCommit.svg": "f354d7a233e4a5923580acbe25264d1f", "resources/theme/default/icons/mActionCommonNode.svg": "f2ab046d5257ee17f76363de01472e36", "resources/theme/default/icons/mActionComposeExport.svg": "53d0f2eaa80a97421ea812d32f5d9670", "resources/theme/default/icons/mActionConfigProperties.svg": "aa6aa2c381d8636a19e815a347831ed2", "resources/theme/default/icons/mActionConnectToFolder.png": "84a044edac968fdf06ecc30455f9b57d", "resources/theme/default/icons/mActionCopyMapImage.svg": "18260fca2fda975633899e07772ec225", "resources/theme/default/icons/mActionCreateDbConnection.png": "1194f60c3604a75a234b7c5829a9f623", "resources/theme/default/icons/mActionCreateInterNode.svg": "7d8cbee95202587a4593044f752438d2", "resources/theme/default/icons/mActionCreatePolygonBySnap.svg": "afd2ee4841eb4162f6d40825768359ee", "resources/theme/default/icons/mActionCreatePolylineBySnap.svg": "e80bb5083740e9bbf248b9ba3b28c988", "resources/theme/default/icons/mActionCreateProject.svg": "0d1f6ed64f39f7f3e3cacaeb376ac952", "resources/theme/default/icons/mActionCreateSpatialIndex.svg": "19063ef92e585e6b89139b95d8bc4ebc", "resources/theme/default/icons/mActionCurrentTask.svg": "37591573decfe551c7cb7418e2e8acad", "resources/theme/default/icons/mActionCustom.svg": "4f20d0450747420cbd2e9c9269193bee", "resources/theme/default/icons/mActionDatabase.svg": "5356e364576af2c38e4216283342db4f", "resources/theme/default/icons/mActionDataComparisons.svg": "05fd271af6c134f6872c80c489064d60", "resources/theme/default/icons/mActionDataExport.svg": "a4adf859430ab231122e24d6d6140459", "resources/theme/default/icons/mActionDataset.svg": "a06eea07e31055fe638120092fd03fed", "resources/theme/default/icons/mActionDataSource.svg": "899c06c28703ea8b15798c799a97cb02", "resources/theme/default/icons/mActionDataSourceManager.svg": "e265e51dc79a614afbba2d9a03eca71c", "resources/theme/default/icons/mActionDeleteAttribute.svg": "f487f09dcfad1b19da3cd46ff020c8aa", "resources/theme/default/icons/mActionDeleteBookmark.svg": "63a5159656718a85300368e95a87c965", "resources/theme/default/icons/mActionDeleteClassification.svg": "328e502956af43b1506928b8e03fc496", "resources/theme/default/icons/mActionDeleteClassificationCode.svg": "7cb7a62ac5e8be4028316c1c3e8836bc", "resources/theme/default/icons/mActionDeleteCustom.svg": "2c3e544e2be400c9f1fc224eb19baa6c", "resources/theme/default/icons/mActionDeleteDataSet.svg": "cf05da90c76989fe5796f0bfa9c69fd6", "resources/theme/default/icons/mActionDeleteDataSpecification.svg": "f4e03936c7564d14d752c7b9570726df", "resources/theme/default/icons/mActionDeleteDataTable.svg": "79ff705674f36ee519327ae6c51ae3d8", "resources/theme/default/icons/mActionDeleteDicItem.svg": "40f4b24ebc5ee91d2a05b715dc5ef94e", "resources/theme/default/icons/mActionDeleteLayer.svg": "10c565c23727bc79f0a3b3653c539e27", "resources/theme/default/icons/mActionDeleteLink.svg": "2d21c91ca791aed38b8135cf405fada5", "resources/theme/default/icons/mActionDeleteRange.svg": "f26af8d0a9917bb3d33bdbdd7665f2b9", "resources/theme/default/icons/mActionDeleteRevision.svg": "7f32ea7fb09ffa5851f57a64b548cf76", "resources/theme/default/icons/mActionDeleteSelected.svg": "27cc93f001805b310dd17a6cd761417f", "resources/theme/default/icons/mActionDeleteStyle.svg": "e8529586cd6c6c35725ae9ddf42678f8", "resources/theme/default/icons/mActionDeselectAll.svg": "acc58e9be78e0153b7d7d1ed921b6230", "resources/theme/default/icons/mActionDiagramStatistic.svg": "ba795b1a3c88b9ecc48bf3533793084b", "resources/theme/default/icons/mActionDicManage.svg": "5711827d34bf8c7f45bb9473339c9d5d", "resources/theme/default/icons/mActionDictionary.svg": "9f3227fd9fd4856b21ed0203f57d462e", "resources/theme/default/icons/mActionDictionaryManager.svg": "31af9da87c0ef66edf88279dc0979691", "resources/theme/default/icons/mActionDirectImport.svg": "2705f7d2b595f44bf7d41ba5469f8ecf", "resources/theme/default/icons/mActionDirectory.svg": "543010d3f4891a87337ea4a0553b6cc4", "resources/theme/default/icons/mActionDisperseLegends.svg": "44e0028546a1d892193bf85c1fc9ee68", "resources/theme/default/icons/mActionDownloadData.svg": "73cf487f43c6c67708755c77d1031b16", "resources/theme/default/icons/mActionDraw.svg": "79d6fde375c1d3a7c8be1e8ec5fc02d2", "resources/theme/default/icons/mActionDrawAnnotation.svg": "1ead0a1082e9fbae833bcfdd520f1f6f", "resources/theme/default/icons/mActionDropSpatialIndex.svg": "b22f1baf81a17fdc104b1bf05fd5c5ca", "resources/theme/default/icons/mActionEdgeTool.svg": "e51484e30111c77e3f34a0e367340041", "resources/theme/default/icons/mActionEditConnection.svg": "b0f644dd694a0c6554d1e1dcac139845", "resources/theme/default/icons/mActionEditCopy.svg": "83c8c2506e3d53b1b0b7865d1873a633", "resources/theme/default/icons/mActionEditCut.svg": "23ce1b2d297515aefe2dea9533184fab", "resources/theme/default/icons/mActionEditPaste.svg": "e59391b2630274e267ad10bb0a40a30d", "resources/theme/default/icons/mActionEditPolyline.svg": "4a3413a2c400b402733577b00c4e4a57", "resources/theme/default/icons/mActionEditSelect.svg": "20ed9f0380e99e271ccc04bf8590d084", "resources/theme/default/icons/mActionElementAlignment.svg": "da6e0b52d636403003a8bf06d81426bd", "resources/theme/default/icons/mActionElementOrder.svg": "9a4846b8d8c64c5a6b839fb5f5f2acab", "resources/theme/default/icons/mActionEmpty.svg": "7d03c7a62ba3b69a498063a52e7a0480", "resources/theme/default/icons/mActionExpandAll.svg": "5ce3b9872728fe1ab2db08881b6696e0", "resources/theme/default/icons/mActionExpandTree.svg": "8df56726928510b542d479f9d65bf2a4", "resources/theme/default/icons/mActionExport.svg": "9262fbccd6dce910b05542130d5b5d3d", "resources/theme/default/icons/mActionExportFont.svg": "fc19d534b16e7e87d74304dc9206913d", "resources/theme/default/icons/mActionExportGeometry.svg": "490f60da490788568dfcc1fb3ab8d57a", "resources/theme/default/icons/mActionExportPDF.svg": "7079bf9f8c4d4ef7ebf3fc26895c651a", "resources/theme/default/icons/mActionExportStyle.svg": "c3ebc4b4d9eef274c460e40db01734e1", "resources/theme/default/icons/mActionExtensionIntersect.svg": "b2b45155b3775a6082f0432db8667476", "resources/theme/default/icons/mActionExtensionPolyline.svg": "e5fdd4473d3a496bd3a0e67dfafc9902", "resources/theme/default/icons/mActionExtractFeatures.svg": "d756e45f408817a284947e1dc2015564", "resources/theme/default/icons/mActionFastScan.svg": "4a055d8089b712ba73b61939c3248f14", "resources/theme/default/icons/mActionFeatureClass.svg": "12960e7e5a7abafae89f6c75fe250172", "resources/theme/default/icons/mActionFeatureImport.svg": "bc1bf048cb86d53ee263523e8d49a33e", "resources/theme/default/icons/mActionFieldAssignment.svg": "55face7af26423b494df7490d9c9a1ef", "resources/theme/default/icons/mActionFileExit.svg": "014da3686c1d21b0df59f2b6d70e5a69", "resources/theme/default/icons/mActionFileNew.svg": "359e36e8c6e7793d550a4050765a169d", "resources/theme/default/icons/mActionFileOpen.svg": "d80181aaa8aa890cb0b7e48319a8d085", "resources/theme/default/icons/mActionFileOpen_small.svg": "e2471acb5d431a1203fe3c3956a4db79", "resources/theme/default/icons/mActionFileSave.svg": "68f08f30bdd326df72b092be223a0d70", "resources/theme/default/icons/mActionFileSaveAs.svg": "9836c3f4771b653b1ee967cae793b742", "resources/theme/default/icons/mActionFillHoll.svg": "7ef3bcc1919ef6f9f132ece12e007827", "resources/theme/default/icons/mActionFilter2.svg": "3ec913bd01c74a188cb4c055fbc03c14", "resources/theme/default/icons/mActionFlash.svg": "9bfe496e74b6e9a43be5908d499af2be", "resources/theme/default/icons/mActionFoldAll.svg": "740369ae0104d790e9d5fd18edd3f159", "resources/theme/default/icons/mActionFolder.svg": "1d4ea7410800af4f5b979135c4d14529", "resources/theme/default/icons/mActionFormView.svg": "f7e61b110fffd58a3803cba75c95aa40", "resources/theme/default/icons/mActionFull.svg": "de410eb887d59537eb5a97991fc1eebd", "resources/theme/default/icons/mActionGJB50000FFT.svg": "26fd67a57ea8dbbf034212047cd73c2e", "resources/theme/default/icons/mActionGoto.svg": "4cc2023f7b3f7813af02c1bcaf11ef9d", "resources/theme/default/icons/mActionGrid.svg": "305cb21216f9e8638e5521ba83f54ff2", "resources/theme/default/icons/mActionGridCheck.svg": "5cd471cd29ff479f87c6aac170c2c117", "resources/theme/default/icons/mActionGroup.svg": "30e60e1533289e2052cf4928583757c8", "resources/theme/default/icons/mActionGroupLayer.svg": "71a8905d793790d9303f2d32815c9079", "resources/theme/default/icons/mActionGroupLine.svg": "a3f83d7e3afba41c961550d99ef97136", "resources/theme/default/icons/mActionHelpContents.svg": "dfcc6f3e7a95c9fa377a24306877dda6", "resources/theme/default/icons/mActionHideAllLayers.svg": "16f373cad1b7b644477951a7ed66351b", "resources/theme/default/icons/mActionHidenFromBrowser.svg": "d38d6063e070d2d61dd6f55713896ab9", "resources/theme/default/icons/mActionHideResults.svg": "3eaa5c01dc7b1bacd0a6e5db58d1fdeb", "resources/theme/default/icons/mActionHideSelectedLayers.svg": "9d5f022d1375227b18a4fe01c6bcdb30", "resources/theme/default/icons/mActionIdentify.svg": "752e8589c7c43e261247a04eebfd130d", "resources/theme/default/icons/mActionImport.svg": "eccb61c61f90c7dd5be6f82059c499c1", "resources/theme/default/icons/mActionImportGeometry.svg": "18642deca79e43f652442d195b59fca3", "resources/theme/default/icons/mActionInspect.svg": "4f20d0450747420cbd2e9c9269193bee", "resources/theme/default/icons/mActionInverseCheck.svg": "9115eb0e5c06d728cf83af898f4a3f79", "resources/theme/default/icons/mActionInvertSelect.svg": "8f2be589133713a5d3ff36e50c1f01c0", "resources/theme/default/icons/mActionInvertSelectedLayers.svg": "9752a3091fe12e8fa6c6c07a53eb96b4", "resources/theme/default/icons/mActionInvertSelection.svg": "6149896f7ea1dbdade1677b31fcf5016", "resources/theme/default/icons/mActionLabelManager.svg": "d5d5d38222a6f64eca412317a25f962f", "resources/theme/default/icons/mActionLayer.svg": "f156bfe69e1e2508e5f0bf15db9ba44e", "resources/theme/default/icons/mActionLayerClassification.svg": "6aec85cd21332ccce4de83dcbc78a0c0", "resources/theme/default/icons/mActionLayerManager.svg": "add1fed077998d1e15ea21b0476024a9", "resources/theme/default/icons/mActionLayerSaveAs.svg": "baf726688146979e6d52548de7214a3d", "resources/theme/default/icons/mActionLayerSaveAsFile.svg": "b17ac7d94a0994f542a783cf8fb0d33b", "resources/theme/default/icons/mActionLayersOverview.svg": "4813c1d18f037f63dae432d4ef253cfe", "resources/theme/default/icons/mActionLayerTreeView.svg": "be643367e7ffd5de10d0dcb108e4c3a1", "resources/theme/default/icons/mActionLayout.svg": "28f9190ac68a00b0d7f6e04170d31cee", "resources/theme/default/icons/mActionLayoutManager.svg": "31be4d584dfc1ccafd8d01cdcd164fc8", "resources/theme/default/icons/mActionlinkage.svg": "b3ce4171038f9d82c8d04ea9cb3ad2d0", "resources/theme/default/icons/mActionLoadData.svg": "684e514f1cff1d2c9e95dd55a858df9f", "resources/theme/default/icons/mActionLoadLayerFile.svg": "f305a0ff3392689c805ce7984044289c", "resources/theme/default/icons/mActionLoadProjects.svg": "65d677b31784876d2af6e7c1fbf57b8a", "resources/theme/default/icons/mActionLoadRevision.svg": "874fed75579a074e530d87b91ad2ff07", "resources/theme/default/icons/mActionLocate.svg": "52f9968f5e0a6392c5f0a58db02b0825", "resources/theme/default/icons/mActionLock.svg": "26131931765f2aec7cc4bd0443f8f2ac", "resources/theme/default/icons/mActionLog.svg": "155acdfdf0f50cc1488483bb2eb844c1", "resources/theme/default/icons/mActionMaintain.svg": "ba47b24e4af73b927909cc5348f7bec8", "resources/theme/default/icons/mActionMaintainBSM.svg": "7acf0cf2e793fb29050771698c22b2e3", "resources/theme/default/icons/mActionMapsheetManage.svg": "1fd72e8c7b4d1b68cdfc45b6a1587ffc", "resources/theme/default/icons/mActionMapsheetNode.svg": "45219d3849e361f574ca86fcda80b3a1", "resources/theme/default/icons/mActionMapStyleManage.svg": "cf9354021a4a5b26ad660525ece1edff", "resources/theme/default/icons/mActionMeasure.svg": "a62f37b1ec481f1c2bab829f83849396", "resources/theme/default/icons/mActionMeasureAngle.svg": "5edcf784a0e8807d14944cce68a1a014", "resources/theme/default/icons/mActionMeasureArea.svg": "3ccde2a2802aac9ed7677d5c92bb3a0c", "resources/theme/default/icons/mActionMergeFeatures.svg": "58fca120fbe1d8ed6fd3a2dee1f90422", "resources/theme/default/icons/mActionMiddleLine.svg": "30f0034bc7c043e397e3f2ddc0ffc345", "resources/theme/default/icons/mActionMirrorTool.svg": "786dda30a600b3326b3ae42402dc443e", "resources/theme/default/icons/mActionModifyElements.svg": "59d8bbab970228ddbf2537c23da41ed3", "resources/theme/default/icons/mActionMosaic.svg": "34c034a1e13abe0d007225fbded76d7a", "resources/theme/default/icons/mActionMoveDown.svg": "e69d25c8b849110e43023f18f68c0bcd", "resources/theme/default/icons/mActionMoveElementBottom.svg": "5c963ec211036b7012aaab490bcb3741", "resources/theme/default/icons/mActionMoveElementDown.svg": "ed84988b86b920d732c1cc2c922e52a8", "resources/theme/default/icons/mActionMoveElementTop.svg": "8d5251c95c7b8b51c06719aed5991511", "resources/theme/default/icons/mActionMoveElementUp.svg": "0f2bae29c5c6a245ef7a1ef79d01d970", "resources/theme/default/icons/mActionMoveFeature.svg": "46a3b71b7e3282a07bcc8fe11a20916f", "resources/theme/default/icons/mActionMoveUp.svg": "c09793cc8b982dfc7160ca61174aa3af", "resources/theme/default/icons/mActionMoveVertexTool.svg": "fd8cdb5ff4b54efded668628786520da", "resources/theme/default/icons/mActionMultiEdit.svg": "1b4e305d58dbf3793eab33d6b474c28a", "resources/theme/default/icons/mActionNetworkStorage.svg": "e62bba269bce3c8ea8c4cf96e11bdd7c", "resources/theme/default/icons/mActionNew.svg": "c04a77f3fadc8f682577a4a1ffa31ea6", "resources/theme/default/icons/mActionNewAttribute.svg": "286fff33a3eb371889d740ae643cf9c4", "resources/theme/default/icons/mActionNewBookmark.svg": "5b5885cbdcefd11ac0e9d54461cfd914", "resources/theme/default/icons/mActionNewConn.svg": "4113d50441e7461c420e93a0b59d9bbf", "resources/theme/default/icons/mActionNewDataSpecification.svg": "c9c120156d64453162f017b2a4abbee7", "resources/theme/default/icons/mActionNewFileGdb.svg": "f5721d9a6558d415f3a67c63b78a95cc", "resources/theme/default/icons/mActionNewFolder.svg": "d7afc17f864be5b81aae706f5bb9141e", "resources/theme/default/icons/mActionNewMapElement.svg": "6566f4e1671d310ab3ed30117c44e5ef", "resources/theme/default/icons/mActionNewPKG.svg": "4156b6fbf9e9a09e8889e1ae0b0330e4", "resources/theme/default/icons/mActionNewSchemeData.svg": "7807bb77c398afb16afd46463672f893", "resources/theme/default/icons/mActionNewTableRow.svg": "f2fd0ead19625b325f33359e6f12a55f", "resources/theme/default/icons/mActionNewTask.svg": "7618baf3704550ed1ae0505eb74d1037", "resources/theme/default/icons/mActionNewTileClass.svg": "0166b686d417d0a81b5ae5b1791b4169", "resources/theme/default/icons/mActionNodeDiluting.svg": "6a864c4a9ce1fdd07ba68f132c980643", "resources/theme/default/icons/mActionOpenData.svg": "8cdca77f195e267228b878d1d7d82fe4", "resources/theme/default/icons/mActionOpenDirectory.svg": "d37744c14f87326d779ce634086a4a9b", "resources/theme/default/icons/mActionOpenJS.svg": "de439993a9ab1770b8e2fb17f5a8d0e1", "resources/theme/default/icons/mActionOpenLayout.svg": "da607b272ab28493f7b354a684388bae", "resources/theme/default/icons/mActionOpenScheme.svg": "781accf4794f648dcf2f8c4097ff8fa7", "resources/theme/default/icons/mActionOpenTable.svg": "b1bdd4c59286ff406b8262f1b61d54e2", "resources/theme/default/icons/mActionOptions.svg": "50f9ee8b59e5e364ba52222d2c55a8fb", "resources/theme/default/icons/mActionOraganizationManager.svg": "d386d4dc75ac892a620c5f726295214e", "resources/theme/default/icons/mActionOverView.svg": "c8df9418bb2d3606aa53e30ab4daa93f", "resources/theme/default/icons/mActionPan.svg": "98a5dbf4184531ba2a2c68db92806456", "resources/theme/default/icons/mActionPanToSelected.svg": "974a9cf2f5750b418b474942b5dcb2a1", "resources/theme/default/icons/mActionParamSetting.svg": "10cb60a011e7788aac961c212e1c8608", "resources/theme/default/icons/mActionPolygonIncise.svg": "2d82c0b0f5739c6bf787c4eab8064a6a", "resources/theme/default/icons/mActionPolygonInterattraction.svg": "622f8a50bc5ceb068e484420b9241020", "resources/theme/default/icons/mActionPolygonOverlay.svg": "95411d192cad3e679a01556a44ba29d5", "resources/theme/default/icons/mActionPolygonToPolyline.svg": "22b2360fe102a0c1d93c7c387aa86026", "resources/theme/default/icons/mActionPolylineToPolygon.svg": "c08885aa366dc2ec78104616d564ec31", "resources/theme/default/icons/mActionPreprocessingScheme.svg": "2cce25bc39ad3c0e64e4ede8a7dbf790", "resources/theme/default/icons/mActionPreprovessingTB.svg": "f8c7613e852b0c9af5f8e3038fd4b73f", "resources/theme/default/icons/mActionPrint.svg": "31c995fa5d814d9746b94d0e3780260b", "resources/theme/default/icons/mActionPrivilegeManager.svg": "d406a3ea8e70ac6188f7ff6cda412fdf", "resources/theme/default/icons/mActionProperties.svg": "643c2dbf159641c13a90dd282c750b66", "resources/theme/default/icons/mActionPropertiesWidget.svg": "7b8bdc3ad81fe89c339754370467ef05", "resources/theme/default/icons/mActionProperty.svg": "0f5fd9de9f38273462de2ef945b9a3ca", "resources/theme/default/icons/mActionQgsAddView.svg": "77154a2bd7a278ec5417f54bea869039", "resources/theme/default/icons/mActionQueryByLine.svg": "100a77b190342c4f4d612d2f4db8964c", "resources/theme/default/icons/mActionQueryByPoint.svg": "15630a334591356d90a90216319a3d48", "resources/theme/default/icons/mActionQueryByPolygon.svg": "6a70cc390d0f99105123a68aac36ee17", "resources/theme/default/icons/mActionQueryRoot.svg": "f442d02fb5ef3741fdf1624a3f02f5d7", "resources/theme/default/icons/mActionRasterImport.svg": "2417938f794ce78543633dc544bca4d0", "resources/theme/default/icons/mActionRedo.svg": "8c028f9ef70e474d7387f9b460a65eb6", "resources/theme/default/icons/mActionRefresh.svg": "52fa4b4278264c367eda284c53d15f89", "resources/theme/default/icons/mActionRegionExport.svg": "845dd15fd40ad4f743623469b5b3fdb4", "resources/theme/default/icons/mActionRegionImport.svg": "8dbd184a3b428ce6e102f7056e116f8b", "resources/theme/default/icons/mActionReload.svg": "43784ed0de3112c14d5921b6303d63a3", "resources/theme/default/icons/mActionRemove.svg": "e6754b6e1d730a5c882c2db92eea2950", "resources/theme/default/icons/mActionRemoveAllLayer.svg": "a6da6d6063b7329140356336a91090cf", "resources/theme/default/icons/mActionRemoveLayer.svg": "1c49ecbc2147eba97ec8aad9633f7ccd", "resources/theme/default/icons/mActionRemoveRepeatData.svg": "95b636aa514362fb03154a017f8eadc9", "resources/theme/default/icons/mActionRemoveRepeatedPoints.svg": "f3559b1f0ead7a72c40d87131c92acd8", "resources/theme/default/icons/mActionRemoveSchemeData.svg": "9194bf7bea36f62dc7dc2f3b30b90cbc", "resources/theme/default/icons/mActionRemoveVertexTool.svg": "8ae82b51d34a411968de1a9d97307367", "resources/theme/default/icons/mActionReName.svg": "2f4f8cbcf71196f22f219881f3e971d4", "resources/theme/default/icons/mActionReset.svg": "741f7fb42d42849d612fc20b12b7cd35", "resources/theme/default/icons/mActionResetDirPath.svg": "c344596ea4ddfc767152bdeb7c02ed27", "resources/theme/default/icons/mActionResolveSharePointError.svg": "f59d218ed27b3d3e93b66853590a8e94", "resources/theme/default/icons/mActionResultExport.svg": "e05fe9e6f120fff6f9fe567427d73eae", "resources/theme/default/icons/mActionResultPreprocessing.svg": "d915ed03dcd61c0d516c76a4b87d0aa4", "resources/theme/default/icons/mActionReversePolyline.svg": "d55a0018bb397763cc96e462198fdbe2", "resources/theme/default/icons/mActionRevertToRevision.svg": "0392f2d180aee9d9365959f9245e265b", "resources/theme/default/icons/mActionRightAngle.svg": "4c55097541c57f3764ca125d0920ef85", "resources/theme/default/icons/mActionRotateFeature.svg": "3e22ce01e2c0c965d96fc17ccf57f686", "resources/theme/default/icons/mActionRuleManage.svg": "15482f473e3fe2874ab18f9f2e8fbadb", "resources/theme/default/icons/mActionSaveAllEdits.svg": "94a89bc9b11cb90a59fc8f044c0a5936", "resources/theme/default/icons/mActionSaveAsScheme.svg": "13d249919c23815a608a9ff5d28846d6", "resources/theme/default/icons/mActionSaveEdits.svg": "777486ea8c29a2a365dfe80977fa17c1", "resources/theme/default/icons/mActionSaveLayout.svg": "8b3789e6e0dd8223130b84000d3ed79f", "resources/theme/default/icons/mActionSaveScheme.svg": "4f281e045c96432fd1cd7a82ca6f606b", "resources/theme/default/icons/mActionScaleBar.svg": "537d6a364f6c093e6b585b7e049b29af", "resources/theme/default/icons/mActionScaleNode.svg": "50f99f8accdc8751b270032cb556b39f", "resources/theme/default/icons/mActionSchemeBatch.svg": "dc5b9b397f9281a476733882693b6c47", "resources/theme/default/icons/mActionSchemeFilter.svg": "717cb0048b15305a8cadd452718d340c", "resources/theme/default/icons/mActionSchemeFit.svg": "43ce16a7914f0ed136fb52182040b068", "resources/theme/default/icons/mActionSchemeManage.svg": "c3514670076c47f378bf24f59d007e43", "resources/theme/default/icons/mActionSchemeNoFit.svg": "ddb52d6845b46bb2da8f44d6515c48ad", "resources/theme/default/icons/mActionSchemeShow.svg": "bd93bfc5885d5307f38203892ee44ef2", "resources/theme/default/icons/mActionSchemeSourceManage.svg": "49f8d190098edf63f5afa2a4fcb1b343", "resources/theme/default/icons/mActionSchemeTargetRoot.svg": "4c51b15a288a6857cb595ca87badc50d", "resources/theme/default/icons/mActionSearch.svg": "c53fee0f34c42a7a9d8e898532a3b86d", "resources/theme/default/icons/mActionSelect.svg": "af097cfbf7068555e0316d56705f153a", "resources/theme/default/icons/mActionSelectAll.svg": "05fe2f51d3089764d072f9ace468d8b4", "resources/theme/default/icons/mActionSelectAllLayers.svg": "fc3274b291accf2f3c94e7b6d21b496d", "resources/theme/default/icons/mActionSelectPolygon.svg": "de8682bdb5e3b611224a6ee8b52515ab", "resources/theme/default/icons/mActionSelectRadius.svg": "06c743aeea2546796c169625cdbfeb0c", "resources/theme/default/icons/mActionSeparateFeatures.svg": "47a255fe5cc8c8cd23a512e458ccf01a", "resources/theme/default/icons/mActionSeparateLayer.svg": "dca40eff33ddc48a7c0a1221c0aae739", "resources/theme/default/icons/mActionServer.svg": "1ab2380a5b5e7915e80d6b7f232d3bd2", "resources/theme/default/icons/mActionSetBottom.svg": "efce405a42a008cf74a9663e46362ab0", "resources/theme/default/icons/mActionSetClipEnv.svg": "cfc446c1a8ce1801fb3682f4caf2185b", "resources/theme/default/icons/mActionSetClipPolygon.svg": "0fc055217ef4255c7e588f08e3edf780", "resources/theme/default/icons/mActionSetDataSource.svg": "92fea7f7b80c74bb4f22cbedbd160e81", "resources/theme/default/icons/mActionSetNoClip.svg": "729fd670d5e947741b64c6ed7ee385b7", "resources/theme/default/icons/mActionSetNull.svg": "33deea05fa20968c10a0c3123e47c0d6", "resources/theme/default/icons/mActionSetSpatialReference.svg": "64f9c175f0e21d1128c10aa08dbcad85", "resources/theme/default/icons/mActionSetting.svg": "2c6d37e1466939c8e16f1cd04ff48d24", "resources/theme/default/icons/mActionSettings.svg": "98160adbf1b7bc7dfa0064d5da680278", "resources/theme/default/icons/mActionSetTop.svg": "57517e5161ba671327848c4c2495ce56", "resources/theme/default/icons/mActionSharing.svg": "8f5e6dffd6231a6858fc5f56ce1a60b2", "resources/theme/default/icons/mActionSharingExport.svg": "10de78f4fe80a0cef1a3609dd40a67f0", "resources/theme/default/icons/mActionSharingImport.svg": "9bed0a42714abdd71b65742d1ca1b26b", "resources/theme/default/icons/mActionShowAllHide.svg": "f6dea326e1c06484a7dbaa3a1c2313fe", "resources/theme/default/icons/mActionShowAllLayers.svg": "1069904cfba0dbc27c02e6659bacbc49", "resources/theme/default/icons/mActionShowBookmarks.svg": "18aa642ffd432316af2e4410f4b29d7d", "resources/theme/default/icons/mActionShowFilter.svg": "ace4d7974edfb60aca730fd5095c3259", "resources/theme/default/icons/mActionShowGridTool.svg": "682e24e73864e87cfdb33e9bd3e9809f", "resources/theme/default/icons/mActionShowLayersSet.svg": "2ac82d593bce15962b546a4aebe8fe48", "resources/theme/default/icons/mActionShowPluginManager.svg": "99436035696bb2cb8f10f5c098c4b44f", "resources/theme/default/icons/mActionShowResults.svg": "f56c5cd78219b41cd930774bb121024b", "resources/theme/default/icons/mActionShowSelectedLayers.svg": "a838ae1987783d19767e54228de05aa1", "resources/theme/default/icons/mActionSimplify.svg": "9c03c4c49fcd354e04832dd253c880a1", "resources/theme/default/icons/mActionSmoothTool.svg": "707f96d7e602170da613f80b679c8905", "resources/theme/default/icons/mActionSpatial.svg": "bef0b6a230ff89396636be69e8b40ef7", "resources/theme/default/icons/mActionSpecialAttributeBrush.svg": "24fc0d1c64c25fe84b8b2cfe896141cd", "resources/theme/default/icons/mActionSplitByPolygon.svg": "538583d5099e9abc25d5b1a9268e10e7", "resources/theme/default/icons/mActionSplitByPolyLine.svg": "8701b4efde0bae3ed46376ef173e4787", "resources/theme/default/icons/mActionSplitBySelect.svg": "26580003f206a37877bd8d4fb7c7e83a", "resources/theme/default/icons/mActionSplitFeatures.svg": "58f0d4717c6590d5116d6c4e3cf6661a", "resources/theme/default/icons/mActionSql.svg": "19852025b86712876a6f8722151414af", "resources/theme/default/icons/mActionStartCheck.svg": "36f7176cf331fccd0b34d63d0ea1330a", "resources/theme/default/icons/mActionStartImport.svg": "c6016f45b0af8a4852c51b94390c8226", "resources/theme/default/icons/mActionStreamline.svg": "e5cbf8db4c102b2afb6c8231f59b5c17", "resources/theme/default/icons/mActionStyleView.svg": "730e0af4ddac5a0fb1f5f539fd30622b", "resources/theme/default/icons/mActionSum.svg": "d017046d48ce90ed5bceab7d3e6d6f1f", "resources/theme/default/icons/mActionSwipe.svg": "12847b35a09965af255f83f9b227e3f0", "resources/theme/default/icons/mActionSysSwitch.svg": "34367f856ddc6239e12d778c5a19b816", "resources/theme/default/icons/mActionTableImport.svg": "8deaa47f6625c021e0fe3236c1d7b94d", "resources/theme/default/icons/mActionTaskManage.svg": "970769a0f3cd8be7dd294a765ab2187e", "resources/theme/default/icons/mActionTeamConfig.svg": "e84b0043b2cb13f560f94a0d6721e07c", "resources/theme/default/icons/mActionTeamEdit.svg": "b0114a6fc46120440e19c53730a0581c", "resources/theme/default/icons/mActionTeamProjectInfoStatistic.svg": "3129a2940c9803c5ca6ba12bef78cb00", "resources/theme/default/icons/mActionTeamRevisionSlider.svg": "5f1ab9a8ba1f48f0fcb3cfd5984862cc", "resources/theme/default/icons/mActionTeamServer.svg": "fecca577325287d69541a40ded17fadb", "resources/theme/default/icons/mActionTeamTimingAcquireLog.svg": "48487ce93bfd8cd3d0aa77a2c26ce9cd", "resources/theme/default/icons/mActionTeamTool.svg": "fc55777995fd4de917463da7c9f5424b", "resources/theme/default/icons/mActionTemplate.svg": "01927217e00be004e12f16b651440359", "resources/theme/default/icons/mActionTemplateCompose.svg": "af1adc1a48861d24dc688b9778d3d80e", "resources/theme/default/icons/mActionTemporaryLayer.svg": "68e4b5c61088a15f89d939c81ff86b87", "resources/theme/default/icons/mActionThematicAttributes.svg": "6b6ee135eedc395c6eb8e04b92a5cab0", "resources/theme/default/icons/mActionTileImport.svg": "903e13e6c35e1ee083a61b23918688de", "resources/theme/default/icons/mActionTiling.svg": "c8e25a3eda0bc19b9778168ecf753375", "resources/theme/default/icons/mActionTimeSlider.svg": "30df8efe796c12114471323077bca30c", "resources/theme/default/icons/mActionTimingAcquire.svg": "489dd9a97dffb720b3162dc14bc86a9e", "resources/theme/default/icons/mActionTimingAcquireSetting.svg": "7ecabd8416d95df2f92da8ff60d44da9", "resources/theme/default/icons/mActionToggleEditing.svg": "29723b6d47441f7bb494714ea429edde", "resources/theme/default/icons/mActionToolBox.svg": "2c9169fc1c7e50f15b84f71bafd17a6d", "resources/theme/default/icons/mActionTrim.svg": "225c5b9cc91e4f5e8ca4aaf8787780c6", "resources/theme/default/icons/mActionUndo.svg": "ec0a88d3076c323ae59118eca56b8163", "resources/theme/default/icons/mActionUngroup.svg": "7bc078804d80699dc8cc91e2082f84d4", "resources/theme/default/icons/mActionUp.svg": "7999c9a02eda90ac2f42b6c3641e904b", "resources/theme/default/icons/mActionUpdate.svg": "40ba9725c8cdd5e1fe69108bb6f8525d", "resources/theme/default/icons/mActionUpdateRecords.svg": "5a46d098c69fbf39923ffe3178018278", "resources/theme/default/icons/mActionUpdateToRevision.svg": "80e6f808eeb64d71829e44a827b9b51f", "resources/theme/default/icons/mActionUploadData.svg": "4817a531daa8606bc9531d50957971c6", "resources/theme/default/icons/mActionUserRoleManager.svg": "e3e59465ff0ccfc907414df8628b5723", "resources/theme/default/icons/mActionVertexTool.svg": "daa8e981408b835ddbe36af3bed62e19", "resources/theme/default/icons/mActionVTSPreview.svg": "f9c9643fd1b174e56abae7e8a5ffe7ba", "resources/theme/default/icons/mActionWeldPolyline.svg": "35c012816b7f000837e465109dcb1f95", "resources/theme/default/icons/mActionYearChangeNavigation.svg": "943edf66d680b0ee7fc4a2d68504b6ab", "resources/theme/default/icons/mActionYearChangeRegression.svg": "b4f5be92104d693da3a88a817166c20e", "resources/theme/default/icons/mActionZoomFullExtent.svg": "6f21d610891d2924bcfe88c73fb764f5", "resources/theme/default/icons/mActionZoomIn.svg": "1042c451e38bbbdea2736329514618a0", "resources/theme/default/icons/mActionZoomInCenter.svg": "f02ed86aaccae6e9a97ecbb852a0b224", "resources/theme/default/icons/mActionZoomLast.svg": "5c42ac5098f8e0f648dbe3de9bb4bad8", "resources/theme/default/icons/mActionZoomNext.svg": "a9fa6a5c006dd0c0840aa4e1774de19d", "resources/theme/default/icons/mActionZoomOut.svg": "7a84e09a885a48b381d69d0b5d3ff69a", "resources/theme/default/icons/mActionZoomOutCenter.svg": "c84df5bb54c1fc4da3656025dd3bd6bd", "resources/theme/default/icons/mActionZoomToBookmark.svg": "9073facd9ee913217bed1c2093a4e098", "resources/theme/default/icons/mActionZoomToLayer.svg": "82c760fa362ccf923603a9ab657d737f", "resources/theme/default/icons/mActionZoomToSelected.svg": "e934636f2b504da8ab0e4e6d3e859bac", "resources/theme/default/icons/MaintainRegionDic.svg": "e220cc3e4c97e63296684f3d9e38d5f8", "resources/theme/default/icons/mapConfig.png": "f7b863779cc89c8be7605bc56a65703c", "resources/theme/default/icons/mapConfig.svg": "c7a0b74014cc0599c1e82c0c8b8be1f1", "resources/theme/default/icons/markdown.svg": "b1318f7383ab486afa82e4568aa58185", "resources/theme/default/icons/matlab.svg": "8d5f10b9fb25f9df14e71d6e4eda19a7", "resources/theme/default/icons/mAutoChangePolygon.svg": "4aed8b896926a1d832f64933d1257f52", "resources/theme/default/icons/mAutoCompletePolygon.svg": "3c11c43f10997872241c257e9987d46c", "resources/theme/default/icons/mComposeSchemeManage.svg": "d352afeceb179d2d645026aa873c5b92", "resources/theme/default/icons/mDataExportSchemeManage.svg": "a7e3c9f7ad828fb76c0cf4cfb13c097b", "resources/theme/default/icons/mDataImportSchemeManage.svg": "fc35fcdf359f9f81fa2ae510ab87c4c1", "resources/theme/default/icons/mDataTransSchemeManage.svg": "c9bf6fa291e4976bf0983bd5288934ab", "resources/theme/default/icons/measureConfig.svg": "903161e927f84e5613a6dd4c9922a1bd", "resources/theme/default/icons/merge_h.svg": "e18a2b6bbdb4a1e6d8a95644122e60d9", "resources/theme/default/icons/merge_v.svg": "a8527f6026fe7118c129f5cba6fb1016", "resources/theme/default/icons/metadata.svg": "b2e273799dbfa6dbc52e8228f5bdbdd9", "resources/theme/default/icons/mGeneratingDLJX.svg": "4c69197baf2338313faf3993d6b115e8", "resources/theme/default/icons/mGeoPackage.svg": "7c73ffb090a38af7feab29aa12152423", "resources/theme/default/icons/mIconAddDBServer.svg": "8c825e00c2816ab43183b541733d71f8", "resources/theme/default/icons/mIconAddServer.svg": "7112be64f8be6720026bc2a8bf9c625d", "resources/theme/default/icons/mIconAfs.svg": "26bc632ff2d7c289e202f6c8f61e1c03", "resources/theme/default/icons/mIconAms.svg": "630bac3c1a415087351fe6492e4bb83d", "resources/theme/default/icons/mIconAnalyseFlow.svg": "ea21512744b1a11c266e5b9d1520389a", "resources/theme/default/icons/mIconAnnotationLayer.svg": "fbe179641e24ec8c54a302265cca4f2f", "resources/theme/default/icons/mIconAnnotationMLayer.svg": "68d1aa7332c4c52ba3e969a14417ae19", "resources/theme/default/icons/mIconApplication.svg": "94bea3681edb4be10e23727c67923918", "resources/theme/default/icons/mIconApply.svg": "51876eb236913705ce2756c72b7fb49a", "resources/theme/default/icons/mIconAttirbuteAssign.svg": "b93e85f9184b920d402f862abf94357b", "resources/theme/default/icons/mIconAttributeTable.svg": "e7db893217b5b1baac3961b549108479", "resources/theme/default/icons/mIconAuxiliaryStorage.svg": "424505094deccde793bb07080494a9b1", "resources/theme/default/icons/mIconCad.svg": "fef13370469b1722e4dcc26d46a89f57", "resources/theme/default/icons/mIconCalEllipsoid.svg": "823474172c2ccec64f5adaee114fd82a", "resources/theme/default/icons/mIconCatalogResource.svg": "6c8e7c6dfd9c958328f27092fb00c3c3", "resources/theme/default/icons/mIconCatalogRoot.svg": "01afcfbe57ea1a4a90b6daf78af9a2a9", "resources/theme/default/icons/mIconChange.svg": "7cc1b16efb9fcf0c8144b9c1e86d258e", "resources/theme/default/icons/mIconCheckLayer.svg": "841eb956c21eb7f7557937b56648eea2", "resources/theme/default/icons/mIconClearText.svg": "f20b46fc4f835d7d636f97f1d7770c63", "resources/theme/default/icons/mIconClearTextHover.svg": "6bf93a9f31af24cc804503c71aadbfa7", "resources/theme/default/icons/mIconClose.svg": "7787829dfdddf0c0ff3306e96b5998fe", "resources/theme/default/icons/mIconCode.svg": "e6351f72e8d1f68207c574af6f6557ad", "resources/theme/default/icons/mIconCodeSpecifiation.svg": "e0a81b82fa77022b5850eb16a0382690", "resources/theme/default/icons/mIconCodingScheme.svg": "654f59de125796f54e270e6278e60d34", "resources/theme/default/icons/mIconCodingSchemeRoot.svg": "06c8ad7cf27e496674ed6bdc31db1ba7", "resources/theme/default/icons/mIconCompoundLayer.svg": "d1026c32abaa5a0591f7a5c7b693eac8", "resources/theme/default/icons/mIconConnect.png": "c4d29a2a304cc265c34def6e2a1cc7ed", "resources/theme/default/icons/mIconCritical.svg": "479fc5b611396c2c535a2bc18a808ef6", "resources/theme/default/icons/mIconDaMeng.svg": "74e85fd3c915ccc760b40a05f961bae5", "resources/theme/default/icons/mIconDataSet.svg": "cb718d909534dadd72d4b72dbddb1a4a", "resources/theme/default/icons/mIconDataStructure.svg": "fd89f1f6fae2b928a841aea919995f34", "resources/theme/default/icons/mIconDbSchema.png": "1b79c7357dd1f0e5eb1f4d47f759b4f6", "resources/theme/default/icons/mIconDelete.svg": "b7645486da851a6b3272d304f2a6dd86", "resources/theme/default/icons/mIconDeselected.svg": "75733116db9e219b0f4382385342b511", "resources/theme/default/icons/mIconDicItem.svg": "68e57fc565b36ae2e1d060ce6dc8c964", "resources/theme/default/icons/mIconEditableEdits.svg": "455990cd70b279a43e6fe1483ef47b3b", "resources/theme/default/icons/mIconError.svg": "affb8053194df39dda4f105433c209d7", "resources/theme/default/icons/mIconExportCatalogDataNode.svg": "66c846fd3b5f7a771e834b12555d546e", "resources/theme/default/icons/mIconExportCatalogFileNode.svg": "719a5a83513ddb084966a21c3909092a", "resources/theme/default/icons/mIconExportCatalogRootNode.svg": "51d5c34391a171eed24ebfc860fc710b", "resources/theme/default/icons/mIconExportSchemeNode.svg": "810c27933bac0c415bba59ad0e28619a", "resources/theme/default/icons/mIconExportSchemeRootNode.svg": "cd1a0f9d1adc73d30ad78f03e26e3125", "resources/theme/default/icons/mIconExpression.svg": "4a7c9010d4faef5cb7dd50d4b063bf1d", "resources/theme/default/icons/mIconExpressionSelect.svg": "d5a11b917f78b8963933e25463ed3f13", "resources/theme/default/icons/mIconExternApplication.svg": "76860ff954accd3d41779f1b13614a03", "resources/theme/default/icons/mIconFcs.svg": "842114c237df2e6488115f32bf6179a0", "resources/theme/default/icons/mIconFifthLevel.svg": "64fd05b7bc8fcc3d5613bff14477230b", "resources/theme/default/icons/mIconFile.svg": "3047ab35641e5516a3eb281bada2613a", "resources/theme/default/icons/mIconFirstLevel.svg": "411ddf0a99c68e8adf1c08389bd2ea10", "resources/theme/default/icons/mIconFolder.svg": "cf1ca6b8396b31dcca5b8f33eb43ceb4", "resources/theme/default/icons/mIconFolderCatalog.svg": "4eb1ba9a379ada6a5d6bdb205259bb04", "resources/theme/default/icons/mIconFourthLevel.svg": "638de27d6466f21ec317cb203840ae5d", "resources/theme/default/icons/mIconFtp.svg": "a199167e87d48e535a28a0f1bba7b62b", "resources/theme/default/icons/mIconFtpConnection.svg": "8a392e40f69a0f418fdbdd881165da08", "resources/theme/default/icons/mIconFtpFile.svg": "dd9f4404c69b29266260a9a9d8df269b", "resources/theme/default/icons/mIconGBase.svg": "fb1586a853c2904b60aaae867f76c85a", "resources/theme/default/icons/mIconGdb.svg": "faf3ba5fe031bfdce3aed9a3f46f078f", "resources/theme/default/icons/mIconGeoMap.svg": "5fddaa3bf5d340522608d62df060290f", "resources/theme/default/icons/mIconGeoModel.svg": "1062170310062340d8e756bf956bc804", "resources/theme/default/icons/mIconImage.svg": "d7d21b7fb0e283fcf8411c03f3e31845", "resources/theme/default/icons/mIconInfo.svg": "3c0cf72d3f29ee6108e7d408a9103694", "resources/theme/default/icons/mIconInnerLayer.svg": "8191e0d1b9834eec58a8ee696da1ceeb", "resources/theme/default/icons/mIconKingBase.svg": "8ad55c2113ceee058166bdd7da6fd468", "resources/theme/default/icons/mIconLayer.png": "21cf151b551b35eed6e034ed7112dbc0", "resources/theme/default/icons/mIconLayer.svg": "9540c68b59d83e5f407a81cb364fe39e", "resources/theme/default/icons/mIconLayoutTemplate.svg": "215df0affb2b3b0d8895161fcc9bdafa", "resources/theme/default/icons/mIconLayoutTemplateRoot.svg": "99d5dce6929dd587527835636b774346", "resources/theme/default/icons/mIconLineLayer.svg": "4c69197baf2338313faf3993d6b115e8", "resources/theme/default/icons/mIconLineMLayer.svg": "fe6b4178b48f8999d83c10155c1a0b0e", "resources/theme/default/icons/mIconLoading.gif": "8fa9058348a86d759eb315dd66de2714", "resources/theme/default/icons/mIconLocalServer.svg": "f890500950ee4e3e5468082e57eabcf9", "resources/theme/default/icons/mIconMapFile.svg": "627ca8d2c2c1796f646e9216d9349bea", "resources/theme/default/icons/mIconMapStyle.svg": "b6356008ed553c02b7a31e7be2b3289f", "resources/theme/default/icons/mIconMixCatalog.svg": "4eb1ba9a379ada6a5d6bdb205259bb04", "resources/theme/default/icons/mIconModelLayer.svg": "72f4b78bf3b06435aef0e06e5ca151e2", "resources/theme/default/icons/mIconModifyServer.svg": "c7d9ee62d4aa9720f2f15a3f22e86b3e", "resources/theme/default/icons/mIconMySQL.svg": "a99effe63b8a0afe08ca87c291451c6e", "resources/theme/default/icons/mIconNewGroup.svg": "e27402c3f3b6866ea996eff280c1329d", "resources/theme/default/icons/mIconNow.svg": "6a8ae624d3a553b4db8d03e60170fee0", "resources/theme/default/icons/mIconOffice.png": "6303c5abbdcdd3a24281007c3f75910e", "resources/theme/default/icons/mIconOracleSpatial.svg": "96b27c5bb382407c8fbb3f1d5cdfbb45", "resources/theme/default/icons/mIconOutsideLayer.svg": "2e84bf82fd9ba6d6d3b170ff227e43b7", "resources/theme/default/icons/mIconOws.svg": "861d35b91c66a25907dd731a522795fd", "resources/theme/default/icons/mIconPg.svg": "870e241bd22d89b83aa26e69b79e44d9", "resources/theme/default/icons/mIconPhysicalTable.svg": "62556fe79abc5c1aa1b139a4caab4f97", "resources/theme/default/icons/mIconPhysicalTenseTable.svg": "8495bd64272f9519ba3639bb108ce6a1", "resources/theme/default/icons/mIconPointLayer.svg": "95251fc052d089796b41a46072661ad2", "resources/theme/default/icons/mIconPointMLayer.svg": "3ace9ed797c1cd91848f6e75df4ce5cf", "resources/theme/default/icons/mIconPolygonLayer.svg": "da646fa3fef5ce81f9f0e9ace1d0be1e", "resources/theme/default/icons/mIconPolygonMLayer.svg": "b76b1c64744e78f711a6ed163b6fbf29", "resources/theme/default/icons/mIconPostgis.svg": "d95101a8f8b9eaa80083d646e5383659", "resources/theme/default/icons/mIconProjectionEnabled.svg": "820493124a75fe953400f9f2ceba9d34", "resources/theme/default/icons/mIconProperties.svg": "b57f75b3eccce67243c8143fc010f052", "resources/theme/default/icons/mIconRaster.svg": "a65c7579f3849569b88caa69d46d6d1c", "resources/theme/default/icons/mIconRasterGroup.svg": "b22c2b30b5b48777566a041b02ca20d7", "resources/theme/default/icons/mIconRasterLayer.svg": "37358bd2779dd20a7580a1b4b354913b", "resources/theme/default/icons/mIconRegionItemNode.svg": "0c892403655a142a739da4a445f10d69", "resources/theme/default/icons/mIconRegionNode.svg": "2b8d8fcdb3054ca0b50d165d76a0e529", "resources/theme/default/icons/mIconRegionRoot.svg": "a05b73abd59d65752a387c0887afeaa1", "resources/theme/default/icons/mIconRegionRootNode.svg": "b7b0001fe203a7c6e9bfaf88d2f2db4c", "resources/theme/default/icons/mIconRegionTree.svg": "981c3314204c6c2ddb53e50da0181732", "resources/theme/default/icons/mIconReload.svg": "4ee18f3e56c0a3ce09a1cc261ca9d12d", "resources/theme/default/icons/mIconRemoveServer.svg": "1644b9d1c6aa137862d1ae8788374b3e", "resources/theme/default/icons/mIconReportWizard.svg": "fc1234e9224f00f23323c50723568edb", "resources/theme/default/icons/mIconReserveSelection.svg": "8ab255dc5906d1cf88675446c3e09240", "resources/theme/default/icons/mIconResourceCatalog.svg": "4eb1ba9a379ada6a5d6bdb205259bb04", "resources/theme/default/icons/mIconRule.svg": "5115e07bbedf98741550b7db9dae61a4", "resources/theme/default/icons/mIconRuleGroup.svg": "99610d48d732d9f76ad9dd28fba1bb1d", "resources/theme/default/icons/mIconRuleRoot.svg": "013cdba55f00d20c4d9d1429a33d3981", "resources/theme/default/icons/mIconSave.svg": "5e0bcceceac29567885531806f0df5eb", "resources/theme/default/icons/mIconSaveAs.svg": "92eae31b2324f5a7b3fc959de7858a54", "resources/theme/default/icons/mIconSecondLevel.svg": "f830a82f170fdc417e8243e99f6463ef", "resources/theme/default/icons/mIconSelectAll.svg": "2c19a865fc8951dc6b0d76e03192fa57", "resources/theme/default/icons/mIconSelectNone.svg": "728e2fbb4f50cd340e739df3efa98505", "resources/theme/default/icons/mIconSelectServer.svg": "7a40c874356f04dfcf9dc16631b01e36", "resources/theme/default/icons/mIconServer.svg": "b037d88ce726e5e2e9022bcfccf1ab1d", "resources/theme/default/icons/mIconServerManager.svg": "db323ee83983521b1fe55d718137118b", "resources/theme/default/icons/mIconSetColor.svg": "04cd244f3efa35e3e49c3d15a41dfd8b", "resources/theme/default/icons/mIconShowStyle.svg": "82e6f287175dfa2492b04316a1001113", "resources/theme/default/icons/mIconShp.svg": "d4b18ad9e5808b63b022799c9b9ad7fe", "resources/theme/default/icons/mIconSixthLevel.svg": "e7553e75a3071065b15b6bcf2bdc8e96", "resources/theme/default/icons/mIconSnapping.svg": "63f355964cf029d5dcaf7181384b8762", "resources/theme/default/icons/mIconSqlite.svg": "aaa168559302aad794f38c3eba3bddd4", "resources/theme/default/icons/mIconSuccess.svg": "2d9a7e0389e29ef07f2f881f478acc57", "resources/theme/default/icons/mIconSystem.svg": "fa75b6702dfc9a38d955c4db45bce8de", "resources/theme/default/icons/mIconTable.svg": "21615bcc2dab3f7d81b36b7267d5c003", "resources/theme/default/icons/mIconTableLayer.svg": "f097c9a2709c4bb46a5c69edcaeb877d", "resources/theme/default/icons/mIconTableMLayer.svg": "3777b46cbf789491572e2ab6c3841384", "resources/theme/default/icons/mIconTense.svg": "a9506e8a7e783d03a27c777d50f639c5", "resources/theme/default/icons/mIconThirdLevel.svg": "1b82d2a307fc30d45b11ea616c7b5c10", "resources/theme/default/icons/mIconTile.svg": "b73d838ec69991e754f3cb8eb1f47366", "resources/theme/default/icons/mIconTileLayer.svg": "e65e45cc49d05e235d10096ad817fc82", "resources/theme/default/icons/mIconTimerContinue.svg": "cfd5c0fdbd6fdcd6a414dac9c092a633", "resources/theme/default/icons/mIconTimerPause.svg": "56f9fb6e1a8b29efb238c60c7abb2682", "resources/theme/default/icons/mIconTxt.svg": "2a5d39dfd28028ea033bbe28e5e5bfad", "resources/theme/default/icons/mIconType.svg": "652794ba38eacdf6364786d77e138b92", "resources/theme/default/icons/mIconValueRangDic.svg": "b5fbdf278321d22243dcc2a0dfa25e72", "resources/theme/default/icons/mIconValueRange.svg": "3656fff54e067f46659582350822c3bd", "resources/theme/default/icons/mIconValueRangeRange.svg": "2b8d8fcdb3054ca0b50d165d76a0e529", "resources/theme/default/icons/mIconVCT.svg": "9de1e1bdb8620f90226157e87ff08f35", "resources/theme/default/icons/mIconWarning.svg": "469d5f397cb89f1768473b9fc065cb1f", "resources/theme/default/icons/mIconWcs.svg": "d50746b54aaf55fe0f070cd61f42b589", "resources/theme/default/icons/mIconWfs.svg": "4bb63bff96c7076f1372a1a21fc746a3", "resources/theme/default/icons/mIconWms.svg": "ff83723069a766205aaeedbd335906dc", "resources/theme/default/icons/mIconWmts.svg": "ad3fe79ff517b26bf49f6ee5d6a31b17", "resources/theme/default/icons/mIconXYZTile.svg": "d0c0b73adfc969f20bf96165e9581276", "resources/theme/default/icons/mIconYearChangeDataInittail.svg": "53d895ee3af75bc504e52de69b648768", "resources/theme/default/icons/missing_value.svg": "864863c0054f6b72766d2f8a3e030f30", "resources/theme/default/icons/mLayerSaveAs.svg": "42e4a4ffc0342a7cc626cc2df0f4748e", "resources/theme/default/icons/model_selection.svg": "222c717feb5de2c675cfb7c85c41b9b4", "resources/theme/default/icons/modified.png": "430719999ef1aad4e546d47662f64a82", "resources/theme/default/icons/Mouse.svg": "87a75d7d8243dad6fd65d9815db3e7c0", "resources/theme/default/icons/mPolygonDifference.svg": "c7fcfd8353e8661aade6824f2f946878", "resources/theme/default/icons/mPolygonIntersection.svg": "8a8cef3083c30309df6946d6ccd660b7", "resources/theme/default/icons/mPubLayerRoot.svg": "5073514803a9dc01c5c70c3c18305ffc", "resources/theme/default/icons/mPubLayerSet.svg": "a64220d6ecb203571ef6f1d8b0bbe5c2", "resources/theme/default/icons/mPubLayerSimple.svg": "40a8f32e0ec29323c176effbab6a1199", "resources/theme/default/icons/mPyramidManage.svg": "f50928a886510ab2489f3875930c252a", "resources/theme/default/icons/mRefreshErrorStatus.svg": "07bf753129c84e7d476e939ee906c4cd", "resources/theme/default/icons/mReportExport.svg": "e4c0687252e51c27e8967b033352b09e", "resources/theme/default/icons/mReportSetting.svg": "9f12bcd4a448ceeed1ddfa07a289d712", "resources/theme/default/icons/mSourceFields.svg": "c29a122376138fa67964299e1cd554dc", "resources/theme/default/icons/mStartCheckProcess.svg": "1a43b916dc8effdee18fbc2126c77714", "resources/theme/default/icons/multieditChangedValues.svg": "fa2114de837cf105940390a270ca0fbb", "resources/theme/default/icons/multieditMixedValues.svg": "41e09b3a0af251bf17d9283b8f81a577", "resources/theme/default/icons/multieditSameValues.svg": "f280c0cd500fd7679b7bc4cc7abec436", "resources/theme/default/icons/mvectorlayercache.svg": "52656796a777dcd29c43e584de7e40ca", "resources/theme/default/icons/MySQL.svg": "b4b89c2f14fe912b9acc90c32f1b3dc8", "resources/theme/default/icons/nActionBasicStatistic.svg": "f58a64edfbcc2a499d017d021caa854f", "resources/theme/default/icons/net.svg": "01609ed2d769c8d7ad4c97460cac8f69", "resources/theme/default/icons/New post.svg": "0faf63c8a6a31411cfedca48447870cd", "resources/theme/default/icons/new.svg": "f39a9d36090c7cad6757b3621aea0dbf", "resources/theme/default/icons/newvectorfile.svg": "56abc8aa55c3e2143c78b52af8a364d9", "resources/theme/default/icons/new_project.svg": "3cd72c019015b461870f3ad6e871aca1", "resources/theme/default/icons/next.png": "ff36945b6427eb8226bec7fe2743af70", "resources/theme/default/icons/nextConflict.svg": "a086d4b6331680eeb568a4df98937305", "resources/theme/default/icons/non_versioned.png": "25ba46f98f7aee7477ffb7d7fc1a7d62", "resources/theme/default/icons/normal.png": "795d679579e414fd37489f552b604b94", "resources/theme/default/icons/numpy.svg": "f36ed6c85013eb6f6bb3e49a8a9ee713", "resources/theme/default/icons/open.svg": "200a281b71b9104332781e9eb2fcc6de", "resources/theme/default/icons/open_folder.svg": "4aac2ccabd5e0ee6afe3286e61b8c85a", "resources/theme/default/icons/oracle.svg": "62030f9604e445ac5ef6b9edc94da181", "resources/theme/default/icons/orderlayergroup.svg": "2dd8c13c7243f17d69087176d29ddbb3", "resources/theme/default/icons/overlay.png": "17f28aabcf682bbf6a22d0a80070b1ce", "resources/theme/default/icons/package.svg": "db8542fb863117d5d74f7a6676ab419e", "resources/theme/default/icons/pagesetup.svg": "b25656114dc0af77191a6d7b206c7e91", "resources/theme/default/icons/paste.svg": "02b0ecdb9e40d6e9a3a589be40ea0790", "resources/theme/default/icons/pasteElement.svg": "deede2c394febaf7818a5a74220adb58", "resources/theme/default/icons/pausefly.svg": "aec4d2aee5c1a96174b7d0efbb654d35", "resources/theme/default/icons/plugin-installed.svg": "715e5c20df916d7d0a959ef6a6efbc40", "resources/theme/default/icons/plugin.svg": "c5c2d3092b1c2958aae669b0ce891492", "resources/theme/default/icons/plugins.svg": "e04bad7db3b8435bff70fd5ebbebc369", "resources/theme/default/icons/postgresql.svg": "5c2c9989c1a23c934678119d55c088b8", "resources/theme/default/icons/previous.png": "af4d639c2ccefd5b57d4772e3cc3bb62", "resources/theme/default/icons/previousConflict.svg": "099b009a440d54790c0cda1d60842134", "resources/theme/default/icons/print.svg": "3ba6cb43288c30503450361636fae5aa", "resources/theme/default/icons/processingAlgorithm.svg": "5acd3a3ea3ac4302ebed7d35fc1f16ae", "resources/theme/default/icons/project.svg": "72a57d9485a1a0a78e977a2f472e2213", "resources/theme/default/icons/projectDataTree.svg": "23c638ad38fe4f0dc6a4661730f24081", "resources/theme/default/icons/providerQGeomap.svg": "2c9169fc1c7e50f15b84f71bafd17a6d", "resources/theme/default/icons/pypi.svg": "6b9ea3945cf090b33076ea91ce2e9612", "resources/theme/default/icons/pypi_color.svg": "aefe42c944201ae3a898d71d5ec62075", "resources/theme/default/icons/pyramids.png": "051b61faa344c78af9a059e9cfc78dae", "resources/theme/default/icons/python.svg": "cdf88def02be5b2ce0e4c40b89d2c6ce", "resources/theme/default/icons/python_gray.svg": "b0b260fbbaa0b24915e46e80a5d7af9d", "resources/theme/default/icons/qgeodataspecificationmanagertool.ico": "c86f314e1777d0e7541709d50f9d726c", "resources/theme/default/icons/R.svg": "c27cc0791576e0ca3616b76731907b9e", "resources/theme/default/icons/reduce.svg": "1e88d456b31261ed99c18414a5c47671", "resources/theme/default/icons/regression.svg": "ea2efc714a40dfba39ecbd5218268fa6", "resources/theme/default/icons/remove.svg": "a6328dbd354bd5965aae818d26b273da", "resources/theme/default/icons/removeElement.svg": "7f477ed033b711e6e3b96f9bf22c79e1", "resources/theme/default/icons/rendering.svg": "55bdf00e277bc65c5639e48f8d9f42d2", "resources/theme/default/icons/replace.svg": "fbba9c3ecb7acb6dc76d5fc36cb03302", "resources/theme/default/icons/resolved.svg": "4a3f747ccc1459e54666994682080e38", "resources/theme/default/icons/ribbonMaximize.png": "e5dc4278826e32c25a4723fc87b943b2", "resources/theme/default/icons/ribbonMinimize.png": "42094d61d30e8a72a1a2cbff7a0df598", "resources/theme/default/icons/right.svg": "5dca8df9c3b66d4d1449494b34f936fe", "resources/theme/default/icons/roaming.svg": "4db76c4b080e95322cde6b52d36cfcfb", "resources/theme/default/icons/rubberBandConfig.svg": "9dd7c66dd566eaabd42ab2edd443654c", "resources/theme/default/icons/run.svg": "ec156027329d2c13877625ff3fcbee01", "resources/theme/default/icons/sample.svg": "59c88431eeb5015338430a9b7d1be8c5", "resources/theme/default/icons/sas.ico": "c4c83c2060701e0389262d9d07362896", "resources/theme/default/icons/save.svg": "89eafd6a566e859840d717e73872df13", "resources/theme/default/icons/save_layout.svg": "de4fd322d23ce467c2d30c2f2cb4fec0", "resources/theme/default/icons/scale.svg": "6b074bd9946d667c2f3e6502e634ecd2", "resources/theme/default/icons/scaleAdd.svg": "1724ab174f6709f9485d555a2d372639", "resources/theme/default/icons/scalebartext.svg": "1c6d5b3e2d85f1cbfb7305ebc7c2ee94", "resources/theme/default/icons/scaleClear.svg": "c62dd67d91bfb849c20eb5a1bd37e215", "resources/theme/default/icons/scaleRemove.svg": "0fb15d6df30ef9a5248804f9d082ad04", "resources/theme/default/icons/scaleReset.svg": "c69773f8695e60c85c82f65bfb44a29e", "resources/theme/default/icons/scorecard.svg": "9919e029f7566ce49fbe7338493e0473", "resources/theme/default/icons/script.svg": "cb1493bb56cd8d924de2516d7dbb5187", "resources/theme/default/icons/search.svg": "b116a8aa818d1cd7ec41752a0c29816b", "resources/theme/default/icons/section.svg": "aea2b044eb14c55452bc8172df030f92", "resources/theme/default/icons/selectedrecords.svg": "171b3d8de98149a3675b853745105c22", "resources/theme/default/icons/setExtent.svg": "7080d56468833b423897465aeca93138", "resources/theme/default/icons/setting.svg": "41cf928d70d4e8ed012cc2d15d224ed2", "resources/theme/default/icons/shengcunfenxi.svg": "5ae32cbb038032ed1443b8005baff03c", "resources/theme/default/icons/shortcutsConfig.svg": "4cb9c5a2687e14ba17d7ad9f4dcbfea9", "resources/theme/default/icons/simplearrow.svg": "157c76b4552215d148febb98baf92b1d", "resources/theme/default/icons/situationpoint.svg": "af69811bf86271d54800957689c28aec", "resources/theme/default/icons/skip_line.svg": "eedc935dd2773c44ff7e54a50811030a", "resources/theme/default/icons/slider_close.svg": "3402865a23ff073e953448e3d2480c24", "resources/theme/default/icons/slider_lasttime.svg": "da6ead6853a3db08a482f28ceaf933e3", "resources/theme/default/icons/slider_lastversion.svg": "3d10f7b5692a9ea4b8929e5a65528bfb", "resources/theme/default/icons/slider_nexttime.svg": "b54ce11ec64888d09640861fcc2ed0a5", "resources/theme/default/icons/slider_nextversion.svg": "54213dc4e51bccdd8348bcbdc0102d7b", "resources/theme/default/icons/slider_zoomin.svg": "abeda64aa9f3fa4e6d3bb2eefe65a89e", "resources/theme/default/icons/slider_zoomout.svg": "b9a24b973053cf1d836872b788180f00", "resources/theme/default/icons/sloperuler.svg": "16d462cb766b85c0ec907ce5c529bb02", "resources/theme/default/icons/spss.svg": "4d8cb6044137301a4101755e43b83fc1", "resources/theme/default/icons/sql.svg": "a0997f68ee9c263ffecd0efbaa524236", "resources/theme/default/icons/stata.svg": "a62e991cde9e8389dea6bf46b0bccb43", "resources/theme/default/icons/sun.svg": "e98cbd692ec62d35d27c78c31d91f86f", "resources/theme/default/icons/symbology.svg": "062e0ba664ee2320d21cda33ddaf3525", "resources/theme/default/icons/symbolreorder.svg": "062e0ba664ee2320d21cda33ddaf3525", "resources/theme/default/icons/system.svg": "c76354112390bc2f9151b4baf729ccfc", "resources/theme/default/icons/table.svg": "21615bcc2dab3f7d81b36b7267d5c003", "resources/theme/default/icons/tablegroup.svg": "b9a57bb1b7a98b1ea2220552ae77f576", "resources/theme/default/icons/task.svg": "1223b13e13ffccea138013fd33b71775", "resources/theme/default/icons/teamEditProject.svg": "35828465cb83319c8579c9cb9a904481", "resources/theme/default/icons/terrain.svg": "5e2ccfec44e7d6a40320912b4137615e", "resources/theme/default/icons/threenorth.svg": "96eada7b3eeebdca632533988e617717", "resources/theme/default/icons/time_series.svg": "94fd406769655b721b17f4cb17bc673f", "resources/theme/default/icons/top.svg": "22d2fefe180a699944a6a5ab545ab5a9", "resources/theme/default/icons/topologyConfig.svg": "2af77dff1d80bcccdefd9079ed4d68b6", "resources/theme/default/icons/transformed.svg": "5b98c431c64bf1f5697a2c63cab6ca11", "resources/theme/default/icons/transparency.png": "17c24a4daf81d8d7f8b9c7642e2fa7e7", "resources/theme/default/icons/transposition.svg": "07d926b580577fcc30c3a709cbde68bc", "resources/theme/default/icons/tree.svg": "14ae56a092c0268672520520ffc4443a", "resources/theme/default/icons/txt.svg": "867501b0b384f46cf6d4f225605995c1", "resources/theme/default/icons/undo.svg": "5484c93bf4a89654d20a2ba6bb66d912", "resources/theme/default/icons/uploaddata.svg": "e2a9a1ccdb820364d99b96d1a3ab39b6", "resources/theme/default/icons/upWard.svg": "b1c72b33367343316cc888d977ebb43d", "resources/theme/default/icons/useLeftAll.svg": "fddc9b7c0d601a881ab55af95659d3cd", "resources/theme/default/icons/useLeftSelected.svg": "1764c036105882a4743fc4e34e384404", "resources/theme/default/icons/useRightAll.svg": "c7020f993a82c847054dadf2b5709a5a", "resources/theme/default/icons/useRightSelected.svg": "18d35ec89cbb795bb88449c8859b3d81", "resources/theme/default/icons/var.svg": "c3d9e7461e40e74c17f3ce5873905f51", "resources/theme/default/icons/var_open.svg": "b023934e733448d74563926e0d5f9a1f", "resources/theme/default/icons/vectorTileStyle.svg": "670fc3779ea1e4b103aa75efd3832baf", "resources/theme/default/icons/view_var.svg": "a495e2e336064e1549622b87c69dd649", "resources/theme/default/icons/visibleMap.svg": "7ec32396ae7a2da699cf55929aed4f98", "resources/theme/default/icons/walking.svg": "790a25d6b2f642d0e2c04e5f5e5efd01", "resources/theme/default/icons/website.svg": "c789f48d1f500ad317ef3cde4818b240", "resources/theme/default/icons/windowicon.ico": "dd4b17c0ec69f51b039c51b6e0887c31", "resources/theme/default/images/addNode.svg": "d11d5a3ce54b3a864281b2f5f3311e36", "resources/theme/default/images/attributeBrush.svg": "ddeee5f9e2e1e63792eff8cbbb840164", "resources/theme/default/images/background.png": "ddf7168c491dac078b9b0c7c6771d602", "resources/theme/default/images/breakByOnePoint.svg": "ed5c5d11f74011fcb4c8a027eeb31599", "resources/theme/default/images/breakByTwoPoints.svg": "ce13a12a1afde966f284661dfdb1471f", "resources/theme/default/images/copyFeature.svg": "0293921cdf1de395e600349621565051", "resources/theme/default/images/cursor_leftbottom.svg": "3e9b60706a3f0bf7d729c48bd440cdc7", "resources/theme/default/images/cursor_leftright.svg": "418f31c70c594b53922604cdddb036e5", "resources/theme/default/images/cursor_lefttop.svg": "c364223abf37f51dd7def7162d9be9af", "resources/theme/default/images/cursor_move.svg": "8a82e82a355f18c8f410bd9bbf0c5f8e", "resources/theme/default/images/cursor_topbottom.svg": "ec0ad72e180c458e3155a88a2db6c023", "resources/theme/default/images/deleteNode.svg": "2aae237e59216f92c6b87dd7757c1a95", "resources/theme/default/images/editDraw.svg": "23e810e15d33b68a03427f8a40a408a1", "resources/theme/default/images/editSelect.svg": "8859783cdb6f54f380faadc8ad60c3c0", "resources/theme/default/images/error.png": "450eb59729737d72ceb03818c43ffcc9", "resources/theme/default/images/extensionPolyline.svg": "91c86deac1a658ed6b928487fb076723", "resources/theme/default/images/identify.svg": "ac8cb0d555021521270e9e6cc0d8ce59", "resources/theme/default/images/information.png": "423578ade54524e34a95580788d7729d", "resources/theme/default/images/mCapturePoint.svg": "5caf3405335284af6d880495b01d5776", "resources/theme/default/images/measure.svg": "23e810e15d33b68a03427f8a40a408a1", "resources/theme/default/images/mIconDeselected.svg": "75733116db9e219b0f4382385342b511", "resources/theme/default/images/mIconSelected.svg": "cc341d78f94f446e0e6ca672482edd15", "resources/theme/default/images/move.svg": "8a82e82a355f18c8f410bd9bbf0c5f8e", "resources/theme/default/images/moveFeature.svg": "8a82e82a355f18c8f410bd9bbf0c5f8e", "resources/theme/default/images/moveNode.svg": "84a9570e8f6d04cd64c450c1523aad4f", "resources/theme/default/images/mPageLayoutPan.svg": "67a143805264211f1031ebb79eb356a4", "resources/theme/default/images/mPageLayoutZoomIn.svg": "0d4e308d01775da24950c7c7869cadc2", "resources/theme/default/images/mPageLayoutZoomOut.svg": "ffa286230cff03f5bf4003a7f2e77a94", "resources/theme/default/images/mPanClose.svg": "a0603e76de7727c6a3a524adec772f49", "resources/theme/default/images/overlayUpdates.png": "75a5188a1a36b3e55a0c26bf0692ec3c", "resources/theme/default/images/pan.svg": "8fa8827e723ea97094655ce0ab60bcbb", "resources/theme/default/images/pyramidfirst.png": "6336d1c87d3a53c59f42ab682a7ef68d", "resources/theme/default/images/pyramidfourth.png": "3ca3b9cdbb6b88a50f6a270c24504df2", "resources/theme/default/images/pyramidsecond.png": "d8eb0fae632533ce16178629a61e77d6", "resources/theme/default/images/pyramidthird.png": "2dba3fd37994c231b6fe468f5922144a", "resources/theme/default/images/rotateFeature.svg": "d47a6e3f34dd3d3484440c7e4a96b58c", "resources/theme/default/images/select.svg": "128d8d763c91a71599ad86fcc069ad63", "resources/theme/default/images/selectbypolygon.svg": "5efdd8dc872ba52a262b939cfcd70515", "resources/theme/default/images/selectbyradius.svg": "c2d9e4efd0649941dfee9a843284ccca", "resources/theme/default/images/splitBySelect.svg": "021d0ae70cb8157d9d6f18feef0db270", "resources/theme/default/images/SwipeDown.svg": "21f3775a767d4cfb81d748276baf522a", "resources/theme/default/images/SwipeLeft.svg": "457aac45411c29aa4d6f1b63e6d999ba", "resources/theme/default/images/SwipeLeftRight.svg": "21193a1f1446c5c392d7a3807427e25a", "resources/theme/default/images/SwipeRight.svg": "cc700b8a09d58417f17496738db67404", "resources/theme/default/images/SwipeUp.svg": "b440961cee34d1649815aa594a896318", "resources/theme/default/images/SwipeUpDown.svg": "e21665a6f5d712ab4b25022ddb738ca5", "resources/theme/default/images/systemabout.png": "067610e0d804b16c75496b4ed77005dd", "resources/theme/default/images/thematicAttributes.svg": "ac8cb0d555021521270e9e6cc0d8ce59", "resources/theme/default/images/warning.png": "9323d69c25b6f79fc974023fee921af0", "resources/theme/default/images/zoomin.svg": "6bf9cf3ff08b719f4f872977e7ee201f", "resources/theme/default/images/zoomout.svg": "debcf4106754577838008ca423288371", "static/README.md": "2b883d8ed7e177b421e29625caf11a10", "static/tutorials_page.html": "7e6350719caf6a92de7a495441cd65ed", "static/css/iview.min.css": "b56ab90b84c3ac9f460f50906cbf5ae8", "static/js/echarts.min.js": "40874546a400f6e1b358c0495998a43f", "static/js/form-create.min.js": "5b2e899b103ec5bade920ac909268db4", "static/js/iview.min.js": "cb94a058fc714808d440d2b9835fed0d", "static/js/jquery-3.5.1.min.js": "dc5e7f18c8d36ac1d3d4753a87c98d0a", "static/js/vue.min.js": "b0473a59bd7e655c4da3d26f50dbba1e", "static/js/element-ui/CHANGELOG.en-US.md": "f90a50248e8a935d4bf94939b2b83bc1", "static/js/element-ui/CHANGELOG.es.md": "cd352a41d428cfe359e2dd25b3e69216", "static/js/element-ui/CHANGELOG.fr-FR.md": "2a5cb94c1cc391f95705a822c50906d2", "static/js/element-ui/CHANGELOG.zh-CN.md": "fae21798d847ea9bd4827f78766d634e", "static/js/element-ui/package.json": "ed15655a88db7bf4e42f2879000f0241", "static/js/element-ui/README.md": "29e235e7c8cba854610d2faa0424c5a0", "static/js/element-ui/lib/alert.js": "44bd2ce7e47fc65112066ebe354ceaca", "static/js/element-ui/lib/aside.js": "6af3243f56f6c0bda3eba64e2cd8078a", "static/js/element-ui/lib/autocomplete.js": "8cfc24a3a0f63f57b0bbefd1d43150b1", "static/js/element-ui/lib/avatar.js": "0c3f24bdffc3f4c3016149e5b589bf58", "static/js/element-ui/lib/backtop.js": "4ba1079d79f186a4b73395ab8048ce30", "static/js/element-ui/lib/badge.js": "d124ddea127b3b87fb7fc0e3d28f976e", "static/js/element-ui/lib/breadcrumb-item.js": "3ee84610ae6e927194916dc1850be078", "static/js/element-ui/lib/breadcrumb.js": "3b696a8b4d753bce1c9a42f1f2f2e559", "static/js/element-ui/lib/button-group.js": "c13e97a9b747982a6fe3475ce0963202", "static/js/element-ui/lib/button.js": "db479a095696d3b41e4e8e5ca573b2d9", "static/js/element-ui/lib/calendar.js": "78b60123511490a4957bb7ecc90ca562", "static/js/element-ui/lib/card.js": "a63bc5d2a60ecffc3fe581d2b9a86b19", "static/js/element-ui/lib/carousel-item.js": "24398b44ec0a885f9f7dcf7b4511b140", "static/js/element-ui/lib/carousel.js": "dc86769400de82ac847dfe71d278331a", "static/js/element-ui/lib/cascader-panel.js": "400c0c6ad5bb41a6d0aa489f027a849c", "static/js/element-ui/lib/cascader.js": "a97cc547f182cb959ff0af6d31f0769c", "static/js/element-ui/lib/checkbox-button.js": "e867a0fcfa56c197d8cbbcd8000ae723", "static/js/element-ui/lib/checkbox-group.js": "81593c2eeeee70e69fff71af4dfe212c", "static/js/element-ui/lib/checkbox.js": "09780b33e4add1d32b2b870c8ccc5a4b", "static/js/element-ui/lib/col.js": "227c1189111f2dfbada9a8f26e1433ed", "static/js/element-ui/lib/collapse-item.js": "0ef8b7bea75fa2d185730fa809d86148", "static/js/element-ui/lib/collapse.js": "8cc69b5cbaefb354e3fa19e748a54118", "static/js/element-ui/lib/color-picker.js": "25752f575ad81607f8b3b4652e1e1790", "static/js/element-ui/lib/container.js": "f2118022ef7e900503a8028e72a47bf2", "static/js/element-ui/lib/date-picker.js": "160c4f0f12cc50d77eeff03eb3e2abce", "static/js/element-ui/lib/dialog.js": "3446278e381ae6162bfc309cd883b84a", "static/js/element-ui/lib/divider.js": "ce49dbf8658355e06eb9ca852acd98e0", "static/js/element-ui/lib/drawer.js": "2a4f53c5e574a8fbe04eb528ccdb4e6b", "static/js/element-ui/lib/dropdown-item.js": "1c440ab125200ed27bb4402f26ae6edf", "static/js/element-ui/lib/dropdown-menu.js": "51e13aaf4f6dea2a6ec4eb6a06f49c1a", "static/js/element-ui/lib/dropdown.js": "02786a92e4ed20d950ad7d09e6dd03e7", "static/js/element-ui/lib/element-ui.common.js": "b6b435a52f5cdc204fb8a023bc856a16", "static/js/element-ui/lib/footer.js": "4d392ecf90fa43ebf25caa31e1783354", "static/js/element-ui/lib/form-item.js": "98d4dd1fa2c81e68ff40dc3344620df9", "static/js/element-ui/lib/form.js": "88eeb8b813539099fec26e9993789af8", "static/js/element-ui/lib/header.js": "9c9ab6bc2af99e67eee8367ab3ed855b", "static/js/element-ui/lib/icon.js": "658fcece90b39788b763c25f17d60207", "static/js/element-ui/lib/image.js": "650a56522f7a590b8fca25fdfb09690a", "static/js/element-ui/lib/index.js": "28fb829b428bc14fe9d26f852dbc11a9", "static/js/element-ui/lib/infinite-scroll.js": "3c09c5248512b2f0281e8e8bf4ecee8c", "static/js/element-ui/lib/input-number.js": "3dd23cc075c49822fe68366cef6f09a3", "static/js/element-ui/lib/input.js": "bb52be1067cfd9b1dd8ded0b664f5605", "static/js/element-ui/lib/link.js": "312480ee5f2292f314346434faa3518f", "static/js/element-ui/lib/loading.js": "9bb5753b57ee274668c5748d38eac2ab", "static/js/element-ui/lib/main.js": "92a26937eaac62367d2b81ebec36d9f0", "static/js/element-ui/lib/menu-item-group.js": "2098666a7bbd0c271cc084c3924d4ec3", "static/js/element-ui/lib/menu-item.js": "bf8db518c9b73c9cd3771dabf91bcaca", "static/js/element-ui/lib/menu.js": "0188cd906e1159936cbee28980fbec39", "static/js/element-ui/lib/message-box.js": "e275b026ca058dff799673d5740b6e22", "static/js/element-ui/lib/message.js": "0f64248045730556999011fa779d1dfa", "static/js/element-ui/lib/notification.js": "6190c53c839faa5b01a815de6769c899", "static/js/element-ui/lib/option-group.js": "f2759330e59d0518f60a6c5547d3c827", "static/js/element-ui/lib/option.js": "1c418a74feafdc73cfa5360764f1b90a", "static/js/element-ui/lib/page-header.js": "6a9f088700adf20d389cc542e6a0deaf", "static/js/element-ui/lib/pagination.js": "17b696cc294ca8bbc37af7b1c5968f7a", "static/js/element-ui/lib/popconfirm.js": "6bcceddbd44e456d716b66a018beaf7c", "static/js/element-ui/lib/popover.js": "a5cf39911205f08d5e5691a158bd81c6", "static/js/element-ui/lib/progress.js": "6f206f6d72b0622ea6a6c2fccd062bb5", "static/js/element-ui/lib/radio-button.js": "efdf34b9f8c565b99aeae587e11eb87a", "static/js/element-ui/lib/radio-group.js": "93003dbff84a768dbb1a12e7d6e7796a", "static/js/element-ui/lib/radio.js": "66201ad4319bcf5330d5711537cb85c6", "static/js/element-ui/lib/rate.js": "d57f0eede17b4ff2c80fbc3a5899d030", "static/js/element-ui/lib/row.js": "4d92917609e4db63a0acc64bca5d9ab4", "static/js/element-ui/lib/scrollbar.js": "76120f65f535b535d19fc1e820e959d5", "static/js/element-ui/lib/select.js": "5e900a932de2f3be38ef8f436fa201e4", "static/js/element-ui/lib/slider.js": "faf0a48d331a5c869c7bf7c8a07abe58", "static/js/element-ui/lib/spinner.js": "83f0cb9cc66bba831681c58c230890fd", "static/js/element-ui/lib/step.js": "cd744e288e5eeb55dde52cbe0909016d", "static/js/element-ui/lib/steps.js": "7cb3835a98f56194a2ca85cbeb197bf2", "static/js/element-ui/lib/submenu.js": "07584a153decdad6f82fe2de4e565f15", "static/js/element-ui/lib/switch.js": "aa60bca689f5db14f3bad0fcd8cb3ece", "static/js/element-ui/lib/tab-pane.js": "9cba2ce5089e06c7a6f9560687e0e150", "static/js/element-ui/lib/table-column.js": "bcf79a6f1de840db943cdee7c4e41921", "static/js/element-ui/lib/table.js": "f017fc250b36fbfebeef1b462b6984f8", "static/js/element-ui/lib/tabs.js": "f19f934d0ee0cb9b4234c9d81301f0b7", "static/js/element-ui/lib/tag.js": "66492bd336c57f37bbd9da3cac97b51c", "static/js/element-ui/lib/time-picker.js": "d2561b513c3dfdbb57f34f3f6855bd5b", "static/js/element-ui/lib/time-select.js": "c562bd018cb94d0a5f993a23bdb2e687", "static/js/element-ui/lib/timeline-item.js": "84ce5c070a064909355b56610bd8ff2f", "static/js/element-ui/lib/timeline.js": "e66393cdd8e7a22413acad9ab1f6f8af", "static/js/element-ui/lib/tooltip.js": "7f6a6999519c70a0485d2ae7d03ea6ab", "static/js/element-ui/lib/transfer.js": "b5825b45e447c403e3b0833e7975fa96", "static/js/element-ui/lib/tree.js": "16346c71a54ffbaddc37b635296704ed", "static/js/element-ui/lib/upload.js": "1682818d886774e15dd8267e40d81ecb", "static/js/element-ui/lib/directives/mousewheel.js": "d57acb00ba5ec4322dd7b4e37dedbb69", "static/js/element-ui/lib/directives/repeat-click.js": "ee7cb0bb5822588e21af009528f04490", "static/js/element-ui/lib/locale/format.js": "471399a5f5d8d53d46cb7e2fcad68d0d", "static/js/element-ui/lib/locale/index.js": "7f48cd4280e7b5be536b37a33af7a441", "static/js/element-ui/lib/locale/lang/af-ZA.js": "1cab2e3d954eaf982bff6464654f162a", "static/js/element-ui/lib/locale/lang/ar.js": "a973ecdc856fa1ea02fc3a1f1d436ddb", "static/js/element-ui/lib/locale/lang/bg.js": "100d5a70d89307668e0a512d953bbbd3", "static/js/element-ui/lib/locale/lang/ca.js": "f85b7ef8722b22ab636c540dc90c9aae", "static/js/element-ui/lib/locale/lang/cs-CZ.js": "5b0aeb0ab3f5177a7d2ae975db11ff20", "static/js/element-ui/lib/locale/lang/da.js": "7b04b9b382da5785b105084c0b1895fc", "static/js/element-ui/lib/locale/lang/de.js": "165678f7ff2d5c05c1b196c1fe36919f", "static/js/element-ui/lib/locale/lang/ee.js": "77cab864f3b5c0d02700606da528e0c9", "static/js/element-ui/lib/locale/lang/el.js": "1ab144c6f49d289c320e8672fdd78d05", "static/js/element-ui/lib/locale/lang/en.js": "fbea06cf549fdf1bc8107e258676825d", "static/js/element-ui/lib/locale/lang/eo.js": "91b4bd398fd27e80d331675e0567eae8", "static/js/element-ui/lib/locale/lang/es.js": "e1845d63e50ee4f117aa16c8b7756cc7", "static/js/element-ui/lib/locale/lang/eu.js": "6851cf67a17a2988f1e905557ebba981", "static/js/element-ui/lib/locale/lang/fa.js": "67763039da687c77702e59237ce66e04", "static/js/element-ui/lib/locale/lang/fi.js": "0b35a1d0fb672b74e243a5f41defdd70", "static/js/element-ui/lib/locale/lang/fr.js": "64c0cbb50596da4841223e8c85c34c1b", "static/js/element-ui/lib/locale/lang/he.js": "2a3719ffb84a33ed3dd1e9799c03a3dd", "static/js/element-ui/lib/locale/lang/hr.js": "81661a420afc076d1792c21f0432a50e", "static/js/element-ui/lib/locale/lang/hu.js": "0fa9fc603c3f5ad1bbbab426db5fa3cf", "static/js/element-ui/lib/locale/lang/hy-AM.js": "a6d88e26e14fd663a5aebe98623b1e5d", "static/js/element-ui/lib/locale/lang/id.js": "ace3933e6fba75bf17787c34580d1430", "static/js/element-ui/lib/locale/lang/it.js": "ddbaa0c9de79f04c13510abf9e9fe347", "static/js/element-ui/lib/locale/lang/ja.js": "927e2dbb268276b854f4ab58486c029d", "static/js/element-ui/lib/locale/lang/kg.js": "321e5d0e5cd78eb71baeea679f9866ad", "static/js/element-ui/lib/locale/lang/km.js": "712afcf5ce5bd04235c9da5cabd3211c", "static/js/element-ui/lib/locale/lang/ko.js": "a1462b4c5f54be3312a11745525baf79", "static/js/element-ui/lib/locale/lang/ku.js": "0843793ace9f2be0d749f90ae499fd25", "static/js/element-ui/lib/locale/lang/kz.js": "7da2b07e5b87618e3a7176ddfe04887a", "static/js/element-ui/lib/locale/lang/lt.js": "9525aa7bd194094651d15525bd32d060", "static/js/element-ui/lib/locale/lang/lv.js": "6a911e229e2501001d303a8fdf425d32", "static/js/element-ui/lib/locale/lang/mn.js": "2b91da6fd41d16584339b227082dd47f", "static/js/element-ui/lib/locale/lang/nb-NO.js": "91463e2c92f200c50e1dccd73e03695f", "static/js/element-ui/lib/locale/lang/nl.js": "feab63aa44ae350f99f1d484a91d942c", "static/js/element-ui/lib/locale/lang/pl.js": "a27556391421cdbf5d2424d38955b645", "static/js/element-ui/lib/locale/lang/pt-br.js": "1a7d47d3cca171739de21a0cc99387f1", "static/js/element-ui/lib/locale/lang/pt.js": "87ef9e7ed1f27c582e7faabc406cf483", "static/js/element-ui/lib/locale/lang/ro.js": "b608c43b34a6975d98e4b7b2b7295402", "static/js/element-ui/lib/locale/lang/ru-RU.js": "0504c7d75043cb31bcb692a689743cef", "static/js/element-ui/lib/locale/lang/sk.js": "3dd18f7fd8a017f994feba8b6d9a0890", "static/js/element-ui/lib/locale/lang/sl.js": "9ce57a4806c0740551d7dc51e786c86e", "static/js/element-ui/lib/locale/lang/sr.js": "d2ff6141f3ecd471a8cf846a24d7a8ed", "static/js/element-ui/lib/locale/lang/sv-SE.js": "3ca29384088f1f47398278654fa3011c", "static/js/element-ui/lib/locale/lang/ta.js": "b4de5e6d6863d34dfa6e98ccf495d504", "static/js/element-ui/lib/locale/lang/th.js": "cf6e83d1c133279705c8296ef90e775b", "static/js/element-ui/lib/locale/lang/tk.js": "7c799830a4ba20120bc2e7bccf3419d8", "static/js/element-ui/lib/locale/lang/tr-TR.js": "061e2668858c3654f3bf6750276546be", "static/js/element-ui/lib/locale/lang/ua.js": "399ff5fe5470ec3e4a57f88d1ae6fe6b", "static/js/element-ui/lib/locale/lang/ug-CN.js": "fa8d94b219647056165f1baaa843b5e6", "static/js/element-ui/lib/locale/lang/uz-UZ.js": "3607e6bf57b1d37e917736c460d7dd63", "static/js/element-ui/lib/locale/lang/vi.js": "3c54c8dec1d0c8afccd03efb53a0b53c", "static/js/element-ui/lib/locale/lang/zh-CN.js": "0b60542152156fa18a045d408bed61ea", "static/js/element-ui/lib/locale/lang/zh-TW.js": "d886891267165c838c345606c972856e", "static/js/element-ui/lib/mixins/emitter.js": "f38340cf5d69582efda171286efafa65", "static/js/element-ui/lib/mixins/focus.js": "b113513900bcf212968edd814c163760", "static/js/element-ui/lib/mixins/locale.js": "9b538e9a7f8d56c2c1f85984a9d4b2d2", "static/js/element-ui/lib/mixins/migrating.js": "7774a8a036683cd8b2b3340e0a63b132", "static/js/element-ui/lib/theme-chalk/alert.css": "4a233d163ac6641263075f6e7c4821db", "static/js/element-ui/lib/theme-chalk/aside.css": "edcc490fb0053f1cce4a71a5c047bdf9", "static/js/element-ui/lib/theme-chalk/autocomplete.css": "47ce2bcdfb1b1b08f5c623f9387391ff", "static/js/element-ui/lib/theme-chalk/avatar.css": "58a5fedd9b307c75a19c3b0533d813b8", "static/js/element-ui/lib/theme-chalk/backtop.css": "8b2ca61408dad479b881960763d3db98", "static/js/element-ui/lib/theme-chalk/badge.css": "ea8bfd89345e13ad428bdfb5574237b4", "static/js/element-ui/lib/theme-chalk/base.css": "f25cc484087487b1e1ef6ce8bf62ca44", "static/js/element-ui/lib/theme-chalk/breadcrumb-item.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/breadcrumb.css": "16d9a27c1cd682756f3173c95a83d0ed", "static/js/element-ui/lib/theme-chalk/button-group.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/button.css": "41b0f4e08fdd9eedc5a38b9713ddd904", "static/js/element-ui/lib/theme-chalk/calendar.css": "982528766ad2393b8617dbbf05dfaa7f", "static/js/element-ui/lib/theme-chalk/card.css": "48a5b07b8b0a6fb0c5eb6eafacdd0cd5", "static/js/element-ui/lib/theme-chalk/carousel-item.css": "6c97d1a467ad4b215ee69ed21754a728", "static/js/element-ui/lib/theme-chalk/carousel.css": "53761931f0070d80e77e2073f18b1d23", "static/js/element-ui/lib/theme-chalk/cascader-panel.css": "d897ade7fa060cfb4a7fc14503e61a44", "static/js/element-ui/lib/theme-chalk/cascader.css": "bdded6ec78f1471b771f1c4e4e07b596", "static/js/element-ui/lib/theme-chalk/checkbox-button.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/checkbox-group.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/checkbox.css": "515b3e4a1c684ea0538292380b38ca5f", "static/js/element-ui/lib/theme-chalk/col.css": "cd14b27ef81a2fc60079ecf869bca3cd", "static/js/element-ui/lib/theme-chalk/collapse-item.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/collapse.css": "9b8b3424302f453728fe80719c97de40", "static/js/element-ui/lib/theme-chalk/color-picker.css": "083fba820bd7440f18cf93af1d6a31dd", "static/js/element-ui/lib/theme-chalk/container.css": "e79009df433ab4403029e519ddc3340d", "static/js/element-ui/lib/theme-chalk/date-picker.css": "bd299472f79e6132d0dc6845176cadbe", "static/js/element-ui/lib/theme-chalk/dialog.css": "d30bf0818a97168906dc243c0e04a1bf", "static/js/element-ui/lib/theme-chalk/display.css": "c110a2385504d5ee6adb4377365270d7", "static/js/element-ui/lib/theme-chalk/divider.css": "6e52365004d46117ecfb085bc38479b0", "static/js/element-ui/lib/theme-chalk/drawer.css": "6ba86d8fe04df4d3549e4b3fc950bcb4", "static/js/element-ui/lib/theme-chalk/dropdown-item.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/dropdown-menu.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/dropdown.css": "246cd4c0d0f8d4493c5e987d0e330925", "static/js/element-ui/lib/theme-chalk/footer.css": "0a75eee620a1eec96cf1718047bde916", "static/js/element-ui/lib/theme-chalk/form-item.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/form.css": "8521897ad3a147046fd049b37f6775c8", "static/js/element-ui/lib/theme-chalk/header.css": "4bf1a1be0a4af7778c092b276458787a", "static/js/element-ui/lib/theme-chalk/icon.css": "83dc46b9fc11c99b5c0511d0a9a9987e", "static/js/element-ui/lib/theme-chalk/image.css": "32f4b078377ca3c364767e55bba62ede", "static/js/element-ui/lib/theme-chalk/index.css": "2414fd307c22e07b681e50e0720cbc23", "static/js/element-ui/lib/theme-chalk/infinite-scroll.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/infiniteScroll.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/input-number.css": "a30d3d47860db05882de8597cbb35a3f", "static/js/element-ui/lib/theme-chalk/input.css": "88d9749aad3cfd64720e1090474a8573", "static/js/element-ui/lib/theme-chalk/link.css": "b29ddaa7be960e0dabeee5b23fed982c", "static/js/element-ui/lib/theme-chalk/loading.css": "ee99b8ad8874ed9e7df64b7dab4159a6", "static/js/element-ui/lib/theme-chalk/main.css": "9923eb608c01cf001501708e1c8df0bc", "static/js/element-ui/lib/theme-chalk/menu-item-group.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/menu-item.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/menu.css": "30fa354841214de1919e49d8e831a5bf", "static/js/element-ui/lib/theme-chalk/message-box.css": "6fe773d1292f0acbc9ddad9153548c58", "static/js/element-ui/lib/theme-chalk/message.css": "6ab057c82772aa70e8ecc9902d4284ec", "static/js/element-ui/lib/theme-chalk/notification.css": "875a37cf12d647c1dee9e7e467ea01fb", "static/js/element-ui/lib/theme-chalk/option-group.css": "b3a13247682f590bb17b55517326ec39", "static/js/element-ui/lib/theme-chalk/option.css": "1698a68c50ff2618face813daa89982e", "static/js/element-ui/lib/theme-chalk/page-header.css": "3508c570c80476d68b49a13d4c14e27c", "static/js/element-ui/lib/theme-chalk/pagination.css": "93a1866f64772a9d877796cc27f59e2b", "static/js/element-ui/lib/theme-chalk/popconfirm.css": "24183a243d4c79db8c383f296300a5be", "static/js/element-ui/lib/theme-chalk/popover.css": "4d19d78df7b0a3157772b86018648ee9", "static/js/element-ui/lib/theme-chalk/popper.css": "36fcdf5712174c8177fe2fcb73977ed5", "static/js/element-ui/lib/theme-chalk/progress.css": "a3d92e7241d275e11982945ad7c7e284", "static/js/element-ui/lib/theme-chalk/radio-button.css": "d126d35d880b72736a6d24b94170b9eb", "static/js/element-ui/lib/theme-chalk/radio-group.css": "86af00fe6b72f9005bf39e3481691586", "static/js/element-ui/lib/theme-chalk/radio.css": "a3110894bf315e7eedf9111a951840f6", "static/js/element-ui/lib/theme-chalk/rate.css": "0f33a694a0e389f05cd24aeec4b1765e", "static/js/element-ui/lib/theme-chalk/reset.css": "3db1afd65a0400d0d643f705d44250f5", "static/js/element-ui/lib/theme-chalk/row.css": "b1ac86fc178549496bb90eec4ba5da5e", "static/js/element-ui/lib/theme-chalk/scrollbar.css": "23449b1c81727518ce5d914579ee6174", "static/js/element-ui/lib/theme-chalk/select-dropdown.css": "f95dc3aef5e200e495d51f00a81b4e20", "static/js/element-ui/lib/theme-chalk/select.css": "d16e8c09f8fa26ec7d03b5652cdbb797", "static/js/element-ui/lib/theme-chalk/slider.css": "c7db7b54589f0ba57dd2b3a1057bfb90", "static/js/element-ui/lib/theme-chalk/spinner.css": "5b5d1e5f3e4422c063adc569a8346fca", "static/js/element-ui/lib/theme-chalk/step.css": "cf252484e262941d6d6c081042e38074", "static/js/element-ui/lib/theme-chalk/steps.css": "ac6f8637955a659b97ea3548a20fcfba", "static/js/element-ui/lib/theme-chalk/submenu.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/switch.css": "dbe3a9344c8c3594fce88715c118edf9", "static/js/element-ui/lib/theme-chalk/tab-pane.css": "d41d8cd98f00b204e9800998ecf8427e", "static/js/element-ui/lib/theme-chalk/table-column.css": "e11267cebea4826211fbfbc1f88c6ec8", "static/js/element-ui/lib/theme-chalk/table.css": "facf1d994f3fda680e22163b2e4148c2", "static/js/element-ui/lib/theme-chalk/tabs.css": "ec342796738d9d1a87137c0451c6b784", "static/js/element-ui/lib/theme-chalk/tag.css": "52178a68247a9fe015ccb5e965ce3fd3", "static/js/element-ui/lib/theme-chalk/time-picker.css": "7a25549a612c52a82dcc265f20566f0c", "static/js/element-ui/lib/theme-chalk/time-select.css": "a230a27e1eae140dc38e608de2651ba6", "static/js/element-ui/lib/theme-chalk/timeline-item.css": "743e68350200b578c75506697a7f5789", "static/js/element-ui/lib/theme-chalk/timeline.css": "b5d2b9a92b38005cff9a5752246992e1", "static/js/element-ui/lib/theme-chalk/tooltip.css": "4722109edb63d5c732ca61ecb3d47175", "static/js/element-ui/lib/theme-chalk/transfer.css": "14928e12a3985c3d0e516e6799601d65", "static/js/element-ui/lib/theme-chalk/tree.css": "5f5d85942e52967f08d4f1698cee2683", "static/js/element-ui/lib/theme-chalk/upload.css": "077d8dc834e6d88194879db89ff54bc5", "static/js/element-ui/lib/theme-chalk/fonts/element-icons.ttf": "4b1a4d348209ad29243b0a042de1b557", "static/js/element-ui/lib/theme-chalk/fonts/element-icons.woff": "f717deee44e7fcc757c6c1ade5cce443", "static/js/element-ui/lib/transitions/collapse-transition.js": "354e780b8a86771cd737928485f7d798", "static/js/element-ui/lib/umd/locale/af-ZA.js": "0fc2ac6b8936f2cd76256d2672b8b426", "static/js/element-ui/lib/umd/locale/ar.js": "18bbfc189ca1a3da137e560c112e0aba", "static/js/element-ui/lib/umd/locale/bg.js": "2c6245f699c62437fa7ee0d163cdd65c", "static/js/element-ui/lib/umd/locale/ca.js": "f494da9c984efa37bb7aff8be66d026e", "static/js/element-ui/lib/umd/locale/cs-CZ.js": "6554aa484f5ec7b4d1e3ad176cc69b71", "static/js/element-ui/lib/umd/locale/da.js": "0fb807a6d9d65b4d438c1e8563e369c4", "static/js/element-ui/lib/umd/locale/de.js": "835ff2b17f107ff50be524805b201f3c", "static/js/element-ui/lib/umd/locale/ee.js": "a363d6f90a0acfea8f31f1a6be49aeee", "static/js/element-ui/lib/umd/locale/el.js": "e9b50aee66128071682125d1e9d98c23", "static/js/element-ui/lib/umd/locale/en.js": "eccc9db8251b0ef6f69337f39234d423", "static/js/element-ui/lib/umd/locale/eo.js": "373c79e4396edec41165343f5a889f99", "static/js/element-ui/lib/umd/locale/es.js": "f33d213c3974b2acdc167886b61f2e47", "static/js/element-ui/lib/umd/locale/eu.js": "62bcc16524b72c7094a20162832b36b5", "static/js/element-ui/lib/umd/locale/fa.js": "273a1e35316564355fed5eb3bfeb2ab8", "static/js/element-ui/lib/umd/locale/fi.js": "9f9889caf4adcffc6cc78c229c457a7a", "static/js/element-ui/lib/umd/locale/fr.js": "ecd5286ed9b8faf83a56bbe449df9e00", "static/js/element-ui/lib/umd/locale/he.js": "db9119fe9dc05c872421bf4758de2eca", "static/js/element-ui/lib/umd/locale/hr.js": "9396ffd6cc82eeb3a09ce0d8ed1dd483", "static/js/element-ui/lib/umd/locale/hu.js": "1e6962cb413392e68dae16680bcd6370", "static/js/element-ui/lib/umd/locale/hy-AM.js": "85701cecfaf21f5813aeebe91b2b7560", "static/js/element-ui/lib/umd/locale/id.js": "1b99f644e81cf63fc7cecd34746dc66e", "static/js/element-ui/lib/umd/locale/it.js": "4fd6e8ba9c2d5fe7c9e74f753b95379c", "static/js/element-ui/lib/umd/locale/ja.js": "567701dd5feb9804153acefabfaa44b9", "static/js/element-ui/lib/umd/locale/kg.js": "4b4067ad2fb93f84a6c9e8c35de483e9", "static/js/element-ui/lib/umd/locale/km.js": "c69fc83984c03a7a4f04cdc6967cca58", "static/js/element-ui/lib/umd/locale/ko.js": "9bdf5bf54251017cb60636c8b4fe0ecf", "static/js/element-ui/lib/umd/locale/ku.js": "581e50d5471c9ec4c535ebcdb5ba68c8", "static/js/element-ui/lib/umd/locale/kz.js": "3113fafaec1e5f4ae75275df004a438f", "static/js/element-ui/lib/umd/locale/lt.js": "1f9ab75d239d73dd6450d20719d14e4c", "static/js/element-ui/lib/umd/locale/lv.js": "06ed0fdc7d15aaaa254ddafd5cc2d984", "static/js/element-ui/lib/umd/locale/mn.js": "a30050261567e96fcae3eb8184077738", "static/js/element-ui/lib/umd/locale/nb-NO.js": "8f696776c06ee3e12e43a4cdd6cce736", "static/js/element-ui/lib/umd/locale/nl.js": "99258a51fa6d3bb2eaf24687b08681b6", "static/js/element-ui/lib/umd/locale/pl.js": "727bf2dd0d8c2917c7d7b67651fa4e2c", "static/js/element-ui/lib/umd/locale/pt-br.js": "9b175360cb8d7199055506a7f57e7d4b", "static/js/element-ui/lib/umd/locale/pt.js": "1626947603ba9812628e5388526e02e7", "static/js/element-ui/lib/umd/locale/ro.js": "fb9eef3d28ce9ecc7ad83b41caf17864", "static/js/element-ui/lib/umd/locale/ru-RU.js": "02776c80fbb8f65298ef9156d79d11ee", "static/js/element-ui/lib/umd/locale/sk.js": "34457b2d2b6c75a8025a0eba36931523", "static/js/element-ui/lib/umd/locale/sl.js": "2d186805c45ce5292f9dfa2f2255677f", "static/js/element-ui/lib/umd/locale/sr.js": "57009e2dc4bc4de61794b29c659a132d", "static/js/element-ui/lib/umd/locale/sv-SE.js": "315c4a945b2b89e206ade38990a7e9f9", "static/js/element-ui/lib/umd/locale/ta.js": "da94b97bf773e49867bdd4c91b738cdf", "static/js/element-ui/lib/umd/locale/th.js": "76dde843e7f874f2e45cc1ea1dadc638", "static/js/element-ui/lib/umd/locale/tk.js": "710dfdc6ba97ebc5b6ed5e5c6ba40c79", "static/js/element-ui/lib/umd/locale/tr-TR.js": "2af8060b6746a342827a94ee1d45972c", "static/js/element-ui/lib/umd/locale/ua.js": "c2240b43e3d70e4b2c25db2580d5b9ad", "static/js/element-ui/lib/umd/locale/ug-CN.js": "6ddaea800aed2638e2d02b06322ceb07", "static/js/element-ui/lib/umd/locale/uz-UZ.js": "ddb5d919cc3756722a2980f995086225", "static/js/element-ui/lib/umd/locale/vi.js": "764578d2497752bec40d8cf3982501d5", "static/js/element-ui/lib/umd/locale/zh-CN.js": "af0b3424682dedebc3064a17c8c8f047", "static/js/element-ui/lib/umd/locale/zh-TW.js": "ee9c9d202116bd367a54b6542b41e9ac", "static/js/element-ui/lib/utils/after-leave.js": "5b6eab2e19137f22b7f155c64c127b5a", "static/js/element-ui/lib/utils/aria-dialog.js": "584e07ba3bcd14fe02d84d456461a381", "static/js/element-ui/lib/utils/aria-utils.js": "bccd0c0998fa688607a28aef5d3954be", "static/js/element-ui/lib/utils/clickoutside.js": "1d2c86f338286924e65ba0beb1e9275b", "static/js/element-ui/lib/utils/date-util.js": "f7bc86e6068c4c4f23c86f7d6fafce77", "static/js/element-ui/lib/utils/date.js": "63bca9e7033fcf66fa9b93ccaf4dad0f", "static/js/element-ui/lib/utils/dom.js": "7a5bf584e8d01360f759c1a78305219c", "static/js/element-ui/lib/utils/merge.js": "48d430909e3583f3010bf4e844bd1163", "static/js/element-ui/lib/utils/popper.js": "f90f278e90fdff8f4afd382145b2db9b", "static/js/element-ui/lib/utils/resize-event.js": "96628f5f98b18fee3c4972e8f39b6481", "static/js/element-ui/lib/utils/scroll-into-view.js": "a2847b7f5d7ae6860f66669f645ce861", "static/js/element-ui/lib/utils/scrollbar-width.js": "6dd9aafa50bf2028e1fa542feb995f89", "static/js/element-ui/lib/utils/shared.js": "e9becb8ca1ad71a5d64d989e28778b11", "static/js/element-ui/lib/utils/types.js": "b76cda09d6b97c9598681b372f3efd6e", "static/js/element-ui/lib/utils/util.js": "c4013004a996dd7d030f779c721c7c2d", "static/js/element-ui/lib/utils/vdom.js": "a72f60b0134bd47f49c537ad28982bad", "static/js/element-ui/lib/utils/vue-popper.js": "ea42e858259fa582acfadc15265b1d30", "static/js/element-ui/lib/utils/menu/aria-menubar.js": "172afd68add2537d32f299e5369c8ad8", "static/js/element-ui/lib/utils/menu/aria-menuitem.js": "2c51a053252827845cce692634443771", "static/js/element-ui/lib/utils/menu/aria-submenu.js": "2d5f39c9bc644388bc57563ee8ecae87", "static/js/element-ui/lib/utils/popup/index.js": "8df7b5c153e9187359c20ab602ad6740", "static/js/element-ui/lib/utils/popup/popup-manager.js": "68856d04bb10de1e999fc10693a73999", "tests/README.md": "bad9b5c1d18429a006532bb7faebd117", "tests/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/assets/\u5168\u90e8\u6d4b\u8bd5.png": "dbed30a78bcec42c7523471fcf514700", "tests/assets/\u6253\u5f00pycharm\u7684pytest\u529f\u80fd.png": "b849c96411e8d82fc8a50f0ff816c1f7", "tests/assets/\u6267\u884c\u6d4b\u8bd5\u7528\u4f8b.png": "39116cca185c73ae3d4517ee0f84133a", "tests/assets/\u6d4b\u8bd5\u5931\u8d25.png": "d04228741f3da0b6e977211fe41c6438", "tests/assets/\u6d4b\u8bd5\u6210\u529f.png": "6669c0c45442db35ab92b06bf9993c06", "tests/test_algorithms/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_algorithms/test_linear_algebra/test_linear_space.py": "6df796d85cb787fd7f045a0ab5c63a1c", "tests/test_algorithms/test_linear_algebra/test_matrix_cross.py": "4b574f0a6131847d802761bd83a6d6ae", "tests/test_algorithms/test_linear_algebra/test_matrix_determinant.py": "041bf9f620c2dcb093bf20cf4ed20c72", "tests/test_algorithms/test_linear_algebra/test_matrix_diagonal.py": "b8afb32ca59752683d9c605a9885e2f5", "tests/test_algorithms/test_linear_algebra/test_matrix_divide.py": "2b63a05c372c145b05920fe5c8e7ee1d", "tests/test_algorithms/test_linear_algebra/test_matrix_dot.py": "3f80ff34c4b639fc33344ce8c23ab153", "tests/test_algorithms/test_linear_algebra/test_matrix_eigenvalue.py": "0edcf7066a5e3143d089a0222d8659be", "tests/test_algorithms/test_linear_algebra/test_matrix_inverse.py": "8f502aabb41e4faaae06663c45fe52a9", "tests/test_algorithms/test_linear_algebra/test_matrix_multiply.py": "45423c811a4db180b269945908595383", "tests/test_algorithms/test_linear_algebra/test_matrix_transpose.py": "d92dc7600a77f090f5f897dff9d099e4", "tests/test_algorithms/test_linear_algebra/test_ones.py": "faa005c5fce0def31dcc4aa83861f4de", "tests/test_algorithms/test_linear_algebra/test_reshape.py": "ff0f15e2ba03d7bd3ee086deab31f9d0", "tests/test_algorithms/test_linear_algebra/test_shape.py": "29a411d526e34d9070155e1a198195db", "tests/test_algorithms/test_linear_algebra/test_zeros.py": "5c8802a5d2bd87dc00e67e7f2f892c9e", "tests/test_algorithms/test_linear_algebra/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_algorithms/test_statistics/run_distribution.py": "fd81a148edd8cb40ed4390dde9c9af9d", "tests/test_algorithms/test_statistics/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_data_adapter/run_dump_load.py": "4b7572b7ce9b3c6ce0ed6d6811b64e6b", "tests/test_data_adapter/test_array.py": "717162f0f2da526e3a18456b12dfbd10", "tests/test_data_adapter/test_data_frame.py": "e56b02672c2d979b495c24fdc113eafc", "tests/test_data_adapter/test_detector.py": "92495e21a9b05068d73833d4d6a8f3f9", "tests/test_data_adapter/test_universal.py": "f69c1055e69f2e844596a3b80ab20c88", "tests/test_data_adapter/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/__init__.py": "4277383d96a0b390d7299069af45c987", "tests/test_dev/test_doc/test_file_tree_node.py": "362ef3dedb9be7eca57248be44f93e3f", "tests/test_dev/test_doc/__init__.py": "d2b42ea8d4d60b51c772335633e18078", "tests/test_dev/test_doc/test_case_for_file_tree_node/main.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/README.md": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/_exclude.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir/core1.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir/test1.txt": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir2/test2.txt": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir2/__init__.pyw": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir3/core3.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_dev/test_doc/test_case_for_file_tree_node/sub_dir3/test3.txt": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_widgets/test_maccabe/mccaberun.py": "17cdb5bf5d1157aeba779172c294ad95", "tests/test_widgets/test_maccabe/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_widgets/test_normal/test_display.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_widgets/test_util/test_util.py": "8db14adf951ddecf73952d6841b2aa93", "tests/test_pmtoolbox/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "tests/test_ui/test_ipython_support.py": "4e109800eedb8113b7da674b05e08bac", "tests/test_ui/test_pmgpanel.py": "a8d7ede78b58ae7be4f738f322f9be98", "tests/test_workspace2/test_data_manager.py": "bcf209b27357532443d75b3c368e68c7", "tests/test_workspace2/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "utils/environ.py": "b8bfeb3f35922c0337c197abea87829f", "utils/http_client.py": "3a5ced47c6f09803ad68b4da5b59d7f1", "utils/path.py": "93a5404fabe530d18791aaafecfd1b40", "utils/platform.py": "2da872dbe9abece68ed95e204c2ff655", "utils/__init__.py": "7e6452c9cf8ce5c4c856dcbdd3cf6b2f", "utils/debug/debuggerprocess.py": "0fe81aa6f61d81df42ef9afcc2d25bd5", "utils/debug/pdbtest.py": "b79fc6b32634f06788247e8d58402d41", "utils/debug/pmdebug.py": "d384421931a8e48e26cab0fba3c4241c", "utils/debug/test2.py": "b53f37a4994356be41f962afcb0a0b10", "utils/debug/__init__.py": "350446184463764465845852bd3ef50e", "utils/doc/file_tree.py": "36bd540c3b4c32b184dee9f2182f0819", "utils/doc/index.rst": "2488cd21dbd21544665f802ab3f0045e", "utils/doc/rst_generator.py": "fca7802a37b44b4a62924aa7521d6a2a", "utils/doc/__init__.py": "892fd1aca5b1cae0f580cd809094dad2", "utils/doc/doc_guide/choose_position.md": "482843264c94f2bd50c448fec43a3cc3", "utils/doc/doc_guide/compile.md": "eeee41c8eefce5234f176c76a0b15ee9", "utils/doc/doc_guide/index.rst": "0f1e7af0e52ee3073edf77f0eb9b0de6", "utils/doc/doc_guide/md_guide.rst": "809611fdb43d6b05edfadf5cc3a8c7c7", "utils/doc/doc_guide/rst_guide.rst": "8fa7462d9a5b56d6c5a67646e2ba4acc", "utils/doc/doc_guide/use_chevereto.rst": "3cb77997069a4c98b34360c9490f5733", "utils/doc/template/module.rst_t": "3af408a56d3d4adb3acfe09f653128ac", "utils/doc/template/package.rst_t": "801c621e304bc973e95f2e2519de04f8", "utils/doc/template/toc.rst_t": "a7cf368655e8fd91249cee24406aaff8", "utils/doc_figures/\u5e15\u7d2f\u6258\u56fe.jpg": "17c5690d782d1554a0eee747b496dcac", "utils/doc_figures/\u5e94\u7528\u5de5\u5177\u680f.png": "52d6b3bbabc43c2d368ce7748e8a9c7d", "utils/doc_figures/\u5f02\u5e38\u503c\u68c0\u6d4b": "49f442e7d72e05764e8353e36a824637", "utils/doc_figures/\u6807\u51c6\u79d1\u5b66\u8ba1\u7b97app\u754c\u9762\u539f\u578b.png": "5a6aa5719ae6d2ab0a3e2deeb4d9f841", "utils/doc_figures/\u9879\u76ee\u7ec4\u6210\u7ed3\u6784.png": "7d7896300a5e62d2fad7062bcba88aee", "utils/io/file_import.py": "d41d8cd98f00b204e9800998ecf8427e", "utils/io/piputil.py": "d45b0ab10e658c8bd1a260e7a7b0daca", "utils/io/__init__.py": "e9846ca05e2cf2393e2d36e130f7e84f", "utils/io/dbconnect/dbBaseTool.py": "964e1d0151fac429242dfdd163d6693b", "utils/io/dbconnect/dbConnectAccount.pkl": "410722595449e489f364425f6cd8c240", "utils/io/dbconnect/dbutils.py": "a83eac2b48d43e4bbb144b6ee30ac5a6", "utils/io/dbconnect/test_dbBaseTool_add_connection.py": "9777701d02960adae45e4ebc5afdabbc", "utils/io/dbconnect/test_dbBaseTool_query.py": "637037577573d38544ed3a801e4a8238", "utils/io/dbconnect/__init__.py": "5111d7ba85f86397e7318a88362fd502", "utils/io/fileutil/compressutils.py": "d79d280d2f6ddc66de6687a7b8201338", "utils/io/fileutil/encoding.py": "f70ddeb46e587c343134428e3a1d9b6c", "utils/io/fileutil/search_in_path.py": "3a369957683bec55df7e6e63cb3ce499", "utils/io/fileutil/variableutils.py": "e980e969d1f33da86e71e1207f282fe5", "utils/io/fileutil/__init__.py": "86e37c6a62dd940b6add84e2f3464697", "utils/io/fileutil/source/encoding/test_ascii.csv": "930b9d198c8fe4cf62cb40bf86deb059", "utils/io/fileutil/source/encoding/test_gb2312.csv": "b78fff031a5e71e40eaa348a628dd45e", "utils/io/fileutil/source/encoding/test_gbk.csv": "b78fff031a5e71e40eaa348a628dd45e", "utils/io/fileutil/source/encoding/test_utf8.csv": "b3c2e6ec634b81b2ebd348a3983fc165", "utils/io/fileutil/test/test_word_in_line.py": "0e2699f99428b73b86fdeb3fca2ee3b3", "utils/io/pmserial/pmqtreadserial.py": "7f31cf4aa590690a8c9e53b4d3599ce8", "utils/io/pmserial/readserial.py": "5cafed26a707eecdac54883dca6d2c33", "utils/io/pmserial/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "utils/settings/settings.py": "a65d80cc4a777b526b057b8efebd6989", "utils/settings/__init__.py": "43d16a290ee34cb378a6c6244e8c0a32", "utils/ui/translation.py": "a75ca908fa328d348adc9106554e35d7", "utils/ui/variableselect.py": "6623e3057f2291f6ad61ee1e55ac58c4", "utils/ui/__init__.py": "05099d0c6cd09966cb7621c9e57c2f13", "utils/ui/app/pmbasicapp.py": "a8cf494179389639ee3a68e39167cdc1", "utils/ui/app/__init__.py": "d41d8cd98f00b204e9800998ecf8427e", "utils/ui/app/test/basicapp_abnormal.py": "74d0fab0335ac9847dd589275e304c64", "utils/ui/app/test/basicapp_pareto.py": "522a51d208d3d32c68e9de0267a9f1fb", "utils/ui/src/balance.png": "0e13e9c8fd6853eedef19ac2ca0d9f01", "utils/ui/src/chemestry.png": "be3234787dcd5ad6b8c03cce7d142dfd", "utils/ui/src/electricity.png": "390b497d0687540630694599edc71dac", "utils/ui/src/engineering machinery.png": "099cdd52b97926617032ff66487cc311", "utils/ui/src/fracture.png": "e2dcccc7d7751d10b0e439a9a8b8f7d3", "utils/ui/src/function.png": "0a6dd73740c6800c913a5dc8556539cb", "utils/ui/src/gauge.png": "167e1ea4af8c9e504c30e734e7761488", "utils/ui/src/histogram.png": "231deddcfe9222512173e3d0b7829728", "utils/ui/src/ic_common_\u751f\u7269&\u81ea\u7136.png": "351343f4046d6d2c7a3405065d3a66a2", "utils/ui/src/loadwave.png": "95280a0b2dbc61a6c817d40e705f0379", "utils/ui/src/log.png": "117ef9da5ed765f2cc31f65bd2a49db9", "utils/ui/src/math_1.png": "a62c3b980b0f9332c56452c2dfac5a8c", "utils/ui/src/math_2.png": "d98240ad143bbc7cc739cac16b18e60a", "utils/ui/src/math_3.png": "0dbbea9ccc5e7cfa409a65e7ab0d16c4", "utils/ui/src/mechanics.png": "e730af4dc4083d52675826590d05dfa8", "utils/ui/src/money.png": "078a6fec99543566f7abd7f9d235cfc1", "utils/ui/src/motor.png": "cb1071e863f9d4108d509a1f0a29ce8e", "utils/ui/src/motor_2.png": "b71bdb729289a54a9330af929f477b39", "utils/ui/src/normal_distribution.png": "18785959972c6076e3201e41ba68d971", "utils/ui/src/physics.png": "67a6b64cee517d8678e2001ebd2af37d", "utils/ui/src/physics_2.png": "75796555027a4edc1bf441a69800de78", "utils/ui/src/plot_1.png": "484e1553dbd4d3b51dc986af7da9126d", "utils/ui/src/plot_2.png": "fa13d212836a556060df8fbee4dd8593", "utils/ui/src/plot_3.png": "bf548bcb5eba63b655fcaafa9af1e50e", "utils/ui/src/plot_4.png": "63658bb0aa5e10850d4cbcefb31bc5ec", "utils/ui/src/roboarm.png": "adc612a5fbe26cbc1ef9964078be30d0", "utils/ui/src/run.png": "fcf7e23f264801b79df841dabdab9417", "utils/ui/src/run_cell.png": "e40eb239205653b61fa2ba5a57f8d378", "utils/ui/src/settings_1.png": "4dc1f5c80740868b1cf0a4f50909dc20", "utils/ui/src/settings_2.png": "e8cd30a0264a6ee00fbe461e72a9fb6e", "utils/ui/src/settings_3.png": "2917d7c1b222d2e235a85f7e677935ca", "utils/ui/src/sinsidual.png": "371e0fdb35b52764d7d9c17774c36a07", "utils/ui/src/statistics.png": "3e1dd67456f93098bc0276c3b37e1b45", "utils/ui/src/statistics_2.png": "524756b6420d9a60cec2212e23112dbc", "utils/ui/src/statistics_3.png": "737c1756516487220aafa992210374bb", "utils/ui/src/viberation.png": "49ccb24861c08a92834e814bf8ea4767", "utils/ui/src/wave.png": "402b0e16aaf792596c734ee454ba25dd", "utils/ui/src/wave_2.png": "ce59ead6a036cca68b02950c9bdcb91a", "utils/ui/src/wave_history.png": "566e2a0ac92bf12f6291e0dd4d272091", "utils/ui/src/\u5206\u5b50\u751f\u7269\u5b66\u5e73\u53f0-\u7070.png": "6a5127ef0f94e54506455e0dd5d8d712", "utils/ui/src/\u751f\u547d\u5065\u5eb7\u4ea7\u4e1a_2\u751f\u7269\u533b\u836f.png": "c6f652bcc942e7c3c244d06726fcf063", "utils/ui/src/\u751f\u7269 (1).png": "9f4b502be694761d44c106a09a61be19", "utils/ui/src/\u751f\u7269 (2).png": "58da036ee4e5ead077590ebb65b80460", "utils/ui/src/\u751f\u7269 (3).png": "9cf816bfb76439a5f366e9beca9bea92", "utils/ui/src/\u751f\u7269 (4).png": "3b699f6ca234d635a8bc3274a7b44020", "utils/ui/src/\u751f\u7269.png": "4bcc3068ba68359848f293c23ac0b670", "utils/ui/src/\u751f\u7269\u8bc6\u522b (1).png": "021f770979cb264bc827ac041bab972b", "utils/ui/src/\u751f\u7269\u8bc6\u522b.png": "d73c19821dbdc9b46facd404afda33f4", "utils/ui/uiutil/datashowutil.py": "a88e7ef43145082c8278f6273e1bfb05", "utils/ui/uiutil/workspaceutil.py": "4a74ba5a7a176257d0e659d4be892301", "utils/ui/uiutil/__init__.py": "d611c6031ffff2a4570872c525a95660", "utils/ui/uiutil/formatting/textformat.py": "dee7f3523b301ceb8bdb0b35da44e456", "utils/ui/uiutil/formatting/__init__.py": "73a717186f47f07e16e0dcb8ed4ed76d", "widgets/frame_less_window.py": "e2a0208d327013c21bd75c71535d05af"}} \ No newline at end of file diff --git a/pyminer/app2.py b/pyminer/app2.py index 0fb9901c..b0197e56 100644 --- a/pyminer/app2.py +++ b/pyminer/app2.py @@ -29,7 +29,7 @@ original_handler = cgitb.handler def exception_handler(i: 'Tuple[ClassVar[BaseException], BaseException]'): - from check_dependency import reinstall_requirements_with_gui + from lib.check_dependency import reinstall_requirements_with_gui global original_handler original_handler(i) print("发生错误。错误详细信息:") @@ -44,7 +44,7 @@ def exception_handler(i: 'Tuple[ClassVar[BaseException], BaseException]'): def on_exception(e): - from check_dependency import ExceptionHandlerDialog + from lib.check_dependency import ExceptionHandlerDialog dlg = ExceptionHandlerDialog(e) dlg.exec_() @@ -52,9 +52,6 @@ def on_exception(e): sys.excepthook.handle = exception_handler -import PySide2 - - os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = utils.get_pysideplugins_directory() os.environ['QT_API'] = 'pyside2' os.environ['PYQTGRAPH_QT_LIB'] = 'PySide2' @@ -85,7 +82,7 @@ from load_modules import load_translator, load_fonts from pmgui import PMToolBarHome, LogOutputConsole t0 = time.time() -from pmlocalserver import server +from lib.localserver import server # TODO:实例化server需要消耗 @@ -209,7 +206,7 @@ class MainWindow(BaseMainWindow): self.on_main_window_shown() - self.start_pmlocalserver() # 只要在插件加载完成之后启动就行,目前放在最后 + self.start_localserver() # 只要在插件加载完成之后启动就行,目前放在最后 self.update_tip_client = UpdateTipClient(True) # 启动程序,检查更新,弹窗提醒 t01 = time.time() @@ -259,12 +256,12 @@ class MainWindow(BaseMainWindow): def moveEvent(self, a0: 'QMoveEvent') -> None: self.window_geometry_changed_signal.emit() - def start_pmlocalserver(self): - """启动本地flask服务器pmlocalserver""" + def start_localserver(self): + """启动本地flask服务器localserver""" server.server_thread.start() def clear_workspace(self): - from features.extensions.extensionlib.extension_lib import extension_lib + from lib.extensions.extensionlib.extension_lib import extension_lib extension_lib.get_interface('ipython_console').run_command('Clearing_Variables_ =\'Clear All\'', hint_text=self.tr('Start Clear...'), hidden=False) extension_lib.get_interface('ipython_console').run_command('get_ipython().clear_all()', diff --git a/pyminer/core/algorithms/pyminer_util/communication.py b/pyminer/core/algorithms/pyminer_util/communication.py index 5d687d58..bae9fd67 100644 --- a/pyminer/core/algorithms/pyminer_util/communication.py +++ b/pyminer/core/algorithms/pyminer_util/communication.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from typing import List -import pyminer_comm -from pyminer_comm.base import shm_allowed +import lib.comm +from lib.comm.base import shm_allowed def get_var(var_name: str, preview=False) -> object: @@ -38,12 +38,12 @@ def get_var(var_name: str, preview=False) -> object: try: if preview or (not shm_allowed()): if preview: - var = pyminer_comm.get_vars([var_name], preview=True).get(var_name) + var = lib.comm.get_vars([var_name], preview=True).get(var_name) else: - var = pyminer_comm.get_vars([var_name], preview=False).get(var_name) + var = lib.comm.get_vars([var_name], preview=False).get(var_name) return var else: - return pyminer_comm.shm_get_vars([var_name]).get(var_name) + return lib.comm.shm_get_vars([var_name]).get(var_name) except ConnectionRefusedError: raise ConnectionRefusedError('Cannot connect to workspace. Please confirm that PyMiner has been started!') @@ -51,9 +51,9 @@ def get_var(var_name: str, preview=False) -> object: def get_vars(var_names: List) -> object: try: if not shm_allowed(): - return pyminer_comm.get_vars(var_names, preview=False) + return lib.comm.get_vars(var_names, preview=False) else: - return pyminer_comm.shm_get_vars(var_names) + return lib.comm.shm_get_vars(var_names) except ConnectionRefusedError: raise ConnectionRefusedError('Cannot connect to workspace. Please confirm that PyMiner has been started!') @@ -92,7 +92,7 @@ def set_var(var_name: str, var: object, provider: str = 'external') -> None: Examples --------- - >>> from pyminer_algorithms import * + >>> from core.algorithms import * >>> set_var('x',[1,2,3,4,5]) >>> get_var('x') [1,2,3,4,5] @@ -107,9 +107,9 @@ def set_var(var_name: str, var: object, provider: str = 'external') -> None: except NameError: pass if not shm_allowed(): - pyminer_comm.set_vars({var_name: var}) + lib.comm.set_vars({var_name: var}) else: - pyminer_comm.shm_set_vars({var_name: var}) + lib.comm.shm_set_vars({var_name: var}) except ConnectionRefusedError: raise ConnectionRefusedError('Cannot connect to workspace. Please confirm that PyMiner has been started!') @@ -145,14 +145,14 @@ def get_var_names(type_filter: str = '') -> List[str]: """ assert type_filter in ['dataframe', 'array', 'numeric', ''] # type_filter不能乱! try: - return pyminer_comm.get_var_names(type_filter) + return lib.comm.get_var_names(type_filter) except ConnectionRefusedError: raise ConnectionRefusedError('Cannot connect to workspace. Please confirm that PyMiner has been started!') def del_var(var_name: str): try: - pyminer_comm.delete_variables([var_name]) + lib.comm.delete_variables([var_name]) except: import traceback traceback.print_exc() @@ -161,9 +161,9 @@ def del_var(var_name: str): def set_vars(var_dic: dict, provider=''): try: if not shm_allowed(): - pyminer_comm.set_vars(var_dic) + lib.comm.set_vars(var_dic) else: - pyminer_comm.shm_set_vars(var_dic) + lib.comm.shm_set_vars(var_dic) except: import traceback traceback.print_exc() diff --git a/pyminer/features/README.md b/pyminer/features/README.md deleted file mode 100644 index 20374cc9..00000000 --- a/pyminer/features/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# 图形界面部分代码说明以及代码结构 - -## 项目规范说明 - -图形界面部分的项目规范基于Python3.8,但尽量不使用装饰器、动态属性、海象运算符等特殊语法,从而保证规范、清晰、易于维护。 - -### 大规模使用的特性: - -- 1、typehint。(类型提示) -主要包含typehint的一般写法(比如`def func(s:str):`)提示时导入的TYPE_CHECKING。 -- 2、lambda的匿名函数及其相关性质 -- 3、PyQt5的基础知识(包括布局、信号与槽等)。界面部分可以使用设计师或者纯手写代码。 - -### 代码命名规范: - -- 1、**变量名、函数名、方法名** 使用小写字母加下划线,从而与pyqt的原生接口相区分。 -- 2、**类名** 使用大写字母驼峰命名,首字母或者缩写大写。 -- 3、**包名、文件名** 使用纯小写字母+数字,除必要之外不使用下划线。 - -## 项目的结构: - -与图形界面有关的类都定义在ui文件夹下面。 - -- base文件夹:里面是与老版本Pyminer进行兼容的代码 -- common文件夹:通用的代码,负责与操作系统沟通,对Pyminer提供统一的函数。比如打开系统的命令行窗口等。 -- generalwidgets:定义了通用控件,只依赖于PyQt或者generalwidgets包内部互相依赖,不依赖于pyminer。 -- pmwidgets:半通用控件,与其他部分没有耦合,但依赖于Pyminer的主界面才能执行功能。 -- source:资源文件,图像、图标等 -- test:测试文件(目前不用) - -注意在generalwidgets和pmwidgets命名的区别:generalwidgets中控件类名都以PMG开头,pmwidgets里面都以PM开头。G代表‘general’ - -## 界面插入的逻辑 - -对于对话框、工具栏来讲,自然无所谓插入界面的问题;但对于以dockwidget形式停靠在窗体各个位置的控件而言,位置的问题就很重要了! - -相应的参数有:{'n', 's', 'w', 'e', 'nw', 'ne', 'sw', 'se', 'c'}几种,分别代表上、下、左、右,左上.... - -逻辑是这样的: - -* n代表y方向最小(因为Qt的坐标系统就是左上角为原点),x方向中等; -* w代表x方向最小,y方向中等; -* se代表x,y方向都是最大(右下角)。 -* c代表x\y都是中等大小。 - -比如屏幕中的控件有三列的时候: - -![aaa](assets/three_columns.png) - -'中等'代表插入第二列,'最小'代表插入第一列;’最大‘代表插入最后一列。 -如果列数不足三列,假如为1或者2列,那么max代表的自然就是第1和第2列。因此即便不满足要求,也不会出现异常。 - -中间的含义是第2个(如果有的话。如果没有,那么也是插入第一列。) - -选出列之后,再选择行,也就是Y坐标。同样n代表Y最小,s代表y最大。没有n或者s的话,代表取中间。 -这样,将参数设置为`sw`之后,就可以插入到这里了。 - -![aaa](assets/sw_add_to_left_bottom.png) - -p.s. 以上的`n`、`s`、`w`、`e`、`c`代表的分别是`东西南北中`,而比如`sw`就代表西北,亦即左上角。 diff --git a/pyminer/features/auth/__init__.py b/pyminer/features/auth/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/auth/authlocalserver.py b/pyminer/features/auth/authlocalserver.py deleted file mode 100644 index a8fc3bf3..00000000 --- a/pyminer/features/auth/authlocalserver.py +++ /dev/null @@ -1,18 +0,0 @@ -from flask import Blueprint, render_template - -auth = Blueprint('auth', __name__, template_folder='templates') - - -@auth.route('/register') -def show_register_page(): - return render_template('register.html') - - -@auth.route('/login') -def show_login_page(): - return render_template('login.html') - - -@auth.route('/reset_password') -def show_reset_password_page(): - pass diff --git a/pyminer/features/auth/authmanager.py b/pyminer/features/auth/authmanager.py deleted file mode 100644 index 938c9f03..00000000 --- a/pyminer/features/auth/authmanager.py +++ /dev/null @@ -1,42 +0,0 @@ -class AuthManager(): - """ - 用户认证管理类 - """ - - @classmethod - def __new__(cls, *args): - if not hasattr(cls, 'instance'): - instance = super().__new__(cls) - cls.instance = instance - return cls.instance - - def __init__(self): - self.login_status = False - self.browser_id = None - - def show_login_page(self): - from features.extensions.extensionlib.extension_lib import extension_lib - extension_lib.get_interface('embedded_browser').open_url(url='http://localhost:5000/auth/login', side='right') - - def show_register_page(self): - from features.extensions.extensionlib.extension_lib import extension_lib - extension_lib.get_interface('embedded_browser').open_url(url='http://localhost:5000/auth/register', side='right') - - @staticmethod - def get_instance() -> 'AuthManager': - return AuthManager.instance - - -_am = AuthManager() - -from pmlocalserver.server import server -from .authlocalserver import auth - -server.register_blueprint(auth, url_prefix='/auth') - -if __name__ == '__main__': - am = AuthManager() - AuthManager.get_instance().login_status = True - assert True == AuthManager.get_instance().login_status - AuthManager.get_instance().login_status = False - assert False == AuthManager.get_instance().login_status diff --git a/pyminer/features/auth/templates/login.html b/pyminer/features/auth/templates/login.html deleted file mode 100644 index f3c019d1..00000000 --- a/pyminer/features/auth/templates/login.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - 8_常用注册页面的表单实例(含验证).html - - - - - - - - - - - - - -
登录:
-
- - - - - - - - - - - - - - - -
账号:
密码:
- -
-
- - \ No newline at end of file diff --git a/pyminer/features/auth/templates/register.html b/pyminer/features/auth/templates/register.html deleted file mode 100644 index e8083998..00000000 --- a/pyminer/features/auth/templates/register.html +++ /dev/null @@ -1,207 +0,0 @@ - - - - - 8_常用注册页面的表单实例(含验证).html - - - - - - - - - - - - - - - -
用户注册:
-
- - - - - - - - - - - - - - - - - - - - - - - - -
用户名:
邮箱:
密码:
重复密码: -
- -
-
- - - \ No newline at end of file diff --git a/pyminer/features/extensions/__init__.py b/pyminer/features/extensions/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/extensions/extensionlib/__init__.py b/pyminer/features/extensions/extensionlib/__init__.py deleted file mode 100644 index 4019c0a2..00000000 --- a/pyminer/features/extensions/extensionlib/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .baseext import BaseExtension, BaseInterface -from .extension_lib import extension_lib -from features.ui import pmwidgets diff --git a/pyminer/features/extensions/extensionlib/baseext.py b/pyminer/features/extensions/extensionlib/baseext.py deleted file mode 100644 index 8b3f3598..00000000 --- a/pyminer/features/extensions/extensionlib/baseext.py +++ /dev/null @@ -1,61 +0,0 @@ -import logging -from typing import Dict, TYPE_CHECKING - -if TYPE_CHECKING: - from PySide2.QtWidgets import QWidget - from features.extensions.extensionlib.extension_lib import ExtensionLib - -logger = logging.getLogger(__name__) - - -class BaseExtension: - widget_classes: Dict[str, 'QWidget'] = None - widgets: Dict[str, 'QWidget'] = None - extension_lib: 'ExtensionLib' = None - public_interface: 'BaseInterface' = None - settings: Dict[str, object] = None - interface: 'BaseInterface' - - def get_widget(self, name: str): - return self.widgets[name] - - def _on_loading(self): - logger.info(f'{self.info.display_name}即将被加载') - self.on_loading() - - def on_loading(self): - pass - - def _on_load(self): - logger.info(f'{self.info.display_name}已经被加载') - self.interface._set_extension(self) - self.on_load() - - def on_load(self): - pass - - def _on_install(self): - logger.info(f'{self.info.display_name}被安装') - self.on_install() - - def on_install(self): - pass - - def _on_uninstall(self): - logger.info(f'{self.info.display_name}被卸载') - self.on_uninstall() - - def on_uninstall(self): - pass - - def _on_close(self): - logger.info(f'{self.info.display_name}已关闭') - self.on_close() - - def on_close(self): - pass - - -class BaseInterface: - def _set_extension(self, extension): - self.extension = extension diff --git a/pyminer/features/extensions/extensionlib/extension_lib.py b/pyminer/features/extensions/extensionlib/extension_lib.py deleted file mode 100644 index 15663e75..00000000 --- a/pyminer/features/extensions/extensionlib/extension_lib.py +++ /dev/null @@ -1,553 +0,0 @@ -import inspect -import os -from typing import TYPE_CHECKING, Callable, Dict, List, Tuple, Optional, Any - -from PySide2.QtCore import QRect, Signal -from PySide2.QtWidgets import QWidget, QDialog - -import utils -from features.extensions.extensionlib import baseext -from features.extensions.extensions_manager.manager import extensions_manager -from features.io.exceptions import PMExceptions -from features.ui import pmwidgets -from features.workspace.data_adapter import UniversalAdapter -from features.workspace.data_manager import data_manager -from features.workspace_old.datamanager.datamanager import data_manager as data_manager_old -from pyminer_comm.base import DataDesc -from utils import get_main_window - -if TYPE_CHECKING: - from pmgwidgets import PMGToolBar - - -class ExtensionLib: - pm_widgets = pmwidgets - BaseInterface = baseext.BaseInterface - BaseExtension = baseext.BaseExtension - - @staticmethod - def get_interface(name: str) -> BaseInterface: - """获取名为 ``name`` 的插件的公共接口(由interface定义) - - Args: - name: 插件名称 - """ - return extensions_manager.get_extension(name).public_interface - - @staticmethod - def insert_widget(widget, insert_mode, config=None): - """ - 在主界面上插入一个控件。 - Args: - widget: - insert_mode: - config: - - Returns: - - """ - return extensions_manager.ui_inserters[insert_mode]( - widget, config) - - @staticmethod - def get_main_program_dir(): - """ - 获取主程序的根目录 - Returns: - - """ - return utils.get_root_dir() - - class UI: - @staticmethod - def widget_exists(widget_name: str) -> bool: - if widget_name in get_main_window().dock_widgets.keys(): - return True - else: - return False - - @staticmethod - def get_toolbar(toolbar_name: str) -> 'PMGToolBar': - """ - 获取工具栏 - - Args: - toolbar_name:工具栏名称 - - Returns: - - """ - tb = get_main_window().toolbars.get(toolbar_name) - - return tb - - @staticmethod - def get_toolbar_widget(toolbar_name: str, widget_name: str) -> Optional['QWidget']: - """ - 获取工具栏上的控件(按钮等) - - Args: - toolbar_name:工具栏名称 - widget_name:工具栏上的控件名称 - - Returns: - - """ - toolbar = ExtensionLib.UI.get_toolbar(toolbar_name) - if toolbar is not None: - widget = toolbar.get_control_widget(widget_name) - return widget - return None - - @staticmethod - def get_main_window_geometry() -> 'QRect': - """ - 获取主界面的尺寸 - - Returns: - - """ - return get_main_window().geometry() - - @staticmethod - def raise_dock_into_view(dock_widget_name: str) -> None: - """ - 将界面上的控件提升到可视的位置 - - Args: - dock_widget_name: - - Returns: - - """ - return get_main_window().raise_dock_into_view(dock_widget_name) - - @staticmethod - def get_default_font() -> str: - """ - 获取默认字体文件 - - Returns: Filepath of font. - - """ - app = get_main_window() - return os.path.join(app.font_dir, app.default_font) - - @staticmethod - def switch_toolbar(toolbar_name: str, switch_only: bool = True): - """ - 切换工具栏 - - Args: - toolbar_name: - switch_only: - - Returns: - - """ - app = get_main_window() - app.switch_toolbar(toolbar_name, switch_only) - - @staticmethod - def exec_dialog(dlg: QDialog): - assert isinstance(dlg, QDialog) - win = get_main_window() - dlg.setParent(win) - dlg.exec_() - - class Signal: - @staticmethod - def get_close_signal() -> Signal: - """ - 获取关闭信号 - - Returns: - - """ - return get_main_window().close_signal - - @staticmethod - def get_window_geometry_changed_signal(): - """ - 获取窗口位置和尺寸变化的事件 - - Returns: - - """ - return get_main_window().window_geometry_changed_signal - - @staticmethod - def get_layouts_ready_signal(): - """ - 获取布局加载完毕的事件 - - Returns: - - """ - return get_main_window().layouts_ready_signal - - @staticmethod - def get_widgets_ready_signal(): - """ - 获取控件加载完毕的事件 - - Returns: - - """ - return get_main_window().widgets_ready_signal - - @staticmethod - def get_events_ready_signal(): - """ - 获取界面信号和事件绑定完毕的事件。 - - Returns: - - """ - return get_main_window().events_ready_signal - - @staticmethod - def get_settings_changed_signal() -> 'Signal': - """ - 获取设置发生变化时的事件。 - - Returns: - - """ - return get_main_window().settings_changed_signal - - class Program: - @staticmethod - def add_settings_panel(text: str, panel_content: List[Tuple[str, str]]): - """ - 添加设置面板 - - Args: - text: - panel_content: - - Returns: - - """ - - return get_main_window().main_option_form.add_settings_panel(text, panel_content) - - @staticmethod - def show_log(level: str, module: str, content: str) -> None: - """ - 调用——PluginInterface.show_log('info','CodeEditor','新建文件') - 输出——2020-08-29 23:43:10 hzy INFO [CodeEditor]:新建文件 - Args: - level: 类型,比如‘info’ - module: 模块。比如'Jupyter' - content: 内容。自定义的字符串 - - Returns: - """ - get_main_window().slot_flush_console(level, module, content) - - @staticmethod - def get_main_program_dir(): - """ - 获取主程序路径 - - Returns: - - """ - return utils.get_root_dir() - - @staticmethod - def get_settings_item_from_file(file: str, item: str, mode: str = "user"): - """ - 从设置文件中获取设置项 - Args: - file: - item: - mode: - - Returns: - - """ - return utils.get_settings_item_from_file(file, item, mode) - - @staticmethod - def write_settings_item_to_file(file: str, item: str, value: Any): - """ - 将配置项写入设置文件中 - Args: - file: - item: - value: - - Returns: - - """ - utils.write_settings_item_to_file(file, item, value) - get_main_window().settings_changed_signal.emit() - - @staticmethod - def set_work_dir(work_dir: str) -> None: - """ - 设置当前工作路径 - - Args: - work_dir: - - Returns: - - """ - utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", work_dir) - get_main_window().settings_changed_signal.emit() - - @staticmethod - def get_work_dir() -> str: - """ - 获取当前工作路径 - - Returns: - - """ - - dir = utils.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR") - if (not isinstance(dir, str)) or (not os.path.exists(dir)): - dir = os.path.join(os.path.expanduser("~"), "Desktop") - utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", dir) - return dir - - @staticmethod - def get_theme() -> str: - """ - 获取主题 - Returns: - - """ - return utils.get_settings_item_from_file("config.ini", "MAIN/THEME") - - @staticmethod - def run_python_file(file_path: str, interpreter_path: str): - """ - 运行Python文件命令 - TODO: Write a shell console into pyminer. - - Args: - file_path: - - Returns: - - """ - raise DeprecationWarning - - @staticmethod - def get_plugin_data_path(plugins_name: str) -> str: - """ - 获取插件的数据文件路径 - Args: - plugins_name: - - Returns:str,文件夹路径。 - - """ - ext = extensions_manager.get_extension(plugins_name) - # assert ext is not None, 'Extension named %s isn\'t exist!' % plugins_name - path = os.path.join(os.path.expanduser('~'), '.pyminer', 'packages') - if not os.path.exists(path): - os.mkdir(path) - plugin_data_path = os.path.join(path, plugins_name) - if not os.path.exists(plugin_data_path): - os.mkdir(plugin_data_path) - return plugin_data_path - - @staticmethod - def show_exception_occured_panel(error: BaseException, solution: str, solution_command: str = ''): - """ - - :param error: - :param solution: - :param solution_command: - :return: - """ - PMExceptions.get_instance().emit_exception_occured_signal(error, solution, solution_command) - - class Data: - @staticmethod - def get_adapter(key: str) -> UniversalAdapter: - return data_manager[key] - - @staticmethod - def clear(): - data_manager_old.clear() - - @staticmethod - def delete_variable(var_name: str, provider: str = 'unknown'): - """ - 删除变量 - Args: - var_name: - provider: - - Returns: - - """ - data_manager_old.delete_data(var_name, provider) - - @staticmethod - def get_all_variable_names() -> List[str]: - """ - 获取所有的变量名 - - Returns: - - """ - return list(data_manager.container.keys()) - - @staticmethod - def get_all_public_variable_names() -> List[str]: - """ - 获取所有非保留的变量的名称 - - Returns: - - """ - return list(data_manager_old.get_all_public_var().keys()) - - @staticmethod - def get_all_variables() -> Dict[str, object]: - """ - 获取全部变量(包含保留类型,可能返回结果比较乱,需要审慎使用) - - Returns: - """ - return data_manager_old.get_all_var() - - @staticmethod - def get_all_public_variables() -> Dict[str, object]: - """ - 获取所有的外部可访问变量。 - - Returns: - """ - return data_manager_old.get_all_public_var() - - @staticmethod - def add_data_changed_callback(callback: Callable[[str, Any, str], None]) -> None: - """ - 添加数据改变时触发的回调函数 - - Args: - callback: - - Returns:None - """ - assert callable(callback) - assert len( - list(inspect.signature(callback).parameters.keys())) == 3, 'Function args should be 3' - data_manager_old.on_modification(callback) - - @staticmethod - def remove_data_changed_callback(callback: Callable): - if callback in data_manager_old.modification_callback_actions: - data_manager_old.modification_callback_actions.remove(callback) - print('removed callback!') - - @staticmethod - def add_data_deleted_callback(deletion_callback: Callable[[str, str], None]): - """ - 绑定的函数,要求其输入的函数参数为两个。 - - Args: - deletion_callback: - - Returns: - - """ - assert callable(deletion_callback) - assert len( - list(inspect.signature(deletion_callback).parameters.keys())) == 2, 'Function args should be 2' - data_manager_old.on_deletion(deletion_callback) - - @staticmethod - def var_exists(var_name: str): - """ - 判断var_name对应的变量是否存在 - Args: - var_name: - - Returns: - - """ - return var_name in data_manager - - @staticmethod - def set_var(varname: str, variable, provider='unknown', **info): - """ - - Args: - varname: - variable: - provider: - **info: - - Returns: - - """ - assert isinstance(variable, DataDesc), \ - 'variable name %s ,%s is not type DataDesc' % (varname, variable) - data_manager_old.set_var(varname, variable, provider) - - @staticmethod - def get_var(var_name: str) -> object: - """ - - Args: - var_name: - - Returns: - - """ - raise DeprecationWarning - # return get_var(var_name) - - @staticmethod - def get_data_desc(var_name) -> DataDesc: - desc = data_manager_old.get_var(var_name) - assert isinstance(desc, DataDesc), repr(desc) - return desc - - @staticmethod - def update_var_dic(var_dic: dict, provider: str, metadata_dic: dict = None): - """ - - Args: - var_dic: - provider: - metadata_dic: - - Returns: - - """ - raise DeprecationWarning - - @staticmethod - def get_metadata(varname: str) -> dict: - """ - - Args: - varname: - - Returns: - - """ - return data_manager_old.get_data_info(varname) - - @staticmethod - def get_all_metadata() -> dict: - """ - - Returns: - - """ - d = {k: v for k, v in data_manager_old.metadataset.items()} - return d - - -extension_lib = ExtensionLib() diff --git a/pyminer/features/extensions/extensionlib/extensionlib.md b/pyminer/features/extensions/extensionlib/extensionlib.md deleted file mode 100644 index 5e5bf1e8..00000000 --- a/pyminer/features/extensions/extensionlib/extensionlib.md +++ /dev/null @@ -1,397 +0,0 @@ -ExtensionLib: - -## 基本方法 - -def get_interface(self, name: str) -> BaseInterface: -获取名为`name`的插件的公共接口(由interface定义) - -- Args: -- name: - -Returns: Interface,须继承BaseInterface,并且在插件的main.py文件中定义。 - -### 在界面的可停靠窗口上插入控件 - - -def insert_widget(self, widget, insert_mode, config=None): - -在主界面上插入一个控件。 -Args: -- widget: 被插入的控件(继承QWidget) -- insert_mode: 插入方式(字符串描述) -- config: 插入的位置等。 - -Returns: - -### 获取主程序路径 - -def get_main_program_dir(self): - -- 获取主程序的根目录 - - -## UI子类(图形界面方法) - -class UI(): -### 获取工具栏方法 -@staticmethod -def get_toolbar(toolbar_name: str) -> 'PMGToolBar': -获取工具栏 - -Args: -- toolbar_name:工具栏名称 - -Returns: 当前工具栏。若工具栏不存在,则返回None。 - -### 获取工具栏上的控件的方法 -@staticmethod -def get_toolbar_widget(toolbar_name: str, widget_name: str) -> Optional['QWidget']: -获取工具栏上的控件(按钮等) - -Args: -- toolbar_name:工具栏名称 -- widget_name:工具栏上的控件名称 - -Returns: QWidget,工具栏上的控件。如果没有则返回None。 - - -@staticmethod -def add_translation_file(file_name: str) -> None: -添加翻译文件 -TODO:这个功能不太好,建议去掉,直接用QApplication里的方法来添加。 -Args: -file_name: -Deprecated!! -Returns: -### 获取主界面的位置和尺寸 -@staticmethod -def get_main_window_geometry() -> 'QRect': -获取主界面的尺寸 - -Returns: QRect(x,y,w,h),亦即MainWindow的geometry。 -### 将当前的停靠窗口提升到可见位置 -@staticmethod -def raise_dock_into_view(dock_widget_name: str) -> None: -将界面上的控件提升到可视的位置 - -Args: -dock_widget_name: - -Returns: -### 获取默认字体文件的路径 -@staticmethod -def get_default_font() -> str: - -获取默认字体文件的位置 - -Returns: Filepath of font. -### 切换工具栏 -@staticmethod -def switch_toolbar(toolbar_name: str, switch_only: bool = True): -切换工具栏 - -Args: -- toolbar_name: -- switch_only: 如果为True,那么在调用时只会切换工具栏,若当前的工具栏名称为`name`,则调用多次,也不会改变当前工具栏的显示状态。为False的时候,若当前工具栏名称为`name`,那么就会改变显示状态,亦即原先显示的隐藏,原先隐藏的显示。 - -Returns: None -## 信号相关 -class Signal(): -### 注意事项: -PyMiner采用QtPy做PySide2和PyQt5之间的转换。目前,PyMiner使用的是PyQt5,因此返回类型为pyqtSignal。未来移植到PySide2平台后,则为Signal. -### 获取主界面关闭事件 -@staticmethod -def get_close_signal() -> Signal: -获取关闭信号 - -Returns: 主界面的窗口关闭信号 - - -### 获取窗口位置、尺寸改变的信号 -@staticmethod -def get_window_geometry_changed_signal(): - -获取窗口位置和尺寸变化的信号 - -Returns - -### 获取布局加载完成信号 -@staticmethod -def get_layouts_ready_signal(): -""" -获取布局加载完毕的事件 - -Returns: - -""" -### 获取控件加载完毕的信号 -@staticmethod -def get_widgets_ready_signal(): -获取控件加载完毕的事件 - -Returns: - -### 获取事件绑定完毕的信号 -@staticmethod -def get_events_ready_signal(): -获取界面信号和事件绑定完毕的事件。 - -Returns: - -### 获取设置被改变的信号 -@staticmethod -def get_settings_changed_signal() -> 'Signal': -获取设置发生变化时的事件。 - -Returns: 主界面设置发生变更时的信号 -## 程序 - - class Program(): -### 添加设置面板 -@staticmethod -def add_settings_panel(text: str, panel_content: List[Tuple[str, str]]): -添加一个设置面板到主界面的设置栏。 -要求就是设置栏的语法符合pmgpanel语法。 -Args: -text: -panel_content: - -Returns: - -### 在日志面板显示日志 -@staticmethod -def show_log(level: str, module: str, content: str) -> None: - -调用——PluginInterface.show_log('info','CodeEditor','新建文件') -输出——2020-08-29 23:43:10 hzy INFO [CodeEditor]:新建文件 -Args: -level: 类型,比如‘info’ -module: 模块。比如'Jupyter' -content: 内容。自定义的字符串 - -Returns: - -### 获取主程序路径 -@staticmethod -def get_main_program_dir(): -获取主程序路径 - -Returns: - -### 添加翻译文件 -@staticmethod -def add_translation(locale: str, text: dict): -""" - -Args: -locale: -text: - -Returns: - -""" -return pmlocale.add_locale(locale, text) - -### 翻译 -@staticmethod -def _(text): - -Args: -text: - -Returns: - - -### 获取设置 -@staticmethod -def get_settings() -> Dict[str, str]: -""" - -Returns: - -""" - -### 设置当前工作路径 -@staticmethod -def set_work_dir(work_dir: str) -> None: - -设置当前工作路径 - -Args: -work_dir: - -Returns: - -""" - -### 获取当前工作路径 - -@staticmethod -def get_work_dir() -> str: - -获取当前工作路径 - -Returns: -### 运行Python文件命令 -@staticmethod -def run_python_file(file_path: str): -""" -运行Python文件命令 -TODO: Write a shell console into pyminer. - -Args: -file_path: - -Returns: None - -## 数据服务相关 - -class Data(): -### 删除变量 -@staticmethod -def delete_variable(var_name: str, provider: str = 'unknown'): -""" -删除变量 -Args: -var_name: -provider: - -Returns: - -""" -data_manager.delete_data(var_name, provider) - -### 获取所有的变量名 -@staticmethod -def get_all_variable_names() -> List[str]: - -获取所有的变量名 - -Returns: - -### 获取所有非保留的变量的名称 -@staticmethod -def get_all_public_variable_names() -> List[str]: - -获取所有非保留的变量的名称 - -Returns: - -### 获取全部变量(包含保留类型) -@staticmethod -def get_all_variables() -> Dict[str, object]: - -获取全部变量(包含保留类型,可能返回结果比较乱,需要审慎使用) - -Returns: - -### 获取所有的外部可访问变量。 -@staticmethod -def get_all_public_variables() -> Dict[str, object]: - -获取所有的外部可访问变量。 - -Returns: - -### 添加数据改变时触发的回调函数 -@staticmethod -def add_data_changed_callback(callback: Callable[[str, str], None]) -> None: - -添加数据改变时触发的回调函数 - -Args: -callback: - -Returns:None - -### 移除数据改变时触发的回调函数 -@staticmethod -def remove_data_changed_callback(callback: Callable): - - -### 添加数据删除时触发的回调函数 -@staticmethod -def add_data_deleted_callback(deletion_callback: Callable[[str, str], None]): -绑定的函数,要求其输入的函数参数为两个。 - -Args: -deletion_callback: - -Returns: - - -​ -@staticmethod -def get_all_vars_of_type(types: Union[object, Tuple]): - -按照类型过滤变量。 - -Args: -types: - -Returns: - - -@staticmethod -def var_exists(var_name: str): - -判断var_name对应的变量是否存在 -Args: -var_name: - -Returns: - - -@staticmethod -def set_var(varname: str, variable, provider='unknown', **info): - -Args: -varname: -variable: -provider: -\*\*info: - -Returns: None - -@staticmethod -def get_var(var_name: str) -> object: - -Args: -var_name: - -Returns: - - -@staticmethod -def update_var_dic(var_dic: dict, provider: str, metadata_dic: dict = None): - -Args: -var_dic: -provider: -metadata_dic: - -Returns: - - -@staticmethod -def get_metadata(varname: str) -> dict: - """ - -Args: -varname: - -Returns: - -""" -return data_manager.get_data_info(varname) - -@staticmethod -def get_all_metadata() -> dict: -""" - -Returns: - -""" -d = {k: v for k, v in data_manager.metadataset.items()} -return d - diff --git a/pyminer/features/extensions/extensionlib/readme.md b/pyminer/features/extensions/extensionlib/readme.md deleted file mode 100644 index e17cd64f..00000000 --- a/pyminer/features/extensions/extensionlib/readme.md +++ /dev/null @@ -1,31 +0,0 @@ -# 插件开发指南: -## PyMiner自带的可停靠子窗口名称: -|中文名称|程序内部名称| -|---------|------------| -| 编辑器 | code_editor| -|ipython控制台| ipython_console| -|工作空间显示器| workspace_inspector| -|变量视图|data_view_table| -|文件树|file_explorer| - -这些控件都有便捷的借口函数方式对其进行访问。将它们的名称列在这里的原因是, -插件和以上系统自带的控件,**名称不能相同**。 - -## Pyminer工具栏中按钮的获取 -### 主页工具栏 -|内部名称 |中文名称| -|---------|---------| -|'button_new_script'|'新建\n脚本'| -|'button_new'|'新建'| -|'button_open'|'打开'| -|'button_import_data'|'导入\n数据',| -|'button_save_workspace'|'保存\n工作区',| -|'button_new_variable'|'新建变量'| -|'button_open_variable'|'打开变量'| -|'button_clear_workspace'|'清除工作区'| -|'button_search_for_files'|'查找文件'| -|'button_compare_files'|'文件比较'| -|'button_settings'|'设置'| -|'button_help'| '帮助'| -|'view_config'|'视图'| - diff --git a/pyminer/features/extensions/extensions_manager/ExtensionLoader.py b/pyminer/features/extensions/extensions_manager/ExtensionLoader.py deleted file mode 100644 index d7c9aa50..00000000 --- a/pyminer/features/extensions/extensions_manager/ExtensionLoader.py +++ /dev/null @@ -1,199 +0,0 @@ -import importlib -import json -import logging -import os -import sys -from collections import namedtuple - -import utils -from features.io.exceptions import pyminer_exc_mgr - -logger = logging.getLogger('extensionmanager.extensionloader') -# from features.extensions.extensions_manager import log - - -Info = namedtuple('Info', - ['icon', - 'name', - 'display_name', - 'version', - 'description', - 'path', - 'type_', - 'group']) - - -class PublicInterface: - pass - - -class ExtensionLoader: - def __init__(self, manager): - self.manager = manager - # 这里不能直接写self.path,因为所有入口文件都叫main.py,会被Python缓存起来 - self.import_path = os.path.join(utils.get_root_dir(), 'packages') - sys.path.append(self.import_path) # 将模块导入路径设置为扩展文件夹,这样可以直接导入入口文件 - self.extension_lib_path = os.path.join( - utils.get_root_dir(), 'pyminer2', 'extensions', 'extensionlib') - sys.path.append(self.extension_lib_path) - - def load(self, file, ui_inserters): - self.package = json.load(file) - self.ui_inserters = ui_inserters - try: - self.name = self.package['name'] - self.display_name = self.package['display_name'] - self.version = self.package['version'] - self.description = self.package['description'] - self.icon = self.package['icon'] - self.type_, self.group = self.package.get( - 'group', '未知类型/未知分组').split('/') - - self.path = os.path.join( - utils.get_root_dir(), 'packages', - self.name) # 扩展文件夹路径 - - main_config = self.package.get( - 'main', {'file': 'main.py', 'main': 'Extension'}) - main_class = self.load_class( - main_config['file'], main_config['main']) - self.main = main_class() - from features.extensions.extensionlib.extension_lib import extension_lib - self.main.extension_lib = extension_lib - self.binding_info() - try: - self.main._on_loading() - except Exception as e: - logger.error(e, exc_info=True) - - interface_config = self.package.get( - 'interface', {'file': 'main.py', 'interface': 'Interface'}) - self.main.interface = self.load_class( - interface_config['file'], interface_config['interface'])() - self.main.public_interface = self.create_public_interface( - self.main.interface) - - for key in getattr(self.main.interface, 'ui_inserters', []): - self.ui_inserters[f'extension_{self.name}_{key}'] = self.main.interface.ui_inserters[key] - - self.main.widget_classes = {} - self.main.widgets = {} # store auto inserted widgets - for widget in self.package['widgets']: - widget_class = self.load_widget(widget) - widget_class_name = widget_class.__name__ - self.main.widget_classes[widget_class_name] = widget_class - - if 'settings' in self.package: - assert isinstance(self.package['settings'], str) - settings_path = os.path.join( - self.path, self.package['settings']) - try: - with open(settings_path, 'r') as f: - settings = json.loads(f.read()) - except Exception as e: - logger.exception(e, exc_info=True) - else: - self.main.settings = settings - - self.manager.vermanager.set_current_modules( - [f'{self.name}=={self.version}']) - - if 'requirements' in self.package: - requirements = self.package['requirements'] - assert isinstance(requirements, list) - solvable, conflict = self.manager.vermanager.check_requirements( - requirements) - if conflict: - raise Exception(f'Conflicts in extensions {conflict}') - if solvable: - for requirement in solvable: - self.manager.enable_extension(requirement) - - try: - self.main._on_load() - except ImportError as e: - import traceback - traceback.print_exc() - if hasattr(e, 'name'): - command = '{executable} -m pip install {package_name}'.format( - package_name=e.name, executable=sys.executable) - else: - command = '' - pyminer_exc_mgr.emit_exception_occured_signal( - e, 'try install module', command) - - except Exception as e: - logger.error(e, exc_info=True) - return self.main - except KeyError as e: - logger.error(f'插件的Package.json不完整 {e}', exc_info=True) - - def binding_info(self): - self.main.info = Info( - name=self.name, - icon=self.icon, - display_name=self.display_name, - description=self.description, - version=self.version, - path=self.path, - group=self.group, - type_=self.type_ - ) - - def import_module(self, path): - filepath = os.path.join(self.path, path) - - # pyminer_paths = [path for path in sys.path if 'pyminer' in path and path not in - # (self.import_path, self.extension_lib_path)] - # for path in pyminer_paths: - # sys.path.remove(path) - # pyminer_paths = [] - - try: - package_name = self.name - module_name = os.path.splitext(os.path.basename(filepath))[0] - module_path = f'{package_name}.{module_name}' - module = None - module = importlib.import_module(module_path) - - except Exception as e: - logger.error(e, exc_info=True) - module = None - # sys.path.extend(pyminer_paths) - return module - - def load_class(self, file, class_name): - path = os.path.join(self.path, file) - # TODO 这里的设置将导致奇怪的错误,即模块不再为单例模式,而这是Python中的一个重要特性 - module = self.import_module(path) - if module: - if hasattr(module, class_name): - return getattr(module, class_name) - else: - logger.error(f"{file}文件中不存在{class_name}类", exc_info=True) - else: - logger.error(f"{file}文件不存在或有误", exc_info=True) - - def load_widget(self, widget_config): - try: - widget_class = self.load_class( - widget_config['file'], widget_config['widget']) - if widget_config.get('auto_insert', True): - widget_config = self.ui_inserters[widget_config['position']]( - widget_class, widget_config['config']) - self.main.widgets[widget_class.__name__] = widget_config - return widget_class - except KeyError as e: - logger.error(f"插件{self.name}的widgets配置不正确!") - logger.error(f"位置:{widget_config}", exc_info=True) - - def create_public_interface(self, interface): - public_interface = PublicInterface() - for attr in dir(interface): - obj = getattr(interface, attr) - if not attr.startswith('_') and callable(obj): - setattr(public_interface, attr, obj) - return public_interface - - def reset(self): - pass diff --git a/pyminer/features/extensions/extensions_manager/README.md b/pyminer/features/extensions/extensions_manager/README.md deleted file mode 100644 index 0b27302a..00000000 --- a/pyminer/features/extensions/extensions_manager/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Package.json 包结构 - -~~~ -{ - "name":..., - "display_name":..., - "version":..., - "description":"...", - "icon":"..." - "main":{ - "file":"", - "main":"" - }, - "interface":{ - "file":"", - "interface":"" - }, - "widgets":[ - { - "file":"", - "widget":"", - "position":"..." - "config":{ - - } - } - ], - "requirements":[ - "name==version", - "name>=version", - "name<=version" - ], - "dependencies":[ - "name==version", - "name>=version", - "name<=version" - ] -} -~~~ \ No newline at end of file diff --git a/pyminer/features/extensions/extensions_manager/UIInserter.py b/pyminer/features/extensions/extensions_manager/UIInserter.py deleted file mode 100644 index 5dee5f9f..00000000 --- a/pyminer/features/extensions/extensions_manager/UIInserter.py +++ /dev/null @@ -1,154 +0,0 @@ -""" -控件插入器 -作者:冰中火 - -这是加载UI控件的插件类。 -插件导入的时候,传递的widget_class是控件的类。 -1、对于新建的工具栏类、插入工具栏的控件类、插入主窗口的控件类,控件插入器直接将控件类实例化, -然后插入在由config.json中指定的位置; -2、对于对话框类,控件插入器不会将其实例化,而会将其保存在对话框类管理器中。使用时,调用相应的方法,可以显示对话框。 -请注意,对话框并不是什么只能问问题,点‘确定、取消’的类。只要继承QDialog的界面都要这样处理。 -以上1中所述的情况将在应用初始化时完成;而2则是动态的过程,可以在应用初始化完成后就弹出对话框进行显示。 - - -插件导入时参数由json中的config设置项所决定。 - -config:是一个字典,但是现在传入的参数还远远不够。 -以这个文件的json配置为例,有以下要求: -"file":声明了控件类的入口位置。一般就是在main.py之中。 -position:插件插入位置。有两种选项:‘new_dock_window’和‘new_toolbar’ -config:设置属性。 -config.message:插件的设置信息,可以为空。 -config.name:插件的名称 -config.side:插件插入窗口时的位置(当position=new_dock_window时有效),有left\right\top\bottom四个选项 -config.text:插件的文字。会显示在dockwidget或者工具栏上 -{ - "file":"main.py", - "widget_class":"WidgetTest", - "position":"new_dock_window", - "config":{ - "message":"no", - "name":"code_editor", - "side": "right", - "text": "编辑器" - } -} - - -插件管理器下一步的目的就是将插件尽可能不一次性的加载完,插件可以自行设置插入到程序的时间, -尽可能在主界面发出初始化完成信号之后在进行调用。 -""" -from typing import TYPE_CHECKING, ClassVar -import utils -if TYPE_CHECKING: - from PySide2.QtWidgets import QWidget - - -def get_item_coor(coors: set, pos: str): - l = list(coors) - if pos == 'max': - return max(l) - elif pos == 'min': - return min(l) - else: - l = sorted(l) - if len(l) == 1: - return l[0] - else: - return l[1] - - -def get_dock_by_position(pos: str): - if not pos in {'top', 'bottom', 'left', 'right'}: - raise Exception('dockwidget的位置须由合法字符串指定,这些字符串是:\'top\', \'bottom\', \'left\', \'right\'') - pos_dic = {'top': ('med', 'min'), 'bottom': ('med', 'max'), 'right': ('max', 'med'), 'left': ('min', 'med')} - - x_set = set() - y_set = set() - x_policy, y_policy = pos_dic[pos] - - for k in utils.get_main_window().dock_widgets.keys(): - w2 = utils.get_main_window().get_dock_widget(k) - if w2.x() >= 0: - x_set.add(w2.x()) - x_pos = get_item_coor(coors=x_set, pos=x_policy) - for k in utils.get_main_window().dock_widgets.keys(): - w2 = utils.get_main_window().get_dock_widget(k) - if w2.x() == x_pos and w2.y() >= 0: - y_set.add(w2.y()) - if 0 in y_set and len(list(y_set)) > 1: - y_set.remove(0) - - y_pos = get_item_coor(coors=y_set, pos=y_policy) - - for k in utils.get_main_window().dock_widgets.keys(): - w2 = utils.get_main_window().get_dock_widget(k) - if w2.x() == x_pos and w2.y() == y_pos: - return w2 - - -class UiInserter(dict): - def __init__(self): - self.update({ - 'new_dock_window': self.new_dock_window, - 'new_toolbar': self.new_toolbar, - 'append_to_toolbar': self.append_to_toolbar, - 'new_dock_window_obj': self.new_dock_window_obj - }) - - def new_toolbar(self, widget_class: ClassVar['QWidget'], config=None): - name = config['name'] - - widget = widget_class() - text = widget.get_toolbar_text() - utils.get_main_window().add_toolbar(name=name, toolbar=widget, text=text) - return widget - - def new_dock_window(self, widget_class: ClassVar['QWidget'], config=None): - dock_name = config['name'] - - side = config['side'] - widget = widget_class() - text = widget.get_widget_text() - dock = utils.get_main_window().add_widget_on_dock(dock_name=dock_name, - widget=widget, text=text, side=side) - - if side in {'top', 'bottom', 'left', 'right'}: - w2 = get_dock_by_position(side) - utils.get_main_window().tabifyDockWidget(w2, dock) - - dock.raise_into_view() - return widget - - def new_dock_window_obj(self, widget: ClassVar['QWidget'], config=None): - """ - 以窗口对象插入,适用于已经创建的窗口。 - :param widget: - :param config: - :return: - """ - dock_name = config['name'] - text = widget.get_widget_text() - side = config['side'] - - widget = widget - dock = utils.get_main_window().add_widget_on_dock(dock_name=dock_name, - widget=widget, text=text, side='left') - - if side in {'top', 'bottom', 'left', 'right'}: - w2 = get_dock_by_position(side) - utils.get_main_window().tabifyDockWidget(w2, dock) - utils.get_main_window() - dock.raise_into_view() - return widget - - def append_to_toolbar(self, widget_class: ClassVar['QWidget'], config=None): - button_name = config['name'] - toolbar_name = config['toolbar'] - widget = widget_class() - toolbar = utils.get_main_window().toolbars.get(toolbar_name) - toolbar.add_widget(button_name, widget) - return widget - - -ui_inserters = UiInserter() diff --git a/pyminer/features/extensions/extensions_manager/__init__.py b/pyminer/features/extensions/extensions_manager/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/extensions/extensions_manager/log.py b/pyminer/features/extensions/extensions_manager/log.py deleted file mode 100644 index 4e4e8666..00000000 --- a/pyminer/features/extensions/extensions_manager/log.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import logging -from utils import get_main_window - - -def log(text): - """日志输出text""" - # TODO (panhaoyu) 这个函数是否无用可删? - get_main_window().slot_flush_console('info', 'Extension', 'Log:' + str(text)) - - -def error(text): - # TODO (panhaoyu) 这个函数是否无用可删? - print("Error:", text) - get_main_window().slot_flush_console( - 'error', 'Extension', 'Error:' + str(text)) - - -def assert_(boolean, text): - """ - boolean:bool - text:str - 若bool为false,以异常级输出text - """ - # TODO (panhaoyu) 这个函数是否无用可删? - if not boolean: - error(text) - - -class ColorHandler(logging.Handler): - """部分关键词彩色,以及添加到日志控件中 - """ - - Colors = { - logging.DEBUG: 'black', - logging.INFO: 'green', - logging.WARNING: 'yellow', - logging.ERROR: 'red', - logging.CRITICAL: 'red' - } - - def format(self, record): - """ - Format the specified record. - - If a formatter is set, use it. Otherwise, use the default formatter - for the module. - """ - if self.formatter: - fmt = self.formatter - else: - fmt = logging.Formatter() - - if fmt.usesTime(): - record.asctime = fmt.formatTime(record, fmt.datefmt) - - color = self.Colors.get(record.levelno, 'black') - # record.asctime - # record.name - # record.module - # record.funcName - # record.lineno - # record.levelname - # record.message - record.message = record.getMessage() - - s = fmt.formatMessage(record) - if record.exc_info: - # Cache the traceback text to avoid converting it multiple times - # (it's constant anyway) - if not record.exc_text: - record.exc_text = fmt.formatException(record.exc_info) - if record.exc_text: - if not s.endswith('
'): - s += '
' - s += record.exc_text - if record.stack_info: - if not s.endswith('
'): - s += '
' - s += fmt.formatStack(record.stack_info) - s = '{1}'.format(color, s.replace('\n', '
').replace(' ', ' ')) - return s - - def emit(self, record): - """ - Emit a record. - """ - try: - msg = self.format(record) - try: - get_main_window().log_output_console.append(msg) - except Exception: - pass - except RecursionError: # See issue 36272 - raise - except Exception: - self.handleError(record) \ No newline at end of file diff --git a/pyminer/features/extensions/extensions_manager/manager.py b/pyminer/features/extensions/extensions_manager/manager.py deleted file mode 100644 index 14fb3bf1..00000000 --- a/pyminer/features/extensions/extensions_manager/manager.py +++ /dev/null @@ -1,206 +0,0 @@ -import importlib -import json -import json.decoder -import logging -import os -import shutil -import sys -import time -import zipfile - -import utils -from features.extensions.extensions_manager.ExtensionLoader import ExtensionLoader -from features.extensions.extensions_manager.UIInserter import ui_inserters -from .vermanager import VersionsManager - -logger = logging.getLogger('extensionmanager') -logger.setLevel(logging.DEBUG) - - -class ExtensionsManager: - """ - 扩展管理类 - """ - - def __init__(self): - self.extensions = {} # 扩展类实例 - self.ui_inserters = ui_inserters - self.id_ = 0 # 扩展id,动态分配的 - self.setting_path = os.path.join( - utils.get_root_dir(), 'configuration', 'extensions.json') # 扩展配置文件位置 - if not os.path.exists(self.setting_path): - raise FileNotFoundError(self.setting_path) - try: - with open(self.setting_path, 'r') as f: - self.setting = json.load(f) - except: - logger.warn('extension.json 已损坏') - self.setting = {} - self.loader = ExtensionLoader(self) - # self.extensions_directory = os.path.join( - # utils.get_root_dir(), 'extensions', 'packages') - self.extensions_directory = os.path.join( - utils.get_root_dir(), 'packages') - self.vermanager = VersionsManager() - - def enable_extension(self, name): - if name in self.setting: - self.setting[name]['enabled'] = True - else: - self.load(name) - self.setting[name] = {'enabled': True} - - def disable_extension(self, name): - self.setting[name]['enabled'] = False - self.unload(name) - - def load(self, name): - with open(os.path.join(self.extensions_directory, name, 'package.json'), encoding='utf-8') as f: - main = self.loader.load(f, self.ui_inserters) - self.extensions[main.info.name] = main - main.id_ = self.id_ - self.id_ += 1 - self.loader.reset() - - def load_from_extension_folder(self, callback): - """ - 加载扩展 - """ - ext_load_status = {} - ext_path = os.path.join(utils.get_root_dir(), 'configuration', 'extensions.json') - with open(ext_path) as f: - ext_dict = json.load(f) - packages = ext_dict.keys() - ext_load_status['ext_count'] = len(packages) - ext_load_status['loaded'] = 0 - for package in packages: - t0 = time.time() - ext_load_status['loaded'] += 1 - if not os.path.isdir(os.path.join(self.extensions_directory, package)): - logger.debug(f'{package} is not dir, ignored') - elif package in self.setting: - if self.setting[package].get('enabled', True): - self.setting[package] = {'enabled': True} - ext_load_status['ext_name'] = package - try: - logger.info(f'load extension {package}') - self.load(package) - except ModuleNotFoundError as e: - raise e - except BaseException: - logger.error( - f'{package} is not a valid package', exc_info=True) - elif package not in self.setting: - self.setting[package] = {'enabled': True} - ext_load_status['ext_name'] = package - try: - logger.info(f'load extension {package} for the first time') - self.load(package) - except BaseException: - logger.error( - f'{package} is not a valid package', exc_info=True) - pass - if callable(callback): - callback(ext_load_status) - t1 = time.time() - logger.info(f'boot time elapsed for {str(package)} : {t1 - t0:f} s') - - def get_extension(self, name): - """通过名称获取扩展""" - return self.extensions.get(name, None) - - def unload(self, name): - ext = self.extensions[name] - # 卸载生命周期函数 - try: - ext._on_close() - except Exception as e: - logger.error(e, exc_info=True) - del self.extensions[name] - - def uninstall(self, name): - """ - 卸载扩展 - """ - ext = self.get_extension(name) - - # 卸载生命周期函数 - try: - ext._on_uninstall() - except Exception as e: - logger.error(e, exc_info=True) - - # 删除扩展实例 - del self.extensions[name] - - # 修改配置文件 - with open(self.setting_path, encoding='utf-8') as f: - config = json.load(f) - for index, c in enumerate(config['extensions']): - if c['name'] == ext.info.name: - del config['extensions'][index] - break - with open(self.setting_path, 'w', encoding='utf-8') as f: - json.dump(config, f) - - # 最后删除扩展文件夹,注意顺序 - path = ext.info.path - shutil.rmtree(path) - - def install(self, path): - """本地安装扩展""" - try: - # 解压扩展 - file = zipfile.ZipFile(path) - dirname = os.path.join(utils.get_root_dir(), 'packages', - '.'.join(os.path.basename(path).split('.')[:-1])) - extract_dir = os.path.join( - utils.get_root_dir(), 'packages') - file.extractall(extract_dir) - file.close() - - # 配置文件 - with open(self.setting_path, encoding='utf-8') as f: - config = json.load(f) - # 扩展内的package.json配置文件 - with open(os.path.join(dirname, 'package.json'), encoding='utf-8') as f: - package = json.load(f) - # 自动安装依赖 - for i in package.get('requirements', []): - if not self.get_extension(i): - self.install_web(*i) - - # 写入配置文件 - config['extensions'].append({ - 'name': package['name'], - 'enable': True - }) - with open(self.setting_path, 'w', encoding='utf-8') as f: - json.dump(config, f) - except Exception as e: - logger.error(f"安装失败 {e}", exc_info=True) - return - else: # else表示没有异常的情况 - self.load(package['name']) - - def download(self, name, version=''): - # 从插件商店安装,之后完成 - pass - - def stop(self): - with open(self.setting_path, 'w') as f: - json.dump(self.setting, f, indent=2) - - def refresh(self, id_): - ext = self.get_extension(id_) - name = ext.info.name - self.unload(name) - with open(os.path.join(ext.info.path, 'package.json'), 'r', encoding='utf-8') as f: - main_config = json.load(f).get( - 'main', {'file': 'main.py', 'main': 'Extension'}) - module_name = f"{name}.{main_config['file'].split('.')[0]}" - importlib.reload(sys.modules[module_name]) - self.load(name) - - -extensions_manager = ExtensionsManager() diff --git a/pyminer/features/extensions/extensions_manager/readme.drawio b/pyminer/features/extensions/extensions_manager/readme.drawio deleted file mode 100644 index 080c8be1..00000000 --- a/pyminer/features/extensions/extensions_manager/readme.drawio +++ /dev/null @@ -1 +0,0 @@ -7VrZbuM2FP0aAu1Lod3ko+RlWiBFC+ShM08DxmJsdWTRkOnY7tf3kqJW0ktQO5lxCgQBeXkpkeeQd5ORP17tP5V0vfydpyxHnpPukT9Bnhf6GP5LwaESBIEWLMosrURuK3jM/mFa6GjpNkvZpqcoOM9Ftu4L57wo2Fz0ZLQs+a6v9szz/lvXdMEMweOc5qb0rywVy0qKvVEr/5Vli2X9Zjci1ciK1sp6J5slTfmuI/KnyB+XnIuqtdqPWS6xq3Gp5s2OjDYLK1khLpmg1/VC863em16XONSbXZR8u0Z+shEl/8bGPOelGvAJGY9n8ODkmRdiRldZLun8REu64kWq5R19xwlmBFaRmIvU635hpWB7G4X0qV5OixKcLsZXTJQH0NOz/PqIHGrodX/X8uRhLVt2OAocLaT6bCyaZ7fwQUMjaEfTO48mgFmkTOq7gMRumQn2uKZzObqDuwKypVjleviWkJMjkJvQvgl0vgndNEJ4hgg0ApQkKIkMMGHloo8YzbNFAe057JMBCIncXwY3N9YDqyxN5XQr9C05zneDfj3qDQ62ea4DCzfeFagJLNQQhEOEJ2g6QskExVNJFgG+RsfJ+gFPfj0a9bGPTOxdxwJ+dAXwQwv4gDCWIAP4MUYYGiFKYnlZ7gdz7zzk3o0gjwzIM2lMniVudwuwG1ocpc2iuMEVIB4ZEG8zZe+nKL5LEzJA2/cuRPsa5xmfcq2hNORxKBuEgDn5aZt9zYqN3Fi5+fmOGPD7DDT9DgO24Ca8AgG1r+4wkGdPBraQC6xlc37IMwC5PA/wU8XGw1MjoPNvC8XRH1sBT2FvwMSx2P0oE6PzlieyMIGvwYRroM5SSO10l5diyRe8oPm0lQ6iwlbngfO1xvdvJsRB56l0K3ifJrbPxGc9Xba/yPYvoe5N9p2hyaHuFLC1z/UDZKczS3bbaapXz3sDpjd8W85ZLzwRtFywWkvzJIE9eRxKllORvfRzahu7ampclvTQUVhz8MqbzpP/lIKOxR1eeGeQCZ/Rd4kzOFnVCtpz1mzlsqNnSQ6l9Y1lDCftsYOwqyQYkSqkS2RUVwXWiaNC7QTh4B7ToVfbEG+Y51uMyK3yIdcMEN/FqvwYFsINTBMR3MRCGFc6Gl5pTPqPqNakZw0OwCtv9+h/x3LzYzO69rG5+MaTd2W3YfRLZ8TO7juxdOubbJQDhmH5kZv82qBhFPTfE7qng4Yz+v89aLDV3oyyqA4jIETAshoHf3U2ZxzbD5NjXBAf3CzJsCXcGMUzVbMLFXvRZSXUsRQCsQlRtFdq5kQzaCSITOQRaAPLs8WVDxQ9RoNr61qKAbeKHj2zGGA6lyKN5WdKiX1ON5tsfiT0a9z0d+PDu/46utA5dFAPT5Rgbu1DKsdm+BDzQYMCRjT8/nUlZ2QUDaPw9LqG+v51nVFzz/oZLKSmOFJ2CoxRYHdPYKRIrCRgvIi0XNCVqSw0ApUAB+oLxtRWmcTSJsax8m7g5pLO9KNlTJvB1ToPnErHVz/kt6a2L+d6CI+1ply5+tISTxrlbnFUWWdQmCrL2ywSJoJddvV7cbNrtRLiqD2a62+wCpQHn7XIfGAz7ZPBRbN89HRH17HT0G1/dVFdjvanK/70Xw== \ No newline at end of file diff --git a/pyminer/features/extensions/extensions_manager/vermanager/__init__.py b/pyminer/features/extensions/extensions_manager/vermanager/__init__.py deleted file mode 100644 index 02f1553c..00000000 --- a/pyminer/features/extensions/extensions_manager/vermanager/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .vermanager import Module, VersionsManager \ No newline at end of file diff --git a/pyminer/features/extensions/extensions_manager/vermanager/vermanager.py b/pyminer/features/extensions/extensions_manager/vermanager/vermanager.py deleted file mode 100644 index f31b9f87..00000000 --- a/pyminer/features/extensions/extensions_manager/vermanager/vermanager.py +++ /dev/null @@ -1,138 +0,0 @@ -import threading -import subprocess -import time -import re -from typing import List -import logging - -logger = logging.getLogger(__name__) - -class Module(object): - ''' - Notation: - --- - name: name - version: 1.2.3 - ver_num: [1, 2, 3] - relation: ==|>=|<= - module_str: name==1.2.3 - requirement: name(==|>=|<=)1.2.3 - ''' - def __init__(self, module_str: str): - if module_str.count('==') != 1: - self.valid = False - return - module_str = module_str.strip() - self.name, self.version = module_str.split('==') - try: - assert re.match('^[a-zA-Z][-_a-zA-Z0-9]*', self.name) is not None - self.ver_num = self.parse(self.version) - except ValueError: - self.valid = False - return - self.requirements = [] - self.valid = True - - def meet_requirement_str(self, requirement: str) -> bool: - requirement = requirement.strip() - match = re.search(r'==|<=|>=', requirement) - if match: - relation = match.group(0) - name, version = re.split(r'==|<=|>=', requirement) - assert self.name == name - return self.meet_requirement(relation, version) - else: - assert self.name == requirement - return True - - def meet_requirement(self, relation: str, version: str): - met = self._meet_requirement(relation, version) - self.requirements.append((relation, version)) # in case error do not record - return met - - def _meet_requirement(self, relation: str, version: str) -> bool: - if version == self.version: - return True - elif relation == '==': - return False - else: - cmp = self.version_compare(self.ver_num, self.parse(version)) - if relation == '>=': - return cmp >= 0 - elif relation == '<=': - return cmp <= 0 - else: - raise ValueError(f'{relation} is not a valid relation') - - def is_conflict(self): - for relation, version in self.requirements: - if not self._meet_requirement(relation, version): # do not record again - return True - else: - return False - - def update(self, version: str): - self.version, version = version, self.version - self.ver_num, ver_num = self.parse(self.version), self.ver_num - if self.is_conflict(): - self.version = version - self.ver_num = ver_num - raise Exception('Conflict with requirements') - else: - logger.error(f'{self.name} should be updated to {self.version}') - - def parse(self, version: str) -> List[int]: - ver_match = re.search(r'\d+(\.\d+)*', version) - if ver_match is None: - raise ValueError(f'unsupported version {version}') - ver = ver_match.group(0) - try: - return [int(i) for i in ver.split('.')] - except: - raise ValueError(f'invalid version {ver}') - - def version_compare(self, ver_num1: str, ver_num2: str) -> int: - for v1, v2 in zip(ver_num1, ver_num2): - if v1 > v2: - return 1 - elif v1 < v2: - return -1 - else: - continue - return 0 - - def __str__(self): - if not self.valid: - return 'invalid version' - return f'{self.name}=={self.version}' - - __repr__ = __str__ - -class VersionsManager(object): - def __init__(self): - self.current_modules = {} - - def set_current_modules(self, current_modules_lst: List[str]): - current_modules = [Module(module_str) for module_str in current_modules_lst if module_str] - self.current_modules.update({module.name: module for module in current_modules if module.valid}) - - def check_requirements(self, requirements: List[str]) -> set: - solvable = set() # requirements - conflict = set() # module names - for requirement in requirements: - name_version_tuple = re.split(r'==|<=|>=', requirement) - name = name_version_tuple[0] - if name not in self.current_modules: - logger.error(f'No version {name} was found') - solvable.add(requirement) - continue - module = self.current_modules[name] - if not module.meet_requirement_str(requirement): - try: - version = name_version_tuple[1] # if not met, there must be version requirement - module.update(version) - solvable.add(requirement) - except: - logger.error(f'Unsolved conflict in version {name}') - conflict.add(name) - return solvable, conflict diff --git a/pyminer/features/extensions/index.rst b/pyminer/features/extensions/index.rst deleted file mode 100644 index 0da2d95e..00000000 --- a/pyminer/features/extensions/index.rst +++ /dev/null @@ -1,25 +0,0 @@ -============================================================================== -插件管理工具 -============================================================================== - -.. automodule:: features.extensions - :members: - :undoc-members: - -.. toctree:: - :maxdepth: 2 - - extensionlib/index.rst - extensions_manager/index.rst - package_manager/index.rst - test_demo/index.rst - extensionlib/readme.md - extensions_manager/README.md - test_demo/README.md - - -本程序包是PyMiner的插件管理工具,此处主要介绍该工具的实现原理及接口,关于用户级的插件开发文档可以见 extensions_ 。 - -.. _extensions: https://gitee.com/py2cn/pyminer/wikis/%E6%8F%92%E4%BB%B6%E5%BC%80%E5%8F%91%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8?sort_id=2809600 - - diff --git a/pyminer/features/feedback.py b/pyminer/features/feedback.py deleted file mode 100644 index f4a8a035..00000000 --- a/pyminer/features/feedback.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -# @Time : 2021/2/12 16:24 -# @Author : jcl -# @Email : 2195932461@qq.com -# @File : feedback.py -# @Software: PyCharm -import requests -from PySide2.QtWidgets import QDialog, QTextEdit, QLabel, QVBoxLayout, QApplication, QPushButton, QMessageBox - -from features.settings import Setting - - -class FeedbackClient(QDialog): - def __init__(self): - super().__init__() - self.vbox = QVBoxLayout() - self.setLayout(self.vbox) - self.text_edit = QTextEdit() - self.setWindowTitle(self.tr('Feedback')) - self.label = QLabel( - self.tr('You can give feedback through issue on suggestions or problems encountered in use! (<200 words)')) - self.confirm_button = QPushButton(self.tr('confirm')) - self.confirm_button.setFixedWidth(75) - self.confirm_button.clicked.connect(self.post) - self.vbox.addWidget(self.label) - self.vbox.addWidget(self.text_edit) - self.vbox.addWidget(self.confirm_button) - setting = Setting() - self.version = setting.get_system_version() - self.exec_() - - def post(self): - text = self.text_edit.toPlainText() - version = self.version - url = 'http://www.pyminer.com/api/v1/feedback/' - data = {'core': version, 'feedback': text} - r = requests.post(url, data) - if r.status_code == 201: - QMessageBox.about(self, self.tr('result'), self.tr('Submitted successfully!')) - else: - QMessageBox.warning(self, self.tr('result'), r.text, QMessageBox.Yes) - - -if __name__ == '__main__': - import sys - - app = QApplication(sys.argv) - FeedbackClient() diff --git a/pyminer/features/index.rst b/pyminer/features/index.rst deleted file mode 100644 index f17811d4..00000000 --- a/pyminer/features/index.rst +++ /dev/null @@ -1,167 +0,0 @@ -================== -主界面及应用说明 -================== - -.. sectionauthor:: 侯展意 - -重要补充说明 -------------------- - -.. sectionauthor:: 郑君 - -``Workspace`` 需要用到 ``DataServer``,目前采用 ``FastAPI`` 框架。 -但无论什么框架,均引用 ``signal`` 模块,该模块只能在 ``main thread`` 使用。 -因此,主线程上必须运行 ``DataServer``,我在 ``pmappmoderm`` 中把 ``GUI`` 移动到新的线程中,``QT`` 会报 ``warning``,但是不影响运行。 -如有问题及时联系我。 - - -主界面代码说明 -------------------- - -源码位置及继承关系 -^^^^^^^^^^^^^^^^^^^^^^^^^ - -主界面类指定义在 ``pmappmodern.py`` 的 ``MainWindow`` 类。 - - -继承自 ``features.ui.generalwidgets.BaseMainWindow`` 。 - -界面功能 -^^^^^^^^^^^^ - -1. 具有若干可自由拖动的停靠窗口,并可以记忆窗口的布局。 -#. 具有若干可通过选项卡切换的工具栏。 - -工具栏 -^^^^^^^^^ - -添加工具栏 -"""""""""""""" - -主界面的工具栏使用的是 ``PMGToolBar`` 这个类,继承自 ``QToolBar`` 。 - -主窗口 ``add_tool_bar()`` 方法,可以将 ``QToolBar`` 或 ``PMGToolBar`` ,抑或是你自己的继承于 ``QToolBar`` 的工具栏添加到主窗口。 - -获取工具栏 -"""""""""""""" - -工具栏通过它的名称进行访问。 - -预定义的工具栏只有一个,名曰 ``'toolbar_home'`` 。 - -举个例子讲,要获取主页对应的工具栏,那么就使用 ``MainWindow.toolbars.get('toolbar_home')`` 进行获取就可以了。 - -在工具栏上添加按钮 -""""""""""""""""""""""""""" - -获取工具栏后,调用 ``MainWindow.add_tool_button()`` 即可添加一个按钮,或者调用 ``add_tool_buttons()`` 添加多个竖排的按钮。 -这两个函数的返回值分别为 ``QPushButton`` 和 ``List[QPushButton]`` 。 - -在工具栏上添加控件 -""""""""""""""""""""""""""""" - -添加控件的方法与在 ``QToolBar`` 上添加控件完全相同,亦即继承了 ``addWidget`` 方法,在此不再赘述。 - -添加带有菜单的按钮 -"""""""""""""""""""""""""""" - -如果需要菜单效果,可以用 ``QMenu`` 写一个菜单,然后添加到按钮之上。 - -工具栏实现细节 -""""""""""""""""""""""""""" - -工具栏看似使用了选项卡,其实不然。 - -最顶端的“选项卡样控件”实为插入了按钮的 ``QToolBar`` ,可以依靠其按钮的点击来进行工具栏的切换。 - -切换工具栏时,其他工具栏隐藏,只有按钮对应的工具栏可以显示。详见switch_toolbar方法。 - -主界面停靠窗口 -^^^^^^^^^^^^^^^^^^ - -主界面由一系列 ``PMDockWidget`` 组成。 -此控件继承于 ``QDockWidget`` 。 - -添加停靠窗口的方法 -"""""""""""""""""""""""""""" - -``MainWindow.add_widget_on_dock()`` 方法可以用来将任意控件添加到dock,而且下次加载之时布局会被保存。 - -停靠窗口的获取 -"""""""""""""""""""" - -``MainWindow.get_dock_widget(widget_name:str)->PMDockWidget`` - -根据名称进行停靠窗口的获取。如果名称不存在,那么就会抛出异常。 - -关于快速启动的说明 -""""""""""""""""""""""""""""" - -为了加快软件启动速度,控件(假设其类名为 ``Widget`` )可以定义方法 ``Widget.setup_ui`` 。 - -当加载时,首先执行控件的 ``__init__`` ,并且将 ``setup_ui`` 压入任务栈之中, -等到主界面显示出来之后再用定时器调用执行控件的 ``setup_ui`` 方法。 - -对于核心控件可以定义 ``show_directly=True`` ,保证立即执行 ``setup_ui`` 方法。 -或者干脆不写``setup_ui`` 方法,而是将启动方法放在 ``__init__`` 之中。 - -窗口隐藏与销毁 -"""""""""""""""" - -``dockwidget`` 的隐藏与显示可以通过主页选项卡中’视图‘菜单进行管理。 -当点击窗口关闭按钮的时候,窗口会被“关闭”。 -但实际上窗口并未被销毁,也就是被隐藏起来了。 -如果确实要销毁窗口,那么请重写 ``PMDockWidget`` 中的 ``closeEvent`` 方法,确保窗口在被关闭的时候被正确销毁了。 - -对于工具栏基类的建议 -"""""""""""""""""""""""""" - -无论是主界面还是插件,建议继承 ``PMGToolBar`` 类,这个类有设置好的样式。 - -使用 ``QToolbar`` 尽管不会出错,但是样式很难统一。 - -.. code-block:: python - - from pmgwidgets import PMGToolBar - - -主界面的全局获取方法 -------------------------- - -在 ``pyminer.globals`` 中定义了关于主界面的一些全局操作。 - - -获取主界面 -^^^^^^^^^^^^^^^^ - -.. code-block:: python - - get_main_window()->MainWindow - -主界面是一个全局变量,应用启动时对其赋值。 -这种写法尽管原始,但主要目的在于尽可能的减少循环导入的可能性,方便未来的插件开发。 - -获取根路径 -^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - get_root_path()->str - - - -.. toctree:: - :maxdepth: 2 - - config/index.rst - data_adapter/index.rst - extensions/index.rst - features/index.rst - tests/index.rst - ui/index.rst - workspace/index.rst - workspace2/index.rst - - pmappmodern.rst - globals.rst - diff --git a/pyminer/features/interpretermanager/__init__.py b/pyminer/features/interpretermanager/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/interpretermanager/interpretermanager.py b/pyminer/features/interpretermanager/interpretermanager.py deleted file mode 100644 index 3861306d..00000000 --- a/pyminer/features/interpretermanager/interpretermanager.py +++ /dev/null @@ -1,204 +0,0 @@ -""" -settings['interpreters'] = -{'base':{'name':'base', - 'info':'pypy3 python 3.6 compatible', - 'path':'/home/.../python3.8'} -} -""" -import os -import sys -from typing import Dict, List - -from PySide2.QtWidgets import QPushButton, QHBoxLayout, QVBoxLayout, QWidget, QDialog, \ - QListWidget, QMessageBox, QSpacerItem, QSizePolicy - -import utils -from pmgwidgets import PMGPanelDialog -from utils import get_settings_item_from_file - - -class Interpreter(): - def __init__(self, name: str, absolute_path: str, version: str): - self.name = name - self.path = absolute_path - self.versioin = version - - -class InterpreterManager(): - interpreter_paths = [] - - def __init__(self): - pass - - -def get_interpreter_version(interpreter_path: str) -> str: - version = os.popen('%s -c \"import sys;print(sys.version.split()[0])\"' % interpreter_path).read().strip() - return version - - -def get_all_external_interpreters() -> List[Dict]: - """ - 获取所有的外部解释器 - Returns: - - """ - return utils.get_settings_item_from_file("config.ini", "RUN/EXTERNAL_INTERPRETERS") - - -def modify_interpreter_config(mode, info: Dict = None, index: int = -1): - """ - - Args: - info: 一个存储解释器信息的字典 - mode: "add","delete","modify" - - Returns: - - """ - - external_interpreters = utils.get_settings_item_from_file("config.ini", "RUN/EXTERNAL_INTERPRETERS") - if mode == "add": - external_interpreters.append(info) - elif mode == "modify": - external_interpreters[index] = info - elif mode == "delete": - external_interpreters.pop(index) - else: - raise NotImplementedError(mode) - utils.write_settings_item_to_file("config.ini", "RUN/EXTERNAL_INTERPRETERS", external_interpreters) - - -class InterpreterManagerWidget(QWidget): - def __init__(self, parent=None): - super(InterpreterManagerWidget, self).__init__(parent) - self.interpreters_list_show = QListWidget() - self.button_add = QPushButton('+') - self.button_delete = QPushButton('-') - self.button_edit = QPushButton(self.tr('Edit')) - self.button_manage_packages = QPushButton(self.tr('Packages')) - self.setLayout(QHBoxLayout()) - self.layout().addWidget(self.interpreters_list_show) - self.button_layout = QVBoxLayout() - self.layout().addLayout(self.button_layout) - self.button_layout.addWidget(self.button_add) - self.button_layout.addWidget(self.button_edit) - self.button_layout.addWidget(self.button_manage_packages) - self.button_layout.addWidget(self.button_delete) - self.button_layout.addItem(QSpacerItem(0, 20, QSizePolicy.Minimum, QSizePolicy.Expanding)) - - self.button_add.clicked.connect(self.add) - self.button_edit.clicked.connect(self.edit) - self.button_delete.clicked.connect(self.remove) - self.button_manage_packages.clicked.connect(self.manage_packages) - self.interpreters_list_show.currentItemChanged.connect(self.on_list_current_item_changed) - self.show_interpreters() - - def gen_info_template(self): - views = [ - ('line_ctrl', 'name', '名称', ''), - ('file_ctrl', 'interpreter_path', '解释器路径', '') - ] - - def add(self): - views = [ - ('line_ctrl', 'name', self.tr('Name'), ''), - ('file_ctrl', 'path', self.tr('Executable Path'), '', 'Executables(*.exe)') - ] - - def set_interpreter_name(settings): - interpreter_path = settings['path'] - dlg.panel.get_ctrl('name').set_value(os.path.basename(interpreter_path)) - - dlg = PMGPanelDialog(parent=self, views=views) - dlg.panel.set_param_changed_callback('path', set_interpreter_name) - - ret = dlg.exec_() - if ret == QDialog.Accepted: - res = dlg.get_value() - d = {'name': res['name'], 'path': res['path'], 'version': get_interpreter_version(res['path'])} - modify_interpreter_config("add", d) - self.show_interpreters() - - def edit(self): - current_index = self.interpreters_list_show.currentRow() - list_index = current_index - 1 # 第一个是默认解释器,所以要减去1 - - external_interpreters = get_all_external_interpreters() - current_interpreter = external_interpreters[list_index] - - views = [ - ('line_ctrl', 'name', self.tr('Name'), current_interpreter['name']), - ('file_ctrl', 'path', self.tr('Executable Path'), current_interpreter['path']) - ] - - dlg = PMGPanelDialog(parent=self, views=views) - dlg.verify = self.verify - ret = dlg.exec_() - - if ret == QDialog.Accepted: - res = dlg.get_value() - d = {'name': res['name'], 'path': res['path'], 'version': get_interpreter_version(res['path'])} - modify_interpreter_config("modify", d, list_index) - self.show_interpreters() - - def manage_packages(self): - from features.interpretermanager.packagemanager import MarketPlace - current_interpreter = self.get_current_interpreter() - if current_interpreter is not None: - path = current_interpreter['path'] - mp = MarketPlace(path) - mp.exec_() - - def verify(self, values) -> bool: - LEN = 16 - if len(values['name']) > LEN: - QMessageBox.warning(self, self.tr('Warning'), - self.tr( - f'Name should be less than {repr(LEN)} characters,but your input was %d characters.' % - len(values['name']))) - return False - else: - return True - - def remove(self): - modify_interpreter_config("delete", index=self.interpreters_list_show.currentRow() - 1) - self.show_interpreters() - - def show_interpreters(self): - self.interpreters_list_show.clear() - self.interpreters_list_show.addItem(self.tr('BuiltIn (3.8.5)')) - ext_interpreters = get_all_external_interpreters() - for interpreter in ext_interpreters: - name = interpreter['name'] - version = interpreter['version'] - text = name + ' (%s)' % version - self.interpreters_list_show.addItem(text) - - def on_list_current_item_changed(self): - """ - 如果是默认解释器的时候,不支持修改。 - Returns: - - """ - self.button_delete.setEnabled(not self.interpreters_list_show.currentRow() == 0) - self.button_edit.setEnabled(not self.interpreters_list_show.currentRow() == 0) - - def get_current_interpreter(self) -> Dict: - - current_index = self.interpreters_list_show.currentRow() - if current_index == 0: - return {'name': 'Builtin', 'path': sys.executable, 'version': sys.version.split()[0]} - elif current_index < 0: - return - else: - list_index = current_index - 1 - return get_all_external_interpreters()[list_index] - - -if __name__ == '__main__': - from PySide2.QtWidgets import QApplication - - app = QApplication([]) - w = InterpreterManagerWidget() - w.show() - app.exec_() diff --git a/pyminer/features/interpretermanager/packagemanager.py b/pyminer/features/interpretermanager/packagemanager.py deleted file mode 100644 index 307e0bde..00000000 --- a/pyminer/features/interpretermanager/packagemanager.py +++ /dev/null @@ -1,200 +0,0 @@ -import subprocess -import sys -from PySide2.QtWidgets import QFrame, QTableWidgetItem, QTableWidget, QMessageBox, QDialog, QDesktopWidget, QHeaderView, \ - QProgressDialog -from PySide2.QtGui import QCloseEvent -from PySide2.QtCore import Signal, Qt, QUrl, QPropertyAnimation, QCoreApplication -from features.ui.base.pm_marketplace.package_manager_main import Ui_Form as marketplace_Ui_Form -from features.ui.base.pm_marketplace.install import Ui_Form as marketplace_install_Ui_Form -from features.ui.base.pm_marketplace.uninstall import Ui_Dialog as marketplace_uninstall_Ui_Dialog - -from pmgwidgets import PMGOneShotThreadRunner - - -class MarketPlaceUninstall(QDialog, marketplace_uninstall_Ui_Dialog): - signal_packages_changed = Signal() - - def __init__(self, parent=None, executable='', package_name=''): - super(MarketPlaceUninstall, self).__init__(parent=parent) - if executable == '': - executable = sys.executable - self._executable = executable - self.setupUi(self) - - self.log_console.set_args(['%s' % self._executable, '-m', 'pip', 'uninstall', package_name, '-y']) - self.log_console.button_to_start.hide() - self.log_console.button_to_terminate.hide() - self.log_console.start_process() - self.button_close.clicked.connect(self.close) - - def closeEvent(self, a0: QCloseEvent) -> None: - self.signal_packages_changed.emit() - - -class MarketPlaceInstall(QDialog, marketplace_install_Ui_Form): - signal_packages_changed = Signal() - - def __init__(self, parent=None, executable=''): - super(MarketPlaceInstall, self).__init__(parent=parent) - if executable == '': - executable = sys.executable - self._executable = executable - self.setupUi(self) - self.center() - self.groupBox.setVisible(False) # 隐藏详情窗口。这是因为pip search功能现在已经无法使用。 - self.exec_log.button_to_start.setVisible(False) - self.exec_log.button_to_terminate.setVisible(False) - - self.exec_log.set_args(['%s' % self._executable, '-m', 'pip', 'download', 'pyqtgraph', - '-i', 'https://pypi.tuna.tsinghua.edu.cn/simple']) - # self.exec_log.start_process() - - self.checkBox_version.clicked.connect(self.checkbox_version_clicked) - self.pushButton_install.clicked.connect(self.install) - self.pushButton_close.clicked.connect(self.close) - _trans = lambda text: QCoreApplication.translate('marketplace_install_Ui_Form', text) - - self.origins = ['https://mirrors.cloud.tencent.com/pypi/simple', - 'https://pypi.org/simple', - 'https://pypi.tuna.tsinghua.edu.cn/simple', - 'https://mirrors.aliyun.com/pypi/simple/', - 'http://pypi.douban.com/simple/' - ] - self.label_3.hide() - self.comboBox_dir.hide() - self.lineEdit_dir.hide() - self.toolButton.hide() - self.checkbox_version_clicked(None) - self.comboBox_source.currentIndexChanged.connect(self.combobox_source_changed) - self.lineEdit_source.setEnabled(False) - - def checkbox_version_clicked(self, checked): - if self.checkBox_version.isChecked(): - self.lineEdit_version.setEnabled(True) - else: - self.lineEdit_version.setEnabled(False) - self.lineEdit_version.setText('') - - def combobox_source_changed(self, s): - index = self.comboBox_source.currentIndex() - if index == len(self.origins): - self.lineEdit_source.setEnabled(True) - else: - self.lineEdit_source.setEnabled(False) - self.lineEdit_source.setText(self.origins[index]) - - def center(self): - qr = self.frameGeometry() - cp = QDesktopWidget().availableGeometry().center() - qr.moveCenter(cp) - self.move(qr.topLeft()) - - def install(self): - package_name = self.lineEdit_name.text() - origin_url = self.lineEdit_source.text() - version = self.lineEdit_version.text() - version = version if self.checkBox_version.isChecked() else '' - - if package_name.strip() == '': - QMessageBox.warning(self, self.tr('Warning'), - self.tr('Package Name should not be empty!' % self.comboBox_source.currentText())) - return - if origin_url == '': - QMessageBox.warning(self, self.tr('Warning'), - self.tr('Origin %s not exist!' % self.comboBox_source.currentText())) - return - if version != '': - package_name = package_name + '==' + version - self.exec_log.set_args(['%s' % self._executable, '-m', 'pip', 'install', package_name, '-i', origin_url]) - self.exec_log.start_process() - - def closeEvent(self, a0: QCloseEvent) -> None: - self.signal_packages_changed.emit() - - -class MarketPlace(QDialog, marketplace_Ui_Form): - def __init__(self, executable: str = ''): - super(MarketPlace, self).__init__() - if executable == '': - executable = sys.executable - self._executable = executable - self.setupUi(self) - - self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - self.center() - - self.pip_list() - - # 绑定事件 - self.toolButton_install.clicked.connect(self.pip_install_display) - self.toolButton_uninstall.clicked.connect(self.pip_uninstall_display) - - def keyPressEvent(self, e): - """ - 按键盘Escape退出当前窗口 - @param e: - """ - if e.key() == Qt.Key_Escape: - self.close() - - def center(self): - qr = self.frameGeometry() - cp = QDesktopWidget().availableGeometry().center() - qr.moveCenter(cp) - self.move(qr.topLeft()) - - def pip_list(self): - - def list_pip_packages(executable): - cmd = executable + ' -m pip list' - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) - out, err = p.communicate() - x = 1 - package_str = list() - for r in out.splitlines(): - if x > 2: - package_str.append(r) - x = x + 1 - return package_str - - def refresh_table(package_str): - package_len = len(package_str) - # 设置表格长度 - self.tableWidget.setRowCount(package_len) - - # 将结果显示在表格中 - for i in range(package_len): - for j in range(2): - items_value = package_str[i].split()[j] - item = QTableWidgetItem(str(items_value, encoding="utf-8")) - item.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter) - self.tableWidget.setItem(i, j, item) - - self.process_dlg = QProgressDialog(parent=self, labelText=('Scanning packages..')) - self.process_dlg.setCancelButton(None) - self.process_dlg.setWindowFlags(self.process_dlg.windowFlags() | Qt.FramelessWindowHint) - self.process_dlg.setRange(0, 0) - - self.pip_th = PMGOneShotThreadRunner(list_pip_packages, args=(self._executable,)) - self.pip_th.signal_finished.connect(refresh_table) - self.pip_th.signal_finished.connect(self.process_dlg.close) - self.process_dlg.show() - - def pip_install_display(self): - pm_pack_install = MarketPlaceInstall(self, executable=self._executable) - pm_pack_install.show() - pm_pack_install.signal_packages_changed.connect(self.pip_list) - - def pip_uninstall_display(self): - row = self.tableWidget.currentRow() - if row >= 0: - current_package = self.tableWidget.item(row, 0).text() - ret = QMessageBox.warning(self, self.tr('Warning'), - self.tr('Are you sure to remove package \'%s\'?' % current_package), - QMessageBox.Yes | QMessageBox.No, QMessageBox.No) - - if ret == QMessageBox.Yes: - pm_pack_uninstall = MarketPlaceUninstall(self, executable=self._executable, - package_name=current_package) - pm_pack_uninstall.show() - pm_pack_uninstall.signal_packages_changed.connect(self.pip_list) diff --git a/pyminer/features/io/__init__.py b/pyminer/features/io/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/io/database.py b/pyminer/features/io/database.py deleted file mode 100644 index cfbdbd36..00000000 --- a/pyminer/features/io/database.py +++ /dev/null @@ -1,155 +0,0 @@ -from typing import List - -from pmgwidgets import PMGPanel -from PySide2.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QMessageBox, QListWidget, QListWidgetItem, \ - QComboBox, QDialog, QInputDialog -from utils import dbConnectTool, get_all_accounts_list, get_all_accounts, dbConnectAccountTool, create_account -from features.io.dbConn import DatabaseConn - - -class DatabaseConfigPanel(QDialog): - def __init__(self, parent=None): - super(DatabaseConfigPanel, self).__init__(parent) - self.setLayout(QVBoxLayout()) - self.combo_select_database_type = QComboBox() - self.combo_select_database_type.addItems(['MySQL', 'PostgreSQL', 'Oracle', 'SQL Server', 'SQLite']) - self.combo_select_database_type.currentIndexChanged.connect(self.on_database_selected) - self.layout().addWidget(self.combo_select_database_type) - conn = DatabaseConn() - views, engine = conn.create_conn('mysql') - - self.settings_panel = PMGPanel(parent=self, views=views) - self.settings_panel.signal_settings_changed.connect(self.on_settings_changed) - self.upper_layout = QHBoxLayout() - self.layout().addLayout(self.upper_layout) - self.upper_layout.addWidget(self.settings_panel) - self.conn_list = QListWidget() - self.conn_list.itemDoubleClicked.connect(self.item_double_clicked) - self.upper_layout.addWidget(self.conn_list) - self.button_test_connection = QPushButton(self.tr('Test Connection')) - self.button_test_connection.clicked.connect(self.test_connection) - self.button_create_account = QPushButton(self.tr('Create Account')) - self.button_create_account.clicked.connect(self.create_account) - self.button_layout = QHBoxLayout() - self.button_layout.addWidget(self.button_test_connection) - self.button_layout.addWidget(self.button_create_account) - self.layout().addLayout(self.button_layout) - # self.settings_panel.on_settings_changed() - index = self.combo_select_database_type.currentIndex() - self.on_database_selected(index) - - def get_current_db_type(self) -> str: - return self.combo_select_database_type.currentText() - - def on_database_selected(self, index): - text = self.get_current_db_type().lower() - conn = DatabaseConn() - views, engine = conn.create_conn(text) - self.settings_panel.set_items(views) - - db_type = self.get_current_db_type().lower() - accounts = get_all_accounts() - db_accounts = accounts.get(db_type) - if db_accounts is not None: - l = list(db_accounts.keys()) - else: - l = [] - self.show_accounts(l) - - def on_settings_changed(self, settings): - pass - - def item_double_clicked(self, item: QListWidgetItem): - """ - 列表项双击触发回调 - :param item: - :return: - """ - settings = self.settings_panel.get_value() - db_type = self.get_current_db_type().lower() - conn_name = item.text() - print(db_type, conn_name) - # 模拟获取某个账号的信息、SSH账号等信息 - accounts = get_all_accounts() - print(accounts, db_type, conn_name) - if accounts.get(db_type) is not None: - account = accounts.get(db_type).get(conn_name) - if account is not None: - self.settings_panel.set_value(account.get('account')) - - # print(accounts.get(db_type).get(conn_name)) - - def show_accounts(self, accounts: List[str]): - """ - 在列表显示所有的连接 - :return: - """ - self.conn_list.clear() - self.conn_list.addItems(accounts) - - def test_connection(self): - """ - 连接检测 - :return: - """ - params = self.settings_panel.get_value() - connectaccount = dict( - account=dict( - user="root", password="123456", host="localhost", - port="3306", database="learning", charset="utf-8" - ), - usessh=False, - SSH={}, - connectdescribe="这又是一个测试" - ) - connectaccount['account'].update(params) - print(connectaccount) - # dbCA = dbConnectAccountTool() - mysql_url = "mysql+pymysql://{user}:{password}@{host}:{port}/{database}" - dbCT = dbConnectTool(account=connectaccount, conn_url=mysql_url) - connect_status = dbCT.createConn() - print(connect_status) - # db_functool = dbFuncTool(connectaccount, mysql_url) - # print(query(db_functool,'select * from scores;')) - if connect_status.get('status') == 'connect': - QMessageBox.information(self, self.tr('Connection Test'), self.tr('Connection Succeeded!'), QMessageBox.Ok) - else: - QMessageBox.information(self, self.tr('Connection Test'), self.tr('Connection Failed!'), QMessageBox.Ok) - - def create_account(self): - """ - 创建一个新的账户 - [TODO]:尚未连接事件 - :return: - """ - print('创建账户——目前尚未连接事件') - account_name, stat = QInputDialog.getText(self, '输入账户名称', '请输入账户名称') - if account_name != '': - params = self.settings_panel.get_value() - connectaccount = dict( - account=dict( - user="root", password="123456", host="localhost", - port="3306", database="learning", charset="utf-8" - ), - usessh=False, - SSH={}, - connectdescribe="这又是一个测试" - ) - connectaccount['account'].update(params) - create_account(account_name, connectaccount) - index = self.combo_select_database_type.currentIndex() - self.on_database_selected(index) - - -if __name__ == '__main__': - import sys - import cgitb - - cgitb.enable() - from PySide2.QtWidgets import QApplication - - app = QApplication(sys.argv) - sp2 = DatabaseConfigPanel() - # sp2.signal_settings_changed.connect(lambda settings: print('views2-settings', settings)) - sp2.show() - sys.exit(app.exec_()) diff --git a/pyminer/features/io/dbConn.py b/pyminer/features/io/dbConn.py deleted file mode 100644 index 13e22097..00000000 --- a/pyminer/features/io/dbConn.py +++ /dev/null @@ -1,131 +0,0 @@ -# -*- coding:utf8 -*- -class DatabaseConn(object): - - def tr(self, s: str): - return s - - def __init__(self): - self.conn_url = "{user}:{password}@{host}:{port}/{database}" - - def create_conn(self, dbtype="mysql"): - """ - 选择创建的通道 - Auth: - GanDaiWei - Args: - dbtype: 传入数据库类型 - Returns: - view: 连接通道的视图效果 - engine: 链接的 url 字符串 - """ - conn_dict = { - "mysql": self.mysql_conn, - "postgresql": self.pgsql_conn, - "oracle": self.oracle_conn, - "sql server": self.mssql_conn, - "sqlite": self.sqlite_conn - } - - assert dbtype in conn_dict, 'Can not create connection to {}'.format(dbtype) - view, engine, engine_type = conn_dict[dbtype]() - engine = engine if engine_type else engine + self.conn_url # 如果 url 不完整情况下需要进行拼接 - return (view, engine) - - def mssql_conn(self): - """ - 创建 SQL server 的链接 - mssql = Microsoft SQL server,即 SQLserver - Returns: - 前端界面视图、使用引擎、是否完整 - """ - mssql_view = [ - ('line_ctrl', 'database', self.tr('Database Name'), ''), - [ - ('line_ctrl', 'host', self.tr('Host Name/IP'), ''), - ('line_ctrl', 'port', self.tr('Port'), '1521') - ], - ('line_ctrl', 'initialDB', self.tr('Initial Database'), 'master'), # 初始数据库连接 - ('line_ctrl', 'user', self.tr('User'), ''), - ('password_ctrl', 'password', self.tr('Password'), ''), - ('line_ctrl', 'dbDesc', self.tr('Database Description'), '') - ] - return (mssql_view, "mssql+pymssql://", False) - - def sqlite_conn(self): - """ - 创建 SQLite 的链接 - Returns: - 前端界面视图、使用引擎、是否完整 - """ - sqlite_view = [ - ('line_ctrl', 'database', self.tr('Database Name'), ''), - ('line_ctrl', 'file', self.tr('Database File Road'), ''), - ('line_ctrl', 'user', self.tr('User'), ''), - ('password_ctrl', 'password', self.tr('Password'), ''), - ('line_ctrl', 'dbDesc', self.tr('Database Description'), '') - ] - return (sqlite_view, "sqlite://{}", True) - - def oracle_conn(self): - """ - 创建 Oracle 的链接 - Returns: - 前端界面视图、使用引擎、是否完整 - """ - oracle_view = [ - ('line_ctrl', 'database', self.tr('Database Name'), ''), - # ('combo_ctrl', 'connType', self.tr('Connect Type'), 'Basic', ['Basic', 'TNS']), # 暂时只支持 Basic 类型连接 - [ - ('line_ctrl', 'host', self.tr('Host Name/IP'), ''), - ('line_ctrl', 'port', self.tr('Port'), '1521') - ], - ('line_ctrl', 'user', self.tr('User'), ''), - ('password_ctrl', 'password', self.tr('Password'), ''), - ('line_ctrl', 'databasedesc', self.tr('Database Description'), '') - ] - return (oracle_view, "oracle://", False) - - def pgsql_conn(self): - """ - 创建 PgSQL 的链接 - Returns: - 前端界面视图、使用引擎、是否完整 - """ - pgsql_view = [ - ('line_ctrl', 'database', self.tr('Database Name'), ''), - [ - ('line_ctrl', 'host', self.tr('Host Name/IP'), 'localhost'), - ('line_ctrl', 'port', self.tr('Port'), '5432') - ], - ('line_ctrl', 'initialDB', self.tr('Initial Database'), 'postgres'), # 初始数据库连接 - ('line_ctrl', 'user', self.tr('User'), 'postgres'), - ('password_ctrl', 'password', self.tr('Password'), ''), - ('line_ctrl', 'databasedesc', self.tr('Database Description'), '') - ] - return (pgsql_view, "postgresql://", False) - - def mysql_conn(self): - """ - 创建MySQL的链接 - Returns: - 前端界面视图、使用引擎、是否完整 - """ - mysql_view = [ - ('line_ctrl', 'database', self.tr('Database Name'), ''), - [ - ('line_ctrl', 'host', self.tr('Host Name/IP'), 'localhost'), - ('line_ctrl', 'port', self.tr('Port'), '3306') - ], - ('line_ctrl', 'user', self.tr('User'), 'root'), - ('password_ctrl', 'password', self.tr('Password'), ''), - ('line_ctrl', 'databasedesc', self.tr('Database Description'), '') - ] - return (mysql_view, "mysql+pymysql://", False) - - -if __name__ == "__main__": - dbConn = DatabaseConn() - a = dbConn.create_conn("MySQL") - b = dbConn.create_conn("PgSQL") - print(a, b) - error = dbConn.create_conn("Mysql") diff --git a/pyminer/features/io/dbConnectAccount.pkl b/pyminer/features/io/dbConnectAccount.pkl deleted file mode 100644 index 578b0ddcced73a5e27fc2b9e848266e362eeeaa2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208 zcmXAjF$%&!5Jd$yMr~|8f{h{s#3R_}1e?uDgqYQxUBp62D^5A078Z75lS;6&@+KNQ zhAWxs&703>a<+ffs@V{F^EE6}a?~&qOl%zX(C0!Zn^g<5AT=S=N*TiDf&;9SjtOf{ zCJLNvrAqL$VzyA)DHa67k&DON@Q8z?q>a8vxCZI2o;B0{m@GD2IY2^NtcT&`|3^ot mER({-5`>;blCb-Ip2}nKe&p}Rt-SBP#lE~=KIa2jfWZ$0Kv?kr diff --git a/pyminer/features/io/encoding.py b/pyminer/features/io/encoding.py deleted file mode 100644 index caac3288..00000000 --- a/pyminer/features/io/encoding.py +++ /dev/null @@ -1,66 +0,0 @@ -import os - -from PySide2.QtWidgets import QDialog, QPushButton, QVBoxLayout, QHBoxLayout, QTextBrowser, QMessageBox - -from pmgwidgets import PMGPanel -import utils -from utils import file_encoding_convert - - -class EncodingConversionWidget(QDialog): - def __init__(self, parent=None): - super(EncodingConversionWidget, self).__init__(parent=parent) - views = [ - ('file_ctrl', 'input_file', '读取文件名', '', '', - utils.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR")), - ('file_ctrl', 'output_file', '输出为文件', '', '', - utils.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR"), 'save'), - [ - ('combo_ctrl', 'input_encoding', '读取编码方式', 'UTF8', ['UTF8', 'GBK', 'ASCII']), - ('combo_ctrl', 'output_encoding', '输出编码方式', 'UTF8', ['UTF8', 'GBK', 'ASCII']) - ] - - ] - self.panel = PMGPanel(parent=self, views=views) - self.text_view = QTextBrowser() - self.button_preview = QPushButton('预览') - self.button_convert = QPushButton('转换') - self.setLayout(QVBoxLayout()) - - self.layout().addWidget(self.panel) - self.layout().addWidget(self.text_view) - button_layout = QHBoxLayout() - self.layout().addLayout(button_layout) - button_layout.addWidget(self.button_preview) - button_layout.addWidget(self.button_convert) - - self.button_preview.clicked.connect(self.preview) - self.button_convert.clicked.connect(self.convert) - - def preview(self): - info = self.panel.get_value() - size = os.path.getsize(info['input_file']) - with open(info['input_file'], 'r', encoding=info['input_encoding'], errors='replace')as f: - if size > 1000: - text = f.read(1000) - else: - text = f.read() - self.text_view.setText(text) - - def convert(self): - info = self.panel.get_value() - try: - file_encoding_convert(info['input_file'], info['input_encoding'], info['output_file'], - info['output_encoding']) - QMessageBox.information(self, '提示', '转换完成!', QMessageBox.Ok, QMessageBox.Ok) - except FileNotFoundError: - QMessageBox.information(self, '未找到输出文件', '未找到输出文件', QMessageBox.Ok, QMessageBox.Ok) - - -if __name__ == '__main__': - from PySide2.QtWidgets import QApplication - - app = QApplication([]) - w = EncodingConversionWidget() - w.show() - app.exec_() diff --git a/pyminer/features/io/exceptions.py b/pyminer/features/io/exceptions.py deleted file mode 100644 index 59f34775..00000000 --- a/pyminer/features/io/exceptions.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- coding:utf-8 -*- -# @Time: 2021/1/27 10:22 -# @Author: Zhanyi Hou -# @Email: 1295752786@qq.com -# @File: exceptions.py - -from PySide2.QtCore import QObject, Signal, QCoreApplication - - -class PyMinerException(BaseException): - def __init__(self, error: BaseException, solution: str, solution_command: str = ''): - self.error = error - self.solution = solution - self.solution_command = solution_command - - def to_markdown(self): - return QCoreApplication.translate('PyMinerException', - """ -# {error} -## Solutions: -{solution} - """.format(error=self.error, solution=self.solution)) - - -class PMExceptions(QObject): - """ - 单例! - """ - signal_exception_occured = Signal(BaseException) - - @classmethod - def __new__(cls, *args): - if not hasattr(cls, 'instance'): - instance = super().__new__(cls) - cls.instance = instance - return cls.instance - - def __init__(self): - super(PMExceptions, self).__init__() - - @staticmethod - def get_instance() -> 'PMExceptions': - return PMExceptions.instance - - def emit_exception_occured_signal(self, error: BaseException, solution: str, solution_command: str): - self.signal_exception_occured.emit(PyMinerException(error, solution, solution_command)) - - -pyminer_exc_mgr = PMExceptions() diff --git a/pyminer/features/io/settings.py b/pyminer/features/io/settings.py deleted file mode 100644 index 60556216..00000000 --- a/pyminer/features/io/settings.py +++ /dev/null @@ -1,175 +0,0 @@ -""" -TODO:DEPRECATED。这个文件将被废弃! -settings.py负责设置文件的输入输出。 -Settings继承字典类,另外写了存储函数。 -还有其他设置的函数 -设置文件: -~/.pyminer文件夹存储设置文件。 -~/.pyminer/pyminer_config存储全局界面的设置文件 -~/.pyminer/packages下存储插件的文件夹,插件的文件也放在下面。 - -插件获取的方式: -extension_lib.Program.get_plugin_data_path(plugin_name) -比如: - -extension_lib.Program.get_plugin_data_path('code_editor') -返回的路径就是~/.pyminer/packages/code_editor文件夹。 - -其中的文件敬请插件开发者管理。建议不要向其中放太多数据,避免过多占用用户的磁盘空间。 -TODO:未来我们会增加一个插件读写设置的接口。可以将插件的文件放到里面。 -=============================== -方案1: -settings = Extension.create_default_settings() # 创建默认设置。 -settings = Extension.read_settings('settings.json') # settings值为一个字典,{'width':100,'height':161} -Extension.save_settings(settings,'settings.json') # 需要手动调用这个回调函数。 -=============================== -方案2: -创建一个默认的属性Extension.settings,与插件目录下的extsettings.json保持关联。 -启动时,插件加载之前调用: -ext = Extension() -ext.create_default_settings() # 创建默认设置 -ext.update_settings() # 从设置文件中读取设置并且更新设置 -ext.save_settings() # pyminer 关闭时自动调用 - -此时直接拿到settings就可以使用了。 -对于多进程插件,可以在启动的子进程中直接获取相关的设置路径。但一般的科学计算插件,是无需保存设置的。 -""" -import logging -import os -import json -import platform -from typing import Dict - -from PySide2.QtWidgets import QApplication - -import qdarkstyle -import utils - -logger = logging.getLogger(__name__) - - -def get_pyminer_data_path() -> str: - path = os.path.join(os.path.expanduser('~'), '.pyminer') - if not os.path.exists(path): - os.makedirs(path) - return path - - -def load_theme(style: str): - """ - 设置主题。 - :param style: - :return: - """ - from utils import get_main_window - app = QApplication.instance() - mw = get_main_window() - style = style.lower() - if style == 'fusion': - mw.setStyleSheet('') - app.setStyleSheet('') - standard_ss = mw.get_stylesheet('standard') - fusion_ss = mw.get_stylesheet('Fusion') - app.setStyleSheet(standard_ss + '\n' + fusion_ss) - mw.setStyleSheet(standard_ss + '\n' + fusion_ss) - # app.setStyle('Fusion') - - elif style == 'qdarkstyle': - app.setStyleSheet('') - mw.setStyleSheet('') - black_ss = mw.get_stylesheet('Qdarkstyle') - app.setStyleSheet(qdarkstyle.load_stylesheet()) # qt_api='pyqt5')) - app.setStyleSheet(app.styleSheet() + '\n' + black_ss) - mw.setStyleSheet(app.styleSheet() + '\n' + black_ss) - # app.setStyle('Windows') - - elif style.lower() == 'windowsvista': - app.setStyleSheet('') - mw.setStyleSheet('') - app.setStyleSheet(mw.get_stylesheet('windowsvista')) - mw.setStyleSheet(mw.get_stylesheet('windowsvista')) - # app.setStyle("windowsvista") - - elif style.lower() == 'windows': - app.setStyleSheet('') - mw.setStyleSheet('') - app.setStyleSheet(mw.get_stylesheet('Windows')) - mw.setStyleSheet(mw.get_stylesheet('Windows')) - # app.setStyle("Windows") - - -# class Settings(dict): -# """ -# 单例! -# """ -# -# @classmethod -# def __new__(cls, *args): -# if not hasattr(cls, 'instance'): -# instance = super().__new__(cls) -# cls.instance = instance -# return cls.instance -# -# def __init__(self): -# super(Settings, self).__init__() -# self.check_pyminer_settings_dir() -# self.update(self.load()) -# -# def check_pyminer_settings_dir(self): -# self.data_path = get_pyminer_data_path() -# path = os.path.join(self.data_path, 'pyminer_config') -# self.settings_path = path -# if not os.path.exists(path): -# os.mkdir(path) -# -# @staticmethod -# def get_instance() -> 'Settings': -# return Settings.instance -# -# def load(self) -> Dict[str, str]: -# """ -# 加载设置项。 -# default_settings是默认设置项 -# :return: -# """ -# with open(os.path.join(utils.get_root_dir(), 'configuration', 'default_settings.json'), 'r') as f: -# default_settings = json.load(f) -# if platform.system().lower() == 'windows': -# default_settings['work_dir'] = os.path.expanduser('~') -# else: -# default_settings['work_dir'] = os.environ['HOME'] -# if not os.path.exists(default_settings['work_dir']): -# os.mkdir(default_settings['work_dir']) -# -# try: -# with open(os.path.join(self.settings_path, 'pyminer_settings.json'), 'r') as f: -# settings = json.load(f) -# except BaseException: -# settings = {} -# -# pmsettings = default_settings -# pmsettings.update(settings) -# if not os.path.exists(pmsettings['work_dir']): -# pmsettings['work_dir'] = os.path.expanduser('~') -# return pmsettings -# -# def save(self): -# """ -# 保存 -# :return: -# """ -# import json -# try: -# config_file = os.path.join(self.settings_path, 'pyminer_settings.json') -# with open(config_file, 'w') as f: -# json.dump(self, f, indent=4) -# except FileNotFoundError as e: -# logging.warning(e) - - -if __name__ == '__main__': - s1 = Settings() - s2 = Settings() - s3 = Settings.instance - print(s3) - print(id(s1), id(s2), s1 is s2, id(s3)) diff --git a/pyminer/features/main_window/base.py b/pyminer/features/main_window/base.py deleted file mode 100644 index 32b23dbf..00000000 --- a/pyminer/features/main_window/base.py +++ /dev/null @@ -1,731 +0,0 @@ -import base64 -import json -import logging -import os -import sys -import time -import webbrowser -from multiprocessing import shared_memory -from typing import List - -import qdarkstyle -from PySide2.QtCore import QPoint, QRectF -from PySide2.QtGui import QMouseEvent, QPainter, QLinearGradient, QCursor -from PySide2.QtGui import QCloseEvent -from PySide2.QtCore import Signal, Qt, QUrl, QPropertyAnimation -from PySide2.QtGui import QCloseEvent -from PySide2.QtGui import QMouseEvent -from PySide2.QtWebEngineWidgets import * -from PySide2.QtWidgets import QListWidgetItem, QWizard, QMessageBox -from PySide2.QtWidgets import QWidget, QDesktopWidget, QFileDialog, QApplication, QDialog - -import utils -from features.extensions.extensionlib.extension_lib import extension_lib -from features.ui.ui_aboutme import Ui_Form as About_Ui_Form -from features.ui.ui_appstore import Ui_Form as appStore_Ui_Form -from features.ui.ui_first_form import Ui_Form as first_Ui_Form -from features.ui.ui_login import Ui_Form as login_Ui_Form -from features.ui.ui_logined import Ui_Form as logined_Ui_Form -from features.ui.ui_option import Ui_Form as Option_Ui_Form -from features.ui.ui_project_wizard import Ui_Wizard as Project_Ui_Form -from pmgwidgets import PMGPanel -from utils import get_main_window, http_client - -logger = logging.getLogger(__name__) - - -class OptionForm(QDialog, Option_Ui_Form): - """ - 打开"选项"窗口 - """ - signal_settings_changed = Signal() - - def __init__(self, parent=None): - super().__init__(parent) - self.setupUi(self) - self.center() - self.page_format.setEnabled(False) - self.page_appearance.setEnabled(False) - - self.setup_ui() - - # 通过combobox控件选择窗口风格 - self.comboBox_theme.activated[str].connect(self.slot_theme_changed) - - self.setting = dict() - - self.listWidget.currentRowChanged.connect(self.option_change) - self.toolButton_workspace.clicked.connect(self.slot_change_workspace) - self.toolButton_output.clicked.connect(self.slot_change_output) - self.pushButton_cancel.clicked.connect(self.close) - self.pushButton_ok.clicked.connect(self.close) - self.pushButton_help.clicked.connect(self.get_help) - - def setup_ui(self): - self.comboBox_9.setEnabled(False) - self.comboBox_8.setEnabled(False) - # self.checkbox_show_startpage.setEnabled(False) - # self.checkBox_minitray.setEnabled(False) - - def add_settings_panel(self, text: str, settings_content: List): - settings_widget = PMGPanel(views=settings_content) - self.signal_settings_changed.connect(settings_widget.emit_settings_changed_signal) - self.stackedWidget.addWidget(settings_widget) - self.listWidget.addItem(QListWidgetItem(text)) - return settings_widget - - def add_page(self, text, page: QWidget): - self.stackedWidget.addWidget(page) - self.listWidget.addItem(QListWidgetItem(text)) - return page - - def closeEvent(self, a0: 'QCloseEvent') -> None: - super(OptionForm, self).closeEvent(a0) - self.refresh_settings() - - def keyPressEvent(self, e): - """ - 按键盘Escape退出当前窗口 - @param e: - """ - if e.key() == Qt.Key_Escape: - self.close() - - def center(self): - qr = self.frameGeometry() - cp = QDesktopWidget().availableGeometry().center() - qr.moveCenter(cp) - self.move(qr.topLeft()) - - def option_change(self, i): - self.stackedWidget.setCurrentIndex(i) - - def slot_theme_changed(self, style): - """ - 在主题颜色改变时触发的回调 - :param style: - :return: - """ - from features.io.settings import load_theme - load_theme(style) - utils.write_settings_item_to_file("config.ini", "MAIN/THEME", self.comboBox_theme.currentText()) - get_main_window().settings_changed_signal.emit() - - def slot_change_workspace(self): - """ - 改变工作路径时的回调 - Returns: - - """ - work_dir = utils.get_settings_item_from_file("config.ini", "MAIN/THEME", self.comboBox_theme.currentText()) - directory = QFileDialog.getExistingDirectory(self, "选择工作路径位置", directory=work_dir) - if not directory == '': - self.lineEdit_worksapce.setText(directory) - - def slot_change_output(self): - directory = QFileDialog.getExistingDirectory(self, "选择输出文件夹位置", os.path.expanduser('~')) - self.lineEdit_output.setText(directory) - - def load_settings(self): - """ - 在show()之前调用这个方法 - 从而每次重新显示的时候都可以刷新数据。 - :return: - """ - settings = utils.get_settings_from_file("config.ini") - logger.debug("PATH/WORKDIR", settings.value('MAIN/PATH_WORKDIR')) - if settings.value('MAIN/THEME') is not None: - for i in range(self.comboBox_theme.count()): - if self.comboBox_theme.itemText(i) == settings.value('MAIN/THEME'): - self.comboBox_theme.setCurrentIndex(i) - self.lineEdit_worksapce.setText(settings.value("MAIN/PATH_WORKDIR")) - self.lineEdit_output.setText(settings.value("MAIN/PATH_OUTPUT")) - - check_update = utils.get_settings_item_from_file("config.ini", "MAIN/CHECK_UPDATE") - show_start_page = utils.get_settings_item_from_file("config.ini", "MAIN/SHOW_START_PAGE") - self.check_box_check_upd_on_startup.setChecked(check_update) - self.checkbox_show_startpage.setChecked(show_start_page) - - def refresh_settings(self): - """ - 窗口关闭时,调用此方法,刷新主界面设置项。 - :return: - """ - utils.write_settings_item_to_file("config.ini", "MAIN/THEME", self.comboBox_theme.currentText()) - utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", self.lineEdit_worksapce.text()) - utils.write_settings_item_to_file("config.ini", "MAIN/PATH_OUTPUT", self.lineEdit_output.text()) - utils.write_settings_item_to_file("config.ini", "MAIN/CHECK_UPDATE", - self.check_box_check_upd_on_startup.isChecked()) - utils.write_settings_item_to_file("config.ini", "MAIN/SHOW_START_PAGE", - self.checkbox_show_startpage.isChecked()) - - get_main_window().on_settings_changed() - self.signal_settings_changed.emit() - - def show(self): - """ - 重写此方法,在显示之前重新加载一遍设置。 - :return: - """ - self.load_settings() - super(OptionForm, self).show() - - def exec_(self): - """ - 继承exec_方法。 - :return: - """ - self.load_settings() - super(OptionForm, self).exec_() - - def get_help(self): - webbrowser.open('https://gitee.com/py2cn/pyminer/wikis/%E9%85%8D%E7%BD%AEPyMiner?sort_id=3263840') - - -class AppstoreForm(QWidget, appStore_Ui_Form): - def __init__(self): - super(AppstoreForm, self).__init__() - self.setupUi(self) - self.center() - - self.browser = QWebEngineView() - # 加载外部的web界面 - self.browser.load(QUrl('https://chrome.zzzmh.cn/index#ext')) - self.horizontalLayout_2.addWidget(self.browser) - - self.toolButton_help.clicked.connect(self.main_help_display) - - def keyPressEvent(self, e): - """ - 按键盘Escape退出当前窗口 - @param e: - """ - if e.key() == Qt.Key_Escape: - self.close() - - def center(self): - qr = self.frameGeometry() - cp = QDesktopWidget().availableGeometry().center() - qr.moveCenter(cp) - self.move(qr.topLeft()) - - def main_help_display(self): - """ - 打开帮助页面 - """ - try: - webbrowser.get('chrome').open_new_tab("http://www.pyminer.com") - except Exception as e: - webbrowser.open_new_tab("http://www.pyminer.com") - - -class AboutForm(QWidget, About_Ui_Form): - """ - 关于 弹出框 - - """ - - def __init__(self): - super(AboutForm, self).__init__() - self.setupUi(self) - self.center() - AUTHOR = utils.get_settings_item_from_file("config.ini", "INFO/AUTHOR", "default") - MAIL = utils.get_settings_item_from_file("config.ini", "INFO/MAIL", "default") - self.textedit_about.setMarkdown("""# PyMiner -PyMiner 是一款基于Python的开源、跨平台数据分析环境。它以方便Python初学者为己任,在Python的知识理论和工作实践之间搭建桥梁,竭诚为初学者服务。 -- PyMiner开箱即用,大大减少配置解释器环境的繁琐性。不仅提供了编程运行的功能,还能够以交互式的形式进行常见的数据分析操作,减少代码编写和文档查阅的时间。 -- PyMiner通过加载各种插件实现不同的需求,开发者可以通过编写插件,将PyMiner扩展的更强大、更趁手,甚至创建一番自己的商用程序。 -- PyMiner提供面向新手的快速入门教程,教程正由开发团队编写中。 -- 我们诚挚希望与Python培训或教育机构/个人合作,让我们的产品帮助到更多学习Python的人。 - -作者:{AUTHOR} - -邮箱:{MAIL} -""".format(AUTHOR=AUTHOR, MAIL=MAIL)) - - self.main_about_display() - - def keyPressEvent(self, e): - """ - 按键盘Escape退出当前窗口 - @param e: - """ - if e.key() == Qt.Key_Escape: - self.close() - - def center(self): - qr = self.frameGeometry() - cp = QDesktopWidget().availableGeometry().center() - qr.moveCenter(cp) - self.move(qr.topLeft()) - - def main_about_display(self): - """ - 打开关于页面 - """ - import platform - python_info = 'Python版本: ' + platform.python_version() + ' ' + platform.python_compiler() - system_info = '系统信息: ' + platform.platform() + ' ' + platform.architecture()[0] - cpu_info = 'CPU信息: ' + platform.processor() - self.feedback.setPlainText(python_info + '\n' + system_info + '\n' + cpu_info) - self.label_version_show.setText(utils.get_settings_item_from_file("config.ini", "INFO/VERSION", "default")) - - -class ProjectWizardForm(QWizard, Project_Ui_Form): - """ - 新建项目引导窗口 - """ - - def __init__(self, parent=None): - super(ProjectWizardForm, self).__init__(parent=None) - self.setupUi(self) - self.center() - self.default_setting() - self.init() - - def init(self): - # 初始化项目路径 - project_name = self.projectNameLineEdit.text() - workspace_dir = os.path.join(os.path.expanduser('~'), 'PyMiner_workspace', project_name) - file_dir = os.path.join(os.path.expanduser('~'), 'PyMiner_workspace', project_name, 'main.py') - self.projectDirectoryEditLine.setText(workspace_dir) - self.absoluteDirectoryEditLine.setText(file_dir) - - # 浏览按钮触发事件 - self.toolButton.clicked.connect(self.getProjectDirectory) - # 向导界面finish按钮按下后触发的事件 - self.button(QWizard.FinishButton).clicked.connect(self.finishWizard) - # 项目名称框text发生改变时触发的事件 - self.projectNameLineEdit.textChanged.connect(self.projectNameLineEditTextChange) - # 选择不同项目类型时下方展示不同的类型描述 - self.file_list.itemClicked.connect(self.fileListItemClicked) - - def getProjectDirectory(self): - """ - 浏览按钮触发的事件,选择文件夹 - :return: - """ - absolute_directory = self.absoluteDirectoryEditLine.text() - project_directory = self.projectDirectoryEditLine.text() - directory_name = QFileDialog.getExistingDirectory(None, "请选择文件夹路径", "./").replace("/", "\\") - self.projectDirectoryEditLine.setText(directory_name) - project_name = self.projectNameLineEdit.text() - if len(project_name) != 0: - if len(directory_name) != 0: - self.absoluteDirectoryEditLine.setText(directory_name + "\\" + project_name + '\\main.py') - self.projectDirectoryEditLine.setText(directory_name + "\\" + project_name) - else: - self.absoluteDirectoryEditLine.setText(absolute_directory) - self.projectDirectoryEditLine.setText(project_directory) - else: - if len(directory_name) != 0: - self.absoluteDirectoryEditLine.setText(directory_name + "\\" + project_name + '\\main.py') - self.projectDirectoryEditLine.setText(directory_name + "\\" + project_name) - else: - self.absoluteDirectoryEditLine.setText(absolute_directory) - self.projectDirectoryEditLine.setText(project_directory) - project_directory = self.projectDirectoryEditLine.text() - if project_directory != "" and os.path.exists(project_directory): - # 警告:该项目已存在,完成向导后原来的项目将会被覆盖!!! - self.warningLabel.adjustSize() - self.warningLabel.setText("Warning: The project already exists, the original \nproject will be overwritten " - "after completing the \nwizard! ! !") - else: - self.warningLabel.setText("") - - def finishWizard(self): - """ - 完成项目创建向导后做的动作,文件夹不存在时创建路径并创建空的main.py文件,文件存在时只创建main.py,然后在主窗口中打开 - :return: - """ - import os - import pathlib - file_path = self.absoluteDirectoryEditLine.text() - project_path = self.projectDirectoryEditLine.text() - current_project_type = self.file_list.currentRow() - if os.path.exists(project_path): - if current_project_type != 3: # Python-Template-PySide2 - pathlib.Path(file_path).touch() # 创建空文件 - else: - from shutil import rmtree - rmtree(project_path) - else: - if current_project_type != 3: # Python-Template-PySide2 - os.mkdir(project_path) - pathlib.Path(file_path).touch() - from shutil import copyfile - if current_project_type == 0: # Python-Empty # 创建空项目 - template_dir = "features/project/template/Empty-Template.py" - if os.path.exists(template_dir): - copyfile(template_dir, file_path) - else: # 若模板文件不存在,默认新建空main.py - with open(file_path, "w") as f: - f.write("# --coding:utf-8--\n") - f.write("") - elif current_project_type == 1: # Python-Template-Basic # 创建base template项目 - template_dir = "features/project/template/Basic-Template.py" - if os.path.exists(template_dir): - copyfile(template_dir, file_path) - else: # 若模板文件不存在,默认将以下内容写入main.py - with open(file_path, "w") as f: - f.write("# --coding:utf-8--\n") - f.write("if __name__ == '__main__':\n") - f.write(" # Create your codes here") - f.write(" pass") - elif current_project_type == 2: # Python-Template-Plot # 创建plot template项目 - template_dir = "features/project/template/Plot-Template.py" - if os.path.exists(template_dir): - copyfile(template_dir, file_path) - else: # 若模板文件不存在,默认将以下内容写入main.py - with open(file_path, "w") as f: - f.write("# --coding:utf-8--\n") - f.write("\n") - f.write("import matplotlib.pyplot as plt\n") - f.write("import numpy as np\n") - f.write("\n") - f.write("\n") - f.write("def demoTemplate():\n") - f.write(" x = np.linspace(0, 5, 200)\n") - f.write(" y1 = x + 1\n") - f.write(" y2 = x - 1\n") - f.write(" plt.figure()\n") - f.write(" ax = plt.axes()\n") - f.write(" ax.spines['top'].set_visible(False)\n") - f.write(" ax.spines['right'].set_visible(False)\n") - f.write(" plt.grid(axis='both', linestyle='-.', c='b')\n") - f.write(" plt.plot(x, y1, 'c--')\n") - f.write(" plt.plot(x, y2, 'r-.')\n") - f.write(" plt.text(1, 0.5, 'text')\n") - f.write(" plt.legend(['y1', 'y2'])\n") - f.write(" plt.xlabel('xlabel')\n") - f.write(" plt.ylabel('ylabel')\n") - f.write(" plt.title('title')\n") - f.write(" plt.show()\n") - f.write("\n") - f.write("\n") - f.write("if __name__ == '__main__':\n") - f.write(" demoTemplate()\n") - elif current_project_type == 3: # Python-Template-PySide2 # 创建pyqt template项目 - template_dir = "features/project/template/PySide2Template" - if os.path.exists(template_dir): - from shutil import copytree - copytree(template_dir, project_path) - else: # 若模板文件不存在,默认将以下内容写入main.py - QMessageBox.warning(self, "警告", "模板路径不存在,请确保模板在程序根目录下的features/project/template/PySide2Template", - QMessageBox.Ok) - extension_lib.Program.set_work_dir(project_path) # 在文件树区域打开新建项目,将当前工作路径切换为新建的项目 - - def projectNameLineEditTextChange(self): - """ - 项目名称发生改变时同步改变绝对路径 - Returns - ------- - - """ - project_name = self.projectNameLineEdit.text() - absolute_directory = self.absoluteDirectoryEditLine.text() - # 将文件路径按照\分割成列表,然后把右边2个元素也就是main.py与项目名称pop()移出列表,最后再拼接成完整的路径 - absolute_directory_list = absolute_directory.split("\\") - absolute_directory_list.pop() # 移除最右边的元素"main.py" - absolute_directory_list.pop() # 移除右边的项目名称元素 - if absolute_directory != "": - # 将新项目名称和main.py与浏览按钮选择的路径进行拼接组合成新的绝对路径和项目路径 - self.projectDirectoryEditLine.setText("\\".join(absolute_directory_list) + "\\" + project_name) - self.absoluteDirectoryEditLine.setText("\\".join(absolute_directory_list) + "\\" + project_name - + "\\main.py") - project_dir = self.projectDirectoryEditLine.text() - if os.path.exists(project_dir): - # 警告:该项目已存在,完成向导后原来的项目将会被覆盖!!! - self.warningLabel.setText("Warning: The project already exists, the original \nproject will be overwritten " - "after completing the \nwizard! ! !") - else: - self.warningLabel.setText("") - - def fileListItemClicked(self): - current_project_type = self.file_list.currentRow() - if current_project_type == 0: # Python-Empty - self.plainTextEdit.setPlainText("Create a Python Project containing an Empty main.py.") - elif current_project_type == 1: # Python-Template-Basic - self.plainTextEdit.setPlainText("Create a Python Project containing a Base Template main.py.") - elif current_project_type == 2: # Python-Template-Plot - self.plainTextEdit.setPlainText("Create a Python Project containing a Plot Template main.py.") - elif current_project_type == 3: # Python-Template-PySide2 - self.plainTextEdit.setPlainText("Create a Python Project containing a PySide2 Template main.py.") - - def keyPressEvent(self, e): - """ - 按键盘Escape退出当前窗口 - @param e: - """ - if e.key() == Qt.Key_Escape: - self.close() - - def center(self): - qr = self.frameGeometry() - cp = QDesktopWidget().availableGeometry().center() - qr.moveCenter(cp) - self.move(qr.topLeft()) - - def default_setting(self): - item = self.file_list.item(1) - item.setSelected(True) - - -class FirstForm(QDialog, first_Ui_Form): - """ - 快速操作窗口 - """ - - def __init__(self, parent=None): - super(FirstForm, self).__init__(parent) - self.setupUi(self) - self.center() - self.setWindowOpacity(0.95) - self.setWindowTitle(self.tr('Quick Start')) - # self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Popup) # 无边框、弹出式 - self.animation = None - # self.setStyleSheet("border-radius:10px;border:none;") - # self.setAttribute(Qt.WA_TranslucentBackground) - - # 绑定事件 - self.btn_open_python.clicked.connect(self.open_script) - self.btn_manual.clicked.connect(self.open_manual) - self.btn_website.clicked.connect(self.open_website) - self.btn_source.clicked.connect(self.open_source) - self.btn_member.clicked.connect(self.open_member) - self.btn_donate.clicked.connect(self.open_donate) - - self.btn_open_csv.clicked.connect(self.open_csv) - self.btn_open_excel.clicked.connect(self.open_excel) - self.btn_open_matlab.clicked.connect(self.open_matlab) - self.btn_open_folder.clicked.connect(self.open_folder) - - def closeEvent(self, event): - if self.animation is None: - self.animation = QPropertyAnimation(self, b'windowOpacity', self.parent()) - # self.animation.setPropertyName(b'windowOpacity') - self.animation.setDuration(200) - self.animation.setStartValue(self.windowOpacity()) - self.animation.setEndValue(0) - self.animation.finished.connect(self.close) - self.animation.start() - event.ignore() - - def mouseMoveEvent(self, e: QMouseEvent): # 重写移动事件 - self._endPos = e.pos() - self._startPos - self.move(self.pos() + self._endPos) - super(FirstForm, self).mouseMoveEvent(e) - - def mousePressEvent(self, e: QMouseEvent): - if e.button() == Qt.LeftButton: - self._isTracking = True - self._startPos = QPoint(e.x(), e.y()) - super(FirstForm, self).mousePressEvent(e) - - def mouseReleaseEvent(self, e: QMouseEvent): - super(FirstForm, self).mouseReleaseEvent(e) - if e.button() == Qt.LeftButton: - self._isTracking = False - self._startPos = None - self._endPos = None - - def keyPressEvent(self, e): - """ - 按键盘Escape退出当前窗口 - @param e: - """ - super(FirstForm, self).keyPressEvent(e) - if e.key() == Qt.Key_Escape: - self.close() - - def center(self): - qr = self.frameGeometry() - cp = QDesktopWidget().availableGeometry().center() - qr.moveCenter(cp) - self.move(qr.topLeft()) - - def open_script(self): - user_home = os.path.expanduser('~') - file_name, filetype = QFileDialog.getOpenFileName(self, "选取文件", user_home, "Python Files (*.py);;All Files (*)") - self.hide() - extension_lib.get_interface('code_editor').open_script(file_name) - self.close() - - def open_manual(self): - """ - 打开快速入门 - :return: - """ - utils.open_url("https://gitee.com/py2cn/pyminer/wikis/%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B?sort_id=3137860") - - def open_website(self): - """ - 打开快速入门 - :return: - """ - utils.open_url("http://www.pyminer.com") - - def open_source(self): - """ - 打开快速入门 - :return: - """ - utils.open_url("https://gitee.com/py2cn/pyminer") - - def open_member(self): - """ - 打开 ‘加入我们’ 页面 - :return: - """ - utils.open_url("https://gitee.com/py2cn/pyminer/wikis/%E8%81%94%E7%B3%BB%E6%88%91%E4%BB%AC?sort_id=2761039") - - def open_donate(self): - """ - 打开 ‘捐赠’ 页面 - :return: - """ - utils.open_url("https://gitee.com/py2cn/pyminer/wikis/%E6%8D%90%E8%B5%A0?sort_id=2925146") - - def open_csv(self): - """ - 调用主程序打开csv到工作区间 - :return: - """ - self.hide() - extension_lib.get_interface('dataio').show_import_file_dialog('csv', '') - self.close() - - def open_excel(self): - """ - 调用主程序打开excel到工作区间 - :return: - """ - self.hide() - extension_lib.get_interface('dataio').show_import_file_dialog('excel', '') - self.close() - - def open_matlab(self): - """ - 调用主程序打开matlab到工作区间 - :return: - """ - self.hide() - extension_lib.get_interface('dataio').show_import_file_dialog('matlab', '') - # get_main_window().process_file('matlab') - self.close() - - def open_folder(self): - user_home = os.path.expanduser('~') - project_path = QFileDialog.getExistingDirectory(self, "选取文件夹", user_home) - self.hide() - extension_lib.Program.set_work_dir(project_path) - self.close() - - -class LoginForm(QDialog, login_Ui_Form): - """ - 登录窗口 - """ - - def __init__(self, parent=None): - super(LoginForm, self).__init__(parent) - self.setupUi(self) - self.init() - - def init(self): - self.loginButton.clicked.connect(self.login) - self.forgetPwdButton.clicked.connect(self.forgetPwd) - self.usernameLineEdit.textChanged.connect(self.usernameErrorChange) - - def login(self): - username = self.usernameLineEdit.text() - password = self.passwordLineEdit.text() - flag = False - if username == "": - self.usernameError.setText("用户名不能为空") - flag = True - if password == "": - self.passwordError.setText("密码不能为空") - flag = True - if not flag: - data = { - "usr": username, - "password": base64.b64encode(password.encode()) - } - url = http_client.API + http_client.LOGIN_URL - resp = http_client.client(url, "post", data) - resp_info = json.loads(resp.text) - if resp.status_code == 200: - if resp_info["code"] == 10000: - token = resp_info["token"] - token_len = len(token) - username_len = len(username.encode("utf-8")) - """ - 将登录后django返回的token令牌保存在共享内存token中,共享内存token在启动pyminer主程序时附带启动了本地flask服务然后 - 创建共享内存token,详情见pmlocalserver/server.py - """ - shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token - buff = shared_memo.buf - # token长度随着用户名长度的增加而增加,用户名最长为21个汉字加一个字符 - # buff[:3]存放token长度,目前最长的用户名21汉字加一字符生成的token长度为343 - # buff[3:5]存放用户名长度,用户名字段最长为64字节,最多21个汉字(字符集utf8) - # buff[5:token_len+5]位存放token - # buff[token_len+5:实际用户名长度(用utf8转换为bytes后的长度)]存放用户名 - buff[:3] = str(token_len).encode("utf-8") # 存放token长度 - buff[3:5] = str(username_len).encode("utf-8") # 将用户名长度存放共享内存 - buff[5:token_len+5] = token.encode("utf-8") # 将token存放进共享内存中,工作空间重启后也能获取到 - buff[token_len+5:token_len+5+username_len] = username.encode("utf-8") # 存放用户名 - self.usernameError.setText("登录成功") - time.sleep(0.5) - self.close() - else: - self.usernameError.setText(resp_info["msg"][0]) - - def forgetPwd(self): - utils.open_url("http://pyminer.com/forgetpassword") - - def usernameErrorChange(self): - self.usernameError.setText("") - self.passwordError.setText("") - username = self.usernameLineEdit.text() - if len(username.encode("utf-8")) > 64: - self.usernameError.setText("最多只能输入21个汉字") - self.loginButton.setEnabled(False) - self.loginButton.setCursor(QCursor(Qt.ForbiddenCursor)) - else: - self.usernameError.setText("") - self.loginButton.setEnabled(True) - self.loginButton.setCursor(QCursor(Qt.PointingHandCursor)) - - -class LoginedForm(QDialog, logined_Ui_Form): - - def __init__(self, parent=None): - super(LoginedForm, self).__init__(parent) - self.setupUi(self) - self.init() - shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token - buff = shared_memo.buf - token_len = int(bytes(buff[:3]).decode()) - username_len = int(bytes(buff[3:5]).decode()) - username = bytes(buff[token_len+5:token_len+5+username_len]).decode("utf-8") - self.usernameLabel.setText(username) - - def init(self): - self.loginOutButton.clicked.connect(self.logout) - - def logout(self): - shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token - buff = shared_memo.buf - for i in range(0, len(buff)): - buff[i:i + 1] = "\x00".encode() - time.sleep(0.5) - self.close() - - -if __name__ == '__main__': - app = QApplication(sys.argv) - # form = FirstForm() - form = LoginedForm() - form.show() - sys.exit(app.exec_()) diff --git a/pyminer/features/openprocess.py b/pyminer/features/openprocess.py deleted file mode 100644 index 1d4cc8df..00000000 --- a/pyminer/features/openprocess.py +++ /dev/null @@ -1,108 +0,0 @@ -import platform -import queue -import subprocess -import sys -import threading -import time -import chardet -from typing import List - -import packages.code_editor.utils.utils - - -class PMProcess(): - def __init__(self, args: List[str]): - self.terminate = False - self.q = queue.Queue() - self.on_command_received = lambda cmd: print(cmd) - self.on_error_received = lambda error: print(error) - self.args = args - self.process = subprocess.Popen(self.args, - stdin=subprocess.PIPE, - shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - self.to = threading.Thread( - target=self.enqueue_stream, args=( - self.process.stdout, self.q, 1)) - self.te = threading.Thread( - target=self.enqueue_stream_err, args=( - self.process.stderr, self.q, 2)) - self.tp = threading.Thread(target=self.consoleLoop) - self.to.setDaemon(True) - self.te.setDaemon(True) - self.tp.setDaemon(True) - self.te.start() - self.to.start() - self.tp.start() - - def enqueue_stream_err(self, stream, queue, type): - """ - stdout写入到队列q中。 - Args: - stream: - queue: - type: - - Returns: - - """ - for line in iter(stream.readline, b''): - if self.terminate: - break - if platform.system().lower() == 'linux': - encoding = 'utf-8' - else: - encoding = chardet.detect(line)['encoding'] - queue.put(str(type) + packages.code_editor.utils.utils.decode(encoding)) - print(line) - stream.close() - - def enqueue_stream(self, stream, queue, type): # 将stderr或者stdout写入到队列q中。 - """ - stdout写入到队列q中。 - Args: - stream: - queue: - type: - - Returns: - - """ - for line in iter(lambda: stream.read(1), b''): - if self.terminate: - break - if platform.system().lower() == 'linux': - encoding = 'utf-8' - else: - encoding = chardet.detect(line)['encoding'] - queue.put(str(type) + packages.code_editor.utils.utils.decode(encoding)) - stream.close() - - def consoleLoop(self): # 封装后的内容。 - return - idleLoops = 0 - while True: - if not self.q.empty(): - line = self.q.get() - if line[0] == '1': - self.on_command_received(line[1:]) - else: - self.on_error_received(line[1:]) - sys.stdout.flush() - else: - time.sleep(0.01) - if idleLoops >= 5: - idleLoops = 0 - # print('write!!') - self.process.stdin.write( - 'messsage\n'.encode('ascii')) # 模拟输入 - self.process.stdin.flush() - continue - idleLoops += 1 - - -if __name__ == '__main__': - pmp = PMProcess(['python', '-u', - 'test_open_app.py']) - while (1): - time.sleep(2) - pass diff --git a/pyminer/features/pluginsmanager/__init__.py b/pyminer/features/pluginsmanager/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/pluginsmanager/pluginsmanager.py b/pyminer/features/pluginsmanager/pluginsmanager.py deleted file mode 100644 index f679afc1..00000000 --- a/pyminer/features/pluginsmanager/pluginsmanager.py +++ /dev/null @@ -1,15 +0,0 @@ -import subprocess -import sys -from PySide2.QtWidgets import QFrame, QTableWidgetItem, QTableWidget, QMessageBox, QDialog, QDesktopWidget, QHeaderView, \ - QProgressDialog -from PySide2.QtGui import QCloseEvent -from PySide2.QtCore import Signal, Qt, QUrl, QPropertyAnimation -from features.ui.pm_marketplace.main import Ui_Form as marketplace_Ui_Form - -from pmgwidgets import PMGOneShotThreadRunner - - -class MarketplaceForm(QDialog, marketplace_Ui_Form): - def __init__(self, parent=None): - super(MarketplaceForm, self).__init__(parent) - self.setupUi(self) diff --git a/pyminer/features/project/template/Basic-Template.py b/pyminer/features/project/template/Basic-Template.py deleted file mode 100644 index 6788f5a1..00000000 --- a/pyminer/features/project/template/Basic-Template.py +++ /dev/null @@ -1,14 +0,0 @@ -# --coding:utf-8-- - -""" -Please make sure the content of the file is complete. -If you customize the template, please make sure it can be executed correctly -by the interpreter after modification. -Do not delete the file and the directory where the file is located. -请确保文件内容完整。 -若自定义模板,请在修改后确保能够被解释器正确执行。 -【请勿删除】该文件以及文件所在目录。 -""" -if __name__ == '__main__': - # Create your codes here - pass diff --git a/pyminer/features/project/template/Empty-Template.py b/pyminer/features/project/template/Empty-Template.py deleted file mode 100644 index 365f9f7f..00000000 --- a/pyminer/features/project/template/Empty-Template.py +++ /dev/null @@ -1,10 +0,0 @@ -# --coding:utf-8-- -""" -Please make sure the content of the file is complete. -If you customize the template, please make sure it can be executed correctly -by the interpreter after modification. -Do not delete the file and the directory where the file is located. -请确保文件内容完整。 -若自定义模板,请在修改后确保能够被解释器正确执行。 -【请勿删除】该文件以及文件所在目录 -""" \ No newline at end of file diff --git a/pyminer/features/project/template/Plot-Template.py b/pyminer/features/project/template/Plot-Template.py deleted file mode 100644 index 000c5ab1..00000000 --- a/pyminer/features/project/template/Plot-Template.py +++ /dev/null @@ -1,36 +0,0 @@ -# --coding:utf-8-- - -""" -Please make sure the content of the file is complete. -If you customize the template, please make sure it can be executed correctly -by the interpreter after modification. -Do not delete the file and the directory where the file is located. -请确保文件内容完整。 -若自定义模板,请在修改后确保能够被解释器正确执行。 -【请勿删除】该文件以及文件所在目录 -""" -import matplotlib.pyplot as plt -import numpy as np - - -def demoTemplate(): - x = np.linspace(0, 5, 200) - y1 = x + 1 - y2 = x - 1 - plt.figure() - ax = plt.axes() - ax.spines['top'].set_visible(False) - ax.spines['right'].set_visible(False) - plt.grid(axis="both", linestyle='-.', c='b') - plt.plot(x, y1, 'c--') - plt.plot(x, y2, 'r-.') - plt.text(1, 0.5, "text") - plt.legend(["y1", "y2"]) - plt.xlabel("xlabel") - plt.ylabel("ylabel") - plt.title("title") - plt.show() - - -if __name__ == '__main__': - demoTemplate() diff --git a/pyminer/features/project/template/PyQt-Template.py b/pyminer/features/project/template/PyQt-Template.py deleted file mode 100644 index e920801d..00000000 --- a/pyminer/features/project/template/PyQt-Template.py +++ /dev/null @@ -1,16 +0,0 @@ -# --coding:utf-8-- -import sys -from PySide2.QtWidgets import QApplication, QDialog - - -class CallPyQtTemplate(object): - def __init__(self): - super(CallPyQtTemplate, self).__init__() - self.setupUi(self) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - form = CallPyQtTemplate() - form.show() - sys.exit(app.exec()) diff --git a/pyminer/features/project/template/PySide2Template/PySide2_Template.py b/pyminer/features/project/template/PySide2Template/PySide2_Template.py deleted file mode 100644 index 7b9215ba..00000000 --- a/pyminer/features/project/template/PySide2Template/PySide2_Template.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'PySide2_Template.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - - -class Ui_PySide2Template(object): - def setupUi(self, PySide2Template): - if not PySide2Template.objectName(): - PySide2Template.setObjectName(u"PySide2Template") - PySide2Template.resize(402, 307) - icon = QIcon() - icon.addFile(u"../../ui/source/icons/logo.ico", QSize(), QIcon.Normal, QIcon.Off) - PySide2Template.setWindowIcon(icon) - self.verticalLayoutWidget = QWidget(PySide2Template) - self.verticalLayoutWidget.setObjectName(u"verticalLayoutWidget") - self.verticalLayoutWidget.setGeometry(QRect(9, 19, 381, 281)) - self.verticalLayout = QVBoxLayout(self.verticalLayoutWidget) - self.verticalLayout.setObjectName(u"verticalLayout") - self.verticalLayout.setContentsMargins(0, 0, 0, 0) - self.textBrowser = QTextBrowser(self.verticalLayoutWidget) - self.textBrowser.setObjectName(u"textBrowser") - - self.verticalLayout.addWidget(self.textBrowser) - - - self.retranslateUi(PySide2Template) - - QMetaObject.connectSlotsByName(PySide2Template) - # setupUi - - def retranslateUi(self, PySide2Template): - PySide2Template.setWindowTitle(QCoreApplication.translate("PySide2Template", u"PySide2Template", None)) - self.textBrowser.setHtml(QCoreApplication.translate("PySide2Template", u"\n" -"\n" -"

This is a PySide2 Template.

", None)) - # retranslateUi - diff --git a/pyminer/features/project/template/PySide2Template/PySide2_Template.ui b/pyminer/features/project/template/PySide2Template/PySide2_Template.ui deleted file mode 100644 index 40ee0698..00000000 --- a/pyminer/features/project/template/PySide2Template/PySide2_Template.ui +++ /dev/null @@ -1,46 +0,0 @@ - - - PySide2Template - - - - 0 - 0 - 402 - 307 - - - - PySide2Template - - - - ../../ui/source/icons/logo.ico../../ui/source/icons/logo.ico - - - - - 9 - 19 - 381 - 281 - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:14pt; font-weight:600; color:#ff0000;">This is a PySide2 Template.</span></p></body></html> - - - - - - - - - diff --git a/pyminer/features/project/template/PySide2Template/__init__.py b/pyminer/features/project/template/PySide2Template/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/project/template/PySide2Template/main.py b/pyminer/features/project/template/PySide2Template/main.py deleted file mode 100644 index 6c1c6520..00000000 --- a/pyminer/features/project/template/PySide2Template/main.py +++ /dev/null @@ -1,26 +0,0 @@ -# --coding:utf-8-- -""" -Please make sure the content of the file is complete. -If you customize the template, please make sure it can be executed correctly -by the interpreter after modification. -Do not delete the file and the directory where the file is located. -请确保文件内容完整。 -若自定义模板,请在修改后确保能够被解释器正确执行。 -【请勿删除】该文件以及文件所在目录。 -""" -import sys -from PySide2.QtWidgets import QApplication, QDialog -from PySide2_Template import Ui_PySide2Template - - -class CallPySideTemplate(QDialog, Ui_PySide2Template): - def __init__(self): - super(CallPySideTemplate, self).__init__() - self.setupUi(self) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - form = CallPySideTemplate() - form.show() - sys.exit(app.exec_()) diff --git a/pyminer/features/project/template/__init__.py b/pyminer/features/project/template/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/settings.py b/pyminer/features/settings.py deleted file mode 100644 index edacc0de..00000000 --- a/pyminer/features/settings.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -import json - -class Setting: - """用于读写pyminer系统信息""" - - def __init__(self): - self.setting_path = os.path.join(os.path.dirname(__file__), 'settings.json') - assert os.path.exists(self.setting_path) - with open(self.setting_path,'r',encoding='utf-8') as f: - self.system_info=json.load(f) - - def get_system_info(self): - return self.system_info - - def get_system_version(self): - """获取系统版本""" - return self.system_info['core']['version'] - - def set_system_version(self,version:str): - """设置系统版本""" - self.system_info['core']['version']=version - - def save(self): - with open(self.setting_path, 'w',encoding='utf-8') as f: - json.dump(self.system_info, f,ensure_ascii=False,indent=4, separators=(',', ': ')) # 确保中文能正确显示,且不是只在一行 - - -if __name__ == '__main__': - setting=Setting() - print(setting.get_system_version()) - setting.set_system_version('1.0.3') - setting.save() - - diff --git a/pyminer/features/ui/__init__.py b/pyminer/features/ui/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/ui/common/__init__.py b/pyminer/features/ui/common/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/ui/common/debug_process_with_pyqt.py b/pyminer/features/ui/common/debug_process_with_pyqt.py deleted file mode 100644 index a2e54a5c..00000000 --- a/pyminer/features/ui/common/debug_process_with_pyqt.py +++ /dev/null @@ -1,324 +0,0 @@ -""" -作者:侯展意 -有关QThread为什么行,为什么不行 -我也不知道啊... -""" -import os -import platform -import re -import time -import sys -import logging -from PySide2.QtCore import QThread, QObject, Signal, QTimer, Qt -from PySide2.QtGui import QCloseEvent -from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QTextBrowser, QCheckBox, QTextEdit -from typing import TYPE_CHECKING, List -from pmgwidgets import PMGJsonTree - -logger = logging.getLogger(__name__) -if TYPE_CHECKING: - from features.openprocess import PMProcess - from packages.code_editor.widgets.tab_widget import PMCodeEditTabWidget -else: - from features.openprocess import PMProcess - - -class DebugProcess(PMProcess): - """ - TODO:Ugly structure and it must be refactored soon!!!!!!!!! - """ - - def enqueue_stream(self, stream, queue, type): - self.enqueue_stream_err(stream, queue, type) - - -class ProcessMonitorThread(QObject): - on_err = Signal(str) - on_out = Signal(str) - signal_process_started = Signal() - on_finished = Signal() - - def __init__(self): - super().__init__() - self.process_terminated = False - self.args = None - self.process: 'DebugProcess' = None - - def stop(self): - self.process.terminate = True - self.process_terminated = True - - def run(self): - self.process = DebugProcess(self.args) - self.signal_process_started.emit() - self.q = self.process.q - idleLoops = 0 - while True: - if self.process_terminated == True: - return - if not self.q.empty(): - line = self.q.get() - if line[0] == '1': - self.on_out.emit(line[1:]) - else: - self.on_err.emit(line[1:]) - sys.stdout.flush() - else: - time.sleep(0.01) - if idleLoops >= 5: - idleLoops = 0 - if self.process.process.poll() is None: - pass - else: - self.on_finished.emit() - return - continue - idleLoops += 1 - - -class ProcessConsole(QTextEdit): - signal_stop_qthread = Signal() - signal_process_stopped = Signal() - signal_process_started = Signal() - signal_goto_file = Signal(str, int) - - def __init__(self, args: list = None): - super().__init__() - self._is_running = False - self.auto_scroll = True - self.args = args # - self.setContentsMargins(20, 20, 0, 0) - self.monitor_thread: 'ProcessMonitorThread' = None - self.out_thread: 'QThread' = None - - def is_running(self): - if self.monitor_thread is not None: - if self.monitor_thread.process.process.poll() is None: - return True - return False - - def start_process(self): - if not self.is_running(): - self.out_thread = QThread(self) - self.monitor_thread = ProcessMonitorThread() - self.monitor_thread.args = self.args - self.monitor_thread.moveToThread(self.out_thread) - - self.out_thread.started.connect(self.monitor_thread.run) - self.out_thread.start() - - self.monitor_thread.on_out.connect(self.on_stdout) - self.monitor_thread.on_err.connect(self.on_stderr) - - self.signal_stop_qthread.connect(self.monitor_thread.stop) - - self.out_thread.finished.connect(self.out_thread.deleteLater) - self.out_thread.finished.connect(self.monitor_thread.deleteLater) - - self.monitor_thread.on_finished.connect(self.terminate_process) - self.monitor_thread.signal_process_started.connect(lambda: self.signal_process_started.emit()) - - def on_stdout(self, text): - cmd = text.strip() - file_paths = re.findall(r'>(.+?)\(', cmd) - if len(file_paths) > 0: - path = file_paths[0].strip() - splitted = cmd.split(path) - if len(splitted) == 2: - if os.path.exists(path): - remaining_words = splitted[1].strip() - current_row = re.findall(r'\((.+?)\)', remaining_words) - if len(current_row) >= 1: - # self.insertHtml('

' + path + ';' + current_row[0] + '

') - print(file_paths[0], current_row, remaining_words) - self.signal_goto_file.emit(path, int(current_row[0])) - self.insertHtml('

' + text + '

') - if self.auto_scroll: - self.ensureCursorVisible() - - def on_stderr(self, text): - self.insertHtml('

' + text + '

') - if self.auto_scroll: - self.ensureCursorVisible() - - def terminate_process(self): - if self.monitor_thread is not None: - self.monitor_thread.process_terminated = True - self.monitor_thread.process.process.terminate() - if self.out_thread.isRunning(): - self.signal_stop_qthread.emit() - self.out_thread.quit() - self.out_thread.wait(500) - self.monitor_thread = None - self.out_thread = None - self.signal_process_stopped.emit() - - def keyPressEvent(self, e: 'QKeyEvent'): - if e.key() == Qt.Key_Backspace or e.key() == Qt.Key_Delete: - return - print(e.key(), e.text()) - if e.key() == Qt.Key_Return: - text = '\n' - else: - text = e.text() - print(text,e.text()) - if text != '' and self.monitor_thread is not None: - try: - print('sent:', text) - self.monitor_thread.process.process.stdin.write(text.encode('utf8')) - self.monitor_thread.process.process.stdin.flush() - except: - import traceback - traceback.print_exc() - super(ProcessConsole, self).keyPressEvent(e) - - -class PMGDebugConsoleWidget(QWidget): - def __init__(self, args: list = None, editor_tab_widget: 'PMCodeEditTabWidget' = None): - super().__init__() - self.extension_lib = None - - self.editor_tab_widget: 'PMCodeEditTabWidget' = editor_tab_widget - self.hbox_layout = QHBoxLayout() - self.tool_widget = QWidget() - self.input_queue: List[str] = [] - self.tool_widget.setLayout(QVBoxLayout()) - self.process_console = ProcessConsole(args=args) - self.process_console.signal_process_stopped.connect(self.on_terminated) - - self.button_to_start = QPushButton('start') - self.tool_widget.layout().addWidget(self.button_to_start) - self.button_to_start.clicked.connect(self.start_process) - - self.button_to_terminate = QPushButton('termi') - self.tool_widget.layout().addWidget(self.button_to_terminate) - self.button_to_terminate.clicked.connect(self.terminate_process) - - self.button_to_clear = QPushButton('step') - self.tool_widget.layout().addWidget(self.button_to_clear) - self.button_to_clear.clicked.connect(lambda: self.input('s')) - - self.button_to_clear = QPushButton('continue') - self.tool_widget.layout().addWidget(self.button_to_clear) - self.button_to_clear.clicked.connect(lambda: self.input('tobreak')) - - self.button_to_clear = QPushButton('clear') - self.tool_widget.layout().addWidget(self.button_to_clear) - self.button_to_clear.clicked.connect(lambda: self.process_console.clear()) - - self.autoscroll_checker = QCheckBox() - self.autoscroll_checker.setToolTip('autoscroll') - self.tool_widget.layout().addWidget(self.autoscroll_checker) - self.autoscroll_checker.stateChanged.connect(self.set_autoscroll) - self.autoscroll_checker.setChecked(True) - self.set_autoscroll() - - self.hbox_layout.addWidget(self.tool_widget) - - self.hbox_layout.addWidget(self.process_console) - self.var_viewer = PMGJsonTree() - self.hbox_layout.addWidget(self.var_viewer) - self.setLayout(self.hbox_layout) - self.process_console.signal_process_started.connect(self.clear_input_queue) - - def set_extension_lib(self, extension_lib): - self.extension_lib = extension_lib - self.extension_lib.Data.add_data_changed_callback(self.on_data_changed) - - def on_data_changed(self, data_name: str, var: object, provider: str): - if data_name == 'debug_vars': - self.var_viewer.set_data_dic(var) - - def input(self, message): - """ - 输入命令。 - 若在windows的终端运行则需要用gbk编码;若在pycharm中运行,则无需gbk编码。 - 因此注意,下面多了个判断过程! - :param message: - :return: - """ - line_ending = '\n' - # if platform.system().lower() == 'windows': - # line_ending = '\r\n' - if not message.endswith(line_ending): - message += line_ending - th = self.process_console.monitor_thread - if th is not None: - if th.process is not None: - process = th.process.process - encoded = b'' - if platform.system().lower() == 'windows' and sys.stdout.isatty(): # 如果在windows的终端运行 - encoded = message.encode('gbk') - else: - encoded = message.encode('utf-8') - process.stdin.write(encoded) # 模拟输入 - process.stdin.flush() - return - - self.input_queue.append(message) - - def clear_input_queue(self): - """ - 进程启动之后,调用这个队列处理器,逐条运行未能运行的命令。 - :return: - """ - for m in self.input_queue: - self.input(m) - - def set_autoscroll(self): - print(self.autoscroll_checker.isChecked()) - self.process_console.auto_scroll = self.autoscroll_checker.isChecked() - - def on_terminated(self): - self.button_to_start.setEnabled(True) - self.button_to_terminate.setEnabled(False) - - def on_started(self): - self.button_to_start.setEnabled(False) - self.button_to_terminate.setEnabled(True) - - def start_process(self): - bp_input = self.editor_tab_widget.get_all_breakpoints('python') - bp_input = bp_input.strip() - self.input(bp_input) - self.process_console.start_process() - self.on_started() - s = r""" -!import sys;sys.path.append(r'%s') -alias pi !import pmtoolbox,os;pmtoolbox.debug.pmdebug.insight(locals()); -alias tobreak c;;pi -alias ps pi self -""" % r'E:\Python\pyminer_bin\PyMiner\bin' - self.input(s) - - def terminate_process(self): - for index in range(self.editor_tab_widget.count()): - self.editor_tab_widget.widget(index).remove_debug_indicator() - self.process_console.terminate_process() - self.on_terminated() - - def is_process_running(self) -> bool: - return self.process_console.is_running() - - def close(self) -> bool: - self.terminate_process() - self.extension_lib.Data.remove_data_changed_callback(self.on_data_changed) - return super().close() - - def closeEvent(self, a0: QCloseEvent) -> None: - self.terminate_process() - super(PMGDebugConsoleWidget, self).closeEvent(a0) - -# if __name__ == '__main__': -# import cgitb -# -# cgitb.enable(format='text') -# from PyQt5.QtWidgets import QApplication -# -# app = QApplication(sys.argv) -# -# w = PMGDebugConsoleWidget(['python', '-u', '-m', 'pdb', -# r'E:\Python\pyminer_bin\PyMiner\bin\pmtoolbox\debug\test.py']) -# w.show() -# w.start_process() -# sys.exit(app.exec_()) diff --git a/pyminer/features/ui/common/open_process_with_pyqt.py b/pyminer/features/ui/common/open_process_with_pyqt.py deleted file mode 100644 index 31f53982..00000000 --- a/pyminer/features/ui/common/open_process_with_pyqt.py +++ /dev/null @@ -1,249 +0,0 @@ -""" -作者:侯展意 -有关QThread为什么行,为什么不行 -我也不知道啊... -""" -import time -import sys -import logging - -from PySide2.QtCore import QThread, QObject, Signal, Qt -from PySide2.QtGui import QCloseEvent, QKeyEvent -from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QTextBrowser, QCheckBox, QTextEdit -from typing import TYPE_CHECKING - -logger = logging.getLogger(__name__) -if TYPE_CHECKING: - from features.openprocess import PMProcess -else: - from features.openprocess import PMProcess - - -class ProcessMonitorThread(QObject): - on_err = Signal(str) - on_out = Signal(str) - on_finished = Signal() - - def __init__(self): - super().__init__() - self.process_terminated = False - self.args = None - - def stop(self): - self.process.terminate = True - self.process_terminated = True - - def run(self): - self.process = PMProcess(self.args) - self.q = self.process.q - idleLoops = 0 - while True: - if self.process_terminated == True: - return - if not self.q.empty(): - line = self.q.get() - if line[0] == '1': - self.on_out.emit(line[1:]) - else: - self.on_err.emit(line[1:]) - sys.stdout.flush() - else: - time.sleep(0.01) - if idleLoops >= 5: - idleLoops = 0 - if self.process.process.poll() is None: - pass - # try: - # self.process.process.stdin.write( - # 'messsage\n'.encode('ascii')) # 模拟输入 - # self.process.process.stdin.flush() - # except OSError: - # logger.info('Process with args \'%s\' terminates(or is terminated).' % repr(self.args)) - # self.on_finished.emit() - # return - # except: - # import traceback - # traceback.print_exc() - # self.on_finished.emit() - # return - else: - self.on_finished.emit() - return - continue - idleLoops += 1 - - -class ProcessConsole(QTextEdit): - signal_stop_qthread = Signal() - signal_process_stopped = Signal() - signal_process_started = Signal() - - insert_mode = '' - - def __init__(self, args: list = None): - super().__init__() - self._is_running = False - self.auto_scroll = True - self.args = args # - self.setContentsMargins(20, 20, 0, 0) - self.monitor_thread: 'ProcessMonitorThread' = None - self.out_thread: 'QThread' = None - - def is_running(self): - if self.monitor_thread is not None: - if self.monitor_thread.process.process.poll() is None: - return True - return False - - def start_process(self): - if not self.is_running(): - self.out_thread = QThread(self) - self.monitor_thread = ProcessMonitorThread() - self.monitor_thread.args = self.args - self.monitor_thread.moveToThread(self.out_thread) - - self.out_thread.started.connect(self.monitor_thread.run) - self.out_thread.start() - - self.monitor_thread.on_out.connect(self.on_stdout) - self.monitor_thread.on_err.connect(self.on_stderr) - - self.signal_stop_qthread.connect(self.monitor_thread.stop) - - self.out_thread.finished.connect(self.out_thread.deleteLater) - self.out_thread.finished.connect(self.monitor_thread.deleteLater) - - self.monitor_thread.on_finished.connect(self.terminate_process) - - def on_stdout(self, text): - if self.insert_mode == 'error': - self.insertHtml('

' + '========' + '

') - self.insert_mode = 'stdout' - - self.insertPlainText(text) - if self.auto_scroll: - self.ensureCursorVisible() - - def on_stderr(self, text): - self.insert_mode = 'error' - self.insertHtml('

' + text + '

') - print(text) - if self.auto_scroll: - self.ensureCursorVisible() - - def terminate_process(self): - if self.monitor_thread is not None: - self.monitor_thread.process_terminated = True - self.monitor_thread.process.process.terminate() - if self.out_thread.isRunning(): - self.signal_stop_qthread.emit() - self.out_thread.quit() - self.out_thread.wait(500) - self.monitor_thread = None - self.out_thread = None - self.signal_process_stopped.emit() - - def keyPressEvent(self, e: 'QKeyEvent'): - if e.key() == Qt.Key_Backspace or e.key() == Qt.Key_Delete: - return - print(e.key(), e.text()) - if e.key() == Qt.Key_Return: - text = '\n' - else: - text = e.text() - if text != '' and self.monitor_thread is not None: - try: - print('sent:', text) - self.monitor_thread.process.process.stdin.write(text.encode('utf8')) - self.monitor_thread.process.process.stdin.flush() - except: - import traceback - traceback.print_exc() - super(ProcessConsole, self).keyPressEvent(e) - - -class PMGProcessConsoleWidget(QWidget): - def __init__(self, args: list = None): - super().__init__() - self.hbox_layout = QHBoxLayout() - self.tool_widget = QWidget() - self.tool_widget.setLayout(QVBoxLayout()) - self.process_console = ProcessConsole(args=args) - self.process_console.signal_process_stopped.connect(self.on_terminated) - - self.button_to_start = QPushButton('start') - self.tool_widget.layout().addWidget(self.button_to_start) - self.button_to_start.clicked.connect(self.start_process) - - self.button_to_terminate = QPushButton('termi') - self.tool_widget.layout().addWidget(self.button_to_terminate) - self.button_to_terminate.clicked.connect(self.terminate_process) - - self.button_to_clear = QPushButton('clear') - self.tool_widget.layout().addWidget(self.button_to_clear) - self.button_to_clear.clicked.connect(lambda: self.process_console.clear()) - - self.autoscroll_checker = QCheckBox() - self.autoscroll_checker.setToolTip('autoscroll') - - self.tool_widget.layout().addWidget(self.autoscroll_checker) - self.autoscroll_checker.stateChanged.connect(self.set_autoscroll) - self.autoscroll_checker.setChecked(True) - self.set_autoscroll() - - self.hbox_layout.addWidget(self.tool_widget) - vbox = QVBoxLayout() - self.hbox_layout.addLayout(vbox) - vbox.addWidget(self.process_console) - # self.command_input = QLineEdit() - # vbox.addWidget() - self.setLayout(self.hbox_layout) - - def set_autoscroll(self): - print(self.autoscroll_checker.isChecked()) - self.process_console.auto_scroll = self.autoscroll_checker.isChecked() - - def on_terminated(self): - self.button_to_start.setEnabled(True) - self.button_to_terminate.setEnabled(False) - - def on_started(self): - self.button_to_start.setEnabled(False) - self.button_to_terminate.setEnabled(True) - - def start_process(self): - self.process_console.start_process() - self.on_started() - - def terminate_process(self): - self.process_console.terminate_process() - self.on_terminated() - - def is_process_running(self) -> bool: - return self.process_console.is_running() - - def closeEvent(self, a0: QCloseEvent) -> None: - self.terminate_process() - # if self.process_console.out_thread.isRunning(): - # self.process_console.monitor_thread.stop() - # self.process_console.out_thread.quit() - # self.process_console.out_thread.wait(500) - - # self.process_console.monitor_thread.stop() - # self.process_console.monitor_thread.deleteLater() - # self.process_console.out_thread.deleteLater() - super(PMGProcessConsoleWidget, self).closeEvent(a0) - - -if __name__ == '__main__': - import cgitb - import sys - - cgitb.enable(format='text') - from PySide2.QtWidgets import QApplication, QTextEdit - - app = QApplication(sys.argv) - w = PMGProcessConsoleWidget([sys.executable, '-u', 'test_open_app.py']) - w.show() - - sys.exit(app.exec_()) diff --git a/pyminer/features/ui/common/openprocess.py b/pyminer/features/ui/common/openprocess.py deleted file mode 100644 index 00872fda..00000000 --- a/pyminer/features/ui/common/openprocess.py +++ /dev/null @@ -1,109 +0,0 @@ -import queue -import re -import subprocess -import sys -import threading -import time -import chardet -from typing import List - -import packages.code_editor.utils.utils - - -class PMProcess(): - def __init__(self, args: List[str]): - self.terminate = False - self.q = queue.Queue() - self.on_error_received = lambda error: print(error) - self.args = args - self.process = subprocess.Popen(self.args, - stdin=subprocess.PIPE, - shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - self.to = threading.Thread( - target=self.enqueue_stream, args=( - self.process.stdout, self.q, 1)) - self.te = threading.Thread( - target=self.enqueue_stream, args=( - self.process.stderr, self.q, 2)) - self.tp = threading.Thread(target=self.consoleLoop) - self.to.setDaemon(True) - self.te.setDaemon(True) - self.tp.setDaemon(True) - self.te.start() - self.to.start() - self.tp.start() - - def enqueue_stream(self, stream, queue, type): # 将stderr或者stdout写入到队列q中。 - for line in iter(stream.readline, b''): - if self.terminate: break - encoding = chardet.detect(line)['encoding'] - queue.put(str(type) + packages.code_editor.utils.utils.decode(encoding)) - stream.close() - - def consoleLoop(self): # 封装后的内容。 - # idleLoops = 0 - while True: - if not self.q.empty(): - line = self.q.get() - if line[0] == '1': - self.on_command_received(line[1:]) - else: - self.on_error_received(line[1:]) - sys.stdout.flush() - else: - time.sleep(0.01) - # idleLoops += 1 - - def input(self, message: str): - if not message.endswith('\n'): - message += '\n' - self.process.stdin.write( - message.encode('utf-8')) # 模拟输入 - self.process.stdin.flush() - - def on_command_received(self, cmd: str): - # print(cmd) - cmd = cmd.strip() - file_paths = re.findall(r'>(.+?)\(', cmd) - if len(file_paths) > 0: - path = file_paths[0].strip() - splitted = cmd.split(path) - if len(splitted) == 2: - remaining_words = splitted[1].strip() - current_row = re.findall(r'\((.+?)\)', remaining_words) - if len(current_row) >= 1: - print(path, int(current_row[0])) - # if remaining_words.startswith('<'): - - # print('file:', file_result.group()) - # while(1): - # if cmd.startswith('(Pdb)'): - # cmd = cmd.strip() - # cmd = cmd.strip('(Pdb)') - # else: - # cmd = cmd.strip() - # # if cmd.startswith('>'): - # - # break - print(cmd) - - -if __name__ == '__main__': - s = r""" -import os -import pmdebug -__global_keys = set(globals().keys()) - -b E:\Python\pyminer_bin\PyMiner\bin\pmtoolbox\debug\test2.py:2 -alias pi for k in locals().keys(): pmdebug.insight(k,locals()[k]);print(12333333333333,os.path.dirname(r'c:\123123')) -alias tobreak c;;pi a -alias ps pi self - -""" - pmp = PMProcess(['python', '-u', '-m', 'pdb', - r'E:\Python\pyminer_bin\PyMiner\bin\pmtoolbox\debug\test.py']) - pmp.input(s) - while (1): - pmp.input('c') - time.sleep(2) - pass diff --git a/pyminer/features/ui/common/platformutil.py b/pyminer/features/ui/common/platformutil.py deleted file mode 100644 index 3c367868..00000000 --- a/pyminer/features/ui/common/platformutil.py +++ /dev/null @@ -1,37 +0,0 @@ -import platform -import subprocess -import logging -logger = logging.getLogger(__name__) - -def check_platform() -> str: - system = platform.system() - return system.lower() - - -def run_command_in_terminal(cmd: str, close_mode: str = 'wait_key'): - logging.warning('this platform is :',check_platform()) - platform_name = check_platform() - if platform_name == 'windows': - close_action = {'auto': 'start cmd.exe /k \"%s &&exit \"', - 'no': 'start cmd.exe /k \"%s \"', - 'wait_key': 'start cmd.exe /k \"%s &&pause &&exit \"' - } - command = close_action[close_mode] % cmd - - elif platform_name == 'deepin': - command = 'deepin-terminal -x bash -c \" %s \" ' % (cmd) - elif platform_name == 'linux': - command = 'gnome-terminal -x bash -c \"%s ;read\" ' % (cmd) - else: - return - subprocess.Popen(command, shell=True) - - -if __name__ == '__main__': - def test_run_in_terminal(): - import time - run_command_in_terminal('dir', close_mode='no') - time.sleep(1) - run_command_in_terminal('dir', close_mode='wait_key') - time.sleep(1) - run_command_in_terminal('dir', close_mode='auto') diff --git a/pyminer/features/ui/common/pmlocale.py b/pyminer/features/ui/common/pmlocale.py deleted file mode 100644 index 7a4876dd..00000000 --- a/pyminer/features/ui/common/pmlocale.py +++ /dev/null @@ -1,47 +0,0 @@ -from typing import Dict - - -class Locale(): - locale: str = 'zh_CN' - valid_locales: set = {'zh_CN', 'en'} - translations: Dict[str, Dict] = {} - - def __init__(self): - pass - - def add_locale(self, locale_name: str, translations: Dict[str, str]): - if locale_name not in self.valid_locales: - raise Exception('invalid locale selection:%s' % locale_name) - locale_dic = self.translations.get(locale_name) - if locale_dic is None: - self.translations[locale_name] = translations - else: - for k in translations: - if locale_dic.get(k) is None: - locale_dic[k]=translations[k] - - def translate(self, text: str) -> str: - if self.locale=='en': - return text - locale = self.translations.get(self.locale) - if locale is not None: - translation = locale.get(text) - if translation is not None: - return translation - return text - - def _(self, text: str) -> str: - return self.translate(text) - - -pmlocale = Locale() -pmlocale.locale = 'zh_CN' -if __name__ == '__main__': - l = pmlocale - l.locale = 'zh_CN' - l.add_locale('en', {'interpreter': 'interpreter'}) - l.add_locale('en', {'console': 'console'}) - l.add_locale('zh_CN', {'console': '控制台'}) - l.add_locale('zh_CN', {'interpreter': '解释器'}) - s = l.translate('interpreter') - # print(s) diff --git a/pyminer/features/ui/common/test_open_app.py b/pyminer/features/ui/common/test_open_app.py deleted file mode 100644 index add93302..00000000 --- a/pyminer/features/ui/common/test_open_app.py +++ /dev/null @@ -1,12 +0,0 @@ -if __name__ == '__main__': - print('hello world!!') - while (1): - try: - s = input('>>>') - print('you input', s) - assert s != '123' - except: - import traceback - - traceback.print_exc() - pass diff --git a/pyminer/features/ui/main.py b/pyminer/features/ui/main.py deleted file mode 100644 index 6c7b700b..00000000 --- a/pyminer/features/ui/main.py +++ /dev/null @@ -1,88 +0,0 @@ -from PySide2.QtCore import Qt -from PySide2.QtGui import QFont -from PySide2.QtWidgets import QApplication, QDialog, QTableWidget, QHeaderView, QAbstractItemView, QFrame, \ - QTableWidgetItem - - -from ui_data_normal import Ui_Dialog -import sys -import numpy as np -import logging -from decimal import Decimal - - -class MyWindow(QDialog, Ui_Dialog): - def __init__(self): - super(MyWindow, self).__init__() - self.setupUi(self) - - # 初始化一组正态分布数据 - self.build_normal() - - self.buttonBox.accepted.connect(self.build_normal) - self.buttonBox.rejected.connect(self.close) - - def custom_menu(self): - ''' - 定制鼠标右键菜单 - :return: - ''' - - def keyPressEvent(self, event): - """ Ctrl + C复制表格内容 """ - if event.modifiers() == Qt.ControlModifier and event.key() == Qt.Key_C: - # 获取表格的选中行 - selected_ranges = self.tableWidget.selectedRanges()[0] # 只取第一个数据块,其他的如果需要要做遍历,简单功能就不写得那么复杂了 - text_str = "" # 最后总的内容 - # 行(选中的行信息读取) - for row in range(selected_ranges.topRow(), selected_ranges.bottomRow() + 1): - row_str = "" - # 列(选中的列信息读取) - for col in range(selected_ranges.leftColumn(), selected_ranges.rightColumn() + 1): - item = self.tableWidget.item(row, col) - row_str += item.text() + '\t' # 制表符间隔数据 - text_str += row_str + '\n' # 换行 - clipboard = QApplication.clipboard() # 获取剪贴板 - clipboard.setText(text_str) # 内容写入剪贴板 - - def build_normal(self): - self.v_precision = self.spinBox_precison.value() - self.v_mean = self.doubleSpinBox_mean.value() - self.v_std = self.doubleSpinBox_std.value() - self.v_count = self.spinBox_count.value() - - np.set_printoptions(precision=self.v_precision) - self.data = np.random.normal(loc=self.v_mean, scale=self.v_std, size=self.v_count) - print(self.data) - print(type(self.data)) - # logging.info(data) - - self.show_table() - - def show_table(self): - - self.tableWidget.setSortingEnabled(True) # 设置表头可以自动排序 - self.tableWidget.setColumnCount(1) - self.tableWidget.setRowCount(len(self.data)) - self.tableWidget.setHorizontalHeaderLabels(['正态分布数据']) - - for i in range(len(self.data)): - - # 调用Decimal 设置数据精度格式 - if self.v_precision == 0: - decimal_format = '0' - else: - decimal_format = '0.' + '0' * self.v_precision - - random_value = Decimal(self.data[i]).quantize(Decimal(decimal_format)) # 调用Decimal 设置数据精度 - - item = QTableWidgetItem(str(random_value)) - item.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter) - self.tableWidget.setItem(i, 0, item) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - form1 = MyWindow() - form1.show() - sys.exit(app.exec_()) diff --git a/pyminer/features/ui/pm_marketplace/__init__.py b/pyminer/features/ui/pm_marketplace/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/ui/pm_marketplace/install.py b/pyminer/features/ui/pm_marketplace/install.py deleted file mode 100644 index 4a60b24a..00000000 --- a/pyminer/features/ui/pm_marketplace/install.py +++ /dev/null @@ -1,212 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'install.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - -from pmgwidgets import PMGProcessConsoleWidget - - -class Ui_Form(object): - def setupUi(self, Form): - if not Form.objectName(): - Form.setObjectName(u"Form") - Form.resize(800, 600) - self.verticalLayout = QVBoxLayout(Form) - self.verticalLayout.setObjectName(u"verticalLayout") - self.horizontalLayout_4 = QHBoxLayout() - self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") - self.formLayout = QFormLayout() - self.formLayout.setObjectName(u"formLayout") - self.label_2 = QLabel(Form) - self.label_2.setObjectName(u"label_2") - - self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label_2) - - self.horizontalLayout_7 = QHBoxLayout() - self.horizontalLayout_7.setObjectName(u"horizontalLayout_7") - self.lineEdit_name = QLineEdit(Form) - self.lineEdit_name.setObjectName(u"lineEdit_name") - - self.horizontalLayout_7.addWidget(self.lineEdit_name) - - self.checkBox_version = QCheckBox(Form) - self.checkBox_version.setObjectName(u"checkBox_version") - - self.horizontalLayout_7.addWidget(self.checkBox_version) - - self.lineEdit_version = QLineEdit(Form) - self.lineEdit_version.setObjectName(u"lineEdit_version") - - self.horizontalLayout_7.addWidget(self.lineEdit_version) - - - self.formLayout.setLayout(0, QFormLayout.FieldRole, self.horizontalLayout_7) - - self.label = QLabel(Form) - self.label.setObjectName(u"label") - - self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label) - - self.horizontalLayout_3 = QHBoxLayout() - self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.comboBox_source = QComboBox(Form) - self.comboBox_source.addItem("") - self.comboBox_source.addItem("") - self.comboBox_source.addItem("") - self.comboBox_source.addItem("") - self.comboBox_source.addItem("") - self.comboBox_source.addItem("") - self.comboBox_source.setObjectName(u"comboBox_source") - self.comboBox_source.setEnabled(True) - self.comboBox_source.setMinimumSize(QSize(100, 0)) - self.comboBox_source.setMaximumSize(QSize(100, 16777215)) - - self.horizontalLayout_3.addWidget(self.comboBox_source) - - self.lineEdit_source = QLineEdit(Form) - self.lineEdit_source.setObjectName(u"lineEdit_source") - self.lineEdit_source.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignVCenter) - self.lineEdit_source.setReadOnly(True) - - self.horizontalLayout_3.addWidget(self.lineEdit_source) - - - self.formLayout.setLayout(1, QFormLayout.FieldRole, self.horizontalLayout_3) - - self.label_3 = QLabel(Form) - self.label_3.setObjectName(u"label_3") - - self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_3) - - self.horizontalLayout = QHBoxLayout() - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.comboBox_dir = QComboBox(Form) - self.comboBox_dir.addItem("") - self.comboBox_dir.addItem("") - self.comboBox_dir.addItem("") - self.comboBox_dir.addItem("") - self.comboBox_dir.setObjectName(u"comboBox_dir") - self.comboBox_dir.setMinimumSize(QSize(100, 0)) - self.comboBox_dir.setMaximumSize(QSize(100, 16777215)) - - self.horizontalLayout.addWidget(self.comboBox_dir) - - self.lineEdit_dir = QLineEdit(Form) - self.lineEdit_dir.setObjectName(u"lineEdit_dir") - self.lineEdit_dir.setReadOnly(True) - - self.horizontalLayout.addWidget(self.lineEdit_dir) - - self.toolButton = QToolButton(Form) - self.toolButton.setObjectName(u"toolButton") - - self.horizontalLayout.addWidget(self.toolButton) - - - self.formLayout.setLayout(2, QFormLayout.FieldRole, self.horizontalLayout) - - - self.horizontalLayout_4.addLayout(self.formLayout) - - - self.verticalLayout.addLayout(self.horizontalLayout_4) - - self.groupBox = QGroupBox(Form) - self.groupBox.setObjectName(u"groupBox") - self.horizontalLayout_5 = QHBoxLayout(self.groupBox) - self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") - self.horizontalLayout_5.setContentsMargins(0, 0, 0, 0) - self.textEdit_desc = QTextEdit(self.groupBox) - self.textEdit_desc.setObjectName(u"textEdit_desc") - - self.horizontalLayout_5.addWidget(self.textEdit_desc) - - - self.verticalLayout.addWidget(self.groupBox) - - self.groupBox_2 = QGroupBox(Form) - self.groupBox_2.setObjectName(u"groupBox_2") - self.horizontalLayout_6 = QHBoxLayout(self.groupBox_2) - self.horizontalLayout_6.setObjectName(u"horizontalLayout_6") - self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0) - self.exec_log = PMGProcessConsoleWidget(self.groupBox_2) - self.exec_log.setObjectName(u"exec_log") - self.exec_log.setMinimumSize(QSize(0, 200)) - - self.horizontalLayout_6.addWidget(self.exec_log) - - - self.verticalLayout.addWidget(self.groupBox_2) - - self.widget = QWidget(Form) - self.widget.setObjectName(u"widget") - self.widget.setMaximumSize(QSize(16777215, 50)) - self.verticalLayout_2 = QVBoxLayout(self.widget) - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.horizontalLayout_2 = QHBoxLayout() - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_2.addItem(self.horizontalSpacer) - - self.pushButton_install = QPushButton(self.widget) - self.pushButton_install.setObjectName(u"pushButton_install") - - self.horizontalLayout_2.addWidget(self.pushButton_install) - - self.pushButton_close = QPushButton(self.widget) - self.pushButton_close.setObjectName(u"pushButton_close") - - self.horizontalLayout_2.addWidget(self.pushButton_close) - - - self.verticalLayout_2.addLayout(self.horizontalLayout_2) - - - self.verticalLayout.addWidget(self.widget) - - - self.retranslateUi(Form) - - QMetaObject.connectSlotsByName(Form) - # setupUi - - def retranslateUi(self, Form): - Form.setWindowTitle(QCoreApplication.translate("Form", u"Install", None)) - self.label_2.setText(QCoreApplication.translate("Form", u"Package:", None)) - self.lineEdit_name.setText("") - self.checkBox_version.setText(QCoreApplication.translate("Form", u"\u6307\u5b9a\u7248\u672c", None)) - self.lineEdit_version.setText(QCoreApplication.translate("Form", u"", None)) - self.label.setText(QCoreApplication.translate("Form", u"Source:", None)) - self.comboBox_source.setItemText(0, QCoreApplication.translate("Form", u"Tencent", None)) - self.comboBox_source.setItemText(1, QCoreApplication.translate("Form", u"Official", None)) - self.comboBox_source.setItemText(2, QCoreApplication.translate("Form", u"Tsinghua", None)) - self.comboBox_source.setItemText(3, QCoreApplication.translate("Form", u"AliYun", None)) - self.comboBox_source.setItemText(4, QCoreApplication.translate("Form", u"DouBan", None)) - self.comboBox_source.setItemText(5, QCoreApplication.translate("Form", u"Customize..", None)) - - self.lineEdit_source.setText(QCoreApplication.translate("Form", u"https://mirrors.cloud.tencent.com/pypi/simple", None)) - self.lineEdit_source.setPlaceholderText(QCoreApplication.translate("Form", u"\u817e\u8baf\u955c\u50cf\u6e90", None)) - self.label_3.setText(QCoreApplication.translate("Form", u"Options:", None)) - self.comboBox_dir.setItemText(0, QCoreApplication.translate("Form", u"\u9ed8\u8ba4\u4f4d\u7f6e", None)) - self.comboBox_dir.setItemText(1, QCoreApplication.translate("Form", u"\u7528\u6237\u76ee\u5f55", None)) - self.comboBox_dir.setItemText(2, QCoreApplication.translate("Form", u"\u4ec5\u4e0b\u8f7d", None)) - self.comboBox_dir.setItemText(3, QCoreApplication.translate("Form", u"\u81ea\u5b9a\u4e49", None)) - - self.lineEdit_dir.setPlaceholderText(QCoreApplication.translate("Form", u"\u9ed8\u8ba4", None)) - self.toolButton.setText(QCoreApplication.translate("Form", u"...", None)) - self.groupBox.setTitle(QCoreApplication.translate("Form", u"\u8be6\u60c5", None)) - self.groupBox_2.setTitle(QCoreApplication.translate("Form", u"Log", None)) - self.pushButton_install.setText(QCoreApplication.translate("Form", u"Install", None)) - self.pushButton_close.setText(QCoreApplication.translate("Form", u"Close", None)) - # retranslateUi - diff --git a/pyminer/features/ui/pm_marketplace/install.ui b/pyminer/features/ui/pm_marketplace/install.ui deleted file mode 100644 index 43127d0f..00000000 --- a/pyminer/features/ui/pm_marketplace/install.ui +++ /dev/null @@ -1,307 +0,0 @@ - - - Form - - - - 0 - 0 - 800 - 600 - - - - Install - - - - - - - - - - Package: - - - - - - - - - - - - - - - - 指定版本 - - - - - - - <Latest> - - - - - - - - - Source: - - - - - - - - - true - - - - 100 - 0 - - - - - 100 - 16777215 - - - - - Tencent - - - - - Official - - - - - Tsinghua - - - - - AliYun - - - - - DouBan - - - - - Customize.. - - - - - - - - https://mirrors.cloud.tencent.com/pypi/simple - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - 腾讯镜像源 - - - - - - - - - Options: - - - - - - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - - 默认位置 - - - - - 用户目录 - - - - - 仅下载 - - - - - 自定义 - - - - - - - - true - - - 默认 - - - - - - - ... - - - - - - - - - - - - - 详情 - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - Log - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 200 - - - - - - - - - - - - 16777215 - 50 - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Install - - - - - - - Close - - - - - - - - - - - - - PMGProcessConsoleWidget - QWidget -
pmgwidgets
- 1 -
-
- - -
diff --git a/pyminer/features/ui/pm_marketplace/main.py b/pyminer/features/ui/pm_marketplace/main.py deleted file mode 100644 index 1602faab..00000000 --- a/pyminer/features/ui/pm_marketplace/main.py +++ /dev/null @@ -1,137 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'main.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - - -class Ui_Form(object): - def setupUi(self, Form): - if not Form.objectName(): - Form.setObjectName(u"Form") - Form.resize(978, 664) - self.verticalLayout = QVBoxLayout(Form) - self.verticalLayout.setObjectName(u"verticalLayout") - self.horizontalLayout = QHBoxLayout() - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.toolButton_install = QToolButton(Form) - self.toolButton_install.setObjectName(u"toolButton_install") - self.toolButton_install.setEnabled(True) - - self.horizontalLayout.addWidget(self.toolButton_install) - - self.toolButton_downloan = QToolButton(Form) - self.toolButton_downloan.setObjectName(u"toolButton_downloan") - self.toolButton_downloan.setEnabled(False) - - self.horizontalLayout.addWidget(self.toolButton_downloan) - - self.toolButton_detail = QToolButton(Form) - self.toolButton_detail.setObjectName(u"toolButton_detail") - self.toolButton_detail.setEnabled(False) - - self.horizontalLayout.addWidget(self.toolButton_detail) - - self.toolButton_update = QToolButton(Form) - self.toolButton_update.setObjectName(u"toolButton_update") - self.toolButton_update.setEnabled(False) - - self.horizontalLayout.addWidget(self.toolButton_update) - - self.toolButton_uninstall = QToolButton(Form) - self.toolButton_uninstall.setObjectName(u"toolButton_uninstall") - self.toolButton_uninstall.setEnabled(False) - - self.horizontalLayout.addWidget(self.toolButton_uninstall) - - self.toolButton_check_update = QToolButton(Form) - self.toolButton_check_update.setObjectName(u"toolButton_check_update") - self.toolButton_check_update.setEnabled(False) - - self.horizontalLayout.addWidget(self.toolButton_check_update) - - self.toolButton_install_requirements = QToolButton(Form) - self.toolButton_install_requirements.setObjectName(u"toolButton_install_requirements") - self.toolButton_install_requirements.setEnabled(False) - - self.horizontalLayout.addWidget(self.toolButton_install_requirements) - - self.toolButton_freeze_requirements = QToolButton(Form) - self.toolButton_freeze_requirements.setObjectName(u"toolButton_freeze_requirements") - self.toolButton_freeze_requirements.setEnabled(False) - - self.horizontalLayout.addWidget(self.toolButton_freeze_requirements) - - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout.addItem(self.horizontalSpacer) - - self.lineEdit = QLineEdit(Form) - self.lineEdit.setObjectName(u"lineEdit") - self.lineEdit.setEnabled(False) - - self.horizontalLayout.addWidget(self.lineEdit) - - - self.verticalLayout.addLayout(self.horizontalLayout) - - self.tableWidget = QTableWidget(Form) - if (self.tableWidget.columnCount() < 6): - self.tableWidget.setColumnCount(6) - __qtablewidgetitem = QTableWidgetItem() - self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem) - __qtablewidgetitem1 = QTableWidgetItem() - self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1) - __qtablewidgetitem2 = QTableWidgetItem() - self.tableWidget.setHorizontalHeaderItem(2, __qtablewidgetitem2) - __qtablewidgetitem3 = QTableWidgetItem() - self.tableWidget.setHorizontalHeaderItem(3, __qtablewidgetitem3) - __qtablewidgetitem4 = QTableWidgetItem() - self.tableWidget.setHorizontalHeaderItem(4, __qtablewidgetitem4) - __qtablewidgetitem5 = QTableWidgetItem() - self.tableWidget.setHorizontalHeaderItem(5, __qtablewidgetitem5) - if (self.tableWidget.rowCount() < 9995): - self.tableWidget.setRowCount(9995) - self.tableWidget.setObjectName(u"tableWidget") - self.tableWidget.setRowCount(9995) - - self.verticalLayout.addWidget(self.tableWidget) - - - self.retranslateUi(Form) - - QMetaObject.connectSlotsByName(Form) - # setupUi - - def retranslateUi(self, Form): - Form.setWindowTitle(QCoreApplication.translate("Form", u"\u6269\u5c55\u4e2d\u5fc3", None)) - self.toolButton_install.setText(QCoreApplication.translate("Form", u"Install", None)) - self.toolButton_downloan.setText(QCoreApplication.translate("Form", u"Download", None)) - self.toolButton_detail.setText(QCoreApplication.translate("Form", u"Details", None)) - self.toolButton_update.setText(QCoreApplication.translate("Form", u"Update", None)) - self.toolButton_uninstall.setText(QCoreApplication.translate("Form", u"Uninstall", None)) - self.toolButton_check_update.setText(QCoreApplication.translate("Form", u"CheckUpdate", None)) - self.toolButton_install_requirements.setText(QCoreApplication.translate("Form", u"Import", None)) - self.toolButton_freeze_requirements.setText(QCoreApplication.translate("Form", u"Export", None)) - ___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0) - ___qtablewidgetitem.setText(QCoreApplication.translate("Form", u"Name", None)); - ___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(1) - ___qtablewidgetitem1.setText(QCoreApplication.translate("Form", u"Version", None)); - ___qtablewidgetitem2 = self.tableWidget.horizontalHeaderItem(2) - ___qtablewidgetitem2.setText(QCoreApplication.translate("Form", u"Latest Version", None)); - ___qtablewidgetitem3 = self.tableWidget.horizontalHeaderItem(3) - ___qtablewidgetitem3.setText(QCoreApplication.translate("Form", u"Type", None)); - ___qtablewidgetitem4 = self.tableWidget.horizontalHeaderItem(4) - ___qtablewidgetitem4.setText(QCoreApplication.translate("Form", u"Update", None)); - ___qtablewidgetitem5 = self.tableWidget.horizontalHeaderItem(5) - ___qtablewidgetitem5.setText(QCoreApplication.translate("Form", u"Uninstall", None)); - # retranslateUi - diff --git a/pyminer/features/ui/pm_marketplace/main.ui b/pyminer/features/ui/pm_marketplace/main.ui deleted file mode 100644 index 2561758f..00000000 --- a/pyminer/features/ui/pm_marketplace/main.ui +++ /dev/null @@ -1,10157 +0,0 @@ - - - Form - - - - 0 - 0 - 978 - 664 - - - - 扩展中心 - - - - - - - - true - - - Install - - - - - - - false - - - Download - - - - - - - false - - - Details - - - - - - - false - - - Update - - - - - - - false - - - Uninstall - - - - - - - false - - - CheckUpdate - - - - - - - false - - - Import - - - - - - - false - - - Export - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - - - - - - - 9995 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name - - - - - Version - - - - - Latest Version - - - - - Type - - - - - Update - - - - - Uninstall - - - - - - - - - diff --git a/pyminer/features/ui/pm_marketplace/package_manager_main.py b/pyminer/features/ui/pm_marketplace/package_manager_main.py deleted file mode 100644 index 650f9604..00000000 --- a/pyminer/features/ui/pm_marketplace/package_manager_main.py +++ /dev/null @@ -1,110 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'package_manager_main.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - - -class Ui_Form(object): - def setupUi(self, Form): - if not Form.objectName(): - Form.setObjectName(u"Form") - Form.resize(978, 664) - self.verticalLayout = QVBoxLayout(Form) - self.verticalLayout.setObjectName(u"verticalLayout") - self.horizontalLayout = QHBoxLayout() - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.toolButton_install = QToolButton(Form) - self.toolButton_install.setObjectName(u"toolButton_install") - self.toolButton_install.setEnabled(True) - - self.horizontalLayout.addWidget(self.toolButton_install) - - self.toolButton_update = QToolButton(Form) - self.toolButton_update.setObjectName(u"toolButton_update") - self.toolButton_update.setEnabled(True) - - self.horizontalLayout.addWidget(self.toolButton_update) - - self.toolButton_uninstall = QToolButton(Form) - self.toolButton_uninstall.setObjectName(u"toolButton_uninstall") - self.toolButton_uninstall.setEnabled(True) - - self.horizontalLayout.addWidget(self.toolButton_uninstall) - - self.toolButton_install_requirements = QToolButton(Form) - self.toolButton_install_requirements.setObjectName(u"toolButton_install_requirements") - self.toolButton_install_requirements.setEnabled(False) - - self.horizontalLayout.addWidget(self.toolButton_install_requirements) - - self.toolButton_freeze_requirements = QToolButton(Form) - self.toolButton_freeze_requirements.setObjectName(u"toolButton_freeze_requirements") - self.toolButton_freeze_requirements.setEnabled(False) - - self.horizontalLayout.addWidget(self.toolButton_freeze_requirements) - - self.toolButton_downloan = QToolButton(Form) - self.toolButton_downloan.setObjectName(u"toolButton_downloan") - self.toolButton_downloan.setEnabled(False) - - self.horizontalLayout.addWidget(self.toolButton_downloan) - - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout.addItem(self.horizontalSpacer) - - self.lineEdit = QLineEdit(Form) - self.lineEdit.setObjectName(u"lineEdit") - self.lineEdit.setEnabled(False) - - self.horizontalLayout.addWidget(self.lineEdit) - - - self.verticalLayout.addLayout(self.horizontalLayout) - - self.tableWidget = QTableWidget(Form) - if (self.tableWidget.columnCount() < 2): - self.tableWidget.setColumnCount(2) - __qtablewidgetitem = QTableWidgetItem() - self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem) - __qtablewidgetitem1 = QTableWidgetItem() - self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1) - if (self.tableWidget.rowCount() < 100): - self.tableWidget.setRowCount(100) - self.tableWidget.setObjectName(u"tableWidget") - self.tableWidget.setRowCount(100) - self.tableWidget.horizontalHeader().setCascadingSectionResizes(False) - self.tableWidget.horizontalHeader().setProperty("showSortIndicator", False) - self.tableWidget.horizontalHeader().setStretchLastSection(False) - - self.verticalLayout.addWidget(self.tableWidget) - - - self.retranslateUi(Form) - - QMetaObject.connectSlotsByName(Form) - # setupUi - - def retranslateUi(self, Form): - Form.setWindowTitle(QCoreApplication.translate("Form", u"Package Manager", None)) - self.toolButton_install.setText(QCoreApplication.translate("Form", u"Install", None)) - self.toolButton_update.setText(QCoreApplication.translate("Form", u"Update", None)) - self.toolButton_uninstall.setText(QCoreApplication.translate("Form", u"Uninstall", None)) - self.toolButton_install_requirements.setText(QCoreApplication.translate("Form", u"Import", None)) - self.toolButton_freeze_requirements.setText(QCoreApplication.translate("Form", u"Export", None)) - self.toolButton_downloan.setText(QCoreApplication.translate("Form", u"Download", None)) - ___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0) - ___qtablewidgetitem.setText(QCoreApplication.translate("Form", u"Name", None)); - ___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(1) - ___qtablewidgetitem1.setText(QCoreApplication.translate("Form", u"Version", None)); - # retranslateUi - diff --git a/pyminer/features/ui/pm_marketplace/package_manager_main.ui b/pyminer/features/ui/pm_marketplace/package_manager_main.ui deleted file mode 100644 index 930d7a1b..00000000 --- a/pyminer/features/ui/pm_marketplace/package_manager_main.ui +++ /dev/null @@ -1,231 +0,0 @@ - - - Form - - - - 0 - 0 - 978 - 664 - - - - Package Manager - - - - - - - - true - - - Install - - - - - - - true - - - Update - - - - - - - true - - - Uninstall - - - - - - - false - - - Import - - - - - - - false - - - Export - - - - - - - false - - - Download - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - - - - - - - 100 - - - false - - - false - - - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name - - - - - Version - - - - - - - - - diff --git a/pyminer/features/ui/pm_marketplace/uninstall.py b/pyminer/features/ui/pm_marketplace/uninstall.py deleted file mode 100644 index edf8200a..00000000 --- a/pyminer/features/ui/pm_marketplace/uninstall.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'uninstall.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - -from pmgwidgets import PMGProcessConsoleWidget - - -class Ui_Dialog(object): - def setupUi(self, Dialog): - if not Dialog.objectName(): - Dialog.setObjectName(u"Dialog") - Dialog.resize(800, 573) - self.verticalLayout = QVBoxLayout(Dialog) - self.verticalLayout.setObjectName(u"verticalLayout") - self.groupBox = QGroupBox(Dialog) - self.groupBox.setObjectName(u"groupBox") - self.horizontalLayout_2 = QHBoxLayout(self.groupBox) - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.log_console = PMGProcessConsoleWidget(self.groupBox) - self.log_console.setObjectName(u"log_console") - - self.horizontalLayout_2.addWidget(self.log_console) - - - self.verticalLayout.addWidget(self.groupBox) - - self.widget = QWidget(Dialog) - self.widget.setObjectName(u"widget") - self.widget.setMaximumSize(QSize(16777215, 50)) - self.widget.setSizeIncrement(QSize(0, 0)) - self.horizontalLayout = QHBoxLayout(self.widget) - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.horizontalSpacer = QSpacerItem(680, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout.addItem(self.horizontalSpacer) - - self.button_close = QPushButton(self.widget) - self.button_close.setObjectName(u"button_close") - - self.horizontalLayout.addWidget(self.button_close) - - - self.verticalLayout.addWidget(self.widget) - - - self.retranslateUi(Dialog) - - QMetaObject.connectSlotsByName(Dialog) - # setupUi - - def retranslateUi(self, Dialog): - Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Dialog", None)) - self.groupBox.setTitle(QCoreApplication.translate("Dialog", u"Log", None)) - self.button_close.setText(QCoreApplication.translate("Dialog", u"Close", None)) - # retranslateUi - diff --git a/pyminer/features/ui/pm_marketplace/uninstall.ui b/pyminer/features/ui/pm_marketplace/uninstall.ui deleted file mode 100644 index 56f340fa..00000000 --- a/pyminer/features/ui/pm_marketplace/uninstall.ui +++ /dev/null @@ -1,79 +0,0 @@ - - - Dialog - - - - 0 - 0 - 800 - 573 - - - - Dialog - - - - - - Log - - - - - - - - - - - - - 16777215 - 50 - - - - - 0 - 0 - - - - - - - Qt::Horizontal - - - - 680 - 20 - - - - - - - - Close - - - - - - - - - - - PMGProcessConsoleWidget - QWidget -
pmgwidgets
- 1 -
-
- - -
diff --git a/pyminer/features/ui/pmwidgets/__init__.py b/pyminer/features/ui/pmwidgets/__init__.py deleted file mode 100644 index 0df559b7..00000000 --- a/pyminer/features/ui/pmwidgets/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .dockwidget import PMDockWidget -from .pmmainwindow import BaseMainWindow -from .toplevel import TopLevelWidget diff --git a/pyminer/features/ui/pmwidgets/dockwidget.py b/pyminer/features/ui/pmwidgets/dockwidget.py deleted file mode 100644 index 052ffdf1..00000000 --- a/pyminer/features/ui/pmwidgets/dockwidget.py +++ /dev/null @@ -1,21 +0,0 @@ -from PySide2.QtGui import QCloseEvent -from pmgwidgets import PMGDockWidget - - -class PMDockWidget(PMGDockWidget): - - def closeEvent(self, event: 'QCloseEvent'): - from utils import get_main_window - main_window = get_main_window() - w = self.widget() - if hasattr(w, 'on_closed_action'): - if w.on_closed_action == 'delete': - main_window.delete_dock_widget(self.name) - return - self.hide() - event.accept() - main_window.refresh_view_configs() - - def bind_events(self): - """绑定该控件的所有事件,会在主程序加载结束后自动执行,不需要在__init__里面手动执行""" - pass diff --git a/pyminer/features/ui/pmwidgets/pmmainwindow.py b/pyminer/features/ui/pmwidgets/pmmainwindow.py deleted file mode 100644 index 431baa7c..00000000 --- a/pyminer/features/ui/pmwidgets/pmmainwindow.py +++ /dev/null @@ -1,373 +0,0 @@ -""" - -这里定义了MainWindow的基类。 - -基类主要包含带选项卡工具栏的管理功能,以及浮动窗口的管理功能。 - -添加浮动窗口时,默认‘关闭’事件就是隐藏。如果是彻底的关闭,需要进行重写。 - -每次界面关闭时,布局会被存入文件pyminer/config/customized/layout.ini之中。 - -再次启动时,若这个文件存在,就会加载,反之不会加载。 - -""" - -import logging -import os -from typing import Dict, TYPE_CHECKING - -import chardet -from PySide2.QtCore import Qt -from PySide2.QtWidgets import QMainWindow, QToolBar, QPushButton, QWidget, QMenu, QDialog - -import utils -from features.ui.common.pmlocale import pmlocale -from pmgwidgets import TopToolBarRight - -if TYPE_CHECKING: - from app2 import PMToolBarHome - from features.ui.pmwidgets.dockwidget import PMDockWidget - from pmgwidgets import ActionWithMessage -logger = logging.getLogger(__name__) - - -class BaseMainWindow(QMainWindow): - """ - PyMiner MainWindow主界面类的基类. - - """ - dialog_classes: Dict[str, 'QDialog'] = {} - toolbars: Dict[str, QToolBar] = {} - _current_toolbar_name: str = '' # 当前的窗口标题栏选项卡 - __dock_widgets: Dict[str, 'PMDockWidget'] - dock_places = {'left': Qt.LeftDockWidgetArea, 'right': Qt.RightDockWidgetArea, 'top': Qt.TopDockWidgetArea, - 'bottom': Qt.BottomDockWidgetArea} - - @property - def dock_widgets(self): - return self.__dock_widgets - - def __init__(self, parent=None): - super().__init__(parent) - self.__dock_widgets = {} - self.setContextMenuPolicy(Qt.NoContextMenu) # 隐藏主界面的菜单栏。 - - def set_dock_titlebar_visible(self, show: bool): - """ - 切换停靠窗口的标题栏是否可见。只有可见的时候才能拖动。 - Args: - show: - - Returns: - - """ - if show: - for k, w in self.dock_widgets.items(): - w.setTitleBarWidget(None) - - else: - for k, w in self.dock_widgets.items(): - w.setTitleBarWidget(QWidget()) - utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", show) - - @staticmethod - def get_stylesheet(style_sheet_name: str = 'standard'): - """ - 获取样式表 - TODO:这个方法应该拿到外面去,不应该和主界面深度绑定! - Args: - style_sheet_name: - - Returns: - - """ - style_sheet = "" - with open(os.path.join(utils.get_root_dir(), 'resources', 'qss', '%s.qss' % style_sheet_name), 'rb') as f: - b = f.read() - enc = chardet.detect(b) - if enc.get('encoding') is not None: - s = b.decode(enc['encoding']) - style_sheet = s - else: - logger.fatal("加载样式表%s失败!" % style_sheet_name) - return style_sheet - - def init_toolbar_tab(self): - """ - 初始化工具栏的选项卡 - Returns: - - """ - from pmgwidgets import TopToolBar - ttb = TopToolBar() - ttb.setObjectName('tab_bar_for_tool_bar') - self.addToolBar(ttb) - ttbr = TopToolBarRight() - ttbr.setObjectName('top_toolbar_right') - self.addToolBar(ttbr) - self.toolbar_hide_button = ttbr.hide_button - self.toolbar_hide_button.clicked.connect(self.on_toolbar_hide_button_pressed) - self.top_toolbar_tab = ttb - - def on_toolbar_hide_button_pressed(self): - """ - 当点击隐藏工具栏的按钮时 - Returns: - - """ - current_toolbar = self.toolbars[self._current_toolbar_name] - if current_toolbar.isVisible(): - current_toolbar.hide() - - else: - current_toolbar.show() - self.refresh_toolbar_hide_button_status() - - def refresh_toolbar_appearance(self, force_to_show: bool = True): - """ - 刷新工具栏的外观 - Args: - force_to_show: - - Returns: - - """ - for k in self.toolbars.keys(): - tab_button: 'QPushButton' = self.toolbars[k].tab_button - width = len(tab_button.text()) * 10 + 20 - button: 'QPushButton' = self.toolbars[k].tab_button - if k != self._current_toolbar_name: - self.toolbars[k].hide() - button.setProperty('stat', 'unselected') - else: - if force_to_show: - self.toolbars[k].show() - button.setProperty('stat', 'selected') - button.setStyle(button.style()) - - def refresh_toolbar_hide_button_status(self): - """ - 刷新工具栏隐藏按钮的状态(按钮的箭头向上还是向下) - Returns: - - """ - current_toolbar = self.toolbars[self._current_toolbar_name] - if not current_toolbar.isVisible(): - self.toolbar_hide_button.setArrowType(Qt.DownArrow) - else: - self.toolbar_hide_button.setArrowType(Qt.UpArrow) - - def on_toolbar_switch_button_clicked(self, name): - self.switch_toolbar(name, switch_only=False) - - def switch_toolbar(self, name: str, switch_only: bool = True): - """ - name:工具栏的名称 - switch_only:如果为True,那么在调用时只会切换工具栏,当当前的工具栏名称与name相等时, - 调用多次不会改变当前工具栏的显示状态。为False的时候,若当前工具栏名称为name,那么就会改变显示状态, - 亦即原先显示的隐藏,原先隐藏的显示。 - """ - if self.toolbars.get(name) is not None: - if name == self._current_toolbar_name: - if not switch_only: - current_tb = self.toolbars[self._current_toolbar_name] - current_tb.setVisible(not current_tb.isVisible()) - else: - self._current_toolbar_name = name - self.refresh_toolbar_appearance(force_to_show=True) - else: - raise Exception('toolbar tab \'%s\' is not defined!' % name) - self.refresh_toolbar_hide_button_status() - - def save_layout(self): - """ - 当关闭程序时保存布局 - Returns: - - """ - cfg_dir = utils.get_user_config_dir() - layout_path = os.path.join(cfg_dir, 'layout.ini') - try: - with open(layout_path, 'wb') as f: - s = b'' # self.saveState() - f.write(s) - except FileNotFoundError: - logging.warning("file not found:" + layout_path) - - def load_layout(self): - # p = os.path.join(Settings.get_instance().settings_path, 'layout.ini') - - # if os.path.exists(p): - # with open(p, 'rb') as f: - # s = f.read() - # self.restoreState(s) - - p = os.path.join(utils.get_root_dir(), 'resources', 'qss', 'standard.ini') - with open(p, 'rb') as f: - s = f.read() - self.restoreState(s) - self.refresh_view_configs() - - def load_predefined_layout(self, layout_type: str = 'standard'): - layouts = {'standard': 'standard.ini'} - p = os.path.join(utils.get_root_dir(), 'resources', 'qss', layouts[layout_type]) - if os.path.exists(p): - with open(p, 'rb') as f: - s = f.read() - self.restoreState(s) - for name in self.toolbars.keys(): - self.toolbars[name].setVisible(False) - self.toolbars[self._current_toolbar_name].setVisible(True) - self.refresh_view_configs() - - def add_widget_on_dock(self, dock_name: str, - widget: QWidget, text: str = '', side='left'): - """ - 向界面添加控件 - Args: - dock_name: - widget: - text: - side: - - Returns: - - """ - from features.ui.pmwidgets import PMDockWidget - text = pmlocale.translate(text) - dw = PMDockWidget(name=dock_name, text=text, parent=self) - dw.text = text - dw.setObjectName(dock_name) - dw.setWidget(widget) - - if hasattr(widget, 'setup_ui'): - if hasattr(widget, 'show_directly'): - if widget.show_directly: - widget.setup_ui() - else: - self.setupui_tasks.append(widget.setup_ui) - else: - self.setupui_tasks.append(widget.setup_ui) - - self.addDockWidget(self.dock_places[side], dw) - if dock_name not in self.dock_widgets.keys(): - self.dock_widgets[dock_name] = dw - else: - raise Exception( - 'docked widget name: \'%s\' is already used!' % - dock_name) - - self.refresh_view_configs() - return dw - - def get_dock_widget(self, widget_name: str) -> 'PMDockWidget': - """ - 获取停靠的控件 - Args: - widget_name: - - Returns: - - """ - dw = self.dock_widgets.get(widget_name) - if dw is None: - logging.debug('dockwidget named \'%s\' is not defined!' % widget_name) - return dw - - def delete_dock_widget(self, widget_name: str): - """ - 删除dock_widget。 - Args: - widget_name: - - Returns: - - """ - if self.dock_widgets.get(widget_name) is not None: - dock_widget = self.dock_widgets.pop(widget_name) - if hasattr(dock_widget.widget(), 'on_dock_widget_deleted'): - dock_widget.widget().on_dock_widget_deleted() - dock_widget.deleteLater() - - def refresh_view_configs(self): - """ - 刷新工具栏的可见状态,更新视图菜单 - Returns: - - """ - from pmgwidgets import ActionWithMessage - - home_toolbar: 'PMToolBarHome' = self.toolbars.get('toolbar_home') - # menu = home_toolbar.get_control_widget('view_config').menu() - # if menu is None: - menu = QMenu() - menu.triggered.connect(home_toolbar.process_visibility_actions) - for k in self.dock_widgets.keys(): - a = ActionWithMessage( - text=self.dock_widgets[k].text, - parent=home_toolbar, - message=k) - a.setCheckable(True) - a.setChecked(self.dock_widgets[k].widget().isVisible()) - menu.addAction(a) - menu.addSeparator() - a = ActionWithMessage( - text=self.tr('Normal View'), - parent=home_toolbar, - message='load_standard_layout') - menu.addAction(a) - a = ActionWithMessage( - text=self.tr('Lock UI Layout'), - parent=home_toolbar, - message='lock_layout') - a.setCheckable(True) - dock_title_visible = utils.get_settings_item_from_file("config.ini", "MAIN/DOCK_TITLEBAR_VISIBLE") - a.setChecked(not dock_title_visible) - menu.addAction(a) - home_toolbar.get_control_widget('view_config').setMenu(menu) - self._view_config_menu = menu - - def on_main_window_shown(self): - """ - 主界面显示时调用的方法 - Returns: - - """ - self.refresh_view_configs() - - def raise_dock_into_view(self, dock_name: str): - """ - 将dockwidget提升到可见。 - """ - dock = self.get_dock_widget(dock_name) - if dock is not None: - dock.raise_into_view() - dock.setVisible(True) - - def delete_temporary_dock_windows(self): - """ - 删除临时性的窗口 - """ - keys = list(self.dock_widgets.keys()) - for dock_name in keys: - dock = self.dock_widgets.get(dock_name) - if dock.widget().is_temporary(): - self.dock_widgets.pop(dock_name) - logging.info('Closing and deleting temporary dock widget object:%s,named:%s, with widget :%s' - % (dock, dock_name, dock.widget())) - dock.close() - dock.deleteLater() - - def bind_events(self): - """ - 让全部的控件都绑定事件。 - - 在启动的最后调用这个绑定事件的方法, - 这样可以避免绑定的时候,由于对应控件未加载,发生找不到对应控件的错误 - """ - for k, w in self.dock_widgets.items(): - if hasattr(w, 'bind_events'): - w.bind_events() - for k, w in self.toolbars.items(): - if hasattr(w, 'bind_events'): - w.bind_events() diff --git a/pyminer/features/ui/pmwidgets/toplevel.py b/pyminer/features/ui/pmwidgets/toplevel.py deleted file mode 100644 index 553149f9..00000000 --- a/pyminer/features/ui/pmwidgets/toplevel.py +++ /dev/null @@ -1,53 +0,0 @@ -from PySide2.QtCore import Qt, QPoint -from PySide2.QtGui import QFocusEvent, QMouseEvent -from PySide2.QtWidgets import QDialog, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel - -from utils import get_main_window - - -class TopLevelWidget(QDialog): - def __init__(self, parent=None): - super(TopLevelWidget, self).__init__(parent) - self.setWindowFlags(Qt.Popup | Qt.FramelessWindowHint) # 点击其他位置之后,可以隐藏。 - self.setLayout(QVBoxLayout()) - self.title_layout = QHBoxLayout() - self.layout().addLayout(self.title_layout) - b = QPushButton('x') - self.title_layout.addWidget(QLabel()) - self.title_layout.addWidget(b) - b.setMaximumWidth(20) - b.clicked.connect(self.hide) - self.central_widget = None - - # get_main_window().window_geometry_changed_signal.connect(self.refresh_position) - self.position: QPoint = None - self.width: int = 500 - self.height = 500 - - def set_central_widget(self, widget: 'QWidget'): - self.layout().addWidget(widget) - self.central_widget = widget - - def set_position(self, position: 'QPoint'): - self.position = position - self.refresh_position() - - def set_width(self, width: int): - self.width = width - - def refresh_position(self) -> None: - if self.position is None: - return - mw = get_main_window() - self.setGeometry(mw.geometry().x() + self.position.x(), mw.geometry().y() + self.position.y() + 16, - self.width, self.height) - - def mousePressEvent(self, a0: QMouseEvent) -> None: - """ - 在鼠标事件中,当鼠标点击弹出的窗口外部时,弹出窗口应当会隐藏。但如果不改写这一事件,在点击其他位置的时候, - 假如点击的位置时按钮,那么就会在隐藏窗口的同时触发按钮事件。如果这个按钮恰好可以控制该窗口的弹出和隐藏, - 那么就会发现窗口消失之后又立刻蹦了出来,这是因为窗口消失之后,它的出现事件又被触发了。 - 设置为Qt.WA_NoMouseReplay,就是为了避免这种糟糕的状况。 - """ - self.setAttribute(Qt.WA_NoMouseReplay) - super().mousePressEvent(a0) diff --git a/pyminer/features/ui/ui_aboutme.py b/pyminer/features/ui/ui_aboutme.py deleted file mode 100644 index 878455db..00000000 --- a/pyminer/features/ui/ui_aboutme.py +++ /dev/null @@ -1,186 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'ui_aboutme.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - -import pyqtsource_rc - -class Ui_Form(object): - def setupUi(self, Form): - if not Form.objectName(): - Form.setObjectName(u"Form") - Form.resize(800, 600) - Form.setMinimumSize(QSize(800, 600)) - Form.setMaximumSize(QSize(800, 600)) - font = QFont() - font.setFamily(u"Albany AMT") - Form.setFont(font) - self.verticalLayout = QVBoxLayout(Form) - self.verticalLayout.setObjectName(u"verticalLayout") - self.horizontalLayout = QHBoxLayout() - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout.addItem(self.horizontalSpacer) - - self.label_3 = QLabel(Form) - self.label_3.setObjectName(u"label_3") - self.label_3.setMinimumSize(QSize(85, 85)) - self.label_3.setMaximumSize(QSize(85, 85)) - self.label_3.setPixmap(QPixmap(u":/logo/icons/logo.png")) - self.label_3.setScaledContents(True) - - self.horizontalLayout.addWidget(self.label_3) - - self.label = QLabel(Form) - self.label.setObjectName(u"label") - font1 = QFont() - font1.setFamily(u"Microsoft YaHei UI") - font1.setPointSize(24) - font1.setBold(True) - font1.setWeight(75) - self.label.setFont(font1) - self.label.setScaledContents(True) - self.label.setAlignment(Qt.AlignCenter) - - self.horizontalLayout.addWidget(self.label) - - self.label_2 = QLabel(Form) - self.label_2.setObjectName(u"label_2") - font2 = QFont() - font2.setFamily(u"\u9ed1\u4f53") - self.label_2.setFont(font2) - self.label_2.setAlignment(Qt.AlignBottom|Qt.AlignHCenter) - - self.horizontalLayout.addWidget(self.label_2) - - self.label_version_show = QLabel(Form) - self.label_version_show.setObjectName(u"label_version_show") - self.label_version_show.setFont(font2) - self.label_version_show.setAlignment(Qt.AlignBottom|Qt.AlignHCenter) - - self.horizontalLayout.addWidget(self.label_version_show) - - self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout.addItem(self.horizontalSpacer_2) - - - self.verticalLayout.addLayout(self.horizontalLayout) - - self.tabWidget = QTabWidget(Form) - self.tabWidget.setObjectName(u"tabWidget") - font3 = QFont() - font3.setFamily(u"\u9ed1\u4f53") - font3.setPointSize(11) - self.tabWidget.setFont(font3) - self.tab = QWidget() - self.tab.setObjectName(u"tab") - self.verticalLayout_2 = QVBoxLayout(self.tab) - self.verticalLayout_2.setSpacing(0) - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) - self.textedit_about = QTextEdit(self.tab) - self.textedit_about.setObjectName(u"textedit_about") - self.textedit_about.setFont(font3) - self.textedit_about.setFrameShape(QFrame.NoFrame) - - self.verticalLayout_2.addWidget(self.textedit_about) - - self.tabWidget.addTab(self.tab, "") - self.tab_2 = QWidget() - self.tab_2.setObjectName(u"tab_2") - self.verticalLayout_3 = QVBoxLayout(self.tab_2) - self.verticalLayout_3.setSpacing(0) - self.verticalLayout_3.setObjectName(u"verticalLayout_3") - self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) - self.feedback = QPlainTextEdit(self.tab_2) - self.feedback.setObjectName(u"feedback") - font4 = QFont() - font4.setFamily(u"Microsoft YaHei UI") - font4.setPointSize(11) - self.feedback.setFont(font4) - self.feedback.setFrameShape(QFrame.NoFrame) - - self.verticalLayout_3.addWidget(self.feedback) - - self.tabWidget.addTab(self.tab_2, "") - self.tab_3 = QWidget() - self.tab_3.setObjectName(u"tab_3") - self.verticalLayout_4 = QVBoxLayout(self.tab_3) - self.verticalLayout_4.setSpacing(0) - self.verticalLayout_4.setObjectName(u"verticalLayout_4") - self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) - self.plainTextEdit_2 = QPlainTextEdit(self.tab_3) - self.plainTextEdit_2.setObjectName(u"plainTextEdit_2") - self.plainTextEdit_2.setFont(font3) - self.plainTextEdit_2.setFrameShape(QFrame.NoFrame) - - self.verticalLayout_4.addWidget(self.plainTextEdit_2) - - self.tabWidget.addTab(self.tab_3, "") - self.tab_4 = QWidget() - self.tab_4.setObjectName(u"tab_4") - self.horizontalLayout_2 = QHBoxLayout(self.tab_4) - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.label_4 = QLabel(self.tab_4) - self.label_4.setObjectName(u"label_4") - self.label_4.setPixmap(QPixmap(u":/images/images/weixin.png")) - self.label_4.setScaledContents(True) - - self.horizontalLayout_2.addWidget(self.label_4) - - self.label_5 = QLabel(self.tab_4) - self.label_5.setObjectName(u"label_5") - self.label_5.setPixmap(QPixmap(u":/images/images/zhifubao.png")) - self.label_5.setScaledContents(True) - - self.horizontalLayout_2.addWidget(self.label_5) - - self.tabWidget.addTab(self.tab_4, "") - - self.verticalLayout.addWidget(self.tabWidget) - - - self.retranslateUi(Form) - - self.tabWidget.setCurrentIndex(0) - - - QMetaObject.connectSlotsByName(Form) - # setupUi - - def retranslateUi(self, Form): - Form.setWindowTitle(QCoreApplication.translate("Form", u"About", None)) - self.label_3.setText("") - self.label.setText(QCoreApplication.translate("Form", u"PyMiner", None)) - self.label_2.setText(QCoreApplication.translate("Form", u"Version:", None)) - self.label_version_show.setText(QCoreApplication.translate("Form", u"v2.0 Beta", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), QCoreApplication.translate("Form", u"About", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QCoreApplication.translate("Form", u"System", None)) - self.plainTextEdit_2.setPlainText(QCoreApplication.translate("Form", u"\u4faf\u5c55\u610f\n" -"py2cn\n" -"Junruoyu-Zheng\n" -"\u5fc3\u968f\u98ce\n" -"nihk\n" -"cl-jiang\n" -"Irony\n" -"\u51b0\u4e2d\u706b\n" -"houxinluo\n" -"\u5f00\u59cb\u8bf4\u6545\u4e8b\n" -"...", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), QCoreApplication.translate("Form", u"Credit", None)) - self.label_4.setText("") - self.label_5.setText("") - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_4), QCoreApplication.translate("Form", u"Donate", None)) - # retranslateUi - diff --git a/pyminer/features/ui/ui_aboutme.ui b/pyminer/features/ui/ui_aboutme.ui deleted file mode 100644 index 747bd4a4..00000000 --- a/pyminer/features/ui/ui_aboutme.ui +++ /dev/null @@ -1,310 +0,0 @@ - - - Form - - - - 0 - 0 - 800 - 600 - - - - - 800 - 600 - - - - - 800 - 600 - - - - - Albany AMT - - - - About - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 85 - 85 - - - - - 85 - 85 - - - - - - - :/logo/icons/logo.png - - - true - - - - - - - - Microsoft YaHei UI - 24 - 75 - true - - - - PyMiner - - - true - - - Qt::AlignCenter - - - - - - - - 黑体 - - - - Version: - - - Qt::AlignBottom|Qt::AlignHCenter - - - - - - - - 黑体 - - - - v2.0 Beta - - - Qt::AlignBottom|Qt::AlignHCenter - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 黑体 - 11 - - - - 0 - - - - About - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 黑体 - 11 - - - - QFrame::NoFrame - - - - - - - - System - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - Microsoft YaHei UI - 11 - - - - QFrame::NoFrame - - - - - - - - Credit - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 黑体 - 11 - - - - QFrame::NoFrame - - - 侯展意 -py2cn -Junruoyu-Zheng -心随风 -nihk -cl-jiang -Irony -冰中火 -houxinluo -开始说故事 -... - - - - - - - - Donate - - - - - - - - - :/images/images/weixin.png - - - true - - - - - - - - - - :/images/images/zhifubao.png - - - true - - - - - - - - - - - - - - diff --git a/pyminer/features/ui/ui_appstore.py b/pyminer/features/ui/ui_appstore.py deleted file mode 100644 index 0ab438a1..00000000 --- a/pyminer/features/ui/ui_appstore.py +++ /dev/null @@ -1,154 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'ui_appstore.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - -import pyqtsource_rc - -class Ui_Form(object): - def setupUi(self, Form): - if not Form.objectName(): - Form.setObjectName(u"Form") - Form.resize(1300, 809) - Form.setStyleSheet(u"") - self.verticalLayout = QVBoxLayout(Form) - self.verticalLayout.setSpacing(0) - self.verticalLayout.setObjectName(u"verticalLayout") - self.verticalLayout.setContentsMargins(0, 0, 0, 0) - self.widget = QWidget(Form) - self.widget.setObjectName(u"widget") - self.widget.setMaximumSize(QSize(16777215, 50)) - self.widget.setStyleSheet(u"background-color: rgb(49, 70,95);") - self.horizontalLayout = QHBoxLayout(self.widget) - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.horizontalLayout.setContentsMargins(0, 0, 0, 0) - self.horizontalSpacer_3 = QSpacerItem(849, 5, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout.addItem(self.horizontalSpacer_3) - - self.toolButton_help = QToolButton(self.widget) - self.toolButton_help.setObjectName(u"toolButton_help") - self.toolButton_help.setStyleSheet(u"color: rgb(255, 255, 255);") - self.toolButton_help.setAutoRaise(True) - - self.horizontalLayout.addWidget(self.toolButton_help) - - self.line = QFrame(self.widget) - self.line.setObjectName(u"line") - self.line.setStyleSheet(u"color: rgb(255, 255, 255);") - self.line.setFrameShape(QFrame.VLine) - self.line.setFrameShadow(QFrame.Sunken) - - self.horizontalLayout.addWidget(self.line) - - self.toolButton_manage = QToolButton(self.widget) - self.toolButton_manage.setObjectName(u"toolButton_manage") - self.toolButton_manage.setStyleSheet(u"color: rgb(255, 255, 255);") - self.toolButton_manage.setAutoRaise(True) - - self.horizontalLayout.addWidget(self.toolButton_manage) - - - self.verticalLayout.addWidget(self.widget) - - self.widget_3 = QWidget(Form) - self.widget_3.setObjectName(u"widget_3") - self.widget_3.setMaximumSize(QSize(16777215, 50)) - self.widget_3.setStyleSheet(u"background-color: rgb(49, 70, 95);") - self.horizontalLayout_3 = QHBoxLayout(self.widget_3) - self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0) - self.toolButton_4 = QToolButton(self.widget_3) - self.toolButton_4.setObjectName(u"toolButton_4") - self.toolButton_4.setEnabled(False) - icon = QIcon() - icon.addFile(u":/color/theme/default/icons/useLeftAll.svg", QSize(), QIcon.Normal, QIcon.Off) - self.toolButton_4.setIcon(icon) - self.toolButton_4.setAutoRaise(True) - - self.horizontalLayout_3.addWidget(self.toolButton_4) - - self.toolButton_5 = QToolButton(self.widget_3) - self.toolButton_5.setObjectName(u"toolButton_5") - icon1 = QIcon() - icon1.addFile(u":/color/theme/default/icons/mIconModelLayer.svg", QSize(), QIcon.Normal, QIcon.Off) - self.toolButton_5.setIcon(icon1) - self.toolButton_5.setIconSize(QSize(35, 35)) - self.toolButton_5.setAutoRaise(True) - - self.horizontalLayout_3.addWidget(self.toolButton_5) - - self.label = QLabel(self.widget_3) - self.label.setObjectName(u"label") - font = QFont() - font.setFamily(u"Microsoft YaHei UI") - font.setPointSize(15) - self.label.setFont(font) - self.label.setStyleSheet(u"color: rgb(255, 255, 255);") - - self.horizontalLayout_3.addWidget(self.label) - - self.horizontalSpacer_4 = QSpacerItem(436, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_3.addItem(self.horizontalSpacer_4) - - self.lineEdit = QLineEdit(self.widget_3) - self.lineEdit.setObjectName(u"lineEdit") - self.lineEdit.setMaximumSize(QSize(500, 35)) - self.lineEdit.setStyleSheet(u"background-color: rgb(255, 255, 255);border:0px groove gray;border-radius:5px;padding:2px 4px") - - self.horizontalLayout_3.addWidget(self.lineEdit) - - self.toolButton_3 = QToolButton(self.widget_3) - self.toolButton_3.setObjectName(u"toolButton_3") - self.toolButton_3.setMaximumSize(QSize(40, 40)) - icon2 = QIcon() - icon2.addFile(u":/color/theme/default/icons/search.svg", QSize(), QIcon.Normal, QIcon.Off) - self.toolButton_3.setIcon(icon2) - self.toolButton_3.setIconSize(QSize(30, 30)) - self.toolButton_3.setAutoRaise(True) - - self.horizontalLayout_3.addWidget(self.toolButton_3) - - - self.verticalLayout.addWidget(self.widget_3) - - self.widget_2 = QWidget(Form) - self.widget_2.setObjectName(u"widget_2") - self.verticalLayout_2 = QVBoxLayout(self.widget_2) - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) - self.horizontalLayout_2 = QHBoxLayout() - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - - self.verticalLayout_2.addLayout(self.horizontalLayout_2) - - - self.verticalLayout.addWidget(self.widget_2) - - - self.retranslateUi(Form) - - QMetaObject.connectSlotsByName(Form) - # setupUi - - def retranslateUi(self, Form): - Form.setWindowTitle(QCoreApplication.translate("Form", u"PyMiner App Store", None)) - self.toolButton_help.setText(QCoreApplication.translate("Form", u"Help", None)) - self.toolButton_manage.setText(QCoreApplication.translate("Form", u"Manage Apps", None)) - self.toolButton_4.setText(QCoreApplication.translate("Form", u"...", None)) - self.toolButton_5.setText(QCoreApplication.translate("Form", u"...", None)) - self.label.setText(QCoreApplication.translate("Form", u"App Store", None)) - self.lineEdit.setPlaceholderText(QCoreApplication.translate("Form", u"Search in sotre...", None)) - self.toolButton_3.setText(QCoreApplication.translate("Form", u"...", None)) - # retranslateUi - diff --git a/pyminer/features/ui/ui_appstore.ui b/pyminer/features/ui/ui_appstore.ui deleted file mode 100644 index dcd075d0..00000000 --- a/pyminer/features/ui/ui_appstore.ui +++ /dev/null @@ -1,273 +0,0 @@ - - - Form - - - - 0 - 0 - 1300 - 809 - - - - PyMiner App Store - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 16777215 - 50 - - - - background-color: rgb(49, 70,95); - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 849 - 5 - - - - - - - - color: rgb(255, 255, 255); - - - Help - - - true - - - - - - - color: rgb(255, 255, 255); - - - Qt::Vertical - - - - - - - color: rgb(255, 255, 255); - - - Manage Apps - - - true - - - - - - - - - - - 16777215 - 50 - - - - background-color: rgb(49, 70, 95); - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - false - - - ... - - - - :/color/theme/default/icons/useLeftAll.svg:/color/theme/default/icons/useLeftAll.svg - - - true - - - - - - - ... - - - - :/color/theme/default/icons/mIconModelLayer.svg:/color/theme/default/icons/mIconModelLayer.svg - - - - 35 - 35 - - - - true - - - - - - - - Microsoft YaHei UI - 15 - - - - color: rgb(255, 255, 255); - - - App Store - - - - - - - Qt::Horizontal - - - - 436 - 20 - - - - - - - - - 500 - 35 - - - - background-color: rgb(255, 255, 255);border:0px groove gray;border-radius:5px;padding:2px 4px - - - Search in sotre... - - - - - - - - 40 - 40 - - - - ... - - - - :/color/theme/default/icons/search.svg:/color/theme/default/icons/search.svg - - - - 30 - 30 - - - - true - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - diff --git a/pyminer/features/ui/ui_check_update.py b/pyminer/features/ui/ui_check_update.py deleted file mode 100644 index f1eb9da6..00000000 --- a/pyminer/features/ui/ui_check_update.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'ui_check_update.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - - -class Ui_Dialog(object): - def setupUi(self, Dialog): - if not Dialog.objectName(): - Dialog.setObjectName(u"Dialog") - Dialog.resize(546, 173) - self.verticalLayout_2 = QVBoxLayout(Dialog) - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.verticalLayout = QVBoxLayout() - self.verticalLayout.setObjectName(u"verticalLayout") - self.label = QLabel(Dialog) - self.label.setObjectName(u"label") - - self.verticalLayout.addWidget(self.label) - - self.horizontalLayout = QHBoxLayout() - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.button_detail = QPushButton(Dialog) - self.button_detail.setObjectName(u"button_detail") - self.button_detail.setMaximumSize(QSize(20, 16777215)) - - self.horizontalLayout.addWidget(self.button_detail) - - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout.addItem(self.horizontalSpacer) - - - self.verticalLayout.addLayout(self.horizontalLayout) - - self.table = QTableWidget(Dialog) - self.table.setObjectName(u"table") - - self.verticalLayout.addWidget(self.table) - - self.horizontalLayout_5 = QHBoxLayout() - self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") - self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_5.addItem(self.horizontalSpacer_2) - - self.button_confirm = QPushButton(Dialog) - self.button_confirm.setObjectName(u"button_confirm") - - self.horizontalLayout_5.addWidget(self.button_confirm) - - self.button_close = QPushButton(Dialog) - self.button_close.setObjectName(u"button_close") - - self.horizontalLayout_5.addWidget(self.button_close) - - - self.verticalLayout.addLayout(self.horizontalLayout_5) - - - self.verticalLayout_2.addLayout(self.verticalLayout) - - - self.retranslateUi(Dialog) - - QMetaObject.connectSlotsByName(Dialog) - # setupUi - - def retranslateUi(self, Dialog): - Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"\u66f4\u65b0\u68c0\u6d4b\u7a0b\u5e8f", None)) - self.label.setText("") - self.button_detail.setText(QCoreApplication.translate("Dialog", u"+", None)) - self.button_confirm.setText(QCoreApplication.translate("Dialog", u"\u66f4\u65b0", None)) - self.button_close.setText(QCoreApplication.translate("Dialog", u"\u4e0b\u6b21\u518d\u8bf4", None)) - # retranslateUi - diff --git a/pyminer/features/ui/ui_check_update.ui b/pyminer/features/ui/ui_check_update.ui deleted file mode 100644 index 6fcaa5e0..00000000 --- a/pyminer/features/ui/ui_check_update.ui +++ /dev/null @@ -1,96 +0,0 @@ - - - Dialog - - - - 0 - 0 - 546 - 173 - - - - 更新检测程序 - - - - - - - - - - - - - - - - - - 20 - 16777215 - - - - + - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 更新 - - - - - - - 下次再说 - - - - - - - - - - - - diff --git a/pyminer/features/ui/ui_data_normal.py b/pyminer/features/ui/ui_data_normal.py deleted file mode 100644 index 0579ff9a..00000000 --- a/pyminer/features/ui/ui_data_normal.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'ui_data_normal.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - - -class Ui_Dialog(object): - def setupUi(self, Dialog): - if not Dialog.objectName(): - Dialog.setObjectName(u"Dialog") - Dialog.resize(458, 405) - self.verticalLayout = QVBoxLayout(Dialog) - self.verticalLayout.setObjectName(u"verticalLayout") - self.horizontalLayout = QHBoxLayout() - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.tableWidget = QTableWidget(Dialog) - self.tableWidget.setObjectName(u"tableWidget") - - self.horizontalLayout.addWidget(self.tableWidget) - - self.formLayout = QFormLayout() - self.formLayout.setObjectName(u"formLayout") - self.label = QLabel(Dialog) - self.label.setObjectName(u"label") - - self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label) - - self.label_2 = QLabel(Dialog) - self.label_2.setObjectName(u"label_2") - - self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_2) - - self.label_3 = QLabel(Dialog) - self.label_3.setObjectName(u"label_3") - - self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_3) - - self.label_4 = QLabel(Dialog) - self.label_4.setObjectName(u"label_4") - - self.formLayout.setWidget(3, QFormLayout.LabelRole, self.label_4) - - self.spinBox_precison = QSpinBox(Dialog) - self.spinBox_precison.setObjectName(u"spinBox_precison") - self.spinBox_precison.setValue(2) - - self.formLayout.setWidget(3, QFormLayout.FieldRole, self.spinBox_precison) - - self.spinBox_count = QSpinBox(Dialog) - self.spinBox_count.setObjectName(u"spinBox_count") - self.spinBox_count.setValue(30) - - self.formLayout.setWidget(2, QFormLayout.FieldRole, self.spinBox_count) - - self.doubleSpinBox_std = QDoubleSpinBox(Dialog) - self.doubleSpinBox_std.setObjectName(u"doubleSpinBox_std") - self.doubleSpinBox_std.setValue(1.000000000000000) - - self.formLayout.setWidget(1, QFormLayout.FieldRole, self.doubleSpinBox_std) - - self.doubleSpinBox_mean = QDoubleSpinBox(Dialog) - self.doubleSpinBox_mean.setObjectName(u"doubleSpinBox_mean") - - self.formLayout.setWidget(0, QFormLayout.FieldRole, self.doubleSpinBox_mean) - - - self.horizontalLayout.addLayout(self.formLayout) - - - self.verticalLayout.addLayout(self.horizontalLayout) - - self.buttonBox = QDialogButtonBox(Dialog) - self.buttonBox.setObjectName(u"buttonBox") - self.buttonBox.setOrientation(Qt.Horizontal) - self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) - - self.verticalLayout.addWidget(self.buttonBox) - - - self.retranslateUi(Dialog) - - QMetaObject.connectSlotsByName(Dialog) - # setupUi - - def retranslateUi(self, Dialog): - Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"\u6570\u636e\u751f\u6210-\u6b63\u6001\u5206\u5e03", None)) - self.label.setText(QCoreApplication.translate("Dialog", u"\u5747\u503c:", None)) - self.label_2.setText(QCoreApplication.translate("Dialog", u"\u6807\u51c6\u5dee:", None)) - self.label_3.setText(QCoreApplication.translate("Dialog", u"\u6570\u91cf:", None)) - self.label_4.setText(QCoreApplication.translate("Dialog", u"\u7cbe\u5ea6:", None)) - # retranslateUi - diff --git a/pyminer/features/ui/ui_data_normal.ui b/pyminer/features/ui/ui_data_normal.ui deleted file mode 100644 index 86cef4e3..00000000 --- a/pyminer/features/ui/ui_data_normal.ui +++ /dev/null @@ -1,94 +0,0 @@ - - - Dialog - - - - 0 - 0 - 458 - 405 - - - - 数据生成-正态分布 - - - - - - - - - - - - - 均值: - - - - - - - 标准差: - - - - - - - 数量: - - - - - - - 精度: - - - - - - - 2 - - - - - - - 30 - - - - - - - 1.000000000000000 - - - - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - diff --git a/pyminer/features/ui/ui_first_form.py b/pyminer/features/ui/ui_first_form.py deleted file mode 100644 index 8d519606..00000000 --- a/pyminer/features/ui/ui_first_form.py +++ /dev/null @@ -1,444 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'ui_first_form.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - -import pyqtsource_rc - -class Ui_Form(object): - def setupUi(self, Form): - if not Form.objectName(): - Form.setObjectName(u"Form") - Form.resize(620, 580) - Form.setMinimumSize(QSize(620, 580)) - Form.setMaximumSize(QSize(620, 580)) - self.verticalLayout = QVBoxLayout(Form) - self.verticalLayout.setSpacing(0) - self.verticalLayout.setObjectName(u"verticalLayout") - self.verticalLayout.setContentsMargins(0, 0, 0, 0) - self.widget_2 = QWidget(Form) - self.widget_2.setObjectName(u"widget_2") - self.widget_2.setStyleSheet(u"") - self.horizontalLayout = QHBoxLayout(self.widget_2) - self.horizontalLayout.setSpacing(0) - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.horizontalLayout.setContentsMargins(0, 0, 0, 0) - self.label_3 = QLabel(self.widget_2) - self.label_3.setObjectName(u"label_3") - font = QFont() - font.setFamily(u"Consolas") - font.setPointSize(28) - self.label_3.setFont(font) - self.label_3.setPixmap(QPixmap(u":/images/images/bg.png")) - self.label_3.setScaledContents(True) - - self.horizontalLayout.addWidget(self.label_3) - - - self.verticalLayout.addWidget(self.widget_2) - - self.widget = QWidget(Form) - self.widget.setObjectName(u"widget") - self.widget.setMinimumSize(QSize(0, 270)) - self.widget.setMaximumSize(QSize(16777215, 270)) - self.widget.setStyleSheet(u"background-color: rgb(33, 33, 33);") - self.horizontalLayout_2 = QHBoxLayout(self.widget) - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.verticalLayout_6 = QVBoxLayout() - self.verticalLayout_6.setSpacing(5) - self.verticalLayout_6.setObjectName(u"verticalLayout_6") - self.verticalLayout_6.setContentsMargins(0, -1, -1, -1) - self.horizontalLayout_7 = QHBoxLayout() - self.horizontalLayout_7.setSpacing(0) - self.horizontalLayout_7.setObjectName(u"horizontalLayout_7") - self.label_24 = QLabel(self.widget) - self.label_24.setObjectName(u"label_24") - self.label_24.setMinimumSize(QSize(20, 0)) - self.label_24.setMaximumSize(QSize(20, 16777215)) - font1 = QFont() - font1.setPointSize(9) - self.label_24.setFont(font1) - self.label_24.setStyleSheet(u"color: rgb(229, 229, 229);") - - self.horizontalLayout_7.addWidget(self.label_24) - - self.label_23 = QLabel(self.widget) - self.label_23.setObjectName(u"label_23") - self.label_23.setFont(font1) - self.label_23.setStyleSheet(u"color: rgb(229, 229, 229);") - - self.horizontalLayout_7.addWidget(self.label_23) - - - self.verticalLayout_6.addLayout(self.horizontalLayout_7) - - self.widget_3 = QWidget(self.widget) - self.widget_3.setObjectName(u"widget_3") - self.widget_3.setMinimumSize(QSize(300, 0)) - self.verticalLayout_2 = QVBoxLayout(self.widget_3) - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.horizontalLayout_4 = QHBoxLayout() - self.horizontalLayout_4.setSpacing(0) - self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") - self.toolButton_2 = QToolButton(self.widget_3) - self.toolButton_2.setObjectName(u"toolButton_2") - icon = QIcon() - icon.addFile(u":/color/theme/default/icons/python.svg", QSize(), QIcon.Normal, QIcon.Off) - self.toolButton_2.setIcon(icon) - self.toolButton_2.setIconSize(QSize(18, 18)) - - self.horizontalLayout_4.addWidget(self.toolButton_2) - - self.btn_open_python = QToolButton(self.widget_3) - self.btn_open_python.setObjectName(u"btn_open_python") - self.btn_open_python.setStyleSheet(u"color: rgb(255, 255, 255);") - self.btn_open_python.setAutoRaise(True) - - self.horizontalLayout_4.addWidget(self.btn_open_python) - - self.horizontalSpacer_4 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_4.addItem(self.horizontalSpacer_4) - - - self.verticalLayout_2.addLayout(self.horizontalLayout_4) - - self.horizontalLayout_5 = QHBoxLayout() - self.horizontalLayout_5.setSpacing(0) - self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") - self.toolButton_3 = QToolButton(self.widget_3) - self.toolButton_3.setObjectName(u"toolButton_3") - icon1 = QIcon() - icon1.addFile(u":/color/theme/default/icons/csv.svg", QSize(), QIcon.Normal, QIcon.Off) - self.toolButton_3.setIcon(icon1) - self.toolButton_3.setIconSize(QSize(18, 18)) - - self.horizontalLayout_5.addWidget(self.toolButton_3) - - self.btn_open_csv = QToolButton(self.widget_3) - self.btn_open_csv.setObjectName(u"btn_open_csv") - self.btn_open_csv.setStyleSheet(u"color: rgb(255, 255, 255);") - self.btn_open_csv.setAutoRaise(True) - - self.horizontalLayout_5.addWidget(self.btn_open_csv) - - self.horizontalSpacer_5 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_5.addItem(self.horizontalSpacer_5) - - - self.verticalLayout_2.addLayout(self.horizontalLayout_5) - - self.horizontalLayout_6 = QHBoxLayout() - self.horizontalLayout_6.setSpacing(0) - self.horizontalLayout_6.setObjectName(u"horizontalLayout_6") - self.toolButton_4 = QToolButton(self.widget_3) - self.toolButton_4.setObjectName(u"toolButton_4") - icon2 = QIcon() - icon2.addFile(u":/color/theme/default/icons/excel.svg", QSize(), QIcon.Normal, QIcon.Off) - self.toolButton_4.setIcon(icon2) - self.toolButton_4.setIconSize(QSize(18, 18)) - - self.horizontalLayout_6.addWidget(self.toolButton_4) - - self.btn_open_excel = QToolButton(self.widget_3) - self.btn_open_excel.setObjectName(u"btn_open_excel") - self.btn_open_excel.setStyleSheet(u"color: rgb(255, 255, 255);") - self.btn_open_excel.setAutoRaise(True) - - self.horizontalLayout_6.addWidget(self.btn_open_excel) - - self.horizontalSpacer_6 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_6.addItem(self.horizontalSpacer_6) - - - self.verticalLayout_2.addLayout(self.horizontalLayout_6) - - self.horizontalLayout_14 = QHBoxLayout() - self.horizontalLayout_14.setSpacing(0) - self.horizontalLayout_14.setObjectName(u"horizontalLayout_14") - self.toolButton_10 = QToolButton(self.widget_3) - self.toolButton_10.setObjectName(u"toolButton_10") - icon3 = QIcon() - icon3.addFile(u":/color/theme/default/icons/E-matlab.svg", QSize(), QIcon.Normal, QIcon.Off) - self.toolButton_10.setIcon(icon3) - self.toolButton_10.setIconSize(QSize(18, 18)) - - self.horizontalLayout_14.addWidget(self.toolButton_10) - - self.btn_open_matlab = QToolButton(self.widget_3) - self.btn_open_matlab.setObjectName(u"btn_open_matlab") - self.btn_open_matlab.setStyleSheet(u"color: rgb(255, 255, 255);") - self.btn_open_matlab.setAutoRaise(True) - - self.horizontalLayout_14.addWidget(self.btn_open_matlab) - - self.horizontalSpacer_7 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_14.addItem(self.horizontalSpacer_7) - - - self.verticalLayout_2.addLayout(self.horizontalLayout_14) - - self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.verticalLayout_2.addItem(self.verticalSpacer) - - - self.verticalLayout_6.addWidget(self.widget_3) - - self.widget_6 = QWidget(self.widget) - self.widget_6.setObjectName(u"widget_6") - self.verticalLayout_5 = QVBoxLayout(self.widget_6) - self.verticalLayout_5.setObjectName(u"verticalLayout_5") - self.horizontalLayout_3 = QHBoxLayout() - self.horizontalLayout_3.setSpacing(0) - self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.toolButton = QToolButton(self.widget_6) - self.toolButton.setObjectName(u"toolButton") - icon4 = QIcon() - icon4.addFile(u":/color/theme/default/icons/open_folder.svg", QSize(), QIcon.Normal, QIcon.Off) - self.toolButton.setIcon(icon4) - self.toolButton.setIconSize(QSize(18, 18)) - - self.horizontalLayout_3.addWidget(self.toolButton) - - self.btn_open_folder = QToolButton(self.widget_6) - self.btn_open_folder.setObjectName(u"btn_open_folder") - self.btn_open_folder.setStyleSheet(u"color: rgb(255, 255, 255);") - self.btn_open_folder.setAutoRaise(True) - - self.horizontalLayout_3.addWidget(self.btn_open_folder) - - self.horizontalSpacer_8 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_3.addItem(self.horizontalSpacer_8) - - - self.verticalLayout_5.addLayout(self.horizontalLayout_3) - - - self.verticalLayout_6.addWidget(self.widget_6) - - - self.horizontalLayout_2.addLayout(self.verticalLayout_6) - - self.verticalLayout_9 = QVBoxLayout() - self.verticalLayout_9.setSpacing(5) - self.verticalLayout_9.setObjectName(u"verticalLayout_9") - self.verticalLayout_9.setContentsMargins(0, -1, -1, -1) - self.horizontalLayout_8 = QHBoxLayout() - self.horizontalLayout_8.setSpacing(0) - self.horizontalLayout_8.setObjectName(u"horizontalLayout_8") - self.label_25 = QLabel(self.widget) - self.label_25.setObjectName(u"label_25") - self.label_25.setMinimumSize(QSize(20, 0)) - self.label_25.setMaximumSize(QSize(20, 16777215)) - self.label_25.setFont(font1) - self.label_25.setStyleSheet(u"color: rgb(229, 229, 229);") - - self.horizontalLayout_8.addWidget(self.label_25) - - self.label_26 = QLabel(self.widget) - self.label_26.setObjectName(u"label_26") - self.label_26.setFont(font1) - self.label_26.setStyleSheet(u"color: rgb(229, 229, 229);") - - self.horizontalLayout_8.addWidget(self.label_26) - - - self.verticalLayout_9.addLayout(self.horizontalLayout_8) - - self.widget_8 = QWidget(self.widget) - self.widget_8.setObjectName(u"widget_8") - self.verticalLayout_10 = QVBoxLayout(self.widget_8) - self.verticalLayout_10.setObjectName(u"verticalLayout_10") - self.horizontalLayout_9 = QHBoxLayout() - self.horizontalLayout_9.setSpacing(0) - self.horizontalLayout_9.setObjectName(u"horizontalLayout_9") - self.toolButton_5 = QToolButton(self.widget_8) - self.toolButton_5.setObjectName(u"toolButton_5") - icon5 = QIcon() - icon5.addFile(u":/color/theme/default/icons/website.svg", QSize(), QIcon.Normal, QIcon.Off) - self.toolButton_5.setIcon(icon5) - self.toolButton_5.setIconSize(QSize(18, 18)) - - self.horizontalLayout_9.addWidget(self.toolButton_5) - - self.btn_manual = QToolButton(self.widget_8) - self.btn_manual.setObjectName(u"btn_manual") - self.btn_manual.setStyleSheet(u"color: rgb(255, 255, 255);") - self.btn_manual.setAutoRaise(True) - - self.horizontalLayout_9.addWidget(self.btn_manual) - - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_9.addItem(self.horizontalSpacer) - - - self.verticalLayout_10.addLayout(self.horizontalLayout_9) - - self.horizontalLayout_10 = QHBoxLayout() - self.horizontalLayout_10.setSpacing(0) - self.horizontalLayout_10.setObjectName(u"horizontalLayout_10") - self.toolButton_6 = QToolButton(self.widget_8) - self.toolButton_6.setObjectName(u"toolButton_6") - self.toolButton_6.setIcon(icon5) - self.toolButton_6.setIconSize(QSize(18, 18)) - - self.horizontalLayout_10.addWidget(self.toolButton_6) - - self.btn_website = QToolButton(self.widget_8) - self.btn_website.setObjectName(u"btn_website") - self.btn_website.setStyleSheet(u"color: rgb(255, 255, 255);") - self.btn_website.setAutoRaise(True) - - self.horizontalLayout_10.addWidget(self.btn_website) - - self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_10.addItem(self.horizontalSpacer_2) - - - self.verticalLayout_10.addLayout(self.horizontalLayout_10) - - self.horizontalLayout_11 = QHBoxLayout() - self.horizontalLayout_11.setSpacing(0) - self.horizontalLayout_11.setObjectName(u"horizontalLayout_11") - self.toolButton_7 = QToolButton(self.widget_8) - self.toolButton_7.setObjectName(u"toolButton_7") - self.toolButton_7.setIcon(icon5) - self.toolButton_7.setIconSize(QSize(18, 18)) - - self.horizontalLayout_11.addWidget(self.toolButton_7) - - self.btn_source = QToolButton(self.widget_8) - self.btn_source.setObjectName(u"btn_source") - self.btn_source.setStyleSheet(u"color: rgb(255, 255, 255);") - self.btn_source.setAutoRaise(True) - - self.horizontalLayout_11.addWidget(self.btn_source) - - self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_11.addItem(self.horizontalSpacer_3) - - - self.verticalLayout_10.addLayout(self.horizontalLayout_11) - - self.verticalSpacer_3 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.verticalLayout_10.addItem(self.verticalSpacer_3) - - - self.verticalLayout_9.addWidget(self.widget_8) - - self.widget_9 = QWidget(self.widget) - self.widget_9.setObjectName(u"widget_9") - self.verticalLayout_11 = QVBoxLayout(self.widget_9) - self.verticalLayout_11.setObjectName(u"verticalLayout_11") - self.horizontalLayout_12 = QHBoxLayout() - self.horizontalLayout_12.setSpacing(0) - self.horizontalLayout_12.setObjectName(u"horizontalLayout_12") - self.toolButton_8 = QToolButton(self.widget_9) - self.toolButton_8.setObjectName(u"toolButton_8") - self.toolButton_8.setIcon(icon5) - self.toolButton_8.setIconSize(QSize(18, 18)) - - self.horizontalLayout_12.addWidget(self.toolButton_8) - - self.btn_member = QToolButton(self.widget_9) - self.btn_member.setObjectName(u"btn_member") - self.btn_member.setStyleSheet(u"color: rgb(255, 255, 255);") - self.btn_member.setAutoRaise(True) - - self.horizontalLayout_12.addWidget(self.btn_member) - - self.horizontalSpacer_10 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_12.addItem(self.horizontalSpacer_10) - - - self.verticalLayout_11.addLayout(self.horizontalLayout_12) - - self.horizontalLayout_13 = QHBoxLayout() - self.horizontalLayout_13.setSpacing(0) - self.horizontalLayout_13.setObjectName(u"horizontalLayout_13") - self.toolButton_9 = QToolButton(self.widget_9) - self.toolButton_9.setObjectName(u"toolButton_9") - icon6 = QIcon() - icon6.addFile(u":/color/theme/default/icons/donate.svg", QSize(), QIcon.Normal, QIcon.Off) - self.toolButton_9.setIcon(icon6) - self.toolButton_9.setIconSize(QSize(18, 18)) - - self.horizontalLayout_13.addWidget(self.toolButton_9) - - self.btn_donate = QToolButton(self.widget_9) - self.btn_donate.setObjectName(u"btn_donate") - self.btn_donate.setStyleSheet(u"color: rgb(255, 255, 255);") - self.btn_donate.setAutoRaise(True) - - self.horizontalLayout_13.addWidget(self.btn_donate) - - self.horizontalSpacer_9 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_13.addItem(self.horizontalSpacer_9) - - - self.verticalLayout_11.addLayout(self.horizontalLayout_13) - - - self.verticalLayout_9.addWidget(self.widget_9) - - - self.horizontalLayout_2.addLayout(self.verticalLayout_9) - - - self.verticalLayout.addWidget(self.widget) - - - self.retranslateUi(Form) - - QMetaObject.connectSlotsByName(Form) - # setupUi - - def retranslateUi(self, Form): - Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None)) - self.label_3.setText("") - self.label_24.setText("") - self.label_23.setText(QCoreApplication.translate("Form", u"Open File", None)) - self.toolButton_2.setText(QCoreApplication.translate("Form", u"...", None)) - self.btn_open_python.setText(QCoreApplication.translate("Form", u"Python File", None)) - self.toolButton_3.setText(QCoreApplication.translate("Form", u"...", None)) - self.btn_open_csv.setText(QCoreApplication.translate("Form", u"CSV File", None)) - self.toolButton_4.setText(QCoreApplication.translate("Form", u"...", None)) - self.btn_open_excel.setText(QCoreApplication.translate("Form", u"Excel File", None)) - self.toolButton_10.setText(QCoreApplication.translate("Form", u"...", None)) - self.btn_open_matlab.setText(QCoreApplication.translate("Form", u"MATLAB File", None)) - self.toolButton.setText(QCoreApplication.translate("Form", u"...", None)) - self.btn_open_folder.setText(QCoreApplication.translate("Form", u"Open Folder...", None)) - self.label_25.setText("") - self.label_26.setText(QCoreApplication.translate("Form", u"Quick Start", None)) - self.toolButton_5.setText(QCoreApplication.translate("Form", u"...", None)) - self.btn_manual.setText(QCoreApplication.translate("Form", u"Use Manual", None)) - self.toolButton_6.setText(QCoreApplication.translate("Form", u"...", None)) - self.btn_website.setText(QCoreApplication.translate("Form", u"Official Site", None)) - self.toolButton_7.setText(QCoreApplication.translate("Form", u"...", None)) - self.btn_source.setText(QCoreApplication.translate("Form", u"Gitee Repo", None)) - self.toolButton_8.setText(QCoreApplication.translate("Form", u"...", None)) - self.btn_member.setText(QCoreApplication.translate("Form", u"Join Us", None)) - self.toolButton_9.setText(QCoreApplication.translate("Form", u"...", None)) - self.btn_donate.setText(QCoreApplication.translate("Form", u"Donate", None)) - # retranslateUi - diff --git a/pyminer/features/ui/ui_first_form.ui b/pyminer/features/ui/ui_first_form.ui deleted file mode 100644 index dfa8c2bf..00000000 --- a/pyminer/features/ui/ui_first_form.ui +++ /dev/null @@ -1,788 +0,0 @@ - - - Form - - - - 0 - 0 - 620 - 580 - - - - - 620 - 580 - - - - - 620 - 580 - - - - Form - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - Consolas - 28 - - - - - - - :/images/images/bg.png - - - true - - - - - - - - - - - 0 - 270 - - - - - 16777215 - 270 - - - - background-color: rgb(33, 33, 33); - - - - - - 5 - - - 0 - - - - - 0 - - - - - - 20 - 0 - - - - - 20 - 16777215 - - - - - 9 - - - - color: rgb(229, 229, 229); - - - - - - - - - - - 9 - - - - color: rgb(229, 229, 229); - - - Open File - - - - - - - - - - 300 - 0 - - - - - - - 0 - - - - - ... - - - - :/color/theme/default/icons/python.svg:/color/theme/default/icons/python.svg - - - - 18 - 18 - - - - - - - - color: rgb(255, 255, 255); - - - Python File - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - - - - - ... - - - - :/color/theme/default/icons/csv.svg:/color/theme/default/icons/csv.svg - - - - 18 - 18 - - - - - - - - color: rgb(255, 255, 255); - - - CSV File - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - - - - - ... - - - - :/color/theme/default/icons/excel.svg:/color/theme/default/icons/excel.svg - - - - 18 - 18 - - - - - - - - color: rgb(255, 255, 255); - - - Excel File - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - - - - - ... - - - - :/color/theme/default/icons/E-matlab.svg:/color/theme/default/icons/E-matlab.svg - - - - 18 - 18 - - - - - - - - color: rgb(255, 255, 255); - - - MATLAB File - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - 0 - - - - - ... - - - - :/color/theme/default/icons/open_folder.svg:/color/theme/default/icons/open_folder.svg - - - - 18 - 18 - - - - - - - - color: rgb(255, 255, 255); - - - Open Folder... - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - 5 - - - 0 - - - - - 0 - - - - - - 20 - 0 - - - - - 20 - 16777215 - - - - - 9 - - - - color: rgb(229, 229, 229); - - - - - - - - - - - 9 - - - - color: rgb(229, 229, 229); - - - Quick Start - - - - - - - - - - - - 0 - - - - - ... - - - - :/color/theme/default/icons/website.svg:/color/theme/default/icons/website.svg - - - - 18 - 18 - - - - - - - - color: rgb(255, 255, 255); - - - Use Manual - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - - - - - ... - - - - :/color/theme/default/icons/website.svg:/color/theme/default/icons/website.svg - - - - 18 - 18 - - - - - - - - color: rgb(255, 255, 255); - - - Official Site - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - - - - - ... - - - - :/color/theme/default/icons/website.svg:/color/theme/default/icons/website.svg - - - - 18 - 18 - - - - - - - - color: rgb(255, 255, 255); - - - Gitee Repo - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - 0 - - - - - ... - - - - :/color/theme/default/icons/website.svg:/color/theme/default/icons/website.svg - - - - 18 - 18 - - - - - - - - color: rgb(255, 255, 255); - - - Join Us - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - - - - - ... - - - - :/color/theme/default/icons/donate.svg:/color/theme/default/icons/donate.svg - - - - 18 - 18 - - - - - - - - color: rgb(255, 255, 255); - - - Donate - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - - - - - diff --git a/pyminer/features/ui/ui_login.py b/pyminer/features/ui/ui_login.py deleted file mode 100644 index 843dd6ab..00000000 --- a/pyminer/features/ui/ui_login.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'ui_login.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - - -class Ui_Form(object): - def setupUi(self, Form): - if not Form.objectName(): - Form.setObjectName(u"Form") - Form.setWindowModality(Qt.ApplicationModal) - Form.resize(407, 361) - sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth()) - Form.setSizePolicy(sizePolicy) - Form.setMinimumSize(QSize(407, 361)) - Form.setMaximumSize(QSize(407, 361)) - Form.setStyleSheet(u"") - self.verticalLayout = QVBoxLayout(Form) - self.verticalLayout.setObjectName(u"verticalLayout") - self.widget = QWidget(Form) - self.widget.setObjectName(u"widget") - self.widget.setMaximumSize(QSize(407, 361)) - self.widget.setSizeIncrement(QSize(407, 361)) - self.widget.setBaseSize(QSize(407, 361)) - self.widget.setStyleSheet(u"QPushButton{\n" -" padding: 8px 20px;\n" -" font-size: 13px;\n" -" line-height: 1.65;\n" -" border-radius: 20px;\n" -" display: inline-block;\n" -" margin-bottom: 0;\n" -" font-weight: 600;\n" -" text-align: center;\n" -" vertical-align: middle;\n" -" touch-action: manipulation;\n" -" cursor: pointer;\n" -" background-image: none;\n" -" border: 1px solid transparent;\n" -" white-space: nowrap;\n" -" font-family: inherit;\n" -" text-transform: none;\n" -" background-color: #00a6fd;\n" -" border-color: #00a6fd;\n" -" color: #fff;\n" -" \n" -"}") - self.layoutWidget = QWidget(self.widget) - self.layoutWidget.setObjectName(u"layoutWidget") - self.layoutWidget.setGeometry(QRect(0, 0, 452, 331)) - self.verticalLayout_2 = QVBoxLayout(self.layoutWidget) - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) - self.verticalLayout_6 = QVBoxLayout() - self.verticalLayout_6.setObjectName(u"verticalLayout_6") - self.usernameError = QLabel(self.layoutWidget) - self.usernameError.setObjectName(u"usernameError") - self.usernameError.setEnabled(True) - self.usernameError.setMinimumSize(QSize(380, 32)) - self.usernameError.setMaximumSize(QSize(380, 32)) - font = QFont() - font.setFamily(u"18thCentury") - font.setPointSize(10) - font.setBold(False) - font.setWeight(50) - self.usernameError.setFont(font) - self.usernameError.setAutoFillBackground(False) - self.usernameError.setStyleSheet(u"*{\n" -"color:red;\n" -"}") - self.usernameError.setAlignment(Qt.AlignCenter) - - self.verticalLayout_6.addWidget(self.usernameError) - - self.horizontalLayout_2 = QHBoxLayout() - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.label = QLabel(self.layoutWidget) - self.label.setObjectName(u"label") - self.label.setMinimumSize(QSize(70, 0)) - self.label.setMaximumSize(QSize(70, 16777215)) - self.label.setBaseSize(QSize(70, 0)) - self.label.setAlignment(Qt.AlignCenter) - - self.horizontalLayout_2.addWidget(self.label) - - self.usernameLineEdit = QLineEdit(self.layoutWidget) - self.usernameLineEdit.setObjectName(u"usernameLineEdit") - self.usernameLineEdit.setMinimumSize(QSize(300, 32)) - self.usernameLineEdit.setMaximumSize(QSize(300, 32)) - self.usernameLineEdit.setStyleSheet(u"QLineEdit{\n" -"background-color: white;\n" -"selection-color: white;\n" -"selection-background-color: blue;\n" -"}") - self.usernameLineEdit.setMaxLength(64) - - self.horizontalLayout_2.addWidget(self.usernameLineEdit) - - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_2.addItem(self.horizontalSpacer) - - - self.verticalLayout_6.addLayout(self.horizontalLayout_2) - - self.passwordError = QLabel(self.layoutWidget) - self.passwordError.setObjectName(u"passwordError") - self.passwordError.setMinimumSize(QSize(380, 32)) - self.passwordError.setMaximumSize(QSize(380, 32)) - self.passwordError.setFont(font) - self.passwordError.setStyleSheet(u"*{\n" -"color:red;\n" -"}") - self.passwordError.setAlignment(Qt.AlignCenter) - - self.verticalLayout_6.addWidget(self.passwordError) - - self.horizontalLayout_3 = QHBoxLayout() - self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.label_2 = QLabel(self.layoutWidget) - self.label_2.setObjectName(u"label_2") - self.label_2.setMinimumSize(QSize(70, 0)) - self.label_2.setMaximumSize(QSize(70, 16777215)) - self.label_2.setBaseSize(QSize(70, 0)) - self.label_2.setAlignment(Qt.AlignCenter) - - self.horizontalLayout_3.addWidget(self.label_2) - - self.passwordLineEdit = QLineEdit(self.layoutWidget) - self.passwordLineEdit.setObjectName(u"passwordLineEdit") - self.passwordLineEdit.setMinimumSize(QSize(300, 0)) - self.passwordLineEdit.setMaximumSize(QSize(300, 32)) - self.passwordLineEdit.setBaseSize(QSize(300, 32)) - self.passwordLineEdit.setStyleSheet(u"QLineEdit{\n" -"background-color: white;\n" -"selection-color: white;\n" -"selection-background-color: blue;\n" -"}") - self.passwordLineEdit.setEchoMode(QLineEdit.Password) - - self.horizontalLayout_3.addWidget(self.passwordLineEdit) - - self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_3.addItem(self.horizontalSpacer_2) - - - self.verticalLayout_6.addLayout(self.horizontalLayout_3) - - - self.verticalLayout_2.addLayout(self.verticalLayout_6) - - self.horizontalLayout = QHBoxLayout() - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.loginButton = QPushButton(self.layoutWidget) - self.loginButton.setObjectName(u"loginButton") - self.loginButton.setMaximumSize(QSize(150, 16777215)) - self.loginButton.setCursor(QCursor(Qt.PointingHandCursor)) - self.loginButton.setStyleSheet(u"") - - self.horizontalLayout.addWidget(self.loginButton) - - self.forgetPwdButton = QPushButton(self.layoutWidget) - self.forgetPwdButton.setObjectName(u"forgetPwdButton") - self.forgetPwdButton.setMaximumSize(QSize(150, 16777215)) - self.forgetPwdButton.setCursor(QCursor(Qt.PointingHandCursor)) - - self.horizontalLayout.addWidget(self.forgetPwdButton) - - - self.verticalLayout_2.addLayout(self.horizontalLayout) - - - self.verticalLayout.addWidget(self.widget) - - - self.retranslateUi(Form) - - QMetaObject.connectSlotsByName(Form) - # setupUi - - def retranslateUi(self, Form): - Form.setWindowTitle(QCoreApplication.translate("Form", u"\u7528\u6237\u767b\u5f55", None)) - self.usernameError.setText("") - self.label.setText(QCoreApplication.translate("Form", u"\u7528 \u6237 \u540d", None)) - self.usernameLineEdit.setPlaceholderText(QCoreApplication.translate("Form", u"\u8bf7\u8f93\u5165\u7528\u6237\u540d", None)) - self.passwordError.setText("") - self.label_2.setText(QCoreApplication.translate("Form", u"\u5bc6 \u7801", None)) - self.passwordLineEdit.setPlaceholderText(QCoreApplication.translate("Form", u"\u8bf7\u8f93\u5165\u5bc6\u7801", None)) - self.loginButton.setText(QCoreApplication.translate("Form", u"\u767b\u5f55", None)) - self.forgetPwdButton.setText(QCoreApplication.translate("Form", u"\u5fd8\u8bb0\u5bc6\u7801\uff1f", None)) - # retranslateUi - diff --git a/pyminer/features/ui/ui_login.ui b/pyminer/features/ui/ui_login.ui deleted file mode 100644 index 290a39b5..00000000 --- a/pyminer/features/ui/ui_login.ui +++ /dev/null @@ -1,376 +0,0 @@ - - - Form - - - Qt::ApplicationModal - - - - 0 - 0 - 407 - 361 - - - - - 0 - 0 - - - - - 407 - 361 - - - - - 407 - 361 - - - - 用户登录 - - - - - - - - - - 407 - 361 - - - - - 407 - 361 - - - - - 407 - 361 - - - - QPushButton{ - padding: 8px 20px; - font-size: 13px; - line-height: 1.65; - border-radius: 20px; - display: inline-block; - margin-bottom: 0; - font-weight: 600; - text-align: center; - vertical-align: middle; - touch-action: manipulation; - cursor: pointer; - background-image: none; - border: 1px solid transparent; - white-space: nowrap; - font-family: inherit; - text-transform: none; - background-color: #00a6fd; - border-color: #00a6fd; - color: #fff; - -} - - - - - 0 - 0 - 452 - 331 - - - - - - - - - true - - - - 380 - 32 - - - - - 380 - 32 - - - - - 18thCentury - 10 - 50 - false - - - - false - - - *{ -color:red; -} - - - - - - Qt::AlignCenter - - - - - - - - - - 70 - 0 - - - - - 70 - 16777215 - - - - - 70 - 0 - - - - 用 户 名 - - - Qt::AlignCenter - - - - - - - - 300 - 32 - - - - - 300 - 32 - - - - QLineEdit{ -background-color: white; -selection-color: white; -selection-background-color: blue; -} - - - 64 - - - 请输入用户名 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 380 - 32 - - - - - 380 - 32 - - - - - 18thCentury - 10 - 50 - false - - - - *{ -color:red; -} - - - - - - Qt::AlignCenter - - - - - - - - - - 70 - 0 - - - - - 70 - 16777215 - - - - - 70 - 0 - - - - 密 码 - - - Qt::AlignCenter - - - - - - - - 300 - 0 - - - - - 300 - 32 - - - - - 300 - 32 - - - - QLineEdit{ -background-color: white; -selection-color: white; -selection-background-color: blue; -} - - - QLineEdit::Password - - - 请输入密码 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - 150 - 16777215 - - - - PointingHandCursor - - - - - - 登录 - - - - - - - - 150 - 16777215 - - - - PointingHandCursor - - - 忘记密码? - - - - - - - - - - - - - - diff --git a/pyminer/features/ui/ui_logined.py b/pyminer/features/ui/ui_logined.py deleted file mode 100644 index 8d469fb4..00000000 --- a/pyminer/features/ui/ui_logined.py +++ /dev/null @@ -1,112 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'ui_logined.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - - -class Ui_Form(object): - def setupUi(self, Form): - if not Form.objectName(): - Form.setObjectName(u"Form") - Form.resize(407, 361) - Form.setMinimumSize(QSize(407, 361)) - Form.setMaximumSize(QSize(407, 361)) - Form.setBaseSize(QSize(407, 361)) - Form.setStyleSheet(u"QPushButton{\n" -" padding: 8px 20px;\n" -" font-size: 13px;\n" -" line-height: 1.65;\n" -" border-radius: 20px;\n" -" display: inline-block;\n" -" margin-bottom: 0;\n" -" font-weight: 600;\n" -" text-align: center;\n" -" vertical-align: middle;\n" -" touch-action: manipulation;\n" -" cursor: pointer;\n" -" background-image: none;\n" -" border: 1px solid transparent;\n" -" white-space: nowrap;\n" -" font-family: inherit;\n" -" text-transform: none;\n" -" background-color: #00a6fd;\n" -" border-color: #00a6fd;\n" -" color: #fff;\n" -" \n" -"}") - self.layoutWidget = QWidget(Form) - self.layoutWidget.setObjectName(u"layoutWidget") - self.layoutWidget.setGeometry(QRect(10, 0, 391, 341)) - self.verticalLayout = QVBoxLayout(self.layoutWidget) - self.verticalLayout.setObjectName(u"verticalLayout") - self.verticalLayout.setContentsMargins(0, 0, 0, 0) - self.horizontalLayout = QHBoxLayout() - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.label = QLabel(self.layoutWidget) - self.label.setObjectName(u"label") - self.label.setFrameShape(QFrame.NoFrame) - self.label.setFrameShadow(QFrame.Plain) - self.label.setTextFormat(Qt.AutoText) - self.label.setAlignment(Qt.AlignCenter) - self.label.setMargin(0) - - self.horizontalLayout.addWidget(self.label) - - self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.horizontalLayout.addItem(self.verticalSpacer_2) - - self.usernameLabel = QLabel(self.layoutWidget) - self.usernameLabel.setObjectName(u"usernameLabel") - self.usernameLabel.setCursor(QCursor(Qt.IBeamCursor)) - self.usernameLabel.setLayoutDirection(Qt.LeftToRight) - self.usernameLabel.setWordWrap(True) - self.usernameLabel.setMargin(0) - self.usernameLabel.setTextInteractionFlags(Qt.TextSelectableByMouse) - - self.horizontalLayout.addWidget(self.usernameLabel) - - - self.verticalLayout.addLayout(self.horizontalLayout) - - self.horizontalLayout_2 = QHBoxLayout() - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_2.addItem(self.horizontalSpacer) - - self.loginOutButton = QPushButton(self.layoutWidget) - self.loginOutButton.setObjectName(u"loginOutButton") - self.loginOutButton.setCursor(QCursor(Qt.PointingHandCursor)) - - self.horizontalLayout_2.addWidget(self.loginOutButton) - - self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.horizontalLayout_2.addItem(self.verticalSpacer) - - - self.verticalLayout.addLayout(self.horizontalLayout_2) - - - self.retranslateUi(Form) - - QMetaObject.connectSlotsByName(Form) - # setupUi - - def retranslateUi(self, Form): - Form.setWindowTitle(QCoreApplication.translate("Form", u"\u7528\u6237\u4fe1\u606f", None)) - self.label.setText(QCoreApplication.translate("Form", u"\u7528 \u6237 \u540d", None)) - self.usernameLabel.setText("") - self.loginOutButton.setText(QCoreApplication.translate("Form", u"\u6ce8 \u9500", None)) - # retranslateUi - diff --git a/pyminer/features/ui/ui_logined.ui b/pyminer/features/ui/ui_logined.ui deleted file mode 100644 index 45a4af71..00000000 --- a/pyminer/features/ui/ui_logined.ui +++ /dev/null @@ -1,174 +0,0 @@ - - - Form - - - - 0 - 0 - 407 - 361 - - - - - 407 - 361 - - - - - 407 - 361 - - - - - 407 - 361 - - - - 用户信息 - - - QPushButton{ - padding: 8px 20px; - font-size: 13px; - line-height: 1.65; - border-radius: 20px; - display: inline-block; - margin-bottom: 0; - font-weight: 600; - text-align: center; - vertical-align: middle; - touch-action: manipulation; - cursor: pointer; - background-image: none; - border: 1px solid transparent; - white-space: nowrap; - font-family: inherit; - text-transform: none; - background-color: #00a6fd; - border-color: #00a6fd; - color: #fff; - -} - - - - - 10 - 0 - 391 - 341 - - - - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - 用 户 名 - - - Qt::AutoText - - - Qt::AlignCenter - - - 0 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - IBeamCursor - - - Qt::LeftToRight - - - - - - true - - - 0 - - - Qt::TextSelectableByMouse - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - PointingHandCursor - - - 注 销 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - diff --git a/pyminer/features/ui/ui_option.py b/pyminer/features/ui/ui_option.py deleted file mode 100644 index 7340b217..00000000 --- a/pyminer/features/ui/ui_option.py +++ /dev/null @@ -1,441 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'ui_option.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - - -class Ui_Form(object): - def setupUi(self, Form): - if not Form.objectName(): - Form.setObjectName(u"Form") - Form.resize(705, 515) - self.verticalLayout_2 = QVBoxLayout(Form) - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.splitter = QSplitter(Form) - self.splitter.setObjectName(u"splitter") - self.splitter.setOrientation(Qt.Horizontal) - self.listWidget = QListWidget(self.splitter) - QListWidgetItem(self.listWidget) - QListWidgetItem(self.listWidget) - QListWidgetItem(self.listWidget) - self.listWidget.setObjectName(u"listWidget") - self.listWidget.setMaximumSize(QSize(200, 16777215)) - self.splitter.addWidget(self.listWidget) - self.stackedWidget = QStackedWidget(self.splitter) - self.stackedWidget.setObjectName(u"stackedWidget") - self.page_general = QWidget() - self.page_general.setObjectName(u"page_general") - self.horizontalLayout_3 = QHBoxLayout(self.page_general) - self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0) - self.tabWidget = QTabWidget(self.page_general) - self.tabWidget.setObjectName(u"tabWidget") - self.tabWidget.setTabPosition(QTabWidget.North) - self.tabBase = QWidget() - self.tabBase.setObjectName(u"tabBase") - self.verticalLayout_8 = QVBoxLayout(self.tabBase) - self.verticalLayout_8.setObjectName(u"verticalLayout_8") - self.formLayout_2 = QFormLayout() - self.formLayout_2.setObjectName(u"formLayout_2") - self.label_theme = QLabel(self.tabBase) - self.label_theme.setObjectName(u"label_theme") - - self.formLayout_2.setWidget(0, QFormLayout.LabelRole, self.label_theme) - - self.comboBox_theme = QComboBox(self.tabBase) - self.comboBox_theme.addItem("") - self.comboBox_theme.addItem("") - self.comboBox_theme.addItem("") - self.comboBox_theme.addItem("") - self.comboBox_theme.setObjectName(u"comboBox_theme") - - self.formLayout_2.setWidget(0, QFormLayout.FieldRole, self.comboBox_theme) - - self.label = QLabel(self.tabBase) - self.label.setObjectName(u"label") - - self.formLayout_2.setWidget(1, QFormLayout.LabelRole, self.label) - - self.horizontalLayout_14 = QHBoxLayout() - self.horizontalLayout_14.setObjectName(u"horizontalLayout_14") - self.lineEdit_worksapce = QLineEdit(self.tabBase) - self.lineEdit_worksapce.setObjectName(u"lineEdit_worksapce") - - self.horizontalLayout_14.addWidget(self.lineEdit_worksapce) - - self.toolButton_workspace = QToolButton(self.tabBase) - self.toolButton_workspace.setObjectName(u"toolButton_workspace") - - self.horizontalLayout_14.addWidget(self.toolButton_workspace) - - - self.formLayout_2.setLayout(1, QFormLayout.FieldRole, self.horizontalLayout_14) - - self.label_15 = QLabel(self.tabBase) - self.label_15.setObjectName(u"label_15") - - self.formLayout_2.setWidget(2, QFormLayout.LabelRole, self.label_15) - - self.horizontalLayout_15 = QHBoxLayout() - self.horizontalLayout_15.setObjectName(u"horizontalLayout_15") - self.lineEdit_output = QLineEdit(self.tabBase) - self.lineEdit_output.setObjectName(u"lineEdit_output") - - self.horizontalLayout_15.addWidget(self.lineEdit_output) - - self.toolButton_output = QToolButton(self.tabBase) - self.toolButton_output.setObjectName(u"toolButton_output") - - self.horizontalLayout_15.addWidget(self.toolButton_output) - - - self.formLayout_2.setLayout(2, QFormLayout.FieldRole, self.horizontalLayout_15) - - self.label_16 = QLabel(self.tabBase) - self.label_16.setObjectName(u"label_16") - - self.formLayout_2.setWidget(3, QFormLayout.LabelRole, self.label_16) - - self.comboBox_9 = QComboBox(self.tabBase) - self.comboBox_9.addItem("") - self.comboBox_9.addItem("") - self.comboBox_9.setObjectName(u"comboBox_9") - - self.formLayout_2.setWidget(3, QFormLayout.FieldRole, self.comboBox_9) - - self.label_11 = QLabel(self.tabBase) - self.label_11.setObjectName(u"label_11") - - self.formLayout_2.setWidget(4, QFormLayout.LabelRole, self.label_11) - - self.comboBox_8 = QComboBox(self.tabBase) - self.comboBox_8.addItem("") - self.comboBox_8.addItem("") - self.comboBox_8.setObjectName(u"comboBox_8") - - self.formLayout_2.setWidget(4, QFormLayout.FieldRole, self.comboBox_8) - - self.check_box_check_upd_on_startup = QCheckBox(self.tabBase) - self.check_box_check_upd_on_startup.setObjectName(u"check_box_check_upd_on_startup") - self.check_box_check_upd_on_startup.setChecked(True) - - self.formLayout_2.setWidget(5, QFormLayout.LabelRole, self.check_box_check_upd_on_startup) - - self.checkbox_show_startpage = QCheckBox(self.tabBase) - self.checkbox_show_startpage.setObjectName(u"checkbox_show_startpage") - self.checkbox_show_startpage.setChecked(True) - - self.formLayout_2.setWidget(6, QFormLayout.LabelRole, self.checkbox_show_startpage) - - - self.verticalLayout_8.addLayout(self.formLayout_2) - - self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.verticalLayout_8.addItem(self.verticalSpacer_2) - - self.tabWidget.addTab(self.tabBase, "") - - self.horizontalLayout_3.addWidget(self.tabWidget) - - self.stackedWidget.addWidget(self.page_general) - self.page_appearance = QWidget() - self.page_appearance.setObjectName(u"page_appearance") - self.verticalLayout_6 = QVBoxLayout(self.page_appearance) - self.verticalLayout_6.setObjectName(u"verticalLayout_6") - self.verticalLayout_5 = QVBoxLayout() - self.verticalLayout_5.setObjectName(u"verticalLayout_5") - self.checkBox_3 = QCheckBox(self.page_appearance) - self.checkBox_3.setObjectName(u"checkBox_3") - self.checkBox_3.setChecked(True) - - self.verticalLayout_5.addWidget(self.checkBox_3) - - self.horizontalLayout_11 = QHBoxLayout() - self.horizontalLayout_11.setObjectName(u"horizontalLayout_11") - self.label_10 = QLabel(self.page_appearance) - self.label_10.setObjectName(u"label_10") - - self.horizontalLayout_11.addWidget(self.label_10) - - self.pushButton = QPushButton(self.page_appearance) - self.pushButton.setObjectName(u"pushButton") - - self.horizontalLayout_11.addWidget(self.pushButton) - - self.horizontalSpacer_4 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_11.addItem(self.horizontalSpacer_4) - - - self.verticalLayout_5.addLayout(self.horizontalLayout_11) - - - self.verticalLayout_6.addLayout(self.verticalLayout_5) - - self.horizontalLayout_6 = QHBoxLayout() - self.horizontalLayout_6.setObjectName(u"horizontalLayout_6") - - self.verticalLayout_6.addLayout(self.horizontalLayout_6) - - self.horizontalLayout_5 = QHBoxLayout() - self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") - self.label_3 = QLabel(self.page_appearance) - self.label_3.setObjectName(u"label_3") - - self.horizontalLayout_5.addWidget(self.label_3) - - self.lineEdit_2 = QLineEdit(self.page_appearance) - self.lineEdit_2.setObjectName(u"lineEdit_2") - self.lineEdit_2.setMaximumSize(QSize(60, 16777215)) - - self.horizontalLayout_5.addWidget(self.lineEdit_2) - - self.horizontalSpacer_3 = QSpacerItem(120, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_5.addItem(self.horizontalSpacer_3) - - - self.verticalLayout_6.addLayout(self.horizontalLayout_5) - - self.horizontalLayout_4 = QHBoxLayout() - self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") - self.label_2 = QLabel(self.page_appearance) - self.label_2.setObjectName(u"label_2") - - self.horizontalLayout_4.addWidget(self.label_2) - - self.comboBox = QComboBox(self.page_appearance) - self.comboBox.addItem("") - self.comboBox.setObjectName(u"comboBox") - - self.horizontalLayout_4.addWidget(self.comboBox) - - self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_4.addItem(self.horizontalSpacer_2) - - - self.verticalLayout_6.addLayout(self.horizontalLayout_4) - - self.textEdit = QTextEdit(self.page_appearance) - self.textEdit.setObjectName(u"textEdit") - self.textEdit.setMaximumSize(QSize(16777215, 16777215)) - - self.verticalLayout_6.addWidget(self.textEdit) - - self.stackedWidget.addWidget(self.page_appearance) - self.page_format = QWidget() - self.page_format.setObjectName(u"page_format") - self.verticalLayout_3 = QVBoxLayout(self.page_format) - self.verticalLayout_3.setObjectName(u"verticalLayout_3") - self.formLayout = QFormLayout() - self.formLayout.setObjectName(u"formLayout") - self.label_4 = QLabel(self.page_format) - self.label_4.setObjectName(u"label_4") - - self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label_4) - - self.comboBox_2 = QComboBox(self.page_format) - self.comboBox_2.addItem("") - self.comboBox_2.addItem("") - self.comboBox_2.addItem("") - self.comboBox_2.setObjectName(u"comboBox_2") - - self.formLayout.setWidget(0, QFormLayout.FieldRole, self.comboBox_2) - - self.comboBox_3 = QComboBox(self.page_format) - self.comboBox_3.addItem("") - self.comboBox_3.addItem("") - self.comboBox_3.addItem("") - self.comboBox_3.setObjectName(u"comboBox_3") - - self.formLayout.setWidget(1, QFormLayout.FieldRole, self.comboBox_3) - - self.label_5 = QLabel(self.page_format) - self.label_5.setObjectName(u"label_5") - - self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_5) - - self.comboBox_4 = QComboBox(self.page_format) - self.comboBox_4.addItem("") - self.comboBox_4.addItem("") - self.comboBox_4.addItem("") - self.comboBox_4.setObjectName(u"comboBox_4") - - self.formLayout.setWidget(2, QFormLayout.FieldRole, self.comboBox_4) - - self.label_6 = QLabel(self.page_format) - self.label_6.setObjectName(u"label_6") - - self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_6) - - self.comboBox_5 = QComboBox(self.page_format) - self.comboBox_5.addItem("") - self.comboBox_5.addItem("") - self.comboBox_5.addItem("") - self.comboBox_5.addItem("") - self.comboBox_5.setObjectName(u"comboBox_5") - - self.formLayout.setWidget(3, QFormLayout.FieldRole, self.comboBox_5) - - self.label_7 = QLabel(self.page_format) - self.label_7.setObjectName(u"label_7") - - self.formLayout.setWidget(3, QFormLayout.LabelRole, self.label_7) - - self.comboBox_6 = QComboBox(self.page_format) - self.comboBox_6.addItem("") - self.comboBox_6.addItem("") - self.comboBox_6.setObjectName(u"comboBox_6") - - self.formLayout.setWidget(4, QFormLayout.FieldRole, self.comboBox_6) - - self.label_8 = QLabel(self.page_format) - self.label_8.setObjectName(u"label_8") - - self.formLayout.setWidget(4, QFormLayout.LabelRole, self.label_8) - - - self.verticalLayout_3.addLayout(self.formLayout) - - self.stackedWidget.addWidget(self.page_format) - self.splitter.addWidget(self.stackedWidget) - - self.verticalLayout_2.addWidget(self.splitter) - - self.widget = QWidget(Form) - self.widget.setObjectName(u"widget") - self.widget.setMaximumSize(QSize(16777215, 50)) - self.horizontalLayout_7 = QHBoxLayout(self.widget) - self.horizontalLayout_7.setObjectName(u"horizontalLayout_7") - self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0) - self.horizontalLayout = QHBoxLayout() - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.pushButton_help = QPushButton(self.widget) - self.pushButton_help.setObjectName(u"pushButton_help") - - self.horizontalLayout.addWidget(self.pushButton_help) - - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout.addItem(self.horizontalSpacer) - - self.pushButton_ok = QPushButton(self.widget) - self.pushButton_ok.setObjectName(u"pushButton_ok") - - self.horizontalLayout.addWidget(self.pushButton_ok) - - self.pushButton_cancel = QPushButton(self.widget) - self.pushButton_cancel.setObjectName(u"pushButton_cancel") - - self.horizontalLayout.addWidget(self.pushButton_cancel) - - - self.horizontalLayout_7.addLayout(self.horizontalLayout) - - - self.verticalLayout_2.addWidget(self.widget) - - - self.retranslateUi(Form) - - self.stackedWidget.setCurrentIndex(0) - self.tabWidget.setCurrentIndex(0) - - - QMetaObject.connectSlotsByName(Form) - # setupUi - - def retranslateUi(self, Form): - Form.setWindowTitle(QCoreApplication.translate("Form", u"Settings", None)) - - __sortingEnabled = self.listWidget.isSortingEnabled() - self.listWidget.setSortingEnabled(False) - ___qlistwidgetitem = self.listWidget.item(0) - ___qlistwidgetitem.setText(QCoreApplication.translate("Form", u"\u5e38\u89c4", None)); - ___qlistwidgetitem1 = self.listWidget.item(1) - ___qlistwidgetitem1.setText(QCoreApplication.translate("Form", u"\u5916\u89c2", None)); - ___qlistwidgetitem2 = self.listWidget.item(2) - ___qlistwidgetitem2.setText(QCoreApplication.translate("Form", u"\u683c\u5f0f\u5316", None)); - self.listWidget.setSortingEnabled(__sortingEnabled) - - self.label_theme.setText(QCoreApplication.translate("Form", u"UI Theme", None)) - self.comboBox_theme.setItemText(0, QCoreApplication.translate("Form", u"Fusion", None)) - self.comboBox_theme.setItemText(1, QCoreApplication.translate("Form", u"Qdarkstyle", None)) - self.comboBox_theme.setItemText(2, QCoreApplication.translate("Form", u"windowsvista", None)) - self.comboBox_theme.setItemText(3, QCoreApplication.translate("Form", u"Windows", None)) - - self.label.setText(QCoreApplication.translate("Form", u"Work Directory", None)) - self.toolButton_workspace.setText(QCoreApplication.translate("Form", u"...", None)) - self.label_15.setText(QCoreApplication.translate("Form", u"Output Directory", None)) - self.toolButton_output.setText(QCoreApplication.translate("Form", u"...", None)) - self.label_16.setText(QCoreApplication.translate("Form", u"UI Language", None)) - self.comboBox_9.setItemText(0, QCoreApplication.translate("Form", u"\u7b80\u4f53\u4e2d\u6587", None)) - self.comboBox_9.setItemText(1, QCoreApplication.translate("Form", u"English", None)) - - self.label_11.setText(QCoreApplication.translate("Form", u"Encoding", None)) - self.comboBox_8.setItemText(0, QCoreApplication.translate("Form", u"utf-8", None)) - self.comboBox_8.setItemText(1, QCoreApplication.translate("Form", u"gb2312", None)) - - self.check_box_check_upd_on_startup.setText(QCoreApplication.translate("Form", u"Check upd on startup", None)) - self.checkbox_show_startpage.setText(QCoreApplication.translate("Form", u"\u663e\u793a\u8d77\u59cb\u9875\u9762", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabBase), QCoreApplication.translate("Form", u"Basic", None)) - self.checkBox_3.setText(QCoreApplication.translate("Form", u"Interlaced coloring", None)) - self.label_10.setText(QCoreApplication.translate("Form", u"Table Header Background:", None)) - self.pushButton.setText(QCoreApplication.translate("Form", u"Color", None)) - self.label_3.setText(QCoreApplication.translate("Form", u"Size:", None)) - self.lineEdit_2.setText(QCoreApplication.translate("Form", u"15", None)) - self.label_2.setText(QCoreApplication.translate("Form", u"Font:", None)) - self.comboBox.setItemText(0, QCoreApplication.translate("Form", u"Source Code Pro", None)) - - self.textEdit.setHtml(QCoreApplication.translate("Form", u"\n" -"\n" -"

Patata is a full-featured IDE

\n" -"

with a high level of usability and outstanding

\n" -"

advanced code editing and refactoring support.

\n" -"


\n" -"

abcdefghijklmnopqrstuvwxyz 0123456789 (){}[]

\n" -"

ABCDEFGHIJKLMNOPQRSTUVWXYZ +-*/= .,;:!? #&$%@|^

", None)) - self.label_4.setText(QCoreApplication.translate("Form", u"\u65e5\u671f\u683c\u5f0f:", None)) - self.comboBox_2.setItemText(0, QCoreApplication.translate("Form", u"2020-01-01", None)) - self.comboBox_2.setItemText(1, QCoreApplication.translate("Form", u"2020/01/01", None)) - self.comboBox_2.setItemText(2, "") - - self.comboBox_3.setItemText(0, QCoreApplication.translate("Form", u"15:30:01(24-\u5c0f\u65f6\u5236)", None)) - self.comboBox_3.setItemText(1, QCoreApplication.translate("Form", u"3:30:01 PM(12-\u5c0f\u65f6\u5236)", None)) - self.comboBox_3.setItemText(2, "") - - self.label_5.setText(QCoreApplication.translate("Form", u"\u65f6\u95f4\u683c\u5f0f:", None)) - self.comboBox_4.setItemText(0, QCoreApplication.translate("Form", u"\u7f8e\u5143US Dollar", None)) - self.comboBox_4.setItemText(1, QCoreApplication.translate("Form", u"\u4eba\u6c11\u5e01Chinese Yuan", None)) - self.comboBox_4.setItemText(2, "") - - self.label_6.setText(QCoreApplication.translate("Form", u"\u8d27\u5e01\u5355\u4f4d:", None)) - self.comboBox_5.setItemText(0, QCoreApplication.translate("Form", u"\uffe5", None)) - self.comboBox_5.setItemText(1, QCoreApplication.translate("Form", u"CNY", None)) - self.comboBox_5.setItemText(2, QCoreApplication.translate("Form", u"$", None)) - self.comboBox_5.setItemText(3, QCoreApplication.translate("Form", u"USD", None)) - - self.label_7.setText(QCoreApplication.translate("Form", u"\u8d27\u5e01\u7b26\u53f7:", None)) - self.comboBox_6.setItemText(0, QCoreApplication.translate("Form", u"\u5217\u6807\u9898\u5185", None)) - self.comboBox_6.setItemText(1, QCoreApplication.translate("Form", u"\u5355\u5143\u683c\u5185", None)) - - self.label_8.setText(QCoreApplication.translate("Form", u"\u8d27\u5e01\u7b26\u53f7\u4f4d\u4e8e:", None)) - self.pushButton_help.setText(QCoreApplication.translate("Form", u"Help", None)) - self.pushButton_ok.setText(QCoreApplication.translate("Form", u"OK", None)) - self.pushButton_cancel.setText(QCoreApplication.translate("Form", u"Cancel", None)) - # retranslateUi - diff --git a/pyminer/features/ui/ui_option.ui b/pyminer/features/ui/ui_option.ui deleted file mode 100644 index f9394124..00000000 --- a/pyminer/features/ui/ui_option.ui +++ /dev/null @@ -1,585 +0,0 @@ - - - Form - - - - 0 - 0 - 705 - 515 - - - - Settings - - - - - - Qt::Horizontal - - - - - 200 - 16777215 - - - - - 常规 - - - - - 外观 - - - - - 格式化 - - - - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QTabWidget::North - - - 0 - - - - Basic - - - - - - - - UI Theme - - - - - - - - Fusion - - - - - Qdarkstyle - - - - - windowsvista - - - - - Windows - - - - - - - - Work Directory - - - - - - - - - - - - ... - - - - - - - - - Output Directory - - - - - - - - - - - - ... - - - - - - - - - UI Language - - - - - - - - 简体中文 - - - - - English - - - - - - - - Encoding - - - - - - - - utf-8 - - - - - gb2312 - - - - - - - - Check upd on startup - - - true - - - - - - - 显示起始页面 - - - true - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - - - - Interlaced coloring - - - true - - - - - - - - - Table Header Background: - - - - - - - Color - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - Size: - - - - - - - - 60 - 16777215 - - - - 15 - - - - - - - Qt::Horizontal - - - - 120 - 20 - - - - - - - - - - - - Font: - - - - - - - - Source Code Pro - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 16777215 - 16777215 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Patata is a full-featured IDE</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">with a high level of usability and outstanding</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">advanced code editing and refactoring support.</p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">abcdefghijklmnopqrstuvwxyz 0123456789 (){}[]</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ABCDEFGHIJKLMNOPQRSTUVWXYZ +-*/= .,;:!? #&amp;$%@|^</p></body></html> - - - - - - - - - - - - - 日期格式: - - - - - - - - 2020-01-01 - - - - - 2020/01/01 - - - - - - - - - - - - - - 15:30:01(24-小时制) - - - - - 3:30:01 PM(12-小时制) - - - - - - - - - - - - - 时间格式: - - - - - - - - 美元US Dollar - - - - - 人民币Chinese Yuan - - - - - - - - - - - - - 货币单位: - - - - - - - - - - - - - CNY - - - - - $ - - - - - USD - - - - - - - - 货币符号: - - - - - - - - 列标题内 - - - - - 单元格内 - - - - - - - - 货币符号位于: - - - - - - - - - - - - - - - 16777215 - 50 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - Help - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - OK - - - - - - - Cancel - - - - - - - - - - - - - diff --git a/pyminer/features/ui/ui_preferences.py b/pyminer/features/ui/ui_preferences.py deleted file mode 100644 index 2aa18e93..00000000 --- a/pyminer/features/ui/ui_preferences.py +++ /dev/null @@ -1,641 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'ui_preferences.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - - -class Ui_Form(object): - def setupUi(self, Form): - if not Form.objectName(): - Form.setObjectName(u"Form") - Form.resize(705, 515) - self.verticalLayout_4 = QVBoxLayout(Form) - self.verticalLayout_4.setObjectName(u"verticalLayout_4") - self.verticalLayout_4.setContentsMargins(9, 0, 9, 9) - self.splitter = QSplitter(Form) - self.splitter.setObjectName(u"splitter") - self.splitter.setOrientation(Qt.Horizontal) - self.widget_2 = QWidget(self.splitter) - self.widget_2.setObjectName(u"widget_2") - self.widget_2.setMaximumSize(QSize(200, 16777215)) - self.verticalLayout_2 = QVBoxLayout(self.widget_2) - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.verticalLayout_2.setContentsMargins(-1, -1, 0, -1) - self.verticalLayout = QVBoxLayout() - self.verticalLayout.setObjectName(u"verticalLayout") - self.lineEdit = QLineEdit(self.widget_2) - self.lineEdit.setObjectName(u"lineEdit") - - self.verticalLayout.addWidget(self.lineEdit) - - self.listWidget = QListWidget(self.widget_2) - QListWidgetItem(self.listWidget) - QListWidgetItem(self.listWidget) - QListWidgetItem(self.listWidget) - QListWidgetItem(self.listWidget) - QListWidgetItem(self.listWidget) - self.listWidget.setObjectName(u"listWidget") - self.listWidget.setMaximumSize(QSize(200, 16777215)) - - self.verticalLayout.addWidget(self.listWidget) - - - self.verticalLayout_2.addLayout(self.verticalLayout) - - self.splitter.addWidget(self.widget_2) - self.stackedWidget = QStackedWidget(self.splitter) - self.stackedWidget.setObjectName(u"stackedWidget") - self.page_general = QWidget() - self.page_general.setObjectName(u"page_general") - self.horizontalLayout_3 = QHBoxLayout(self.page_general) - self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0) - self.tabWidget = QTabWidget(self.page_general) - self.tabWidget.setObjectName(u"tabWidget") - self.tabWidget.setTabPosition(QTabWidget.North) - self.tabBase = QWidget() - self.tabBase.setObjectName(u"tabBase") - self.verticalLayout_8 = QVBoxLayout(self.tabBase) - self.verticalLayout_8.setObjectName(u"verticalLayout_8") - self.formLayout_2 = QFormLayout() - self.formLayout_2.setObjectName(u"formLayout_2") - self.label = QLabel(self.tabBase) - self.label.setObjectName(u"label") - - self.formLayout_2.setWidget(1, QFormLayout.LabelRole, self.label) - - self.label_15 = QLabel(self.tabBase) - self.label_15.setObjectName(u"label_15") - - self.formLayout_2.setWidget(2, QFormLayout.LabelRole, self.label_15) - - self.checkBox = QCheckBox(self.tabBase) - self.checkBox.setObjectName(u"checkBox") - self.checkBox.setChecked(True) - - self.formLayout_2.setWidget(5, QFormLayout.LabelRole, self.checkBox) - - self.checkBox_2 = QCheckBox(self.tabBase) - self.checkBox_2.setObjectName(u"checkBox_2") - - self.formLayout_2.setWidget(8, QFormLayout.LabelRole, self.checkBox_2) - - self.label_16 = QLabel(self.tabBase) - self.label_16.setObjectName(u"label_16") - - self.formLayout_2.setWidget(3, QFormLayout.LabelRole, self.label_16) - - self.comboBox_language = QComboBox(self.tabBase) - self.comboBox_language.addItem("") - self.comboBox_language.addItem("") - self.comboBox_language.setObjectName(u"comboBox_language") - - self.formLayout_2.setWidget(3, QFormLayout.FieldRole, self.comboBox_language) - - self.label_11 = QLabel(self.tabBase) - self.label_11.setObjectName(u"label_11") - - self.formLayout_2.setWidget(4, QFormLayout.LabelRole, self.label_11) - - self.comboBox_encoding = QComboBox(self.tabBase) - self.comboBox_encoding.addItem("") - self.comboBox_encoding.addItem("") - self.comboBox_encoding.setObjectName(u"comboBox_encoding") - - self.formLayout_2.setWidget(4, QFormLayout.FieldRole, self.comboBox_encoding) - - self.horizontalLayout_14 = QHBoxLayout() - self.horizontalLayout_14.setObjectName(u"horizontalLayout_14") - self.lineEdit_worksapce = QLineEdit(self.tabBase) - self.lineEdit_worksapce.setObjectName(u"lineEdit_worksapce") - - self.horizontalLayout_14.addWidget(self.lineEdit_worksapce) - - self.toolButton_workspace = QToolButton(self.tabBase) - self.toolButton_workspace.setObjectName(u"toolButton_workspace") - - self.horizontalLayout_14.addWidget(self.toolButton_workspace) - - - self.formLayout_2.setLayout(1, QFormLayout.FieldRole, self.horizontalLayout_14) - - self.horizontalLayout_15 = QHBoxLayout() - self.horizontalLayout_15.setObjectName(u"horizontalLayout_15") - self.lineEdit_output = QLineEdit(self.tabBase) - self.lineEdit_output.setObjectName(u"lineEdit_output") - - self.horizontalLayout_15.addWidget(self.lineEdit_output) - - self.toolButton_output = QToolButton(self.tabBase) - self.toolButton_output.setObjectName(u"toolButton_output") - - self.horizontalLayout_15.addWidget(self.toolButton_output) - - - self.formLayout_2.setLayout(2, QFormLayout.FieldRole, self.horizontalLayout_15) - - self.label_theme = QLabel(self.tabBase) - self.label_theme.setObjectName(u"label_theme") - - self.formLayout_2.setWidget(0, QFormLayout.LabelRole, self.label_theme) - - self.comboBox_theme = QComboBox(self.tabBase) - self.comboBox_theme.addItem("") - self.comboBox_theme.addItem("") - self.comboBox_theme.addItem("") - self.comboBox_theme.addItem("") - self.comboBox_theme.setObjectName(u"comboBox_theme") - - self.formLayout_2.setWidget(0, QFormLayout.FieldRole, self.comboBox_theme) - - self.checkBox_minitray = QCheckBox(self.tabBase) - self.checkBox_minitray.setObjectName(u"checkBox_minitray") - self.checkBox_minitray.setChecked(True) - - self.formLayout_2.setWidget(6, QFormLayout.LabelRole, self.checkBox_minitray) - - self.checkBox_startpage = QCheckBox(self.tabBase) - self.checkBox_startpage.setObjectName(u"checkBox_startpage") - self.checkBox_startpage.setChecked(True) - - self.formLayout_2.setWidget(7, QFormLayout.LabelRole, self.checkBox_startpage) - - - self.verticalLayout_8.addLayout(self.formLayout_2) - - self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.verticalLayout_8.addItem(self.verticalSpacer_2) - - self.tabWidget.addTab(self.tabBase, "") - - self.horizontalLayout_3.addWidget(self.tabWidget) - - self.stackedWidget.addWidget(self.page_general) - self.page_appearance = QWidget() - self.page_appearance.setObjectName(u"page_appearance") - self.verticalLayout_6 = QVBoxLayout(self.page_appearance) - self.verticalLayout_6.setObjectName(u"verticalLayout_6") - self.verticalLayout_5 = QVBoxLayout() - self.verticalLayout_5.setObjectName(u"verticalLayout_5") - self.checkBox_3 = QCheckBox(self.page_appearance) - self.checkBox_3.setObjectName(u"checkBox_3") - self.checkBox_3.setChecked(True) - - self.verticalLayout_5.addWidget(self.checkBox_3) - - self.horizontalLayout_11 = QHBoxLayout() - self.horizontalLayout_11.setObjectName(u"horizontalLayout_11") - self.label_10 = QLabel(self.page_appearance) - self.label_10.setObjectName(u"label_10") - - self.horizontalLayout_11.addWidget(self.label_10) - - self.pushButton = QPushButton(self.page_appearance) - self.pushButton.setObjectName(u"pushButton") - - self.horizontalLayout_11.addWidget(self.pushButton) - - self.horizontalSpacer_4 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_11.addItem(self.horizontalSpacer_4) - - - self.verticalLayout_5.addLayout(self.horizontalLayout_11) - - - self.verticalLayout_6.addLayout(self.verticalLayout_5) - - self.horizontalLayout_6 = QHBoxLayout() - self.horizontalLayout_6.setObjectName(u"horizontalLayout_6") - - self.verticalLayout_6.addLayout(self.horizontalLayout_6) - - self.horizontalLayout_5 = QHBoxLayout() - self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") - self.label_3 = QLabel(self.page_appearance) - self.label_3.setObjectName(u"label_3") - - self.horizontalLayout_5.addWidget(self.label_3) - - self.lineEdit_2 = QLineEdit(self.page_appearance) - self.lineEdit_2.setObjectName(u"lineEdit_2") - self.lineEdit_2.setMaximumSize(QSize(60, 16777215)) - - self.horizontalLayout_5.addWidget(self.lineEdit_2) - - self.horizontalSpacer_3 = QSpacerItem(120, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_5.addItem(self.horizontalSpacer_3) - - - self.verticalLayout_6.addLayout(self.horizontalLayout_5) - - self.horizontalLayout_4 = QHBoxLayout() - self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") - self.label_2 = QLabel(self.page_appearance) - self.label_2.setObjectName(u"label_2") - - self.horizontalLayout_4.addWidget(self.label_2) - - self.comboBox = QComboBox(self.page_appearance) - self.comboBox.addItem("") - self.comboBox.setObjectName(u"comboBox") - - self.horizontalLayout_4.addWidget(self.comboBox) - - self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_4.addItem(self.horizontalSpacer_2) - - - self.verticalLayout_6.addLayout(self.horizontalLayout_4) - - self.textEdit = QTextEdit(self.page_appearance) - self.textEdit.setObjectName(u"textEdit") - self.textEdit.setMaximumSize(QSize(16777215, 16777215)) - - self.verticalLayout_6.addWidget(self.textEdit) - - self.stackedWidget.addWidget(self.page_appearance) - self.page = QWidget() - self.page.setObjectName(u"page") - self.verticalLayout_11 = QVBoxLayout(self.page) - self.verticalLayout_11.setObjectName(u"verticalLayout_11") - self.verticalLayout_11.setContentsMargins(0, 0, 0, 0) - self.widget_3 = QWidget(self.page) - self.widget_3.setObjectName(u"widget_3") - self.verticalLayout_9 = QVBoxLayout(self.widget_3) - self.verticalLayout_9.setObjectName(u"verticalLayout_9") - self.label_9 = QLabel(self.widget_3) - self.label_9.setObjectName(u"label_9") - font = QFont() - font.setBold(True) - font.setWeight(75) - self.label_9.setFont(font) - - self.verticalLayout_9.addWidget(self.label_9) - - self.line = QFrame(self.widget_3) - self.line.setObjectName(u"line") - self.line.setFrameShape(QFrame.HLine) - self.line.setFrameShadow(QFrame.Sunken) - - self.verticalLayout_9.addWidget(self.line) - - self.widget_4 = QWidget(self.widget_3) - self.widget_4.setObjectName(u"widget_4") - self.widget_4.setMaximumSize(QSize(16777215, 150)) - self.verticalLayout_13 = QVBoxLayout(self.widget_4) - self.verticalLayout_13.setObjectName(u"verticalLayout_13") - self.horizontalLayout_2 = QHBoxLayout() - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.tableWidget = QTableWidget(self.widget_4) - if (self.tableWidget.columnCount() < 2): - self.tableWidget.setColumnCount(2) - __qtablewidgetitem = QTableWidgetItem() - self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem) - __qtablewidgetitem1 = QTableWidgetItem() - self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1) - self.tableWidget.setObjectName(u"tableWidget") - - self.horizontalLayout_2.addWidget(self.tableWidget) - - self.verticalLayout_7 = QVBoxLayout() - self.verticalLayout_7.setObjectName(u"verticalLayout_7") - self.pushButton_2 = QPushButton(self.widget_4) - self.pushButton_2.setObjectName(u"pushButton_2") - - self.verticalLayout_7.addWidget(self.pushButton_2) - - self.pushButton_3 = QPushButton(self.widget_4) - self.pushButton_3.setObjectName(u"pushButton_3") - - self.verticalLayout_7.addWidget(self.pushButton_3) - - self.pushButton_4 = QPushButton(self.widget_4) - self.pushButton_4.setObjectName(u"pushButton_4") - - self.verticalLayout_7.addWidget(self.pushButton_4) - - self.pushButton_5 = QPushButton(self.widget_4) - self.pushButton_5.setObjectName(u"pushButton_5") - - self.verticalLayout_7.addWidget(self.pushButton_5) - - self.pushButton_6 = QPushButton(self.widget_4) - self.pushButton_6.setObjectName(u"pushButton_6") - - self.verticalLayout_7.addWidget(self.pushButton_6) - - self.verticalSpacer_4 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.verticalLayout_7.addItem(self.verticalSpacer_4) - - self.verticalSpacer_3 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.verticalLayout_7.addItem(self.verticalSpacer_3) - - - self.horizontalLayout_2.addLayout(self.verticalLayout_7) - - - self.verticalLayout_13.addLayout(self.horizontalLayout_2) - - - self.verticalLayout_9.addWidget(self.widget_4) - - self.tabWidget_2 = QTabWidget(self.widget_3) - self.tabWidget_2.setObjectName(u"tabWidget_2") - self.tab = QWidget() - self.tab.setObjectName(u"tab") - self.verticalLayout_12 = QVBoxLayout(self.tab) - self.verticalLayout_12.setObjectName(u"verticalLayout_12") - self.horizontalLayout_8 = QHBoxLayout() - self.horizontalLayout_8.setObjectName(u"horizontalLayout_8") - self.tableWidget_2 = QTableWidget(self.tab) - if (self.tableWidget_2.columnCount() < 2): - self.tableWidget_2.setColumnCount(2) - __qtablewidgetitem2 = QTableWidgetItem() - self.tableWidget_2.setHorizontalHeaderItem(0, __qtablewidgetitem2) - __qtablewidgetitem3 = QTableWidgetItem() - self.tableWidget_2.setHorizontalHeaderItem(1, __qtablewidgetitem3) - self.tableWidget_2.setObjectName(u"tableWidget_2") - - self.horizontalLayout_8.addWidget(self.tableWidget_2) - - self.verticalLayout_10 = QVBoxLayout() - self.verticalLayout_10.setObjectName(u"verticalLayout_10") - self.pushButton_7 = QPushButton(self.tab) - self.pushButton_7.setObjectName(u"pushButton_7") - - self.verticalLayout_10.addWidget(self.pushButton_7) - - self.pushButton_8 = QPushButton(self.tab) - self.pushButton_8.setObjectName(u"pushButton_8") - - self.verticalLayout_10.addWidget(self.pushButton_8) - - self.pushButton_9 = QPushButton(self.tab) - self.pushButton_9.setObjectName(u"pushButton_9") - - self.verticalLayout_10.addWidget(self.pushButton_9) - - self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.verticalLayout_10.addItem(self.verticalSpacer) - - - self.horizontalLayout_8.addLayout(self.verticalLayout_10) - - - self.verticalLayout_12.addLayout(self.horizontalLayout_8) - - self.tabWidget_2.addTab(self.tab, "") - - self.verticalLayout_9.addWidget(self.tabWidget_2) - - - self.verticalLayout_11.addWidget(self.widget_3) - - self.stackedWidget.addWidget(self.page) - self.page_format = QWidget() - self.page_format.setObjectName(u"page_format") - self.verticalLayout_3 = QVBoxLayout(self.page_format) - self.verticalLayout_3.setObjectName(u"verticalLayout_3") - self.formLayout = QFormLayout() - self.formLayout.setObjectName(u"formLayout") - self.label_4 = QLabel(self.page_format) - self.label_4.setObjectName(u"label_4") - - self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label_4) - - self.comboBox_2 = QComboBox(self.page_format) - self.comboBox_2.addItem("") - self.comboBox_2.addItem("") - self.comboBox_2.addItem("") - self.comboBox_2.setObjectName(u"comboBox_2") - - self.formLayout.setWidget(0, QFormLayout.FieldRole, self.comboBox_2) - - self.comboBox_3 = QComboBox(self.page_format) - self.comboBox_3.addItem("") - self.comboBox_3.addItem("") - self.comboBox_3.addItem("") - self.comboBox_3.setObjectName(u"comboBox_3") - - self.formLayout.setWidget(1, QFormLayout.FieldRole, self.comboBox_3) - - self.label_5 = QLabel(self.page_format) - self.label_5.setObjectName(u"label_5") - - self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_5) - - self.comboBox_4 = QComboBox(self.page_format) - self.comboBox_4.addItem("") - self.comboBox_4.addItem("") - self.comboBox_4.addItem("") - self.comboBox_4.setObjectName(u"comboBox_4") - - self.formLayout.setWidget(2, QFormLayout.FieldRole, self.comboBox_4) - - self.label_6 = QLabel(self.page_format) - self.label_6.setObjectName(u"label_6") - - self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_6) - - self.comboBox_5 = QComboBox(self.page_format) - self.comboBox_5.addItem("") - self.comboBox_5.addItem("") - self.comboBox_5.addItem("") - self.comboBox_5.addItem("") - self.comboBox_5.setObjectName(u"comboBox_5") - - self.formLayout.setWidget(3, QFormLayout.FieldRole, self.comboBox_5) - - self.label_7 = QLabel(self.page_format) - self.label_7.setObjectName(u"label_7") - - self.formLayout.setWidget(3, QFormLayout.LabelRole, self.label_7) - - self.comboBox_6 = QComboBox(self.page_format) - self.comboBox_6.addItem("") - self.comboBox_6.addItem("") - self.comboBox_6.setObjectName(u"comboBox_6") - - self.formLayout.setWidget(4, QFormLayout.FieldRole, self.comboBox_6) - - self.label_8 = QLabel(self.page_format) - self.label_8.setObjectName(u"label_8") - - self.formLayout.setWidget(4, QFormLayout.LabelRole, self.label_8) - - - self.verticalLayout_3.addLayout(self.formLayout) - - self.stackedWidget.addWidget(self.page_format) - self.splitter.addWidget(self.stackedWidget) - - self.verticalLayout_4.addWidget(self.splitter) - - self.widget = QWidget(Form) - self.widget.setObjectName(u"widget") - self.widget.setMaximumSize(QSize(16777215, 50)) - self.horizontalLayout_7 = QHBoxLayout(self.widget) - self.horizontalLayout_7.setObjectName(u"horizontalLayout_7") - self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0) - self.horizontalLayout = QHBoxLayout() - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.pushButton_help = QPushButton(self.widget) - self.pushButton_help.setObjectName(u"pushButton_help") - - self.horizontalLayout.addWidget(self.pushButton_help) - - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout.addItem(self.horizontalSpacer) - - self.pushButton_ok = QPushButton(self.widget) - self.pushButton_ok.setObjectName(u"pushButton_ok") - - self.horizontalLayout.addWidget(self.pushButton_ok) - - self.pushButton_cancel = QPushButton(self.widget) - self.pushButton_cancel.setObjectName(u"pushButton_cancel") - - self.horizontalLayout.addWidget(self.pushButton_cancel) - - - self.horizontalLayout_7.addLayout(self.horizontalLayout) - - - self.verticalLayout_4.addWidget(self.widget) - - - self.retranslateUi(Form) - - self.stackedWidget.setCurrentIndex(0) - self.tabWidget.setCurrentIndex(0) - self.tabWidget_2.setCurrentIndex(0) - - - QMetaObject.connectSlotsByName(Form) - # setupUi - - def retranslateUi(self, Form): - Form.setWindowTitle(QCoreApplication.translate("Form", u"Preferences", None)) - self.lineEdit.setPlaceholderText(QCoreApplication.translate("Form", u"type filter text", None)) - - __sortingEnabled = self.listWidget.isSortingEnabled() - self.listWidget.setSortingEnabled(False) - ___qlistwidgetitem = self.listWidget.item(0) - ___qlistwidgetitem.setText(QCoreApplication.translate("Form", u"General", None)); - ___qlistwidgetitem1 = self.listWidget.item(1) - ___qlistwidgetitem1.setText(QCoreApplication.translate("Form", u"Appearance", None)); - ___qlistwidgetitem2 = self.listWidget.item(2) - ___qlistwidgetitem2.setText(QCoreApplication.translate("Form", u"Interpreters", None)); - ___qlistwidgetitem3 = self.listWidget.item(3) - ___qlistwidgetitem3.setText(QCoreApplication.translate("Form", u"Editor", None)); - ___qlistwidgetitem4 = self.listWidget.item(4) - ___qlistwidgetitem4.setText(QCoreApplication.translate("Form", u"Fonts", None)); - self.listWidget.setSortingEnabled(__sortingEnabled) - - self.label.setText(QCoreApplication.translate("Form", u"Work Directory", None)) - self.label_15.setText(QCoreApplication.translate("Form", u"Output Directory", None)) - self.checkBox.setText(QCoreApplication.translate("Form", u"Check upd on startup", None)) - self.checkBox_2.setText(QCoreApplication.translate("Form", u"Start with system", None)) - self.label_16.setText(QCoreApplication.translate("Form", u"UI Language", None)) - self.comboBox_language.setItemText(0, QCoreApplication.translate("Form", u"English", None)) - self.comboBox_language.setItemText(1, QCoreApplication.translate("Form", u"\u7b80\u4f53\u4e2d\u6587", None)) - - self.label_11.setText(QCoreApplication.translate("Form", u"Encoding", None)) - self.comboBox_encoding.setItemText(0, QCoreApplication.translate("Form", u"utf-8", None)) - self.comboBox_encoding.setItemText(1, QCoreApplication.translate("Form", u"gb2312", None)) - - self.toolButton_workspace.setText(QCoreApplication.translate("Form", u"...", None)) - self.toolButton_output.setText(QCoreApplication.translate("Form", u"...", None)) - self.label_theme.setText(QCoreApplication.translate("Form", u"UI Theme", None)) - self.comboBox_theme.setItemText(0, QCoreApplication.translate("Form", u"Fusion", None)) - self.comboBox_theme.setItemText(1, QCoreApplication.translate("Form", u"Qdarkstyle", None)) - self.comboBox_theme.setItemText(2, QCoreApplication.translate("Form", u"windowsvista", None)) - self.comboBox_theme.setItemText(3, QCoreApplication.translate("Form", u"Windows", None)) - - self.checkBox_minitray.setText(QCoreApplication.translate("Form", u"Minimize to tray", None)) - self.checkBox_startpage.setText(QCoreApplication.translate("Form", u"Display StartPage", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabBase), QCoreApplication.translate("Form", u"Basic", None)) - self.checkBox_3.setText(QCoreApplication.translate("Form", u"Interlaced coloring", None)) - self.label_10.setText(QCoreApplication.translate("Form", u"Table Header Background:", None)) - self.pushButton.setText(QCoreApplication.translate("Form", u"Color", None)) - self.label_3.setText(QCoreApplication.translate("Form", u"Size:", None)) - self.lineEdit_2.setText(QCoreApplication.translate("Form", u"15", None)) - self.label_2.setText(QCoreApplication.translate("Form", u"Font:", None)) - self.comboBox.setItemText(0, QCoreApplication.translate("Form", u"Source Code Pro", None)) - - self.textEdit.setHtml(QCoreApplication.translate("Form", u"\n" -"\n" -"

Patata is a full-featured IDE

\n" -"

with a high level of usability and outstanding

\n" -"

advanced code editing and refactoring support.

\n" -"


\n" -"

abcdefghijklmnopqrstuvwxyz 0123456789 (){}[]

\n" -"

ABCDEFGHIJKLMNOPQRSTUVWXYZ +-*/= .,;:!? #&$%@|^

", None)) - self.label_9.setText(QCoreApplication.translate("Form", u"Python Interpreters", None)) - ___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0) - ___qtablewidgetitem.setText(QCoreApplication.translate("Form", u"Name", None)); - ___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(1) - ___qtablewidgetitem1.setText(QCoreApplication.translate("Form", u"Location", None)); - self.pushButton_2.setText(QCoreApplication.translate("Form", u"New ...", None)) - self.pushButton_3.setText(QCoreApplication.translate("Form", u"Up", None)) - self.pushButton_4.setText(QCoreApplication.translate("Form", u"Down", None)) - self.pushButton_5.setText(QCoreApplication.translate("Form", u"Remove", None)) - self.pushButton_6.setText(QCoreApplication.translate("Form", u"Config Conda", None)) - ___qtablewidgetitem2 = self.tableWidget_2.horizontalHeaderItem(0) - ___qtablewidgetitem2.setText(QCoreApplication.translate("Form", u"Name", None)); - ___qtablewidgetitem3 = self.tableWidget_2.horizontalHeaderItem(1) - ___qtablewidgetitem3.setText(QCoreApplication.translate("Form", u"Version", None)); - self.pushButton_7.setText(QCoreApplication.translate("Form", u"Manage with pip", None)) - self.pushButton_8.setText(QCoreApplication.translate("Form", u"Manage with conda", None)) - self.pushButton_9.setText(QCoreApplication.translate("Form", u"Manage with pipenv", None)) - self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab), QCoreApplication.translate("Form", u"Packages", None)) - self.label_4.setText(QCoreApplication.translate("Form", u"\u65e5\u671f\u683c\u5f0f:", None)) - self.comboBox_2.setItemText(0, QCoreApplication.translate("Form", u"2020-01-01", None)) - self.comboBox_2.setItemText(1, QCoreApplication.translate("Form", u"2020/01/01", None)) - self.comboBox_2.setItemText(2, "") - - self.comboBox_3.setItemText(0, QCoreApplication.translate("Form", u"15:30:01(24-\u5c0f\u65f6\u5236)", None)) - self.comboBox_3.setItemText(1, QCoreApplication.translate("Form", u"3:30:01 PM(12-\u5c0f\u65f6\u5236)", None)) - self.comboBox_3.setItemText(2, "") - - self.label_5.setText(QCoreApplication.translate("Form", u"\u65f6\u95f4\u683c\u5f0f:", None)) - self.comboBox_4.setItemText(0, QCoreApplication.translate("Form", u"\u7f8e\u5143US Dollar", None)) - self.comboBox_4.setItemText(1, QCoreApplication.translate("Form", u"\u4eba\u6c11\u5e01Chinese Yuan", None)) - self.comboBox_4.setItemText(2, "") - - self.label_6.setText(QCoreApplication.translate("Form", u"\u8d27\u5e01\u5355\u4f4d:", None)) - self.comboBox_5.setItemText(0, QCoreApplication.translate("Form", u"\uffe5", None)) - self.comboBox_5.setItemText(1, QCoreApplication.translate("Form", u"CNY", None)) - self.comboBox_5.setItemText(2, QCoreApplication.translate("Form", u"$", None)) - self.comboBox_5.setItemText(3, QCoreApplication.translate("Form", u"USD", None)) - - self.label_7.setText(QCoreApplication.translate("Form", u"\u8d27\u5e01\u7b26\u53f7:", None)) - self.comboBox_6.setItemText(0, QCoreApplication.translate("Form", u"\u5217\u6807\u9898\u5185", None)) - self.comboBox_6.setItemText(1, QCoreApplication.translate("Form", u"\u5355\u5143\u683c\u5185", None)) - - self.label_8.setText(QCoreApplication.translate("Form", u"\u8d27\u5e01\u7b26\u53f7\u4f4d\u4e8e:", None)) - self.pushButton_help.setText(QCoreApplication.translate("Form", u"Help", None)) - self.pushButton_ok.setText(QCoreApplication.translate("Form", u"Ok", None)) - self.pushButton_cancel.setText(QCoreApplication.translate("Form", u"Cancel", None)) - # retranslateUi - diff --git a/pyminer/features/ui/ui_preferences.ui b/pyminer/features/ui/ui_preferences.ui deleted file mode 100644 index 4fb629cd..00000000 --- a/pyminer/features/ui/ui_preferences.ui +++ /dev/null @@ -1,857 +0,0 @@ - - - Form - - - - 0 - 0 - 705 - 515 - - - - Preferences - - - - 9 - - - 0 - - - 9 - - - 9 - - - - - Qt::Horizontal - - - - - 200 - 16777215 - - - - - 0 - - - - - - - type filter text - - - - - - - - 200 - 16777215 - - - - - General - - - - - Appearance - - - - - Interpreters - - - - - Editor - - - - - Fonts - - - - - - - - - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QTabWidget::North - - - 0 - - - - Basic - - - - - - - - Work Directory - - - - - - - Output Directory - - - - - - - Check upd on startup - - - true - - - - - - - Start with system - - - - - - - UI Language - - - - - - - - English - - - - - 简体中文 - - - - - - - - Encoding - - - - - - - - utf-8 - - - - - gb2312 - - - - - - - - - - - - - ... - - - - - - - - - - - - - - ... - - - - - - - - - UI Theme - - - - - - - - Fusion - - - - - Qdarkstyle - - - - - windowsvista - - - - - Windows - - - - - - - - Minimize to tray - - - true - - - - - - - Display StartPage - - - true - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - - - - Interlaced coloring - - - true - - - - - - - - - Table Header Background: - - - - - - - Color - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - Size: - - - - - - - - 60 - 16777215 - - - - 15 - - - - - - - Qt::Horizontal - - - - 120 - 20 - - - - - - - - - - - - Font: - - - - - - - - Source Code Pro - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 16777215 - 16777215 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Patata is a full-featured IDE</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">with a high level of usability and outstanding</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">advanced code editing and refactoring support.</p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">abcdefghijklmnopqrstuvwxyz 0123456789 (){}[]</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ABCDEFGHIJKLMNOPQRSTUVWXYZ +-*/= .,;:!? #&amp;$%@|^</p></body></html> - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - 75 - true - - - - Python Interpreters - - - - - - - Qt::Horizontal - - - - - - - - 16777215 - 150 - - - - - - - - - - Name - - - - - Location - - - - - - - - - - New ... - - - - - - - Up - - - - - - - Down - - - - - - - Remove - - - - - - - Config Conda - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - 0 - - - - Packages - - - - - - - - - Name - - - - - Version - - - - - - - - - - Manage with pip - - - - - - - Manage with conda - - - - - - - Manage with pipenv - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - - - - - - - - - - - 日期格式: - - - - - - - - 2020-01-01 - - - - - 2020/01/01 - - - - - - - - - - - - - - 15:30:01(24-小时制) - - - - - 3:30:01 PM(12-小时制) - - - - - - - - - - - - - 时间格式: - - - - - - - - 美元US Dollar - - - - - 人民币Chinese Yuan - - - - - - - - - - - - - 货币单位: - - - - - - - - - - - - - CNY - - - - - $ - - - - - USD - - - - - - - - 货币符号: - - - - - - - - 列标题内 - - - - - 单元格内 - - - - - - - - 货币符号位于: - - - - - - - - - - - - - - - 16777215 - 50 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - Help - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Ok - - - - - - - Cancel - - - - - - - - - - - - - diff --git a/pyminer/features/ui/ui_project_wizard.py b/pyminer/features/ui/ui_project_wizard.py deleted file mode 100644 index 0e37d326..00000000 --- a/pyminer/features/ui/ui_project_wizard.py +++ /dev/null @@ -1,358 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'ui_project_wizard.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - -import pyqtsource_rc - -class Ui_Wizard(object): - def setupUi(self, Wizard): - if not Wizard.objectName(): - Wizard.setObjectName(u"Wizard") - Wizard.resize(736, 505) - Wizard.setWizardStyle(QWizard.ModernStyle) - Wizard.setOptions(QWizard.HelpButtonOnRight|QWizard.NoBackButtonOnStartPage) - self.wizardPage1 = QWizardPage() - self.wizardPage1.setObjectName(u"wizardPage1") - self.horizontalLayout = QHBoxLayout(self.wizardPage1) - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.horizontalLayout.setContentsMargins(9, 9, 9, 9) - self.widget_left = QWidget(self.wizardPage1) - self.widget_left.setObjectName(u"widget_left") - self.widget_left.setMinimumSize(QSize(200, 0)) - self.widget_left.setMaximumSize(QSize(180, 16777215)) - self.verticalLayout = QVBoxLayout(self.widget_left) - self.verticalLayout.setObjectName(u"verticalLayout") - self.verticalLayout.setContentsMargins(5, 5, 5, 5) - self.label = QLabel(self.widget_left) - self.label.setObjectName(u"label") - - self.verticalLayout.addWidget(self.label) - - self.line = QFrame(self.widget_left) - self.line.setObjectName(u"line") - self.line.setFrameShape(QFrame.HLine) - self.line.setFrameShadow(QFrame.Sunken) - - self.verticalLayout.addWidget(self.line) - - self.listWidget = QListWidget(self.widget_left) - font = QFont() - font.setBold(True) - font.setWeight(75) - __qlistwidgetitem = QListWidgetItem(self.listWidget) - __qlistwidgetitem.setFont(font); - QListWidgetItem(self.listWidget) - self.listWidget.setObjectName(u"listWidget") - self.listWidget.setStyleSheet(u"border:0px;") - - self.verticalLayout.addWidget(self.listWidget) - - self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.verticalLayout.addItem(self.verticalSpacer) - - - self.horizontalLayout.addWidget(self.widget_left) - - self.widget_right = QWidget(self.wizardPage1) - self.widget_right.setObjectName(u"widget_right") - self.verticalLayout_4 = QVBoxLayout(self.widget_right) - self.verticalLayout_4.setSpacing(5) - self.verticalLayout_4.setObjectName(u"verticalLayout_4") - self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) - self.horizontalLayout_2 = QHBoxLayout() - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.label_11 = QLabel(self.widget_right) - self.label_11.setObjectName(u"label_11") - self.label_11.setMaximumSize(QSize(15, 15)) - self.label_11.setPixmap(QPixmap(u":/color/theme/default/icons/search.svg")) - self.label_11.setScaledContents(True) - - self.horizontalLayout_2.addWidget(self.label_11) - - self.label_2 = QLabel(self.widget_right) - self.label_2.setObjectName(u"label_2") - - self.horizontalLayout_2.addWidget(self.label_2) - - self.lineEdit = QLineEdit(self.widget_right) - self.lineEdit.setObjectName(u"lineEdit") - - self.horizontalLayout_2.addWidget(self.lineEdit) - - - self.verticalLayout_4.addLayout(self.horizontalLayout_2) - - self.horizontalLayout_3 = QHBoxLayout() - self.horizontalLayout_3.setSpacing(9) - self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.horizontalLayout_3.setContentsMargins(0, -1, -1, -1) - self.widget_3 = QWidget(self.widget_right) - self.widget_3.setObjectName(u"widget_3") - self.widget_3.setMaximumSize(QSize(180, 16777215)) - self.verticalLayout_2 = QVBoxLayout(self.widget_3) - self.verticalLayout_2.setSpacing(5) - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) - self.label_3 = QLabel(self.widget_3) - self.label_3.setObjectName(u"label_3") - - self.verticalLayout_2.addWidget(self.label_3) - - self.treeWidget = QTreeWidget(self.widget_3) - icon = QIcon() - icon.addFile(u":/color/theme/default/icons/folder_yellow.svg", QSize(), QIcon.Normal, QIcon.Off) - __qtreewidgetitem = QTreeWidgetItem(self.treeWidget) - __qtreewidgetitem.setIcon(0, icon); - self.treeWidget.setObjectName(u"treeWidget") - self.treeWidget.header().setVisible(False) - - self.verticalLayout_2.addWidget(self.treeWidget) - - - self.horizontalLayout_3.addWidget(self.widget_3) - - self.widget_4 = QWidget(self.widget_right) - self.widget_4.setObjectName(u"widget_4") - self.widget_4.setMaximumSize(QSize(16777215, 16777215)) - self.verticalLayout_3 = QVBoxLayout(self.widget_4) - self.verticalLayout_3.setObjectName(u"verticalLayout_3") - self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) - self.label_4 = QLabel(self.widget_4) - self.label_4.setObjectName(u"label_4") - - self.verticalLayout_3.addWidget(self.label_4) - - self.file_list = QListWidget(self.widget_4) - icon1 = QIcon() - icon1.addFile(u":/color/theme/default/icons/python.svg", QSize(), QIcon.Normal, QIcon.Off) - __qlistwidgetitem1 = QListWidgetItem(self.file_list) - __qlistwidgetitem1.setIcon(icon1); - __qlistwidgetitem2 = QListWidgetItem(self.file_list) - __qlistwidgetitem2.setIcon(icon1); - __qlistwidgetitem3 = QListWidgetItem(self.file_list) - __qlistwidgetitem3.setIcon(icon1); - __qlistwidgetitem4 = QListWidgetItem(self.file_list) - __qlistwidgetitem4.setIcon(icon1); - self.file_list.setObjectName(u"file_list") - - self.verticalLayout_3.addWidget(self.file_list) - - - self.horizontalLayout_3.addWidget(self.widget_4) - - - self.verticalLayout_4.addLayout(self.horizontalLayout_3) - - self.plainTextEdit = QPlainTextEdit(self.widget_right) - self.plainTextEdit.setObjectName(u"plainTextEdit") - self.plainTextEdit.setMaximumSize(QSize(16777215, 90)) - self.plainTextEdit.setStyleSheet(u"background-color: rgb(243, 243, 243);") - self.plainTextEdit.setReadOnly(True) - - self.verticalLayout_4.addWidget(self.plainTextEdit) - - - self.horizontalLayout.addWidget(self.widget_right) - - Wizard.addPage(self.wizardPage1) - self.wizardPage2 = QWizardPage() - self.wizardPage2.setObjectName(u"wizardPage2") - self.horizontalLayout_6 = QHBoxLayout(self.wizardPage2) - self.horizontalLayout_6.setObjectName(u"horizontalLayout_6") - self.widget_left_2 = QWidget(self.wizardPage2) - self.widget_left_2.setObjectName(u"widget_left_2") - self.widget_left_2.setMinimumSize(QSize(200, 0)) - self.widget_left_2.setMaximumSize(QSize(180, 16777215)) - self.verticalLayout_5 = QVBoxLayout(self.widget_left_2) - self.verticalLayout_5.setObjectName(u"verticalLayout_5") - self.verticalLayout_5.setContentsMargins(5, 5, 5, 5) - self.label_5 = QLabel(self.widget_left_2) - self.label_5.setObjectName(u"label_5") - - self.verticalLayout_5.addWidget(self.label_5) - - self.line_2 = QFrame(self.widget_left_2) - self.line_2.setObjectName(u"line_2") - self.line_2.setFrameShape(QFrame.HLine) - self.line_2.setFrameShadow(QFrame.Sunken) - - self.verticalLayout_5.addWidget(self.line_2) - - self.listWidget_2 = QListWidget(self.widget_left_2) - font1 = QFont() - font1.setBold(False) - font1.setWeight(50) - __qlistwidgetitem5 = QListWidgetItem(self.listWidget_2) - __qlistwidgetitem5.setFont(font1); - __qlistwidgetitem6 = QListWidgetItem(self.listWidget_2) - __qlistwidgetitem6.setFont(font); - self.listWidget_2.setObjectName(u"listWidget_2") - self.listWidget_2.setStyleSheet(u"border:0px;") - - self.verticalLayout_5.addWidget(self.listWidget_2) - - self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.verticalLayout_5.addItem(self.verticalSpacer_2) - - - self.horizontalLayout_6.addWidget(self.widget_left_2) - - self.widget_right_2 = QWidget(self.wizardPage2) - self.widget_right_2.setObjectName(u"widget_right_2") - self.verticalLayout_6 = QVBoxLayout(self.widget_right_2) - self.verticalLayout_6.setObjectName(u"verticalLayout_6") - self.label_9 = QLabel(self.widget_right_2) - self.label_9.setObjectName(u"label_9") - - self.verticalLayout_6.addWidget(self.label_9) - - self.line_3 = QFrame(self.widget_right_2) - self.line_3.setObjectName(u"line_3") - self.line_3.setFrameShape(QFrame.HLine) - self.line_3.setFrameShadow(QFrame.Sunken) - - self.verticalLayout_6.addWidget(self.line_3) - - self.formLayout_2 = QFormLayout() - self.formLayout_2.setObjectName(u"formLayout_2") - self.projectNameText = QLabel(self.widget_right_2) - self.projectNameText.setObjectName(u"projectNameText") - - self.formLayout_2.setWidget(0, QFormLayout.LabelRole, self.projectNameText) - - self.projectNameLineEdit = QLineEdit(self.widget_right_2) - self.projectNameLineEdit.setObjectName(u"projectNameLineEdit") - self.projectNameLineEdit.setClearButtonEnabled(False) - - self.formLayout_2.setWidget(0, QFormLayout.FieldRole, self.projectNameLineEdit) - - self.projectDirectory = QLabel(self.widget_right_2) - self.projectDirectory.setObjectName(u"projectDirectory") - - self.formLayout_2.setWidget(1, QFormLayout.LabelRole, self.projectDirectory) - - self.horizontalLayout_4 = QHBoxLayout() - self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") - self.projectDirectoryEditLine = QLineEdit(self.widget_right_2) - self.projectDirectoryEditLine.setObjectName(u"projectDirectoryEditLine") - self.projectDirectoryEditLine.setStyleSheet(u"") - self.projectDirectoryEditLine.setReadOnly(True) - - self.horizontalLayout_4.addWidget(self.projectDirectoryEditLine) - - self.toolButton = QToolButton(self.widget_right_2) - self.toolButton.setObjectName(u"toolButton") - - self.horizontalLayout_4.addWidget(self.toolButton) - - - self.formLayout_2.setLayout(1, QFormLayout.FieldRole, self.horizontalLayout_4) - - self.absoluteDirectory = QLabel(self.widget_right_2) - self.absoluteDirectory.setObjectName(u"absoluteDirectory") - - self.formLayout_2.setWidget(2, QFormLayout.LabelRole, self.absoluteDirectory) - - self.absoluteDirectoryEditLine = QLineEdit(self.widget_right_2) - self.absoluteDirectoryEditLine.setObjectName(u"absoluteDirectoryEditLine") - self.absoluteDirectoryEditLine.setStyleSheet(u"") - self.absoluteDirectoryEditLine.setReadOnly(True) - - self.formLayout_2.setWidget(2, QFormLayout.FieldRole, self.absoluteDirectoryEditLine) - - self.verticalSpacer_3 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.formLayout_2.setItem(4, QFormLayout.LabelRole, self.verticalSpacer_3) - - self.warningLabel = QLabel(self.widget_right_2) - self.warningLabel.setObjectName(u"warningLabel") - self.warningLabel.setFont(font) - self.warningLabel.setCursor(QCursor(Qt.IBeamCursor)) - self.warningLabel.setStyleSheet(u"color: rgb(255, 102, 0);") - self.warningLabel.setTextFormat(Qt.AutoText) - - self.formLayout_2.setWidget(3, QFormLayout.FieldRole, self.warningLabel) - - - self.verticalLayout_6.addLayout(self.formLayout_2) - - - self.horizontalLayout_6.addWidget(self.widget_right_2) - - Wizard.addPage(self.wizardPage2) - - self.retranslateUi(Wizard) - - QMetaObject.connectSlotsByName(Wizard) - # setupUi - - def retranslateUi(self, Wizard): - Wizard.setWindowTitle(QCoreApplication.translate("Wizard", u"New Project", None)) - self.label.setText(QCoreApplication.translate("Wizard", u"Steps", None)) - - __sortingEnabled = self.listWidget.isSortingEnabled() - self.listWidget.setSortingEnabled(False) - ___qlistwidgetitem = self.listWidget.item(0) - ___qlistwidgetitem.setText(QCoreApplication.translate("Wizard", u"1. Select Project Type", None)); - ___qlistwidgetitem1 = self.listWidget.item(1) - ___qlistwidgetitem1.setText(QCoreApplication.translate("Wizard", u"2. Configure Project", None)); - self.listWidget.setSortingEnabled(__sortingEnabled) - - self.label_11.setText("") - self.label_2.setText(QCoreApplication.translate("Wizard", u"Search", None)) - self.label_3.setText(QCoreApplication.translate("Wizard", u"Language", None)) - ___qtreewidgetitem = self.treeWidget.headerItem() - ___qtreewidgetitem.setText(0, QCoreApplication.translate("Wizard", u"Type", None)); - - __sortingEnabled1 = self.treeWidget.isSortingEnabled() - self.treeWidget.setSortingEnabled(False) - ___qtreewidgetitem1 = self.treeWidget.topLevelItem(0) - ___qtreewidgetitem1.setText(0, QCoreApplication.translate("Wizard", u"Python", None)); - self.treeWidget.setSortingEnabled(__sortingEnabled1) - - self.label_4.setText(QCoreApplication.translate("Wizard", u"Project Type", None)) - - __sortingEnabled2 = self.file_list.isSortingEnabled() - self.file_list.setSortingEnabled(False) - ___qlistwidgetitem2 = self.file_list.item(0) - ___qlistwidgetitem2.setText(QCoreApplication.translate("Wizard", u"Python-Empty", None)); - ___qlistwidgetitem3 = self.file_list.item(1) - ___qlistwidgetitem3.setText(QCoreApplication.translate("Wizard", u"Python-Template-Basic", None)); - ___qlistwidgetitem4 = self.file_list.item(2) - ___qlistwidgetitem4.setText(QCoreApplication.translate("Wizard", u"Python-Template-Plot", None)); - ___qlistwidgetitem5 = self.file_list.item(3) - ___qlistwidgetitem5.setText(QCoreApplication.translate("Wizard", u"Python-Template-PySide2", None)); - self.file_list.setSortingEnabled(__sortingEnabled2) - - self.plainTextEdit.setPlainText("") - self.label_5.setText(QCoreApplication.translate("Wizard", u"Steps", None)) - - __sortingEnabled3 = self.listWidget_2.isSortingEnabled() - self.listWidget_2.setSortingEnabled(False) - ___qlistwidgetitem6 = self.listWidget_2.item(0) - ___qlistwidgetitem6.setText(QCoreApplication.translate("Wizard", u"1. Select Project Type", None)); - ___qlistwidgetitem7 = self.listWidget_2.item(1) - ___qlistwidgetitem7.setText(QCoreApplication.translate("Wizard", u"2. Configure Project", None)); - self.listWidget_2.setSortingEnabled(__sortingEnabled3) - - self.label_9.setText(QCoreApplication.translate("Wizard", u"Project Configuration", None)) - self.projectNameText.setText(QCoreApplication.translate("Wizard", u"Project Name:", None)) - self.projectNameLineEdit.setText(QCoreApplication.translate("Wizard", u"PyMinerProject", None)) - self.projectDirectory.setText(QCoreApplication.translate("Wizard", u"Project Directory:", None)) - self.toolButton.setText(QCoreApplication.translate("Wizard", u"...", None)) - self.absoluteDirectory.setText(QCoreApplication.translate("Wizard", u"Absolute Directory:", None)) - self.warningLabel.setText("") - # retranslateUi - diff --git a/pyminer/features/ui/ui_project_wizard.ui b/pyminer/features/ui/ui_project_wizard.ui deleted file mode 100644 index f59a3618..00000000 --- a/pyminer/features/ui/ui_project_wizard.ui +++ /dev/null @@ -1,543 +0,0 @@ - - - Wizard - - - - 0 - 0 - 736 - 505 - - - - New Project - - - QWizard::ModernStyle - - - QWizard::HelpButtonOnRight|QWizard::NoBackButtonOnStartPage - - - - - 9 - - - 9 - - - 9 - - - 9 - - - - - - 200 - 0 - - - - - 180 - 16777215 - - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - Steps - - - - - - - Qt::Horizontal - - - - - - - border:0px; - - - - 1. Select Project Type - - - - 75 - true - - - - - - 2. Configure Project - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - 5 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - 15 - 15 - - - - - - - :/color/theme/default/icons/search.svg - - - true - - - - - - - Search - - - - - - - - - - - - 9 - - - 0 - - - - - - 180 - 16777215 - - - - - 5 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Language - - - - - - - false - - - - Type - - - - - Python - - - - :/color/theme/default/icons/folder_yellow.svg:/color/theme/default/icons/folder_yellow.svg - - - - - - - - - - - - 16777215 - 16777215 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Project Type - - - - - - - - Python-Empty - - - - :/color/theme/default/icons/python.svg:/color/theme/default/icons/python.svg - - - - - Python-Template-Basic - - - - :/color/theme/default/icons/python.svg:/color/theme/default/icons/python.svg - - - - - Python-Template-Plot - - - - :/color/theme/default/icons/python.svg:/color/theme/default/icons/python.svg - - - - - Python-Template-PySide2 - - - - :/color/theme/default/icons/python.svg:/color/theme/default/icons/python.svg - - - - - - - - - - - - - - 16777215 - 90 - - - - background-color: rgb(243, 243, 243); - - - true - - - - - - - - - - - - - - - - - - 200 - 0 - - - - - 180 - 16777215 - - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - Steps - - - - - - - Qt::Horizontal - - - - - - - border:0px; - - - - 1. Select Project Type - - - - 50 - false - - - - - - 2. Configure Project - - - - 75 - true - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - Project Configuration - - - - - - - Qt::Horizontal - - - - - - - - - Project Name: - - - - - - - PyMinerProject - - - false - - - - - - - Project Directory: - - - - - - - - - - - - true - - - - - - - ... - - - - - - - - - Absolute Directory: - - - - - - - - - - true - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 75 - true - - - - IBeamCursor - - - color: rgb(255, 102, 0); - - - - - - Qt::AutoText - - - - - - - - - - - - - - - - diff --git a/pyminer/features/ui/ui_workspace_launcher.py b/pyminer/features/ui/ui_workspace_launcher.py deleted file mode 100644 index 7afda480..00000000 --- a/pyminer/features/ui/ui_workspace_launcher.py +++ /dev/null @@ -1,121 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'ui_workspace_launcher.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - - -class Ui_Dialog(object): - def setupUi(self, Dialog): - if not Dialog.objectName(): - Dialog.setObjectName(u"Dialog") - Dialog.resize(444, 300) - self.verticalLayout = QVBoxLayout(Dialog) - self.verticalLayout.setSpacing(6) - self.verticalLayout.setObjectName(u"verticalLayout") - self.verticalLayout.setContentsMargins(0, 0, 0, 9) - self.widget = QWidget(Dialog) - self.widget.setObjectName(u"widget") - self.widget.setStyleSheet(u"background-color: rgb(255, 255, 255);") - self.verticalLayout_3 = QVBoxLayout(self.widget) - self.verticalLayout_3.setObjectName(u"verticalLayout_3") - self.verticalLayout_2 = QVBoxLayout() - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.label_4 = QLabel(self.widget) - self.label_4.setObjectName(u"label_4") - font = QFont() - font.setBold(True) - self.label_4.setFont(font) - - self.verticalLayout_2.addWidget(self.label_4) - - self.label_2 = QLabel(self.widget) - self.label_2.setObjectName(u"label_2") - - self.verticalLayout_2.addWidget(self.label_2) - - self.label_5 = QLabel(self.widget) - self.label_5.setObjectName(u"label_5") - - self.verticalLayout_2.addWidget(self.label_5) - - - self.verticalLayout_3.addLayout(self.verticalLayout_2) - - - self.verticalLayout.addWidget(self.widget) - - self.line = QFrame(Dialog) - self.line.setObjectName(u"line") - self.line.setFrameShape(QFrame.HLine) - self.line.setFrameShadow(QFrame.Sunken) - - self.verticalLayout.addWidget(self.line) - - self.widget_2 = QWidget(Dialog) - self.widget_2.setObjectName(u"widget_2") - self.verticalLayout_4 = QVBoxLayout(self.widget_2) - self.verticalLayout_4.setObjectName(u"verticalLayout_4") - self.horizontalLayout_3 = QHBoxLayout() - self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.label_3 = QLabel(self.widget_2) - self.label_3.setObjectName(u"label_3") - - self.horizontalLayout_3.addWidget(self.label_3) - - self.lineEdit_3 = QLineEdit(self.widget_2) - self.lineEdit_3.setObjectName(u"lineEdit_3") - - self.horizontalLayout_3.addWidget(self.lineEdit_3) - - self.toolButton_3 = QToolButton(self.widget_2) - self.toolButton_3.setObjectName(u"toolButton_3") - - self.horizontalLayout_3.addWidget(self.toolButton_3) - - - self.verticalLayout_4.addLayout(self.horizontalLayout_3) - - self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.verticalLayout_4.addItem(self.verticalSpacer) - - self.checkBox = QCheckBox(self.widget_2) - self.checkBox.setObjectName(u"checkBox") - - self.verticalLayout_4.addWidget(self.checkBox) - - self.buttonBox = QDialogButtonBox(self.widget_2) - self.buttonBox.setObjectName(u"buttonBox") - self.buttonBox.setOrientation(Qt.Horizontal) - self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) - - self.verticalLayout_4.addWidget(self.buttonBox) - - - self.verticalLayout.addWidget(self.widget_2) - - - self.retranslateUi(Dialog) - - QMetaObject.connectSlotsByName(Dialog) - # setupUi - - def retranslateUi(self, Dialog): - Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Workspace launcher", None)) - self.label_4.setText(QCoreApplication.translate("Dialog", u"Select a workspace", None)) - self.label_2.setText(QCoreApplication.translate("Dialog", u"PyMiner stores your projects in a folder called a workspace.", None)) - self.label_5.setText(QCoreApplication.translate("Dialog", u"Choose a workspace folder to use for this session.", None)) - self.label_3.setText(QCoreApplication.translate("Dialog", u"Workspace", None)) - self.toolButton_3.setText(QCoreApplication.translate("Dialog", u"Browse...", None)) - self.checkBox.setText(QCoreApplication.translate("Dialog", u"Use this as the default and do not ask again", None)) - # retranslateUi - diff --git a/pyminer/features/ui/ui_workspace_launcher.ui b/pyminer/features/ui/ui_workspace_launcher.ui deleted file mode 100644 index 8a63c0e5..00000000 --- a/pyminer/features/ui/ui_workspace_launcher.ui +++ /dev/null @@ -1,139 +0,0 @@ - - - Dialog - - - - 0 - 0 - 444 - 300 - - - - Workspace launcher - - - - 6 - - - 0 - - - 0 - - - 0 - - - 9 - - - - - background-color: rgb(255, 255, 255); - - - - - - - - - true - - - - Select a workspace - - - - - - - PyMiner stores your projects in a folder called a workspace. - - - - - - - Choose a workspace folder to use for this session. - - - - - - - - - - - - Qt::Horizontal - - - - - - - - - - - - Workspace - - - - - - - - - - Browse... - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Use this as the default and do not ask again - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - diff --git a/pyminer/features/ui/widgets/README.md b/pyminer/features/ui/widgets/README.md deleted file mode 100644 index f9b18e2e..00000000 --- a/pyminer/features/ui/widgets/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# 文本编辑器 -`codeeditwidget.py`当中。 -目前自动补全还是有一定的问题:异步输入的时候,返回的结果往往不正确。 \ No newline at end of file diff --git a/pyminer/features/ui/widgets/__init__.py b/pyminer/features/ui/widgets/__init__.py deleted file mode 100644 index 61e1a2ca..00000000 --- a/pyminer/features/ui/widgets/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .controlpanel import PMPageExt - diff --git a/pyminer/features/ui/widgets/controlpanel.py b/pyminer/features/ui/widgets/controlpanel.py deleted file mode 100644 index c42fb741..00000000 --- a/pyminer/features/ui/widgets/controlpanel.py +++ /dev/null @@ -1,164 +0,0 @@ -import os -import webbrowser - -# 也就是widget_right -from PySide2.QtWidgets import QWidget, QSizePolicy, QListWidget, QListWidgetItem, \ - QHBoxLayout, QLabel, QPushButton, QFileDialog, QVBoxLayout, QMenu, QTableWidget, QTableWidgetItem -from PySide2.QtGui import QPixmap, QCursor -from PySide2.QtCore import Qt, QSize -from pmgwidgets import PMDockObject -from features.extensions.extensions_manager.manager import extensions_manager - - -class ExtInfoWidget(QWidget): - """ - 扩展信息组件,扩展列表中的一项 - """ - - def __init__(self, parent, ext, ext_manager): - """ - parent:父组件 - ext:信息组件对应扩展 - ext_manager:扩展管理器 - """ - super().__init__(parent) - self.ext = ext - self.ext_manager = ext_manager - self.page = parent - self.init_ui() - - def uninstall(self): - """卸载操作""" - self.ext_manager.uninstall(self.ext.info.name) - self.page.init_extensions() - - def refresh(self): - """刷新操作""" - self.ext_manager.refresh(self.ext.info.name) - - def show_menu(self, p): - """右键菜单""" - menu = QMenu(self) - action_info = menu.addAction('卸载') - action_info.triggered.connect(self.uninstall) - action_refresh = menu.addAction('刷新') - action_refresh.triggered.connect(self.refresh) - menu.exec_(QCursor.pos()) - - def info(self): - """展示扩展信息(扩展商店中的)""" - url = f'http://py2cn.com/extensions?name={self.ext.info.name}' - webbrowser.open(url) - - def init_ui(self): - """初始化ui""" - self.layout = QHBoxLayout(self) - - # 扩展图标 - img = QLabel(self) - img_path = os.path.join(self.ext.info.path, self.ext.info.icon) - pixmap = QPixmap(img_path) - pixmap = pixmap.scaledToHeight(50) - img.setPixmap(pixmap) - self.layout.addWidget(img) - - # 扩展名称 - ext_name = QLabel(self) - ext_name.setText(self.ext.info.display_name) - self.layout.addWidget(ext_name) - - # 设置菜单模式,关联菜单事件 - self.setContextMenuPolicy(Qt.CustomContextMenu) - self.customContextMenuRequested.connect(self.show_menu) - - self.setLayout(self.layout) - self.show() - - def mouseDoubleClickEvent(self, *args): - self.info() - - -class PMPageExt(QWidget, PMDockObject): - """ - 扩展选项卡页 - """ - - def __init__(self, main_window): - """ - main_window:主窗口 - """ - super().__init__() - self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) - self.main_window = main_window - self.ext_manager = extensions_manager - self.init_ui() - - # def sizeHint(self) -> QSize: - # return QSize(100,300) - # def resizeEvent(self, a0: QResizeEvent) -> None: - # self.setMaximumWidth(300) - # super().resizeEvent(a0) - - def install(self): - """安装扩展""" - path, _ = QFileDialog.getOpenFileName( - parent=None, - caption='请选择要安装的压缩包', - directory='C:/', - filter='所有文件(*.*);;zip文件(*.zip)', - initialFilter='zip文件(*.zip)' - ) - self.ext_manager.install(path) - # 刷新扩展列表 - self.init_extensions() - - def init_extensions(self): - self.ext_list.clear() # 先清空 - for ext in self.ext_manager.extensions.values(): - item = QListWidgetItem(self.ext_list, 0) - item.setSizeHint(QSize(self.ext_list.width() - 20, 50)) - w = ExtInfoWidget(self, ext, self.ext_manager) - self.ext_list.addItem(item) - self.ext_list.setItemWidget(item, w) - - def init_ui(self): - """初始化ui""" - self.layout = QVBoxLayout(self) - - # 扩展列表 - self.ext_list = QListWidget(self) - self.init_extensions() - self.ext_list.show() - self.layout.addWidget(self.ext_list) - - # 从本地安装按钮 - self.install_btn = QPushButton(self) - self.install_btn.setText('安装 - 从本地') - self.install_btn.clicked.connect(self.install) - self.layout.addWidget(self.install_btn) - - self.setLayout(self.layout) - - -class PMWorkspaceInspectWidget(QTableWidget): - def __init__(self, parnet=None): - super().__init__(parent=None) - self.setRowCount(4) - self.setColumnCount(10) - for i, name in enumerate(['名称', '类型', '大小', '值']): - self.setHorizontalHeaderItem(i, QTableWidgetItem(name)) - # self.setCellWidget() - # self.setItem(0,0,QTableWidgetItem('123123123')) - - def set_data_view(self): - pass - - -if __name__ == '__main__': - from PySide2.QtWidgets import QApplication - import sys - - app = QApplication(sys.argv) - sa = PMWorkspaceInspectWidget() - sa.show() - sys.exit(app.exec_()) diff --git a/pyminer/features/ui/widgets/notificationwidget.py b/pyminer/features/ui/widgets/notificationwidget.py deleted file mode 100644 index bc16acca..00000000 --- a/pyminer/features/ui/widgets/notificationwidget.py +++ /dev/null @@ -1,224 +0,0 @@ -import base64 - -from PySide2.QtCore import Signal, QTimer, QRectF, Qt, QSize -from PySide2.QtGui import QColor, QPainter, QPainterPath, QPixmap, QImage -from PySide2.QtWidgets import QListWidget, QWidget, QListWidgetItem, QHBoxLayout, QGridLayout, QLabel, QSpacerItem, \ - QSizePolicy, QGraphicsDropShadowEffect, QApplication - - -class NotificationItem(QWidget): - closed = Signal(QListWidgetItem) - - def __init__(self, title, message, item, *args, - ntype=0, callback=None, **kwargs): - super(NotificationItem, self).__init__(*args, **kwargs) - self.item = item - self.callback = callback - layout = QHBoxLayout(self) - layout.setSpacing(0) - layout.setContentsMargins(0, 0, 0, 0) - self.bgWidget = QWidget(self) # 背景控件, 用于支持动画效果 - layout.addWidget(self.bgWidget) - - layout = QGridLayout(self.bgWidget) - layout.setHorizontalSpacing(15) - layout.setVerticalSpacing(10) - - # 标题左边图标 - layout.addWidget( - QLabel(self, pixmap=NotificationIcon.icon(ntype)), 0, 0) - - # 标题 - self.labelTitle = QLabel(title, self) - font = self.labelTitle.font() - font.setBold(True) - font.setPixelSize(22) - self.labelTitle.setFont(font) - - # 关闭按钮 - self.labelClose = QLabel( - self, cursor=Qt.PointingHandCursor, pixmap=NotificationIcon.icon(NotificationIcon.Close)) - - # 消息内容 - self.labelMessage = QLabel( - message, self, cursor=Qt.PointingHandCursor, wordWrap=True, alignment=Qt.AlignLeft | Qt.AlignTop) - font = self.labelMessage.font() - font.setPixelSize(20) - self.labelMessage.setFont(font) - self.labelMessage.adjustSize() - - # 添加到布局 - layout.addWidget(self.labelTitle, 0, 1) - layout.addItem(QSpacerItem( - 40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum), 0, 2) - layout.addWidget(self.labelClose, 0, 3) - layout.addWidget(self.labelMessage, 1, 1, 1, 2) - - # 边框阴影 - effect = QGraphicsDropShadowEffect(self) - effect.setBlurRadius(12) - effect.setColor(QColor(0, 0, 0, 25)) - effect.setOffset(0, 2) - self.setGraphicsEffect(effect) - - self.adjustSize() - - # 5秒自动关闭 - self._timer = QTimer(self, timeout=self.doClose) - self._timer.setSingleShot(True) # 只触发一次 - self._timer.start(5000) - - def doClose(self): - # noinspection PyBroadException - try: - # 可能由于手动点击导致item已经被删除了 - self.closed.emit(self.item) - except BaseException: - pass - - def showAnimation(self, width): - # 显示动画 - pass - - def closeAnimation(self): - # 关闭动画 - pass - - def mousePressEvent(self, event): - super(NotificationItem, self).mousePressEvent(event) - w = self.childAt(event.pos()) - if not w: - return - if w == self.labelClose: # 点击关闭图标 - # 先尝试停止计时器 - self._timer.stop() - self.closed.emit(self.item) - elif w == self.labelMessage and self.callback and callable(self.callback): - # 点击消息内容 - self._timer.stop() - self.closed.emit(self.item) - self.callback() # 回调 - - def paintEvent(self, event): - # 圆角以及背景色 - super(NotificationItem, self).paintEvent(event) - painter = QPainter(self) - path = QPainterPath() - path.addRoundedRect(QRectF(self.rect()), 6, 6) - painter.fillPath(path, Qt.white) - - -class NotificationWindow(QListWidget): - _instance = None - - def __init__(self, *args, **kwargs): - super(NotificationWindow, self).__init__(*args, **kwargs) - self.setSpacing(20) - self.setMinimumWidth(412) - self.setMaximumWidth(412) - QApplication.instance().setQuitOnLastWindowClosed(True) - # 隐藏任务栏,无边框,置顶等 - self.setWindowFlags(self.windowFlags() | Qt.Tool | - Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) - # 去掉窗口边框 - self.setFrameShape(self.NoFrame) - # 背景透明 - self.viewport().setAutoFillBackground(False) - self.setAttribute(Qt.WA_TranslucentBackground, True) - # 不显示滚动条 - self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - # 获取屏幕高宽 - rect = QApplication.instance().desktop().availableGeometry(self) - self.setMinimumHeight(rect.height()) - self.setMaximumHeight(rect.height()) - self.move(rect.width() - self.minimumWidth() - 18, 0) - - def removeItem(self, item): - # 删除item - w = self.itemWidget(item) - self.removeItemWidget(item) - item = self.takeItem(self.indexFromItem(item).row()) - w.close() - w.deleteLater() - del item - - @classmethod - def _createInstance(cls): - # 创建实例 - if not cls._instance: - cls._instance = NotificationWindow() - cls._instance.show() - NotificationIcon.init() - - @classmethod - def info(cls, title, message, callback=None): - cls._createInstance() - item = QListWidgetItem(cls._instance) - w = NotificationItem(title, message, item, cls._instance, - ntype=NotificationIcon.Info, callback=callback) - w.closed.connect(cls._instance.removeItem) - item.setSizeHint(QSize(cls._instance.width() - - cls._instance.spacing(), w.height())) - cls._instance.setItemWidget(item, w) - - @classmethod - def success(cls, title, message, callback=None): - cls._createInstance() - item = QListWidgetItem(cls._instance) - w = NotificationItem(title, message, item, cls._instance, - ntype=NotificationIcon.Success, callback=callback) - w.closed.connect(cls._instance.removeItem) - item.setSizeHint(QSize(cls._instance.width() - - cls._instance.spacing(), w.height())) - cls._instance.setItemWidget(item, w) - - @classmethod - def warning(cls, title, message, callback=None): - cls._createInstance() - item = QListWidgetItem(cls._instance) - w = NotificationItem(title, message, item, cls._instance, - ntype=NotificationIcon.Warning, callback=callback) - w.closed.connect(cls._instance.removeItem) - item.setSizeHint(QSize(cls._instance.width() - - cls._instance.spacing(), w.height())) - cls._instance.setItemWidget(item, w) - - @classmethod - def error(cls, title, message, callback=None): - cls._createInstance() - item = QListWidgetItem(cls._instance) - w = NotificationItem(title, message, item, - ntype=NotificationIcon.Error, callback=callback) - w.closed.connect(cls._instance.removeItem) - width = cls._instance.width() - cls._instance.spacing() - item.setSizeHint(QSize(width, w.height())) - cls._instance.setItemWidget(item, w) - - -class NotificationIcon: - Info, Success, Warning, Error, Close = range(5) - Types = { - Info: None, - Success: None, - Warning: None, - Error: None, - Close: None - } - - @classmethod - def init(cls): - cls.Types[cls.Info] = QPixmap(QImage.fromData(base64.b64decode( - 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAC5ElEQVRYR8VX0VHbQBB9e/bkN3QQU0FMBSEVYFcQ8xPBJLJ1FWAqOMcaxogfTAWQCiAVRKkgTgfmM4zRZu6QhGzL0p0nDPr17e7bt7tv14RX/uiV48MJgAon+8TiAMRtMFogaqUJxADPwRRzg67kl8+xbWJWANR40iPQSSFgtX/mGQkaDr56V3VAKgGos4s2JXwJoF3naMPvMS+SrpTHs032GwGkdF+DsFMVnJm/oyGGeHico0EjIjpYes+YMyVd6R/flfkpBWCCQ9zaZM2LZDfLMGXsZ5kdI/lYBmINgHHyyLd1mWdBbAFAM/GY7K2WYx1AeB4T6L1N9umbGxZ0qktATaEAdCps48D39oq/LwEw3U5CN92LfczJoewfT7MAywDCaEbAuxeLrh0zz4L+0e4aAJfGy+sP3IMxlH1vpMJoSMCJDXgWtJeJVc6ACs9HBBrYODCJAFdYvAmkPJxnNqMwYht7Bn+T/lGg3z4DGEd3RPhQ54DBvwAOVkeqagRXfTLjh+x7+8sALOtfHLuiYzWOAiLoKbD58mnIGbCmLxUepS6NQmYlUGE0JeCTTXT9JvA9E9sZgO5iIpoyc6/YzcqSwQzgGgBXB7oXpH9klpRSkxY1xW/b7Iu2zk34PILPnazCqEPAtTWA8iZ0HsOu9L0bw4DzCJeNocMGNDpQ3IKO+6NUiJ4ysZNiBv5I3zPnmJmG5oM+wbS+9+qkvGi7NAXGmeUy0ioofa+XA0jH0UaMKpdRWs/adcwMqfV/tenqpqHY/Znt+j2gJi00RUzA201dXaxh9iZdZloJS+9H1otrkbRrD5InFqpPskxEshJQ468CkSmJC+i1HigaaxCAuCljgoDhwPdOjf7rFVxxuJrMkXScjtKc1rOLNpJk6nii5XmYzbngzlZn+RIb40kPJPTBYXUt6VEDJ8Pi6bWpNFb/jFYY6YGpDeKdjBmTKdMcxDGEmP73v2a2Gr/NOycGtglQZ/MPzEqCMLGckJEAAAAASUVORK5CYII='))) - cls.Types[cls.Success] = QPixmap(QImage.fromData(base64.b64decode( - 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACZUlEQVRYR8VXS3LTQBDtVsDbcAPMCbB3limkcAKSG4QFdnaYE2BOQLKzxSLJCeAGSUQheSnfwLmB2VJhXmpExpFHI2sk2RWv5FJPv9evP9NieuIfPzE+VSJw8qt3IMDvmahDoDYxt2UAACXMWIIowR5ffn8TJbaBWRE4CXvHAH9RgKXOgQUI48CfXZbZbiTw8Xe/w3d0zkydMkem91IZpyWOJu5sUXS+kEAqt3B+MNOLOuDqDEBLxxFHk7eza5MfIwEJDjhXTYD1s8zinYlEjsCD7FdNI9cJpEq0RFdPR47AMOzLCn69zegz6UgCP+pmfa8RSKudnPNdgCufTOLDxJtdPP7PoA1Cd8HEL5sSUCCD0B0x8bc1f8Bi6sevcgS2VXh6hMOwDz0gsUddNaxWKRjeuKfE/KlJ9Dq4UYH/o/Ns6scj+bgiMAjdayb26xLQwTfVEwg3gRcf6ARq578KuLo7VDc8psCQqwfjr4EfjYvkrAquFJ56UYpdSkAZSmNd1rrg0leOQFELgvA58OJTxVyRaAJORPOpF6UXnFUR5sDiXjs7UqsOMGMRlrWhTkJXpFL3mNrQZhA1lH3F0TiI5FurUQyMpn58VjhkSqQA4Tbw4nSVW6sBU5VXktXSeONlJH3s8jrOVr9RgVSFuNcWfzlh5n3LoKzMAPxxWuiULiQpiR2sZNnCyzIuWUr5Z1Ml0sgdHFZaShVDuR86/0huL3VXtDk/F4e11vKsTHLSCeKx7bYkW80hjLOrV1GhWH0ZrSlyh2MwdZhYfi8oZeYgLBmUiGd8sfVPM6syr2lUSYGaGBuP3QN6rVUwYV/egwAAAABJRU5ErkJggg=='))) - cls.Types[cls.Warning] = QPixmap(QImage.fromData(base64.b64decode( - 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACmElEQVRYR8VXTW7TUBD+xjYSXZFukOIsSE9AskNJJMoJmq4r7OYEwAkabhBOkB/Emt4gVIojdpgbpIumEitX6gKB7UHPkauXxLHfc4F6Z3l+vvnmm/fGhAd+6IHzQwvA9cfOITMfAdQAcx1EdVEAM/tEFADsWyaPn57MfdXClABcT1qnzHSWJiwMzrwgoF91vXGRbS6AH59ajd8hDYmoURQo67tgxoij42rv62KX/04Agu44xmciVMokT32YERgGjquvZ1+y4mQCWPUa0/sk3vQlwqssEFsAVrQbU4XKL/ai2+5PPK6waQ4AOsoDnDARh83NdmwBuJq0fQI9L6p+L7rd3+/5gbAToMPI+FbkIzRRc72mbLcGIFE7jGFRIPHddmZrvstJh1X8CHGv6sxHqe1GkPYCoGcqgcoCAPPCdr2DLQC6wqMoPEj7qdqCNKllxs30sLpjYDluDUDGG5XqhY2sal3w4PiD7c7fJnHShMtJR8zpy/8CALiwndnhBgD1/t+XAXkaZAaUVHwnHulg0W6BNEWlAQD8zna8gQB0Ne70iXCm2j55jCUAei1gxvuaO+uXAcDg7zXHSy640iKUAehOEDJFqDmGQkiPLO5Fv+KADXOqvCuIsrPGsIyQdHou22YeRMJgOdHTQTkAfGk7XrLKrWlAvOhcRgBfWiZ3RQti0zxXuUFXCXMuo0TRitfxugjbIxC5RYzI6s9kIGFh+KLOpiW22id5AUuI8IaisFG4kCQg/sFKJgtPLix3KWXGeRETRbQDuCFCV2spTYMm+2FEI1WBbYIRPTeiqFtqLZeDraaD+qrbkpgQAvfl1WsXU0p/RjIjYYhTkNFgcCVlRlRKoAAc+5aF0V//NVPoc2kTLQZKZ8lx/AMXBmMwuXUwOAAAAABJRU5ErkJggg=='))) - cls.Types[cls.Error] = QPixmap(QImage.fromData(base64.b64decode( - 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACrklEQVRYR82XW27aQBSG/4PtiNhIpStouoImKwjZAV1B07coWCpZQcgK6kh2lLeSFZSsIOwgdAdkBaUSEBQDpxpjU9vM+EJR03nDzJz/mzm3GcIrD3plfZQCeD47O1ho2jERNRmoE9AQG2BgBGBAwIiZe5Zh3JPjiG+5oxCAEF5q2iWITnMtRhOYu5XF4mr/9naYtSYXYGLbHQCXhYVTEwlom657rVqvBOB2uz71/a+ldq1SYe6ahnEhc4sSYGzbfQKOt915eh0D/ZrrnqS/SwEmrVYXRJ92Jb4OC+C65rrtuN0NgIltNwF837V4zN5Hy3V70e9NgFZrCKJ3CQDmJ9MwDsW36XzeB/AhA/CHqeuN2WxWX2paX2JraHneeynA+Pz8lCqVbxLjV5brimxAEJxqiEA8CjZVBvFy+bl2c9MV9hInoAw85qFpGEeRYQVEQjzMokcQHWxsiPne8jzh6j8AodGfyqNlHpiGcaKAkIk/gChwm2yYuv5W2FqfwLNtN5bAQ2bwySB83zENo50A8/1McaFRAU72XVek+mpk+D/JlIKI/xkee654uCbIhjVAqZIrgSgpLhiCwN4OAEj4vEB2yDybBCjsAol4ZD0nRdMQSRcUCsKUeNSw4o2mKMRGEOamoVx8FXDZKVosDYNMUHXAsBRnppo8RQcbpTgIGEkhykpFjnWxzGhPQYxt2yHgS/oIlKVYTJxImpG482nz+VG1Wh1N84pMCCGa0ULXHwmoJwCYnyzPW5fn/68dh7EgPbrMMl3gz7gro+n/7EoWD7w4a96l1NnJ1Yz5Lt6wCgFEk0r1CIkbiPnC9DxH5aHcd4FYGD5MOqVOg/muslh0/vphkm63k5eXZvA0I6qD+ZCI3jDzLxANiHn1NNvb6+30aVYgwLeeUsgFW1svsPA3Ncq4MHzVeO8AAAAASUVORK5CYII='))) - cls.Types[cls.Close] = QPixmap(QImage.fromData(base64.b64decode( - 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAeElEQVQ4T2NkoBAwUqifgboGzJy76AIjE3NCWmL0BWwumzV/qcH/f38XpCfHGcDkUVwAUsDw9+8GBmbmAHRDcMlheAGbQnwGYw0DZA1gp+JwFUgKZyDCDQGpwuIlrGGAHHAUGUCRFygKRIqjkeKERE6+oG5eIMcFAOqSchGwiKKAAAAAAElFTkSuQmCC'))) - - @classmethod - def icon(cls, ntype): - return cls.Types.get(ntype) diff --git a/pyminer/features/ui/widgets/reportwidget.py b/pyminer/features/ui/widgets/reportwidget.py deleted file mode 100644 index 9d490968..00000000 --- a/pyminer/features/ui/widgets/reportwidget.py +++ /dev/null @@ -1,37 +0,0 @@ -from PySide2.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QSpacerItem, QSizePolicy, QPushButton -from PySide2.QtCore import QSize, QCoreApplication - - -class PMReportWidget(QWidget): - def __init__(self): - super().__init__() - _translate = QCoreApplication.translate - self.setObjectName("tab_report") - - self.verticalLayout_2 = QVBoxLayout(self) - self.verticalLayout_2.setObjectName("verticalLayout_2") - self.widget_2 = QWidget(self) - self.widget_2.setMaximumSize(QSize(16777215, 30)) - self.widget_2.setObjectName("widget_2") - self.horizontalLayout_5 = QHBoxLayout(self.widget_2) - self.horizontalLayout_5.setContentsMargins(0, 0, 0, 0) - self.horizontalLayout_5.setObjectName("horizontalLayout_5") - self.horizontalLayout_4 = QHBoxLayout() - self.horizontalLayout_4.setObjectName("horizontalLayout_4") - spacerItem1 = QSpacerItem( - 40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - self.horizontalLayout_4.addItem(spacerItem1) - self.pushButton_browser_open = QPushButton(self.widget_2) - self.pushButton_browser_open.setMinimumSize(QSize(80, 0)) - self.pushButton_browser_open.setObjectName("pushButton_browser_open") - self.horizontalLayout_4.addWidget(self.pushButton_browser_open) - self.horizontalLayout_5.addLayout(self.horizontalLayout_4) - self.verticalLayout_2.addWidget(self.widget_2) - self.horizontalLayout_result = QHBoxLayout() - self.horizontalLayout_result.setObjectName("horizontalLayout_result") - spacerItem2 = QSpacerItem( - 20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - self.horizontalLayout_result.addItem(spacerItem2) - self.verticalLayout_2.addLayout(self.horizontalLayout_result) - - self.pushButton_browser_open.setText(_translate("MainWindow", "浏览器打开")) diff --git a/pyminer/features/ui/widgets/resources.py b/pyminer/features/ui/widgets/resources.py deleted file mode 100644 index b6c0463a..00000000 --- a/pyminer/features/ui/widgets/resources.py +++ /dev/null @@ -1,380 +0,0 @@ -from PySide2.QtGui import QPixmap, QIcon - -icon_lc_dbreportedit = QIcon() -icon_lc_dbreportedit.addPixmap(QPixmap(":/pyqt/source/images/lc_dbreportedit.png"), QIcon.Normal, - QIcon.Off) - -icon_lc_draw_chart = QIcon() -icon_lc_draw_chart.addPixmap(QPixmap(":/pyqt/source/images/lc_drawchart.png"), QIcon.Normal, - QIcon.Off) - -icon_lc_save = QIcon() -icon_lc_save.addPixmap( - QPixmap(":/pyqt/source/images/lc_save.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_statisiticsmenu = QIcon() -icon_lc_statisiticsmenu.addPixmap(QPixmap(":/pyqt/source/images/lc_statisticsmenu.png"), QIcon.Normal, - QIcon.Off) - -icon_sc_shadowcurser = QIcon() -icon_sc_shadowcurser.addPixmap( - QPixmap(":/pyqt/source/images/sc_shadowcursor.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_connectorlinesarrowend = QIcon() -icon_lc_connectorlinesarrowend.addPixmap(QPixmap(":/pyqt/source/images/lc_connectorlinesarrowend.png"), QIcon.Normal, - QIcon.Off) - -icon_lc_undo = QIcon() -icon_lc_undo.addPixmap( - QPixmap(":/pyqt/source/images/lc_undo.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_redo = QIcon() -icon_lc_redo.addPixmap( - QPixmap(":/pyqt/source/images/lc_redo.png"), - QIcon.Normal, - QIcon.Off) - -icon_sc_deletepage = QIcon() -icon_sc_deletepage.addPixmap( - QPixmap(":/pyqt/source/images/sc_deletepage.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_aligncenter = QIcon() -icon_lc_aligncenter.addPixmap( - QPixmap(":/pyqt/source/images/lc_aligncenter.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_alignmiddle = QIcon() -icon_lc_alignmiddle.addPixmap( - QPixmap(":/pyqt/source/images/lc_alignmiddle.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_zoomin = QIcon() -icon_lc_zoomin.addPixmap( - QPixmap(":/pyqt/source/images/lc_zoomin.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_zoomout = QIcon() -icon_lc_zoomout.addPixmap( - QPixmap(":/pyqt/source/images/lc_zoomout.png"), - QIcon.Normal, - QIcon.Off) - -icon_dataprovider = QIcon() -icon_dataprovider.addPixmap( - QPixmap(":/pyqt/source/images/dataprovider.png"), - QIcon.Normal, - QIcon.Off) - -icon_sc_autosum = QIcon() -icon_sc_autosum.addPixmap( - QPixmap(":/pyqt/source/images/sc_autosum.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_drawchart = QIcon() -icon_lc_drawchart.addPixmap( - QPixmap(":/pyqt/source/images/lc_drawchart.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_statisticsmenu = QIcon() -icon_lc_statisticsmenu.addPixmap(QPixmap(":/pyqt/source/images/lc_statisticsmenu.png"), QIcon.Normal, - QIcon.Off) - -icon_wordcountdialog = QIcon() -icon_wordcountdialog.addPixmap( - QPixmap(":/pyqt/source/images/wordcountdialog.png"), - QIcon.Normal, - QIcon.Off) - -icon_distributecolumns = QIcon() -icon_distributecolumns.addPixmap(QPixmap(":/pyqt/source/images/distributecolumns.png"), QIcon.Normal, - QIcon.Off) - -icon_dbdistinctvalues = QIcon() -icon_dbdistinctvalues.addPixmap(QPixmap(":/pyqt/source/images/dbdistinctvalues.png"), QIcon.Normal, - QIcon.Off) - -icon_delete_columns = QIcon() -icon_delete_columns.addPixmap( - QPixmap(":/pyqt/source/images/deletecolumns.png"), - QIcon.Normal, - QIcon.Off) - -icon_mergedocuments = QIcon() -icon_mergedocuments.addPixmap( - QPixmap(":/pyqt/source/images/mergedocuments.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_dataarearefresh = QIcon() -icon_lc_dataarearefresh.addPixmap(QPixmap(":/pyqt/source/images/lc_dataarearefresh.png"), QIcon.Normal, - QIcon.Off) - -icon_data_provider = QIcon() -icon_data_provider.addPixmap(QPixmap(":/pyqt/source/images/dataprovider.png"), QIcon.Normal, - QIcon.Off) - -icon_nostackdirectboth_52x60 = QIcon() -icon_nostackdirectboth_52x60.addPixmap(QPixmap(":/pyqt/source/images/nostackdirectboth_52x60.png"), QIcon.Normal, - QIcon.Off) - -icon_columns_52x60 = QIcon() -icon_columns_52x60.addPixmap( - QPixmap(":/pyqt/source/images/columns_52x60.png"), - QIcon.Normal, - QIcon.Off) - -icon_formfilternavigator = QIcon() -icon_formfilternavigator.addPixmap(QPixmap(":/pyqt/source/images/formfilternavigator.png"), QIcon.Normal, - QIcon.Off) -icon_lc_connectorcurve = QIcon() -icon_lc_connectorcurve.addPixmap(QPixmap(":/pyqt/source/images/lc_connectorcurve.png"), QIcon.Normal, - QIcon.Off) -icon_transition_random = QIcon() -icon_transition_random.addPixmap(QPixmap(":/pyqt/source/images/transition-random.png"), QIcon.Normal, - QIcon.Off) - -icon_lc_accepttrackedchange = QIcon() -icon_lc_accepttrackedchange.addPixmap(QPixmap(":/pyqt/source/images/lc_accepttrackedchange.png"), QIcon.Normal, - QIcon.Off) - -icon_lc_datasubtotals = QIcon() -icon_lc_datasubtotals.addPixmap(QPixmap(":/pyqt/source/images/lc_datasubtotals.png"), QIcon.Normal, - QIcon.Off) - -icon_entirecolumn = QIcon() -icon_entirecolumn.addPixmap( - QPixmap(":/pyqt/source/images/entirecolumn.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_selectdb = QIcon() -icon_lc_selectdb.addPixmap( - QPixmap(":/pyqt/source/images/lc_selectdb.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_togglemergecells = QIcon() -icon_lc_togglemergecells.addPixmap(QPixmap(":/pyqt/source/images/lc_togglemergecells.png"), QIcon.Normal, - QIcon.Off) - -icon_lc_datadatapilotrun = QIcon() -icon_lc_datadatapilotrun.addPixmap(QPixmap(":/pyqt/source/images/lc_datadatapilotrun.png"), QIcon.Normal, - QIcon.Off) - -icon_NavOverFlow_Info = QIcon() -icon_NavOverFlow_Info.addPixmap(QPixmap(":/pyqt/source/images/NavOverFlow_Info.png"), QIcon.Normal, - QIcon.Off) - -icon_lc_dbviewtablenames = QIcon() -icon_lc_dbviewtablenames.addPixmap(QPixmap(":/pyqt/source/images/lc_dbviewtablenames.png"), QIcon.Normal, - QIcon.Off) - -icon_graphicfilterpopart = QIcon() -icon_graphicfilterpopart.addPixmap(QPixmap(":/pyqt/source/images/graphicfilterpopart.png"), QIcon.Normal, - QIcon.Off) - -icon_deleterows = QIcon() -icon_deleterows.addPixmap( - QPixmap(":/pyqt/source/images/deleterows.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_renametable = QIcon() -icon_lc_renametable.addPixmap( - QPixmap(":/pyqt/source/images/lc_renametable.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_formatcolumns = QIcon() -icon_lc_formatcolumns.addPixmap(QPixmap(":/pyqt/source/images/lc_formatcolumns.png"), QIcon.Normal, - QIcon.Off) - -icon_lc_closedoc = QIcon() -icon_lc_closedoc.addPixmap( - QPixmap(":/pyqt/source/images/lc_closedoc.png"), - QIcon.Normal, - QIcon.Off) - -icon_netfill = QIcon() -icon_netfill.addPixmap( - QPixmap(":/pyqt/source/images/netfill_52x60.png"), - QIcon.Normal, - QIcon.Off) - -icon_stockcolumns = QIcon() -icon_stockcolumns.addPixmap(QPixmap(":/pyqt/source/images/stockcolumns_52x60.png"), QIcon.Normal, - QIcon.Off) - -icon_bubble = QIcon() -icon_bubble.addPixmap( - QPixmap(":/pyqt/source/images/bubble_52x60.png"), - QIcon.Normal, - QIcon.Off) -icon_areas = QIcon() -icon_areas.addPixmap( - QPixmap(":/pyqt/source/images/areas_52x60.png"), - QIcon.Normal, - QIcon.Off) - -icon_pie = QIcon() -icon_pie.addPixmap( - QPixmap(":/pyqt/source/images/pie_52x60.png"), - QIcon.Normal, - QIcon.Off) - -icon_areaspiled = QIcon() -icon_areaspiled.addPixmap(QPixmap(":/pyqt/source/images/areaspiled_52x60.png"), QIcon.Normal, - QIcon.Off) - -icon_dbviewtables = QIcon() -icon_dbviewtables.addPixmap( - QPixmap(":/pyqt/source/images/dbviewtables.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_autosum = QIcon() -icon_lc_autosum.addPixmap( - QPixmap(":/pyqt/source/images/lc_autosum.png"), - QIcon.Normal, - QIcon.Off) - -icon_New = QIcon() -icon_New.addPixmap( - QPixmap(":/pyqt/source/images/New.png"), - QIcon.Normal, - QIcon.Off) - -icon_folder = QIcon() -icon_folder.addPixmap( - QPixmap(":/pyqt/source/images/folder.png"), - QIcon.Normal, - QIcon.Off) - -icon_input = QIcon() -icon_input.addPixmap( - QPixmap(":/pyqt/source/images/input.png"), - QIcon.Normal, - QIcon.Off) - -icon_Save = QIcon() -icon_Save.addPixmap( - QPixmap(":/pyqt/source/images/Save.png"), - QIcon.Normal, - QIcon.Off) - -icon_wb_setting_normal = QIcon() -icon_wb_setting_normal.addPixmap(QPixmap(":/pyqt/source/images/wb-setting-normal.png"), QIcon.Normal, - QIcon.Off) - -icon_Delete = QIcon() -icon_Delete.addPixmap( - QPixmap(":/pyqt/source/images/Delete.png"), - QIcon.Normal, - QIcon.Off) - -icon_Cut = QIcon() -icon_Cut.addPixmap( - QPixmap(":/pyqt/source/images/Cut.png"), - QIcon.Normal, - QIcon.Off) - -icon_Copy = QIcon() -icon_Copy.addPixmap( - QPixmap(":/pyqt/source/images/Copy.png"), - QIcon.Normal, - QIcon.Off) - -icon_Paste = QIcon() -icon_Paste.addPixmap( - QPixmap(":/pyqt/source/images/Paste.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_formfilternavigator = QIcon() -icon_lc_formfilternavigator.addPixmap(QPixmap(":/pyqt/source/images/lc_formfilternavigator.png"), QIcon.Normal, - QIcon.Off) -icon_lc_mergecells = QIcon() -icon_lc_mergecells.addPixmap( - QPixmap(":/pyqt/source/images/lc_mergecells.png"), - QIcon.Normal, - QIcon.Off) - -icon_hlinettp = QIcon() -icon_hlinettp.addPixmap( - QPixmap(":/pyqt/source/images/hlinettp.png"), - QIcon.Normal, - QIcon.Off) - -icon_dbqueryedit = QIcon() -icon_dbqueryedit.addPixmap( - QPixmap(":/pyqt/source/images/dbqueryedit.png"), - QIcon.Normal, - QIcon.Off) - -icon_infobox = QIcon() -icon_infobox.addPixmap( - QPixmap(":/pyqt/source/images/infobox.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_dbqueryrename = QIcon() -icon_lc_dbqueryrename.addPixmap(QPixmap(":/pyqt/source/images/lc_dbqueryrename.png"), QIcon.Normal, - QIcon.Off) - -icon_lc_dia = QIcon() -icon_lc_dia.addPixmap( - QPixmap(":/pyqt/source/images/lc_dia.png"), - QIcon.Normal, - QIcon.Off) - -icon_lc_dbsortingandgrouping = QIcon() -icon_lc_dbsortingandgrouping.addPixmap(QPixmap(":/pyqt/source/images/lc_dbsortingandgrouping.png"), QIcon.Normal, - QIcon.Off) -icon_lc_insertplugin = QIcon() -icon_lc_insertplugin.addPixmap( - QPixmap(":/pyqt/source/images/lc_insertplugin.png"), - QIcon.Normal, - QIcon.Off) - -icon_jupyter = QIcon() -icon_jupyter.addPixmap( - QPixmap(":/pyqt/source/images/jupyter.png"), - QIcon.Normal, - QIcon.Off) - -icon_python = QIcon() -icon_python.addPixmap( - QPixmap(":/pyqt/source/images/python.png"), - QIcon.Normal, - QIcon.Off) - -icon_ext = QIcon() -icon_ext.addPixmap( - QPixmap(':/pyqt/source/images/extension_32.png'), - QIcon.Normal, - QIcon.Off) - -icon_ext_install = QIcon() -icon_ext_install.addPixmap( - QPixmap(':/pyqt/source/images/Extensions.png.png'), - QIcon.Normal, - QIcon.Off) - - -icon_lc_arrowshapes_right_arrow_callout = QIcon() -icon_lc_arrowshapes_right_arrow_callout.addPixmap( - QPixmap(":/pyqt/source/images/lc_arrowshapes.right-arrow-callout.png"), - QIcon.Normal, QIcon.Off) diff --git a/pyminer/features/util/__init__.py b/pyminer/features/util/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/util/check_update_ui.py b/pyminer/features/util/check_update_ui.py deleted file mode 100644 index f5c30de9..00000000 --- a/pyminer/features/util/check_update_ui.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'check_update_ui.ui' -## -## Created by: Qt User Interface Compiler version 5.15.2 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - - -class Ui_Dialog(object): - def setupUi(self, Dialog): - if not Dialog.objectName(): - Dialog.setObjectName(u"Dialog") - Dialog.resize(546, 173) - self.verticalLayout_2 = QVBoxLayout(Dialog) - self.verticalLayout_2.setObjectName(u"verticalLayout_2") - self.verticalLayout = QVBoxLayout() - self.verticalLayout.setObjectName(u"verticalLayout") - self.label = QLabel(Dialog) - self.label.setObjectName(u"label") - - self.verticalLayout.addWidget(self.label) - - self.horizontalLayout = QHBoxLayout() - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.button_detail = QPushButton(Dialog) - self.button_detail.setObjectName(u"button_detail") - self.button_detail.setMaximumSize(QSize(20, 16777215)) - - self.horizontalLayout.addWidget(self.button_detail) - - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout.addItem(self.horizontalSpacer) - - - self.verticalLayout.addLayout(self.horizontalLayout) - - self.table = QTableWidget(Dialog) - self.table.setObjectName(u"table") - - self.verticalLayout.addWidget(self.table) - - self.horizontalLayout_5 = QHBoxLayout() - self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") - self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - - self.horizontalLayout_5.addItem(self.horizontalSpacer_2) - - self.button_confirm = QPushButton(Dialog) - self.button_confirm.setObjectName(u"button_confirm") - - self.horizontalLayout_5.addWidget(self.button_confirm) - - self.button_close = QPushButton(Dialog) - self.button_close.setObjectName(u"button_close") - - self.horizontalLayout_5.addWidget(self.button_close) - - - self.verticalLayout.addLayout(self.horizontalLayout_5) - - - self.verticalLayout_2.addLayout(self.verticalLayout) - - - self.retranslateUi(Dialog) - - QMetaObject.connectSlotsByName(Dialog) - # setupUi - - def retranslateUi(self, Dialog): - Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"\u66f4\u65b0\u68c0\u6d4b\u7a0b\u5e8f", None)) - self.label.setText("") - self.button_detail.setText(QCoreApplication.translate("Dialog", u"+", None)) - self.button_confirm.setText(QCoreApplication.translate("Dialog", u"\u66f4\u65b0", None)) - self.button_close.setText(QCoreApplication.translate("Dialog", u"\u4e0b\u6b21\u518d\u8bf4", None)) - # retranslateUi - diff --git a/pyminer/features/util/check_update_ui.ui b/pyminer/features/util/check_update_ui.ui deleted file mode 100644 index 6fcaa5e0..00000000 --- a/pyminer/features/util/check_update_ui.ui +++ /dev/null @@ -1,96 +0,0 @@ - - - Dialog - - - - 0 - 0 - 546 - 173 - - - - 更新检测程序 - - - - - - - - - - - - - - - - - - 20 - 16777215 - - - - + - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 更新 - - - - - - - 下次再说 - - - - - - - - - - - - diff --git a/pyminer/features/util/make_update.py b/pyminer/features/util/make_update.py deleted file mode 100644 index 2f29fc66..00000000 --- a/pyminer/features/util/make_update.py +++ /dev/null @@ -1,96 +0,0 @@ -import hashlib -import json -import os -import pathlib -from typing import Dict - -import pathspec - -import utils -from utils import is_mac_platform, is_linux_platform, is_windows_platform - -WINDOWS_X64 = 0 -LINUX_X64 = 1 -MAC_X64 = 2 -CURRENT_PLATFORM = -1 -if is_mac_platform(): - STRIP_LINEEND_FCN = lambda b: b.replace(b'\r', b'\n') -elif is_linux_platform(): - STRIP_LINEEND_FCN = lambda b: b -elif is_windows_platform(): - STRIP_LINEEND_FCN = lambda b: b.replace(b'\r', b'') - -PROJ_ROOT = utils.get_root_dir() - -FOLDERS_TO_IGNORE = [".git"] -FOLDER_NAMES_TO_IGNORE = ["__pycache__"] -FILE_NAMES_TO_IGNORE = ["__latest.json"] - -FOLDERS_TO_IGNORE = [os.path.join(PROJ_ROOT, f) for f in FOLDERS_TO_IGNORE] - -GITIGNORE_PATH = os.path.join(PROJ_ROOT, '.gitignore') - - -def get_filter_list(): - """从gitignore获取忽略文件""" - with open(GITIGNORE_PATH, 'r') as f: - filter_list = f.read().splitlines() - filter_list.append("__latest.json") - return filter_list - - -spec = pathspec.PathSpec.from_lines(pathspec.patterns.GitWildMatchPattern, get_filter_list()) - - -def should_be_recorded(path: pathlib.Path) -> bool: - """ - - :return: - """ - if path.is_dir(): - return False # 文件夹不记录 - if '.git' in str(path): - return False - if spec.match_file(path): - return False - return True - - -def get_file_md5(path): - if not os.path.isfile(path): - return "" - myhash = hashlib.md5() - f = open(path, 'rb') - while True: - b = f.read(8096) - - b = STRIP_LINEEND_FCN(b) # 这里是因为git会自动转换\r\n,为了保证多平台统一,在计算md5码时去除\r - if not b: - break - myhash.update(b) - f.close() - md5 = myhash.hexdigest() - return md5 - - -if __name__ == '__main__': - d: Dict[str, str] = {} - for root, dirs, files in os.walk(PROJ_ROOT): - # if folder_should_be_ignored(root): - # continue - for file in files: - - abso_path = os.path.join(root, file) - - path = pathlib.Path(abso_path) - re_path = str(path.relative_to(PROJ_ROOT)).replace('\\', '/') - if not should_be_recorded(pathlib.Path(abso_path)): - continue - d[re_path] = get_file_md5(abso_path) - if file.startswith("."): - print("aaaaaa", file) - print(re_path) - print(d[re_path]) - print(d) - with open(os.path.join(PROJ_ROOT, "__latest.json"), "w", encoding="utf8") as f: - json.dump({"files": d}, f) diff --git a/pyminer/features/util/openprocess.py b/pyminer/features/util/openprocess.py deleted file mode 100644 index 1d4cc8df..00000000 --- a/pyminer/features/util/openprocess.py +++ /dev/null @@ -1,108 +0,0 @@ -import platform -import queue -import subprocess -import sys -import threading -import time -import chardet -from typing import List - -import packages.code_editor.utils.utils - - -class PMProcess(): - def __init__(self, args: List[str]): - self.terminate = False - self.q = queue.Queue() - self.on_command_received = lambda cmd: print(cmd) - self.on_error_received = lambda error: print(error) - self.args = args - self.process = subprocess.Popen(self.args, - stdin=subprocess.PIPE, - shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - self.to = threading.Thread( - target=self.enqueue_stream, args=( - self.process.stdout, self.q, 1)) - self.te = threading.Thread( - target=self.enqueue_stream_err, args=( - self.process.stderr, self.q, 2)) - self.tp = threading.Thread(target=self.consoleLoop) - self.to.setDaemon(True) - self.te.setDaemon(True) - self.tp.setDaemon(True) - self.te.start() - self.to.start() - self.tp.start() - - def enqueue_stream_err(self, stream, queue, type): - """ - stdout写入到队列q中。 - Args: - stream: - queue: - type: - - Returns: - - """ - for line in iter(stream.readline, b''): - if self.terminate: - break - if platform.system().lower() == 'linux': - encoding = 'utf-8' - else: - encoding = chardet.detect(line)['encoding'] - queue.put(str(type) + packages.code_editor.utils.utils.decode(encoding)) - print(line) - stream.close() - - def enqueue_stream(self, stream, queue, type): # 将stderr或者stdout写入到队列q中。 - """ - stdout写入到队列q中。 - Args: - stream: - queue: - type: - - Returns: - - """ - for line in iter(lambda: stream.read(1), b''): - if self.terminate: - break - if platform.system().lower() == 'linux': - encoding = 'utf-8' - else: - encoding = chardet.detect(line)['encoding'] - queue.put(str(type) + packages.code_editor.utils.utils.decode(encoding)) - stream.close() - - def consoleLoop(self): # 封装后的内容。 - return - idleLoops = 0 - while True: - if not self.q.empty(): - line = self.q.get() - if line[0] == '1': - self.on_command_received(line[1:]) - else: - self.on_error_received(line[1:]) - sys.stdout.flush() - else: - time.sleep(0.01) - if idleLoops >= 5: - idleLoops = 0 - # print('write!!') - self.process.stdin.write( - 'messsage\n'.encode('ascii')) # 模拟输入 - self.process.stdin.flush() - continue - idleLoops += 1 - - -if __name__ == '__main__': - pmp = PMProcess(['python', '-u', - 'test_open_app.py']) - while (1): - time.sleep(2) - pass diff --git a/pyminer/features/util/update.py b/pyminer/features/util/update.py deleted file mode 100644 index 22aad5c8..00000000 --- a/pyminer/features/util/update.py +++ /dev/null @@ -1,364 +0,0 @@ -import hashlib -import logging -import os -import platform -import subprocess -import sys -from pathlib import Path - -import requests -from PySide2.QtCore import Qt, QThread, Signal -from PySide2.QtWidgets import QProgressBar, QVBoxLayout, QLabel, QApplication, QDesktopWidget, QDialog, QHBoxLayout, \ - QPushButton, QTableWidgetItem, QHeaderView, QTableView - -import utils -from features.util.check_update_ui import Ui_Dialog -from features.util.make_update import should_be_recorded - -""" -自动更新逻辑 -1. 在程序启动脚本中,先运行本文件,如果检测到上次更新未完成(存在update.log),则执行更新程序。这部分逻辑应在打包程序时添加 -2. 在系统启动时,后台开启更新检测,若存在更新,弹出对话框,选择是否更新。如是执行更新程序 -3. 手动点击,执行更新程序 -""" - -# MD5_JSON_URL = "https://gitee.com/py2cn/pyminer/raw/dev/__latest.json" -MD5_JSON_URL = "https://gitee.com/py2cn/pyminer/raw/master/__latest.json" - -# REMOTE_URL = 'https://gitee.com/py2cn/pyminer/raw/dev/' # 稳定版 -REMOTE_URL = "https://gitee.com/py2cn/pyminer/raw/master/" - -logger = logging.getLogger(__name__) - - -class BaseUpdateThread(QThread): - def __init__(self, url): - super().__init__() - self.url = url - self.local_files_info = {} - self.remote_files_info = {} - self.delete_files_info = [] - self.update_files_info = [] - self.local_pip_list = [] - self.remote_pip_list = [] - self.root = Path(__file__).parent.parent.parent - - def get_pip_list(self): - platform_ = platform.system() - requirement = 'requirements.txt' - if platform_ == "Linux": - requirement = 'requirements_linux.txt' - elif platform_ == "Mac": - requirement = 'requirements_mac.txt' - path = self.root.joinpath(requirement) - pip_list = [] - if path.is_file(): - with open(path, 'r', encoding='utf-8') as f: - pip_list = f.read().splitlines() - return pip_list - - def get_file_md5(self, path): - if not os.path.isfile(path): - return "" - myhash = hashlib.md5() - f = open(path, 'rb') - while True: - b = f.read(8096) - b = b.replace(b'\r', b'') # 这里是因为git会自动转换\r\n,为了保证多平台统一,在计算md5码时去除\r - if not b: - break - myhash.update(b) - f.close() - md5 = myhash.hexdigest() - return md5 - - def generate_local_files_info(self): - """生成目录树信息""" - for path in self.root.glob('**/*'): - if should_be_recorded(path): - re_path = str(path.relative_to(self.root)).replace('\\', '/') - md5 = self.get_file_md5(path) - self.local_files_info.update( - { - re_path: md5 - } - ) - - def get_remote_json_info(self): - """获取远程文件信息""" - try: - response = requests.get(url=self.url, timeout=5) - except Exception as e: - return - if response.status_code == 200: - self.remote_files_info = response.json()['files'] - - def generate_delete_files_info(self): - if not self.remote_files_info or not self.local_files_info: - return - for key in self.local_files_info.keys(): - if not self.remote_files_info.get(key): - self.delete_files_info.append(key) - - def generate_update_files_info(self): - if not self.remote_files_info or not self.local_files_info: - return - for key in self.remote_files_info.keys(): - if self.local_files_info.get(key): - if self.remote_files_info[key] != self.local_files_info[key]: # md5值不同 - self.update_files_info.append(key) - else: - self.update_files_info.append(key) # 本地不存在 - - -class UpdateTipThread(BaseUpdateThread): - """用于程序启动时检测更新""" - exist_update = Signal(bool) - update_files_list = Signal(list) - delete_files_list = Signal(list) - - def __init__(self, url): - super().__init__(url) - - def run(self): - self.generate_local_files_info() - self.local_pip_list = self.get_pip_list() # 获取当前的pip列表 - self.get_remote_json_info() - self.generate_delete_files_info() - self.generate_update_files_info() - if self.update_files_info or self.delete_files_info: # 检测到可用更新 - # if self.update_files_info: # 检测到可用更新 - self.exist_update.emit(True) - self.update_files_list.emit(self.update_files_info) - self.delete_files_list.emit(self.delete_files_info) - - -class UpdateClientThread(BaseUpdateThread): - """用于执行更新""" - upgrade_bar = Signal(int) # 更新进度条 - tip_label = Signal(str) # 更新进度条 - exit_sign = Signal(bool) - - def __init__(self, url): - super().__init__(url) - - def run(self): - log_path = Path(__file__).parent.joinpath('update.log') - if not log_path.is_file(): - log_path.touch() - self.tip_label.emit('正在收集本地文件信息') - self.generate_local_files_info() - self.local_pip_list = self.get_pip_list() # 获取当前的pip列表 - self.upgrade_bar.emit(20) - self.tip_label.emit('正在查找更新') - self.get_remote_json_info() - self.upgrade_bar.emit(40) - self.tip_label.emit('正在查找可删除文件') - self.generate_delete_files_info() - self.upgrade_bar.emit(50) - self.tip_label.emit('正在查找可更新文件') - self.generate_update_files_info() - self.upgrade_bar.emit(60) - self.tip_label.emit('正在执行更新') - self.perform_update() - self.upgrade_bar.emit(80) - self.tip_label.emit('正在删除多余文件') - self.perform_delete() - self.remote_pip_list = self.get_pip_list() # 再次获取pip列表 - self.upgrade_bar.emit(90) - self.tip_label.emit('正在检查是否需要安装新的第三方库') - self.perform_pip() - os.remove(log_path) # 删除空文件,标志着更新完成 - self.tip_label.emit('更新完成') - self.exit_sign.emit(True) - self.upgrade_bar.emit(100) - - def perform_update(self): - counts = len(self.update_files_info) - for index, item in enumerate(self.update_files_info): - try: - url = REMOTE_URL + item - self.tip_label.emit('正在下载:%s' % url) - response = requests.get(url=url, timeout=5) - except Exception as e: - return - if response.status_code == 200: - local_path = self.root.joinpath(item) - if not local_path.parent.is_dir(): - os.makedirs(local_path.parent) - with open(local_path, 'wb') as f: - f.write(response.content) - self.upgrade_bar.emit(60 + int((index + 1) * 20 / counts)) - - def perform_delete(self): - """执行删除""" - for item in self.delete_files_info: - abs_path = self.root.joinpath(item) - if abs_path.is_file(): - os.remove(abs_path) - - def perform_pip(self): - for item in self.remote_pip_list: - if item not in self.local_pip_list: - self.tip_label.emit('正在安装:%s' % item) - # 推荐的安装方式 - subprocess.check_call( - [sys.executable, "-m", "pip", "install", item, '-i', 'https://pypi.douban.com/simple']) - - -class UpdateTipClient(Ui_Dialog): - def __init__(self, startup: bool): - self.dialog = QDialog() - self.setupUi(self.dialog) - self.url = MD5_JSON_URL - self.update_files_list = [] - self.delete_files_list = [] - self.root = Path(__file__).parent.parent.parent.parent - self.is_start_thread(startup) - - def is_start_thread(self, startup: bool): - """ - 根据根目录下是否存在.git目录,判断是否处于开发状态,开发状态不检查更新 - 根据设置界面检查更新checkbox是否为True,决定是否启动检查更新 - """ - if self.root.joinpath('.git').is_dir(): - return - if not (startup and (not utils.get_settings_item_from_file("config.ini", "MAIN/CHECK_UPDATE"))): - self.thread = UpdateTipThread(url=self.url) - self.thread.update_files_list.connect(self.set_update_files_list) - self.thread.delete_files_list.connect(self.set_delete_files_list) - self.thread.exist_update.connect(self.set_exist_update) - self.thread.start() - - def init_gui(self): - self.update_files_num = 0 - self.delete_files_num = 0 - self.button_close.clicked.connect(self.dialog.close) - self.button_confirm.clicked.connect(self.perform_update) - self.button_detail.clicked.connect(self.show_table) - self.table.setColumnCount(2) - self.table.setHorizontalHeaderLabels(['status', 'file']) - self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents) - self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents) - self.table.setEditTriggers(QTableView.NoEditTriggers) - self.table.setMinimumHeight(300) - self.table.setVisible(False) - self.dialog.setFixedHeight(100) - self.move_center() - if not QApplication.instance(): - app = QApplication(sys.argv) - self.dialog.exec_() - - def move_center(self): - qr = self.dialog.frameGeometry() - cp = QDesktopWidget().availableGeometry().center() - qr.moveCenter(cp) - self.dialog.move(qr.topLeft()) - - def set_update_files_list(self, files): - self.update_files_list = files - row = self.table.rowCount() - self.table.setRowCount(self.table.rowCount() + len(files)) - for index, item in enumerate(self.update_files_list): - self.table.setItem(row + index, 1, QTableWidgetItem(item)) - self.table.setItem(row + index, 0, QTableWidgetItem('update')) - self.set_label() - - def set_delete_files_list(self, files): - self.delete_files_list = files - row = self.table.rowCount() - self.table.setRowCount(row + len(files)) - for index, item in enumerate(self.delete_files_list): - self.table.setItem(row + index, 1, QTableWidgetItem(item)) - self.table.setItem(row + index, 0, QTableWidgetItem('delete')) - self.set_label() - - def set_label(self): - self.label.setText( - "检测到新版本,此次包含{0}个文件更新,{1}个文件删除。".format( - len(self.update_files_list), len(self.delete_files_list))) - - def set_exist_update(self, flag): - """ - 存在更新则启动界面 - """ - if flag: - self.init_gui() - - def perform_update(self): - self.dialog.close() - UpgradeClient(url=self.url) - - def show_table(self): - if self.table.isVisible(): - self.button_detail.setText('+') - self.table.setVisible(False) - self.dialog.setFixedHeight(100) - else: - self.dialog.setFixedHeight(400) - self.button_detail.setText('-') - self.table.setVisible(True) - - -class UpgradeClient(QDialog): - def __init__(self, url): - super().__init__() - self.setWindowTitle("Pyminer客户端升级助手") - self.v_layout = QVBoxLayout() - self.h_layout = QHBoxLayout() - self.button = QPushButton('退出') - self.button.setEnabled(False) - self.button.clicked.connect(lambda: self.close()) - self.upgrade_bar = QProgressBar() - self.tip_label = QLabel("") - self.upgrade_bar.setRange(0, 100) - self.upgrade_bar.setValue(0) - self.v_layout.addWidget(self.tip_label) - self.h_layout.addWidget(self.upgrade_bar) - self.h_layout.addWidget(self.button) - self.v_layout.addLayout(self.h_layout) - self.setWindowFlags(Qt.WindowMinimizeButtonHint) - self.setFixedWidth(500) - self.setFixedHeight(70) - self.move_center() - self.setLayout(self.v_layout) - self.thread = UpdateClientThread(url=url) - self.thread.upgrade_bar.connect(self.set_upgrade_bar) - self.thread.tip_label.connect(self.set_tip_label) - self.thread.exit_sign.connect(self.set_exit_sign) - self.thread.start() - self.exec_() - - def move_center(self): - qr = self.frameGeometry() - cp = QDesktopWidget().availableGeometry().center() - qr.moveCenter(cp) - self.move(qr.topLeft()) - - def set_upgrade_bar(self, i): - self.upgrade_bar.setValue(i) - - def set_tip_label(self, text): - self.tip_label.setText(text) - - def set_exit_sign(self, sign): - self.button.setEnabled(sign) - - -def perform_update(): - if not QApplication.instance(): - app = QApplication(sys.argv) - UpgradeClient(url=MD5_JSON_URL) - - -def check_update_onload(): - """在启动时检查是否需要先执行更新""" - log_path = Path(__file__).parent.joinpath('update.log') - if log_path.is_file(): - perform_update() - - -if __name__ == '__main__': - check_update_onload() - perform_update() diff --git a/pyminer/features/workspace/__init__.py b/pyminer/features/workspace/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/workspace/blinker/__init__.py b/pyminer/features/workspace/blinker/__init__.py deleted file mode 100644 index 3ea239c6..00000000 --- a/pyminer/features/workspace/blinker/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -from blinker.base import ( - ANY, - NamedSignal, - Namespace, - Signal, - WeakNamespace, - receiver_connected, - signal, -) - -__all__ = [ - 'ANY', - 'NamedSignal', - 'Namespace', - 'Signal', - 'WeakNamespace', - 'receiver_connected', - 'signal', - ] - - -__version__ = '1.4' diff --git a/pyminer/features/workspace/blinker/_saferef.py b/pyminer/features/workspace/blinker/_saferef.py deleted file mode 100644 index 269e3624..00000000 --- a/pyminer/features/workspace/blinker/_saferef.py +++ /dev/null @@ -1,234 +0,0 @@ -# extracted from Louie, http://pylouie.org/ -# updated for Python 3 -# -# Copyright (c) 2006 Patrick K. O'Brien, Mike C. Fletcher, -# Matthew R. Scott -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# -# * Neither the name of the nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -"""Refactored 'safe reference from dispatcher.py""" - -import operator -import sys -import traceback -import weakref - - -try: - callable -except NameError: - def callable(object): - return hasattr(object, '__call__') - - -if sys.version_info < (3,): - get_self = operator.attrgetter('im_self') - get_func = operator.attrgetter('im_func') -else: - get_self = operator.attrgetter('__self__') - get_func = operator.attrgetter('__func__') - - -def safe_ref(target, on_delete=None): - """Return a *safe* weak reference to a callable target. - - - ``target``: The object to be weakly referenced, if it's a bound - method reference, will create a BoundMethodWeakref, otherwise - creates a simple weakref. - - - ``on_delete``: If provided, will have a hard reference stored to - the callable to be called after the safe reference goes out of - scope with the reference object, (either a weakref or a - BoundMethodWeakref) as argument. - """ - try: - im_self = get_self(target) - except AttributeError: - if callable(on_delete): - return weakref.ref(target, on_delete) - else: - return weakref.ref(target) - else: - if im_self is not None: - # Turn a bound method into a BoundMethodWeakref instance. - # Keep track of these instances for lookup by disconnect(). - assert hasattr(target, 'im_func') or hasattr(target, '__func__'), ( - "safe_ref target %r has im_self, but no im_func, " - "don't know how to create reference" % target) - reference = BoundMethodWeakref(target=target, on_delete=on_delete) - return reference - - -class BoundMethodWeakref(object): - """'Safe' and reusable weak references to instance methods. - - BoundMethodWeakref objects provide a mechanism for referencing a - bound method without requiring that the method object itself - (which is normally a transient object) is kept alive. Instead, - the BoundMethodWeakref object keeps weak references to both the - object and the function which together define the instance method. - - Attributes: - - - ``key``: The identity key for the reference, calculated by the - class's calculate_key method applied to the target instance method. - - - ``deletion_methods``: Sequence of callable objects taking single - argument, a reference to this object which will be called when - *either* the target object or target function is garbage - collected (i.e. when this object becomes invalid). These are - specified as the on_delete parameters of safe_ref calls. - - - ``weak_self``: Weak reference to the target object. - - - ``weak_func``: Weak reference to the target function. - - Class Attributes: - - - ``_all_instances``: Class attribute pointing to all live - BoundMethodWeakref objects indexed by the class's - calculate_key(target) method applied to the target objects. - This weak value dictionary is used to short-circuit creation so - that multiple references to the same (object, function) pair - produce the same BoundMethodWeakref instance. - """ - - _all_instances = weakref.WeakValueDictionary() - - def __new__(cls, target, on_delete=None, *arguments, **named): - """Create new instance or return current instance. - - Basically this method of construction allows us to - short-circuit creation of references to already- referenced - instance methods. The key corresponding to the target is - calculated, and if there is already an existing reference, - that is returned, with its deletion_methods attribute updated. - Otherwise the new instance is created and registered in the - table of already-referenced methods. - """ - key = cls.calculate_key(target) - current = cls._all_instances.get(key) - if current is not None: - current.deletion_methods.append(on_delete) - return current - else: - base = super(BoundMethodWeakref, cls).__new__(cls) - cls._all_instances[key] = base - base.__init__(target, on_delete, *arguments, **named) - return base - - def __init__(self, target, on_delete=None): - """Return a weak-reference-like instance for a bound method. - - - ``target``: The instance-method target for the weak reference, - must have im_self and im_func attributes and be - reconstructable via the following, which is true of built-in - instance methods:: - - target.im_func.__get__( target.im_self ) - - - ``on_delete``: Optional callback which will be called when - this weak reference ceases to be valid (i.e. either the - object or the function is garbage collected). Should take a - single argument, which will be passed a pointer to this - object. - """ - def remove(weak, self=self): - """Set self.isDead to True when method or instance is destroyed.""" - methods = self.deletion_methods[:] - del self.deletion_methods[:] - try: - del self.__class__._all_instances[self.key] - except KeyError: - pass - for function in methods: - try: - if callable(function): - function(self) - except Exception: - try: - traceback.print_exc() - except AttributeError: - e = sys.exc_info()[1] - print ('Exception during saferef %s ' - 'cleanup function %s: %s' % (self, function, e)) - self.deletion_methods = [on_delete] - self.key = self.calculate_key(target) - im_self = get_self(target) - im_func = get_func(target) - self.weak_self = weakref.ref(im_self, remove) - self.weak_func = weakref.ref(im_func, remove) - self.self_name = str(im_self) - self.func_name = str(im_func.__name__) - - def calculate_key(cls, target): - """Calculate the reference key for this reference. - - Currently this is a two-tuple of the id()'s of the target - object and the target function respectively. - """ - return (id(get_self(target)), id(get_func(target))) - calculate_key = classmethod(calculate_key) - - def __str__(self): - """Give a friendly representation of the object.""" - return "%s(%s.%s)" % ( - self.__class__.__name__, - self.self_name, - self.func_name, - ) - - __repr__ = __str__ - - def __nonzero__(self): - """Whether we are still a valid reference.""" - return self() is not None - - def __cmp__(self, other): - """Compare with another reference.""" - if not isinstance(other, self.__class__): - return cmp(self.__class__, type(other)) - return cmp(self.key, other.key) - - def __call__(self): - """Return a strong reference to the bound method. - - If the target cannot be retrieved, then will return None, - otherwise returns a bound instance method for our object and - function. - - Note: You may call this method any number of times, as it does - not invalidate the reference. - """ - target = self.weak_self() - if target is not None: - function = self.weak_func() - if function is not None: - return function.__get__(target) - return None diff --git a/pyminer/features/workspace/blinker/_utilities.py b/pyminer/features/workspace/blinker/_utilities.py deleted file mode 100644 index 056270d7..00000000 --- a/pyminer/features/workspace/blinker/_utilities.py +++ /dev/null @@ -1,163 +0,0 @@ -from weakref import ref - -from blinker._saferef import BoundMethodWeakref - - -try: - callable -except NameError: - def callable(object): - return hasattr(object, '__call__') - - -try: - from collections import defaultdict -except: - class defaultdict(dict): - - def __init__(self, default_factory=None, *a, **kw): - if (default_factory is not None and - not hasattr(default_factory, '__call__')): - raise TypeError('first argument must be callable') - dict.__init__(self, *a, **kw) - self.default_factory = default_factory - - def __getitem__(self, key): - try: - return dict.__getitem__(self, key) - except KeyError: - return self.__missing__(key) - - def __missing__(self, key): - if self.default_factory is None: - raise KeyError(key) - self[key] = value = self.default_factory() - return value - - def __reduce__(self): - if self.default_factory is None: - args = tuple() - else: - args = self.default_factory, - return type(self), args, None, None, self.items() - - def copy(self): - return self.__copy__() - - def __copy__(self): - return type(self)(self.default_factory, self) - - def __deepcopy__(self, memo): - import copy - return type(self)(self.default_factory, - copy.deepcopy(self.items())) - - def __repr__(self): - return 'defaultdict(%s, %s)' % (self.default_factory, - dict.__repr__(self)) - - -try: - from contextlib import contextmanager -except ImportError: - def contextmanager(fn): - def oops(*args, **kw): - raise RuntimeError("Python 2.5 or above is required to use " - "context managers.") - oops.__name__ = fn.__name__ - return oops - -class _symbol(object): - - def __init__(self, name): - """Construct a new named symbol.""" - self.__name__ = self.name = name - - def __reduce__(self): - return symbol, (self.name,) - - def __repr__(self): - return self.name -_symbol.__name__ = 'symbol' - - -class symbol(object): - """A constant symbol. - - >>> symbol('foo') is symbol('foo') - True - >>> symbol('foo') - foo - - A slight refinement of the MAGICCOOKIE=object() pattern. The primary - advantage of symbol() is its repr(). They are also singletons. - - Repeated calls of symbol('name') will all return the same instance. - - """ - symbols = {} - - def __new__(cls, name): - try: - return cls.symbols[name] - except KeyError: - return cls.symbols.setdefault(name, _symbol(name)) - - -try: - text = (str, unicode) -except NameError: - text = str - - -def hashable_identity(obj): - if hasattr(obj, '__func__'): - return (id(obj.__func__), id(obj.__self__)) - elif hasattr(obj, 'im_func'): - return (id(obj.im_func), id(obj.im_self)) - elif isinstance(obj, text): - return obj - else: - return id(obj) - - -WeakTypes = (ref, BoundMethodWeakref) - - -class annotatable_weakref(ref): - """A weakref.ref that supports custom instance attributes.""" - - -def reference(object, callback=None, **annotations): - """Return an annotated weak ref.""" - if callable(object): - weak = callable_reference(object, callback) - else: - weak = annotatable_weakref(object, callback) - for key, value in annotations.items(): - setattr(weak, key, value) - return weak - - -def callable_reference(object, callback=None): - """Return an annotated weak ref, supporting bound instance methods.""" - if hasattr(object, 'im_self') and object.im_self is not None: - return BoundMethodWeakref(target=object, on_delete=callback) - elif hasattr(object, '__self__') and object.__self__ is not None: - return BoundMethodWeakref(target=object, on_delete=callback) - return annotatable_weakref(object, callback) - - -class lazy_property(object): - """A @property that is only evaluated once.""" - - def __init__(self, deferred): - self._deferred = deferred - self.__doc__ = deferred.__doc__ - - def __get__(self, obj, cls): - if obj is None: - return self - value = self._deferred(obj) - setattr(obj, self._deferred.__name__, value) - return value diff --git a/pyminer/features/workspace/blinker/base.py b/pyminer/features/workspace/blinker/base.py deleted file mode 100644 index cc5880e6..00000000 --- a/pyminer/features/workspace/blinker/base.py +++ /dev/null @@ -1,455 +0,0 @@ -# -*- coding: utf-8; fill-column: 76 -*- -"""Signals and events. - -A small implementation of signals, inspired by a snippet of Django signal -API client code seen in a blog post. Signals are first-class objects and -each manages its own receivers and message emission. - -The :func:`signal` function provides singleton behavior for named signals. - -""" -from warnings import warn -from weakref import WeakValueDictionary - -from blinker._utilities import ( - WeakTypes, - contextmanager, - defaultdict, - hashable_identity, - lazy_property, - reference, - symbol, - ) - - -ANY = symbol('ANY') -ANY.__doc__ = 'Token for "any sender".' -ANY_ID = 0 - - -class Signal(object): - """A notification emitter.""" - - #: An :obj:`ANY` convenience synonym, allows ``Signal.ANY`` - #: without an additional import. - ANY = ANY - - @lazy_property - def receiver_connected(self): - """Emitted after each :meth:`connect`. - - The signal sender is the signal instance, and the :meth:`connect` - arguments are passed through: *receiver*, *sender*, and *weak*. - - .. versionadded:: 1.2 - - """ - return Signal(doc="Emitted after a receiver connects.") - - @lazy_property - def receiver_disconnected(self): - """Emitted after :meth:`disconnect`. - - The sender is the signal instance, and the :meth:`disconnect` arguments - are passed through: *receiver* and *sender*. - - Note, this signal is emitted **only** when :meth:`disconnect` is - called explicitly. - - The disconnect signal can not be emitted by an automatic disconnect - (due to a weakly referenced receiver or sender going out of scope), - as the receiver and/or sender instances are no longer available for - use at the time this signal would be emitted. - - An alternative approach is available by subscribing to - :attr:`receiver_connected` and setting up a custom weakref cleanup - callback on weak receivers and senders. - - .. versionadded:: 1.2 - - """ - return Signal(doc="Emitted after a receiver disconnects.") - - def __init__(self, doc=None): - """ - :param doc: optional. If provided, will be assigned to the signal's - __doc__ attribute. - - """ - if doc: - self.__doc__ = doc - #: A mapping of connected receivers. - #: - #: The values of this mapping are not meaningful outside of the - #: internal :class:`Signal` implementation, however the boolean value - #: of the mapping is useful as an extremely efficient check to see if - #: any receivers are connected to the signal. - self.receivers = {} - self._by_receiver = defaultdict(set) - self._by_sender = defaultdict(set) - self._weak_senders = {} - - def connect(self, receiver, sender=ANY, weak=True): - """Connect *receiver* to signal events sent by *sender*. - - :param receiver: A callable. Will be invoked by :meth:`send` with - `sender=` as a single positional argument and any \*\*kwargs that - were provided to a call to :meth:`send`. - - :param sender: Any object or :obj:`ANY`, defaults to ``ANY``. - Restricts notifications delivered to *receiver* to only those - :meth:`send` emissions sent by *sender*. If ``ANY``, the receiver - will always be notified. A *receiver* may be connected to - multiple *sender* values on the same Signal through multiple calls - to :meth:`connect`. - - :param weak: If true, the Signal will hold a weakref to *receiver* - and automatically disconnect when *receiver* goes out of scope or - is garbage collected. Defaults to True. - - """ - receiver_id = hashable_identity(receiver) - if weak: - receiver_ref = reference(receiver, self._cleanup_receiver) - receiver_ref.receiver_id = receiver_id - else: - receiver_ref = receiver - if sender is ANY: - sender_id = ANY_ID - else: - sender_id = hashable_identity(sender) - - self.receivers.setdefault(receiver_id, receiver_ref) - self._by_sender[sender_id].add(receiver_id) - self._by_receiver[receiver_id].add(sender_id) - del receiver_ref - - if sender is not ANY and sender_id not in self._weak_senders: - # wire together a cleanup for weakref-able senders - try: - sender_ref = reference(sender, self._cleanup_sender) - sender_ref.sender_id = sender_id - except TypeError: - pass - else: - self._weak_senders.setdefault(sender_id, sender_ref) - del sender_ref - - # broadcast this connection. if receivers raise, disconnect. - if ('receiver_connected' in self.__dict__ and - self.receiver_connected.receivers): - try: - self.receiver_connected.send(self, - receiver=receiver, - sender=sender, - weak=weak) - except: - self.disconnect(receiver, sender) - raise - if receiver_connected.receivers and self is not receiver_connected: - try: - receiver_connected.send(self, - receiver_arg=receiver, - sender_arg=sender, - weak_arg=weak) - except: - self.disconnect(receiver, sender) - raise - return receiver - - def connect_via(self, sender, weak=False): - """Connect the decorated function as a receiver for *sender*. - - :param sender: Any object or :obj:`ANY`. The decorated function - will only receive :meth:`send` emissions sent by *sender*. If - ``ANY``, the receiver will always be notified. A function may be - decorated multiple times with differing *sender* values. - - :param weak: If true, the Signal will hold a weakref to the - decorated function and automatically disconnect when *receiver* - goes out of scope or is garbage collected. Unlike - :meth:`connect`, this defaults to False. - - The decorated function will be invoked by :meth:`send` with - `sender=` as a single positional argument and any \*\*kwargs that - were provided to the call to :meth:`send`. - - - .. versionadded:: 1.1 - - """ - def decorator(fn): - self.connect(fn, sender, weak) - return fn - return decorator - - @contextmanager - def connected_to(self, receiver, sender=ANY): - """Execute a block with the signal temporarily connected to *receiver*. - - :param receiver: a receiver callable - :param sender: optional, a sender to filter on - - This is a context manager for use in the ``with`` statement. It can - be useful in unit tests. *receiver* is connected to the signal for - the duration of the ``with`` block, and will be disconnected - automatically when exiting the block: - - .. testsetup:: - - from __future__ import with_statement - from blinker import Signal - on_ready = Signal() - receiver = lambda sender: None - - .. testcode:: - - with on_ready.connected_to(receiver): - # do stuff - on_ready.send(123) - - .. versionadded:: 1.1 - - """ - self.connect(receiver, sender=sender, weak=False) - try: - yield None - except: - self.disconnect(receiver) - raise - else: - self.disconnect(receiver) - - def temporarily_connected_to(self, receiver, sender=ANY): - """An alias for :meth:`connected_to`. - - :param receiver: a receiver callable - :param sender: optional, a sender to filter on - - .. versionadded:: 0.9 - - .. versionchanged:: 1.1 - Renamed to :meth:`connected_to`. ``temporarily_connected_to`` was - deprecated in 1.2 and will be removed in a subsequent version. - - """ - warn("temporarily_connected_to is deprecated; " - "use connected_to instead.", - DeprecationWarning) - return self.connected_to(receiver, sender) - - def send(self, *sender, **kwargs): - """Emit this signal on behalf of *sender*, passing on \*\*kwargs. - - Returns a list of 2-tuples, pairing receivers with their return - value. The ordering of receiver notification is undefined. - - :param \*sender: Any object or ``None``. If omitted, synonymous - with ``None``. Only accepts one positional argument. - - :param \*\*kwargs: Data to be sent to receivers. - - """ - # Using '*sender' rather than 'sender=None' allows 'sender' to be - # used as a keyword argument- i.e. it's an invisible name in the - # function signature. - if len(sender) == 0: - sender = None - elif len(sender) > 1: - raise TypeError('send() accepts only one positional argument, ' - '%s given' % len(sender)) - else: - sender = sender[0] - if not self.receivers: - return [] - else: - return [(receiver, receiver(sender, **kwargs)) - for receiver in self.receivers_for(sender)] - - def has_receivers_for(self, sender): - """True if there is probably a receiver for *sender*. - - Performs an optimistic check only. Does not guarantee that all - weakly referenced receivers are still alive. See - :meth:`receivers_for` for a stronger search. - - """ - if not self.receivers: - return False - if self._by_sender[ANY_ID]: - return True - if sender is ANY: - return False - return hashable_identity(sender) in self._by_sender - - def receivers_for(self, sender): - """Iterate all live receivers listening for *sender*.""" - # TODO: test receivers_for(ANY) - if self.receivers: - sender_id = hashable_identity(sender) - if sender_id in self._by_sender: - ids = (self._by_sender[ANY_ID] | - self._by_sender[sender_id]) - else: - ids = self._by_sender[ANY_ID].copy() - for receiver_id in ids: - receiver = self.receivers.get(receiver_id) - if receiver is None: - continue - if isinstance(receiver, WeakTypes): - strong = receiver() - if strong is None: - self._disconnect(receiver_id, ANY_ID) - continue - receiver = strong - yield receiver - - def disconnect(self, receiver, sender=ANY): - """Disconnect *receiver* from this signal's events. - - :param receiver: a previously :meth:`connected` callable - - :param sender: a specific sender to disconnect from, or :obj:`ANY` - to disconnect from all senders. Defaults to ``ANY``. - - """ - if sender is ANY: - sender_id = ANY_ID - else: - sender_id = hashable_identity(sender) - receiver_id = hashable_identity(receiver) - self._disconnect(receiver_id, sender_id) - - if ('receiver_disconnected' in self.__dict__ and - self.receiver_disconnected.receivers): - self.receiver_disconnected.send(self, - receiver=receiver, - sender=sender) - - def _disconnect(self, receiver_id, sender_id): - if sender_id == ANY_ID: - if self._by_receiver.pop(receiver_id, False): - for bucket in self._by_sender.values(): - bucket.discard(receiver_id) - self.receivers.pop(receiver_id, None) - else: - self._by_sender[sender_id].discard(receiver_id) - self._by_receiver[receiver_id].discard(sender_id) - - def _cleanup_receiver(self, receiver_ref): - """Disconnect a receiver from all senders.""" - self._disconnect(receiver_ref.receiver_id, ANY_ID) - - def _cleanup_sender(self, sender_ref): - """Disconnect all receivers from a sender.""" - sender_id = sender_ref.sender_id - assert sender_id != ANY_ID - self._weak_senders.pop(sender_id, None) - for receiver_id in self._by_sender.pop(sender_id, ()): - self._by_receiver[receiver_id].discard(sender_id) - - def _cleanup_bookkeeping(self): - """Prune unused sender/receiver bookeeping. Not threadsafe. - - Connecting & disconnecting leave behind a small amount of bookeeping - for the receiver and sender values. Typical workloads using Blinker, - for example in most web apps, Flask, CLI scripts, etc., are not - adversely affected by this bookkeeping. - - With a long-running Python process performing dynamic signal routing - with high volume- e.g. connecting to function closures, "senders" are - all unique object instances, and doing all of this over and over- you - may see memory usage will grow due to extraneous bookeeping. (An empty - set() for each stale sender/receiver pair.) - - This method will prune that bookeeping away, with the caveat that such - pruning is not threadsafe. The risk is that cleanup of a fully - disconnected receiver/sender pair occurs while another thread is - connecting that same pair. If you are in the highly dynamic, unique - receiver/sender situation that has lead you to this method, that - failure mode is perhaps not a big deal for you. - """ - for mapping in (self._by_sender, self._by_receiver): - for _id, bucket in list(mapping.items()): - if not bucket: - mapping.pop(_id, None) - - def _clear_state(self): - """Throw away all signal state. Useful for unit tests.""" - self._weak_senders.clear() - self.receivers.clear() - self._by_sender.clear() - self._by_receiver.clear() - - -receiver_connected = Signal("""\ -Sent by a :class:`Signal` after a receiver connects. - -:argument: the Signal that was connected to -:keyword receiver_arg: the connected receiver -:keyword sender_arg: the sender to connect to -:keyword weak_arg: true if the connection to receiver_arg is a weak reference - -.. deprecated:: 1.2 - -As of 1.2, individual signals have their own private -:attr:`~Signal.receiver_connected` and -:attr:`~Signal.receiver_disconnected` signals with a slightly simplified -call signature. This global signal is planned to be removed in 1.6. - -""") - - -class NamedSignal(Signal): - """A named generic notification emitter.""" - - def __init__(self, name, doc=None): - Signal.__init__(self, doc) - - #: The name of this signal. - self.name = name - - def __repr__(self): - base = Signal.__repr__(self) - return "%s; %r>" % (base[:-1], self.name) - - -class Namespace(dict): - """A mapping of signal names to signals.""" - - def signal(self, name, doc=None): - """Return the :class:`NamedSignal` *name*, creating it if required. - - Repeated calls to this function will return the same signal object. - - """ - try: - return self[name] - except KeyError: - return self.setdefault(name, NamedSignal(name, doc)) - - -class WeakNamespace(WeakValueDictionary): - """A weak mapping of signal names to signals. - - Automatically cleans up unused Signals when the last reference goes out - of scope. This namespace implementation exists for a measure of legacy - compatibility with Blinker <= 1.2, and may be dropped in the future. - - .. versionadded:: 1.3 - - """ - - def signal(self, name, doc=None): - """Return the :class:`NamedSignal` *name*, creating it if required. - - Repeated calls to this function will return the same signal object. - - """ - try: - return self[name] - except KeyError: - return self.setdefault(name, NamedSignal(name, doc)) - - -signal = Namespace().signal diff --git a/pyminer/features/workspace/data/__init__.py b/pyminer/features/workspace/data/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/workspace/data_adapter/__init__.py b/pyminer/features/workspace/data_adapter/__init__.py deleted file mode 100644 index 5427329d..00000000 --- a/pyminer/features/workspace/data_adapter/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -TODO 数据结构并没有进行社区讨论,是我拍脑袋写的,后面应当再进行接口及结构类型的合理性分析。 -""" - -from .array import ArrayAdapter -from .base import BaseAdapter -from .detector import Detector -from .universal import UniversalAdapter diff --git a/pyminer/features/workspace/data_adapter/array.py b/pyminer/features/workspace/data_adapter/array.py deleted file mode 100644 index 177e3e4a..00000000 --- a/pyminer/features/workspace/data_adapter/array.py +++ /dev/null @@ -1,67 +0,0 @@ -""" -这个模块是对于 ``np.ndarray`` 进行的封装,也是以此为例探索如何进行数据的封装。 -""" - -# from functools import cached_property -from typing import Any, Tuple, Dict - -import numpy -from sliceable_generator import SliceableGenerator - -from .universal import UniversalAdapter - - -class ArrayAdapter(UniversalAdapter): - data: numpy.ndarray - - # @cached_property - def shape(self) -> Tuple[int, ...]: - """ - 获取矩阵的形状。 - - 矩阵的形状,或者说大小,就是单纯的 ``ndarray.shape`` 。 - - Returns: - 矩阵的形状 - """ - return self.data.shape - - # @cached_property - def serialized_data(self): - """ - 将数据进行序列化。 - - 对于 ``ndarray`` , ``numpy`` 原生的 ``ndarray.tolist()`` 已经可以完美地实现这个功能,没必要进行额外的工作。 - - Returns: - 序列化后的数据,对于 ``ndarray`` 就直接调用了 ``ndarray.tolist()`` 函数。 - """ - return self.data.tolist() - - @classmethod - def load(cls, data: Dict[str, Any]) -> 'ArrayAdapter': - data = numpy.array(data['data']) - return cls(data) - - def get_header_name(self, dimension=0): - """ - 对于矩阵而言,其行列名就是简单的数字。 - - 不同于 ``DataFrame`` , ``array`` 是没有行列名的。 - 此处仅作为占位,返回从0开始的数字列表。 - - 由于 ``python`` 中采用0位置作为数组的第一位,此处采纳相同的用法,采用0作为起点。 - - Args: - dimension: 行列名的维度,这个参数决定了返回值的长度。 - - Returns: - 某个维度下的表头的列表。 - - """ - dimensions = len(self.data.shape) - if dimensions == 1 and dimension == 1: # 一维数组的维度1需要独立定义 - return ('0' for _ in range(1)) - assert 0 <= dimension < dimensions, f'对于此数组,维度应在[0,{dimensions}]范围内' - assert isinstance(dimension, int), '维度应当是整数' - return SliceableGenerator(str(i) for i in range(self.shape[dimension])) diff --git a/pyminer/features/workspace/data_adapter/base.py b/pyminer/features/workspace/data_adapter/base.py deleted file mode 100644 index 5a543bdc..00000000 --- a/pyminer/features/workspace/data_adapter/base.py +++ /dev/null @@ -1,174 +0,0 @@ -# from functools import cached_property -from typing import Any, Tuple, Dict, Union - -from sliceable_generator import SliceableGenerator - -SELECTOR_TYPE = Union[Tuple[Union[int, None], Union[int, None], Union[int, None]], int] - - -class BaseAdapter(object): - """ - 数据适配器的基类。 - - 数据适配器的意义在于,将逻辑与界面进行分离。 - 工作空间中的每一个数据都将是一个数据适配器的实例。 - 这就确保了所有的数据接口统一,可以方便地用于在界面中进行显示, - 而不必要在界面中加入逻辑进行判断。 - - 在这个类中采用了缓存属性的方案,使得一些计算耗时比较长的内容可以仅在需要的时候才进行计算。 - - 所有在 ``pyminer`` 中进行跨线程、跨进程、跨插件的数据交换功能都应当采用这个类的子类的实例进行传输。 - - 目前(2020/11/22)这个适配器仍是一个愿景,各个插件依旧各自为战,后面需要进行整合。 - - 请不要直接继承此类,请继承 ``UniversalAdapter`` 类,以获得更通用的功能,以及新实现的通用方法。 - - """ - data: Any # 请各个子适配器都定义这个data的类型,以便于IDE进行类型提示 - - def __init__(self, data: Any): - self.data = data - - # @cached_property - def shape(self) -> Tuple[int, ...]: - """数据的形状,与 ``numpy`` 保持一致。 - - Returns: - #. 对于没有维度的数据,比如整型、字符串,其尺寸就是一个空元组。 - #. 对于一个长度为 ``n`` 的一维列表,其尺寸就是 (n,) - - - """ - raise NotImplementedError - - # @cached_property - def dimensions(self): - """数据的维度,事实上就是 ``shape`` 的长度的简单计算。""" - return len(self.shape) - - # @cached_property - def abstract(self) -> Dict[str, Any]: - """ - 摘要,用于实现元数据的快速传输 - """ - return { - 'shape': list(self.shape) - } - - # @cached_property - def serialized_data(self): - """ - 实现实际存储的数据的序列化。 - - 数据转变为字符串是通过 ``json.dumps`` 实现的, - 这个接口只需要保证返回值是 ``json.dumps`` 可以解析的内容即可, - 这个接口的具体实现不需要调用 ``json.dumps`` 。 - - 这个接口仅处理数据本身,不包括数据的信息等元数据。 - 关于元数据的处理将在 ``dump`` 接口中进行描述。 - - 以下是一些序列化的示例: - * 对于Numpy的矩阵可以序列化为[[1,2,3],[4,5,6]]。 - * 对于Pandas的表格可以序列化为[[1,2,3],['Tom','Jack','Jenny']]。 - * 对于Pandas等具有行列名的数据结构,其行列名定义在Abstract中,而非serialized_data中。 - - Returns: - 嵌套的 ``dict`` , ``list`` ,以及具体的 ``str`` , ``int`` , ``float`` 等数据。 - 这应该是可以被 ``json.dumps`` 处理的类型。 - """ - raise NotImplementedError - - def dump(self) -> Dict[str, Any]: - """ - 将数据进行序列化。 - - dump/load用于进行数据的交互,即打造类似于pickle的功能,不过可以序列化后通过http进行传输。 - - 目前考虑可能要在Server端添加type信息,因此可能需要保留关键字type。 - - 这个接口将处理包括具体的数据本身,以及元数据在内的所有数据。 - 这个接口相当于实现了 ``pickle`` 的部分功能,可以确保整个 ``Adapter`` 在处理前后保持一致。 - - TODO (panhaoyu) 如果后期采用高速传输方案,将修改这个接口,将value字段设置为内存地址的标识符。 - - Returns: - 所有数据的序列化。 - """ - result = self.abstract.copy() # 这里是浅复制,因为本函数仅修改第一层对象,因此没必要采用深复制 - result['data'] = self.serialized_data - result['type'] = self.__class__.__name__ # 这个用于在反序列化时查找值 - return result - - @classmethod - def load(cls, data: Dict[str, Any]) -> 'BaseAdapter': - """ - 将数据进行反序列化。 - - dump/load用于进行数据的交互,即打造类似于pickle的功能,不过可以序列化后通过http进行传输。 - - 这个接口用于解析由 ``dump`` 函数存储的数据。 - - Args: - data: 由 ``dump`` 进行导出的数据。 - - Returns: - 一个基于 ``dump`` 的导出数据读取得到的新的 ``Adapter`` 的实例。 - - """ - raise NotImplementedError - - def get_array(self) -> Union[SliceableGenerator[Any], Any]: - # TODO (panhaoyu) 这个类型事实上应该采用递归类型进行表示,不过我暂时不会用,就采用 ``Any`` 进行临时的表示了。 - """将数据整合为一个多维数组。 - - 这个方法主要用于切片等需要对数据进行操作的场景。 - - 这个数组采用了 ``SliceableGenerator`` ,以获得懒加载功能以及多维切片功能,相对于 ``list`` 性能较高, - 不过相对于 ``numpy.ndarray`` 的直接索引,还是慢了不少,特殊数据类型还是需要进行优化。 - - Returns: - 由多层生成器构成的多维数组。 - 这个数组的维度以及各维度的大小应当于 ``shape`` 保持一致。 - - Notes: - 这个方法并不包含对数据的切片操作,而是返回了一个可以用于切片的生成器。 - - 这个方法并不一定会返回一个数组! - 如果需要保证可以拿到数组,可以使用 ``get_array_atleast_2d`` 。 - """ - raise NotImplementedError - - def get_array_atleast_2d(self) -> SliceableGenerator[Any]: - """在工作空间的数据查看等场合,需要保证数据类型至少是一个二维数组,以用于表格显式。 - - Returns: - 一个至少是二维的数组。 - - Notes: - ``get_array`` 和 ``get_array_atleast_2d`` 都是有应用场景的。 - ``get_array`` 是用于用户进行切片操作。 - ``get_array_atleast_2d`` 是用于进行表格显示的。 - - """ - raise NotImplementedError - - def get_header_name(self, dimension=0) -> SliceableGenerator[str]: - """ - 获取数据在某个维度上的名称列表。 - - 即使是一维数组,也要同时定义dimension=0和dimension=1。 - - Args: - dimension: 需要查看的维度。 - - Returns: - 该维度上所有表头的名称。 - - """ - raise NotImplementedError - - -if __name__ == '__main__': - from doctest import testmod - - testmod() diff --git a/pyminer/features/workspace/data_adapter/data_frame.py b/pyminer/features/workspace/data_adapter/data_frame.py deleted file mode 100644 index 53231633..00000000 --- a/pyminer/features/workspace/data_adapter/data_frame.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -这个模块是对于 ``np.ndarray`` 进行的封装,也是以此为例探索如何进行数据的封装。 -""" - -# from functools import cached_property -from typing import Any, Tuple, Dict - -from pandas import DataFrame -from sliceable_generator import SliceableGenerator - -from . import ArrayAdapter - - -class DataFrameAdapter(ArrayAdapter): - data: DataFrame - - # @cached_property - def shape(self) -> Tuple[int, int]: - """获取表格的形状,必为一个二维数组""" - return self.data.shape - - # @cached_property - def serialized_data(self): - return self.data.to_dict() - - @classmethod - def load(cls, data: Dict[str, Any]) -> 'DataFrameAdapter': - return cls(DataFrame.from_dict(data['data'])) - - def get_array(self): - return SliceableGenerator(self.data.values, depth=2) - - def get_array_atleast_2d(self): - return self.get_array() - - def get_header_name(self, dimension=0): - assert dimension in (0, 1) - if dimension == 0: - return SliceableGenerator(str(i) for i in self.data.index.to_list()) - else: - return SliceableGenerator(str(i) for i in self.data.columns.to_list()) diff --git a/pyminer/features/workspace/data_adapter/detector.py b/pyminer/features/workspace/data_adapter/detector.py deleted file mode 100644 index a3acb2a7..00000000 --- a/pyminer/features/workspace/data_adapter/detector.py +++ /dev/null @@ -1,121 +0,0 @@ -""" -本模块用于判断一个数据的类型,并将其封装为合适的Adapter。 -""" -from typing import List, Tuple, Dict - -from numpy import ndarray -from pandas import DataFrame - -from features.workspace.data_adapter.array import ArrayAdapter -from features.workspace.data_adapter.base import BaseAdapter -from features.workspace.data_adapter.data_frame import DataFrameAdapter -from features.workspace.data_adapter.universal import UniversalAdapter - - -class Detector: - """ - 类型识别器的作用在于,将任意的类型转换为一个合适的 ``DataAdapter`` 。 - - 在这里补充一个知识点:在 Python 中,一切变量都是对象。 - - >>> class cls: pass - >>> assert isinstance(cls, type) - >>> assert isinstance(type, object) - >>> assert isinstance(type, type) - >>> assert issubclass(cls, object) - >>> assert issubclass(cls, type) is False - >>> assert issubclass(type, object) - - 类是 ``type`` 的实例, ``type`` 是 ``object`` 的实例,同时 ``type`` 也是它本身的实例。 - - 类是 ``object`` 的子类,类不是 ``type`` 的子类, ``type`` 是 ``object`` 的子类。 - - 这个知识点对于本类的开发是必不可少的,因为本类的主要内容就是基于对象的类进行数据适配器的识别与分配。 - - 这个类主要包括了以下内容: - - #. 注册数据类型及其相对应的适配器的映射; - #. 根据已注册的类型实现数据的自动包装; - #. 定义的数据类型到数据适配器的映射 - """ - - def __init__(self): - - # 这个变量用于进行类型与数据适配器的映射。 - # 其中的每一项都是一个列表,采用列表的原因,这保证了数据的有序性。 - # 这里预制了一个类型映射,即将任意类型都映射到 ``UniversalAdapter`` 。 - # 这里并没有预制其他类型映射,因为这些应该在对象初始化时完成。 - # 目前考虑在 ``DataManager`` 里对数据适配器进行初始化,因此内置的类型映射可以在初始化时完成。 - # 内置类型的初始化的定义,是在本类中完成的,这主要是由于内置的数据适配器定义在了本包中, - # 出于解耦的考虑将他们定义在了 ``init`` 函数中。 - self.__data: List[Tuple[type, type]] = [(object, UniversalAdapter)] - - # 这个变量用于进行类型与数据适配器的快速查询。 - # 由于在程序运行过程中,经常发生变量的改变,因此采用O(1)的字典对映射进行缓存。 - self.__cached_data: Dict[type, type] = {} - - def register(self, detect_type: type, adapter_class: type, replace=False) -> None: - """注册一个类型,以用于进行类型识别。 - - 由于PyMiner不可能涵盖所有的数据类型,因此需要插件自行实现其所需要的数据类型。 - - Args: - detect_type: - adapter_class: - replace: 如果已注册过该类型,是否覆盖注册。如不覆盖注册,则会报错。 - - Raises: - ValueError: 如果类型 - - Notes: - TODO (panhaoyu) 该方法尚不支持指定类型的插入顺序,后续应当进行调整。 - 可选的方案是,支持传入一个 ``before`` 参数,支持一个列表的类型,使得新的类型在这些类型之前。 - - """ - assert isinstance(detect_type, type) - assert issubclass(adapter_class, BaseAdapter) - - # 判断类型是否已存在,如已存在且未指定 ``replace=True`` 则报错。 - if any(detect == detect_type for detect, adapter in self.__data) and not replace: - raise ValueError('Register failed, data type already registered, user ``replace=True`` to overwrite.') - - # 由于指定了新的类型,类型的映射关系可能出现改变,需要重建映射,故清空已有的映射关系。 - self.__cached_data.clear() - - # 由于暂不支持指定类型的插入位置,先将其插入在第一位。 - self.__data.insert(0, (detect_type, adapter_class)) - - def detect(self, data: any) -> BaseAdapter: - """根据登录的类型自动识别 - - Args: - data: 任何数据 - - Returns: - 识别数据得到的数据适配器 - - """ - data_type = type(data) - if data_type in self.__cached_data: - return self.__cached_data[data_type](data) - else: - # 如果没有已缓存的数据适配器,则遍历所有数据,查询当前类型对应的数据适配器。 - available = [adapter_class for detect, adapter_class in self.__data if issubclass(data_type, detect)] - # 由于 ``UniversalAdapter`` 的存在,这里一定是可以得到至少一个数据适配器的。 - self.__cached_data[data_type] = available[0] - return available[0](data) - - def init_builtin_adapters(self): - """建立内置数据类型的映射。 - - Notes: - TODO (panhaoyu) 实现多种数据类型的适配,至少要实现内置的 ``list`` 等数据类型以及 ``Pandas`` 的一系列数据类型的适配。 - """ - self.register(ndarray, ArrayAdapter) - self.register(DataFrame, DataFrameAdapter) - - -if __name__ == '__main__': - import doctest - - doctest.testmod() diff --git a/pyminer/features/workspace/data_adapter/index.rst b/pyminer/features/workspace/data_adapter/index.rst deleted file mode 100644 index a3c98bad..00000000 --- a/pyminer/features/workspace/data_adapter/index.rst +++ /dev/null @@ -1,20 +0,0 @@ -============= -数据适配功能 -============= - -.. toctree:: - - array.rst - base_structure.rst - universal.rst - -这个包用于容纳所有PyMiner的数据结构。 - -数据结构主要用于实现适配功能,将不同包里面的优秀数据结构进行整合,包装为PyMiner对象,以达到为PyMiner所用的目的。 -在用户端,并不会看到这些数据结构,而是仍会拿到各个包里面的原始数据结构。 - -目前需要讨论的点是,数据结构是采用大而全的方式,还是采用小而精的方式? -具体的数据结构还要部分依赖于Reco的C共享内存实现,目前只是一个快速开发的版本。 - -之前考虑过直接继承numpy.ndarray等数据结构,不过在实际的操作中发现较多问题,目前已放弃,转为采用Adapter的思路。 - diff --git a/pyminer/features/workspace/data_adapter/universal.py b/pyminer/features/workspace/data_adapter/universal.py deleted file mode 100644 index 6e637e0a..00000000 --- a/pyminer/features/workspace/data_adapter/universal.py +++ /dev/null @@ -1,47 +0,0 @@ -import pickle -# from functools import cached_property -from typing import Any, Dict, Tuple - -from sliceable_generator import SliceableGenerator - -from .base import BaseAdapter - - -class UniversalAdapter(BaseAdapter): - """ - 该适配器可以传递一切对象。 - - TODO (panhaoyu) 不能传递动态类型 - """ - data: Any - - # @cached_property - def shape(self) -> Tuple[int, ...]: - """通用类型是没有维度的,这可以适用于一切类型,而对于存在维度的数据类型,应该独立地定义一个适配器。""" - return () - - # @cached_property - def serialized_data(self): - return pickle.dumps(self.data) - - @classmethod - def load(cls, data: Dict[str, Any]) -> 'BaseAdapter': - return cls(pickle.loads(data['data'])) - - def get_array(self): - if self.dimensions > 0: - return SliceableGenerator(self.data, depth=self.dimensions) - else: - return self.data - - def get_array_atleast_2d(self): - if self.dimensions > 1: - return self.get_array() - elif self.dimensions == 1: - return SliceableGenerator((self.get_array() for _ in range(1)), depth=2) - else: - return SliceableGenerator(((self.get_array() for _ in range(1)) for __ in range(1))) - - def get_header_name(self, dimension=0): - assert dimension in (0, 1), 'Dimension only supports `0` or `1`' - return SliceableGenerator('0' for _ in range(1)) diff --git a/pyminer/features/workspace/data_manager.py b/pyminer/features/workspace/data_manager.py deleted file mode 100644 index 4387b218..00000000 --- a/pyminer/features/workspace/data_manager.py +++ /dev/null @@ -1,226 +0,0 @@ -""" -该模块用于承载数据管理的功能,即工作空间。 - -``DataManager`` 类,其实例就是工作空间,提供了包括添加变量、删除变量、历史记录回溯、历史记录访问量等内容。 - -该模块在设计时考虑了历史记录功能,不过该功能是否有必要,还有待商榷。 - -该模块的操作对象为 ``DataAdapter``。 -将数据外面包上一层可以确保其元数据的识别等便利性。 -关于 ``DataAdapter`` 的详细内容请参见相关文档。 - -""" -from collections import OrderedDict -from typing import Dict, Tuple, List, Any - -from features.workspace.data_adapter import BaseAdapter -from features.workspace.data_adapter import Detector -from .signals import workspace_data_created, workspace_data_deleted, workspace_data_changed - - -class DataManager(object): - """ - 数据管理类。 - - 应当注意的时,数据管理的对象,是 ``DataAdapter`` 而不是原生的数据。 - - 如果需要写入一个原生数据,可以采用 ``set_raw_data`` 方法。 - - 值得一提的是,最初的设想,通过 ``__setitem__`` 写入原生数据,然后通过 ``__getitem__`` 读出数据适配器。 - 但是这样相当于与字典的功能发生了较大的差异,一个 python 用户的习惯应该是写入什么就取出什么,这不符合 python 用户的习惯。 - 因此,采用了一个独立的方法 ``set_raw_data`` 用于写入原生数据并自动进行识别。 - """ - - def __init__(self): - # TODO 将历史记录的上限和回收站的上限作为对象初始化的参数进行传值 - - # Container数据结构中管理器的主要内容。 - # 其键为变量名,值为两个列表构成的元组,共同用来表示历史记录。 - # 变量的历史记录和大多数程序一致,都是采用单线式的历史记录管理策略,如下所示: - # 当前记录:[1,2,3,4,5,6,7],[] - # 撤销一次:[1,2,3,4,5,6],[7] - # 撤销一次:[1,2,3,4,5],[6,7] - # 重做一次:[1,2,3,4,5,6],[7] - # 写入一次:[1,2,3,4,5,6,8],[] # 写入时删除重做列表 - self.container: Dict[str, Tuple[List[BaseAdapter], List[BaseAdapter]]] = dict() - - # RecycleBin用于存储用户明确删除的变量,其基本工作流程的伪代码如下所示: - # 当前空间:container={a,b,c}, recycle_bin={} - # 删除a: container={b,c}, recycle_bin={a} - # 删除b: container={c}, recycle_bin={a,b} - # 恢复a: container={a,c}, recycle_bin={b} - self.recycle_bin = OrderedDict() - - # 数据适配器自动识别类 - self.detector = Detector() - self.detector.init_builtin_adapters() - - def __getitem__(self, key: str) -> BaseAdapter: - """ - 从工作空间读取变量。 - - Args: - key: 变量名 - - Returns: - BaseAdapter: 变量值的Adapter,不是原始值 - - """ - current, future = self.container[key] - current or self.__raise_key_error(key) - return current[-1] - - def __setitem__(self, key: str, value: BaseAdapter): - """ - 将变量写入工作空间 - - Args: - key: 变量名 - value: 变量值,应该是 ``BaseAdapter`` 的子类。 - """ - created = False # 用于记录本次操作是新建了一个变量还是修改了一个变量 - assert isinstance(value, BaseAdapter) - - # 首先确保工作空间中有该变量的历史记录容器 - if key not in self.container: # 如果工作空间中没有该变量 - created = True - if key not in self.recycle_bin: # 回收站中也没有,新建该变量的历史记录 - self.container[key] = ([], []) - else: # 从回站中恢复 - self.container[key] = self.recycle_bin[key] - del self.recycle_bin[key] - - # 处理历史记录相关内容 - current, future = self.container[key] - if future: - future.clear() - if not current: - created = True - current.append(value) - if len(current) > 15: # 对每个变量的最多保存的历史记录数量 - current.pop(0) - if created: - workspace_data_created.send(self, key=key) - else: - workspace_data_changed.send(self, key=key) - - def __delitem__(self, key: str): - """ - 在工作空间中删去一个变量。 - - Args: - key: 需要删去的变量名。 - """ - # TODO (panhaoyu) 这里实际应当进行当前工作空间的变量和回收站中的变量的合并,此处时间原因先采用直接替换的方式 - key in self.container or self.__raise_key_error(key) - self.recycle_bin[key] = self.container[key] - del self.container[key] - workspace_data_deleted.send(self, key=key) - - def __contains__(self, item: str): - """检查工作空间中是否已存在某个变量""" - return item in self.container - - def __iter__(self): - yield from self.container - - def set_raw_data(self, key: str, value: Any): - """将一个原生变量写入数据管理器。 - - Args: - key: 变量名。 - value: 原生变量。 - """ - self[key] = self.detector.detect(value) - - def back(self, key: str) -> bool: - """ - 将变量撤回到前一个历史记录点。 - - Args: - key: 变量名 - - Returns: - bool: 变量是否撤销成功 - - """ - key in self.container or self.__raise_key_error(key) - current, future = self.container[key] - if len(current) < 2: - return False - future.insert(0, current.pop()) - return True - - def forward(self, key: str) -> bool: - """ - 重做变量,即使得变量前进一个历史记录点。 - - Args: - key: 变量名 - - Returns: - 变量是否重做成功 - """ - key in self.container or self.__raise_key_error(key) - current, future = self.container[key] - if not future: - return False - current.append(future.pop(0)) - if len(current) > 15: - current.pop(0) - return True - - def restore_from_recycle_bin(self, key: str): - """ - 从回收站中恢复一个变量。 - - 这将覆盖工作空间中的同名变量!需要弹窗警告! - 这个方法的名字很长,就是为了防止与“从历史记录中前移一位”功能相混淆。 - - Args: - key: 变量名 - """ - key in self.recycle_bin or self.__raise_key_error(key, '回收站') - self.container[key] = self.recycle_bin[key] - workspace_data_created.send(key=key) - del self.recycle_bin[key] - - def __raise_key_error(self, key: str, position='工作空间'): - raise KeyError(f'{position}未定义变量:{key}') - - def keys(self) -> List[str]: - """ - 将工作空间内的名字作为一个列表返回。 - - 每次都返回一个新列表。 - - Returns: - 变量名的列表。 - """ - return list(self.container.keys()) - - def values(self) -> List[BaseAdapter]: - """ - 将工作空间内的值作为一个列表返回。 - - 每次都返回一个新列表。 - Returns: - 变量值的列表。 - """ - return [current[-1] for current, future in self.container.values()] - - def items(self) -> List[Tuple[str, BaseAdapter]]: - """ - 将工作空间的键值对作为一个列表返回。 - - 每次都返回一个新列表。 - - Returns: - 工作空间的数据的键值对 - """ - return [(key, history[0][-1]) for key, history in self.container.items()] - - -# 请不要直接使用此变量! -# 目前已知的用法仅有两处,一个是在 workspace_old ,一个是在 extension_lib 。 -data_manager = DataManager() diff --git a/pyminer/features/workspace/index.rst b/pyminer/features/workspace/index.rst deleted file mode 100644 index 8ce081cd..00000000 --- a/pyminer/features/workspace/index.rst +++ /dev/null @@ -1,31 +0,0 @@ -============================================================================== -工作空间v2 -============================================================================== - -这一部分本意是取代已有的workspace,打造一个全新的workspace。 - -通过进行架构的调整使得其可以获得较好的性能,并可以嵌入 ``DataAdapter`` 内容。 - -目前共享内存版本的工作空间已进入最后阶段,待共享内存版本稳定后,本工作空间将进行兼容。 - -目前已成功替代现有的 ``workspace`` 。 - -新版的工作空间同样是支持历史记录功能的,但是对于数据的拷贝并没有进行很好的实现, -即,如果对数据进行原位修改,工作空间是无法识别的。 -由于现在是否需要历史记录功能还未存在定论,故暂不对此功能进行优化。 -如果确实需要进行优化,则可以在 ``adapter`` 层面添加 ``copy`` 方法, -在 ``DataManager.__getitem__`` 里返回 ``adapter.copy()`` 。 -暂时没有实现的计划,因此工作空间的历史记录功能是不可用的。 - -新版的工作空间仅经过了简单的单元测试,后面需要进行完善。 - -.. automodule:: features.workspace2 - - -.. toctree:: - :maxdepth: 2 - - - data_manager.rst - signals.rst - diff --git a/pyminer/features/workspace/signals.py b/pyminer/features/workspace/signals.py deleted file mode 100644 index 63243001..00000000 --- a/pyminer/features/workspace/signals.py +++ /dev/null @@ -1,9 +0,0 @@ -import os -import sys -sys.path.append(os.path.dirname(__file__)) - -from .blinker import signal - -workspace_data_changed = signal('workspace-data-changed') -workspace_data_created = signal('workspace-data-created') -workspace_data_deleted = signal('workspace-data-deleted') diff --git a/pyminer/features/workspace/signals.rst b/pyminer/features/workspace/signals.rst deleted file mode 100644 index e77e2970..00000000 --- a/pyminer/features/workspace/signals.rst +++ /dev/null @@ -1,66 +0,0 @@ -================== -信号 -================== - -工作空间中发生的事件将通过信号的方式传递给插件。 - -.. note:: - - 在旧版工作空间中,变量的增删改查是通过回调函数的方式添加的,在新版的工作空间中,也同样是采用的回调函数。 - 区别在于,旧版工作空间中是将回调的管理功能写入在了工作空间类中,而新版的工作空间是采用了 blinker_ 进行实现的。 - 有关于 blinker_ 的用法,请参考相应的文档,这里不进行过多介绍。 - -.. _blinker: https://pythonhosted.org/blinker/ - -回调函数的使用方法可以直接参考测试用例: ``tests.test_workspace2.test_data_manager.TestSignals`` 中的用法。 -由于正在开发中,可能会出现频繁的更新,因此以测试用例中的内容为准。 - -目前支持以下信号: - -.. py:data:: workspace_data_created - - 工作空间中添加了新的数据。 - - .. code-block:: python - - @workspace_data_created.connect - def created(sender: DataManager, key: str): - pass - -.. py:data:: workspace_data_changed - - 工作空间中已有的数据发生了改变。 - - .. code-block:: python - - @workspace_data_changed.connect - def changed(sender: DataManager, key: str): - pass - - .. note:: - - 这个信号的参数仅仅传入了一个 ``key`` ,因为如果需要获取其历史记录,这应该是 ``DataManager`` 提供方法进行调用, - 而不是通过信号的参数进行传输。 - -.. py:data:: workspace_data_deleted - - 工作空间中的数据被删除了。 - - .. code-block:: python - - @workspace_data_deleted.connect - def deleted(sender: DataManager, key: str): - pass - - .. note:: - - 这个数据并不会真的被删除,而是被移入了回收站,在工作空间中看不见了。 - -.. note:: - - 相比于之前的旧版 ``workspace`` ,通过传递 ``provider`` 以判断是否是本插件传递过去的数据, - 新版的 ``workspace`` 使用完全基于信号与事件的传递方式,不需要再判断 ``provider`` 。 - -这里支持的信号的数量比较少,因为并不清楚是否需要支持其他的信号。 -比如是否可以在数据创建前,激发一个信号,根据信号的返回值判断是否阻止创建这个数据。 -目前并没有发现相关需求,如果确实需要,可以添加。 diff --git a/pyminer/features/workspace_old/__init__.py b/pyminer/features/workspace_old/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/workspace_old/datamanager/__init__.py b/pyminer/features/workspace_old/datamanager/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/features/workspace_old/datamanager/converter.py b/pyminer/features/workspace_old/datamanager/converter.py deleted file mode 100644 index 8bba5c0b..00000000 --- a/pyminer/features/workspace_old/datamanager/converter.py +++ /dev/null @@ -1,73 +0,0 @@ -from typing import TYPE_CHECKING -if TYPE_CHECKING: - import numpy as np - import pandas as pd - -from pyminer2.workspace_old.datamanager.variable import Variable -from .exceptions import ConvertError - - -class Converter: - def __init__(self, data_manager): - self.data_manager = data_manager - - def convert_to_data(self, var) -> dict: - typename = type(var).__name__ - convert_func = f'convert_{typename.lower()}' - if hasattr(self, convert_func): - return getattr(self, convert_func)(var) - elif isinstance(var, Variable): - return var.dump() - else: - raise ConvertError(f'{var} is inconvertible') - - def convert_to_var(self, data: dict): - assert self.data_manager.dataset.is_valid(data) - var = Variable(data['type'], data) - try: - # in case any error which means unsupported type - iconvert_func = f'iconvert_{data["type"].lower()}' - return getattr(self, iconvert_func)(var) - except BaseException: - # no valid converter - return var - - # convert to data, func format: convert_obj - - def convert_ndarray(self, arr: 'np.ndarray') -> dict: - # TODO (panhaoyu) 三维数组甚至四维数组都是很常见的数据格式,应该支持 - import numpy as np - if arr.dtype in (np.int, np.float): - if len(arr.shape) == 2: - return Variable('Matrix', {'value': arr.tolist()}).dump() - elif len(arr.shape) == 1: - return Variable('Vector', {'value': arr.tolist()}).dump() - else: - raise ConvertError - else: - raise ConvertError(f'{arr} is inconvertible') - - def convert_list(self, lst: list) -> dict: - import numpy as np - return self.convert_ndarray(np.array(lst)) - - def convert_dataframe(self, dataframe: 'pd.DataFrame') -> dict: - return Variable('DataFrame', {'table': dataframe.values.tolist(), 'columns': dataframe.columns.tolist()}) - - # convert to var, func format: iconvert_type - # TODO (panhaoyu) 这三个函数目前没有在pycharm中发现调用,是否可以删除? - - def iconvert_matrix(self, mat: Variable) ->'np.ndarray': - import numpy as np - assert mat.type == 'Matrix' - return np.array(mat['value']) - - def iconvert_vector(self, vec: Variable) -> 'np.ndarray': - import numpy as np - assert vec.type == 'Vector' - return np.array(vec['value']) - - def iconvert_dataframe(self, dataframe: Variable) -> 'pd.DataFrame': - import pandas as pd - assert dataframe.type == 'DataFrame' - return pd.DataFrame(dataframe['table'], columns=dataframe['columns']) diff --git a/pyminer/features/workspace_old/datamanager/datamanager.py b/pyminer/features/workspace_old/datamanager/datamanager.py deleted file mode 100644 index a94f6bd6..00000000 --- a/pyminer/features/workspace_old/datamanager/datamanager.py +++ /dev/null @@ -1,77 +0,0 @@ -from contextlib import contextmanager -from typing import Dict, Union, Any - -from pyminer_comm.base import DataDesc -from features.workspace.data_manager import data_manager as next_data_manager -from features.workspace.signals import workspace_data_created, workspace_data_changed, workspace_data_deleted -from features.workspace_old.datamanager.exceptions import NotFoundError - - -class DataManager: - def __init__(self): - self.next_data_manager = next_data_manager - self.provider = 'unknown' - self.__weakref_protector = [] # 用于避免弱引用的回调函数被销毁 - - @contextmanager - def set_provider(self, provider='unknown'): - self.provider = provider - yield - self.provider = 'unknown' - - def get_all_var(self) -> Dict[str, Any]: - return {k: v.data for k, v in self.next_data_manager.items()} - - def get_all_public_var(self) -> Dict[str, Union[object, int, float]]: - return self.get_all_var() - - def get_vars_of_types(self, types): - return {k: v.data for k, v in self.next_data_manager.items() if isinstance(v, types)} - - def get_var(self, key: str): - if key not in self.next_data_manager.keys(): - raise NotFoundError(f'{key} not found') - return self.next_data_manager[key].data - - def get_data_info(self, key: str) -> dict: - if key not in self.next_data_manager.keys(): - raise NotFoundError(f'{key} not found') - return self.next_data_manager[key].abstract - - def set_var_dict(self, variables: dict, provider='unknown', info_dict=None): - with self.set_provider(provider): - for k, v in variables.items(): - self.next_data_manager.set_raw_data(k, v) - - def set_var(self, key: str, value, provider='unknown', **info): - assert isinstance(value, DataDesc), 'Variable name:%s value:%s is not instance of DataDesc!' % (key, value) - with self.set_provider(provider): - self.next_data_manager.set_raw_data(key, value) - - def delete_data(self, key: str, provider='unknown'): - with self.set_provider(provider): - del self.next_data_manager[key] - - def clear(self): - for key in self.next_data_manager.keys(): - del self.next_data_manager[key] - - def on_modification(self, modification_callback): - def changed(sender, key: str): - value = self.next_data_manager[key] - modification_callback(key, value.data, self.provider) - - self.__weakref_protector.append(changed) - - workspace_data_created.connect(changed) - workspace_data_changed.connect(changed) - - def on_deletion(self, deletion_callback): - def deleted(sender, key: str): - deletion_callback(key, self.provider) - - self.__weakref_protector.append(deleted) - workspace_data_deleted.connect(deleted) - - -data_manager = DataManager() diff --git a/pyminer/features/workspace_old/datamanager/dataset.py b/pyminer/features/workspace_old/datamanager/dataset.py deleted file mode 100644 index e11bc705..00000000 --- a/pyminer/features/workspace_old/datamanager/dataset.py +++ /dev/null @@ -1,130 +0,0 @@ -from pyminer2.workspace_old.datamanager.exceptions import ConflictError - - -class DataSet(dict): - """ - 这个类主要用于对变量进行管理,包括以下内容: - * 添加内置类型,定义新的类型 - * 对变量根据类型进行校核,支持递归校核 - """ - - def __init__(self): - super().__init__() - self.__insert_builtin_type__('Type', {'type': 'Type', 'structure': { - 'structure': 'dict', - }}) - # TODO (panhaoyu) 把这种基本数据类型进行如此的定义,性能不会受影响吗? - # TODO (panhaoyu) 内置数据类型是否过多? - self.__insert_builtin_type__('Complex', {'type': 'Type', 'structure': { - 'real': 'float', - 'imag': 'float', - }}) - self.__insert_builtin_type__('Matrix', {'type': 'Type', 'structure': { - 'value': [['float|int|Complex']], - }}) - self.__insert_builtin_type__('Vector', {'type': 'Type', 'structure': { - 'value': ['float|int|Complex'], - }}) - self.__insert_builtin_type__('TimeSeries', {'type': 'Type', 'structure': { - 'time': ['float|int'], - 'data': ['float|int'], - }}) - self.__insert_builtin_type__('StateSpace', {'type': 'Type', 'structure': { - 'A': 'Matrix', - 'B': 'Matrix', - 'C': 'Matrix', - 'D': 'Matrix', - 'x': ['str'], - 'y': ['str'], - 'u': ['str'], - 'sys': 'str', - }}) - self.__insert_builtin_type__('DataFrame', {'type': 'Type', 'structure': { - 'table': [['float|int|Complex|str']], - 'columns': ['str'], - }}) - - # TODO (panhaoyu) series与矩阵有什么区别呢? - self.__insert_builtin_type__('Series', {'type': 'Type', 'structure': { - 'value': [['float|int|Complex|str']], - }}) - self.builtin_types = self.select_type('Type') - - def __insert_builtin_type__(self, key: str, obj: dict): - self[key] = obj - - def write(self, key: str, obj: dict): - assert isinstance(key, str) - assert key.isidentifier() - if key in self.builtin_types: - raise ConflictError('conflict variable name') - assert self.is_valid(obj) - self[key] = obj - - def read(self, key: str) -> dict: - return self[key] - - def synchronise(self, key: str, obj: dict): - self[key] = obj - - def is_valid(self, obj: dict) -> bool: - # noinspection PyBroadException - try: - obj_type = obj['type'] - type_def = self[obj_type] - structure = type_def['structure'] - self.compare(obj, structure) - except Exception: - return False - else: - return True - - def compare(self, obj, structure) -> None: - """ - 用于判断某个对象是否符合给定的结构。 - 目标结构可以是以下内容: - 字典:递归检则每一个键是否符合要求 - 列表:检测列表对象中的每一项是否都是给定的结构 - 字符串: - 字符串内包含“|”分割符:表示可能是以下类型之一 - 字符串是int,float,str,list,dict中的一种:检测对象是否是相应的Python类型 - 其他字符串:从内置类型列表中查询该类型并进行检测 - :param obj: 待检测的对象 - :param structure: 目标结构 - :return: 无返回值,如果比较失败则报错 - """ - if isinstance(structure, dict): - for key in structure: - req_val = structure[key] - obj_val = obj[key] - self.compare(obj_val, req_val) - elif isinstance(structure, list): - req_type = structure[0] - for item in obj: - self.compare(item, req_type) - else: - assert isinstance(structure, str) - if '|' in structure: - valid = False - for sub_structure in structure.split('|'): - try: - self.compare(obj, sub_structure) - valid = True - except AssertionError: - pass - assert valid - elif structure in ('list', 'dict', 'float', 'int', 'str'): - assert type(obj).__name__ == structure - else: - assert isinstance(obj, dict) and obj.get('type', '') == structure - type_def = self[structure] - structure = type_def['structure'] - self.compare(obj, structure) - - def select_type(self, type_name: str): - # TODO (panhaoyu) 这个函数的意义何在?请补充注释 - dct = {} - for key, value in self.items(): - if value['type'] == type_name: - dct[key] = value - return dct diff --git a/pyminer/features/workspace_old/datamanager/exceptions.py b/pyminer/features/workspace_old/datamanager/exceptions.py deleted file mode 100644 index 8b6f7a4d..00000000 --- a/pyminer/features/workspace_old/datamanager/exceptions.py +++ /dev/null @@ -1,18 +0,0 @@ -class ConflictError(Exception): - pass - - -class NotFoundError(Exception): - pass - - -class ConvertError(Exception): - """用于在数据类型无法转换时进行报错""" - # TODO (panhaoyu) 建议改成ConvertError - # 由于改动涉及其他模块,需要在合并后的一个绝对安全的情况下进行修改 - pass - - -class WouldBlockError(Exception): - # TODO (panhaoyu) 建议改成DataBlockedError - pass diff --git a/pyminer/features/workspace_old/datamanager/historyset.py b/pyminer/features/workspace_old/datamanager/historyset.py deleted file mode 100644 index ba64a591..00000000 --- a/pyminer/features/workspace_old/datamanager/historyset.py +++ /dev/null @@ -1,59 +0,0 @@ -from pyminer2.workspace_old.datamanager.exceptions import NotFoundError - - -class HistoryError(Exception): - pass - - -class DataHistory(list): - def __init__(self, max_stack_num): - super().__init__() - self.max_stack_num = max_stack_num - self.index = 0 - - def push(self, var): - for i in range(self.index): - self.pop(0) - self.index = 0 - self.insert(0, var) - if len(self) > self.max_stack_num: - self.pop(-1) - - def stepback(self, var): - self.push(var) - if self.index >= self.max_stack_num: - raise HistoryError('stack bottom of history is reached') - self.index += 1 - return self[self.index] - - def stepforward(self): - if self.index <= 0: - raise HistoryError('stack top of history is reached') - self.index -= 1 - return self[self.index] - - -class HistorySet(dict): - def __init__(self, max_stack_num=15): - super().__init__() - self.max_stack_num = max_stack_num - - def push(self, key: str, var): - if key in self: - history = self[key] - else: - history = DataHistory(self.max_stack_num) - self[key] = history - history.push(var) - - def stepback(self, key: str, var): - if key not in self: - raise NotFoundError(f'{key} not found in history') - history = self[key] - return history.stepback(var) - - def stepforward(self, key: str): - if key not in self: - raise NotFoundError(f'{key} not found in history') - history = self[key] - return history.stepforward() diff --git a/pyminer/features/workspace_old/datamanager/metadataset.py b/pyminer/features/workspace_old/datamanager/metadataset.py deleted file mode 100644 index 62dc569e..00000000 --- a/pyminer/features/workspace_old/datamanager/metadataset.py +++ /dev/null @@ -1,81 +0,0 @@ -import contextlib -import threading -import time - -from pyminer2.workspace_old.datamanager.exceptions import ConflictError, NotFoundError -from .exceptions import WouldBlockError - - -class MetaData(dict): - # TODO (panhaoyu) 这里建议采用object加属性的方式进行操作,现在这种方式不支持代码提示 - def __init__(self, provider, **info): - super().__init__() - self['provider'] = provider - self['modified_by'] = [provider, ] - self.update(info) - self['synchronised'] = False - self['deleted'] = False - self['lock'] = threading.RLock() - - -class MetaDataSet(dict): - # TODO (panhaoyu) 既然所有的方法名都带有“data“,那么这个“data“可能就是冗余的。 - - # 这两个函数仅仅用于添加代码提示 - def __getitem__(self, item: str) -> MetaData: - return super(MetaDataSet, self).__getitem__(item) - - def __setitem__(self, key: str, value: MetaData): - super(MetaDataSet, self).__setitem__(key, value) - - def define_data(self, key: str, info: MetaData): - if key in self and not self[key]['deleted']: - raise ConflictError(f'meta data {key} already exist') - - # TODO (panhaoyu) 数据类型的定义是否应统一放在MataData里面 - info['creation_time'] = time.time() - info['modification_time'] = [info['creation_time'], ] - self[key] = info - - def modify_data(self, key: str, modified_by: str): - if key not in self: - raise NotFoundError(f'no such data {key}') - info = self[key] - info['modification_time'].append(time.time()) - info['modified_by'].append(modified_by) - info['synchronised'] = False - info['deleted'] = False - - def delete_data(self, key: str): - if key not in self or self[key]['deleted']: - raise NotFoundError(f'no such data {key}') - self[key]['deleted'] = True - - def restore_data(self, key: str): - if key not in self: - raise NotFoundError(f'no such data {key}') - self[key]['deleted'] = False - - def synchronise_data(self, key: str): - if key not in self or self[key]['deleted']: - raise NotFoundError(f'no such data {key}') - self[key]['synchronised'] = True - - def update(self, key: str, **info): - if key not in self or self[key]['deleted']: - raise NotFoundError(f'no such data {key}') - self[key].update(info) - - @contextlib.contextmanager - def lock_data(self, key: str): - if key not in self or self[key]['deleted']: - # TODO (panhaoyu) 对于不存在的变量,需要明确报错,而不是继续运行 - yield - else: - lock = self[key]['lock'] - if not lock.acquire(blocking=False): - raise WouldBlockError(key) - try: - yield lock - finally: - lock.release() diff --git a/pyminer/features/workspace_old/datamanager/recyclebin.py b/pyminer/features/workspace_old/datamanager/recyclebin.py deleted file mode 100644 index 24d798b1..00000000 --- a/pyminer/features/workspace_old/datamanager/recyclebin.py +++ /dev/null @@ -1,35 +0,0 @@ -from pyminer2.workspace_old.datamanager.exceptions import NotFoundError - - -class RecycleBin(list): - """ - 回收站,数据类型为(key, value)。 - 使用discard方法将对象移入回收站,再使用restore方法将对象移出回收站。 - """ - - def __init__(self, max_size=1000): - super().__init__() - self.max_size = max_size - - def get_varname(self, index: int): - if index >= len(self): - raise NotFoundError(f'{index} out of limit') - return self[index][0] - - def discard(self, varname: str, variable): - self.append((varname, variable)) - if len(self) > self.max_size: - self.pop(0) - - def restore(self, index: int, var_to_discard=None) -> tuple: - # for the case where variables with same name - # exist in workspace and recycle bin, if you - # restore the variable in recycle bin, you have - # to discard the variable in the workspace - if index >= len(self): - raise NotFoundError(f'{index} out of limit') - varname, var_to_restore = self[index] - self.pop(index) - if var_to_discard is not None: - self.discard(varname, var_to_discard) - return varname, var_to_restore diff --git a/pyminer/features/workspace_old/datamanager/variable.py b/pyminer/features/workspace_old/datamanager/variable.py deleted file mode 100644 index a159aa44..00000000 --- a/pyminer/features/workspace_old/datamanager/variable.py +++ /dev/null @@ -1,29 +0,0 @@ -import copy -import json - - -class VariableError(Exception): - pass - - -class Variable(dict): - def __init__(self, vartype: str, members: dict): - members['type'] = vartype - self.type = vartype - self.update(members) - super(Variable, self).__init__() - - def load(self, dct: dict): - if 'type' not in dct: - raise VariableError('invalid json object') - return Variable(dct['type'], dct) - - def loads(self, jsonstr: str): - dct = json.loads(jsonstr) - return self.load(dct) - - def dump(self): - return copy.copy(self) - - def dumps(self): - return json.dumps(self) diff --git a/pyminer/features/workspace_old/datamanager/varset.py b/pyminer/features/workspace_old/datamanager/varset.py deleted file mode 100644 index 67362ead..00000000 --- a/pyminer/features/workspace_old/datamanager/varset.py +++ /dev/null @@ -1,31 +0,0 @@ -from pyminer2.workspace_old.datamanager.variable import Variable -from pyminer2.workspace_old.datamanager.exceptions import ConflictError - - -class VarSet(dict): - """ - 这个类是对于字典进行的扩展。 - 主要功能是添加了get_var和set_var两个函数。 - """ - - def insert_builtin_types(self, builtin_types: dict): - # TODO (panhaoyu) 基于pycharm的索引没能找到调用,是否说明该功能已弃用? - self.update(builtin_types) - - def __getitem__(self, item: str): - # TODO (panhaoyu) 这个类需要类型提示 - return super(VarSet, self).__getitem__(item) - - def __setitem__(self, key: str, value): - assert isinstance(key, str) - assert key.isidentifier(), 'Key %s is not identifier!' % key - if key in self and isinstance(self[key], Variable) and self[key].type == 'Type': - raise ConflictError(f'{key} is a builtin type') - else: - super(VarSet, self).__setitem__(key, value) - - def get_var(self, key: str): - return self[key] - - def set_var(self, value: str, variable): - self[value] = variable diff --git a/pyminer/features/workspace_old/history.md b/pyminer/features/workspace_old/history.md deleted file mode 100644 index 1f7ca197..00000000 --- a/pyminer/features/workspace_old/history.md +++ /dev/null @@ -1,151 +0,0 @@ -# Workspace 设计记录 - -## 2020/08/29 - -本次更新完成以下两个内容: - -- 变量的读写,基于 JSON 的传输。提供了 `read` 和 `write` 函数,便于数据服务器调用。 -- 简单的数据结构合法性检查。 - -尚未实现的功能有数据的锁定等。 - -### 数据结构规范 - -变量指变量名及其对应的数据。变量名是一个字符串,该字符串首位字符必须为 `[_a-zA-Z]`,其余字符必须为 `[_a-zA-Z0-9]`。 - -数据必须是一个 `dict` 结构,该结构必须包含至少两个字段,其中一个字段为 `'type'`,表示变量的类型。变量的类型也是变量,其类型为 `'type'`。示例: - -~~~ -a = {'type':'matrix', 'value':[[1,2,3],[3,2,1]]} - -matrix = {'type':'type', 'structure':{'value':[['float']]}}) -~~~ - -则 `a` 是一个 `matrix`,`matrix` 是一种 `type`。`type` 是一个特殊的类型,定义如下: - -~~~ -type = {'type':'type', 'structure':{'structure':'dict'}} -~~~ - -### 数据结构的形式化定义 - -在 `type` 的定义中,`'structure'` 字段自指性地说明了这种类型的实例应该包含哪些字段,且这些字段的类型是什么(注意,此处的类型包括了变量的类型和 json 的五种 object,分别是 dict, list, int, float, str)。从 `type` 的定义可以得知,每一个 `type` 都必须包含 `'structure'` 字段,该字段的类型是 dict。`type` 也自指地完成了定义。 - -而 `matrix` 是一种 `type`,其定义必须符合它的类型要求,即 `type` 的要求。可以看到,`matrix` 的确包含 `'structure'` 字段,且其类型的确为 dict。进一步,又有 `a` 是一个 `matrix`,按照 `matrix` 的要求,`a` 必须包含 `'value'` 字段,且其类型必须是 list。 该 list 的子元素仍然必须为 list,内部的 list 的子元素则应是 `float`(一般认为,`int` 属于 `float` 而 `float` 不属于 `int`)。经检查,`a` 符合要求,因此 `a` 是合法的。 - -此例中,`type` 和 `matrix` 就是对数据结构的形式化定义。 - -### 数据结构合法性检查 - -数据结构合法性检查是通过 `compare` 函数的递归调用实现的。注意到每个变量都显示声明了自己的类型,取得该类型的定义后,该变量的剩余部分(即除 `'type'` 字段外)和其类型的 `'structure'` 所指向的 dict 是同构的。因此,如果类型规定的是不包含子元素的结构,如 `int`,直接判断二者是否相同;如果是包含子元素的结构,则递归地比较各个子元素。 - -如果子元素是不确定的,例如在 `type` 的定义中,`'structure'` 字段的 dict 定义是不确定的,则可以用 `'dict'` 来代替。同理,`'list'` 也可以用来指代不确定的 list。 - -如前所述,字段也可以是已经定义好的类型。此时,先检查字段的类型是否正确,如果正确,再检查字段结构是否合法。 - -需要注意的是,数据的结构合法性检查通过了,并不代表数据就是合法的。此形式化定义有其局限性,比如,`matrix` 要求 `'value'` 字段的值的各行元素数目相等,这个目前暂时无法判断。 - -## 2020/08/30 - -本次更新主要完成 `Variable` 类和 `Converter` 类的设计。目前系统架构为: - -~~~ - [ DataManager ] -InnerUser <-> [<-> VarSet <-Converter-> DataSet <->] <-> DataServer <-> OuterUser - [ History RecycleBin ] -~~~ - -### 名词定义和介绍 - -`VarSet` 实时保存 Python 变量,比如 `np.ndarray`,`int`,`timeseries`等,其中 `timeseris` 是继承于 `Variable` 的类。`DataSet` 则缓存 `dict`,如上次更新所述。 - -`Variable` 类是可以直接和上述数据结构(`dict`)转化的类。数据结构转化为 `Variable` 类的子类,类型为数据结构的 `type`。 - -`Converter` 实现在 Python 对象和上述数据结构之间相互转化。其中还特殊定义了一些数据结构转化成特殊的对象(非 `Variable` 子类),比如 `matrix` 应转化成 `numpy.ndarray`。相应地,还提供从 `numpy.ndarray` 到 `matrix` 的转化。 - -### 数据传递链路 - -InnerUser 写入数据,直接保存至 VarSet,VarSet 通知 DataSet 该数据发生改变。数据链路结束。 - -InnerUser 读取数据,直接从 VarSet 获取。 - -OuterUser 写入数据,保存至 DataSet,DataSet 调用 Converter 将数据写入 VarSet,更新该数据的状态为已知。 - -OuterUser 读取数据,从 DataSet 读取。DataSet 检测数据状态是否已知,如果已知,直接返回;如果未知,则调用 Converter 从 VarSet 获取值,修改数据状态为已知。 - -以上读取数据链路都是基于该值存在,若不存在,按正常逻辑返回错误或空值。 - -## 2020/08/30 #2 - -本次更新完成 `DataManager` 全部功能,实现了 `VarSet`,`RecycleBin`,`HistorySet` 和 `MetaDataSet` 四个组件。 - -### 为什么把 MetaDataSet 分离出来? - -因为删除或者撤销(回退)数据不应该引起元数据的变化。 - -### 为什么 RecycleBin 继承于 list 而不是 dict? - -因为一个数据可以被删多次(删除后手动创建新的,又删除),避免覆盖 - -### 如何实现撤销?为什么撤销需要传参? - -撤销传参是因为可以对特定参数进行撤销。暂不支持全局按顺序撤销。 - -撤销时,先把当前数据推入 HistorySet,否则当前数据将被覆盖而无法重做。然后将指针进一,即可得到撤销后的值。 - -### 为什么在 DataManager 内部,恢复值要传值? - -因为可能出现以下情况,准备在 RecycleBin 中恢复 `a`,但是当前 `VarSet` 中已经存在 `a`,这时候就要把当前的值放入 RecycleBin。 - -### 什么时候会进行数据转换(上述数据结构和 Python 对象)? - -Python 对象转换成上述数据结构,仅发生在数据服务器请求一个值,当前值在 DataSet 中不存在或者不是最新版。 - -上述数据结构转换成 Python 对象,仅发生在数据服务器向 DataSet 写入一个值,DataManager 自动同步到 VarSet。 - -## 2020/08/31 - -添加对数据上锁的功能。默认对数据上非阻塞可重入锁,如果需要阻塞锁,可以加上一层。 - -## 2020/08/31 # 2 - -添加数据增删改的 callback 函数,以便可视化界面刷新。具体用法见测试用例,用户向 DataManager 注册 callback 函数,在数据发生变化时回调。其中新增和修改被放在同一个回调函数中。 - -## 2020/08/31 # 3 (修改 2020/09/01) - -增加数据服务器功能,并将 DataManager 和 DataServer 合并到主程序中。~~由于 DataServer 采用 FastAPI 框架,需要用到 signal 模块,因此不得不在主线程运行,所以 GUI 程序只能在新的线程运行。目前已经实现这个功能。~~目前,数据服务器采用 json-rpc 框架,可以运行在新的线程上。但此框架对 POST 请求有更复杂的规定,且不支持 GET 请求。故更改了 API。 - -数据服务器目前支持两个 API: - -~~~ -post: - path: / - content-type: application/json - json: method: read - params: [dataname] - jsonrpc: 2.0 - id: 0 - func: datamanager.read_data(dataname) - -post: - path: / - content-type: application/json - json: method: read - params: [dataname, data, provider] - jsonrpc: 2.0 - id: 0 - func: datamanager.write_data(dataname, data, provider) -~~~ - -如果请求失败,失败的原因可以检测 response 的 `detail`。目前有如下几种: - -| 方法 | detail | 描述 | -|--|--|--| -| read | WOULD_BLOCK_ERROR | 数据被其他线程占用 | -| read | NOT_FOUND_ERROR | 未找到请求的数据 | -| read | INTERNAL_ERROR | 未知错误 | -| write | WOULD_BLOCK_ERROR | 数据被其他线程占用 | -| write | INVALID_VALUE_ERROR | 不合法的数据名或数据 | -| write | CONFLICT_ERROR | 没有权限修改数据(内建类型) | -| write | INTERNAL_ERROR | 未知错误 | - diff --git a/pyminer/features/workspace_old/index.rst b/pyminer/features/workspace_old/index.rst deleted file mode 100644 index 18c6697f..00000000 --- a/pyminer/features/workspace_old/index.rst +++ /dev/null @@ -1,17 +0,0 @@ -============================================================================== -工作空间 -============================================================================== - -.. toctree:: - :maxdepth: 2 - - datamanager/index.rst - history.md - - - -.. automodule:: pyminer2.workspace - :members: - :undoc-members: - - diff --git a/pyminer/languages/en/en.ts b/pyminer/languages/en/en.ts index 245db6a9..f8a83f00 100644 --- a/pyminer/languages/en/en.ts +++ b/pyminer/languages/en/en.ts @@ -3,12 +3,12 @@ - + Try Handle automatically - + Close @@ -34,32 +34,32 @@ ExceptionHandlerDialog - + An Exception Occured! - + Exception notes and solutions - + Exception Details - + No description or solutions for this error. - + Unknown Error - + Value Error diff --git a/pyminer/languages/zh_CN/zh_CN.ts b/pyminer/languages/zh_CN/zh_CN.ts index 22c96f41..4204c6fb 100644 --- a/pyminer/languages/zh_CN/zh_CN.ts +++ b/pyminer/languages/zh_CN/zh_CN.ts @@ -3,12 +3,12 @@ - + Try Handle automatically 尝试自动解决错误 - + Close 关闭 @@ -16,17 +16,17 @@ Dialog - + Dialog 对话框 - + Log 输出 - + Close 关闭 @@ -34,32 +34,32 @@ ExceptionHandlerDialog - + An Exception Occured! 一个异常发生了! - + Exception notes and solutions 异常的注释和解决方案 - + Exception Details 异常信息 - + No description or solutions for this error. 未找到针对这一错误的解决方案 - + Unknown Error 未知错误 - + Value Error 值错误 diff --git a/pyminer/languages/zh_TW/zh_TW.ts b/pyminer/languages/zh_TW/zh_TW.ts index 245db6a9..6da51367 100644 --- a/pyminer/languages/zh_TW/zh_TW.ts +++ b/pyminer/languages/zh_TW/zh_TW.ts @@ -3,12 +3,12 @@ - + Try Handle automatically - + Close @@ -16,17 +16,17 @@ Dialog - + Dialog - + Log - + Close @@ -34,32 +34,32 @@ ExceptionHandlerDialog - + An Exception Occured! - + Exception notes and solutions - + Exception Details - + No description or solutions for this error. - + Unknown Error - + Value Error diff --git a/pyminer/lib/auth/authmanager.py b/pyminer/lib/auth/authmanager.py index 938c9f03..e6ea8dc8 100644 --- a/pyminer/lib/auth/authmanager.py +++ b/pyminer/lib/auth/authmanager.py @@ -29,7 +29,7 @@ class AuthManager(): _am = AuthManager() -from pmlocalserver.server import server +from lib.localserver.server import server from .authlocalserver import auth server.register_blueprint(auth, url_prefix='/auth') diff --git a/pyminer/check_dependency.py b/pyminer/lib/check_dependency.py similarity index 98% rename from pyminer/check_dependency.py rename to pyminer/lib/check_dependency.py index 89ac73f9..84b59a46 100644 --- a/pyminer/check_dependency.py +++ b/pyminer/lib/check_dependency.py @@ -86,8 +86,8 @@ def check_installed_packages(): from PySide2.QtWidgets import QTextBrowser operator = '>=' try: - import pyminer_comm - assert is_version_satisfied(str(pyminer_comm.__version__), '0.4') + import lib.comm + assert is_version_satisfied(str(lib.comm.__version__), '0.4') except Exception: import traceback dlg = QTextBrowser() @@ -95,7 +95,7 @@ def check_installed_packages(): '执行命令:{interpreter_path} -m pip install {package_name}{operator}{required_version}\n' '错误详细信息:{exc}'.format( required_version='0.4', - package_name='pyminer_comm', + package_name='comm', operator=operator, interpreter_path=sys.executable, exc=traceback.format_exc())) diff --git a/pyminer/pyminer_comm/__init__.py b/pyminer/lib/comm/__init__.py similarity index 78% rename from pyminer/pyminer_comm/__init__.py rename to pyminer/lib/comm/__init__.py index a611c6a4..3ec10bcc 100644 --- a/pyminer/pyminer_comm/__init__.py +++ b/pyminer/lib/comm/__init__.py @@ -5,8 +5,8 @@ # @File: __init__.py.py import logging -from pyminer_comm.data_client import * -from pyminer_comm.pyminer_client import * +from .data_client import * +from .pyminer_client import * logging.basicConfig( format="%(asctime)-15s %(name)-40s %(levelname)-8s %(message)s", diff --git a/pyminer/pyminer_comm/base/__init__.py b/pyminer/lib/comm/base/__init__.py similarity index 100% rename from pyminer/pyminer_comm/base/__init__.py rename to pyminer/lib/comm/base/__init__.py diff --git a/pyminer/pyminer_comm/base/datadesc.py b/pyminer/lib/comm/base/datadesc.py similarity index 100% rename from pyminer/pyminer_comm/base/datadesc.py rename to pyminer/lib/comm/base/datadesc.py diff --git a/pyminer/pyminer_comm/base/encode_decode.py b/pyminer/lib/comm/base/encode_decode.py similarity index 100% rename from pyminer/pyminer_comm/base/encode_decode.py rename to pyminer/lib/comm/base/encode_decode.py diff --git a/pyminer/pyminer_comm/base/network.py b/pyminer/lib/comm/base/network.py similarity index 100% rename from pyminer/pyminer_comm/base/network.py rename to pyminer/lib/comm/base/network.py diff --git a/pyminer/pyminer_comm/base/sys_utils.py b/pyminer/lib/comm/base/sys_utils.py similarity index 98% rename from pyminer/pyminer_comm/base/sys_utils.py rename to pyminer/lib/comm/base/sys_utils.py index d52ae455..f55cae78 100644 --- a/pyminer/pyminer_comm/base/sys_utils.py +++ b/pyminer/lib/comm/base/sys_utils.py @@ -10,7 +10,7 @@ import socket import sys from typing import List -from pyminer_comm.base.network import get +from lib.comm.base.network import get logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) diff --git a/pyminer/pyminer_comm/data_client/data_client.py b/pyminer/lib/comm/data_client/__init__.py similarity index 98% rename from pyminer/pyminer_comm/data_client/data_client.py rename to pyminer/lib/comm/data_client/__init__.py index 6f3a71d9..3aae601f 100644 --- a/pyminer/pyminer_comm/data_client/data_client.py +++ b/pyminer/lib/comm/data_client/__init__.py @@ -1,8 +1,9 @@ + import logging import typing from typing import Dict, Any, List -from pyminer_comm.base import get, dict_to_b64, b64_to_dict, pickle_to_dict, dict_to_pickle, get_protocol, shm_allowed, \ +from lib.comm.base import get, dict_to_b64, b64_to_dict, pickle_to_dict, dict_to_pickle, get_protocol, shm_allowed, \ DataDesc logger = logging.getLogger(__name__) diff --git a/pyminer/pyminer_comm/data_client/unittest_data_client.py b/pyminer/lib/comm/data_client/unittest_data_client.py similarity index 87% rename from pyminer/pyminer_comm/data_client/unittest_data_client.py rename to pyminer/lib/comm/data_client/unittest_data_client.py index 9fad4f2d..a62f3fd8 100644 --- a/pyminer/pyminer_comm/data_client/unittest_data_client.py +++ b/pyminer/lib/comm/data_client/unittest_data_client.py @@ -1,5 +1,5 @@ import unittest -from pyminer_comm.data_client import get_vars, get_var_names, shm_get_vars, set_vars, \ +from lib.comm.data_client import get_vars, get_var_names, shm_get_vars, set_vars, \ shm_set_vars diff --git a/pyminer/pyminer_comm/pyminer_client/__init__.py b/pyminer/lib/comm/pyminer_client/__init__.py similarity index 100% rename from pyminer/pyminer_comm/pyminer_client/__init__.py rename to pyminer/lib/comm/pyminer_client/__init__.py diff --git a/pyminer/pyminer_comm/pyminer_client/pm_client.py b/pyminer/lib/comm/pyminer_client/pm_client.py similarity index 97% rename from pyminer/pyminer_comm/pyminer_client/pm_client.py rename to pyminer/lib/comm/pyminer_client/pm_client.py index a16f941b..3074ad52 100644 --- a/pyminer/pyminer_comm/pyminer_client/pm_client.py +++ b/pyminer/lib/comm/pyminer_client/pm_client.py @@ -6,7 +6,7 @@ import json from typing import Any, Dict, Optional, List -from pyminer_comm.base import get, dict_to_b64, b64_to_dict, DataDesc, get_protocol +from lib.comm.base import get, dict_to_b64, b64_to_dict, DataDesc, get_protocol class SetDataDescError(Exception): diff --git a/pyminer/pyminer_comm/readme.md b/pyminer/lib/comm/readme.md similarity index 100% rename from pyminer/pyminer_comm/readme.md rename to pyminer/lib/comm/readme.md diff --git a/pyminer/features/__init__.py b/pyminer/lib/comm/tests/__init__.py similarity index 100% rename from pyminer/features/__init__.py rename to pyminer/lib/comm/tests/__init__.py diff --git a/pyminer/pyminer_comm/tests/test_communication.py b/pyminer/lib/comm/tests/test_communication.py similarity index 85% rename from pyminer/pyminer_comm/tests/test_communication.py rename to pyminer/lib/comm/tests/test_communication.py index b4b670a1..e72aaee5 100644 --- a/pyminer/pyminer_comm/tests/test_communication.py +++ b/pyminer/lib/comm/tests/test_communication.py @@ -1,8 +1,7 @@ -import time import unittest -from pyminer_comm import set_vars, set_var, get_vars, get_var_names, get_var -from pyminer_comm import get_style_sheet, get_settings, modify_settings -from pyminer_comm.base import get_protocol, is_pyminer_service_started, DataDesc +from lib.comm import set_vars, set_var, get_vars, get_var_names, get_var +from lib.comm import get_style_sheet, get_settings, modify_settings +from lib.comm.base import get_protocol, is_pyminer_service_started, DataDesc class Test(unittest.TestCase): # 继承unittest.TestCase diff --git a/pyminer/lib/extensions/extensionlib/extension_lib.py b/pyminer/lib/extensions/extensionlib/extension_lib.py index 08ffd79e..9de9b92d 100644 --- a/pyminer/lib/extensions/extensionlib/extension_lib.py +++ b/pyminer/lib/extensions/extensionlib/extension_lib.py @@ -13,7 +13,7 @@ from lib.ui import pmwidgets from lib.workspace.data_adapter import UniversalAdapter from lib.workspace.data_manager import data_manager from lib.workspace_old.datamanager.datamanager import data_manager as data_manager_old -from pyminer_comm.base import DataDesc +from lib.comm.base import DataDesc from utils import get_main_window if TYPE_CHECKING: diff --git a/pyminer/pmlocalserver/readme.md b/pyminer/lib/localserver/readme.md similarity index 87% rename from pyminer/pmlocalserver/readme.md rename to pyminer/lib/localserver/readme.md index c529cf27..0af78781 100644 --- a/pyminer/pmlocalserver/readme.md +++ b/pyminer/lib/localserver/readme.md @@ -4,7 +4,7 @@ 再本教程之前,您应该知悉插件的开发流程 -在`pyminer/pmlocalserver`文件夹下有一个`server.py`文件,如代码所示,它会创建一个线程,在线程中运行本地flask服务器,**这个文件一般不需要改动,它会在所有插件加载完成后再启动** +在`pyminer/lib/localserver`文件夹下有一个`server.py`文件,如代码所示,它会创建一个线程,在线程中运行本地flask服务器,**这个文件一般不需要改动,它会在所有插件加载完成后再启动** ```python from flask import Flask @@ -29,7 +29,7 @@ if __name__ == '__main__': import logging logger = logging.getLogger('qt_vditor') from features.extensions.extensionlib import BaseExtension, BaseInterface -from pmlocalserver.server import server +from lib.localserver.server import server from .route import qt_vditor class Extension(BaseExtension): diff --git a/pyminer/pmlocalserver/server.py b/pyminer/lib/localserver/server.py similarity index 100% rename from pyminer/pmlocalserver/server.py rename to pyminer/lib/localserver/server.py diff --git a/pyminer/lib/main_window/base.py b/pyminer/lib/main_window/base.py index b591423f..691ab2c7 100644 --- a/pyminer/lib/main_window/base.py +++ b/pyminer/lib/main_window/base.py @@ -662,7 +662,7 @@ class LoginForm(QDialog, login_Ui_Form): username_len = len(username.encode("utf-8")) """ 将登录后django返回的token令牌保存在共享内存token中,共享内存token在启动pyminer主程序时附带启动了本地flask服务然后 - 创建共享内存token,详情见pmlocalserver/server.py + 创建共享内存token,详情见lib/localserver/server.py """ shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token buff = shared_memo.buf diff --git a/pyminer/lib/workspace_old/datamanager/datamanager.py b/pyminer/lib/workspace_old/datamanager/datamanager.py index 3d28549a..24d54e67 100644 --- a/pyminer/lib/workspace_old/datamanager/datamanager.py +++ b/pyminer/lib/workspace_old/datamanager/datamanager.py @@ -1,7 +1,7 @@ from contextlib import contextmanager from typing import Dict, Union, Any -from pyminer_comm.base import DataDesc +from lib.comm.base import DataDesc from lib.workspace.data_manager import data_manager as next_data_manager from lib.workspace.signals import workspace_data_created, workspace_data_changed, workspace_data_deleted from lib.workspace_old.datamanager.exceptions import NotFoundError diff --git a/pyminer/packages/advanced_drawings_toolbar/main.py b/pyminer/packages/advanced_drawings_toolbar/main.py index 02df410e..5d3bec18 100644 --- a/pyminer/packages/advanced_drawings_toolbar/main.py +++ b/pyminer/packages/advanced_drawings_toolbar/main.py @@ -24,7 +24,7 @@ from matplotlib import pyplot as plt from matplotlib import cm, colors, colorbar import json -from pyminer_comm import get_var +from lib.comm import get_var logger = logging.getLogger(__name__) diff --git a/pyminer/packages/applications_toolbar/apps/cftool/GUI_QT.py b/pyminer/packages/applications_toolbar/apps/cftool/GUI_QT.py index fee87b2e..069ebbd3 100644 --- a/pyminer/packages/applications_toolbar/apps/cftool/GUI_QT.py +++ b/pyminer/packages/applications_toolbar/apps/cftool/GUI_QT.py @@ -26,7 +26,7 @@ from matplotlib.figure import Figure import numpy as np from widgets import PMGPanel, center_window, set_closable, set_minimizable, set_always_on_top from utils import bind_combo_with_workspace -from pyminer_comm import get_var, get_var_names +from lib.comm import get_var, get_var_names if not TYPE_CHECKING: import algorithm diff --git a/pyminer/packages/applications_toolbar/apps/demo_app/main.py b/pyminer/packages/applications_toolbar/apps/demo_app/main.py index 5d8a0c54..d8ee05ed 100644 --- a/pyminer/packages/applications_toolbar/apps/demo_app/main.py +++ b/pyminer/packages/applications_toolbar/apps/demo_app/main.py @@ -3,7 +3,7 @@ 创建日期:2021-02-06 22:51:51 说明:自定义开发的应用 """ -from pyminer_comm import get_var, set_var +from lib.comm import get_var, set_var from PySide2.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QLabel diff --git a/pyminer/packages/applications_toolbar/apps/flowchart/plugin_nodes/nodes.py b/pyminer/packages/applications_toolbar/apps/flowchart/plugin_nodes/nodes.py index 6dec4049..beeebc80 100644 --- a/pyminer/packages/applications_toolbar/apps/flowchart/plugin_nodes/nodes.py +++ b/pyminer/packages/applications_toolbar/apps/flowchart/plugin_nodes/nodes.py @@ -48,7 +48,7 @@ class VariableSetter(PMGFlowContent): Returns: """ - from pyminer_comm import set_var + from lib.comm import set_var # print(args) # assert len(value) == 1, repr(args) if name.isidentifier(): @@ -104,13 +104,13 @@ class VariableGetter(PMGFlowContent): Returns: """ - from pyminer_comm import get_var, get_var_names + from lib.comm import get_var, get_var_names assert self.info['var_name'] in get_var_names(), 'Variable is not Chosen!' return [get_var(self.info['var_name'])] def on_settings_requested(self, parent): - from pyminer_comm import get_var_names + from lib.comm import get_var_names vars = get_var_names() if not self.info['var_name'] in vars: if len(vars) != 0: diff --git a/pyminer/packages/applications_toolbar/source/app_main.py b/pyminer/packages/applications_toolbar/source/app_main.py index 02fa5ff1..c84f0e24 100644 --- a/pyminer/packages/applications_toolbar/source/app_main.py +++ b/pyminer/packages/applications_toolbar/source/app_main.py @@ -3,7 +3,7 @@ 创建日期:2020-01-01 说明:示例描述信息 """ -from pyminer_comm import get_var, set_var +from lib.comm import get_var, set_var from PySide2.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QLabel diff --git a/pyminer/packages/dataio/export.py b/pyminer/packages/dataio/export.py index d3caa608..99aa4da9 100644 --- a/pyminer/packages/dataio/export.py +++ b/pyminer/packages/dataio/export.py @@ -1,7 +1,7 @@ from typing import Any, List, TYPE_CHECKING from PySide2.QtWidgets import QApplication, QWidget, QDialog, QHBoxLayout, QVBoxLayout, QMessageBox, QDialogButtonBox from widgets import PMTableView, PMGPanel, in_unit_test -from pyminer_comm import get_var +from lib.comm import get_var import json if TYPE_CHECKING: diff --git a/pyminer/packages/dataio/sample.py b/pyminer/packages/dataio/sample.py index 141888e3..a3a051dc 100644 --- a/pyminer/packages/dataio/sample.py +++ b/pyminer/packages/dataio/sample.py @@ -13,7 +13,7 @@ from PySide2.QtWidgets import * from dataImportModel import Ui_Form as dataImportFormEngine from widgets import kwargs_to_str -from pyminer_comm import set_var, run_command +from lib.comm import set_var, run_command # 导入matlab加载模块 diff --git a/pyminer/packages/drawings_toolbar/fastui/base.py b/pyminer/packages/drawings_toolbar/fastui/base.py index 436fddec..28ed9eb5 100644 --- a/pyminer/packages/drawings_toolbar/fastui/base.py +++ b/pyminer/packages/drawings_toolbar/fastui/base.py @@ -38,7 +38,7 @@ from PySide2.QtWidgets import QDialog, QVBoxLayout, QApplication, QPushButton, Q QTextBrowser from widgets import PMGPanel, PMGOneShotThreadRunner -from pyminer_comm import get_var_names, run_command, call_interface +from lib.comm import get_var_names, run_command, call_interface from utils import bind_combo_with_workspace diff --git a/pyminer/packages/drawings_toolbar/fastui/draw_boxplot.py b/pyminer/packages/drawings_toolbar/fastui/draw_boxplot.py index b847d632..391337f9 100644 --- a/pyminer/packages/drawings_toolbar/fastui/draw_boxplot.py +++ b/pyminer/packages/drawings_toolbar/fastui/draw_boxplot.py @@ -4,7 +4,7 @@ import os from PySide2.QtWidgets import QApplication -from pyminer_comm import get_var_names +from lib.comm import get_var_names from utils import bind_panel_combo_ctrl_with_workspace if not __name__ == '__main__': diff --git a/pyminer/packages/drawings_toolbar/fastui/draw_hist.py b/pyminer/packages/drawings_toolbar/fastui/draw_hist.py index 78713153..399adca1 100644 --- a/pyminer/packages/drawings_toolbar/fastui/draw_hist.py +++ b/pyminer/packages/drawings_toolbar/fastui/draw_hist.py @@ -5,7 +5,7 @@ from collections import OrderedDict from PySide2.QtWidgets import QApplication -from pyminer_comm import get_var_names +from lib.comm import get_var_names from utils import bind_panel_combo_ctrl_with_workspace if not __name__ == '__main__': diff --git a/pyminer/packages/drawings_toolbar/fastui/functions.py b/pyminer/packages/drawings_toolbar/fastui/functions.py index 5619822d..17a02184 100644 --- a/pyminer/packages/drawings_toolbar/fastui/functions.py +++ b/pyminer/packages/drawings_toolbar/fastui/functions.py @@ -2,7 +2,7 @@ import os from PySide2.QtWidgets import QApplication, QMessageBox, QWidget -from pyminer_comm import run_command, get_var_names +from lib.comm import run_command, get_var_names from utils import bind_panel_combo_ctrl_with_workspace if not __name__ == '__main__': diff --git a/pyminer/packages/drawings_toolbar/fastui/plot.py b/pyminer/packages/drawings_toolbar/fastui/plot.py index 0cf269a5..4abc8db0 100644 --- a/pyminer/packages/drawings_toolbar/fastui/plot.py +++ b/pyminer/packages/drawings_toolbar/fastui/plot.py @@ -5,7 +5,7 @@ from collections import OrderedDict from PySide2.QtWidgets import QApplication -from pyminer_comm import get_var_names +from lib.comm import get_var_names from utils import bind_panel_combo_ctrl_with_workspace if not __name__ == '__main__': diff --git a/pyminer/packages/drawings_toolbar/main.py b/pyminer/packages/drawings_toolbar/main.py index bac7158f..5a1b7ca0 100644 --- a/pyminer/packages/drawings_toolbar/main.py +++ b/pyminer/packages/drawings_toolbar/main.py @@ -25,7 +25,7 @@ from matplotlib import pyplot as plt from matplotlib import cm, colors, colorbar import json -from pyminer_comm import get_var +from lib.comm import get_var logger = logging.getLogger(__name__) diff --git a/pyminer/packages/ipython_console/initialize.py b/pyminer/packages/ipython_console/initialize.py index 433382e4..c563bf4d 100644 --- a/pyminer/packages/ipython_console/initialize.py +++ b/pyminer/packages/ipython_console/initialize.py @@ -7,8 +7,8 @@ import types import typing -from pyminer_comm import modify_settings, set_data_desc_dic -from pyminer_comm.base import dict_to_b64, b64_to_dict, dict_to_pickle, pickle_to_dict, DataDesc, is_big_variable, \ +from lib.comm import modify_settings, set_data_desc_dic +from lib.comm.base import dict_to_b64, b64_to_dict, dict_to_pickle, pickle_to_dict, DataDesc, is_big_variable, \ NoPreviewError try: diff --git a/pyminer/packages/jupyter_notebook_support/ipython_data_show.py b/pyminer/packages/jupyter_notebook_support/ipython_data_show.py index e419f774..e0fa747b 100644 --- a/pyminer/packages/jupyter_notebook_support/ipython_data_show.py +++ b/pyminer/packages/jupyter_notebook_support/ipython_data_show.py @@ -4,13 +4,12 @@ # @Email: 1295752786@qq.com # @File: ipython_data_show.py import logging -from typing import Dict -from PySide2.QtWidgets import QTableView, QTableWidget, QWidget, QVBoxLayout, QComboBox, QApplication, QTableWidgetItem, \ +from PySide2.QtWidgets import QTableWidget, QWidget, QVBoxLayout, QComboBox, QApplication, QTableWidgetItem, \ QHeaderView from widgets import PMDockObject -from pyminer_comm.base import DataDesc -from pyminer_comm import get_var_names, get_var +from lib.comm.base import DataDesc +from lib.comm import get_var_names, get_var logger = logging.getLogger(__name__) diff --git a/pyminer/packages/jupyter_notebook_support/main.py b/pyminer/packages/jupyter_notebook_support/main.py index 99cd13c3..f1bbf806 100644 --- a/pyminer/packages/jupyter_notebook_support/main.py +++ b/pyminer/packages/jupyter_notebook_support/main.py @@ -7,11 +7,10 @@ import os import subprocess import sys -from PySide2.QtCore import Signal, QSize, Qt, QLocale, QTranslator, QCoreApplication +from PySide2.QtCore import Signal, QSize, QLocale, QTranslator, QCoreApplication from PySide2.QtGui import QMouseEvent, QContextMenuEvent -from PySide2.QtWidgets import QVBoxLayout, QTextEdit, QPlainTextEdit, QTableWidget, QTableWidgetItem, QWidget, \ - QApplication, QLabel, QHeaderView, QMenu, QAction -from pyminer_comm.base import DataDesc +from PySide2.QtWidgets import QVBoxLayout, QTableWidget, QTableWidgetItem, QApplication, QHeaderView, QMenu, QAction +from lib.comm.base import DataDesc from widgets import create_icon, QDialog import socket diff --git a/pyminer/packages/jupyter_notebook_support/scripts/pyminer_ipython_node.py b/pyminer/packages/jupyter_notebook_support/scripts/pyminer_ipython_node.py index 1f20d9dc..55c5fa63 100644 --- a/pyminer/packages/jupyter_notebook_support/scripts/pyminer_ipython_node.py +++ b/pyminer/packages/jupyter_notebook_support/scripts/pyminer_ipython_node.py @@ -6,13 +6,9 @@ import logging import types -import ast -import time -import datetime - -import sys, os +import os import typing -from IPython.core.magic import register_line_magic, register_cell_magic, register_line_cell_magic +from IPython.core.magic import register_line_cell_magic __logger = logging.getLogger() __logger.info("Env variable-- IPYTHON_AS_PYMINER_NODE: %s" % os.environ.get('IPYTHON_AS_PYMINER_NODE')) @@ -21,8 +17,8 @@ if (os.environ.get('IPYTHON_AS_PYMINER_NODE') is not None) and (int(os.environ.g __ip = get_ipython() __ip.builtin_constants = {'tau', 'In', 'Out', 'PI', 'inf', 'nan', 'E'} try: - from pyminer_comm.base import DataDesc - from pyminer_comm import set_var + from lib.comm.base import DataDesc + from lib.comm import set_var # import ipyparams except: pass @@ -33,7 +29,6 @@ if (os.environ.get('IPYTHON_AS_PYMINER_NODE') is not None) and (int(os.environ.g 通过当前的文件名和 :return: """ - import importlib # importlib.reload(ipyparams) # current_notebook = ipyparams.notebook_name # if current_notebook == '': diff --git a/pyminer/packages/pm_calc/fastui/base.py b/pyminer/packages/pm_calc/fastui/base.py index 82e60ee6..5c2af77c 100644 --- a/pyminer/packages/pm_calc/fastui/base.py +++ b/pyminer/packages/pm_calc/fastui/base.py @@ -40,7 +40,7 @@ from PySide2.QtWidgets import QDialog, QVBoxLayout, QApplication, QPushButton, Q QTextBrowser from widgets import PMGPanel, PMGOneShotThreadRunner, center_window -from pyminer_comm import get_var_names, run_command, call_interface +from lib.comm import get_var_names, run_command, call_interface from utils import input_identifier, bind_combo_with_workspace diff --git a/pyminer/packages/pm_calc/fastui/create_random_variable.py b/pyminer/packages/pm_calc/fastui/create_random_variable.py index bbb9142c..7baaa37d 100644 --- a/pyminer/packages/pm_calc/fastui/create_random_variable.py +++ b/pyminer/packages/pm_calc/fastui/create_random_variable.py @@ -11,7 +11,7 @@ import os from PySide2.QtWidgets import QApplication from widgets import PMGPanel -from pyminer_comm import get_var_names +from lib.comm import get_var_names if not __name__ == '__main__': from .base import DFOperationDialog diff --git a/pyminer/packages/pm_calc/fastui/create_tensor.py b/pyminer/packages/pm_calc/fastui/create_tensor.py index 3fc1cfc3..0a94815f 100644 --- a/pyminer/packages/pm_calc/fastui/create_tensor.py +++ b/pyminer/packages/pm_calc/fastui/create_tensor.py @@ -3,7 +3,7 @@ import os from PySide2.QtWidgets import QApplication, QLabel from widgets import PMGPanel -from pyminer_comm import get_var_names +from lib.comm import get_var_names if not __name__ == '__main__': from .base import DFOperationDialog diff --git a/pyminer/packages/pm_calc/fastui/create_vector.py b/pyminer/packages/pm_calc/fastui/create_vector.py index 7717b388..5fbe92c6 100644 --- a/pyminer/packages/pm_calc/fastui/create_vector.py +++ b/pyminer/packages/pm_calc/fastui/create_vector.py @@ -1,7 +1,7 @@ from PySide2.QtWidgets import QApplication from widgets import PMGPanel -from pyminer_comm import get_var_names +from lib.comm import get_var_names if not __name__ == '__main__': from .base import DFOperationDialog diff --git a/pyminer/packages/pm_calc/fastui/equation_solve.py b/pyminer/packages/pm_calc/fastui/equation_solve.py index e0020d02..1dd9ddab 100644 --- a/pyminer/packages/pm_calc/fastui/equation_solve.py +++ b/pyminer/packages/pm_calc/fastui/equation_solve.py @@ -1,6 +1,6 @@ from PySide2.QtWidgets import QApplication -from pyminer_comm import get_var_names +from lib.comm import get_var_names from utils import bind_panel_combo_ctrl_with_workspace if not __name__ == '__main__': diff --git a/pyminer/packages/pm_calc/fastui/matrix_calc.py b/pyminer/packages/pm_calc/fastui/matrix_calc.py index 2ea4545c..13e3ad42 100644 --- a/pyminer/packages/pm_calc/fastui/matrix_calc.py +++ b/pyminer/packages/pm_calc/fastui/matrix_calc.py @@ -1,6 +1,6 @@ from PySide2.QtWidgets import QApplication, QMessageBox -from pyminer_comm import get_var_names +from lib.comm import get_var_names from utils import bind_panel_combo_ctrl_with_workspace if not __name__ == '__main__': diff --git a/pyminer/packages/pm_calc/fastui/matrix_inv.py b/pyminer/packages/pm_calc/fastui/matrix_inv.py index 767b02b8..4c56a409 100644 --- a/pyminer/packages/pm_calc/fastui/matrix_inv.py +++ b/pyminer/packages/pm_calc/fastui/matrix_inv.py @@ -1,6 +1,6 @@ from PySide2.QtWidgets import QApplication, QMessageBox -from pyminer_comm import get_var_names +from lib.comm import get_var_names from utils import bind_panel_combo_ctrl_with_workspace if not __name__ == '__main__': diff --git a/pyminer/packages/pm_calc/fastui/matrix_numbers.py b/pyminer/packages/pm_calc/fastui/matrix_numbers.py index 0b7e494e..b0787cab 100644 --- a/pyminer/packages/pm_calc/fastui/matrix_numbers.py +++ b/pyminer/packages/pm_calc/fastui/matrix_numbers.py @@ -1,6 +1,6 @@ from PySide2.QtWidgets import QApplication, QMessageBox -from pyminer_comm import get_var_names +from lib.comm import get_var_names from utils import bind_panel_combo_ctrl_with_workspace if not __name__ == '__main__': from .base import DFOperationDialog diff --git a/pyminer/packages/pm_calc/fastui/numerical_integration.py b/pyminer/packages/pm_calc/fastui/numerical_integration.py index 9ce79c3f..59b2e530 100644 --- a/pyminer/packages/pm_calc/fastui/numerical_integration.py +++ b/pyminer/packages/pm_calc/fastui/numerical_integration.py @@ -2,7 +2,7 @@ import os from PySide2.QtWidgets import QApplication, QMessageBox -from pyminer_comm import get_var_names +from lib.comm import get_var_names from utils import bind_panel_combo_ctrl_with_workspace if not __name__ == '__main__': diff --git a/pyminer/packages/pm_calc/fastui/reshape_tensor.py b/pyminer/packages/pm_calc/fastui/reshape_tensor.py index 84c60c77..3ede8e8a 100644 --- a/pyminer/packages/pm_calc/fastui/reshape_tensor.py +++ b/pyminer/packages/pm_calc/fastui/reshape_tensor.py @@ -3,7 +3,7 @@ import os from PySide2.QtWidgets import QApplication, QLabel from widgets import PMGPanel -from pyminer_comm import get_var_names +from lib.comm import get_var_names from utils import bind_panel_combo_ctrl_with_workspace if not __name__ == '__main__': diff --git a/pyminer/packages/pm_preprocess/base.py b/pyminer/packages/pm_preprocess/base.py index eaab43f0..a53747ea 100644 --- a/pyminer/packages/pm_preprocess/base.py +++ b/pyminer/packages/pm_preprocess/base.py @@ -34,7 +34,7 @@ from PySide2.QtWidgets import QWidget, QDesktopWidget, QDialog, QInputDialog, QL QComboBox from PySide2.QtCore import Qt, Signal from utils import input_identifier, bind_combo_with_workspace -from pyminer_comm import set_var, get_var +from lib.comm import set_var, get_var import pandas as pd diff --git a/pyminer/packages/pm_preprocess/datareplace.py b/pyminer/packages/pm_preprocess/datareplace.py index c7401523..d4cd5d88 100644 --- a/pyminer/packages/pm_preprocess/datareplace.py +++ b/pyminer/packages/pm_preprocess/datareplace.py @@ -14,7 +14,7 @@ from PySide2.QtWidgets import QWidget, QDesktopWidget, QApplication, QComboBox, from PySide2.QtCore import Qt, Signal # 导入数据相关操作模块 from packages.pm_preprocess.ui.data_filter import Ui_Form as DataFilter_Ui_Form # 数据筛选 -from pyminer_comm import get_var, set_var +from lib.comm import get_var, set_var from packages.pm_preprocess.ui.data_repace import Ui_Form as DataReplace_Ui_Form from packages.pm_preprocess.base import BaseDataPreprocessForm from utils import bind_combo_with_workspace diff --git a/pyminer/packages/pm_preprocess/fastui/base.py b/pyminer/packages/pm_preprocess/fastui/base.py index 0b1b79c7..1286c8eb 100644 --- a/pyminer/packages/pm_preprocess/fastui/base.py +++ b/pyminer/packages/pm_preprocess/fastui/base.py @@ -32,14 +32,13 @@ pd.concat函数有返回值。在点击“preview” """ from abc import abstractmethod from typing import List - from PySide2.QtCore import Qt, QCoreApplication, Signal -from widgets import PMGPanel, PMGOneShotThreadRunner -from pyminer_comm import get_var_names, run_command, call_interface -from utils import input_identifier, bind_combo_with_workspace from PySide2.QtWidgets import QDialog, QVBoxLayout, QApplication, QPushButton, QComboBox, QHBoxLayout, QLabel, \ QTextBrowser +from widgets import PMGPanel, PMGOneShotThreadRunner +from lib.comm import get_var_names, run_command, call_interface +from utils import input_identifier, bind_combo_with_workspace class BaseOperationDialog(QDialog): """ diff --git a/pyminer/packages/pm_preprocess/fastui/datamerge.py b/pyminer/packages/pm_preprocess/fastui/datamerge.py index e812b5a3..f885187a 100644 --- a/pyminer/packages/pm_preprocess/fastui/datamerge.py +++ b/pyminer/packages/pm_preprocess/fastui/datamerge.py @@ -12,12 +12,12 @@ # @File: datamerge.py from typing import List +from PySide2.QtWidgets import QDialogButtonBox, QVBoxLayout, QSpinBox, QApplication, QMessageBox -from widgets import PMGPanelDialog, PMGPanel, PMGOneShotThreadRunner -from pyminer_comm.base import is_pyminer_service_started -from pyminer_comm import get_var_names, get_var, set_var, run_command, call_interface -from utils import VariableSelect, input_identifier -from PySide2.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QSpinBox, QApplication, QMessageBox, QPushButton +from widgets import PMGPanel, PMGOneShotThreadRunner +from lib.comm.base import is_pyminer_service_started +from lib.comm import get_var_names, run_command +from utils import input_identifier if not __name__ == '__main__': from .base import BaseOperationDialog diff --git a/pyminer/packages/pm_preprocess/fastui/fillna.py b/pyminer/packages/pm_preprocess/fastui/fillna.py index a04bb190..47974018 100644 --- a/pyminer/packages/pm_preprocess/fastui/fillna.py +++ b/pyminer/packages/pm_preprocess/fastui/fillna.py @@ -18,13 +18,7 @@ # 链接:https://www.jianshu.com/p/17cb2733a6d7 -from typing import List - -from widgets import PMGPanelDialog, PMGPanel -from pyminer_comm.base import is_pyminer_service_started -from pyminer_comm import get_var_names, get_var, set_var, run_command -from utils import VariableSelect, input_identifier -from PySide2.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QSpinBox, QApplication, QMessageBox, QPushButton +from PySide2.QtWidgets import QApplication if not __name__ == '__main__': from .base import DFOperationDialog diff --git a/pyminer/packages/pm_preprocess/fastui/templates/dropna.py b/pyminer/packages/pm_preprocess/fastui/templates/dropna.py index 228dd36e..f20be671 100644 --- a/pyminer/packages/pm_preprocess/fastui/templates/dropna.py +++ b/pyminer/packages/pm_preprocess/fastui/templates/dropna.py @@ -1,12 +1,7 @@ - -from typing import List - -from widgets import PMGPanelDialog, PMGPanel -from pyminer_comm.base import is_pyminer_service_started -from pyminer_comm import get_var_names, get_var, set_var, run_command -from utils import VariableSelect, input_identifier -from PySide2.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QSpinBox, QApplication, QMessageBox, QPushButton,QComboBox - +from PySide2.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QApplication, QMessageBox, QComboBox +from widgets import PMGPanel +from lib.comm import get_var_names, run_command +from utils import input_identifier class CLASS_NAME(QDialog): def __init__(self, ): diff --git a/pyminer/packages/pm_preprocess/fastui/templates/template.py b/pyminer/packages/pm_preprocess/fastui/templates/template.py index e8319935..aae4e169 100644 --- a/pyminer/packages/pm_preprocess/fastui/templates/template.py +++ b/pyminer/packages/pm_preprocess/fastui/templates/template.py @@ -13,8 +13,8 @@ code = """ from typing import List from widgets import PMGPanelDialog, PMGPanel -from pyminer_comm.base import is_pyminer_service_started -from pyminer_comm import get_var_names, get_var, set_var, run_command +from comm.base import is_pyminer_service_started +from comm import get_var_names, get_var, set_var, run_command from pmtoolbox import VariableSelect, input_identifier from PySide2.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QSpinBox, QApplication, QMessageBox, QPushButton,QComboBox diff --git a/pyminer/packages/qt_vditor/main.py b/pyminer/packages/qt_vditor/main.py index 533296c2..4ef8782a 100644 --- a/pyminer/packages/qt_vditor/main.py +++ b/pyminer/packages/qt_vditor/main.py @@ -5,7 +5,7 @@ import logging logger = logging.getLogger('qt_vditor') from lib.extensions.extensionlib import BaseExtension, BaseInterface -from pmlocalserver.server import server +from lib.localserver.server import server from .route import qt_vditor class Extension(BaseExtension): diff --git a/pyminer/packages/socket_server/server_by_socket.py b/pyminer/packages/socket_server/server_by_socket.py index d4a99491..f5684766 100644 --- a/pyminer/packages/socket_server/server_by_socket.py +++ b/pyminer/packages/socket_server/server_by_socket.py @@ -8,7 +8,7 @@ from typing import Dict, Any from PySide2.QtCore import Signal, QObject, QThread from PySide2.QtWidgets import QApplication -from pyminer_comm.base import b64_to_dict, dict_to_b64, DataDesc, get_protocol +from lib.comm.base import b64_to_dict, dict_to_b64, DataDesc, get_protocol logger = logging.getLogger(__name__) DATA_CHANGED = 1 diff --git a/pyminer/packages/workspace_inspector/data_viewer.py b/pyminer/packages/workspace_inspector/data_viewer.py index b12cd9af..0b1dd56f 100644 --- a/pyminer/packages/workspace_inspector/data_viewer.py +++ b/pyminer/packages/workspace_inspector/data_viewer.py @@ -1,10 +1,9 @@ import pprint -import sys import threading from typing import Dict, TYPE_CHECKING +from PySide2.QtWidgets import QTabWidget, QTextBrowser, QWidget -from pyminer_comm import get_var, set_var -from PySide2.QtWidgets import QTabWidget, QTextBrowser, QWidget, QMessageBox +from lib.comm import get_var, set_var from widgets import PMTableView, PMGTableWidget, PMDockObject, PMGTableViewer, PMGJsonTree if TYPE_CHECKING: @@ -221,7 +220,7 @@ class PMVariableViewerWidget(QTabWidget, PMDockObject): :param dataname: :return: """ - from pyminer_comm.base import DataDesc + from lib.comm.base import DataDesc desc: DataDesc = self.lib.Data.get_data_desc(dataname) if desc.big: data = get_var(dataname, preview=True) diff --git a/pyminer/packages/workspace_inspector/inspectortable.py b/pyminer/packages/workspace_inspector/inspectortable.py index 81ecd098..acf3e8ed 100644 --- a/pyminer/packages/workspace_inspector/inspectortable.py +++ b/pyminer/packages/workspace_inspector/inspectortable.py @@ -1,5 +1,4 @@ import os -import threading import time from typing import Dict, TYPE_CHECKING, Callable, Any, List @@ -11,12 +10,11 @@ from PySide2.QtCore import Signal, Qt, QLocale, QModelIndex from widgets import PMDockObject, in_unit_test, create_translator from utils import load_variable_pmd, load_variable_pkl, save_variable_pkl, save_variable_pmd, save_variable_table, \ save_variable_matrix -from lib.extensions.extensionlib import BaseExtension, BaseInterface -from pyminer_comm.base import DataDesc -from pyminer_comm import get_var, get_var_names, set_var, del_var, set_vars, get_vars +from lib.comm.base import DataDesc +from lib.comm import get_var, set_var, del_var, set_vars if TYPE_CHECKING: - from .data_viewer import PMVariableViewerWidget + pass class PMVariableTreeWidget(QTableWidget): @@ -439,7 +437,6 @@ class PMVariableTreeWidget(QTableWidget): return i def show_data(self, data_name): - import numpy as np import pandas as pd data_desc = self.get_current_var_desc() if data_desc.big: diff --git a/pyminer/pmgwidgets/display/__init__.py b/pyminer/pmgwidgets/display/__init__.py deleted file mode 100644 index 6b679ffb..00000000 --- a/pyminer/pmgwidgets/display/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -hint = 'However if your program needn\'t this package,this warning is neglectable.' -try: - from .matplotlib.qt5agg import PMMatplotlibQt5Widget -except ModuleNotFoundError: - import warnings - - warnings.warn('matplotlib is not installed. ' + hint) - pass - -from .dynamicgraph import * diff --git a/pyminer/pmgwidgets/display/browser/__init__.py b/pyminer/pmgwidgets/display/browser/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/display/browser/browser.py b/pyminer/pmgwidgets/display/browser/browser.py deleted file mode 100644 index 11ba8aa4..00000000 --- a/pyminer/pmgwidgets/display/browser/browser.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -代码来源: -https://www.cnblogs.com/taostaryu/p/9772492.html - -""" -import sys -from PySide2.QtWidgets import QMainWindow, QApplication, QWidget, QVBoxLayout, QToolBar, QLineEdit -from PySide2.QtCore import QUrl, Signal -from PySide2.QtWebEngineWidgets import QWebEngineView - - -class PMGWebBrowser(QWidget): - def __init__(self, parent=None, toolbar='standard'): - """ - - :param parent: - :param toolbar:多种选项:‘no’,‘standard’,'no_url_input' - """ - super().__init__(parent) - self.webview = PMGWebEngineView() - self.webview.load(QUrl("https://cn.bing.com")) - self.setLayout(QVBoxLayout()) - self.toolbar = QToolBar() - self.url_input = QLineEdit() - # self.url_input.setText('https://cn.bing.com') - # self.load_url() - self.toolbar.addWidget(self.url_input) - self.toolbar.addAction('go').triggered.connect(lambda b: self.load_url()) - self.toolbar.addAction('back').triggered.connect(self.webview.back) - self.toolbar.addAction('forward').triggered.connect(self.webview.forward) - self.layout().addWidget(self.toolbar) - if toolbar == 'no': - self.toolbar.hide() - elif toolbar == 'no_url_input': - self.url_input.hide() - - self.layout().addWidget(self.webview) - self.setWindowTitle('My Browser') - self.showMaximized() - - # command:> - # /home/hzy/Documents/Developing/Python/pyminer_dist_debian_deepin/python/bin/python3.8 -m jupyter notebook --port 5000 --no-browser --ip='*' --NotebookApp.token='' - # --NotebookApp.password='' c:\users\12957\ - - # self.webview.load(QUrl("http://127.0.0.1:5000/notebooks/desktop/Untitled.ipynb")) # 直接请求页面。 - # self.webview.load(QUrl("E:\Python\pyminer_bin\PyMiner\bin\pmgwidgets\display\browser\show_formula.html")) # 直接请求页面。 - # self.setCentralWidget(self.webview) - - def load_url(self, url: str = ''): - if url == '': - url = self.url_input.text().strip() - # print('',url) - else: - self.url_input.setText(url) - self.webview.load(QUrl(url)) - - -class PMGWebEngineView(QWebEngineView): - windowList = [] - signal_new_window_created = Signal(PMGWebBrowser) - - # 重写createwindow() - def createWindow(self, QWebEnginePage_WebWindowType): - # new_webview = WebEngineView() - new_window = PMGWebBrowser() - # new_window.setCentralWidget(new_webview) - # new_window.show() - self.windowList.append(new_window) # 注:没有这句会崩溃!!! - self.signal_new_window_created.emit(new_window) - return new_window.webview - - -if __name__ == "__main__": - app = QApplication(sys.argv) - - w = PMGWebBrowser() - w.show() - w2 = PMGWebBrowser() - w2.show() - w3 = PMGWebBrowser() - w3.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/display/browser/get_ipy.py b/pyminer/pmgwidgets/display/browser/get_ipy.py deleted file mode 100644 index 06c7e604..00000000 --- a/pyminer/pmgwidgets/display/browser/get_ipy.py +++ /dev/null @@ -1,48 +0,0 @@ -import json -from sys import getsizeof - -from IPython import get_ipython -from IPython.core.magics.namespace import NamespaceMagics - -_nms = NamespaceMagics() -_Jupyter = get_ipython() -_nms.shell = _Jupyter.kernel.shell - -try: - import numpy as np # noqa: F401 -except ImportError: - pass - - -def _getsizeof(x): - # return the size of variable x. Amended version of sys.getsizeof - # which also supports ndarray, Series and DataFrame - if type(x).__name__ in ['ndarray', 'Series']: - return x.nbytes - elif type(x).__name__ == 'DataFrame': - return x.memory_usage().sum() - else: - return getsizeof(x) - - -def _getshapeof(x): - # returns the shape of x if it has one - # returns None otherwise - might want to return an empty string for an empty collum - try: - return x.shape - except AttributeError: # x does not have a shape - return None - - -def var_dic_list(): - types_to_exclude = ['module', 'function', 'builtin_function_or_method', - 'instance', '_Feature', 'type', 'ufunc'] - values = _nms.who_ls() - vardic = [{'varName': v, 'varType': type(eval(v)).__name__, 'varSize': str(_getsizeof(eval(v))), 'varShape': str(_getshapeof(eval(v))) if _getshapeof(eval(v)) else '', 'varContent': str(eval(v))[:200]} # noqa - - for v in values if (v not in ['_html', '_nms', 'NamespaceMagics', '_Jupyter']) & (type(eval(v)).__name__ not in types_to_exclude)] # noqa - return json.dumps(vardic) - -if __name__=='__main__': - # command to refresh the list of variables - print(var_dic_list()) diff --git a/pyminer/pmgwidgets/display/browser/handler.py b/pyminer/pmgwidgets/display/browser/handler.py deleted file mode 100644 index 14cf330d..00000000 --- a/pyminer/pmgwidgets/display/browser/handler.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (c) Jupyter Development Team, Spyder Project Contributors. -# Distributed under the terms of the Modified BSD License. - -"""Entry point for server rendering notebooks for Spyder.""" - -import os -from jinja2 import FileSystemLoader -from notebook.base.handlers import IPythonHandler, FileFindHandler -from notebook.notebookapp import flags, NotebookApp -from notebook.utils import url_path_join as ujoin -from traitlets import Bool -from notebook.services.kernels.kernelmanager import MappingKernelManager -from jupyter_client.ioloop.manager import IOLoopKernelManager - -HERE = os.path.dirname(__file__) - -flags['dark'] = ( - {'SpyderNotebookServer': {'dark_theme': True}}, - 'Use dark theme when rendering notebooks' -) - - -class NotebookHandler(IPythonHandler): - """ - Serve a notebook file from the filesystem in the notebook interface - """ - - def get(self): - """Get the main page for the application's interface.""" - # Options set here can be read with PageConfig.getOption - # config_data = { - # # Use camelCase here, since that's what the lab components expect - # 'baseUrl': self.base_url, - # 'token': self.settings['token'], - # 'darkTheme': self.settings['dark_theme'], - # 'notebookPath': filename, - # 'frontendUrl': ujoin(self.base_url, 'static/'), - # # FIXME: Don't use a CDN here - # 'mathjaxUrl': 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/' - # '2.7.5/MathJax.js', - # 'mathjaxConfig': "TeX-AMS_CHTML-full,Safe" - # } - # return self.write( - # self.render_template( - # 'index.html', - # static=self.static_url, - # base_url=self.base_url, - # config_data=config_data - # ) - # ) - # self.session.send(stream, msg) - mgr: MappingKernelManager = self.kernel_manager - print(mgr.list_kernels()) - - for k in mgr._kernels: - ioloopmanager: IOLoopKernelManager = mgr._kernels[k] - print('AAAAAAAAAAAAA', ioloopmanager.kernel) - return self.write("aaaaaaaaaa") - # def get_templaer.load(self.settings['jinja2_ete(self, name): - # # loader = FileSystemLoader(HERE) - # # return loadnv'], name) - - -class SpyderNotebookServer(NotebookApp): - """Server rendering notebooks in HTML and serving them over HTTP.""" - - flags = flags - - dark_theme = Bool( - False, config=True, - help='Whether to use dark theme when rendering notebooks') - - def init_webapp(self): - """Initialize tornado webapp and httpserver.""" - self.tornado_settings['dark_theme'] = self.dark_theme - - super().init_webapp() - print(self.base_url) - url = ujoin(self.base_url, r'/notebook/(.*)') - print(url) - - default_handlers = [ - (r"/pyminers", NotebookHandler), - # (ujoin(self.base_url, r"/pyminer/(.*)"), FileFindHandler, - # {'path': os.path.join(HERE, 'build')}) - ] - - self.web_app.add_handlers('.*', default_handlers) - # self.web_app.find_handler() - -def run(): - import time - from IPython import get_ipython - - while (1): - time.sleep(2) - _Jupyter = get_ipython() - print(_Jupyter) - - -if __name__ == '__main__': - # import threading - - # th = threading.Thread(target=run) - # th.setDaemon(True) - # th.start() - - SpyderNotebookServer.launch_instance( - argv=['--port', '5000', '--no-browser', '--ip=\'*\'', '--NotebookApp.token=\'\'']) diff --git a/pyminer/pmgwidgets/display/dynamicgraph/__init__.py b/pyminer/pmgwidgets/display/dynamicgraph/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/display/dynamicgraph/base/__init__.py b/pyminer/pmgwidgets/display/dynamicgraph/base/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/display/dynamicgraph/base/basetimeseries.py b/pyminer/pmgwidgets/display/dynamicgraph/base/basetimeseries.py deleted file mode 100644 index d50643aa..00000000 --- a/pyminer/pmgwidgets/display/dynamicgraph/base/basetimeseries.py +++ /dev/null @@ -1,210 +0,0 @@ -import logging -import sys -import time - -from PySide2.QtCore import QTimer -from PySide2.QtWidgets import QWidget, QApplication, QVBoxLayout, QPushButton -import numpy as np -from typing import List, Dict, Tuple -from pmgwidgets.display.matplotlib.qt5agg import PMMatplotlibQt5Widget - -logger = logging.getLogger('display.basetimeseries') - - -class PMBaseTimeSeriesWidget(QWidget): - def __init__(self, parent: 'QWidget' = None, recent_samples: int = 100, show_mode: str = '', - max_samples: int = 10000, sample_type: np.dtype = np.float): - """ - 运用循环队进行数据刷新 - :param parent: - :param recent_samples: - :param show_mode: "recently":最近的 recent_points个点,"all":显示全部 - :param max_samples:最多采样数目。如果采样数量太多,就舍弃前面的数据。 - """ - super().__init__(parent=parent) - self.recent_sample_num = recent_samples - self.max_samples = max_samples - self.buffer_length = int(max_samples * 1.5) - self.bottom_pointers: Dict[str, int] = {} - self.top_pointers: Dict[str, int] = {} - self.time: Dict[str, np.ndarray] = {} # np.zeros(self.buffer_length, dtype=np.float) - self.data: Dict[str, np.ndarray] = {} - self.last_plot_time: float = 0 - # self.init_plot() - - def add_data(self, data_name, data_type): - self.data[data_name] = np.zeros(self.buffer_length, dtype=data_type) - self.time[data_name] = np.zeros(self.buffer_length, dtype=np.float) - self.top_pointers[data_name] = 0 - self.bottom_pointers[data_name] = 0 - - def add_sample(self, data_name: str, value: float, sample_time: float = -1): - """ - 增加一个采样点 - :param data_name: - :param value: - :return: - """ - if sample_time < 0: - sample_time = time.time() - top_pointer = self.top_pointers[data_name] - - if top_pointer == self.buffer_length: - self.trim_data(data_name) - - top_pointer = self.top_pointers[data_name] - self.data[data_name][top_pointer] = value - self.time[data_name][top_pointer] = sample_time - self.top_pointers[data_name] = self.top_pointers[data_name] + 1 - self.refresh() - - def trim_data(self, data_name: str): - self.data[data_name][:self.max_samples] = self.data[data_name][ - self.buffer_length - self.max_samples:self.buffer_length] - self.data[data_name][self.max_samples:] = np.zeros(self.buffer_length - self.max_samples) - self.time[data_name][:self.max_samples] = self.time[data_name][ - self.buffer_length - self.max_samples:self.buffer_length] - self.time[data_name][self.max_samples:] = np.zeros(self.buffer_length - self.max_samples) - self.top_pointers[data_name] = self.max_samples - # self.bottom_pointers[data_name] = self.max_samples - - def on_length_exceed(self): - pass - - def get_time_series(self, data_name: str) -> Tuple[np.ndarray, np.ndarray]: - data = self.data.get(data_name) - sample_time = self.time.get(data_name) - assert data is not None, 'no data named %s' % data_name - if self.top_pointers[data_name] - self.max_samples < 0: - return sample_time[:self.top_pointers[data_name]], data[:self.top_pointers[data_name]] - return sample_time[self.top_pointers[data_name] - self.max_samples:self.top_pointers[data_name]], \ - data[self.top_pointers[data_name] - self.max_samples:self.top_pointers[data_name]] - - def get_recent_data(self, data_name: str) -> Tuple[np.ndarray, np.ndarray]: - data = self.data.get(data_name) - sample_time = self.time.get(data_name) - assert data is not None, 'no data named %s' % data_name - if self.top_pointers[data_name] - self.recent_sample_num < 0: - return sample_time[:self.top_pointers[data_name]], \ - data[:self.top_pointers[data_name]] - return sample_time[self.top_pointers[data_name] - self.recent_sample_num:self.top_pointers[data_name]], \ - data[self.top_pointers[data_name] - self.recent_sample_num:self.top_pointers[data_name]] - - def create_new_line(self): - pass - - def refresh(self): - """ - 'It is suggested that refresh rate should lower than 10 fps for Matplotlib widget.' - 刷新帧率通常不能超过每秒钟10帧——而且点数不太多的情况下, - :return: - """ - self.clear() - for k in self.time.keys(): - t, y = self.get_recent_data(k) - self.plot(t, y) - - def init_plot(self): - pass - - def plot(self, t, y): - pass - - def clear(self): - pass - - -class PMTimeSeriesMPLWidget(PMBaseTimeSeriesWidget): - def __init__(self, max_samples: int = 10000, recent_samples: int = 100): - super(PMTimeSeriesMPLWidget, self).__init__(max_samples=max_samples, recent_samples=recent_samples) - - self.setLayout(QVBoxLayout()) - self.plot_widget = PMMatplotlibQt5Widget(self) - self.layout().addWidget(self.plot_widget) - self.layout().addWidget(QPushButton('aaaa')) - - self.ax = None - - def plot(self, t, y): - ax = self.plot_widget.add_subplot(111) - ax.plot(t, y, 'r') - ax.set_xlabel('test_x_label') - self.plot_widget.draw() - self.plot_widget.canvas.flush_events() - - def clear(self): - self.plot_widget.figure.clf() - - -class PMTimeSeriesPGWidget(PMBaseTimeSeriesWidget): - def __init__(self, max_samples: int = 10000, recent_samples: int = 100): - super(PMTimeSeriesPGWidget, self).__init__(max_samples=max_samples, recent_samples=recent_samples) - import pyqtgraph - self.curves: Dict = {} - self.setLayout(QVBoxLayout()) - self.plot_widget = pyqtgraph.plot() # PMMatplotlibQt5Widget(self) - self.layout().addWidget(self.plot_widget) - self.layout().addWidget(QPushButton('aaaa')) - - self.ax = None - - def add_data(self, data_name, data_type): - super().add_data(data_name, data_type) - self.curves[data_name] = self.plot_widget.plot() - - # def plot(self, t, y): - # self.curves[].setData(y) - def refresh(self): - for k in self.time.keys(): - t, y = self.get_recent_data(k) - self.curves[k].setData(t, y) - - def clear(self): - pass - - -def time_out(): - t0 = time.time() - global i, graphics - i += 1 - graphics.add_sample('a', value=np.random.randint(100)) - t1 = time.time() - logger.debug(i, 'time elapsed :', t1 - t0) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - - - def mpl(): - global i, graphics - graphics = PMTimeSeriesMPLWidget(max_samples=100, recent_samples=20) - graphics.show() - i = 0 - - graphics.add_data('a', np.float) - - timer = QTimer() - timer.start(50) - timer.timeout.connect(time_out) - - - def pg(): - global i, graphics - graphics = PMTimeSeriesPGWidget(max_samples=2000, recent_samples=1000) - graphics.show() - i = 0 - - graphics.add_data('a', np.float) - - - timer = QTimer() - - timer.timeout.connect(time_out) - - timer.start(1) - pg() - # timer.start(100) - # mpl() - - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/display/dynamicgraph/mplplots/__init__.py b/pyminer/pmgwidgets/display/dynamicgraph/mplplots/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/display/dynamicgraph/pgexample.py b/pyminer/pmgwidgets/display/dynamicgraph/pgexample.py deleted file mode 100644 index fd70829a..00000000 --- a/pyminer/pmgwidgets/display/dynamicgraph/pgexample.py +++ /dev/null @@ -1,6 +0,0 @@ -import sys - -from pyqtgraph import examples - -if __name__ == '__main__': - examples.run() diff --git a/pyminer/pmgwidgets/display/dynamicgraph/pgplots/__init__.py b/pyminer/pmgwidgets/display/dynamicgraph/pgplots/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/display/examples.py b/pyminer/pmgwidgets/display/examples.py deleted file mode 100644 index ae8d24c9..00000000 --- a/pyminer/pmgwidgets/display/examples.py +++ /dev/null @@ -1,4 +0,0 @@ -from pyqtgraph import examples - -if __name__ == '__main__': - examples.run() diff --git a/pyminer/pmgwidgets/display/matplotlib/__init__.py b/pyminer/pmgwidgets/display/matplotlib/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/display/matplotlib/pmagg.py b/pyminer/pmgwidgets/display/matplotlib/pmagg.py deleted file mode 100644 index 2e665d7f..00000000 --- a/pyminer/pmgwidgets/display/matplotlib/pmagg.py +++ /dev/null @@ -1,36 +0,0 @@ -import sys -from PySide2 import QtWidgets -import matplotlib.pyplot as plt -import random -sys.path.append(r'E:\Python\pyminer_bin\PyMiner\bin\pyminer2\extensions\packages\pmagg') -import PMAgg -import os - - -class MainWindow(QtWidgets.QDialog): - def __init__(self, figure, config_path): - super().__init__() - layout = QtWidgets.QVBoxLayout() - mpl_app = PMAgg.Window(config_path) - # 只需要将mpl绘图产生的figure对象以及一个配置文件.cfg的路径传给PMAgg即可,配置文件可以留空。 - mpl_app.get_canvas(figure) - layout.addWidget(mpl_app) - # 一个额外的按钮 - self.button = QtWidgets.QPushButton('test') - layout.addWidget(self.button) - self.setLayout(layout) - - -if __name__ == '__main__': - # matplotlib 绘图 - fig = plt.figure() - ax = fig.add_subplot(111) - data = [random.random() for i in range(25)] - ax.plot(data, '*-') - # app - app = QtWidgets.QApplication(sys.argv) - config_path = os.path.join(r'E:\Python\pyminer_bin\PyMiner\bin\pyminer2\extensions\packages\pmagg', 'settings.cfg') - main = MainWindow(fig, config_path) - main.setWindowTitle('Simple PySide2 and PMAgg example') - main.show() - sys.exit(app.exec_()) \ No newline at end of file diff --git a/pyminer/pmgwidgets/display/matplotlib/pyqtgraph/__init__.py b/pyminer/pmgwidgets/display/matplotlib/pyqtgraph/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/display/matplotlib/pyqtgraph/pyqtgraphwidget.py b/pyminer/pmgwidgets/display/matplotlib/pyqtgraph/pyqtgraphwidget.py deleted file mode 100644 index 318ff05f..00000000 --- a/pyminer/pmgwidgets/display/matplotlib/pyqtgraph/pyqtgraphwidget.py +++ /dev/null @@ -1,69 +0,0 @@ -import sys -import random -import numpy as np -import pyqtgraph as pg -from PySide2.QtCore import QTimer -from PySide2.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout - - -class PMPyQtGraphWidget(QWidget): - def __init__(self, parent=None): - super(PMPyQtGraphWidget, self).__init__(parent) - self.resize(600, 600) - self.lines = [] - # 1 - pg.setConfigOptions(leftButtonPan=False) - pg.setConfigOption('background', 'w') - pg.setConfigOption('foreground', 'k') - - # 2 - # x = np.random.normal(size=1000) - # y = np.random.normal(size=1000) - # r_symbol = random.choice(['o', 's', 't', 't1', 't2', 't3', 'd', '+', 'x', 'p', 'h', 'star']) - # r_color = random.choice(['b', 'g', 'r', 'c', 'm', 'y', 'k', 'd', 'l', 's']) - - # 3 - self.pw = pg.PlotWidget(self,axisItems = {'bottom': pg.DateAxisItem()}) - # self.plot_data = self.pw.plot(x, y, pen=None, symbol=r_symbol, symbolBrush=r_color) - - # 4 - # self.plot_btn = QPushButton('Replot', self) - # # self.plot_btn.clicked.connect(self.plot_slot) - - self.v_layout = QVBoxLayout() - self.v_layout.addWidget(self.pw) - # self.v_layout.addWidget(self.plot_btn) - self.setLayout(self.v_layout) - - def plot(self, x, ylist): - self.baseplot(x, ylist) - # self.timer2 = QTimer() - # self.timer2.singleShot(5000, lambda: self.baseplot(np.array(x)+2, ylist)) - # self.baseplot(x, ylist) - - def baseplot(self, x, ylist): - # print('baseplot!') - for line in self.lines: - line.clear() - for y in ylist: - plot_data = self.pw.plot(x, y, pen=None, symbol='+', symbolBrush='r') - self.lines.append(plot_data) - - def draw(self): - pass - - def clear(self): - pass - # def plot_slot(self): - # x = np.random.normal(size=1000) - # y = np.random.normal(size=1000) - # r_symbol = random.choice(['o', 's', 't', 't1', 't2', 't3', 'd', '+', 'x', 'p', 'h', 'star']) - # r_color = random.choice(['b', 'g', 'r', 'c', 'm', 'y', 'k', 'd', 'l', 's']) - # self.plot_data.setData(x, y, pen=None, symbol=r_symbol, symbolBrush=r_color) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - demo = PMPyQtGraphWidget() - demo.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/display/matplotlib/qt5agg.py b/pyminer/pmgwidgets/display/matplotlib/qt5agg.py deleted file mode 100644 index c88513aa..00000000 --- a/pyminer/pmgwidgets/display/matplotlib/qt5agg.py +++ /dev/null @@ -1,50 +0,0 @@ -from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg -import matplotlib.pyplot as plt -from PySide2.QtWidgets import QVBoxLayout, QWidget -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from matplotlib.axes._subplots import Axes - - -class PMMatplotlibQt5Widget(QWidget): - def __init__(self, parent=None): - super().__init__(parent) - self.figure = plt.figure(facecolor='#FFD7C4') # 可选参数,facecolor为背景颜色 - self.canvas = FigureCanvasQTAgg(self.figure) - layout = QVBoxLayout() - layout.addWidget(self.canvas) - self.setLayout(layout) - - def add_subplot(self, param) -> 'Axes': - return self.figure.add_subplot(param) - - def draw(self) -> None: - self.canvas.draw() - - def clear(self): - self.figure.clf() - - -if __name__ == '__main__': - import sys - # from PySide2.QtWidgets import QApplication - from PySide2.QtWidgets import QApplication - from pmgwidgets.display import PMMatplotlibQt5Widget - - - def draw(): - ax = pmqt5mplwgt.add_subplot(121) - ax2 = pmqt5mplwgt.add_subplot(122) - ax.plot([1, 2, 3]) - ax.set_xlabel('test_x_label') - ax2.set_xlabel('test_2') - ax2.plot([1, 3, 1, 4, 15]) - pmqt5mplwgt.draw() - - - app = QApplication(sys.argv) - pmqt5mplwgt = PMMatplotlibQt5Widget() - pmqt5mplwgt.show() - draw() - app.exec_() diff --git a/pyminer/pmgwidgets/display/vtk/__init__.py b/pyminer/pmgwidgets/display/vtk/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/doc_figures/nested_lists_to_place_widgets.png b/pyminer/pmgwidgets/doc_figures/nested_lists_to_place_widgets.png deleted file mode 100644 index a9247c0d3de4473f798da8a936b7de86ab842f27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3438 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 X5)MY{gl*`}9|=%Z(o%%WTfO}sY96mk diff --git a/pyminer/pmgwidgets/doc_figures/pmflowarea_1.png b/pyminer/pmgwidgets/doc_figures/pmflowarea_1.png deleted file mode 100644 index bcf6e2c4c08447d449e9de5d624646180b97fbcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3961 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 DGoW3P diff --git a/pyminer/pmgwidgets/doc_figures/pmflowarea_2.png b/pyminer/pmgwidgets/doc_figures/pmflowarea_2.png deleted file mode 100644 index 801eda3645d47987474ddb688d60d0ca75c792f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3959 zcmeHKX;f257JhDsXsaj~H6SXj-~tiS?1Uh)*|KQBJrI>m2#XLIeyFLRi8Uk_irT&h$*roayPAe{)W~SIene_ui`SeswGM zxRc#CO52qH0Qlypy)^;=mJoe=d4J6n`?FX8SYNyNEn@~f@dSVk>yBC7bu7u@VU zJHw`0@yHkw2*Q|~`ZBH)c%PKgG8E}%lsyd%hUemMaRs)HDf-dZ1nS#ecnfN(qwx7dL;>b)1Fno>AfPD@|NFBSIB zx?m;(Jf@~{kwT82SPCZvG2#ui5cyr;p?*GvcX#!p35|yt9-xr)1v(2EA2Ukbqlg-X7Q z3MaF(d2`d3EX0MgTaW2t;eI1a>ORPyUt_03?eNzmv^4 zmoN)l^2dt?swNuEc&q6$`=@7f%$5PyGT_PWgPFv0EZqwk5H5e+QHdtYj-P_b#?ZTD4W!C###oNhJ%a}ifX z0S1#wJImV%=9hx6nMRFRn(9xVtE`zZCXL!6B_j08NMGk&RRIUrtDV7dZRlEn<*NIC zRnBmM4k1<+_gpb)>kT#ubSLa<%gfb0>G3_eEVi z;(<+98*Y$VgOR*Pa~=sl_tm%0cb6I)67=_m+K#{ykU%rm%@ zsb<_k8;_pmT0JUuxAc)DpniaxQ`|7W9MEyA%E_&@65iL)*M;BjM!$=HW4qDt(iJyx zsGFt|_&Ve!Tq8vn6;Gu)PY9AaRhyiw)xJMDGx{gcrC?ze5my~(#*+rj?guQ12Jo0? zvnDrdT1}MD${pwT1ccv;Z z0H(xwdbSt4MqJm2Zi2O!%U&Dnqr#2DzCcCY*YD|3wfoEKauNg*iBbBC7YE$a;F~s# za?8imVtSPAieVsS;EYc3OUsPh+s{FHf$QH`Dc|hSt7#EwrK`;~_w6CLx{1r;$_9Q( zIzY-ga%HaegJ^-f;M9GU<2IZ1e8lX>3Wixz1M|SK?lrg&l#V+^=BYNp`yK%1$Q~+< z4GoNu5r2;J_6Bl$M2 z5Lj6&EEWJJ>!Rhf6}|tg_*e@79ICe71prGtX1QBw8L)AQ#}YdyAWpakRzUR0;vGb1 z_^h=&a9@Friam&B8b|T4^)v}NCSe&cmMJH_O-n3jsj?inBWJ?U*+E{2C!3W%-#3WaQc zme&|7Hy!zo{LaM1QP7y?P^Im!N)U+W^{y={KRM&oDQH?G=_RM5t>yOaTypx`-(vH{ ziLr8f7ad!iX#Y>Q>m-PHzTCe6;+oLmdXKtTQWhH_<-?Dzczf?fp|xrD_=oGK}9e)=iHephwgr8Znh8bVm0ZWB*R$1q}>JCS!)NRZopdI`gr#>Hi_(_EcrGwZjQ z=igDnCcYUrJ{|48^%rfH)TV71kxGmxET8TK)rQ^! z=XX(Gm_@zZUa8HxnehPMf!Gle2ETsMko_W&s#4JmKah5;kjJkH^mZA^kyWN0%WLQ0 zC4Pn>C(f+nL>Dss$pu|hPo|gf2*CtJM(-JNz&s5TI~!p!-=G7Y2=_fc$I45Wi(w8f za0EySrZUYDgT#yk_r@e)8jy0?jxT#7{_K((p+=8}}JmHpNz#n8Y&H76%$cFXlcFqk@z$D3_iUbe0JRGD7N zYiNpJuuh@wkb}WXGar3TO-(&Bvy7l3*6S3MdZW-n0r<)64;|;<1Nv8p+4yn@m6=MI ztJfND$aQpd96+yYnVG@S%3t}DABGtYBEA_!I2L=c2QmxtP7OJD%R|)L$7iA_$z*1{ zu*XIYDRxVt_T-q}Z%5u&-JlZb?(rW=*aNFjh4n~sLC;#z@}6yPNvC~4EzQl%c+%n2 ztgJvV(HnZE$lF8rx{ofqb@ZGdmA7k}Vt`!WS$|auM0G!G#97 z&@9$Xim&KIxvxGG`|w9O*;H!&4Xyr5VEuk7IuRjd#Lnht<9BnBovp2|w7Q*f2?;~! zwXD4D={_F1>kpm9 ztM?|DersC!nW}|t@vc7aW{%&ebSKUeKptg<&S0HsEw0#vDJki{tTE3k#GP2 diff --git a/pyminer/pmgwidgets/doc_figures/settings_panel.png b/pyminer/pmgwidgets/doc_figures/settings_panel.png deleted file mode 100644 index b4c6efde1e420a860e2b110fda5f5eddf57077ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6119 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 diff --git a/pyminer/pmgwidgets/docs/doc_figures/pmflowarea_2.png b/pyminer/pmgwidgets/docs/doc_figures/pmflowarea_2.png deleted file mode 100644 index 801eda3645d47987474ddb688d60d0ca75c792f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3959 zcmeHKX;f257JhDsXsaj~H6SXj-~tiS?1Uh)*|KQBJrI>m2#XLIeyFLRi8Uk_irT&h$*roayPAe{)W~SIene_ui`SeswGM zxRc#CO52qH0Qlypy)^;=mJoe=d4J6n`?FX8SYNyNEn@~f@dSVk>yBC7bu7u@VU zJHw`0@yHkw2*Q|~`ZBH)c%PKgG8E}%lsyd%hUemMaRs)HDf-dZ1nS#ecnfN(qwx7dL;>b)1Fno>AfPD@|NFBSIB zx?m;(Jf@~{kwT82SPCZvG2#ui5cyr;p?*GvcX#!p35|yt9-xr)1v(2EA2Ukbqlg-X7Q z3MaF(d2`d3EX0MgTaW2t;eI1a>ORPyUt_03?eNzmv^4 zmoN)l^2dt?swNuEc&q6$`=@7f%$5PyGT_PWgPFv0EZqwk5H5e+QHdtYj-P_b#?ZTD4W!C###oNhJ%a}ifX z0S1#wJImV%=9hx6nMRFRn(9xVtE`zZCXL!6B_j08NMGk&RRIUrtDV7dZRlEn<*NIC zRnBmM4k1<+_gpb)>kT#ubSLa<%gfb0>G3_eEVi z;(<+98*Y$VgOR*Pa~=sl_tm%0cb6I)67=_m+K#{ykU%rm%@ zsb<_k8;_pmT0JUuxAc)DpniaxQ`|7W9MEyA%E_&@65iL)*M;BjM!$=HW4qDt(iJyx zsGFt|_&Ve!Tq8vn6;Gu)PY9AaRhyiw)xJMDGx{gcrC?ze5my~(#*+rj?guQ12Jo0? zvnDrdT1}MD${pwT1ccv;Z z0H(xwdbSt4MqJm2Zi2O!%U&Dnqr#2DzCcCY*YD|3wfoEKauNg*iBbBC7YE$a;F~s# za?8imVtSPAieVsS;EYc3OUsPh+s{FHf$QH`Dc|hSt7#EwrK`;~_w6CLx{1r;$_9Q( zIzY-ga%HaegJ^-f;M9GU<2IZ1e8lX>3Wixz1M|SK?lrg&l#V+^=BYNp`yK%1$Q~+< z4GoNu5r2;J_6Bl$M2 z5Lj6&EEWJJ>!Rhf6}|tg_*e@79ICe71prGtX1QBw8L)AQ#}YdyAWpakRzUR0;vGb1 z_^h=&a9@Friam&B8b|T4^)v}NCSe&cmMJH_O-n3jsj?inBWJ?U*+E{2C!3W%-#3WaQc zme&|7Hy!zo{LaM1QP7y?P^Im!N)U+W^{y={KRM&oDQH?G=_RM5t>yOaTypx`-(vH{ ziLr8f7ad!iX#Y>Q>m-PHzTCe6;+oLmdXKtTQWhH_<-?Dzczf?fp|xrD_=oGK}9e)=iHephwgr8Znh8bVm0ZWB*R$1q}>JCS!)NRZopdI`gr#>Hi_(_EcrGwZjQ z=igDnCcYUrJ{|48^%rfH)TV71kxGmxET8TK)rQ^! z=XX(Gm_@zZUa8HxnehPMf!Gle2ETsMko_W&s#4JmKah5;kjJkH^mZA^kyWN0%WLQ0 zC4Pn>C(f+nL>Dss$pu|hPo|gf2*CtJM(-JNz&s5TI~!p!-=G7Y2=_fc$I45Wi(w8f za0EySrZUYDgT#yk_r@e)8jy0?jxT#7{_K((p+=8}}JmHpNz#n8Y&H76%$cFXlcFqk@z$D3_iUbe0JRGD7N zYiNpJuuh@wkb}WXGar3TO-(&Bvy7l3*6S3MdZW-n0r<)64;|;<1Nv8p+4yn@m6=MI ztJfND$aQpd96+yYnVG@S%3t}DABGtYBEA_!I2L=c2QmxtP7OJD%R|)L$7iA_$z*1{ zu*XIYDRxVt_T-q}Z%5u&-JlZb?(rW=*aNFjh4n~sLC;#z@}6yPNvC~4EzQl%c+%n2 ztgJvV(HnZE$lF8rx{ofqb@ZGdmA7k}Vt`!WS$|auM0G!G#97 z&@9$Xim&KIxvxGG`|w9O*;H!&4Xyr5VEuk7IuRjd#Lnht<9BnBovp2|w7Q*f2?;~! zwXD4D={_F1>kpm9 ztM?|DersC!nW}|t@vc7aW{%&ebSKUeKptg<&S0HsEw0#vDJki{tTE3k#GP2 diff --git a/pyminer/pmgwidgets/docs/threading_and_tasking.md b/pyminer/pmgwidgets/docs/threading_and_tasking.md deleted file mode 100644 index d7d85dcd..00000000 --- a/pyminer/pmgwidgets/docs/threading_and_tasking.md +++ /dev/null @@ -1,218 +0,0 @@ -# 线程调用与后台任务执行器 -示例可见:`pmgwidgets/examples/utilities/threadings`文件夹 - ->警告: -> ->- 在调用后台线程执行器PMGOneShot0hreadRunner\PMGLoopThreadRunner的时候,务必对执行器对象保持引用!否则执行器对象会被Python解释器垃圾回收,轻则任务无法完成,重则造成程序崩溃。 -> ->- 注意:传入的callback函数不得在其中直接刷新UI(比如,调用文本框的setText方法),否则可能出现段错误(segmentation fault)。段错误会**立即导致界面崩溃**,且无法使用try...catch...或者cgitb等手段进行处理! -> ->注意: -> ->- 为了简单起见,本文档中的实例都是面向过程的。在示例中将执行器对象定义为全局变量,就是保持引用的一种方式。而当使用面向对象程序设计方式时,将其作为界面或者控件的属性,也不失为一种可行的解决方案。 - -## 后台线程只执行一次`PMGOneShotThreadRunner` -示例代码可以在`pmgwidgets/examples/utilities/threadings/singleshot.py`找到 -```python -import sys -import time - -from pmgwidgets import PMGOneShotThreadRunner # 导入单线程任务运行器 -from PySide2.QtWidgets import QTextEdit, QApplication, QWidget, QVBoxLayout, QPushButton - - -def run(loop_times): - for i in range(loop_times): - print(i) - time.sleep(1) - return 'finished!!', 'aaaaaa', ['finished', 123] - - -def single_shoot(): - global oneshot, textedit - if oneshot is not None: - if oneshot.is_running(): # 如果后台线程已经在运行,那么就不要重新创建,否则可能造成程序崩溃。在实际程序中可以考虑加一个弹出框来进行提示。 - return - oneshot = PMGOneShotThreadRunner(run, args=(3,)) - oneshot.signal_finished.connect(lambda x: textedit.append('任务完成,函数返回值:' + repr(x))) - - -oneshot = None -app = QApplication(sys.argv) -basewidget = QWidget() -basewidget.setLayout(QVBoxLayout()) - -textedit = QTextEdit() -pushbutton = QPushButton('run') -pushbutton.clicked.connect(single_shoot) -basewidget.layout().addWidget(textedit) -basewidget.layout().addWidget(pushbutton) -basewidget.show() -sys.exit(app.exec_()) - -``` -运行时,点击弹出的窗体的`run`按钮,即可触发运行事件。等待3秒钟过后,即可显示下面的文字。多次点击,可以多次执行。 - -![](doc_figures/test_oneshot_thread.png) - - - -### `PMGOneShotThreadRunner`类介绍 - -#### 传入参数: -- callback:传入函数对象。 -- args: 传入函数的参数,默认值为None。应当以元组形式依次传入。如果为None则不对函数传入参数。 -#### 信号 -signal_finished,需要连接到的槽函数有一个参数,代表传入函数对象的返回值。 - -#### 方法 -is_running,返回线程是否在运行。 - -#### 注意事项 -对于单步执行的子线程,`pmgwidgets`库**暂时不提供**强制停止未完成任务(或者出现错误而退出)的子线程的接口。用户需要保证子线程可以在一定时间后正确的退出。 - - - -## 后台线程执行有限次`PMGLoopThreadRunner` -后台线程执行有限次的例子可见`pmgwidgets/examples/utilities/threadings/loop_limited_times1.py`与 -`pmgwidgets/examples/utilities/threadings/loop_limited_times2.py`。 -首先,执行有限次的模型是这样的:执行有限次同一函数,但是每次执行时都要传入不同的参数。这样,我们只要传入一个函数,以及一个参数列表, -列表长度就是循环的次数。返回的参数由`signal_step_finished`传回。 -代码看这里:(`pmgwidgets/examples/utilities/threadings/loop_limited_times1.py`) - -```python -import sys -import time -from PySide2.QtWidgets import QTextEdit, QApplication -from pmgwidgets import PMGLoopThreadRunner - - -def run(i, j): - time.sleep(0.1) - return i + j - - -def on_step_finished(step, result): - global text1 - text1.append('传入每步不同的可迭代参数\nstep:%d,result:%s\n' % (step, repr(result))) - - -def on_finished(): - global text1 - text1.append('所有任务完成!') - - -app = QApplication(sys.argv) -text1 = QTextEdit() -text1.show() -oneshot = PMGLoopThreadRunner(run, iter_args=[(i, i + 1) for i in range(36)]) -# 传入一个列表可迭代对象(当然也可以是其他迭代器。)作为参数。列表的长度就是循环的次数,列表的每一个元素代表每一步传入的参数。 -oneshot.signal_step_finished.connect(on_step_finished) # 每一步执行后的结果由signal_step_finished传回。多参数则会放进tuple里面。 -oneshot.signal_finished.connect(on_finished) - -sys.exit(app.exec_()) -``` -### `PMGLoopThreadRunner`类介绍 -#### 传入参数: -- callback:传入函数对象。 -- iter_args: 传入函数的参数,默认值为None。应当以可迭代对象的形式传入,可迭代对象的每个元素都是元组。可以为None。 -**注意:只有当iter_args为None的时候,才会解析loop_times和step_args参数**! -- loop_times:执行的次数。 -- step_args:当loop_times生效时每步执行传入的参数,类型应为元组。 - -通过以上的示例我们可以看出,loop_times的功能完全可以被iter_args替代。但为了简洁方便,还是设计了这一方法。 -若要用loop_times配合step_args,则必须设置iter_args为None。 -使用loop_times配合step_args的示例详见`pmgwidgets/examples/utilities/threadings/loop_limited_times2.py` -#### 信号 -signal_step_finished:传递两个参数,分别是步数(整数,从0开始)和单步执行的结果。 -signal_finished,意思后台线程执行完规定次数退出前发出的信号。它没有传递参数,在这点上与单步执行器不同。 -这是因为在结束时,他只是通知一下前台程序”任务已经完成,后台线程要退出了“;而程序每一步的执行结果,都已经在signal_step_finished中传过了。 - - - - - -## 后台线程无限反复运行`PMGEndlessLoopThreadRunner` -后台线程反复运行无数次的例子可见 -`pmgwidgets/examples/utilities/threadings/endlessloop.py`。 -首先,执行有限次的模型是这样的:执行有限次同一函数,但是每次执行时都要传入不同的参数。这样,我们只要传入一个函数,以及一个参数列表, -列表长度就是循环的次数。返回的参数由`signal_step_finished`传回。 -### 例程 -```python -import sys -import time -from PySide2.QtWidgets import QTextEdit, QApplication, QPushButton, QWidget, QVBoxLayout -from pmgwidgets import PMGEndlessLoopThreadRunner - - -def run(i, j): - time.sleep(0.1) - return i + j - - -def on_step_finished(result): - global text1, stepcount - text1.append('step:%d,result:%s\n' % (stepcount,repr(result))) - stepcount += 1 - - -def on_finished(): - global text1 - text1.append('thread quit, all tasks completed!') - - -def start_thread(): - global endless_loop - if endless_loop is not None: - if endless_loop.is_running(): - return - endless_loop = PMGEndlessLoopThreadRunner(run, args=(0, 0)) - endless_loop.signal_step_finished.connect(on_step_finished) - endless_loop.signal_finished.connect(on_finished) - -def stop_thread(): - global endless_loop - endless_loop.shut_down() - -stepcount = 0 -endless_loop:PMGEndlessLoopThreadRunner = None - -app = QApplication(sys.argv) -basewidget = QWidget() -basewidget.setLayout(QVBoxLayout()) - -text1 = QTextEdit() -pushbutton_run = QPushButton('Run') -pushbutton_stop = QPushButton('Stop') -pushbutton_run.clicked.connect(start_thread) -pushbutton_stop.clicked.connect(stop_thread) -basewidget.layout().addWidget(text1) -basewidget.layout().addWidget(pushbutton_run) -basewidget.layout().addWidget(pushbutton_stop) -basewidget.show() -sys.exit(app.exec_()) -``` -直接运行,则可以看到以下界面: -![image-20201128192325593](doc_figures/endlessloop_ui.png) - -在这个界面上点击`Run`即可运行。看到以下效果: -![image-20201128192325593](doc_figures/endlessloop_running.png) - -在这个界面上点击`Stop`即可停止。看到以下效果: -![image-20201128192325593](doc_figures/endlessloop_stop.png) - -再次点击`Run`,可以继续运行。 - -### `PMGEndlessLoopThreadRunner`类介绍 - -#### 传入参数: -- callback: 回调函数。函数每执行一次,信号`signal_step_finished`将发出,信号只有一个参数,也就是我们输入的callback的返回值。 -- args:参数 - -#### 信号 -signal_step_finished:传递两个参数,分别是步数(整数,从0开始)和单步执行的结果。 -signal_finished,意思后台线程执行完规定次数退出前发出的信号。它没有传递参数,在这点上与单步执行器不同。 -这是因为在结束时,他只是通知一下前台程序”任务已经完成,后台线程要退出了“;而程序每一步的执行结果,都已经在signal_step_finished中传过了。 - -#### 方法 -is_running,返回线程是否在运行。 \ No newline at end of file diff --git a/pyminer/pmgwidgets/elements/__init__.py b/pyminer/pmgwidgets/elements/__init__.py deleted file mode 100644 index eb1e9220..00000000 --- a/pyminer/pmgwidgets/elements/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .toolbar import * -from .dockobject import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/elements/dockobject.py b/pyminer/pmgwidgets/elements/dockobject.py deleted file mode 100644 index f5c5e5c0..00000000 --- a/pyminer/pmgwidgets/elements/dockobject.py +++ /dev/null @@ -1,62 +0,0 @@ -from typing import Tuple - -from PySide2.QtWidgets import QWidget - - -class PMDockObject(object): - """ - 修改: - 原先,主窗口中的各个可停靠窗口,在点击右上角关闭按钮的时候会隐藏,可以在视图菜单中打开。 - 但是当控件中有on_closed_action属性,且值为‘delete’的时候,控件就会被回收。 - 为了实现控件的管理,控件需要继承PMDockObject,并且需要用多继承的方式。 - 注意,凡是要和一些内置事件绑定的控件,都不要用delete。 - - - from features.ui.generalwidgets import PMDockObject - 这个PMDockObject中定义了一些方法,作为补充。 - - class PMDockObject(object): - on_closed_action = 'hide' # 或者'delete'。 - - def raise_widget_to_visible(self, widget: 'QWidget'): - pass - - def on_dock_widget_deleted(self): - pass - - """ - on_closed_action = 'hide' # 或者'delete'。 - - def is_temporary(self) -> bool: - """ - 如果为True,相应的控件将在窗口关闭时删除,并且不会记忆其位置。如果为False,则相应的控件不会被删除,且其位置将被记忆。 - - 默认返回False。 - """ - return False - - def raise_widget_to_visible(self, widget: 'QWidget'): - pass - - def on_dock_widget_deleted(self): - pass - - def get_split_portion_hint(self) -> Tuple[int, int]: - return (None, None) - - def set_extension_lib(self, extension_lib): - """ - 设置扩展库。 - :param extension_lib: - :return: - """ - self.extension_lib = extension_lib - - def setup_ui(self): - pass - - def bind_events(self): - pass - - def get_widget_text(self) -> str: - return '' diff --git a/pyminer/pmgwidgets/elements/toolbar.py b/pyminer/pmgwidgets/elements/toolbar.py deleted file mode 100644 index 2f91a758..00000000 --- a/pyminer/pmgwidgets/elements/toolbar.py +++ /dev/null @@ -1,200 +0,0 @@ -from typing import List, Callable, Optional - -from PySide2.QtCore import Qt, QSize -from PySide2.QtGui import QIcon -from PySide2.QtWidgets import QToolBar, QPushButton, QMenu, QToolButton, QAction, QWidget, QHBoxLayout - - -class ActionWithMessage(QAction): - def __init__(self, text: str = '', icon: QIcon = None, - parent: QWidget = None, message: str = ''): - super().__init__(parent) - self.setText(text) - if icon is not None: - self.setIcon(icon) - self.message = message - - -class TopToolBar(QToolBar): - def __init__(self): - super().__init__() - self.setFloatable(False) - self.setMovable(False) - self.buttonbar_widget = QWidget() - self.addWidget(self.buttonbar_widget) - self.buttonbar_widget.setLayout(QHBoxLayout()) - self.buttonbar_widget.setContentsMargins(0, 0, 0, 0) - self.buttonbar_widget.layout().setContentsMargins(0, 0, 0, 0) - self.button_names = [] - - def add_button(self, name: str, text: str): - pbtn = QPushButton(text) - pbtn.setObjectName('pmtopToolbarButton') - pbtn.setProperty('stat', 'unselected') - self.buttonbar_widget.layout().addWidget(pbtn) - self.button_names.append(name) - return pbtn - - def insert_button(self, name: str, text: str, insert_after: str): - pbtn = QPushButton(text) - pbtn.setObjectName('pmtopToolbarButton') - pbtn.setProperty('stat', 'unselected') - - assert insert_after in self.button_names, f'{insert_after} do not in buttons: {self.button_names}' - index = self.button_names.index(insert_after) - self.button_names.insert(index + 1, name) - self.buttonbar_widget.layout().insertWidget(index + 1, pbtn) - return pbtn - - def get_button(self, name: str): - return self.findChild(QPushButton, name) - - -class TopToolBarRight(QToolBar): - def __init__(self): - super().__init__() - self.setFloatable(False) - self.setMovable(False) - self.setLayoutDirection(Qt.RightToLeft) - self.hide_button = QToolButton() - self.hide_button.setObjectName("hidebutton") - self.hide_button.setArrowType(Qt.UpArrow) - self.addWidget(self.hide_button) - - -class PMGToolBar(QToolBar): - tab_button: QPushButton = None - _control_widget_dic = {} - - def __init__(self, parent=None): - super().__init__(parent) - self._control_widget_dic = {} - - def get_toolbar_text(self) -> str: - return 'Toolbar' - - def get_control_widget(self, widget_name: str) -> QPushButton: - w = self._control_widget_dic.get(widget_name) - if w is None: - raise Exception( - 'Toolbar has no widget named \'%s\'' % - widget_name) - return w - - def bind_events(self): - pass - - def add_tool_button(self, name: str, text: str = '', tooltip: str = '', - icon: QIcon = None, menu: QMenu = None): - tb = QToolButton() - tb.setPopupMode(QToolButton.InstantPopup) - tb.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) - tb.setText(text) - tb.setToolTip(tooltip) - tb.setProperty('qssp', 'tooliconbtn') - if icon is not None: - pixmap = icon.pixmap(QSize(40, 40)) - icon = QIcon(pixmap) - tb.setIcon(icon) - - tb.setIconSize(QSize(40, 40)) - if menu is not None: - tb.setMenu(menu) - self.addWidget(tb) - self._control_widget_dic[name] = tb - return tb - - def add_height_occupation(self): - from pmgwidgets import PMPushButtonPane - - pp = PMPushButtonPane() - button_list = pp.add_height_occu_buttons() - self.addWidget(pp) - return button_list - - def add_buttons(self, button_num: int, names: List[str], texts: List[str], icons_path: List[str] = None) \ - -> List['QPushButton']: - from pmgwidgets import PMPushButtonPane - - pp = PMPushButtonPane() - button_list = pp.add_buttons(button_num, texts, icons_path) - for i, name in enumerate(names): - self._control_widget_dic[name] = button_list[i] - self.addWidget(pp) - return button_list - - def add_widget(self, name: str, widget: 'QWidget'): - self._control_widget_dic[name] = widget - self.addWidget(widget) - return widget - - def add_menu_to(self, button_name: str, - action_texts: List[str], - action_commands: List['Callable'], - action_icon: QIcon = None) -> Optional[QMenu]: - button = self.get_control_widget(button_name) - if button is not None: - menu = QMenu(self) - for text, cmd in zip(action_texts, action_commands): - a = QAction(text=text, parent=menu) - if action_icon is not None: - a.setIcon(action_icon) - menu.addAction(a) - a.triggered.connect(cmd) - button.setMenu(menu) - return menu - return None - - def append_menu(self, button_name: str, action_text: str, action_command: 'Callable', - action_icon: QIcon = None) -> 'QAction': - button: 'QToolButton' = self.get_control_widget(button_name) - action = None - if button is not None: - menu = button.menu() - if menu is None: - menu = self.add_menu_to(button_name, [action_text], [action_command], action_icon=action_icon) - return menu.actions()[0] - else: - action = QAction(text=action_text, parent=menu) - if action_icon is not None: - action.setIcon(action_icon) - menu.addAction(action) - action.triggered.connect(action_command) - - return action - - def append_qmenu(self, button_name: str, menu_text: str, menu_icon: QIcon = None) -> QMenu: - button: 'QToolButton' = self.get_control_widget(button_name) - action = None - if button is not None: - menu = button.menu() - new_menu = QMenu(menu) - new_menu.setTitle(menu_text) - # menu.addMenu() - menu.addMenu(new_menu) - # if menu is None: - # self.add_menu_to(button_name, [action_text], [action_command], action_icon=action_icon) - # else: - # action = QAction(text=action_text, parent=menu) - # if action_icon is not None: - # action.setIcon(action_icon) - # menu.addAction(action) - # action.triggered.connect(action_command) - - return new_menu - - def add_menu_separator(self, button_name): - button: 'QToolButton' = self.get_control_widget(button_name) - action = None - if button is not None: - menu: QMenu = button.menu() - if menu is not None: - menu.addSeparator() - - def insert_after(self) -> str: - """ - 返回插入在某某后面 - Returns: - - """ - return '' diff --git a/pyminer/pmgwidgets/examples/__init__.py b/pyminer/pmgwidgets/examples/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/examples/utilities/__init__.py b/pyminer/pmgwidgets/examples/utilities/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/examples/utilities/examples.py b/pyminer/pmgwidgets/examples/utilities/examples.py deleted file mode 100644 index 860b2fbf..00000000 --- a/pyminer/pmgwidgets/examples/utilities/examples.py +++ /dev/null @@ -1,21 +0,0 @@ -if __name__ == '__main__': - from pmgwidgets import BaseClient - - import numpy as np - - x = np.random.random(10) + np.linspace(1, 10, 10) - y = np.random.random(10) + np.linspace(1, 10, 10) - - c = BaseClient() - - print('set_var') - c.set_var('x', x) - c.set_var('y', y) - c.set_var('z', y) - c.set_var('w', y) - c.set_var('t', y) - c.set_var('y', y) - c.get_var('x') - print(c.get_all_vars()) - print(c.get_all_var_names()) - c.get_var('m') # 若没有m变量,就会报错 diff --git a/pyminer/pmgwidgets/examples/utilities/long_conn.py b/pyminer/pmgwidgets/examples/utilities/long_conn.py deleted file mode 100644 index e201e96c..00000000 --- a/pyminer/pmgwidgets/examples/utilities/long_conn.py +++ /dev/null @@ -1,5 +0,0 @@ -from pmgwidgets import GeneralClient -import time -__client = GeneralClient() -while(1): - time.sleep(1) \ No newline at end of file diff --git a/pyminer/pmgwidgets/flowchart/__init__.py b/pyminer/pmgwidgets/flowchart/__init__.py deleted file mode 100644 index abea00de..00000000 --- a/pyminer/pmgwidgets/flowchart/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .core import * -from .dataprocesswidget import PMDataProcessFlowWidget -from .simulationwidget import PMGSimulationWidget diff --git a/pyminer/pmgwidgets/flowchart/core/__init__.py b/pyminer/pmgwidgets/flowchart/core/__init__.py deleted file mode 100644 index 52eae64f..00000000 --- a/pyminer/pmgwidgets/flowchart/core/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .flow_content import * -from .flowchart_widget import PMFlowWidget \ No newline at end of file diff --git a/pyminer/pmgwidgets/flowchart/core/flow_content.py b/pyminer/pmgwidgets/flowchart/core/flow_content.py deleted file mode 100644 index 4ef6ee15..00000000 --- a/pyminer/pmgwidgets/flowchart/core/flow_content.py +++ /dev/null @@ -1,391 +0,0 @@ -''' -register contents -manager.register('') -''' -import json -import time -import types - -from PySide2.QtCore import QObject -from PySide2.QtWidgets import QApplication -from PySide2.QtCore import Signal -from typing import TYPE_CHECKING, Callable, List, Union, Tuple, Dict - -if TYPE_CHECKING: - from pmgwidgets.flowchart.core.flow_node import Node - from pmgwidgets.flowchart.core.flowchart_widget import PMGraphicsScene - - -class FlowContentError(): - def __init__(self, brief: str, detailed: str = ''): - self.brief: str = brief - if detailed == '': - detailed = brief - self.detailed: str = detailed - - -class PMGBaseFlowContent(QObject): - signal_exec_started = Signal(str) - signal_exec_doing = Signal(str) - signal_exec_finished = Signal(str) - signal_error_occurs = Signal(FlowContentError) - - def __init__(self): - super(PMGBaseFlowContent, self).__init__() - self.ports_changable: List[bool, bool] = [False, False] - self.input_args = [] - - self.results = [] - self.node: 'Node' = None - - def refresh_input_port_indices(self): - input_port_list = [p.get_connected_port()[0] for p in self.node.input_ports if len(p.get_connected_port()) > 0] - self.input_port_indices = [] - try: - for p in input_port_list: - index = p.node.get_port_index(p) - self.input_port_indices.append([p, index]) - except Exception as e: - import traceback - traceback.print_exc() - info = traceback.format_exc() - self.signal_error_occurs.emit(FlowContentError('Module:%s,Error:%s' % (self.node.text, str(e)), - info)) - return - - def format_param(self) -> str: - return '' - - def format_text(self) -> str: - return '' - - def set_params(self, params: Union[str]): - try: - if isinstance(params, str): - params = eval(params) - - if isinstance(params, list): - self.params = params - for i in range(len(params)): - self.params[i] = self.params[i] - param_name = self.params[i][1] - param_obj = self.params[i][3] - self.vars[param_name] = param_obj - self.node.display_internal_values(self.format_param()) - except: - import traceback - traceback.print_exc() - - def get_settings_params(self) -> List: - return [] - - def _process(self, input_args: list = None): - if input_args is None: - input_args = [] - try: - for p, index in self.input_port_indices: - if isinstance(p.node.content.results, types.GeneratorType): - input_args = [] # 对于迭代器场合,不需要任何输入值! - else: - val = p.node.content.results[index] - input_args.append(val) - - except Exception as e: - import traceback - traceback.print_exc() - self.signal_error_occurs.emit(FlowContentError(str(e), traceback.format_exc())) - return - self.input_args = input_args - self.signal_exec_started.emit('started') - if not isinstance(input_args, list): - self.signal_error_occurs.emit(FlowContentError('input list is not instance of list')) - return None - t1 = time.time() - try: - result = self.process(*input_args) - except Exception as e: - import traceback - exc = traceback.format_exc() - self.signal_error_occurs.emit( - FlowContentError('Module:%s,Error:%s' % (self.node.text, str(e)), - 'Info:%s' % (exc))) - return None - # self.results = copy.deepcopy(result) - if isinstance(result, types.GeneratorType): # 如果发现返回值是一个迭代器,就执行迭代器的next方法。 - step = 0 - while 1: - try: - self.results = next(result) - - next_content = self.get_next_content() - # self.signal_exec_finished.emit( - # 'finished\ninput value:%s\noutput value:%s' % (repr(input_list), repr(self.results))) - self.signal_exec_finished.emit('Iterating, %s' % repr(self.results)) - QApplication.instance().processEvents() # 调用processEvents进行处理 - if next_content is None: - return - else: - next_content._process() - except StopIteration: - self.signal_exec_finished.emit('finished!') - return - - self.results = result - next_content = self.get_next_content() - # self.signal_exec_finished.emit( - # 'finished\ninput value:%s\noutput value:%s' % (repr(input_list), repr(self.results))) - self.signal_exec_finished.emit('finished') - if next_content is None: - return - else: - next_content._process() - - def refresh(self): - pass - - def dump(self): - return {'code': self.code, 'type': 'function', 'params': self.params, 'ports_changable': self.ports_changable} - - def process(self, *args) -> List[object]: - - return [] - - def get_next_content(self) -> 'FlowContentForFunction': - scene: 'PMGraphicsScene' = self.node.base_rect.scene() - scene.node_index_to_execute += 1 - node_index = scene.node_index_to_execute - if node_index >= len(scene.call_id_list): - scene.node_index_to_execute = 0 - return None - node_id = scene.call_id_list[node_index] - return scene.find_node(node_id).content - - def settings_window_requested(self, parent): - """ - 当设置窗口被请求时处理的函数。 - 设置结束后,在节点表面上回显参数。需要调用format_params函数 - Args: - parent: 父控件,若要弹出对话框就必须这样做。 - - Returns: - - """ - self.on_settings_requested(parent) - self.node.display_internal_values(self.format_param()) - - def on_settings_requested(self, parent): - pass - - -class PMGFlowContent(PMGBaseFlowContent): - def __init__(self): - super(PMGFlowContent, self).__init__() - self.input_args_labels = ['input1'] - self.output_ports_labels = ['output1', 'output2'] - self.class_name = 'Demo Node' - self.text = '示例节点' - self.icon_path = '' - self.info = {} - - def process(self, *args) -> List[object]: - print('hello world!!!') - return [] - - def dump(self): - return {'type': self.class_name, 'info': self.info} - - def load_info(self, info: dict): - self.info = info - - def format_text(self) -> str: - return self.text - - -class FlowContentForFunction(PMGBaseFlowContent): - - def __init__(self, node): - super(FlowContentForFunction, self).__init__() - self.node = node - self.node.content = self - self.code: str = None - self.params: List[Union[Tuple, int, float, str]] = [] - self.refresh_func: Callable = None - - self.func: Callable = None - self.input_port_indices: List[List] = [] - self.vars: Dict[str, Union[int, str, float, object]] = {} - - def set_function(self, function_def: str = None, func_name: str = None): - import time - t1 = time.time() - self.code: str = function_def - g = globals() - g.update(self.vars) - exec(self.code, g) - self.func: Callable = globals().get(func_name) - self.refresh_func: Callable = globals().get('refresh') - t2 = time.time() - - def refresh_input_port_indices(self): - input_port_list = [p.get_connected_port()[0] for p in self.node.input_ports if len(p.get_connected_port()) > 0] - self.input_port_indices = [] - try: - for p in input_port_list: - index = p.node.get_port_index(p) - self.input_port_indices.append([p, index]) - except Exception as e: - import traceback - traceback.print_exc() - self.signal_error_occurs.emit( - FlowContentError('Module: %s,Exception:%s' % - (self.node.text, str(e)), traceback.format_exc())) - return - - def get_settings_params(self): - return self.params.copy() - - def update_settings(self, settings_dic: dict): - for i, tup in enumerate(self.params): - param_name = tup[1] - l = list(self.params[i]) - l[3] = settings_dic[param_name] - self.params[i] = tuple(l) - self.vars[param_name] = settings_dic[param_name] - self.node.display_internal_values(self.format_param()) - - def _process(self, input_args: list = None): - if input_args is None: - input_args = [] - try: - for p, index in self.input_port_indices: - val = p.node.content.results[index] - # val = copy.deepcopy(val) - input_args.append(val) - - except Exception as e: - import traceback - traceback.print_exc() - self.signal_error_occurs.emit(FlowContentError('Module:%s,Error:%s' % (self.node.text, e), - traceback.format_exc())) - return - self.input_args = input_args - self.signal_exec_started.emit('started') - if not isinstance(input_args, list): - self.signal_error_occurs.emit(FlowContentError( - 'input list is not instance of list', - 'input list is not instance of list,but of type ' + repr(type(input_args)))) - return None - t1 = time.time() - try: - result = self.process(*input_args) - except: - import traceback - exc = traceback.format_exc() - traceback.print_exc() - self.signal_error_occurs.emit('Module:%s\nInfo:%s' % (self.node.text, exc)) - return None - # self.results = copy.deepcopy(result) - - if isinstance(result, types.GeneratorType): - step = 0 - while 1: - try: - self.results = next(result) - - next_content = self.get_next_content() - # self.signal_exec_finished.emit( - # 'finished\ninput value:%s\noutput value:%s' % (repr(input_list), repr(self.results))) - self.signal_exec_finished.emit('finished') - if next_content is None: - return - else: - next_content._process() - except StopIteration: - return - - self.results = result - next_content = self.get_next_content() - # self.signal_exec_finished.emit( - # 'finished\ninput value:%s\noutput value:%s' % (repr(input_list), repr(self.results))) - self.signal_exec_finished.emit('finished') - if next_content is None: - return - else: - next_content._process() - - def dump(self): - return {'code': self.code, 'type': 'function', 'params': self.params, 'ports_changable': self.ports_changable} - - def format_param(self) -> str: - keys = list(self.vars.keys()) - if len(keys) == 1: - return str(self.vars[keys[0]]) - else: - try: - return json.dumps(self.vars, indent=4) - except: - return str(self.vars) - - def process(self, *args): - assert self.func is not None - globals().update(self.vars) - return self.func(*args) - - def refresh(self): - if callable(self.refresh_func): - try: - self.refresh_func(self) - except: - import traceback - traceback.print_exc() - - -class FlowContentEditableFunction(FlowContentForFunction): - def __init__(self, node, code: str = ''): - super().__init__(node) - self.ports_changable = [True, True] - self.input_args = [] - self.results = [] - self.node: 'Node' = node - self.node.content = self - if code == '': - code = """ -import time -def function(x,y): - return y*2,x+2 - """ - self.code = code - self.set_function(code, 'function') - - def get_settings_params(self) -> List[Union[Tuple, List]]: - return [('text_edit', 'code', 'Input Python Code', self.code, 'python')] - - def update_settings(self, settings_dic: dict): - self.code = settings_dic['code'] - - def process(self, *args): - globals().update({'self': self}) - # exec(self.code, globals()) - # return function(*args) - - return self.func(*args) - - def dump(self): - return {'code': self.code, 'type': 'custom_function'} - - -flowcontent_types = {'function': FlowContentForFunction, - 'custom_function': FlowContentEditableFunction} -if __name__ == '__main__': - def process(): - self = 123455 - code = """ -def function(): - print(123) - """ - loc = locals() - exec(code) - print(loc['function']) - - - process() diff --git a/pyminer/pmgwidgets/flowchart/core/flow_items.py b/pyminer/pmgwidgets/flowchart/core/flow_items.py deleted file mode 100644 index a274c017..00000000 --- a/pyminer/pmgwidgets/flowchart/core/flow_items.py +++ /dev/null @@ -1,685 +0,0 @@ -""" -绘制层次: - -""" -from PySide2.QtCore import QLineF, QPointF, Qt, QRectF, Signal -from PySide2.QtGui import QPolygonF, QPen, QPainterPath, QColor, QPainter, QBrush -from PySide2.QtWidgets import QGraphicsLineItem, QGraphicsItem, QGraphicsSceneMouseEvent, QGraphicsObject, \ - QStyleOptionGraphicsItem, QWidget, QGraphicsSceneHoverEvent, QGraphicsTextItem, QTextEdit - -from typing import TYPE_CHECKING, Tuple, List, Callable, Any - -if TYPE_CHECKING: - from .flowchart_widget import Node, PMGraphicsScene - -COLOR_NORMAL = QColor(212, 227, 242) -COLOR_LINE_NORMAL = QColor(30, 30, 30) -COLOR_HOVER = QColor(255, 200, 00) -COLOR_HOVER_PORT = QColor(0, 0, 50) -COLOR_HOVER_MID_POINT = QColor(0, 0, 200) -COLOR_SELECTED = QColor(255, 255, 0) - - -def round_position(point: QPointF, pixels=5): - x, y = point.x(), point.y() - x_cor, y_cor = round(x * 1.0 / pixels) * pixels, round(y * 1.0 / pixels) * pixels - return QPointF(x_cor, y_cor) - - -class PMGSimpleSignal(): - """ - 简单的信号类 - 此信号类接口类似于Signal,但父类不一定必须继承QObject。可以从其他地方发出,并且起到去耦合的作用。 - """ - - def __init__(self, *object_types): - self.object_types = object_types - self.callbacks = [] - - def connect(self, callback: Callable): - self.callbacks.append(callback) - - def emit(self, *args): - assert len(args) == len(self.object_types), '输入参数长度与定义时不等' - for arg, arg_type in zip(args, self.object_types): - assert isinstance(arg, arg_type), '参数%s类型与定义不同' % repr(arg) - - for cb in self.callbacks: - cb(*args) - - def disconnect(self, callback: Callable): - if callback in self.callbacks: - self.callbacks.remove(callback) - - -class PMGGraphicsLineItem(QGraphicsLineItem): - - def __init__(self, line: QLineF): - super(PMGGraphicsLineItem, self).__init__(line) - - self.signal_hover_enter = PMGSimpleSignal(QGraphicsSceneHoverEvent) - self.signal_hover_leave = PMGSimpleSignal(QGraphicsSceneHoverEvent) - self.signal_mouse_pressd = PMGSimpleSignal(QGraphicsSceneMouseEvent) - self.signal_mouse_doubleclicked = PMGSimpleSignal(QGraphicsSceneMouseEvent, PMGGraphicsLineItem) - self.setAcceptHoverEvents(True) - - def hoverEnterEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: - self.signal_hover_enter.emit(event) - - def hoverLeaveEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: - self.signal_hover_leave.emit(event) - - def mousePressEvent(self, event: 'QGraphicsSceneMouseEvent') -> None: - """ - 这里不能进行继承。一旦进行了继承,似乎会让下面所有的东西都收到信号,从而无法选定。 - :param event: - :return: - """ - super(PMGGraphicsLineItem, self).mousePressEvent(event) - self.signal_mouse_pressd.emit(event) - - def mouseDoubleClickEvent(self, event: 'QGraphicsSceneMouseEvent') -> None: - self.signal_mouse_doubleclicked.emit(event, self) - - def paint(self, QPainter, QStyleOptionGraphicsItem, widget=None): - """ - 屏蔽绘制事件! - Args: - QPainter: - QStyleOptionGraphicsItem: - widget: - - Returns: - - """ - pass - - -class CustomLine(QGraphicsLineItem): - """ - CustomLine不是QObject,没有办法绑定信号,只能用回调函数的方式。 - 之前有重绘事件的回调函数,现已删除,改为鼠标事件触发。 - - 这是一个line,其中起点是start_port,终点end_port,中继点为mid_points中从第1个元素开始依次向前。 - 所以一共有起点+终点+len(mid_points)个节点,从而有len(mid_points)+1个线段。 - - 每一个线段背后都是一个QGraphicsLineItem。为何不是简单绘制?盖因一般的绘制没有办法捕获鼠标事件。 - 如果使用QGraphicsLineItem,那么可以捕获键盘事件。 - - 当点击线段的时候会触发选择事件。首先,线段会调用QGraphicsScene(self.canvas)进行一个清除选择的操作————如果不按ctrl的话。 - 然后设置本身状态为选择。 - - self.canvas.selectedItems()可获取当前被选中的部件。 - - 下一步任务:插入节点、删除节点。 - """ - - def __init__(self, start_port: 'CustomPort', end_port: 'CustomPort', canvas: 'PMGraphicsScene' = None, - mid_points: 'List[CustomMidPoint]' = None): - super(CustomLine, self).__init__() - self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable) # 拖动 - - self._refreshed = False - self.color = COLOR_LINE_NORMAL - self.start_port = start_port - self.end_port = end_port - if self not in start_port.connected_lines: - start_port.connected_lines.append(self) - if self not in end_port.connected_lines: - end_port.connected_lines.append(self) - self.line_items: List['QGraphicsLineItem'] = [] - self.center_points = mid_points if (mid_points is not None) else [] - for p in self.center_points: - canvas.addItem(p) - self.connect_midpoint_signals(p) - p.line = self - canvas.signal_clear_selection.connect(self.on_clear_selection) - self.refresh() - self.canvas = canvas - self.init_line_items() - - def is_selected(self): - return self in self.canvas.selected_items - - def get_opposite_port(self, port: 'CustomPort') -> 'CustomPort': - """ - - :param port:某个端口 - :return: 对面的端口 - """ - if port is self.start_port: - return self.end_port - else: - return self.start_port - - def remove_mid_point(self, mid_point: 'CustomMidPoint'): - """ - 移除中间节点 - :param mid_point: - :return: - """ - index = self.center_points.index(mid_point) - point_to_remove = self.center_points.pop(index) - line_to_remove = self.line_items.pop(index) - self.canvas.removeItem(point_to_remove) - self.canvas.removeItem(line_to_remove) - self.canvas.removeItem(mid_point) - self.refresh_line_items() - self.update() - self.canvas.update_viewport() - - def bind_line_item_signals(self, line_item: 'PMGGraphicsLineItem'): - """ - 绑定线段的信号 - :param line_item: - :return: - """ - line_item.signal_mouse_doubleclicked.connect(self.on_line_item_double_clicked) - line_item.signal_mouse_pressd.connect(self.on_line_item_pressed) - line_item.signal_hover_enter.connect(self.on_line_item_hover_enter) - line_item.signal_hover_leave.connect(self.on_line_item_hover_leave) - - def connect_midpoint_signals(self, mid_point: 'CustomMidPoint'): - mid_point.signal_double_clicked.connect(self.remove_mid_point) - mid_point.point_dragged.connect(self.refresh) - - def add_mid_point(self, line_item: 'PMGGraphicsLineItem', pos: QPointF): - """ - 增加中间节点 - :param line_item: - :param pos: - :return: - """ - index = self.line_items.index(line_item) - new_center_point = CustomMidPoint(pos, line=self) - self.canvas.addItem(new_center_point) - self.center_points.insert(index, new_center_point) - self.connect_midpoint_signals(new_center_point) - if index == 0: - last_pos = self.start_port.center_pos - else: - last_pos = self.center_points[index].center_pos - next_pos = new_center_point.center_pos - new_line_item = PMGGraphicsLineItem(QLineF(last_pos, next_pos)) - - # pen = QPen() - # pen.setColor(self.color) - # pen.setWidth(3) - # new_line_item.setPen(pen) - self.canvas.addItem(new_line_item) - self.line_items.insert(index, new_line_item) - self.bind_line_item_signals(new_line_item) # 绑定中间节点的信号。 - print(len(self.line_items)) - self.refresh_line_items() - self.update() - self.canvas.update_viewport() - - def on_line_item_double_clicked(self, event: 'QGraphicsSceneMouseEvent', line_item: 'PMGGraphicsLineItem'): - - self.add_mid_point(line_item, pos=event.scenePos()) - - def init_line_items(self): - """ - 初始化线段 - :return: - """ - last_pos = self.start_port.center_pos - for p in self.center_points: - pos = p.center_pos - line_item = PMGGraphicsLineItem(QLineF(last_pos, pos)) - self.bind_line_item_signals(line_item) - - pen = QPen() - pen.setColor(self.color) - pen.setWidth(5) - line_item.setPen(pen) - self.canvas.addItem(line_item) - last_pos = pos - self.line_items.append(line_item) - line_item = PMGGraphicsLineItem(QLineF(last_pos, self.end_port.center_pos)) - self.bind_line_item_signals(line_item) - - self.canvas.addItem(line_item) - self.line_items.append(line_item) - - def refresh_line_items(self): - """ - 刷新背后的直线段。 - :return: - """ - last_pos = self.start_port.center_pos - if len(self.line_items) == 0: - return - for i, p in enumerate(self.center_points): - pos = p.center_pos - line = QLineF(last_pos, pos) - self.line_items[i].setLine(line) - last_pos = pos - - line = QLineF(last_pos, self.end_port.center_pos) - self.line_items[-1].setLine(line) - - def on_line_item_hover_enter(self, e: 'QGraphicsSceneHoverEvent'): - self.color = COLOR_HOVER - self.update() - - def on_line_item_hover_leave(self, e: 'QGraphicsSceneHoverEvent'): - if not self.is_selected(): - self.color = COLOR_LINE_NORMAL - self.update() - - def on_line_item_pressed(self, e: 'QGraphicsSceneMouseEvent'): - """ - 当线段被点击时触发的事件。 - :param e: - :return: - """ - if e.button() == Qt.LeftButton: - if not e.modifiers() == Qt.ControlModifier: - self.canvas.signal_clear_selection.emit() - self.canvas.select_item(self) - self.color = COLOR_SELECTED - - def on_clear_selection(self): - """ - 当清除选择时触发的事件。 - :return: - """ - self.color = COLOR_LINE_NORMAL - self.canvas.unselect_item(self) - # self.update() - - def refresh(self): - """ - 当刷新时触发的事件 - :return: - """ - self._refreshed = False - self.refresh_line_items() - self.update() - self._refreshed = True - - def draw_arrow(self, QPainter, point_1: QPointF, point_2: QPointF) -> 'QPolygonF': - """ - 绘制箭头。 - :param QPainter: - :param point_1: - :param point_2: - :return: - """ - - line = QLineF(point_1, point_2) - - v = line.unitVector() - - v.setLength(20) # 改变单位向量的大小,实际就是改变箭头长度 - v.translate(QPointF(int(line.dx() / 2), int(line.dy() / 2))) - - n = v.normalVector() # 法向量 - n.setLength(n.length() * 0.2) # 这里设定箭头的宽度 - n2 = n.normalVector().normalVector() # 两次法向量运算以后,就得到一个反向的法向量 - p1 = v.p2() - p2 = n.p2() - p3 = n2.p2() - # if PYSIDE2: - QPainter.drawPolygon([p1, p2, p3]) - # else: - # QPainter.drawPolygon(p1, p2, p3) - return QPolygonF([p1, p2, p3, p1]) - - def paint(self, q_painter: 'QPainter', style_option_graphics_item: 'QStyleOptionGraphicsItem', - widget: 'QWidget' = None): - - pen = QPen() - pen.setColor(self.color) - pen.setWidth(3) - pen.setJoinStyle(Qt.MiterJoin) # 让箭头变尖 - q_painter.setPen(pen) - - path = QPainterPath() - - point1 = self.start_port - path.moveTo(self.start_port.center_pos) - # for i in self.line_items: - # i.setPen(QColor(255, 0, 0)) - # i.update() - for p in self.center_points + [self.end_port]: - pen.setWidth(3) - q_painter.setPen(pen) - path.lineTo(p.center_pos) - q_painter.drawLine(QLineF(point1.center_pos, p.center_pos)) - arrow = self.draw_arrow(q_painter, point1.center_pos, p.center_pos) - path.addPolygon(arrow) # 将箭头添加到连线上 - point1 = p - - def get_central_points_positions(self): - """ - 获取所有中间节点的位置。 - :return: - """ - positions = [] - for point in self.center_points: - positions.append((point.x(), point.y())) - return positions - - def hoverEnterEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: - """ - 悬浮事件进入所触发的事件。 - :param event: - :return: - """ - self.color = COLOR_HOVER_PORT - - self.update() - - def on_delete(self): - """ - 删除线对象 - 首先从起始和结束的端口的连线中删除这个线; - 然后,从画布上移除自身所有的中间线段对象和中继点对象 - 从画布上删除自身; - 从所有连线的列表中移除自身。 - :return: - """ - try: - self.start_port.connected_lines.remove(self) - except ValueError: - import traceback - traceback.print_exc() - try: - self.end_port.connected_lines.remove(self) - except ValueError: - import traceback - traceback.print_exc() - for line_item in self.line_items: - self.canvas.removeItem(line_item) - for mid_item in self.center_points: - self.canvas.removeItem(mid_item) - self.canvas.removeItem(self) - self.canvas.lines.remove(self) - - -class CustomMidPoint(QGraphicsObject): - point_dragged = Signal(QGraphicsObject) - signal_double_clicked = Signal(object) - - def __init__(self, pos: QPointF = None, line: 'CustomLine' = None): - super(CustomMidPoint, self).__init__() - self.setAcceptHoverEvents(True) # 接受鼠标悬停事件 - self.relative_pos = (0, 0) - self.color = COLOR_NORMAL - self.size = (10, 10) - if pos is not None: - self.setPos(pos) - self.line = line - self.setZValue(1.0) # 设置层次。 - - def boundingRect(self): - return QRectF(0, 0, self.size[0], self.size[1]) - - @property - def center_pos(self): - return QPointF(self.x() + self.size[0] / 2, self.y() + self.size[1] / 2) - - def mouseMoveEvent(self, event: 'QGraphicsSceneMouseEvent') -> None: - """ - 鼠标拖动时触发的事件。 - :param event: - :return: - """ - mouse_x, mouse_y = event.scenePos().x(), event.scenePos().y() - self.setPos(round_position(QPointF(mouse_x, mouse_y))) - self.point_dragged.emit(self) - - def paint(self, painter, styles, widget=None): - pen1 = QPen(Qt.SolidLine) - pen1.setColor(self.color) - painter.setPen(pen1) - - brush1 = QBrush(Qt.SolidPattern) - brush1.setColor(self.color) - painter.setBrush(brush1) - - painter.setRenderHint(QPainter.Antialiasing) # 反锯齿 - painter.drawRoundedRect(self.boundingRect(), 10, 10) - - def hoverEnterEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: - self.color = COLOR_HOVER_MID_POINT - self.update() - - def hoverLeaveEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: - self.color = COLOR_NORMAL - self.update() - - def mousePressEvent(self, evt: QGraphicsSceneMouseEvent): - if evt.button() == Qt.LeftButton: - pos = (evt.scenePos().x(), evt.scenePos().y()) - self.relative_pos = (pos[0] - self.x(), pos[1] - self.y()) - - elif evt.button() == Qt.RightButton: - pass - elif evt.button() == Qt.MidButton: - pass - - def paintEvent(self, QPaintEvent): - pen1 = QPen() - pen1.setColor(QColor(166, 66, 250)) - painter = QPainter(self) - painter.setPen(pen1) - painter.begin(self) - painter.drawRoundedRect(self.boundingRect(), 10, 10) # 绘制函数 - painter.end() - - def mouseDoubleClickEvent(self, event: 'QGraphicsSceneMouseEvent') -> None: - self.signal_double_clicked.emit(self) - # self.line.remove_mid_point(self) - - -class CustomPort(QGraphicsObject): - port_clicked = Signal(QGraphicsObject) - - def __init__(self, port_id: str, text: str = 'port', content: Any = None, port_type='input'): - super(CustomPort, self).__init__() - self.setAcceptHoverEvents(True) # 接受鼠标悬停事件 - self.relative_pos = (0, 0) - self.color = COLOR_NORMAL - self.id = port_id - self.text = text - self.size = (10, 10) - self.content = content - self.connected_lines = [] - self.canvas = None - self.node: 'Node' = None - - self.text_item = QGraphicsTextItem(parent=self) - self.port_type = port_type - if port_type == 'input': - self.text_item.setPos(10, -5) - else: - self.text_item.setPos(-30, -5) - self.text_item.setPlainText(self.text) - - def set_text(self, text: str): - self.text_item.setPlainText(text) - self.text = text - - def boundingRect(self): - return QRectF(0, 0, self.size[0], self.size[1]) - - @property - def center_pos(self): - return QPointF(self.x() + self.size[0] / 2, self.y() + self.size[1] / 2) - - def paint(self, painter, styles, widget=None): - pen1 = QPen(Qt.SolidLine) - pen1.setColor(QColor(128, 128, 128)) - painter.setPen(pen1) - - brush1 = QBrush(Qt.SolidPattern) - brush1.setColor(self.color) - painter.setBrush(brush1) - - painter.setRenderHint(QPainter.Antialiasing) # 反锯齿 - painter.drawRoundedRect(self.boundingRect(), 10, 10) - - def hoverEnterEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: - self.color = COLOR_HOVER_PORT - self.update() - - def hoverLeaveEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: - self.color = COLOR_NORMAL - self.update() - - def mousePressEvent(self, evt: QGraphicsSceneMouseEvent): - if evt.button() == Qt.LeftButton: - pos = (evt.scenePos().x(), evt.scenePos().y()) - self.relative_pos = (pos[0] - self.x(), pos[1] - self.y()) - self.port_clicked.emit(self) - elif evt.button() == Qt.RightButton: - pass - elif evt.button() == Qt.MidButton: - pass - - def paintEvent(self, paint_event): - pen1 = QPen() - pen1.setColor(QColor(166, 66, 250)) - painter = QPainter(self) - painter.setPen(pen1) - painter.begin(self) - painter.drawRoundedRect(self.boundingRect(), 10, 10) # 绘制函数 - painter.end() - - def get_pos(self) -> Tuple[int, int]: - pos = self.pos() - return pos.x(), pos.y() - - def get_connected_lines(self) -> List['CustomLine']: - if len(self.connected_lines) == 0: - return [] - else: - return self.connected_lines - - def get_connected_port(self) -> List['CustomPort']: - """ - 获取连接的节点 - :return: - """ - lines = self.get_connected_lines() - if len(lines) == 0: - return [] - port_list = [] - for l in lines: - port_list.append(l.get_opposite_port(self)) - return port_list - - def on_delete(self): - for line in self.connected_lines: - line.on_delete() - self.scene().removeItem(self) - - def parse_id(self) -> Tuple[str, str, str]: - """ - 解析id。id由三个元素构成,由冒号分割。 - 如3:input:2,意思就是id3为3的节点中,id为2的输入端口。注意 - :return: - """ - node_id, type, port_id = self.id.split(':') - return node_id, type, port_id - - def __repr__(self): - return super(CustomPort, self).__repr__() + 'id = ' + str(self.id) - - -class CustomRect(QGraphicsItem): - def __init__(self, node: 'Node' = None): - super(CustomRect, self).__init__() - self.setFlags(QGraphicsItem.ItemIsSelectable) # 只有设置了可以选取才能被选中。 - self.setAcceptHoverEvents(True) # 接受鼠标悬停事件 - self.relative_pos = (0, 0) - self.color = COLOR_NORMAL - self.node = node - - def boundingRect(self): - return QRectF(0, 0, 120, 120) - - def paint(self, painter, styles, widget=None): - pen1 = QPen(Qt.SolidLine) - pen1.setColor(QColor(128, 128, 128)) - painter.setPen(pen1) - - brush1 = QBrush(Qt.SolidPattern) - brush1.setColor(self.color) - painter.setBrush(brush1) - - painter.setRenderHint(QPainter.Antialiasing) # 反锯齿 - painter.drawRoundedRect(self.boundingRect(), 10, 10) - - def hoverEnterEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: - self.color = COLOR_HOVER - self.update() - - def hoverLeaveEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: - self.color = COLOR_NORMAL - if self.isSelected(): - self.color = COLOR_SELECTED - self.update() - - def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None: - self.setPos(round_position( - QPointF(event.scenePos().x() - self.relative_pos[0], - event.scenePos().y() - self.relative_pos[1]))) - self.node.refresh_pos() - - def mouseDoubleClickEvent(self, event: 'QGraphicsSceneMouseEvent') -> None: - """ - [!TODO]整理这里的代码,节点编辑这一块的代码非常乱! - :param event: - :return: - """ - self.on_value_show_requested() - # self.on_edit_properties_requested() - - def on_value_show_requested(self): - from PySide2.QtWidgets import QDialog, QVBoxLayout - val_dlg = QDialog() - val_dlg.setLayout(QVBoxLayout()) - text_show = QTextEdit() - text = 'inputs:\n' + repr(self.node.content.input_args) + '\n' + 'results:\n' + repr(self.node.content.results) - text_show.setText(text) - val_dlg.layout().addWidget(text_show) - val_dlg.exec_() - - def mousePressEvent(self, evt: QGraphicsSceneMouseEvent): - if evt.button() == Qt.LeftButton: - pos = (evt.scenePos().x(), evt.scenePos().y()) - self.relative_pos = (pos[0] - self.x(), pos[1] - self.y()) - if not evt.modifiers() == Qt.ControlModifier: - self.scene().signal_clear_selection.emit() - self.scene().select_item(self) - self.color = COLOR_SELECTED - elif evt.button() == Qt.RightButton: - pass - elif evt.button() == Qt.MidButton: - pass - - def paintEvent(self, paintEvent): - pen1 = QPen() - pen1.setColor(self.color) - painter = QPainter(self) - painter.setPen(pen1) - painter.begin(self) - painter.drawRoundedRect(self.boundingRect(), 10, 10) # 绘制函数 - painter.end() - - def on_clear_selection(self): - """ - 当清除选择时触发的事件。 - :return: - """ - self.color = COLOR_NORMAL - if self.scene() is not None: - self.scene().unselect_item(self) - - def on_delete(self): - self.node.on_delete() - pass diff --git a/pyminer/pmgwidgets/flowchart/core/flow_node.py b/pyminer/pmgwidgets/flowchart/core/flow_node.py deleted file mode 100644 index 086c8877..00000000 --- a/pyminer/pmgwidgets/flowchart/core/flow_node.py +++ /dev/null @@ -1,438 +0,0 @@ -import os -import sys -from typing import Tuple, List, Dict, Union, TYPE_CHECKING, Callable -import json -from PySide2.QtWidgets import QGraphicsTextItem, QGraphicsPixmapItem, QMessageBox -from PySide2.QtCore import QObject, QPointF -from PySide2.QtGui import QPixmap - -from pmgwidgets.flowchart.core.flow_items import CustomRect, CustomPort -from pmgwidgets import get_parent_path, assert_in - -if TYPE_CHECKING: - from pmgwidgets.flowchart.core.flowchart_widget import PMGraphicsScene, PMFlowWidget -from pmgwidgets.flowchart.core.flow_content import FlowContentEditableFunction, FlowContentForFunction, FlowContentError -from pmgwidgets.flowchart.nodes.docparser import parse_doc - - -class Node(QObject): - """ - Node是一个节点的抽象 - """ - - def __init__(self, canvas: 'PMGraphicsScene', node_id, text: str = '', input_ports: List[CustomPort] = None, - output_ports: List[CustomPort] = None, icon_path=r'', look: Dict[str, str] = None): - super(Node, self).__init__() - assert isinstance(look, dict) - self.look = look - direction = self.look.get('direction') - self.direction = 'E' if direction is None else direction # 输出端口的方向 - assert_in(self.direction, ['E', 'W']) - self.look['direction'] = self.direction - - self.id = node_id - self.text = text if text != '' else node_id - self.base_rect = CustomRect(self) - - icon_path = os.path.join(get_parent_path(__file__), 'icons', 'logo.png') if icon_path == '' else icon_path - self.icon_path = icon_path - pix_map = QPixmap(icon_path) - self.pix_map_item = QGraphicsPixmapItem(pix_map, parent=self.base_rect) - self.pix_map_item.setPos(20, 20) - - self.text_item = QGraphicsTextItem(parent=self.base_rect) - - start_left = 50 - self.text_item.setPos(start_left, 10) - self.text_item.setPlainText(self.text) - - self.internal_value_text = QGraphicsTextItem(parent=self.base_rect) - self.internal_value_text.setPos(start_left, 30) - self.internal_value_text.setPlainText('') - - self.status_text = QGraphicsTextItem(parent=self.base_rect) - self.status_text.setPos(start_left, 100) - self.status_text.setPlainText('wait') - - self.input_ports = input_ports - self.output_ports = output_ports - - self.input_ports_dic = {p.id: p for p in input_ports} - self.output_ports_dic = {p.id: p for p in output_ports} - self.canvas = canvas - # self.set_content(content) - self.setup() - - def display_internal_values(self, val_str: str = ''): - self.internal_value_text.setPlainText(val_str) - - def set_content(self, content: 'FlowContentEditableFunction' = None): - self.content: 'FlowContentEditableFunction' = content if content is not None else FlowContentEditableFunction( - self, '') - self.content.signal_exec_finished.connect(self.on_exec_finished) - self.content.signal_exec_started.connect(self.on_exec_started) - self.content.signal_error_occurs.connect(self.on_error_occurs) - self.display_internal_values(self.content.format_param()) - - def on_error_occurs(self, error: FlowContentError): - flow_widget: PMFlowWidget = self.canvas.flow_widget - flow_widget.on_error_occurs(error) - - def on_exec_started(self, content): - """ - 执行前进行的操作 - :param content: - :return: - """ - self.status_text.setPlainText(content) - - def on_exec_finished(self, content: str): - """ - 执行完成后进行的操作 - :param content: - :return: - """ - self.status_text.setPlainText(content) - - # - def reset(self): - self.status_text.setPlainText('wait') - - def get_port_index(self, port: CustomPort): - """ - 获取端口的索引 - :param port: - :return: - """ - return self.input_ports.index(port) if port.port_type == 'input' else self.output_ports.index(port) - - def set_icon(self, icon_path: str): - pass - - def set_pos(self, x: int, y: int): - """ - 设置位置,左上角角点 - :param x: - :param y: - :return: - """ - self.base_rect.setPos(x, y) - self.refresh_pos() - - def get_pos(self) -> Tuple[int, int]: - """ - 获取位置,左上角角点 - :return: - """ - pos = self.base_rect.pos() - return pos.x(), pos.y() - - def refresh_pos(self): - """ - 刷新位置。当节点被拖动的时候,此方法会被触发。 - """ - y = self.base_rect.y() - dy_input = self.base_rect.boundingRect().height() / (1 + len(self.input_ports)) - dy_output = self.base_rect.boundingRect().height() / (1 + len(self.output_ports)) - if self.direction == 'E': - x_input = self.base_rect.x() + 5 - x_output = self.base_rect.x() + self.base_rect.boundingRect().width() - 15 - elif self.direction == 'W': - x_input = self.base_rect.x() + self.base_rect.boundingRect().width() - 15 - x_output = self.base_rect.x() + 5 - else: - raise NotImplementedError - for i, p in enumerate(self.input_ports): - p.setPos(QPointF(x_input, y + int(dy_input * (1 + i)))) - for i, p in enumerate(self.output_ports): - p.setPos(QPointF(x_output, y + int(dy_output * (1 + i)))) - self.canvas.signal_item_dragged.emit('') - - def setup(self): - self.base_rect.setPos(80, 80) - self.canvas.signal_clear_selection.connect(self.base_rect.on_clear_selection) - self.canvas.addItem(self.base_rect) - for p in self.input_ports + self.output_ports: - self.canvas.addItem(p) - p.port_clicked.connect(self.on_port_clicked) - p.node = self - self.refresh_pos() - - def on_port_clicked(self, port: 'CustomPort'): - - if self.canvas.drawing_lines: - if self.canvas.line_start_port is not port: - if not port.port_type == self.canvas.line_start_port.port_type: - if self.canvas.allow_multiple_input or ( - (not self.canvas.allow_multiple_input) and len(port.connected_lines) == 0): - self.canvas.connect_port(port) - - else: - if port.port_type == 'output': - self.canvas.drawing_lines = True - # if self.canvas.item - - self.canvas.line_start_point = port.center_pos - self.canvas.line_start_port = port - - def on_delete(self): - for port in self.input_ports + self.output_ports: - port.canvas = self.canvas - port.on_delete() - self.canvas.removeItem(self.base_rect) - self.canvas.nodes.remove(self) - self.deleteLater() - - def __repr__(self): - s = super(Node, self).__repr__() - return s + repr(self.input_ports) + repr(self.output_ports) - - def get_port(self, port_id: str) -> 'CustomPort': - for port in self.input_ports + self.output_ports: - if port_id == port.id: - return port - return None - - def add_port(self, port: CustomPort): - """ - 添加一个端口 - :param port: - :return: - """ - - port_type = port.port_type - if port_type == 'input': - self.input_ports.append(port) - self.input_ports_dic[port.id] = port - elif port_type == 'output': - self.output_ports.append(port) - self.output_ports_dic[port.id] = port - else: - raise ValueError('port type invalid') - if port.node is None: - port.node = self - self.refresh_pos() - self.canvas.addItem(port) - port.port_clicked.connect(self.on_port_clicked) - - return port - - def remove_port(self, port: CustomPort): - """ - 删除一个端口 - :param port: - :return: - """ - - port_type = port.port_type - if port_type == 'input': - self.input_ports.remove(port) - self.input_ports_dic.pop(port.id) - elif port_type == 'output': - self.output_ports.remove(port) - self.output_ports_dic.pop(port.id) - else: - raise ValueError('port type invalid') - - port.on_delete() - self.refresh_pos() - - def change_property(self, property: Dict[str, Union[int, str]]): - """ - 改变各个端口的文字、端口的数目以及文字。 - :param property: - :return: - """ - self.text = property['text'] - self.text_item.setPlainText(self.text) - self.content.update_settings(property) - self.valid_port_ids = [] - if property.get('inputs') is not None: - for input_id, input_text in zip(property['inputs'][0], property['inputs'][1]): - self.valid_port_ids.append(input_id) - p = self.get_port(input_id) - if p is None: - p = self.add_port(CustomPort(port_id=input_id, text=input_text, port_type='input')) - p.set_text(input_text) - for p in self.input_ports: - if p.id not in self.valid_port_ids: - self.remove_port(p) - - if property.get('outputs') is not None: - for output_id, output_text in zip(property['outputs'][0], property['outputs'][1]): - self.valid_port_ids.append(output_id) - p = self.get_port(output_id) - if p is None: - p = self.add_port(CustomPort(port_id=output_id, text=output_text, port_type='output')) - p.set_text(output_text) - - for p in self.output_ports: - if p.id not in self.valid_port_ids: - self.remove_port(p) - - def change_ports_property(self, property: Dict[str, Union[int, str]]): - """ - 改变各个端口的文字、端口的数目以及文字。 - :param property: - :return: - """ - self.text = property['text'] - self.text_item.setPlainText(self.text) - self.valid_port_ids = [] - if property.get('inputs') is not None: - for input_id, input_text in zip(property['inputs'][0], property['inputs'][1]): - self.valid_port_ids.append(input_id) - p = self.get_port(input_id) - if p is None: - p = self.add_port(CustomPort(port_id=input_id, text=input_text, port_type='input')) - p.set_text(input_text) - for p in self.input_ports: - if p.id not in self.valid_port_ids: - self.remove_port(p) - - if property.get('outputs') is not None: - for output_id, output_text in zip(property['outputs'][0], property['outputs'][1]): - self.valid_port_ids.append(output_id) - p = self.get_port(output_id) - if p is None: - p = self.add_port(CustomPort(port_id=output_id, text=output_text, port_type='output')) - p.set_text(output_text) - - for p in self.output_ports: - if p.id not in self.valid_port_ids: - self.remove_port(p) - - def on_edit_ports(self): - from pmgwidgets import PMGPanel - from PySide2.QtWidgets import QDialog, QVBoxLayout - dlg = QDialog(self.base_rect.scene().flow_widget) - sp = PMGPanel() - p: 'CustomPort' = None - input_ids, output_ids = [], [] - input_texts, output_texts = [], [] - self._last_var = 0 - - def new_id_input(): - node_id = self.id - max_val = 0 - for p in self.input_ports: - n, t, p = p.parse_id() - if max_val < int(p): - max_val = int(p) - self._last_var += 1 - return '%s:input:%d' % (node_id, max_val + self._last_var) - - def new_id_output(): - node_id = self.id - max_val = 0 - for p in self.output_ports: - n, t, p = p.parse_id() - if max_val < int(p): - max_val = int(p) - self._last_var += 1 - return '%s:output:%d' % (node_id, max_val + self._last_var) - - for p in self.input_ports: - input_ids.append(p.id) - input_texts.append(p.text) - - for p in self.output_ports: - output_ids.append(p.id) - output_texts.append(p.text) - - views = [] - # views += self.content.get_settings_params() - views += [('line_ctrl', 'text', 'Node Text', self.text), - ] - if self.content.ports_changable[0]: - views.append(('list_ctrl', 'inputs', 'Set Inputs', [input_ids, input_texts], new_id_input)) - if self.content.ports_changable[1]: - views.append(('list_ctrl', 'outputs', 'Set Outputs', [output_ids, output_texts], new_id_output)) - sp.set_items(views) - dlg.setLayout(QVBoxLayout()) - dlg.layout().addWidget(sp) - dlg.exec_() - - dic = sp.get_value() - self.change_ports_property(dic) - - def on_edit_properties_requested(self): - """ - Show Settings Panel. - If It was customized node,it will call the function of the content. - Or the default settings parameters will be got. - Returns: - - """ - from pmgwidgets import PMGPanel - from PySide2.QtWidgets import QDialog, QVBoxLayout - - if isinstance(self.content, FlowContentForFunction): - dlg = QDialog(self.base_rect.scene().flow_widget) - sp = PMGPanel() - p: 'CustomPort' = None - input_ids, output_ids = [], [] - input_texts, output_texts = [], [] - self._last_var = 0 - - def new_id_input(): - node_id = self.id - max_val = 0 - for p in self.input_ports: - n, t, p = p.parse_id() - if max_val < int(p): - max_val = int(p) - self._last_var += 1 - return '%s:input:%d' % (node_id, max_val + self._last_var) - - def new_id_output(): - node_id = self.id - max_val = 0 - for p in self.output_ports: - n, t, p = p.parse_id() - if max_val < int(p): - max_val = int(p) - self._last_var += 1 - return '%s:output:%d' % (node_id, max_val + self._last_var) - - for p in self.input_ports: - input_ids.append(p.id) - input_texts.append(p.text) - - for p in self.output_ports: - output_ids.append(p.id) - output_texts.append(p.text) - - views = [] - views += self.content.get_settings_params() - views += [('line_ctrl', 'text', 'Node Text', self.text), - ] - if self.content.ports_changable[0]: - views.append(('list_ctrl', 'inputs', 'Set Inputs', [input_ids, input_texts], new_id_input)) - if self.content.ports_changable[1]: - views.append(('list_ctrl', 'outputs', 'Set Outputs', [output_ids, output_texts], new_id_output)) - sp.set_items(views) - dlg.setLayout(QVBoxLayout()) - dlg.layout().addWidget(sp) - dlg.exec_() - - dic = sp.get_value() - self.change_property(dic) - else: - try: - self.content.settings_window_requested(self.canvas.flow_widget) - except Exception as e: - import traceback - exc = traceback.format_exc() - print(exc) - QMessageBox.warning(self.canvas.flow_widget, 'Error', str(e)) - - def invert(self): - self.direction = 'W' if self.direction == 'E' else 'E' - self.refresh_pos() - self.look['direction'] = self.direction - - -def make_calculation_node(node_function: Callable) -> 'Node': - info = parse_doc(node_function) - content = FlowContentEditableFunction(code=0) diff --git a/pyminer/pmgwidgets/flowchart/core/flowchart_scene.py b/pyminer/pmgwidgets/flowchart/core/flowchart_scene.py deleted file mode 100644 index fe408083..00000000 --- a/pyminer/pmgwidgets/flowchart/core/flowchart_scene.py +++ /dev/null @@ -1,368 +0,0 @@ -""" -node properties: -id:str -text:str -icon:str(path of icon) -ports:{} -content:{} - -properties of contents: -code:str -type:str -params:List[str] -""" -import json -import logging -import os -import time -from typing import List, Dict, TYPE_CHECKING - -if TYPE_CHECKING: - from pmgwidgets import PMGFlowContent -from pmgwidgets.flowchart.core.flow_content import FlowContentForFunction, flowcontent_types -from pmgwidgets.flowchart.core.flow_items import CustomPort, CustomLine, CustomMidPoint, CustomRect -from pmgwidgets.flowchart.core.flow_node import Node -from pmgwidgets.utilities.uilogics.undomanager import UndoManager -from PySide2.QtCore import QLineF, Qt, QPointF, Signal -from PySide2.QtGui import QPen, QColor, QKeyEvent -from PySide2.QtWidgets import QGraphicsView, \ - QGraphicsScene, QGraphicsSceneMouseEvent, QMenu, QGraphicsSceneContextMenuEvent - -logger = logging.getLogger(__name__) -COLOR_NORMAL = QColor(212, 227, 242) -COLOR_HOVER = QColor(255, 200, 00) -COLOR_HOVER_PORT = QColor(0, 0, 50) - - -class PMGraphicsScene(QGraphicsScene): - signal_item_dragged = Signal(str) # 拖拽控件发生的事件。 - signal_port_clicked = Signal(str) # 点击端口的事件 - signal_clear_selection = Signal() # 清除选择的事件 - - def __init__(self, parent=None, graphics_view: 'QGraphicsView' = None, flow_widget: 'PMFlowWidget' = None, - allow_multiple_input=False): - super().__init__(parent) - self.undo_manager = UndoManager() - self.call_id_list: List = [] - self.lines: List[CustomLine] = [] - self.nodes: List['Node'] = [] - self.selected_items = [] - self.drawing_lines = False - self.line_start_port = None - self.line_start_point = None - self.line_end_port = None - self.node_index_to_execute = 0 - self.line = self.addLine(0, 0, 1, 1, QPen()) - self.graphics_view = graphics_view - self.flow_widget: 'PMFlowWidget' = flow_widget - self.allow_multiple_input = allow_multiple_input - - def contextMenuEvent(self, event: 'QGraphicsSceneContextMenuEvent') -> None: - super(PMGraphicsScene, self).contextMenuEvent(event) - self.menu = QMenu() - node = self.get_rect_under_mouse().node - - self.menu.addAction('Delete Selected').triggered.connect(lambda x: self.delete_selected_item()) - print(node) - if node is not None: - self.menu.addAction('Invert').triggered.connect(lambda x: self.invert_node(node)) - base_rect = self.get_rect_under_mouse() - if base_rect is not None: - self.menu.addAction('Edit').triggered.connect(lambda x: base_rect.node.on_edit_properties_requested()) - self.menu.addAction('Edit Ports').triggered.connect(lambda x: base_rect.node.on_edit_ports()) - self.menu.exec_(event.screenPos()) - - def keyPressEvent(self, event: 'QKeyEvent') -> None: - if event.key() == Qt.Key_Delete: - self.delete_selected_item() - elif event.key() == Qt.Key_Escape: - if self.drawing_lines: - self.drawing_lines = False - self.line.hide() - - def mouseReleaseEvent(self, event: 'QGraphicsSceneMouseEvent') -> None: - super().mouseReleaseEvent(event) - self.update_viewport() - - def mouseMoveEvent(self, event: 'QGraphicsSceneMouseEvent') -> None: - super(PMGraphicsScene, self).mouseMoveEvent(event) - if self.drawing_lines: - self.line.show() - self.line_end_point = event.scenePos() - self.line.setLine(QLineF(self.line_end_point, self.line_start_point)) - self.sceneRect() - self.update_viewport() - - def connect_port(self, end_port): - self.line.hide() - line = CustomLine(self.line_start_port, end_port, self) - self.lines.append(line) - self.addItem(line) - self.signal_item_dragged.connect(line.refresh) - self.drawing_lines = False - self.add_stat() - - def find_port(self, port_id: int): - for n in self.nodes: - for p in n.input_ports + n.output_ports: - if p.id == port_id: - return p - return None - - def find_node(self, node_id: str) -> Node: - for n in self.nodes: - if n.id == node_id: - return n - return None - - def new_id(self) -> str: - max_id = 0 - for n in self.nodes: - a = int(n.id) - if a > max_id: - max_id = a - new_id = max_id + 1 - return str(new_id) - - def add_node(self, node: 'Node' = None): - """ - 添加节点 - Args: - node: - - Returns: - - """ - assert isinstance(node, Node) - - self.nodes.append(node) - self.add_stat() - - def get_rect_under_mouse(self) -> CustomRect: - # items =[] - for n in self.nodes: - if n.base_rect.isUnderMouse(): - return n.base_rect - return None - - def get_selected_base_rects(self) -> List[CustomRect]: - items = [] - for selected_item in self.selected_items: - print(self.selected_items) - if isinstance(selected_item, CustomRect): - items.append(selected_item) - return items - - def invert_node(self, node: Node): - if node is not None: - node.invert() - self.update_viewport() - - def delete_selected_item(self): - """ - 删除被选中的物品 - :return: - """ - self.add_stat() - for selected_item in self.selected_items: - if hasattr(selected_item, 'on_delete'): - selected_item.on_delete() - self.selected_items = [] - - def unselect_item(self, item): - if item in self.selected_items: - self.selected_items.remove(item) - - def select_item(self, item): - if item not in self.selected_items: - self.selected_items.append(item) - - def topo_sort(self, draw_graph=False): - """ - 拓扑排序 - :return: - """ - lines = [] - for l in self.lines: - start_id, end_id = l.start_port.node.id, l.end_port.node.id - lines.append((start_id, end_id)) - import networkx - - DG = networkx.DiGraph(lines) - if draw_graph: - networkx.draw_spring(DG, with_labels=True) - import matplotlib.pyplot as plt - plt.show() - return list(networkx.topological_sort(DG)) - - def load_flowchart(self, path=''): - - file = './examples/flowchart_stat_demo.json' if path == '' else path - if not os.path.exists(file): - return - - with open(file, 'r') as f: - text = f.read() - self.flowchart_from_json(text) - - def add_stat(self): - self.undo_manager.push(self.flowchart_to_json()) - - def undo(self): - """ - 重做 - :return: - """ - result = self.undo_manager.undo() - print('undo', result) - if result is not None: - self.reset_stat(result) - - def redo(self): - """ - 撤销 - :return: - """ - result = self.undo_manager.redo() - print(result) - if result is not None: - self.reset_stat(result) - - def dump_flowchart(self, path=''): - t0 = time.time() - file = './examples/flowchart_stat_demo.json' if path == '' else path - json_str = self.flowchart_to_json() - with open(file, 'w') as f: - f.write(json_str) - t1 = time.time() - print('time elapsed for dumping flowchart', t1 - t0) - - def flowchart_from_json(self, json_str): - t0 = time.time() - fc_info_dic: Dict[str, Dict] = json.loads(json_str) - nodes_dic = fc_info_dic['nodes'] - connections: List = fc_info_dic['connections'] - - for k in nodes_dic.keys(): - node_property = nodes_dic[k] - node_name = node_property['id'] - node_pos = node_property['pos'] - node_text = node_property['text'] - node_icon_path = node_property['icon'] - node_content = node_property['content'] - node_look = node_property.get('look') - node_look = node_look if node_look is not None else {} - input_ports = [] - for input_port_id in node_property['input_ports'].keys(): - port_property = node_property['input_ports'][input_port_id] - port = CustomPort(port_id=input_port_id, text=port_property['text'], content=port_property['contents'], - port_type='input') - input_ports.append(port) - output_ports = [] - for output_port_id in node_property['output_ports'].keys(): - port_property = node_property['output_ports'][output_port_id] - port = CustomPort(port_id=output_port_id, text=port_property['text'], content=port_property['contents'], - port_type='output') - output_ports.append(port) - - node = Node(self, node_name, text=node_text, input_ports=input_ports, output_ports=output_ports, - icon_path=node_icon_path, look=node_look) - content_type = flowcontent_types.get(node_content.get('type')) - if content_type is not None: - content: 'FlowContentForFunction' = content_type(node=node) - code = node_content['code'] - content.set_function(code, 'function') - params = node_content.get('params') - content.set_params([] if params is None else params) - ports_changable = node_content.get('ports_changable') - ports_changable = ports_changable if ports_changable is not None else [False, False] - content.ports_changable = ports_changable - else: - content: 'PMGFlowContent' = self.flow_widget.node_manager.content_classes.get( - node_content.get('type'))() - content.node = node - content.class_name = node_content.get('type') - content.load_info(node_content.get('info')) - node.set_content(content) - node.set_pos(*node_pos) - self.nodes.append(node) - for line_property in connections: - start_id, end_id = line_property['start_id'], line_property['end_id'] - start_port, end_port = self.find_port(start_id), self.find_port(end_id) - mid_positions = line_property['mid_positions'] - mid_points = [] - for pos in mid_positions: - mid_points.append(CustomMidPoint(pos=QPointF(*pos))) - - line = CustomLine(canvas=self, start_port=start_port, end_port=end_port, mid_points=mid_points) - self.addItem(line) - self.signal_item_dragged.connect(line.refresh) - self.lines.append(line) - t1 = time.time() - print('time elapsed for loading flowchart:', t1 - t0) - # self.add_stat() - - def reset_status(self): - self.drawing_lines = False - self.nodes = [] - self.lines = [] - self.selected_items = [] - self.clear() - self.line_start_port = None - self.line_start_point = None - self.line_end_port = None - self.node_index_to_execute = 0 - self.line = self.addLine(0, 0, 1, 1, QPen()) - - def reset_stat(self, json_str: str): - self.reset_status() - self.flowchart_from_json(json_str) - - def flowchart_to_json(self) -> str: - fc_info = {} - connections = [] - nodes_dic = {} - fc_info['nodes'] = nodes_dic - fc_info['connections'] = connections - for line in self.lines: - line_properties = {} - start_id = line.start_port.id - end_id = line.end_port.id - line_properties['start_id'] = start_id - line_properties['end_id'] = end_id - mid_positions = line.get_central_points_positions() - line_properties['mid_positions'] = mid_positions - connections.append(line_properties) - for node in self.nodes: - node_properties = {} - node_properties['text'] = node.text - node_properties['id'] = node.id - node_properties['pos'] = node.get_pos() - node_properties['icon'] = node.icon_path - node_properties['content'] = node.content.dump() - node_properties['look'] = node.look - input_ports_dic = {} - output_ports_dic = {} - for port in node.input_ports: - input_ports_dic[port.id] = {'id': port.id, 'pos': port.get_pos(), 'contents': {}, 'text': port.text} - for port in node.output_ports: - output_ports_dic[port.id] = {'id': port.id, 'pos': port.get_pos(), 'contents': {}, 'text': port.text} - node_properties['input_ports'] = input_ports_dic - node_properties['output_ports'] = output_ports_dic - nodes_dic[node.id] = node_properties - return json.dumps(fc_info, indent=4) - - def reset(self): - self.clear() - self.call_id_list: List = [] - self.lines: List[CustomLine] = [] - self.nodes: List['Node'] = [] - self.drawing_lines = False - self.line_start_port = None - self.line_start_point = None - self.line_end_port = None - self.node_index_to_execute = 0 - self.line = self.addLine(0, 0, 1, 1, QPen()) - - def update_viewport(self): - self.graphics_view.viewport().update() diff --git a/pyminer/pmgwidgets/flowchart/core/flowchart_widget.py b/pyminer/pmgwidgets/flowchart/core/flowchart_widget.py deleted file mode 100644 index d4329b66..00000000 --- a/pyminer/pmgwidgets/flowchart/core/flowchart_widget.py +++ /dev/null @@ -1,250 +0,0 @@ -""" -node properties: -id:str -text:str -icon:str(path of icon) -ports:{} -content:{} - -properties of contents: -code:str -type:str -params:List[str] -""" -import json -import os -import sys -import time -from typing import List, Dict - -from pmgwidgets.flowchart.core.flow_content import FlowContentForFunction, flowcontent_types, PMGFlowContent, \ - FlowContentError - -from pmgwidgets.flowchart.core.flow_node import Node -from pmgwidgets.flowchart.core.nodemanager import NodeManagerWidget -from pmgwidgets.flowchart.core.flowchart_scene import PMGraphicsScene -from pmgwidgets.widgets.basic.texts.statusreport import show_error -from PySide2.QtCore import QSize, QCoreApplication, QLineF, Qt, QThread, Signal -from PySide2.QtGui import QColor, QKeyEvent, QWheelEvent, QCloseEvent -from PySide2.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QToolButton, QSpacerItem, QSizePolicy, QGraphicsView, \ - QFrame, QApplication, QFileDialog, QMessageBox - -COLOR_NORMAL = QColor(212, 227, 242) -COLOR_HOVER = QColor(255, 200, 00) -COLOR_HOVER_PORT = QColor(0, 0, 50) - - -class PMGraphicsView(QGraphicsView): - def wheelEvent(self, event: 'QWheelEvent') -> None: - """ - 鼠标滚轮事件 - :param event: - :return: - """ - if event.modifiers() == Qt.ControlModifier: - if event.angleDelta().y() > 0: - self.scale(1.1, 1.1) - else: - self.scale(0.9, 0.9) - - -class PMFlowWidget(QWidget): - def __init__(self, parent=None, path=''): - self._path = path - _translate = QCoreApplication.translate - super().__init__(parent) - # self.setup_ui() - - def setup_ui(self): - self.setObjectName("tab_flow") - self.base_layout = QHBoxLayout(self) - self.verticalLayout_6 = QVBoxLayout() - self.base_layout.addLayout(self.verticalLayout_6) - self.verticalLayout_6.setContentsMargins(0, 0, 0, 0) - self.verticalLayout_6.setSpacing(0) - self.verticalLayout_6.setObjectName("verticalLayout_6") - self.widget_3 = QWidget(self) - self.widget_3.setMinimumSize(QSize(0, 30)) - self.widget_3.setObjectName("widget_3") - - # self.horizontal_layout_down = QHBoxLayout(self.widget_3) - self.horizontal_layout = QHBoxLayout(self.widget_3) - self.horizontal_layout.setContentsMargins(0, 0, 0, 0) - self.horizontal_layout.setSpacing(1) - self.horizontal_layout.setObjectName("horizontalLayout_6") - - self.tool_button_run = QToolButton(self.widget_3) - self.tool_button_run.setText('Run_bg') - self.tool_button_run.setIconSize(QSize(25, 25)) - self.tool_button_run.setObjectName("toolButton_4") - - self.horizontal_layout.addWidget(self.tool_button_run) - - self.tool_button_run_fg = QToolButton(self.widget_3) - self.tool_button_run_fg.setText('Run_fg') - self.horizontal_layout.addWidget(self.tool_button_run_fg) - - self.tool_button_step = QToolButton(self.widget_3) - self.tool_button_step.setText('Step') - self.horizontal_layout.addWidget(self.tool_button_step) - - self.tool_button_save = QToolButton(self.widget_3) - self.tool_button_save.setText('Save') - self.horizontal_layout.addWidget(self.tool_button_save) - - self.tool_button_reset = QToolButton(self.widget_3) - self.tool_button_reset.setText('Reset') - self.horizontal_layout.addWidget(self.tool_button_reset) - - self.tool_button_undo = QToolButton(self.widget_3) - self.tool_button_undo.setText('Undo') - self.horizontal_layout.addWidget(self.tool_button_undo) - # self.tool_button_undo.setEnabled(False) - - self.tool_button_redo = QToolButton(self.widget_3) - self.tool_button_redo.setText('Redo') - self.horizontal_layout.addWidget(self.tool_button_redo) - # self.tool_button_redo.setEnabled(False) - - spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - self.horizontal_layout.addItem(spacerItem) - self.verticalLayout_6.addWidget(self.widget_3) - - self.graphicsView = PMGraphicsView(self) - - self.graphicsView.setFrameShape(QFrame.NoFrame) - self.graphicsView.setObjectName("graphicsView") - self.verticalLayout_6.addWidget(self.graphicsView) - - self.scene = PMGraphicsScene(graphics_view=self.graphicsView, flow_widget=self) - self.scene.setSceneRect(-1000, -1000, 2000, 2000) - - self.node_manager = NodeManagerWidget(scene=self.scene) - # self.node_manager.scene = self.scene - self.base_layout.addWidget(self.node_manager) - self.nodes: List[Node] = self.scene.nodes - self.lines = self.scene.lines - - self.node_manager.register_node_content(PMGFlowContent, 'simple_calc', 'UserDefinedFunc') - self.load_nodes_library() - self.graphicsView.setScene(self.scene) - - self.tool_button_run.clicked.connect(self.run) - self.tool_button_undo.clicked.connect(self.scene.undo) - self.tool_button_redo.clicked.connect(self.scene.redo) - # self.tool_button_open.clicked.connect(self.open) - self.tool_button_reset.clicked.connect(self.reset) - self.tool_button_save.clicked.connect(self.save) - self.tool_button_run_fg.clicked.connect(lambda: self.run_in_fg()) - self.tool_button_step.clicked.connect(self.step) - if self._path != '': - self.scene.load_flowchart(self._path) - - def load(self, path: str): - self._path = path - self.scene.load_flowchart(path) - - def on_error_occurs(self, error: FlowContentError): - show_error(self, error.brief, error.detailed, self.tr('Error')) - - def reset(self): - self.scene.reset_status() - self.scene.load_flowchart(self._path) - - def open(self): - file_name, ext = QFileDialog.getOpenFileName(self, '选择文件', '', '流程图文件(*.pmcache *.json *.pmfc)') - if file_name == '': - return - try: - self._path = file_name - self.reset() - # self.load_flowchart(file_name) - self.setWindowTitle(os.path.basename(file_name)) - except: - import traceback - traceback.print_exc() - pass - - def save(self): - self.scene.dump_flowchart(self._path) - - def pre_run(self): - call_id_list = self.scene.topo_sort() - for i in call_id_list: - self.scene.find_node(i).content.refresh_input_port_indices() - self.scene.find_node(i).content.refresh() - - def step(self): - """ - 要求必须是拓扑排序之后才可以用! - Returns: - - """ - self.run_fg_for_one_step() - - def run_in_fg(self, input_args_list: List[object] = None) -> List[object]: - """ - 前端直接进行数据处理,而非在后台线程执行。 - 这样不能做耗时操作(因为会卡住界面),但是可以直接获取运行后的数据,并且结果相对简单一些。 - :return: - """ - self.pre_run() - if input_args_list is None: - input_args_list = [] - for node in self.scene.nodes: - node.reset() - call_id_list = self.scene.topo_sort() - self.scene.call_id_list = call_id_list - return self.run_fg_for_one_step(input_args_list) - - def run_fg_for_one_step(self, input_args_list: List[object] = None): - call_id_list = self.scene.call_id_list - self.scene.find_node(call_id_list[0]).content._process(input_args_list) - - return self.scene.find_node(call_id_list[-1]).content.results - - def run(self): - """ - 运行代码 - """ - call_id_list = self.scene.topo_sort() - self.scene.call_id_list = call_id_list - - thread = QThread() - for node in self.scene.nodes: - node.reset() - node.content.moveToThread(thread) - worker = self.scene.find_node(call_id_list[0]).content - worker.moveToThread(thread) - thread.started.connect(worker._process) - thread.start() - self.worker = worker - self.thread = thread - - def closeEvent(self, a0: 'QCloseEvent') -> None: - """ - 当文件名为示例文件的时候,不可自动存储,但是可以手动点击保存。 - :param a0: - :return: - """ - if not self._path.endswith('.json'): - self.scene.dump_flowchart(self._path) - - def load_nodes_library(self): - from pmgwidgets.flowchart.nodes.simplecalc import Constant, Add, Mul - self.node_manager.register_node_content(Constant, 'simple_calc', 'Constant') - self.node_manager.register_node_content(Add, 'simple_calc', 'Add') - self.node_manager.register_node_content(Mul, 'simple_calc', 'Mul') - - -if __name__ == '__main__': - from pmgwidgets.flowchart.core.flow_content import PMGFlowContent - import cgitb - - cgitb.enable() - app = QApplication(sys.argv) - graphics = PMFlowWidget() - graphics.setup_ui() - graphics.load('flowchart_stat.pmcache') - graphics.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/flowchart/core/nodemanager.py b/pyminer/pmgwidgets/flowchart/core/nodemanager.py deleted file mode 100644 index 902a9a92..00000000 --- a/pyminer/pmgwidgets/flowchart/core/nodemanager.py +++ /dev/null @@ -1,283 +0,0 @@ -""" -This is node manager. - -""" -import copy -import json -import os -import sys -from typing import List, Dict, Tuple, Union, TYPE_CHECKING, Type - -from pmgwidgets import PMGPanel -from pmgwidgets.flowchart.core.flow_content import FlowContentForFunction -from pmgwidgets.flowchart.core.flow_items import CustomPort -from pmgwidgets.flowchart.core.flow_node import Node -from PySide2.QtCore import Signal -from PySide2.QtGui import QColor -from PySide2.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QListWidget, QPushButton, QDialog, QToolBox, QTextEdit - -COLOR_NORMAL = QColor(212, 227, 242) -COLOR_HOVER = QColor(255, 200, 00) -COLOR_HOVER_PORT = QColor(0, 0, 50) - -if TYPE_CHECKING: - from pmgwidgets.flowchart.core.flowchart_widget import PMGraphicsScene - from pmgwidgets.flowchart.core.flow_content import PMGBaseFlowContent, PMGFlowContent - - -class NodeManagerWidget(QWidget): - signal_new_node = Signal(Node) - - def __init__(self, parent: QWidget = None, scene: 'PMGraphicsScene' = None): - super().__init__(parent) - self.content_classes: Dict[str, Type[PMGFlowContent]] = {} - self.text_to_class_name: Dict[str, str] = {} - self.groups = ['simple_calc', 'dataset', 'plot', 'linear_algebra', 'io'] - self.trans_dic = {'simple_calc': '计算', - 'dataset': '数据集', - 'plot': '绘图', - 'logic': '逻辑', - 'linear_algebra': '线性代数', - 'io': '输入输出' - } - self.node_info_dic: Dict[str, Dict[str, Dict[str, object]]] = {key: dict() for key in self.groups} - - self.setLayout(QVBoxLayout()) - self.top_layout = QHBoxLayout() - self.layout().addLayout(self.top_layout) - # self.button_edit = QPushButton('Edit') - # self.button_add = QPushButton('Add') - # self.top_layout.addWidget(self.button_edit) - # self.top_layout.addWidget(self.button_add) - # self.button_edit.clicked.connect(self.on_edit) - # self.button_add.clicked.connect(self.on_add) - - self.toolbox = QToolBox() - self.list_widgets: Dict[str, QListWidget] = {} - for text in self.groups: - list_widget = QListWidget() - list_widget.doubleClicked.connect(self.on_item_double_clicked) - self.layout().addWidget(self.toolbox) - self.toolbox.addItem(list_widget, self.trans_dic[text]) - self.list_widgets[text] = list_widget - self.scene: 'PMGraphicsScene' = scene - self.setMinimumWidth(300) - self.load_nodes() - - def on_add(self): - group = self.get_current_list_widget_group() - self.add_node_info( - {'text': 'untitled', 'inputs': ['input1'], 'outputs': ['output1'], 'code': '', 'params': [], 'icon': '', - 'group': group, 'ports_changeable': [False, False]}) - - def on_edit(self): - list_widget = self.toolbox.currentWidget() - curr_row = list_widget.currentRow() - - if curr_row >= 0: - group_name = self.toolbox.itemText(self.toolbox.currentIndex()) - curr_text = list_widget.currentItem().text() - dic = self.node_info_dic[group_name][curr_text] - edit_layout = QHBoxLayout() - input_widget = QTextEdit() - edit_layout.addWidget(input_widget) - check_button = QPushButton(text='check') - edit_layout.addWidget(check_button) - input_widget.setText(repr(dic['params'])) - views = [ - ('line_ctrl', 'text', 'Node Text', dic['text']), - ('check_ctrl', 'inputs_changeable', 'Input Ports Changeable', dic['ports_changeable'][0]), - ('check_ctrl', 'outputs_changeable', 'Output Ports Changeble', dic['ports_changeable'][1]), - ('editor_ctrl', 'code', 'Input Python Code', dic['code'], 'python'), - ('list_ctrl', 'inputs', 'Set Inputs', [[None] * len(dic['inputs']), dic['inputs']], lambda: None), - ('list_ctrl', 'outputs', 'Set Outputs', [[None] * len(dic['outputs']), dic['outputs']], lambda: None), - ('file_ctrl', 'icon', 'Set Icon', dic['icon']), - ('combo_ctrl', 'group', 'Group Name', dic['group'], self.groups) - ] - sp = PMGPanel(parent=None, views=views) - dialog = QDialog(self) - - def verify(): - try: - text = input_widget.document().toPlainText() - l = eval(text) - if isinstance(l, list): - dialog2 = QDialog(dialog) - sp2 = PMGPanel(parent=None, views=l) - dialog2.setLayout(QHBoxLayout()) - dialog2.layout().addWidget(sp2) - dialog2.layout().addLayout(edit_layout) - dialog2.exec_() - except: - import traceback - traceback.print_exc() - - check_button.clicked.connect(verify) - dialog.setLayout(QVBoxLayout()) - dialog.layout().addWidget(sp) - dialog.layout().addLayout(edit_layout) - dialog.exec_() - dic = sp.get_value() - params = None - try: - params = eval(input_widget.document().toPlainText()) - except: - import traceback - traceback.print_exc() - group = self.get_current_list_widget_group() - if isinstance(params, list): - self.node_info_dic[group][curr_text]['params'] = params - self.node_info_dic[group][curr_text]['text'] = dic['text'] - self.node_info_dic[group][curr_text]['icon'] = dic['icon'] - self.node_info_dic[group][curr_text]['code'] = dic['code'] - self.node_info_dic[group][curr_text]['inputs'] = dic['inputs'][1] - self.node_info_dic[group][curr_text]['outputs'] = dic['outputs'][1] - self.node_info_dic[group][curr_text]['group'] = dic['group'] - self.node_info_dic[group][curr_text]['ports_changeable'] = [dic['inputs_changeable'], - dic['outputs_changeable']] - list_widget.item(curr_row).setText(dic['text']) - self.save_node_templetes() - self.load_nodes() - else: - return - - def add_node(self, text: str, inputs: List[str], outputs: List[str], ports_changeable: List[bool], - params: List[Union[List, Tuple]] = '', icon_path: str = '', func_str: str = ''): - """ - 添加新的节点 - """ - node_id = self.scene.new_id() - input_ports = [CustomPort(node_id + ':input:%d' % int(i + 1), text=name, port_type='input') for i, name in - enumerate(inputs)] - output_ports = [CustomPort(node_id + ':output:%d' % int(i + 1), text=name, port_type='output') for i, name in - enumerate(outputs)] - node = Node(canvas=self.scene, node_id=node_id, text=text, input_ports=input_ports, output_ports=output_ports, - icon_path=icon_path) - content = FlowContentForFunction(node) - content.set_function(func_str, 'function') - content.set_params(params) - content.ports_changable = ports_changeable - node.set_content(content) - self.scene.add_node(node) - - def on_item_double_clicked(self): - list_widget: QListWidget = self.toolbox.currentWidget() - group = self.get_current_list_widget_group() - curr_row = list_widget.currentRow() - - if curr_row >= 0: - curr_text = list_widget.currentItem().text() - if curr_text in self.node_info_dic[group]: - node_info = self.node_info_dic[group][curr_text] - text: str = node_info.get('text') - inputs: List[str] = node_info.get('inputs') - outputs: List[str] = node_info.get('outputs') - code: str = node_info.get('code') - params: List = node_info.get('params') - icon_path: str = node_info.get('icon') - ports_changeable: List[bool] = node_info.get('ports_changeable') - params = copy.deepcopy(params) # 需要复制一份再传过去,否则会是一个对象。 - self.add_node(text, inputs, outputs, ports_changeable, params, icon_path, code) - else: - content: PMGFlowContent = self.content_classes.get(self.text_to_class_name[curr_text])() - - node_id = self.scene.new_id() - input_ports = [CustomPort(node_id + ':input:%d' % int(i + 1), text=name, port_type='input') for i, name - in enumerate(content.input_args_labels)] - output_ports = [CustomPort(node_id + ':output:%d' % int(i + 1), text=name, port_type='output') for - i, name in - enumerate(content.output_ports_labels)] - node = Node(canvas=self.scene, node_id=node_id, text=content.text, input_ports=input_ports, - output_ports=output_ports, - icon_path=content.icon_path, - look={}) - content.node = node - # content.class_name = curr_text - node.set_content(content) - self.scene.add_node(node) - pass - - def add_node_info(self, info_dic: Dict[str, object]): - """ - add new infomation of node - """ - group = self.get_current_list_widget_group() - text = info_dic.get('text') - self.get_current_list_widget().addItem(text) - self.node_info_dic[group][text](info_dic) - - def get_current_list_widget(self) -> QListWidget: - return self.toolbox.currentWidget() - - def get_current_list_widget_group(self) -> str: - text = self.toolbox.itemText(self.toolbox.currentIndex()) - for k, v in self.trans_dic.items(): - if text == v: - return k - return '' - - def load_nodes(self): - """ - 加载节点 - 加载节点之后,可以 - """ - import pandas - self.node_info_dic = {key: dict() for key in self.groups} - return - df = pandas.read_csv(os.path.join(os.path.dirname(__file__), 'lib', 'test.csv')) - # for k in self.node_info_dic: - for i in range(df.shape[0]): - row = df.loc[i] - dic = { - 'text': row['text'] if not pandas.isna(row['text']) else '', - 'code': row['code'] if not pandas.isna(row['code']) else '', - 'inputs': json.loads(row['inputs']), - 'outputs': json.loads(row['outputs']), - 'params': json.loads(row['params']) - } - dic['icon'] = row['icon'] if not pandas.isna(row['icon']) else '' - dic['group'] = row['group'] if not pandas.isna(row.get('group')) else 'simple_calc' - ports_changeable = row.get('ports_changeable') - dic['ports_changeable'] = json.loads(ports_changeable) if ports_changeable is not None else [False, False] - self.node_info_dic[dic['group']][dic['text']] = dic - - self.refresh_list() - - def save_node_templetes(self): - return - import pandas - - columns = ['text', 'inputs', 'outputs', 'ports_changeable', 'params', 'icon', 'group', 'code'] - content = [] - node_infos = [] - for k in self.node_info_dic: - for k1 in self.node_info_dic[k]: - node_infos += [self.node_info_dic[k][k1]] # self.node_info_dic[k] - - for node_info in node_infos: - text = node_info.get('text') - icon = node_info.get('icon') - inputs = json.dumps(node_info.get('inputs')) - outputs = json.dumps(node_info.get('outputs')) - ports_changeable = json.dumps(node_info.get('ports_changeable')) - params = json.dumps(node_info.get('params')) - code = node_info.get('code') - group = node_info.get('group') - content.append([text, inputs, outputs, ports_changeable, params, icon, group, code]) - df = pandas.DataFrame(content, columns=columns) - - df.to_csv(os.path.join(os.path.dirname(__file__), 'lib', 'test.csv')) - - def refresh_list(self): - for k in self.node_info_dic: - node_infos = self.node_info_dic[k] - list_widget = self.list_widgets[k] - list_widget.clear() - for k1, info in node_infos.items(): - list_widget.addItem(info['text']) - - def register_node_content(self, content_class: Type['PMGFlowContent'], group_name: str, text: str = ''): - content = content_class() - self.list_widgets[group_name].addItem(content.text) - self.content_classes[content.class_name] = content_class - self.text_to_class_name[content.text] = content.class_name diff --git a/pyminer/pmgwidgets/flowchart/core/utils.py b/pyminer/pmgwidgets/flowchart/core/utils.py deleted file mode 100644 index b8a18278..00000000 --- a/pyminer/pmgwidgets/flowchart/core/utils.py +++ /dev/null @@ -1,13 +0,0 @@ -from PySide2.QtCore import QPointF - - -def round_position(point: QPointF, pixels=5): - """ - 圆整位置。 - :param point: - :param pixels:圆整的单位(最好是1,2,5,10,20,...) - :return: - """ - x, y = point.x(), point.y() - x_cor, y_cor = round(x * 1.0 / pixels) * pixels, round(y * 1.0 / pixels) * pixels - return QPointF(x_cor, y_cor) diff --git a/pyminer/pmgwidgets/flowchart/create_node_content_class.md b/pyminer/pmgwidgets/flowchart/create_node_content_class.md deleted file mode 100644 index 0bf1dc1c..00000000 --- a/pyminer/pmgwidgets/flowchart/create_node_content_class.md +++ /dev/null @@ -1,86 +0,0 @@ -# 使用面向对象方式进行节点创建 -## 简单示例解析 -1、在pmgwidgets/flowchart/nodes/simplecalc.py -仿照现有的节点,编写一个现有的节点名为Mul. -如果想要建立其他文件,可以在同一目录下建立。 -需要继承PMGFlowContent这个基类。 -我们参考Add这个类。 -不妨将Add类复制一遍之后,在其上加以修改。 -```python -class Mul(PMGFlowContent): - def __init__(self): - super().__init__() - self.input_args_labels = ['in1', 'in2'] - self.output_ports_labels = ['out'] - self.class_name = 'Mul' - self.text = '乘积' - self.icon_path = '' - - def process(self, *args) -> List[object]: - if len(args) > 1: - mul = args[0] - for a in args[1:]: - mul *= a - else: - raise ValueError - return [mul] -``` -对于PMGFlowContent类有以下方式: -- input_ports_labels:输入端口的文字列表。根据这个列表将自动生成输入端口,输入端口的数量与列表长度一致,文字从上至下依次为列表 -从前往后的各个项。 -- output_ports_labels:输出端口的文字列表,含义同输入端口文字列表。 -- class_name:节点的类。一般应当以英文明明 -- text:节点的文字,支持中文等utf-8编码的字符。 -- icon_path:图标的属性(尽量用绝对路径) - -注意事项: -- `__init__(self)`方法除了`self`之外,不能有任何参数。 - - -2、在pmgwidgets/flowchart/core/flowchart_widget.py中,跳转到load_nodes_library(self)这个方法。 -```python -def load_nodes_library(self): - from pmgwidgets.flowchart.nodes.simplecalc import Constant, Add - self.node_manager.register_node_content(Constant, 'simple_calc', 'Constant') - self.node_manager.register_node_content(Add, 'simple_calc', 'Add') - -``` -添加导入Mul,并且照葫芦画瓢,将代码改成: -```python -def load_nodes_library(self): - from pmgwidgets.flowchart.nodes.simplecalc import Constant, Add, Mul - self.node_manager.register_node_content(Constant, 'simple_calc', 'Constant') - self.node_manager.register_node_content(Add, 'simple_calc', 'Add') - self.node_manager.register_node_content(Mul, 'simple_calc', 'Mul') -``` -`simple_calc`指的是简单计算这一分组。 - -运行这个文件,即可看见新的节点`Mul`已被创建。双击右键即可插入。 -点击run_fg即可运行。但注意,至少要有两个模块和一条连接线。一个简单的示例如下图。 -双击节点,可以查看节点的输入值和输出值。 -![](doc_figures/create_new_content_Mul.png) - -3、点击设置弹出窗口效果 -参考simple_calc.py下的Constant类,重写其on_settings_requested(self, parent)方法即可。 -在这个节点上点击右键,即可弹出这个窗口。 -大概像这样: -```python -def on_settings_requested(self, parent): - dlg = QDialog(parent=parent) - dlg.exec_() -``` - -4、设置显示的文本内容 -参考Constant类,重写format_param(self)方法即可。大概如此: - -```python -def format_params(self): - return "hello" -``` - -这样节点就会显示“hello”文本。 - -5、设置图标(未做) - -6、设置存储信息 -节点的info属性会在保存时保存和加载。只要修改info属性即可。 diff --git a/pyminer/pmgwidgets/flowchart/dataprocesswidget.py b/pyminer/pmgwidgets/flowchart/dataprocesswidget.py deleted file mode 100644 index 41def247..00000000 --- a/pyminer/pmgwidgets/flowchart/dataprocesswidget.py +++ /dev/null @@ -1,209 +0,0 @@ -""" -node properties: -id:str -text:str -icon:str(path of icon) -ports:{} -content:{} - -properties of contents: -code:str -type:str -params:List[str] -""" -import json -import os -import sys -import time -from typing import List - -t0 = time.time() -from pmgwidgets.flowchart.core.flowchart_widget import PMFlowWidget -from pmgwidgets.flowchart.core.flow_node import Node -from pmgwidgets.flowchart.core.nodemanager import NodeManagerWidget -from pmgwidgets.flowchart.core.flowchart_scene import PMGraphicsScene -from PySide2.QtCore import QSize, QCoreApplication, Qt -from PySide2.QtGui import QColor, QWheelEvent -from PySide2.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QToolButton, QSpacerItem, QSizePolicy, QGraphicsView, \ - QFrame, QApplication, QFileDialog, QMessageBox - -COLOR_NORMAL = QColor(212, 227, 242) -COLOR_HOVER = QColor(255, 200, 00) -COLOR_HOVER_PORT = QColor(0, 0, 50) - - -class PMGraphicsView(QGraphicsView): - def wheelEvent(self, event: 'QWheelEvent') -> None: - """ - 鼠标滚轮事件 - :param event: - :return: - """ - if event.modifiers() == Qt.ControlModifier: - if event.angleDelta().y() > 0: - self.scale(1.1, 1.1) - else: - self.scale(0.9, 0.9) - - -class PMDataProcessFlowWidget(PMFlowWidget): - def __init__(self, parent=None, path=''): - self._path = path - _translate = QCoreApplication.translate - super().__init__(parent) - self.setObjectName("tab_flow") - self.base_layout = QHBoxLayout(self) - self.verticalLayout_6 = QVBoxLayout() - self.base_layout.addLayout(self.verticalLayout_6) - self.verticalLayout_6.setContentsMargins(0, 0, 0, 0) - self.verticalLayout_6.setSpacing(0) - self.verticalLayout_6.setObjectName("verticalLayout_6") - self.widget_3 = QWidget(self) - self.widget_3.setMinimumSize(QSize(0, 30)) - self.widget_3.setObjectName("widget_3") - - self.horizontal_layout = QHBoxLayout(self.widget_3) - self.horizontal_layout.setContentsMargins(0, 0, 0, 0) - self.horizontal_layout.setSpacing(1) - self.horizontal_layout.setObjectName("horizontalLayout_6") - - self.tool_button_run_fg = QToolButton(self.widget_3) - self.tool_button_run_fg.setText('Run') - self.horizontal_layout.addWidget(self.tool_button_run_fg) - - self.tool_button_save = QToolButton(self.widget_3) - self.tool_button_save.setText('Save') - self.horizontal_layout.addWidget(self.tool_button_save) - - self.tool_button_save_as = QToolButton(self.widget_3) - self.tool_button_save_as.setText('Save As') - self.horizontal_layout.addWidget(self.tool_button_save_as) - - self.tool_button_open = QToolButton(self.widget_3) - self.tool_button_open.setText('Open') - self.horizontal_layout.addWidget(self.tool_button_open) - - self.tool_button_reset = QToolButton(self.widget_3) - self.tool_button_reset.setText('Reset') - self.horizontal_layout.addWidget(self.tool_button_reset) - - self.tool_button_undo = QToolButton(self.widget_3) - self.tool_button_undo.setText('Undo') - self.horizontal_layout.addWidget(self.tool_button_undo) - # self.tool_button_undo.setEnabled(False) - - self.tool_button_redo = QToolButton(self.widget_3) - self.tool_button_redo.setText('Redo') - self.horizontal_layout.addWidget(self.tool_button_redo) - # self.tool_button_redo.setEnabled(False) - - spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - self.horizontal_layout.addItem(spacerItem) - self.verticalLayout_6.addWidget(self.widget_3) - - self.graphicsView = PMGraphicsView(self) - - self.graphicsView.setFrameShape(QFrame.NoFrame) - self.graphicsView.setObjectName("graphicsView") - self.verticalLayout_6.addWidget(self.graphicsView) - - self.scene = PMGraphicsScene(graphics_view=self.graphicsView, flow_widget=self) - self.scene.setSceneRect(-1000, -1000, 2000, 2000) - - self.node_manager = NodeManagerWidget(scene=self.scene) - # self.node_manager.scene = self.scene - self.base_layout.addWidget(self.node_manager) - self.nodes: List[Node] = self.scene.nodes - self.lines = self.scene.lines - - self.load_nodes_library() - self.graphicsView.setScene(self.scene) - - self.tool_button_undo.clicked.connect(self.scene.undo) - self.tool_button_redo.clicked.connect(self.scene.redo) - self.tool_button_open.clicked.connect(self.open) - self.tool_button_reset.clicked.connect(self.reset) - self.tool_button_save.clicked.connect(self.save) - self.tool_button_save_as.clicked.connect(self.saveas) - self.tool_button_run_fg.clicked.connect(lambda: self.run_in_fg()) - if self._path != '': - self.scene.load_flowchart(self._path) - - def load(self, path: str): - self._path = path - self.scene.load_flowchart(path) - - def saveas(self): - """ - - Returns: - """ - file_name, ext = QFileDialog.getSaveFileName(self, '选择文件', '', '流程图文件(*.pmfc)') - if file_name == '': - return - self._path = file_name - self.save() - self.setWindowTitle(os.path.basename(file_name)) - - def reset(self): - self.scene.reset_status() - self.scene.load_flowchart(self._path) - self.pre_run() - - - - def run_in_fg(self, input_args_list: List[object] = None) -> List[object]: - """ - 前端直接进行数据处理,而非在后台线程执行。 - 这样不能做耗时操作(因为会卡住界面),但是可以直接获取运行后的数据,并且结果相对简单一些。 - :return: - """ - self.pre_run() - if input_args_list is None: - input_args_list = [] - for node in self.scene.nodes: - node.reset() - call_id_list = self.scene.topo_sort() - self.scene.call_id_list = call_id_list - return self.run_fg_for_one_step(input_args_list) - - def run_fg_for_one_step(self, input_args_list: List[object] = None): - call_id_list = self.scene.call_id_list - self.scene.find_node(call_id_list[0]).content._process(input_args_list) - - return self.scene.find_node(call_id_list[-1]).content.results - - def load_nodes_library(self): - from pmgwidgets.flowchart.nodes.simplecalc import Constant, Add, Mul - from pmgwidgets.flowchart.nodes.random import Random - from pmgwidgets.flowchart.nodes.plots import HistPlot - from pmgwidgets.flowchart.nodes.dfoperation import DataReplace - from pmgwidgets.flowchart.nodes.dataframeoperation import DropDuplicated - from pmgwidgets.flowchart.nodes.io import Iterator, ListDirs, PandasImport, PandasFileImport - - self.node_manager.register_node_content(Constant, 'simple_calc') - self.node_manager.register_node_content(Add, 'simple_calc') - self.node_manager.register_node_content(Mul, 'simple_calc') - self.node_manager.register_node_content(Random, 'simple_calc') - self.node_manager.register_node_content(HistPlot, 'plot') - self.node_manager.register_node_content(DataReplace, 'dataset') - self.node_manager.register_node_content(DropDuplicated, 'dataset') - # self.node_manager.register_node_content(Iterator, 'simple_calc') - self.node_manager.register_node_content(ListDirs, 'io') - self.node_manager.register_node_content(PandasImport, 'io') - self.node_manager.register_node_content(PandasFileImport, 'io') - - def closeEvent(self, e): - super().closeEvent(e) - - -if __name__ == '__main__': - from pmgwidgets.flowchart.core.flow_content import PMGFlowContent - import cgitb - - cgitb.enable() - app = QApplication(sys.argv) - graphics = PMDataProcessFlowWidget() - graphics.load('dataprocess.pmcache') - graphics.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/flowchart/doc_figures/before_run.png b/pyminer/pmgwidgets/flowchart/doc_figures/before_run.png deleted file mode 100644 index 47dffcb07cf65acaf79e09f7613a2db3839e4349..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23979 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 A$N&HU diff --git a/pyminer/pmgwidgets/flowchart/doc_figures/check_json.png b/pyminer/pmgwidgets/flowchart/doc_figures/check_json.png deleted file mode 100644 index eb6c2fa3af3c1514be1e54ee061123cb9e07ff2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19866 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 B^u_=H diff --git a/pyminer/pmgwidgets/flowchart/doc_figures/click_edit_button.png b/pyminer/pmgwidgets/flowchart/doc_figures/click_edit_button.png deleted file mode 100644 index 29ccca60f497c205a190f37adf5e57f2c1017b3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4992 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

@Ihk+X*3tqF&r)|j%Jmgw6KctzX8r!I; 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 Q&?5kklr$6z<;?>AAI;&hcmMzZ diff --git a/pyminer/pmgwidgets/flowchart/doc_figures/create.png b/pyminer/pmgwidgets/flowchart/doc_figures/create.png deleted file mode 100644 index 699fb754d43c5f9522890cb2e1734c38ee20c6b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4838 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 J#2Fy({1@ZS*^~eP diff --git a/pyminer/pmgwidgets/flowchart/doc_figures/create_new_content_Mul.png b/pyminer/pmgwidgets/flowchart/doc_figures/create_new_content_Mul.png deleted file mode 100644 index 8cc0dc71b368ba88abe34f4c9d37a7d96e2d3c31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15782 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 z zdN<{sviRNDFQx5}y(fV>D6<(jdDx>DnCWQ&++DABjw^iqyr;|hOZm|N(9+wdO1K&P z)u)4kD9++xkJ%OX)XUtBgC3w@&ov+o|E_H)@l!(mNSx~DeD_~GBwzMv-N9W$1EZsd zfS}?f{0tn zL*q||a&j8y=5AY7k$41V;HXg1CRXY{6y7d4L8o(#HP;L14Klx6l9mvvTI*ay;U}q$ zdp6K7c`O``=!P?Yr>+X-+7^Y~RNs}U0@UHyG?lLD*h}`2-{6OzL?o>AIs19n_^Yp$ zh<-Ve`j&<38%EPJw@p+Jjn ziLr>s#H+R9Q=Se|!t&(i$-6gr$`myev3_NpV|;(udUUlEFk^;>8<%i)x8 ztRTrYphp+GQNoWC?}Sk#y*LDKLQm2U0&q==u3MhF8rW>4*Cuc9@z>M=vHO!AfK>!NmZTu1M8_Od}Q z|Ard@Zz%p#k>=>XRv!i&7LqE&<u})RNv*k4HO8L2qluP<$`dUWUSGt@VKUxqSbyq;mzUuh6i__;+V7Mg{C3 zuMZEP1kY>vuO?j^=KN-;AvB(PqSp`{J(Y^;#qWa#t~FbpQF>d`m=vhhce#}>9jP3X zsjBE@r1mR#E#eXR)7`g)Cl|GITdM^=6l4=t#DJKL^h6Idw#{%`UUUZl5z5xalb*K@0#TB@@qnG7#bhVMUM&KLsA{ab6%}L z2OHwypESnecc%H;Ffc7T{5Sp1l&522?{ZC>V=CXz6IUS~4+{Yl!zBtH2&Sn08KU)6 zhUNG{z?Q_oH;A&dU4|9mZs%#KZ!GP$dn;S(lgw&vt0Gww z`xD24Yo}VnKD2h$%^?z3QsZ*F6dPisJ57~!)pRv#r?1ZspHQaI7As|2P{B!44(+hW zokFllR)i&nk)YHuFO;=gtwHZjk$`5Sy_L31@Q)OU=4}KSd%24(T%_;FB!OOy zmi4o;Iwga|l1lNTn8kX&yS=|gv`G=1wZia8)YKqLc`0!ld&VA15{vf%GCamvnTry{ ziP_v;yi7%2rdyG_H=VhYOKj*CI<(B3C6egGGU50LekK`>i}_PJw>)J?#*|u1YwxDe zRQ7H0qA6x-m!J!L>}+Kl%ayF-EafNbCnvIuzEov1H`#}=WY!`e&@6hxF2Q)ew5 zUF~yPPrEbHNizSAJ~rB`JeO)?|Ks;c>G9d(B25-E6KAMgZ2i8^!Yo1Xivp_>Y+#&0 zW3?lbspio-XP~&wO%u-=q9O*YqkIcu96HJ?nD1hlOgPzo=rLUUh@hM{GZI@=)wXR_ z%()mS0jF^f7K)u0&x!A3PCDzJ857>Bsp@}f*xSTSd_oAA$RB$pWrkfzVqv#kLIwvV zan(Z4ug3Tm)zlCV&hze0I5DH5Gk<9i(pKgWLlX2*f)Y2V$O0d(5aj7c7U)1>!F4Wg)Pw8Xox#CqvbwZRNDN+W-*FGP8jHg9dZFWkj^((7e%pH`^;L zG{5~}kZzD&>25vae2A$aVd53SEB?c^Ze;@nw{kC~-=>BeFD(8Bsf6sQ?7M-t;7*$6ybpy{u182J>j3a)TG^GzK<;$7;1}{@!)rPMkq{0<@9n;WHn)nRTa;QcP@T`%B_JX^i?x4GQODJjQxgY0uEgXU3zmg|ENbmnOUz)hdwYY0_=q zS@zi4TBFc#re9)^y^g!9Pd!$HtS6{4mJ8MuT}}U1m2x<|r=YX<5h48KKskrCT5^gE z9H0|0t5~60Na>!!g!yNCEFyiH%xDt&gr+@%y^0wAU1Gqr&?Bv9cmC3Eg~t)O{#xG| zWffuZS3g|yjcWE0B5^qi2r({$Z9#%fSxdP_9-$PrVepbb#DSQg`U9vdh;qpndpw-Be z(FNYaRO;#wk;|oXfASWbK7nYtbolV=lm znH}EO{OfVF{y_95AmQmC$-PH8l{DRvvt5tyl`sJ7o`juonBq9cBt0K}>LU!&eWtZ@ x@y8!XlJV6P1%`$>;U-nzgB%qRktS2#{%+sOVsD5uU@Jf;9NmuB91FhjKL90x@QVNd diff --git a/pyminer/pmgwidgets/flowchart/doc_figures/custom_node.png b/pyminer/pmgwidgets/flowchart/doc_figures/custom_node.png deleted file mode 100644 index 4baa3d11bc455270dad4ace4ef608b56122e763e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6221 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 Msiv!nRDp#4KZz2B@&Et; diff --git a/pyminer/pmgwidgets/flowchart/doc_figures/edit_node.png b/pyminer/pmgwidgets/flowchart/doc_figures/edit_node.png deleted file mode 100644 index b047ee097a6ac64b93ecdbeccc48bd274d30c10a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11421 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 diff --git a/pyminer/pmgwidgets/flowchart/doc_figures/popup_edit_panel.png b/pyminer/pmgwidgets/flowchart/doc_figures/popup_edit_panel.png deleted file mode 100644 index 2c0ff2e30df318e3332b8371f7da53941715c205..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8469 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 akR~7|thir@3H~bsV06mtWXTDq-~S7dJ#Nqd diff --git a/pyminer/pmgwidgets/flowchart/doc_figures/sketch_after_edit.png b/pyminer/pmgwidgets/flowchart/doc_figures/sketch_after_edit.png deleted file mode 100644 index 4f91a16ed39ef77b326e62d40944814a7e7e0bfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15351 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�AC{~h=d!Y!%7CTG9~!`kKq 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 N-qX2TruyXh{{uVuc5MIv diff --git a/pyminer/pmgwidgets/flowchart/icons/down.png b/pyminer/pmgwidgets/flowchart/icons/down.png deleted file mode 100644 index d9d0cf6d0bc80115e7d9b5bd169def5a4582899b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 584 zcmV-O0=NB%P)0v@7=@qtxVOC}Db^N?O>rY)RmAF6O{s#Q8=?LM1@SKk{tew!7lKr(F6>4@({)`4 zLU)Q#Qz;Eeim8psbyDr-*vMk7MO%X^MyxHb9XT-He}RDdnWMKdOf1+KOa!8ACrzL9 z0bT@S4N+{dvBg9dZ464OPL+Qq2!gQ|8-cO=u+gAELii5@2^ecI7K}A0t-H+zRv4H- z8-uoVUVGLA)2}HXd$?E_j`A2oJ?L% z4k!1g&X-WR5GOI_7k^+cg3EKSaJ^e5}&m*m-ESKR>ICPu)t2lf_HN zk4-a{CFrcvITyj_IhpsQdl}M(Xfz?+Yt#7fZLv|W+%*8(UzXktnQKFNL0z6GO+YGy z{g*T6$($$69HF3SH5+WMtS>g|l{;JCpNi=&qxSXr`&h0hh$juo)EOR5J zLwFVV(X3PLz_)whfd&Az%~z|#S=q=4b1tM*Uk`=>)F6Yd&dfe}poF81dgb0A7~nS; W)D@WJfdOaPm)zxYuRG&^ZnM{1a=Sabx3e2*pEB)SyP2K; z?|Ei+?zm#)fd-F;xA$z7b}9WDjoj)Z!)y=z`{k* zbHkzr{`F*}r?XW$0Np*%Ivox(3hnfjDRQiPPvW=#1%OLuqrL0G_%L+)TpXW5JC{t+ zms;Z%z z@gF@0Fmx>3+_P2w7P{MfDqhzge_c{{-QK@2?HPcX!RUhl1;2s3Tk}?$hUM@yEQgPT z0)U-+1;QB^z{cY&pUvkeZMmR|QE?rX|nzHI|KZ7(Jgf#r?7{JwUqL0Wjehs<}tL`}& zK+5`@-=%9xK#PfK=?f85)ssM2LH>$B5#th~ z?ZoV=&qv3}leg_pT(JZIu0IB@zY5(tvk_C@N0C&QM^!g3`dUApgc4F1(N1D@=^Uit zIY`5MWdRI-5N_}4kl%&wy*xK&07zUx!CR6j(3bJ1`Z?H#CZL3B!~;OrnXyUo#I1W1 zmx};m=cA8H5`G1`>v%`e00a=*f`i)@k+Lc6-BW?>y)h_$3L5;P)zl6Erg=!i^N@z4 zIQC`z8L5WcV|Naz9{|97p!izekb&ip6#ryUQNeYbkgoBt4?t5EoyFrXcB*twS1NW&^d6XA^T?y%8iB)zu;B?K&m2zlpydR)RfdVwY=7h zTs9oBfgsvq0d06GVY zG*ECY{R=?2>I{NY0JH|GYtvFxRwl070-#YaPXkLrj%|u;IZ%5MwhMrniW=c}w&`Jm z3oKl>4?yQ&kp_~G3;TjP%hJFHf)_xc@LKq@nG{ZbWyR^bV*nZj>%BpZ%P2oq4euD? zoRBv+!3qGCV0uv~zm6IgZqxP30O%Yzo)m0pkeGs0*dJ6lHPQvS@HxWrbd&;sN|<-- zBUZM-!8%7Z$UICATz3V4MuGp_P%JSIXZH-WoK!g7$yKn6GKBK7#x;<0*WCl4bFg`e ztXLJg?m7UCg8ekumP@XS0ibgbl?E4G7Yab5;9?pCxGo-m&Y{vY2y)#s02&1cX%OtX zw*YhwylL>jbzcBz6im|Kq3iwu&^fG3gU7D>4nU)zr6CZ`BClOv8vvG6$p<1g0NeoJ z4gmILf|lzPz!d)U(T&Y_ZVs{U_wB#V0Gu2i%?}ix#Un3tJ`f5>N07&9@BzS7CPxo7 z9gKa5PJ=)I zhOXNJz$7vaf&iGhZX19u5ovH40GI2I0Wi6p1{VQvyIv6hU2dhp1pu~PcLe~G8)>Kz zfFsvk1E8ytG&lrMk?XDlU~-xU2LLK|T?hbOcGF-3fNQP`1;At{4V(a6bzL|BT|8;9 z03gJ5&j2u4rNIP%FxNc=pvx!?WdI0w-4_5%OKD&b_89;;1+E_w?YeIObU_;SK^oYy zXjuZlTps|}PkB8T-~QW^mWJvh;f{H9;U8~ZU#|ZE!$D!oHJQ}700000NkvXXu0mjf DAnWoV diff --git a/pyminer/pmgwidgets/flowchart/nodes/__init__.py b/pyminer/pmgwidgets/flowchart/nodes/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/flowchart/nodes/dataframeoperation/__init__.py b/pyminer/pmgwidgets/flowchart/nodes/dataframeoperation/__init__.py deleted file mode 100644 index 384473ff..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/dataframeoperation/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .dropduplicated import DropDuplicated - # self.results = copy.deepcopy(result) \ No newline at end of file diff --git a/pyminer/pmgwidgets/flowchart/nodes/dataframeoperation/dropduplicated.py b/pyminer/pmgwidgets/flowchart/nodes/dataframeoperation/dropduplicated.py deleted file mode 100644 index bb762c51..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/dataframeoperation/dropduplicated.py +++ /dev/null @@ -1,64 +0,0 @@ -import sys -from typing import List, Union, Tuple, Dict, TYPE_CHECKING, Callable -from pmgwidgets import PMGFlowContent, PMGPanelDialog - -if TYPE_CHECKING: - import pandas as pd - - -class DropDuplicated(PMGFlowContent): - - def __init__(self): - super(DropDuplicated, self).__init__() - self.input_args_labels = ['in'] - self.output_ports_labels = ['out'] - self.class_name = 'DropDuplicated' - self.text = '去除重复值' - self.icon_path = '' - self.agg = None - self.info = {'regulations': []} - - def process(self, *args) -> List: - """ - 删除缺失值的方法 - Args: - *args: - - Returns: - - """ - import pandas as pd - assert isinstance(args[0], pd.DataFrame) - df: pd.DataFrame = args[0] - # if df.duplicated(): - return [df.drop_duplicates()] - - def on_settings_requested(self, parent): - """ - - Args: - parent: - - Returns: - - """ - views = [['rules_ctrl', 'rules', '规则编辑', - [ - {'name': 'input_col_name', 'text': '输入流字段', 'init': '$ALL'}, - {'name': 'output_col_name', 'text': '输出流字段', 'init': ''}, - {'name': 'str_to_replace', 'text': '待替换数据', 'init': ''}, - {'name': 'replace_with', 'text': '替换为', 'init': ''}, - {'name': 'regex', 'text': '使用正则表达式', 'init': False}, - {'name': 'match_words', 'text': '全字匹配', 'init': True}, - {'name': 'case_sensitive', 'text': '大小写敏感', 'init': False} - ], - ] - ] - dlg = PMGPanelDialog(parent=parent, views=views) - - dlg.setMinimumSize(600, 480) - - dlg.panel.set_value({'rules': self.info['regulations']}) - dlg.exec_() - - self.info['regulations'] = dlg.panel.get_value()['rules'] diff --git a/pyminer/pmgwidgets/flowchart/nodes/dataframeoperation/randomrowsample.py b/pyminer/pmgwidgets/flowchart/nodes/dataframeoperation/randomrowsample.py deleted file mode 100644 index dc4426f2..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/dataframeoperation/randomrowsample.py +++ /dev/null @@ -1,68 +0,0 @@ -import sys -from typing import List, Union, Tuple, Dict, TYPE_CHECKING, Callable -from pmgwidgets import PMGFlowContent, PMGPanelDialog - -if TYPE_CHECKING: - import pandas as pd - - -class RandomRowSample(PMGFlowContent): - - def __init__(self): - super(RandomRowSample, self).__init__() - self.input_args_labels = ['输入'] - self.output_ports_labels = ['取样'] # , '检验'] - self.class_name = 'RandomRowSample' - self.text = '随机抽样' - self.icon_path = '' - self.info = {'sampling_rate': 0.2} - - def process(self, *args) -> List: - """ - 随机取样的方法 - Args: - *args: - - Returns: - - """ - import pandas as pd - assert isinstance(args[0], pd.DataFrame) - df: pd.DataFrame = args[0] - # if df.duplicated(): - length = df.shape[0] - return [df.sample(n=int(self.info['sampling_rate'] * length))] - - def on_settings_requested(self, parent): - """ - - Args: - parent: - - Returns: - - """ - views = [('numberspin_ctrl', 'sampling_rate', '抽样比率', self.info['sampling_rate'], '', (0, 1), 0.0001)] - dlg = PMGPanelDialog(parent=parent, views=views) - - dlg.setMinimumSize(600, 480) - dlg.exec_() - - self.info['sampling_rate'] = dlg.panel.get_value()['sampling_rate'] - - -if __name__ == '__main__': - import sys - - from PySide2.QtWidgets import QApplication - - app = QApplication(sys.argv) - - # r.load_info({'gen_array': False, 'size': (1, 2, 3), 'type': 'normal'}) - # r.process() - info = {'sampling_rate': 0.2} - r = RandomRowSample() - r.load_info(info) - r.on_settings_requested(None) - print(r.info) - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/flowchart/nodes/dfoperation.py b/pyminer/pmgwidgets/flowchart/nodes/dfoperation.py deleted file mode 100644 index 17f77b0e..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/dfoperation.py +++ /dev/null @@ -1,118 +0,0 @@ -import sys -from typing import List, Union, Tuple, Dict, TYPE_CHECKING, Callable -from pmgwidgets import PMGFlowContent, PMGPanelDialog - -if TYPE_CHECKING: - import pandas as pd - - -class DataReplace(PMGFlowContent): - - def __init__(self): - super(DataReplace, self).__init__() - self.input_args_labels = ['in'] - self.output_ports_labels = ['out'] - self.class_name = 'DataReplace' - self.text = '数据替换' - self.icon_path = '' - self.agg = None - self.info = {'regulations': []} - - def get_rule(self, match_words) -> Tuple[Callable, Callable]: - """ - 抽象为: - 待替换的字符(origin),match,replacement, - Args: - match_words: - - Returns: - - """ - if match_words: - return self.equals, lambda origin, match, replacement: replacement - else: - return self.contains, lambda origin, match, replacement: origin.replace(match, replacement) - - def equals(self, origin: str, match: str) -> bool: - return origin == match - - def contains(self, origin: str, match: str) -> bool: - if isinstance(origin, str): - return origin.find(match) != -1 - return False - - def process(self, *args) -> List: - """ - - Args: - *args: - - Returns: - - """ - import pandas as pd - assert isinstance(args[0], pd.DataFrame) - df: pd.DataFrame = args[0] - regulations = self.info['regulations'] - - for regulation in regulations: - column_name = regulation['input_col_name'] - match = regulation['str_to_replace'] - replace_with = regulation['replace_with'] - match_words = regulation['match_words'] - match_rule, replace_rule = self.get_rule(match_words=match_words) - if column_name == '$ALL' or column_name == '': - for row in range(df.shape[0]): - for col in range(df.shape[1]): - if match_rule(df.iloc[row, col], match): - df.iloc[row, col] = replace_rule(df.iloc[row, col], match, replace_with) - else: - column = df[column_name] - # print(column,match) - for row in range(df.shape[0]): - print('row', row, column_name) - if match_rule(column[row], match): - df.loc[row, column_name] = replace_rule(column[row], match, replace_with) - - return [df] - - def check_data(self, data): - pass - - def load_info(self, info: dict): - print('load info!!!!!!!!!!') - self.info = info - print(self.info) - - def on_settings_requested(self, parent): - ''' - headers = ['输入流字段', '输出流字段', '待替换数据', '替换为', '使用正则表达式', '全字匹配', '大小写敏感'] - self.table_keys = ['input_col_name', 'output_col_name', 'str_to_replace', 'replace_with', 'match_words', - 'regex', - 'case_sensitive'] - Args: - parent: - - Returns: - - ''' - views = [['rules_ctrl', 'rules', '规则编辑', - [ - {'name': 'input_col_name', 'text': '输入流字段', 'init': '$ALL'}, - {'name': 'output_col_name', 'text': '输出流字段', 'init': ''}, - {'name': 'str_to_replace', 'text': '待替换数据', 'init': ''}, - {'name': 'replace_with', 'text': '替换为', 'init': ''}, - {'name': 'regex', 'text': '使用正则表达式', 'init': False}, - {'name': 'match_words', 'text': '全字匹配', 'init': True}, - {'name': 'case_sensitive', 'text': '大小写敏感', 'init': False} - ], - ] - ] - dlg = PMGPanelDialog(parent=parent, views=views) - - dlg.setMinimumSize(600, 480) - - dlg.panel.set_value({'rules': self.info['regulations']}) - dlg.exec_() - - self.info['regulations'] = dlg.panel.get_value()['rules'] diff --git a/pyminer/pmgwidgets/flowchart/nodes/docparser.py b/pyminer/pmgwidgets/flowchart/nodes/docparser.py deleted file mode 100644 index 8ff6bc0c..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/docparser.py +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Callable -import json - - -def parse_doc(function: Callable): - doc: str = function.__doc__ - row_iter = filter(lambda s: s != '', doc.split('\n')) - dic = {} - for row in row_iter: - split_list = row.split(':') - if len(split_list) == 2: - var_name, value_str = split_list - var_name = var_name.strip() - value_str = value_str.strip() - if var_name == 'input' or var_name == 'output': - assert value_str.startswith('[') and value_str.endswith(']') - try: - dic[var_name] = json.loads(value_str.strip()) - except: - raise Exception(repr(value_str.strip()) + ' cannot be parsed as a list!') - else: - dic[var_name] = value_str - else: - continue - assert isinstance(dic.get('input'), list), '\'input\' is not defined.' - assert isinstance(dic.get('output'), list) is not None, '\'output\' is not defined.' - print(dic) - - -if __name__ == '__main__': - from pmgwidgets.flowchart.nodes.reliabilities import relia_and - - doc = relia_and.__doc__ - print(doc) - parse_doc(relia_and) diff --git a/pyminer/pmgwidgets/flowchart/nodes/io/__init__.py b/pyminer/pmgwidgets/flowchart/nodes/io/__init__.py deleted file mode 100644 index 2502bf1c..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/io/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .iterator import Iterator -from .listdir import ListDirs -from .pdimport import PandasImport, PandasFileImport diff --git a/pyminer/pmgwidgets/flowchart/nodes/io/iterator.py b/pyminer/pmgwidgets/flowchart/nodes/io/iterator.py deleted file mode 100644 index 066acf13..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/io/iterator.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -有无办法通过迭代器方式递归实现流程图的迭代仿真? -""" -import sys -import time -from typing import List, Union, Tuple, Dict, TYPE_CHECKING, Callable -from pmgwidgets import PMGFlowContent, PMGPanelDialog - -if TYPE_CHECKING: - import pandas as pd - - -class Iterator(PMGFlowContent): - - def __init__(self): - super(Iterator, self).__init__() - self.input_args_labels = [] - self.output_ports_labels = ['取样'] # , '检验'] - self.class_name = 'Iterator' - self.text = '迭代器' - self.icon_path = '' - self.info = {'sampling_rate': 0.2} - - def process(self, *args) -> List: - """ - 基础迭代器 - Args: - *args: - - Returns: - - """ - for i in range(10): - yield [i] - - def on_settings_requested(self, parent): - """ - - Args: - parent: - - Returns: - - """ - views = [('numberspin_ctrl', 'sampling_rate', '抽样比率', self.info['sampling_rate'], '', (0, 1), 0.0001)] - dlg = PMGPanelDialog(parent=parent, views=views) - - dlg.setMinimumSize(600, 480) - dlg.exec_() - - self.info['sampling_rate'] = dlg.panel.get_value()['sampling_rate'] - - -if __name__ == '__main__': - import sys - - from PySide2.QtWidgets import QApplication - - app = QApplication(sys.argv) - - # r.load_info({'gen_array': False, 'size': (1, 2, 3), 'type': 'normal'}) - # r.process() - info = {'sampling_rate': 0.2} - r = Iterator() - r.load_info(info) - r.on_settings_requested(None) - print(r.info) - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/flowchart/nodes/io/listdir.py b/pyminer/pmgwidgets/flowchart/nodes/io/listdir.py deleted file mode 100644 index 31248e47..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/io/listdir.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -有无办法通过迭代器方式递归实现流程图的迭代仿真? -""" -import os -import sys -import time -from typing import List, Union, Tuple, Dict, TYPE_CHECKING, Callable -from pmgwidgets import PMGFlowContent, PMGPanelDialog - -if TYPE_CHECKING: - import pandas as pd - - -class ListDirs(PMGFlowContent): - - def __init__(self): - super(ListDirs, self).__init__() - self.input_args_labels = [] - self.output_ports_labels = ['路径'] # , '检验'] - self.class_name = 'ListDirs' - self.text = '文件列举' - self.icon_path = '' - self.info = { - 'ext_filter': '.csv', - 'dir': '' - } - - def process(self, *args) -> List: - """ - 基础迭代器 - Args: - *args: - - Returns: - - """ - ext = self.info['ext_filter'] - files = [path for path in os.listdir(self.info['dir']) if os.path.splitext(path)[1] == ext] - for file_path in files: - path = os.path.normcase(os.path.join(self.info['dir'], file_path)) - yield [path] - - def on_settings_requested(self, parent): - """ - - Args: - parent: - - Returns: - - """ - views = [ - ('folder_ctrl', 'dir', '选取路径', self.info['dir']), - ('line_ctrl', 'ext_filter', '扩展名类型', self.info['ext_filter']), - ] - dlg = PMGPanelDialog(parent=parent, views=views) - - dlg.setMinimumSize(600, 480) - dlg.exec_() - - self.info = dlg.panel.get_value() - - -if __name__ == '__main__': - import sys - - from PySide2.QtWidgets import QApplication - - app = QApplication(sys.argv) - - # r.load_info({'gen_array': False, 'size': (1, 2, 3), 'type': 'normal'}) - # r.process() - info = { - 'ext_filter': '.csv', - 'dir': '/home/' - } - r = ListDirs() - r.load_info(info) - r.on_settings_requested(None) - print(r.info) - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/flowchart/nodes/io/pdimport.py b/pyminer/pmgwidgets/flowchart/nodes/io/pdimport.py deleted file mode 100644 index bfe5d624..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/io/pdimport.py +++ /dev/null @@ -1,194 +0,0 @@ -""" -有无办法通过迭代器方式递归实现流程图的迭代仿真? -""" -import os -import sys -import time -from typing import List, Union, Tuple, Dict, TYPE_CHECKING, Callable -from pmgwidgets import PMGFlowContent, PMGPanelDialog, ErrorReporter, PANEL_VIEW_CLASS - -if TYPE_CHECKING: - import pandas as pd - - -def import_pandas(file: str, **kwargs): - if not isinstance(file, str): - raise ErrorReporter.create_type_error('File path', file, str) - if not os.path.exists(file): - raise ErrorReporter.create_file_not_found_error(file) - - import pandas as pd - - ext = os.path.splitext(file)[1] - kw = {'skiprows': kwargs['skiprows']} - if kwargs['limit_nrows'] == True: - kw['nrows'] = kwargs['nrows'] - if kwargs['find_header_in_table'] == True: - kw['header'] = kwargs['header'] - else: - kw['header'] = None - print(kw) - if ext == '.csv': - return [pd.read_csv(file, sep=kwargs['csv_sep'], **kw)] - elif ext == '.xls' or ext == '.xlsx': - return [pd.read_excel(file, **kw)] - else: - raise ValueError('Cannot Read file of this extension: \'%s\'' % ext) - - -class BaseTableImport(PMGFlowContent): - def __init__(self): - super().__init__() - self.info = { - 'sampling_rate': 0.2, 'file_path': '', - 'csv_sep': ',', - 'find_header_in_table': True, - 'skiprows': 0, - 'limit_nrows': False, - 'nrows': -1, - 'header': 0 - } - - def format_settings(self, views: PANEL_VIEW_CLASS) -> PANEL_VIEW_CLASS: - info = self.info - views += [ - [('combo_ctrl', 'csv_sep', 'CSV分隔符', info['csv_sep'], ['\t', ','], ['制表符(Tab,\\t)', '逗号(’,‘)'])], - ('numberspin_ctrl', 'skiprows', '跳过行数', info['skiprows'], '', (0, 100)), - [ - ('check_ctrl', 'find_header_in_table', '从表中获取列名', info['find_header_in_table']), - ('numberspin_ctrl', 'header', '表头行数', info['header'], '', (0, 100)), - ], [ - ('check_ctrl', 'limit_nrows', '限制最大行数', info['limit_nrows']), - ('numberspin_ctrl', 'nrows', '读取最大行数', info['nrows'], '', (0, 100000)), - ] - ] - return views - - def process(self) -> List: - """ - 基础迭代器 - Args: - *args: - - Returns: - - """ - return import_pandas(self.info['file_path'], **self.info) - # csv_sep=self.info['csv_sep'], skip_rows=self.info['skiprows'], - # first_row_as_header=self.info['find_header_in_table'], nrows=self.info['nrows'],limit_nrows = self.info['limit_nrows'] ) - - -class PandasFileImport(BaseTableImport): - def __init__(self): - super(PandasFileImport, self).__init__() - self.input_args_labels = [] - self.output_ports_labels = ['数据集'] # , '检验'] - self.class_name = 'PandasImport' - self.text = '读取Pandas数据集' - self.icon_path = '' - - def on_settings_requested(self, parent): - """ - - Args: - parent: - - Returns: - - """ - views = [ - ('file_ctrl', 'file_path', '导入文件的路径', self.info['file_path']), - ] - views = self.format_settings(views) - dlg = PMGPanelDialog(parent=parent, views=views) - dlg.setMinimumSize(600, 480) - dlg.exec_() - self.info = dlg.panel.get_value() - - def process(self) -> List: - """ - 基础迭代器 - Args: - *args: - - Returns: - - """ - return import_pandas(self.info['file_path'], **self.info) - - -class PandasImport(BaseTableImport): - - def __init__(self): - super(PandasImport, self).__init__() - self.input_args_labels = ['路径'] - self.output_ports_labels = ['数据集'] # , '检验'] - self.class_name = 'PandasImport' - self.text = '从上游路径\n输入Pandas数据集' - self.icon_path = '' - - def on_settings_requested(self, parent): - """ - - Args: - parent: - - Returns: - - """ - views = self.format_settings([]) - - dlg = PMGPanelDialog(parent=parent, views=views) - dlg.setMinimumSize(600, 480) - dlg.exec_() - self.info = dlg.panel.get_value() - - def process(self,path) -> List: - """ - 被调用时执行的代码 - Args: - *args: - - Returns: - - """ - return import_pandas(path, **self.info) - - -if __name__ == '__main__': - import sys - - from PySide2.QtWidgets import QApplication - - app = QApplication(sys.argv) - - info = {'sampling_rate': 0.2} - pj = lambda *s: os.path.normcase(os.path.join(*s)) - folder = pj(os.path.dirname(__file__), 'test_files') - r = PandasFileImport() - r.load_info({ - 'sampling_rate': 0.2, - 'file_path': pj(folder, 'test.xlsx'), - 'csv_sep': '\t', - 'find_header_in_table': True, - 'skiprows': 0, - 'limit_nrows': True, - 'nrows': 3, - 'header': 0 - }) - print(r.process()[0]) - - r.load_info({ - 'sampling_rate': 0.2, - 'file_path': pj(folder, 'test.csv'), - 'csv_sep': '\t', - 'find_header_in_table': False, - 'skiprows': 3, - 'limit_nrows': False, - 'nrows': -1, - 'header': 0 - }) - - print(r.process()[0]) - - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/flowchart/nodes/plots.py b/pyminer/pmgwidgets/flowchart/nodes/plots.py deleted file mode 100644 index 324aadb7..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/plots.py +++ /dev/null @@ -1,100 +0,0 @@ -import sys -from typing import List, Union, Tuple -from pmgwidgets import PMGFlowContent -import numpy as np -import matplotlib.pyplot as plt - - -class LinePlot(PMGFlowContent): - """ - 根据输入的数据,绘制一条直线。 - 允许输入的数据类型:多个端口的直线。 - - """ - - def __init__(self): - super(LinePlot, self).__init__() - self.input_args_labels = ['in1'] - self.output_ports_labels = [] - self.class_name = 'LinePlot' - self.text = '折线图' - self.icon_path = '' - self.agg = None - - # self.info = {'gen_array': False, 'size': (1, 2, 3), - # 'type': 'normal'} # 命名为self.info的变量会被自动保存,下一次会调用load_info方法进行读取。 - - def process(self, *args) -> List: - """ - - Args: - *args: - - Returns: - - """ - from packages.pmagg import PMAgg - for arg in args: - pass - if self.agg is None: - self.agg = PMAgg.Window() - - plt.plot([1, 2, 3, 4, 5]) - fig = plt.gcf() - self.agg.get_canvas(fig) - self.agg.show() - - return [] - - def check_data(self, data): - pass - - def load_info(self, info: dict): - print('load info!!!!!!!!!!') - self.info = info - print(self.info) - - -class HistPlot(PMGFlowContent): - """ - 根据输入的数据,绘制一条直线。 - 允许输入的数据类型:多个端口的直线。 - - """ - - def __init__(self): - super(HistPlot, self).__init__() - self.input_args_labels = ['in1'] - self.output_ports_labels = [] - self.class_name = 'HistPlot' - self.text = '条形图' - self.icon_path = '' - self.agg = None - - def process(self, *args) -> List: - """ - - Args: - *args: - - Returns: - - """ - from packages.pmagg import PMAgg - if self.agg is None: - self.agg = PMAgg.Window() - - plt.hist(x=args, bins=20, color='steelblue', edgecolor='black') - fig = plt.gcf() - self.agg.get_canvas(fig) - self.agg.show() - - return [] - - def check_data(self, data): - pass - - def load_info(self, info: dict): - print('load info!!!!!!!!!!') - self.info = info - print(self.info) diff --git a/pyminer/pmgwidgets/flowchart/nodes/random.py b/pyminer/pmgwidgets/flowchart/nodes/random.py deleted file mode 100644 index 85a57b18..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/random.py +++ /dev/null @@ -1,74 +0,0 @@ -import sys -from typing import List, Union, Tuple - -from PySide2.QtWidgets import QApplication, QDialog, QVBoxLayout, QLineEdit -from pmgwidgets import PMGFlowContent, PMGPanelDialog -import numpy as np - - -class Random(PMGFlowContent): - """ - 随机数生成的类 - 可以切换生成的数据类型是整数/浮点还是矩阵。 - - """ - - def __init__(self): - super(Random, self).__init__() - self.input_args_labels = [] - self.output_ports_labels = ['output1'] - self.class_name = 'Random' - self.text = '随机数生成' - self.icon_path = '' - - self.info = {'gen_array': False, 'size': (1, 2, 3), - 'type': 'normal'} # 命名为self.info的变量会被自动保存,下一次会调用load_info方法进行读取。 - - def process(self, *args) -> List[Union[int, float, np.ndarray]]: - """ - 事件处理的方法。 - Args: - *args: - - Returns: - - """ - if self.info['gen_array']: - if self.info['type'] == 'uniform': - return [np.random.random(size=self.info['size'])] - elif self.info['type'] == 'normal': - return [np.random.randn(*self.info['size'])] - else: - if self.info['type'] == 'uniform': - return [np.random.random()] - elif self.info['type'] == 'normal': - return [np.random.randn()] - - def on_settings_requested(self, parent): - """ - - Args: - parent: - - Returns: - - """ - assert len(self.info.keys()) > 0, 'info is empty.there maybe no information stored.' - views = [ - ('check_ctrl', 'gen_array', 'Generate Array', self.info['gen_array']), - ('eval_ctrl', 'size', 'Size', self.info['size'], 'safe'), - ('combo_ctrl', 'type', 'Type', self.info['type'], ['uniform', 'normal'], ['均匀分布', '正态分布']) - ] - dlg = PMGPanelDialog(parent=parent, views=views) - dlg.panel.set_param_changed_callback('gen_array', - lambda params: dlg.panel.get_ctrl('size').setEnabled(params['gen_array'])) - dlg.exec_() - value = dlg.panel.get_value() - self.load_info(value) - - def format_param(self) -> str: - return '模式:' + str(self.info['type']) - - def load_info(self, info: dict): - self.info = info - print(self.info) diff --git a/pyminer/pmgwidgets/flowchart/nodes/reliabilities.py b/pyminer/pmgwidgets/flowchart/nodes/reliabilities.py deleted file mode 100644 index db15bd49..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/reliabilities.py +++ /dev/null @@ -1,19 +0,0 @@ -def relia_or(*args): - """ - input:["*"] - output:["out"] - text:"and" - """ - pass - - -def relia_and(*args): - """ - input:["*"] - output:["out"] - text:"and" - """ - - -if __name__ == '__main__': - print(relia_and.__doc__) diff --git a/pyminer/pmgwidgets/flowchart/nodes/simplecalc.py b/pyminer/pmgwidgets/flowchart/nodes/simplecalc.py deleted file mode 100644 index 229ec40d..00000000 --- a/pyminer/pmgwidgets/flowchart/nodes/simplecalc.py +++ /dev/null @@ -1,78 +0,0 @@ -import sys -from typing import List - -from PySide2.QtWidgets import QApplication, QDialog, QVBoxLayout, QLineEdit -from pmgwidgets import PMFlowWidget, PMGFlowContent - - -class ContentDialog(QDialog): - def __init__(self, parent=None, initial_value: float = 0): - super().__init__(parent) - self.setLayout(QVBoxLayout()) - self.line_edit = QLineEdit() - self.layout().addWidget(self.line_edit) - self.line_edit.setText(str(initial_value)) - - -class Constant(PMGFlowContent): - def __init__(self): - super(Constant, self).__init__() - self.input_args_labels = [] - self.output_ports_labels = ['output1'] - self.class_name = 'Constant' - self.text = '常数' - self.icon_path = '' - self._value = 0 - - def process(self, *args) -> List[object]: - return [self._value] - - def on_settings_requested(self, parent): - dlg = ContentDialog(parent) - - dlg.exec_() - self._value = float(dlg.line_edit.text()) - print(self._value) - - def format_param(self) -> str: - return '值:' + str(self._value) - - -class Add(PMGFlowContent): - def __init__(self): - super(Add, self).__init__() - self.input_args_labels = ['in1', 'in2'] - self.output_ports_labels = ['out'] - self.class_name = 'Add' - self.text = '求和' - self.icon_path = '' - self.ports_changable = [True, False] - - def process(self, *args) -> List[object]: - if len(args) > 1: - sum = args[0] - for a in args[1:]: - sum += a - else: - raise ValueError - print(args[0], args[1]) - return [sum] - - -class Mul(PMGFlowContent): - def __init__(self): - super().__init__() - self.input_args_labels = ['in1', 'in2'] - self.output_ports_labels = ['out'] - self.class_name = 'Mul' - self.text = '乘积' - self.icon_path = '' - - def process(self, *args) -> List[object]: - if len(args) > 1: - mul = args[0] - for a in args[1:]: - mul *= a - else: - raise ValueError - return [mul] diff --git a/pyminer/pmgwidgets/flowchart/readme.md b/pyminer/pmgwidgets/flowchart/readme.md deleted file mode 100644 index ac623a91..00000000 --- a/pyminer/pmgwidgets/flowchart/readme.md +++ /dev/null @@ -1,136 +0,0 @@ -# 流程图 - -pmgwidgets.flowchart是流程图绘制子包。依赖于networkx和qtpy。 - -简单的示例可以直接执行`pmgwidgets/flowchart/flowchart_widget.py` - -## 组成部分 - -![组成部分](doc_figures/composition_structure.png) - -使用: - -```python -from pmgwidgets import PMFlowWidget -app = QApplication(sys.argv) -graphics = PMFlowWidget(path=r'C:/Users/12957/Desktop/乡土中国.pmcache') -graphics.show() -sys.exit(app.exec_()) -``` - -PMFlowWidget可以像普通的QWidget那样嵌套在任何位置。 - -启动参数: - -parent:指定父控件。 - -path:指定启动时加载的流程图。 - -PMFlowWidget暂时不支持清空重绘。可以销毁当前控件再新建一个控件。 - -## 操作 - -### 预留节点 - -很多节点是已经预留好的。比如求和、求积等。 - -### 添加节点 - -![添加节点](doc_figures/create_node.png) - -点击右键菜单的New,即可插入一个新的自定义节点。 - -也可单击节点菜单插入新的节点。 - -### 连线 - -单击节点的一个出端口即可开始连线,连线**必须终止于不同节点的入端口**,否则无法连接。 - - - -### 编辑节点 - -双击节点即可编辑 - -![节点编辑](doc_figures/edit_node.png) - -- Node Text:节点显示的文字信息 -- Set Inputs:输入节点端口编辑。点击`+`可以添加一个端口,点击`-`删除当前端口。双击选项可以编辑文字。 -- Set Outputs:输出节点编辑,和输入相同 -- Input Python Code:输入Python代码,是节点执行的内容。 -### 运行代码 -点击`Run`即可运行。节点代码执行后,会在此节点位置显示执行的输入输出结果。 - -执行之前情况如下![执行之前](doc_figures/before_run.png) - -执行之后情况如下: - -图片:image-20201017130216358 -路径:C:/Users/12957/AppData/Roaming/Typora/typora-user-images/image-20201017130216358.png -请检查此路径。 - -### 集成到程序中并运行代码 - -#### 在UI线程中直接运行代码 - -参考pmgwidgets/flowchart/tests/continously_data_process.py文件中的内容 -可以这样做: - -获取流程图的对象 - -```python -graphics = PMFlowWidget(path='continously_data_process.json') -graphics.show() -result = graphics.run_in_fg([1]) -``` -`run_in_fg`方法适用于有明显的开始和结束节点的情况。 - -在执行时,所有的节点将会进行**拓扑排序**。拓扑排序的目的,就是保证**节点的执行顺序符合用户连线的规定**。但是,当输入节点不唯一或输出节点不唯一时, -(输入节点指的是“有出无进”的节点,而输出节点指的是“有进无出”的节点。)不能保证第一个执行的节点具体是哪个输入节点,或者 -最末一个输出节点是哪个输出节点——由此,就会出现错误。所以目前输入参数只支持输入和输出节点唯一的情况。 - -`run_in_fg`的参数为一个列表(list),被传入第一个节点,然后以`*args`的方式展开为参数。返回值则是**最后一个节点的执行结果**。 -注意,第一个节点的参数和返回值都是list型,解包和打包操作在内部完成。 - -[TODO!]之后需要支持用户指定输入和输出节点! - -`run_in_fg`方法可以让我们的流程图直接在UI线程之中处理计算任务,并且直接获取输出值。对于耗时不明显的操作,直接在前端中处理更加及时、准确、直观。当然,如果希望在运行过程中屏蔽用户对流程图的操作(比如说,程序执行过程中删除某个节点,可能导致灾难性的后果),那么使用这个方法应当也是可以的。 - -当然,这对于UI线程而言,是本职工作之外的琐事。如果“琐事”消耗的时间太长,就会导致界面卡滞,严重影响用户体验。这样就需要在后台线程运行代码了。 - -#### 在后台线程中运行代码 - -[!TODO]接口已经留好,未完待续。。。 - -#### 插入预定义节点 - -在节点窗口中,点击“Add“可以创建一个自定义节点,双击列表项可以将节点插入到图形窗口中。点击‘‘Edit’’可以编辑当前选中的项。 - -自己新建的自定义节点将被保存。 - -### 自定义代码的规范 - -- 输入参数数量与输入端口数目相同 -- 输出参数需要用列表包裹起来,列表长度与输出端口数目相同 -- 输入参数从左到右依次为输入端口从上到下的值,输出参数从左到右依次为输出参数从左到右的值。 - -比如以下代码是规范的: - -```python -import time -def function(x): - return [x*2] -``` - -可以给函数添加默认值参数: - -```python -import time -def function(x=123): - return [x*2] -``` - - -## 示例 - -在pmgwidgets/flowchart/tests里面有一些示例可以供参考。 diff --git a/pyminer/pmgwidgets/flowchart/readme_arch.md b/pyminer/pmgwidgets/flowchart/readme_arch.md deleted file mode 100644 index 9662c7c2..00000000 --- a/pyminer/pmgwidgets/flowchart/readme_arch.md +++ /dev/null @@ -1,29 +0,0 @@ -# 流程图部分架构设计 -流程图由节点和连线组成。节点就是一个方框,连线就是连接不同方框之间的箭头。 - -## 图形元素 -### 节点 -节点由底板图形、端口、图标以及若干文字对象组成。 -- 端口就是节点与其他节点相连的结构。端口分为出和入两种,连线只能从某个节点的“出”端口出发,指向其他节点的“入”端口。 -- 图标需要存储在icons文件夹下面。 -- 文字对象主要包括:节点的文字标记、端口文字标记、状态显示文字。 - -当鼠标悬浮在节点上时,节点的底板图形会改变颜色;双击节点,即可弹出相关的设置界面。 - -每一个节点都有内容`content`。`content`里面包含节点中运行的函数等。 - -节点中的函数输入参数一一对应于端口,输出参数为一个列表,列表长度应当与输出端口相同,一一对应于输出端口。哪怕只有唯一一个输出参数,也应该用中括号括成列表的形式。 - -节点有预定义好的节点,存储在pandas的dataframe里面。 - -如果要继承节点,那么就继承content。节点的图形部分还是完全相同的。 - -### 连线 -连线是由多个直线组成的折线。它的主要参数就是起点端口和终点端口。除了两端的端口之外,还有若干中继点。一个有n段的折线,包含n-1个中继点。 - -第一段直线从起点端口出发,走向第一个中继点;后面的直线从前一个中继点到下一个中继点。最后一条直线的终点也就是连线的终点端口。中继节点存在列表中。 - -双击任意一条连线,即可在相应位置插入一个中继点。插入操作同时也对中继节点列表以及连线列表进行了一次插入。插入之后,触发一次重绘事件。 - -双击中继节点可以删除此中继节点。这个操作会弹出中继节点列表中的节点,同时也触发一次重绘事件。 - diff --git a/pyminer/pmgwidgets/flowchart/simulationwidget.py b/pyminer/pmgwidgets/flowchart/simulationwidget.py deleted file mode 100644 index ef691916..00000000 --- a/pyminer/pmgwidgets/flowchart/simulationwidget.py +++ /dev/null @@ -1,149 +0,0 @@ -""" -node properties: -id:str -text:str -icon:str(path of icon) -ports:{} -content:{} - -properties of contents: -code:str -type:str -params:List[str] -""" -import json -import os -import sys -import time -from typing import List, Dict - -from pmgwidgets.flowchart.core.flow_content import FlowContentForFunction, flowcontent_types, PMGFlowContent - -from pmgwidgets.flowchart.core.flow_node import Node -from pmgwidgets.flowchart.core.nodemanager import NodeManagerWidget -from pmgwidgets.flowchart.core.flowchart_scene import PMGraphicsScene -from pmgwidgets.flowchart.core.flowchart_widget import PMGraphicsView -from PySide2.QtCore import QSize, QCoreApplication, QLineF, Qt, QThread, Signal -from PySide2.QtGui import QColor, QKeyEvent, QWheelEvent, QCloseEvent -from PySide2.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QToolButton, QSpacerItem, QSizePolicy, QGraphicsView, \ - QFrame, QApplication, QFileDialog, QMessageBox -from pmgwidgets.flowchart.core import PMFlowWidget - -COLOR_NORMAL = QColor(212, 227, 242) -COLOR_HOVER = QColor(255, 200, 00) -COLOR_HOVER_PORT = QColor(0, 0, 50) - - -class PMGSimulationWidget(PMFlowWidget): - def __init__(self, parent=None, path=''): - super().__init__(parent, path) - self._path = path - _translate = QCoreApplication.translate - self.setObjectName("tab_flow") - self.base_layout = QHBoxLayout(self) - self.verticalLayout_6 = QVBoxLayout() - self.base_layout.addLayout(self.verticalLayout_6) - self.verticalLayout_6.setContentsMargins(0, 0, 0, 0) - self.verticalLayout_6.setSpacing(0) - self.verticalLayout_6.setObjectName("verticalLayout_6") - self.widget_3 = QWidget(self) - self.widget_3.setMinimumSize(QSize(0, 30)) - self.widget_3.setObjectName("widget_3") - - # self.horizontal_layout_down = QHBoxLayout(self.widget_3) - self.horizontal_layout = QHBoxLayout(self.widget_3) - self.horizontal_layout.setContentsMargins(0, 0, 0, 0) - self.horizontal_layout.setSpacing(1) - self.horizontal_layout.setObjectName("horizontalLayout_6") - - self.tool_button_run_fg = QToolButton(self.widget_3) - self.tool_button_run_fg.setText('Run_fg') - self.horizontal_layout.addWidget(self.tool_button_run_fg) - - self.tool_button_save = QToolButton(self.widget_3) - self.tool_button_save.setText('Save') - self.horizontal_layout.addWidget(self.tool_button_save) - - self.tool_button_reset = QToolButton(self.widget_3) - self.tool_button_reset.setText('Reset') - self.horizontal_layout.addWidget(self.tool_button_reset) - - self.tool_button_undo = QToolButton(self.widget_3) - self.tool_button_undo.setText('Undo') - self.horizontal_layout.addWidget(self.tool_button_undo) - - self.tool_button_redo = QToolButton(self.widget_3) - self.tool_button_redo.setText('Redo') - self.horizontal_layout.addWidget(self.tool_button_redo) - - spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - self.horizontal_layout.addItem(spacerItem) - self.verticalLayout_6.addWidget(self.widget_3) - - self.graphicsView = PMGraphicsView(self) - - self.graphicsView.setFrameShape(QFrame.NoFrame) - self.graphicsView.setObjectName("graphicsView") - self.verticalLayout_6.addWidget(self.graphicsView) - - self.scene = PMGraphicsScene(graphics_view=self.graphicsView, flow_widget=self, allow_multiple_input=True) - self.scene.setSceneRect(-1000, -1000, 2000, 2000) - - self.node_manager = NodeManagerWidget(scene=self.scene) - # self.node_manager.scene = self.scene - self.base_layout.addWidget(self.node_manager) - self.nodes: List[Node] = self.scene.nodes - self.lines = self.scene.lines - - self.node_manager.register_node_content(PMGFlowContent, 'simple_calc', 'UserDefinedFunc') - self.load_nodes_library() - self.graphicsView.setScene(self.scene) - - self.tool_button_undo.clicked.connect(self.scene.undo) - self.tool_button_redo.clicked.connect(self.scene.redo) - # self.tool_button_open.clicked.connect(self.open) - self.tool_button_reset.clicked.connect(self.reset) - self.tool_button_save.clicked.connect(self.save) - self.tool_button_run_fg.clicked.connect(lambda: self.run_in_fg()) - if self._path != '': - self.scene.load_flowchart(self._path) - - # def load_nodes_library(self): - # import pmgwidgets.flowchart.nodes.simulation as package_sim - # import inspect - # for class_name in dir(package_sim): - # cls = eval('package_sim.' + class_name) - # if inspect.isclass(cls) and issubclass(cls, package_sim.BaseLigralGenerator): - # self.node_manager.register_node_content(cls, 'simple_calc') - - def run_in_fg(self, input_args_list: List[object] = None) -> List[object]: - """ - 前端直接进行数据处理,而非在后台线程执行。 - 这样不能做耗时操作(因为会卡住界面),但是可以直接获取运行后的数据,并且结果相对简单一些。 - :return: - """ - from pmgwidgets.flowchart.nodes.simulation import BaseLigralGenerator - j_list = [] - for node in self.scene.nodes: - content: BaseLigralGenerator = node.content - j_list.append(content.generate_ligjson()) - print(content.generate_ligjson()) - text = json.dumps(j_list, indent=4) - print(text) - ligral_path = r'c:\users\12957\Desktop\ligral.exe' - file_path = os.path.join(os.path.dirname(__file__), 'temp.lig.json') - with open(file_path, 'w')as f: - f.write(text) - from pmgwidgets.utilities.platform import run_command_in_terminal_block - run_command_in_terminal_block('%s %s --json' % (ligral_path, file_path)) - - -if __name__ == '__main__': - import cgitb - - cgitb.enable() - app = QApplication(sys.argv) - graphics = PMGSimulationWidget() - graphics.load('flowchart_stat.pmcache') - graphics.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/flowchart/tests/__init__.py b/pyminer/pmgwidgets/flowchart/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/flowchart/tests/continously_data_process.py b/pyminer/pmgwidgets/flowchart/tests/continously_data_process.py deleted file mode 100644 index d7410133..00000000 --- a/pyminer/pmgwidgets/flowchart/tests/continously_data_process.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -DO] add a table to store some informations about calculation. -""" -import sys -import time - -from PySide2.QtCore import QTimer -from PySide2.QtWidgets import QApplication - -from pmgwidgets.flowchart.core.flowchart_widget import PMFlowWidget - -if __name__ == '__main__': - app = QApplication(sys.argv) - graphics = PMFlowWidget(path='continously_data_process.json') - graphics.show() - graphics.pre_run() - graphics.run_in_fg() - timer = QTimer() - timer.start(100) - i = 0 - - - def run_fg(): - """ - 在前端直接运行代码 - :return: - """ - t0 = time.time() - global i,timer - i += 1 - result = graphics.run_fg_for_one_step() - print('exec result:', result) - if i>100: - timer.stop() - t1 = time.time() - print('time elapsed %f'%(t1-t0)) - - - timer.timeout.connect(run_fg) - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/flowchart/tests/database_import.py b/pyminer/pmgwidgets/flowchart/tests/database_import.py deleted file mode 100644 index 78d5405a..00000000 --- a/pyminer/pmgwidgets/flowchart/tests/database_import.py +++ /dev/null @@ -1,16 +0,0 @@ -import sys -import time - -from PySide2.QtCore import QTimer -from PySide2.QtWidgets import QApplication - -from pmgwidgets.flowchart.core.flowchart_widget import PMFlowWidget -import cgitb -cgitb.enable() -if __name__ == '__main__': - - times = {True: 0, False: 1} - app = QApplication(sys.argv) - graphics = PMFlowWidget(path='database_import.json') - graphics.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/flowchart/tests/fault_tree.py b/pyminer/pmgwidgets/flowchart/tests/fault_tree.py deleted file mode 100644 index 84e21da7..00000000 --- a/pyminer/pmgwidgets/flowchart/tests/fault_tree.py +++ /dev/null @@ -1,46 +0,0 @@ -import sys -import time - -from PySide2.QtCore import QTimer -from PySide2.QtWidgets import QApplication - -from pmgwidgets.flowchart.core.flowchart_widget import PMFlowWidget - -if __name__ == '__main__': - times = {True: 0, False: 1} - app = QApplication(sys.argv) - graphics = PMFlowWidget(path='fault_tree.json') - graphics.show() - graphics.pre_run() - graphics.run_in_fg() - timer = QTimer() - timer.start(1) - i = 0 - - - def run_fg(): - """ - 在前端直接运行代码 - :return: - """ - t0 = time.time() - global i, timer - steps = 100 - for j in range(steps): - i += 1 - # result = graphics.run_in_fg([]) - - result = graphics.run_fg_for_one_step() - times[result[0]] += 1 - - print('exec result:', result) - if i > 10000: - timer.stop() - t1 = time.time() - - print('Run Times:%d,Reliability is %f' % (i, times[True] / (times[True] + times[False]))) - print('time elapsed %f' % (t1 - t0)) - - - timer.timeout.connect(run_fg) - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/flowchart/tests/node_test.py b/pyminer/pmgwidgets/flowchart/tests/node_test.py deleted file mode 100644 index da219b9c..00000000 --- a/pyminer/pmgwidgets/flowchart/tests/node_test.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -from typing import List, Union - -from PySide2.QtWidgets import QApplication, QDialog, QVBoxLayout, QLineEdit -# from pmgwidgets.flowchart.nodes.random import Random -# from pmgwidgets.flowchart.nodes.plots import HistPlot -from pmgwidgets.flowchart.nodes.dfoperation import DataReplace -import numpy as np - -if __name__ == '__main__': - app = QApplication(sys.argv) - - # r.load_info({'gen_array': False, 'size': (1, 2, 3), 'type': 'normal'}) - # r.process() - info = { - 'regulations': [ - {'input_col_name': 'aa', 'output_col_name': 'aa', 'str_to_replace': 'aa', 'replace_with': 'dddd', - 'match_words': True, 'regex': False, 'case_sensitive': False}]} - r = DataReplace() - r.load_info(info) - r.on_settings_requested(None) - sys.exit(app.exec_()) diff --git "a/pyminer/pmgwidgets/flowchart/\345\210\233\345\273\272\346\226\260\350\212\202\347\202\271(deprecated).md" "b/pyminer/pmgwidgets/flowchart/\345\210\233\345\273\272\346\226\260\350\212\202\347\202\271(deprecated).md" deleted file mode 100644 index 1e526bf5..00000000 --- "a/pyminer/pmgwidgets/flowchart/\345\210\233\345\273\272\346\226\260\350\212\202\347\202\271(deprecated).md" +++ /dev/null @@ -1,54 +0,0 @@ -# 如何创建一个新的节点类 - - -## 添加新节点类 -点击Add按钮添加一个节点 -![](doc_figures/click_right_top_add_button.png) -## 编辑 -选中新增的`untitled`项,并且点击Edit编辑。 -![](doc_figures/click_edit_button.png) -弹出编辑面板效果如下: -![](doc_figures/popup_edit_panel.png) -编辑面板的含义如下: -![](doc_figures/edit_panel_meaning.png) - -## 实例 - -若要创建一个数据库连接节点,我们将其抽象为: - -- 节点文字:DBConn -- 输入端口没有,输出端口一个,数量不得改变。输出端口命名为‘db’ -- 图标暂不设置,使用默认图标 -- 组名称为IO(可以点击下拉菜单切换组名称) - -- 设置信息:ip地址、端口、用户名、密码。因此需要根据pmgwidgets的方式编写设置面板的json。 - -编写后的效果如下: -![](doc_figures/sketch_after_edit.png) - -其中,函数的输入只是一个实例。最后一栏的JSON全文如下: - -```json -[ - ['line_ctrl', 'user_name', 'User Name', '12000'], - ['line_ctrl', 'password', 'Password', 'abcdef'], - ['line_ctrl', 'ip', 'IP', '127.0.0.1'], - ['number_ctrl', 'port', 'Port', 12306, '', [0, 65535]] -] -``` - -点击`Check`按钮可以检验输入框的效果,弹出的对话框将反映你写的json可否正确的被转换为界面元素。 -![](doc_figures/check_json.png) - -直接点击右上角叉号退出对话框即可,你的变更将被自动保存。对话框关闭的瞬间,所做的变更将被存储到磁盘中,无需担心数据丢失。 - -## 新建节点 - -双击“DBConn”列表项,即可插入一个DBConn节点。 - -点击右键“Edit”,即可编辑它。 -![](doc_figures/custom_node.png) -弹出的设置面板效果如图: -![](doc_figures/configure_panel.png) - -点击“x”号,信息也会自动保存。 \ No newline at end of file diff --git a/pyminer/pmgwidgets/utilities/__init__.py b/pyminer/pmgwidgets/utilities/__init__.py deleted file mode 100644 index 129155fd..00000000 --- a/pyminer/pmgwidgets/utilities/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .platform import * -from .source import * -from .uilogics import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/utilities/network/__init__.py b/pyminer/pmgwidgets/utilities/network/__init__.py deleted file mode 100644 index 57b89290..00000000 --- a/pyminer/pmgwidgets/utilities/network/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .baseclient import BaseClient, get_style_sheet -from .generalclient import GeneralClient -from .qtclient import PMClient -from .server import PMGServer -from .util import timeit diff --git a/pyminer/pmgwidgets/utilities/network/baseclient.py b/pyminer/pmgwidgets/utilities/network/baseclient.py deleted file mode 100644 index 0666f09a..00000000 --- a/pyminer/pmgwidgets/utilities/network/baseclient.py +++ /dev/null @@ -1,289 +0,0 @@ -import base64 -import json -import socket -import sys -import time -from typing import List, Union, Dict, Any - -import cloudpickle - -from pmgwidgets.utilities.network.util import generate_client_payload, strip_byte_end - - -def get_style_sheet() -> str: - return BaseClient().get_style_sheet() - - -class BaseClient(object): - def __init__(self, name='Anonymous BaseClient'): - self.name = name - - def init_socket(self, port: int = 12306): - host = 'localhost' - client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # 在客户端开启心跳维护 - client.connect((host, port)) - return client - - def get_var(self, data_name: str): - """ - 从工作空间获取数据 - :param data_name: - :return: - """ - payload = self.generate_request_template() - payload['method'] = 'read_p' - payload['params'] = [data_name] - - response_dic = self.send_dict_and_get_request_dict(payload) - if response_dic.get('message') == 'succeeded': - data_b64 = response_dic.get(data_name) - s = self.load_data_from_b64(data_b64) - return s - else: - raise ValueError(response_dic.get('message')) - - def dump_data_from_b64(self, data: Any) -> str: - try: - data_dumped_bytes = cloudpickle.dumps(data) - return base64.b64encode(data_dumped_bytes).decode('ascii') - except: - return '' - - def load_data_from_b64(self, data_b64: str) -> object: - try: - return cloudpickle.loads(base64.b64decode(data_b64)) - except: - import traceback - traceback.print_exc() - return None - - def delete_var(self, var_name: Union[str, List[str]], provider: str): - payload = self.generate_request_template() - payload['method'] = 'delete_variable' - payload['params'] = [var_name, provider] - response_dic = self.send_dict_and_get_request_dict(payload) - if response_dic['message'] == 'succeeded': - return response_dic['var_name'] - else: - return [] - - def get_all_public_var_names(self): - """ - 获取所有的可由外部获取的变量 - :return: - """ - - payload = self.generate_request_template() - payload['method'] = 'get_all_public_variable_names' - payload['params'] = [] - response_dic = self.send_dict_and_get_request_dict(payload) - if response_dic['message'] == 'succeeded': - return response_dic['var_names'] - else: - return [] - - def get_all_var_names(self): - """ - 获取所有的变量名称 - :return: - """ - payload = self.generate_request_template() - payload['method'] = 'get_all_variable_names' - payload['params'] = [] - response_dic = self.send_dict_and_get_request_dict(payload) - if response_dic['message'] == 'succeeded': - return response_dic['var_names'] - else: - return [] - - def set_var_dic(self, var_dic: dict, provider: str = 'server'): - """ - 设置种类 - :param var_dic: - :param provider: - :return: - """ - t0 = time.time() - dic = {} - for k in var_dic.keys(): - try: - b64 = self.dump_data_from_b64(var_dic[k]) - dic[k] = b64 - except: - import traceback - traceback.print_exc() - pass - dumped_data = self.dump_data_from_b64(dic) - payload = self.generate_request_template() - payload['method'] = 'write_var_dic' - payload['params'] = [dumped_data, provider] - t2 = time.time() - response_dic = self.send_dict_and_get_request_dict(payload) - t1 = time.time() - # print('set variable dict time elapsed %f s, with transfering consumed %f s.' % (t1 - t0, t1 - t2)) - return response_dic - - def get_all_vars(self): - # print('set variable dict time elapsed %f' % (t1 - t0)) - payload = self.generate_request_template() - payload['method'] = 'get_var_dic' - payload['params'] = [] - response_dic = self.send_dict_and_get_request_dict(payload) - if response_dic.get('var_dic') is not None: - b = response_dic.get('var_dic') - return self.load_data_from_b64(b) - else: - return response_dic - - def get_vars(self, var_names: str): - payload = self.generate_request_template() - payload['method'] = 'get_vars' - payload['params'] = [var_names] - response_dic = self.send_dict_and_get_request_dict(payload) - if response_dic.get('var_dic') is not None: - b = response_dic.get('var_dic') - return self.load_data_from_b64(b) - else: - return response_dic - return - - def get_all_var_names_of_type(self, type: str): - """ - 获取一定类型的数据。 - :param type: - :return: - """ - assert type in ['string', 'array', 'table', 'numeric'] - payload = self.generate_request_template() - payload['method'] = 'get_all_var_names_of_type' - payload['params'] = [type] - response_dic = self.send_dict_and_get_request_dict(payload) - if response_dic.get('message') == 'succeeded': - b = response_dic.get('var_names') - return self.load_data_from_b64(b) - else: - return [] - - def set_var(self, data_name: str, data: Any, provider: str = 'server'): - """ - 向数据管理类中写入数据 - Args: - data_name: - data: - provider: - - Returns: - - """ - if sys.getsizeof(data) / (1024 * 1024) > 150: - raise MemoryError('Data \'%s\' size %f MB is larger than limit ( 150MB ) .' % ( - data_name, sys.getsizeof(data) / 1024 / 1024)) - dumped_data = self.dump_data_from_b64(data) - message = 'Data size after b64 encode %f MB is too large,it should less than 300MB after base64 encoded.\n ' % ( - sys.getsizeof(dumped_data) / 1024 / 1024) - - assert sys.getsizeof( - dumped_data) / 1024 / 1024 <= 300, MemoryError(message) - - payload = self.generate_request_template() - payload['method'] = 'write_p' - payload['params'] = [data_name, dumped_data, provider] - response_dic = self.send_dict_and_get_request_dict(payload) - return response_dic - - def get_settings(self) -> dict: - """ - 获取主界面的设置项。 - :return: - """ - payload = self.generate_request_template() - payload['method'] = 'get_settings' - payload['params'] = [] - result_dic = self.send_dict_and_get_request_dict(payload) - assert result_dic is not None - return result_dic - - def set_settings_param(self, param_name: str, param_val: Any): - payload = self.generate_request_template() - payload['method'] = 'set_settings_param' - payload['params'] = [param_name, param_val] - result_dic = self.send_dict_and_get_request_dict(payload) - assert result_dic is not None - return result_dic - - def get_style_sheet(self) -> str: - """ - 获取主界面的样式表 - :return: - """ - payload = self.generate_request_template() - payload['method'] = 'get_style_sheet' - payload['params'] = [] - result = self.send_dict_and_get_request_dict(payload).get('style_sheet') - assert result is not None - return result - - def request_data(self, byte_data) -> bytes: - HOST = '127.0.0.1' - PORT = 12306 - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 定义socket类型,网络通信,TCP - s.settimeout(5) - s.connect((HOST, PORT)) # 要连接的IP与端口 - payload = self.generate_request_template() - payload['method'] = 'request_data' - s.send(json.dumps(payload).encode('utf-8')) - msg = s.recv(1024) - s.sendall(byte_data + b'PMEND') # 把命令发送给对端 - recv_list = [] - while (1): - b = s.recv(65536) - recv_list.append(b) - if b.endswith(b'PMEND'): - recv_list[-1] = strip_byte_end(recv_list[-1]) - break - data = b''.join(recv_list) # 把接收的数据定义为变量 - - s.close() # 关闭连接 - return data - - def generate_request_template(self) -> Dict[str, Union[List, str]]: - template = generate_client_payload() - template['name'] = self.name - return template - - def send_dict_and_get_request_dict(self, dict_to_send: Dict) -> Dict[str, Union[Dict, List, str, float, int]]: - try: - dict_byte = json.dumps(dict_to_send).encode('utf-8') - data_byte = self.request_data(dict_byte) - return json.loads(data_byte) - except TypeError: - import traceback - traceback.print_exc() - raise TypeError( - 'Cannot dump this object \'%s\' due to its type cannot be json serialized.' % repr(dict_to_send)) - except json.decoder.JSONDecodeError: - import traceback - traceback.print_exc() - raise ValueError('Cannot decode this json: \'%s\'' % str(data_byte)) - except ConnectionRefusedError: - raise ConnectionRefusedError('Connection Refused!') - except: - import traceback - traceback.print_exc() - - -if __name__ == '__main__': - import numpy as np - - dic = { - 'a': np.ndarray([200, 200]), - 'b': np.ndarray([200, 200]), - 'c': np.ndarray([200, 200]), - } - t0 = time.time() - bc = BaseClient() - a = bc.set_var_dic(dic) - # s = bc.get_all_var_names_of_type('table') - t1 = time.time() - print(t1 - t0) diff --git a/pyminer/pmgwidgets/utilities/network/generalclient.py b/pyminer/pmgwidgets/utilities/network/generalclient.py deleted file mode 100644 index d9655f3a..00000000 --- a/pyminer/pmgwidgets/utilities/network/generalclient.py +++ /dev/null @@ -1,94 +0,0 @@ -# coding=utf-8 -""" -client端 -长连接,短连接,心跳 -""" -import json -import threading -import zlib -from typing import List - -import time - -from .util import timeit, receive -from .baseclient import BaseClient - - -def parse_splicing_packets(packet_bytes: bytes) -> List[bytes]: - return packet_bytes.split(b'PMEND') - - -class GeneralClient(BaseClient): - - def __init__(self, name: str = 'Anonymous GeneralClient'): - super().__init__(name) - self.client = self.init_socket(12306) - self.name = name - th = threading.Thread(target=self.run_event_loop) - th.setDaemon(True) - th.start() - - def shut_down(self): - self.client.close() - - def on_server_message_received(self, packet: bytes): - try: - dic = json.loads(packet) - msg = dic.get('message') - if msg == 'data_changed': - pass - except: - import traceback - traceback.print_exc() - pass - - @timeit - def compress(self, byte_str): - return zlib.compress(byte_str) - - def run_event_loop(self): - payload = { - "method": "start_long_connection", - "name": self.name, - "params": [], - "id": 0, - } - self.client.sendall(json.dumps(payload).encode('utf-8') + b'PMEND') - recv = receive(self.client) - - message_dic = json.loads(recv) - if message_dic.get('message') == 'succeeded': - while True: - try: - recv = receive(self.client) - packets = parse_splicing_packets(recv) - for packet in packets: - self.on_server_message_received(packet) - except: - import traceback - traceback.print_exc() - break - else: - raise ConnectionError(message_dic.get('content')) - - -if __name__ == '__main__': - import numpy as np - - x = np.random.random(10) + np.linspace(1, 10, 10) - y = np.random.random(10) + np.linspace(1, 10, 10) - print(x) - c = GeneralClient() - - print('set_var') - c.set_var('x', x) - c.set_var('y', y) - c.set_var('z', y) - c.set_var('w', y) - c.set_var('t', y) - c.set_var('y', y) - c.get_var('x') - print(c.get_all_vars()) - print(c.get_all_var_names()) - while (1): - time.sleep(1) diff --git a/pyminer/pmgwidgets/utilities/network/qtclient.py b/pyminer/pmgwidgets/utilities/network/qtclient.py deleted file mode 100644 index c177b3da..00000000 --- a/pyminer/pmgwidgets/utilities/network/qtclient.py +++ /dev/null @@ -1,125 +0,0 @@ -# coding=utf-8 -__author__ = '侯展意' - -import json -import logging -import socket -import sys -import warnings -import zlib -from typing import List - -from PySide2.QtCore import QObject, QThread, Signal, QTimer -from PySide2.QtWidgets import QApplication - -from .baseclient import BaseClient -from .util import timeit, receive - -logger = logging.getLogger(__name__) - - -def parse_splicing_packets(packet_bytes: bytes) -> List[bytes]: - return packet_bytes.split(b'PMEND') - - -class RecvWork(QObject): - signal_received = Signal(bytes) - - def __init__(self, sock: socket.socket, name: str): - super(RecvWork, self).__init__() - self.quit = False - self.socket = sock - self.name = name - - def work(self): - payload = { - "method": "start_long_connection", - "name": self.name, - "id": 0, - } - self.socket.sendall(json.dumps(payload).encode('utf-8') + b'PMEND') - while True: - try: - recv = receive(self.socket) - assert recv != b'' - packets = parse_splicing_packets(recv) - for p in packets: - self.signal_received.emit(p) - except AssertionError: - self.socket.close() - warnings.warn('Connection \'%s\' Closed!' % self.name) - break - except: - import traceback - traceback.print_exc() - break - self.thread().quit() - - def close_socket(self): - self.socket.close() - - -class PMClient(QObject, BaseClient): - signal_server_message_received = Signal(dict) - signal_data_changed = Signal(str) - - def __init__(self, parent=None, name='Anonymous QtClient'): - super().__init__(parent) - self.name = name - self.client = self.init_socket(12306) - self.thread_recv = QThread() - self.worker_recv = RecvWork(self.client, self.name) - self.signal_received = self.worker_recv.signal_received - self.worker_recv.signal_received.connect(self.on_server_message_received) - - self.worker_recv.moveToThread(self.thread_recv) - self.thread_recv.started.connect(self.worker_recv.work) - self.thread_recv.start() - - def shut_down(self): - logger.info('client quit') - self.worker_recv.close_socket() - self.thread_recv.quit() - self.thread_recv.wait(500) - - def on_server_message_received(self, packet: bytes): - try: - dic = json.loads(packet) - logger.info(dic) - msg = dic.get('message') - if msg == 'data_changed': - data_name = dic.get('data_name') - if data_name is not None: - self.signal_data_changed.emit(data_name) - self.signal_server_message_received.emit(dic) - except: - import traceback - traceback.print_exc() - pass - - def send_bytes(self, packet: bytes): - self.client.sendall(packet) - - @timeit - def compress(self, byte_str): - return zlib.compress(byte_str) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - import numpy as np - - x = np.random.random(10) + np.linspace(1, 10, 10) - y = np.random.random(10) + np.linspace(1, 10, 10) - print(x) - c = PMClient() - print('set_var') - c.set_var('x', x) - c.set_var('y', y) - c.get_var('x') - print(c.get_all_var_names()) - timer = QTimer() - timer.start(10000) - timer.timeout.connect(lambda: c.get_var('x')) - c.shut_down() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/utilities/network/server.py b/pyminer/pmgwidgets/utilities/network/server.py deleted file mode 100644 index f69a0dc0..00000000 --- a/pyminer/pmgwidgets/utilities/network/server.py +++ /dev/null @@ -1,215 +0,0 @@ -""" -基于qthread的服务器 -直接基于socket。 - -""" - -import json -import logging -import socket -import sys -import time -from typing import List, Tuple, Dict, Union - -from PySide2.QtCore import QObject, QThread, QTimer -from PySide2.QtWidgets import QApplication - -from .util import receive, strip_byte_end - -logger = logging.getLogger(__name__) - - -def parse_splicing_packets(packet_bytes: bytes) -> List[bytes]: - """ - 处理粘包问题的函数 - :param packet_bytes: - :return: - """ - return packet_bytes.split(b'PMEND') - - -def dict_to_byte_msg(dic: Dict) -> bytes: - b = (json.dumps(dic) + 'PMEND').encode('utf-8') - return b - - -def generate_response_template() -> Dict[str, Union[str, int, Dict, List, float]]: - payload = {'message': 'succeeded', 'content': '', 'timestamp': time.time()} - return payload - - -def send_dict(sock: socket.socket, dic: Dict): - sock.sendall(dict_to_byte_msg(dic)) - - -class LoopWork(QObject): - def __init__(self, server_obj: 'PMGServer', server_socket: socket.socket): - super().__init__() - self.server_socket = server_socket - self.server_obj = server_obj - self.threads = [] - - def work(self): - self.accept_client(self.server_socket) - - def accept_client(self, server_socket): - """ - 接收新连接. - 请求长连接的时候就把连接放到连接池中 - 请求短链接的时候就直接处理。 - TODO:一眼望去圈复杂度太大,需要重构! - """ - while True: - try: - sock, _ = server_socket.accept() # 阻塞,等待客户端连接 - # 加入连接池 - conn_message = sock.recv(1024) - conn_message = strip_byte_end(conn_message) - try: - message_dic = json.loads(conn_message) - if message_dic.get('method') == 'start_long_connection': - name = message_dic.get('name') - if name is not None: - self.handle_long_connection(name, sock) - else: - response = generate_response_template() - response['message'] = 'failed' - response['content'] = 'socket name is None' - send_dict(sock, response) - logger.info('name is None, invalid request content!') - else: # 如果请求的不是一个长连接,就直接进行处理, - - response = generate_response_template() - response['message'] = 'succeeded' - response['content'] = 'connection established' - send_dict(sock, response) - b = receive(sock) - - if len(b) <= 1000: - message = str(b) - else: - message = str(b[:1000]) - - t0 = time.time() - self.handle_packet(sock, b) - t1 = time.time() - logger.info(f"Message handled!\nThe message was:{message}\nTime elapsed {t1 - t0:f} s\n") - - except: - import traceback - traceback.print_exc() - logger.info('failed to decode json:%s' % str(conn_message)) - response = generate_response_template() - response['message'] = 'failed' - response['content'] = 'invalid request json:\n%s' % str(conn_message) - send_dict(sock, response) - except: - import traceback - traceback.print_exc() - break - - def handle_long_connection(self, name: str, sock: socket.socket): - """ - 处理长连接请求 - :return: - """ - if name not in self.server_obj.long_conn_sockets.keys(): - self.server_obj.long_conn_sockets[name] = sock - response = generate_response_template() - response['message'] = 'succeeded' - response['content'] = 'socket connected' - send_dict(sock, response) - else: - logger.info('socket named \'%s\' is already connected!' % name) - response = generate_response_template() - response['message'] = 'failed' - response['content'] = 'socket name \'%s\' already connected' % name - send_dict(sock, response) - - def handle_packet(self, client: socket.socket, packet: bytes) -> None: - """ - 处理数据包的方法 - :param client: socket.socket,要求为tcp的端口。 - :param packet: bytes - :return: - """ - try: - try: - dic = json.loads(packet) - func = self.server_obj.dispatcher_dic[dic['method']] - args = dic['params'] - vy = func(*args).encode('utf-8') + b'PMEND' - client.sendall(vy) - except json.decoder.JSONDecodeError: - vy = json.dumps({'message': 'failed'}).encode('utf-8') + b'PMEND' - client.sendall(vy) - - except: - import traceback - traceback.print_exc() - client.close() - - -def init_socket(address: Tuple[str, int]): - """ - 初始化套接字 - """ - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.bind(address) - server_socket.listen(5) - logger.info("服务端已启动,等待客户端连接...") - return server_socket - - -class PMGServer(QObject): - def __init__(self, address: Tuple[str, int], parent=None): - super().__init__(parent) - self.dispatcher_dic = {} - self.long_conn_sockets: Dict[str, socket.socket] = {} - self.socket = init_socket(address) - self.server_loop_thread = QThread() - self.loop_worker = LoopWork(self, self.socket) - self.loop_worker.moveToThread(self.server_loop_thread) - - self.server_loop_thread.started.connect(self.loop_worker.work) - self.server_loop_thread.start() - - def broadcast_message(self, message_dic: dict = None): - """ - 广播信息 - message:传递信息 - # 'DATA_CHANGED' - # 'SHUT_DOWN' - :param message_dic:要发送的信息,应该是一个可以json序列化的字典。 - :return: - """ - - if message_dic is None: - message_dic = {'name': 'broadcast', 'message': 'Are you alive?'} - ids = [] - logger.info('broadcast message:' + repr(message_dic)) - for k in self.long_conn_sockets.keys(): - try: - self.long_conn_sockets[k].sendall(json.dumps(message_dic).encode('utf8') + b'PMEND') - except ConnectionResetError: - ids.append(k) - logger.info('Connection \'%s\' closed!' % k) - except: - import traceback - traceback.print_exc() - ids.append(k) - logger.info('died connections:' + repr(ids)) - for not_used_socket_name in ids: - sock = self.long_conn_sockets.pop(not_used_socket_name) - sock.close() - - -if __name__ == '__main__': - app = QApplication(sys.argv) - ADDRESS = ('127.0.0.1', 12306) # 绑定地址 - s = PMGServer(ADDRESS) - - qtimer = QTimer() - qtimer.start(2000) - qtimer.timeout.connect(lambda: s.broadcast_message(None)) - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/utilities/network/util.py b/pyminer/pmgwidgets/utilities/network/util.py deleted file mode 100644 index 7c9fface..00000000 --- a/pyminer/pmgwidgets/utilities/network/util.py +++ /dev/null @@ -1,95 +0,0 @@ -import json -import time -import socket -import logging -import warnings -from typing import Dict, Union, List - -logger = logging.getLogger(__name__) - - -def strip_byte_end(bytestream): - if bytestream.endswith(b'PMEND'): - return bytestream[: -5] - else: - return bytestream - - -def generate_client_payload() -> Dict[str, Union[str, Dict, List]]: - """ - 生成Client的消息模板 - :return: - """ - payload = {'timestamp': time.time(), - 'name': 'Anonymous Client', - 'contents': '' - } - return payload - - -def generate_server_payload() -> Dict[str, Union[str, Dict, List]]: - """ - 生成服务器消息模板 - :return: - """ - payload = {'message': 'succeeded', # 还有failed - 'timestamp': time.time() - } - return payload - - -def send_dict(sock: socket.socket, dict_to_send: Dict) -> None: - """ - 发送一个字典 - :param sock: - :param dict_to_send: - :return: - """ - content = (json.dumps(dict_to_send) + 'PMEND').encode('utf-8') - sock.sendall(content) - - -def receive(socket_obj: socket.socket) -> bytes: - recv_list = [] - empty_loops = 0 - while (1): - try: - b = socket_obj.recv(1024) - if b == b'': - empty_loops += 1 - if empty_loops > 1000: - raise ValueError('Too much empty values received!All received was:' + repr(recv_list)) - else: - empty_loops = 0 - recv_list.append(b) - if len(recv_list) >= 2: - if (recv_list[-2] + b).endswith(b'PMEND'): - recv_list[-2] = recv_list[-2] + recv_list[-1] - recv_list.pop() - recv_list[-1] = strip_byte_end(recv_list[-1]) - break - else: - if b.endswith(b'PMEND'): - recv_list[-1] = strip_byte_end(recv_list[-1]) - break - - - except ConnectionAbortedError: - warnings.warn('Connection terminated.') - return b'' - except: - import traceback - traceback.print_exc() - return b'' - - return b''.join(recv_list) - - -def timeit(func): - def wrapper(*args, **kwargs): - t0 = time.time() - r = func(*args, **kwargs) - logger.debug('time_elapsed', time.time() - t0) - return r - - return wrapper diff --git a/pyminer/pmgwidgets/utilities/platform/__init__.py b/pyminer/pmgwidgets/utilities/platform/__init__.py deleted file mode 100644 index ea56ec57..00000000 --- a/pyminer/pmgwidgets/utilities/platform/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -from .commandutils import * -from .fileutils import * -from .filemanager import * -from .openprocess import * -from .translation import * -from .pmdebug import * -try: - from .filesyswatchdog import PMGFileSystemWatchdog -except ModuleNotFoundError: - import warnings - warnings.warn("Module \'watchdog\' is not Installed so the class PMGFileSystemWatchdog cannot be imported.") \ No newline at end of file diff --git a/pyminer/pmgwidgets/utilities/platform/commandutils.py b/pyminer/pmgwidgets/utilities/platform/commandutils.py deleted file mode 100644 index 1166d570..00000000 --- a/pyminer/pmgwidgets/utilities/platform/commandutils.py +++ /dev/null @@ -1,167 +0,0 @@ -import os -import platform -import subprocess -import sys -from typing import Union, Optional - - -def check_platform() -> str: - """ - Check platform. - returns 'linux', 'windows' or 'osx' - - Returns: platform name in lowercase, a str - """ - system = platform.system() - plat = platform.platform(1, 1) - return system.lower() - - -def run_command_in_terminal(cmd: str, close_mode: str = 'wait_key') -> None: - """ - Run command in system terminal. - TODO: Adapt it to OSX and Linux system!!! - - Args: - cmd: application command, which should be platform-crossing. - close_mode: What the terminal do when execution finished. There are a few options:['wait_key','auto','no']. - - * 'wait_key' means the terminal closes when user pressed any key after execution. - * 'auto' means the terminal closes instantly after execution. - * 'no' means the terminal will keep shown until user manually close it. - - Returns: - - """ - platform_name = check_platform() - if platform_name == 'windows': - close_action = {'auto': 'start cmd.exe /k \"%s &&exit \"', - 'no': 'start cmd.exe /k \"%s \"', - 'wait_key': 'start cmd.exe /k \"%s &&pause &&exit \"' - } - command = close_action[close_mode] % cmd - subprocess.Popen(command, shell=True) - - - elif platform_name == 'linux': - ret = os.system('which gnome-terminal') - - if ret == 0: - close_action = {'auto': 'deepin-terminal -C \"%s\"', - 'no': 'deepin-terminal -C \"%s\" --keep-open', - 'wait_key': 'deepin-terminal -C \"%s\" --keep-open' - } - command = close_action[close_mode] % cmd - subprocess.Popen(command, shell=True) - else: - close_action = {'auto': 'gnome-terminal -x bash -c "%s;"', - 'no': 'gnome-terminal -x bash -c "%s; read"', - 'wait_key': 'gnome-terminal -x bash -c "%s; read"' - } - command = close_action[close_mode] % (cmd) - subprocess.Popen(command, shell=True) - - else: - return - - -def run_command_in_terminal_block(cmd: str, close_mode: str = 'wait_key') -> None: - """ - Run command in a terminal window, and the running event will block current Program. - The programm will be continued after closing the command terminal. - TODO:Is this function threading-safe? - - Args: - cmd: application command, which should be platform-crossing. - close_mode: What the terminal do when execution finished. There are a few options:['wait_key','auto','no']. - - * 'wait_key' means the terminal closes when user pressed any key after execution. - * 'auto' means the terminal closes instantly after execution. - * 'no' means the terminal will keep shown until user manually close it. - - Returns: - """ - platform_name = check_platform() - if platform_name == 'windows': - close_action = {'auto': 'start cmd.exe /k \"%s &&exit \"', - 'no': 'start cmd.exe /k \"%s \"', - 'wait_key': 'start cmd.exe /k \"%s &&pause &&exit \"' - } - command = close_action[close_mode] % cmd - f = os.popen(command, 'r', 1) - - elif platform_name == 'linux': - ret = os.system('which gnome-terminal') - - if ret == 0: - close_action = {'auto': 'deepin-terminal -C \"%s\"', - 'no': 'deepin-terminal -C \"%s\" --keep-open', - 'wait_key': 'deepin-terminal -C \"%s\" --keep-open' - } - command = close_action[close_mode] % cmd - subprocess.Popen(command, shell=True) - else: - close_action = {'auto': 'gnome-terminal -x bash -c "%s;"', - 'no': 'gnome-terminal -x bash -c "%s; read"', - 'wait_key': 'gnome-terminal -x bash -c "%s; read"' - } - command = close_action[close_mode] % (cmd) - subprocess.Popen(command, shell=True) - - else: - return - - -def run_python_file_in_terminal(file_path, interpreter_path: str = None, close_mode: str = 'wait_key', - blocking=False) -> Optional[str]: - """ - Run Python file in terminal - Args: - file_path: - interpreter_path: - close_mode: - blocking: - - Returns: - - """ - if interpreter_path is None: - interpreter_path = sys.executable - if blocking: - return run_command_in_terminal_block('%s %s' % (interpreter_path, file_path), close_mode=close_mode) - else: - return run_command_in_terminal('%s %s' % (interpreter_path, file_path), close_mode=close_mode) - - -def check_application(app_name): - os.system(app_name) - - -def get_parent_path(path: str, storey: int = 1) -> str: - """ - 获取文件或者文件夹的父路径。 - Args: - path: original path(file or folder) - storey: If is 1,return parent path;if is 2,return the parent path's parent path - - Returns: - """ - for i in range(storey): - path = os.path.dirname(path) - return path - - -if __name__ == '__main__': - run_python_file_in_terminal('./test/python_file_test.py', blocking=True) - - - def test_run_in_terminal(): - import time - run_command_in_terminal('dir', close_mode='no') - time.sleep(1) - run_command_in_terminal('dir', close_mode='wait_key') - time.sleep(1) - run_command_in_terminal('dir', close_mode='auto') - - - test_run_in_terminal() diff --git a/pyminer/pmgwidgets/utilities/platform/filemanager.py b/pyminer/pmgwidgets/utilities/platform/filemanager.py deleted file mode 100644 index 9b2eeb5a..00000000 --- a/pyminer/pmgwidgets/utilities/platform/filemanager.py +++ /dev/null @@ -1,26 +0,0 @@ -import subprocess -import os -import platform - - -def open_file_manager(path: str): - assert os.path.exists(path) - path = os.path.normcase(path) # windows的输入命令格式似乎需要注意一下!需要换成斜杠,否则会识别不出来的。 - if platform.system().lower() == 'windows': - subprocess.Popen(['explorer.exe', path], shell=True) - elif platform.system().lower() == 'linux': - if os.system('which nautilus') == 0: - subprocess.Popen(['nautilus', path]) - return - elif os.system('which dde-file-manager') == 0: - subprocess.Popen(['dde-file-manager', path]) - return - else: - raise NotImplementedError('Cannot Detect system file manager!') - else: - raise NotImplementedError("This Platform is not supported now!") - - -if __name__ == '__main__': - # open_file_manager(r'J:\Developing\pyminer_bin\PyMiner\bin\pmgwidgets\utilities\platform') - open_file_manager(r'/home/hzy/图片') diff --git a/pyminer/pmgwidgets/utilities/platform/filesyswatchdog.py b/pyminer/pmgwidgets/utilities/platform/filesyswatchdog.py deleted file mode 100644 index 58835757..00000000 --- a/pyminer/pmgwidgets/utilities/platform/filesyswatchdog.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -作者(Author):1295752786@qq.com -文件系统看门狗-(Watchdog for filesystem) -来源- (source) -https://stackoverflow.com/questions/35874217/watchdog-pythons-library-how-to-send-signal-when-a-file-is-modified -源代码为PyQt4,本人整理、移植到qtpy。(Originally code was in PyQt4 and I transplanted to PySide2.) -""" - -from PySide2.QtCore import Signal, QThread, SignalInstance -from watchdog.events import FileSystemEventHandler, FileModifiedEvent, FileMovedEvent, \ - FileCreatedEvent, FileDeletedEvent -from watchdog.observers import Observer - - -class MyEventHandler(FileSystemEventHandler, QThread): - signal_file_modified: SignalInstance = Signal(str) - signal_file_created: SignalInstance = Signal(str) - signal_file_deleted: SignalInstance = Signal(str) - signal_file_moved: SignalInstance = Signal(str, str) # 仅当在本文件夹内才会触发,如果移动到了其他文件夹则触发删除信号 - - def on_deleted(self, event: FileDeletedEvent): - self.signal_file_deleted.emit(event.src_path) - - def on_modified(self, event: FileModifiedEvent): - self.signal_file_modified.emit(event.src_path) - - def on_created(self, event: FileCreatedEvent): - self.signal_file_created.emit(event.src_path) - - def on_moved(self, event: FileMovedEvent): - self.signal_file_moved.emit(event.src_path, event.dest_path) - - -class PMGFileSystemWatchdog(QThread): - """ - Watch Dog 的一切操作都是在path这个文件夹下完成的,其余位置的文件变更并不会被监测到。 - 因此,如果将一个文件移动出这个文件夹,触发的并不是“修改”信号,而是触发“删除”信号。 - - # TODO 目前仅支持监控一整个文件夹,需要添加监控单一文件的方法 - """ - - def __init__(self, path): - super(PMGFileSystemWatchdog, self).__init__() - - self.path = path - self.observer = Observer() - self.event_handler = MyEventHandler() - self.signal_file_modified: SignalInstance = self.event_handler.signal_file_modified - self.signal_file_created: SignalInstance = self.event_handler.signal_file_created - self.signal_file_deleted: SignalInstance = self.event_handler.signal_file_deleted - self.signal_file_moved: SignalInstance = self.event_handler.signal_file_moved - self.observer.schedule(self.event_handler, self.path, recursive=True) - self.observer.start() - - def stop(self): - self.observer.stop() - self.deleteLater() diff --git a/pyminer/pmgwidgets/utilities/platform/fileutils.py b/pyminer/pmgwidgets/utilities/platform/fileutils.py deleted file mode 100644 index 777d70a1..00000000 --- a/pyminer/pmgwidgets/utilities/platform/fileutils.py +++ /dev/null @@ -1,134 +0,0 @@ -import os - -import chardet - - -def get_parent_path(path, layers=1): - """获取父级目录 - - Args: - path: 当前目录。 - layers: 向上查找的层级数。 - - Returns: - 当前目录向上 ``layers`` 级的父目录。 - """ - assert isinstance(layers, int) and layers > 0 - for i in range(layers): - path = os.path.dirname(path) - return path - - -def load_json(path) -> dict: - """ - 加载json,指定编码方式 - :param path: - :return: - """ - import json - with open(path, 'rb') as f: - byte_str = f.read() - encoding = chardet.detect(byte_str)['encoding'] - return json.loads(byte_str.decode(encoding)) - - -def dump_json(dic: dict, path: str, indent=4) -> None: - """ - 加载json,指定编码方式 - :param path: - :return: - """ - import json - with open(path, 'wb') as f: - byte_str = json.dumps(dic, indent=indent).encode('utf-8') - f.write(byte_str) - - -def create_file_if_not_exist(abso_file_path: str, default_content: bytes = b''): - """ - 在任意可能的路径创建一个文件,倘若文件不存在。 - :param abso_file_path: - :param default_content: - :return: - """ - dir_stack = [] - path = abso_file_path - # assert os.path.isfile(abso_file_path), 'Path \'%s\' is not a file!' % abso_file_path - if os.path.isfile(abso_file_path): - return - while 1: - parent_path = os.path.dirname(path) - if not os.path.exists(parent_path): - dir_stack.append(parent_path) - path = parent_path - else: - break - dir_stack.reverse() - for path in dir_stack: - os.mkdir(path) - with open(abso_file_path, 'wb') as f: - f.write(default_content) - pass - - -def move_to_trash(path: str) -> bool: - """ - 将文件移动到回收站。成功返回True,失败返回False - :param path:绝对路径。 - :return: - """ - import platform - import send2trash - if platform.system() == "Windows": - path = path.replace('/', '\\') - try: - send2trash.send2trash(path) - return True - except: - import traceback - traceback.print_exc() - return False - - -def rename_file(prev_absolute_path: str, new_absolute_path: str) -> bool: - """ - 重命名文件或者文件夹 - :param prev_absolute_path:之前的绝对路径名称 - :param new_absolute_path: 之后的绝对路径名称 - :return: - """ - import os - try: - os.rename(prev_absolute_path, new_absolute_path) - return True - except: - import traceback - traceback.print_exc() - return False - - -def copy_paste(source_path: str, target_path: str): - """ - - :param source_path: 源文件或文件夹 - :param target_path: 目标文件或文件夹 - :return: - """ - import shutil, os - if os.path.isfile(source_path): - copy_func = shutil.copyfile - else: - copy_func = shutil.copytree - - try: - copy_func(source_path, target_path) - except: - import traceback - traceback.print_exc() - return False - return True - - -if __name__ == '__main__': - print(get_parent_path(os.path.dirname(__file__), 2)) - print(load_json(r'/pyminer2/extensions/packages/code_editor/customized/settings.json')) diff --git a/pyminer/pmgwidgets/utilities/platform/openprocess.py b/pyminer/pmgwidgets/utilities/platform/openprocess.py deleted file mode 100644 index abb634e9..00000000 --- a/pyminer/pmgwidgets/utilities/platform/openprocess.py +++ /dev/null @@ -1,51 +0,0 @@ -import queue -import subprocess -import threading -import time -import chardet -from typing import List - -import packages.code_editor.utils.utils - - -class PMGProcess(): - def __init__(self, args: List[str]): - self.terminate = False - self.q = queue.Queue() - self.on_command_received = lambda cmd: None - self.on_error_received = lambda error: None - self.args = args - self.process = subprocess.Popen(self.args, - stdin=subprocess.PIPE, - shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - self.to = threading.Thread( - target=self.enqueue_stream, args=( - self.process.stdout, self.q, 1)) - self.te = threading.Thread( - target=self.enqueue_stream, args=( - self.process.stderr, self.q, 2)) - self.tp = threading.Thread(target=self.console_loop) - self.to.setDaemon(True) - self.te.setDaemon(True) - self.tp.setDaemon(True) - self.te.start() - self.to.start() - self.tp.start() - - def enqueue_stream(self, stream, queue, type): # 将stderr或者stdout写入到队列q中。 - for line in iter(stream.readline, b''): - if self.terminate: - break - encoding = chardet.detect(line)['encoding'] - queue.put(str(type) + packages.code_editor.utils.utils.decode(encoding)) - stream.close() - - def console_loop(self): # 封装后的内容。 - pass - - -if __name__ == '__main__': - pmp = PMGProcess(['python', '-u', '-c', 'print(hello world!)']) - while (1): - time.sleep(2) - pass diff --git a/pyminer/pmgwidgets/utilities/platform/pmdebug.py b/pyminer/pmgwidgets/utilities/platform/pmdebug.py deleted file mode 100644 index 463ce7bb..00000000 --- a/pyminer/pmgwidgets/utilities/platform/pmdebug.py +++ /dev/null @@ -1,37 +0,0 @@ -import sys -import pickle - -sys.path.append(r'/') - - -def test1(): - print(123) - - -def test(): - test1() - print(123456) - - -def insight(name, var): - from pyminer_comm import set_var - - if name not in ['globals', 'os'] and (not name.startswith('__')): - try: - print('set_var') - pickle.dumps(var) - set_var(name, var, 'debugger') - print('set_var') - except: - d = {} - import traceback - traceback.print_exc() - for k in dir(var): - try: - attr = getattr(var, k) - pickle.dumps(attr) - d[k] = attr - except: - d[k] = str(getattr(var, k)) - print(name, '=', d) - set_var(name, d, 'debugger') diff --git a/pyminer/pmgwidgets/utilities/platform/test/__init__.py b/pyminer/pmgwidgets/utilities/platform/test/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/utilities/platform/test/python_file_test.py b/pyminer/pmgwidgets/utilities/platform/test/python_file_test.py deleted file mode 100644 index fa461a65..00000000 --- a/pyminer/pmgwidgets/utilities/platform/test/python_file_test.py +++ /dev/null @@ -1,10 +0,0 @@ -import numpy as np -import time - -i = 0 -while (1): - time.sleep(1) - print('this is a test python file!') - i += 1 - if i > 10: - break diff --git a/pyminer/pmgwidgets/utilities/platform/translation.py b/pyminer/pmgwidgets/utilities/platform/translation.py deleted file mode 100644 index 22690753..00000000 --- a/pyminer/pmgwidgets/utilities/platform/translation.py +++ /dev/null @@ -1,12 +0,0 @@ -def add_translation_file(file_path: str): - from PySide2.QtWidgets import QApplication - from PySide2.QtCore import QTranslator - app = QApplication.instance() - if hasattr(app, 'trans'): - try: - tr = QTranslator() - path = file_path - tr.load(path) - app.installTranslator(tr) - except: - pass diff --git a/pyminer/pmgwidgets/utilities/source/__init__.py b/pyminer/pmgwidgets/utilities/source/__init__.py deleted file mode 100644 index b6df99fe..00000000 --- a/pyminer/pmgwidgets/utilities/source/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .iconutils import create_icon -from .colorutils import color_tup2str, color_str2tup -from .graphicsitemutils import PMGPlotCustomizer diff --git a/pyminer/pmgwidgets/utilities/source/colorutils.py b/pyminer/pmgwidgets/utilities/source/colorutils.py deleted file mode 100644 index 344f820a..00000000 --- a/pyminer/pmgwidgets/utilities/source/colorutils.py +++ /dev/null @@ -1,42 +0,0 @@ -def convert(c): - v = ord(c) - if (48 <= v <= 57): - return v - 48 - else: - return v - 87 # 返回a的值。 - - -def color_str2tup(value: str) -> tuple: - """ - pos或者wh的输入都是tuple - """ - value = value.lower() - c0 = convert(value[1]) - c1 = convert(value[2]) - c2 = convert(value[3]) - c3 = convert(value[4]) - c4 = convert(value[5]) - c5 = convert(value[6]) - a1 = c0 * 16 + c1 - a2 = c2 * 16 + c3 - a3 = c4 * 16 + c5 - return (a1, a2, a3) - - -def color_tup2str(value: tuple) -> str: - """ - 问题修正 - :param value: - :return: - """ - if value is None: - return None - strcolor = '#' - for i in value: - strcolor += hex(int(i))[-2:].replace('x', '0') - return strcolor - - -if __name__ == '__main__': - print(color_tup2str((0, 222, 155))) - print(color_str2tup('#00aaff')) diff --git a/pyminer/pmgwidgets/utilities/source/graphicsitemutils.py b/pyminer/pmgwidgets/utilities/source/graphicsitemutils.py deleted file mode 100644 index 717e99b4..00000000 --- a/pyminer/pmgwidgets/utilities/source/graphicsitemutils.py +++ /dev/null @@ -1,93 +0,0 @@ -from typing import Union - - -class PMGPlotCustomizer(): - def __init__(self): - self._line_color = '#000000' - self._line_style = '--' - self._line_width = 2 - self._border_color = '#000000' - self._border_width = 2 - self._symbol = 't' - self._item_color = '#000000' - self._face_color = '#ffffff' - self._legend_face_color = '#ffffff' - self._symbols_dic = {} - - @property - def border_color(self): - return self._border_color - - @border_color.setter - def border_color(self, color: str): - self._border_color = color - - @property - def border_width(self): - return self._border_width - - @border_width.setter - def border_width(self, border_width: Union[int, float]): - self._border_width = border_width - - @property - def face_color(self): - return self._face_color - - @face_color.setter - def face_color(self, color: str): - self._face_color = color - - @property - def item_color(self): - return self._item_color - - @item_color.setter - def item_color(self, color: str): - self._item_color = color - - @property - def line_color(self): - return self._line_color - - @line_color.setter - def line_color(self, color: str): - self._line_color = color - - @property - def line_style(self): - return self._line_style - - @line_style.setter - def line_style(self, style: str): - self._line_style = style - - @property - def line_width(self): - return self._line_width - - @line_width.setter - def line_width(self, width: Union[int, float]): - assert isinstance(width, (int, float)) - self._line_width = width - - @property - def symbol(self): - return self._symbol - - @symbol.setter - def symbol(self, symbol: str): - if symbol in self._symbols_dic.keys(): - self._symbol = self._symbols_dic[symbol] - else: - raise ValueError( - 'Symbol \'%s\' is not allowed.\nAll allowed symbols are:%s' % (symbol, - list(self._symbols_dic.keys()))) - - @property - def legend_face_color(self): - return self._legend_face_color - - @legend_face_color.setter - def legend_face_color(self, color): - self._legend_face_color = color diff --git a/pyminer/pmgwidgets/utilities/source/iconutils.py b/pyminer/pmgwidgets/utilities/source/iconutils.py deleted file mode 100644 index 226acb2b..00000000 --- a/pyminer/pmgwidgets/utilities/source/iconutils.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Tuple - -from PySide2.QtGui import QIcon, QPixmap - - -def create_icon(icon_path: str = ":/pyqt/source/images/New.png"): - icon = QIcon() - icon.addPixmap(QPixmap(icon_path), QIcon.Normal, QIcon.Off) - return icon - - -def color_rgb_to_str(value: Tuple[int, ...]) -> str: - result = '#' - for i in value: - result += hex(int(i))[-2:].replace('x', '0') - return result diff --git a/pyminer/pmgwidgets/utilities/source/translation.py b/pyminer/pmgwidgets/utilities/source/translation.py deleted file mode 100644 index 3b93cd20..00000000 --- a/pyminer/pmgwidgets/utilities/source/translation.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -from PySide2.QtWidgets import QApplication -from PySide2.QtCore import QLocale, QTranslator - -def create_translation(target_files: str): - import os - folder = os.path.dirname(target_files) - name = os.path.basename(target_files) - name_without_ext = os.path.splitext(name) - names = '' - for file_path in target_files: - name = os.path.basename(file_path) - names += name + ' ' - os.system('cd %s && pylupdate5 -noobsolete %s -ts translations/%s.ts' % (folder, names, name_without_ext)) - -def create_translator(path:str): - - inner_app = QApplication.instance() - translator = QTranslator() - translator.load(path) - inner_app.installTranslator(translator) - return translator \ No newline at end of file diff --git a/pyminer/pmgwidgets/utilities/uilogics/__init__.py b/pyminer/pmgwidgets/utilities/uilogics/__init__.py deleted file mode 100644 index c3200698..00000000 --- a/pyminer/pmgwidgets/utilities/uilogics/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .tasks import * -from .undomanager import * -from .windowutils import * -from .codechecking import * -from .uidisplay import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/utilities/uilogics/codechecking.py b/pyminer/pmgwidgets/utilities/uilogics/codechecking.py deleted file mode 100644 index 78248d2e..00000000 --- a/pyminer/pmgwidgets/utilities/uilogics/codechecking.py +++ /dev/null @@ -1,72 +0,0 @@ -from typing import Tuple, Union, Any, Type, Container - -ERROR_INVALID_TYPE = 'Parameter or Variable' -TYPE_RANGE = Tuple[Union[int, float], Union[int, float]] - - -def iter_isinstance(iter, elem_cls) -> bool: - """ - 检查可迭代变量是否为iter_type指定的类型。 - :param iter: - :param elem_cls: - :return: - """ - for item in iter: - if not isinstance(item, elem_cls): - return False - return True - - -def assert_in(elem: Any, container: Container): - """ - 判断元素elem是否在container中。 - Args: - elem: - container: - - Returns: - - """ - assert elem in container, 'Element {0} not in Container {1}'.format(elem, container) - - -def assert_not_in(elem, container: Container): - """ - 判断元素elem是否在container中。 - Args: - elem: - container: - - Returns: - - """ - assert elem not in container, 'Element {0} in Container {1}'.format(elem, container) - - -class ErrorReporter(): - @staticmethod - def create_invalid_parameter_value_message(param_name: str, param_value: Any): - return 'Parameter \'%s\' value %s is not allowed.' % (param_name, str(param_value)) - - @staticmethod - def create_invalid_parameter_type_message(param_name, param_type, expected_type) -> Any: - return 'Parameter \'%s\' type %s is not allowed.Expected type is %s' % ( - param_name, str(param_type), str(expected_type)) - - @staticmethod - def create_invalid_variable_value_message(variable_name, variable_value): - return 'Parameter \'%s\' value %s is not allowed.' % (variable_name, variable_value) - - @staticmethod - def create_file_not_found_error(file: str): - if file != '': - return FileNotFoundError('File \'%s\' not found!' % file) - else: - return FileNotFoundError('File name is empty.') - - @staticmethod - def create_type_error(name: str, value: Any, type_expected: Union[Type[Any], str]): - typ = type(value) - return TypeError( - 'Variable \'%s\' is expected to be an instance of %s, but actually it was an instance of %s' % ( - name, str(type_expected), str(typ))) diff --git a/pyminer/pmgwidgets/utilities/uilogics/drags.py b/pyminer/pmgwidgets/utilities/uilogics/drags.py deleted file mode 100644 index 26344070..00000000 --- a/pyminer/pmgwidgets/utilities/uilogics/drags.py +++ /dev/null @@ -1,39 +0,0 @@ -import sys - -from PySide2.QtCore import QUrl -from PySide2.QtGui import QDropEvent -from PySide2.QtWidgets import QApplication, QTextBrowser - - -class Demo(QTextBrowser): # 1 - def __init__(self): - super(Demo, self).__init__() - self.setAcceptDrops(True) # 2 - - def dragEnterEvent(self, QDragEnterEvent): # 3 - print('Drag Enter') - if QDragEnterEvent.mimeData().hasText(): - QDragEnterEvent.acceptProposedAction() - print() - - def dragMoveEvent(self, QDragMoveEvent): # 4 - # print('Drag Move') - pass - - def dragLeaveEvent(self, QDragLeaveEvent): # 5 - # print('Drag Leave') - pass - - def dropEvent(self, drop_event: QDropEvent): # 6 - print('Drag Drop') - url: QUrl = None - urls = drop_event.mimeData().urls() - for url in urls: - print(url.toLocalFile()) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - demo = Demo() - demo.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/utilities/uilogics/tasks/__init__.py b/pyminer/pmgwidgets/utilities/uilogics/tasks/__init__.py deleted file mode 100644 index 818d608b..00000000 --- a/pyminer/pmgwidgets/utilities/uilogics/tasks/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .threads import * -from .minimal_thread import PMGQThreadManager -from .loop_background import * -from .one_shot_background import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/utilities/uilogics/tasks/loop_background.py b/pyminer/pmgwidgets/utilities/uilogics/tasks/loop_background.py deleted file mode 100644 index eb67576e..00000000 --- a/pyminer/pmgwidgets/utilities/uilogics/tasks/loop_background.py +++ /dev/null @@ -1,168 +0,0 @@ -# coding=utf-8 -__author__ = '侯展意' - -import logging -import sys -import time -from typing import Callable, Tuple, Iterable -# from collections import Iterable -from PySide2.QtGui import QCloseEvent -from PySide2.QtWidgets import QApplication -from PySide2.QtCore import QObject, Signal - -logger = logging.getLogger(__name__) -from pmgwidgets.utilities.uilogics.tasks.minimal_thread import PMGQThreadManager - - -class PMGEndlessLoopWorker(QObject): - """ - 在循环中工作。 - 输入参数:单步工作函数;参数(可迭代对象)。 - """ - signal_step_finished = Signal(object) - signal_finished = Signal() - - def __init__(self, work_fcn: Callable, args: Iterable = None): - super(PMGEndlessLoopWorker, self).__init__() - self.quit = False - self.args = args if args is not None else [] - self.work_fcn: Callable = work_fcn - - def work(self): - assert callable(self.work_fcn) - - while (1): - step_ret = self.work_fcn(*self.args) - self.signal_step_finished.emit(step_ret) - if self.quit: - break - self.signal_finished.emit() - - def on_exit(self): - self.quit = True - - -class PMGLoopWorker(QObject): - signal_step_finished = Signal(int, object) - signal_finished = Signal() - - def __init__(self, work_fcn: Callable, iter_args: Iterable = None, loop_times: int = 100, - step_args: Iterable = None): - """ - 在循环中工作。 - 第一种方法可以传入可迭代对象作为 iter_args 参数,循环次数就是 iter_args 的长度。此种情况下loop_times和step_args无效。 - 第二种方法,当iter_args为None的时候,传入循环次数loop_times作为参数,每一步分别的参数由step_args传入。 - 输入参数:单步工作函数;参数(可迭代对象)。 - 注意:传入的callback函数不得在其中直接刷新UI(比如,调用文本框的setText方法),否则可能出现段错误。段错误会立即导致界面崩溃,且不可使用try...catch...或者cgitb等手段进行处理! - Args: - work_fcn: - iter_args: - loop_times: - step_args: - - """ - super(PMGLoopWorker, self).__init__() - self.quit = False - - self.iter_args = iter_args if iter_args is not None else [([] if step_args is None else step_args) for i in - range(loop_times)] - self.work_fcn: Callable = work_fcn - - def work(self): - assert callable(self.work_fcn) - assert self.iter_args is not None - for i, step_args in enumerate(self.iter_args): - step_ret = self.work_fcn(*step_args) - self.signal_step_finished.emit(i, step_ret) - self.signal_finished.emit() - - def on_exit(self): - self.quit = True - - -class PMGLoopThreadRunner(QObject): - signal_finished = Signal() - signal_step_finished = Signal(int, object) - - def __init__(self, callback: Callable, iter_args: Iterable = None, loop_times: int = 100, - step_args: Iterable = None): - """ - 连续执行有限多次回调函数callback。函数每执行一次,会发出含两个参数(参数依次为“当前步数”和“callback的返回值”)的信号`signal_step_finished`。 - 第一种方法可以传入可迭代对象作为`iter_args`参数,循环次数就是 `iter_args` 的长度。此种情况下`loop_times`和`step_args`无效。 - 第二种方法,当`iter_args`为`None`的时候,传入循环次数`loop_times`作为参数,此时每步的参数是相同的,均有参数`step_args`传入。 - - 如果函数有多个返回值,则信号`signal_step_finished`的参数为:<整数,元组>。第二个参数是一个元组,依次包含callback各个返回参数。 - Args: - callback: 回调函数。函数每执行一次,信号`signal_step_finished`将发出。 - iter_args:循环每一步需要输入的参数 - loop_times:循环次数 - step_args:所有步相同的参数 - 注意:传入的callback函数不得在其中直接刷新UI(比如,调用文本框的setText方法),否则可能出现段错误。 - 段错误会立即导致界面崩溃,且无法使用try...catch...或者cgitb等手段进行处理! - - """ - super().__init__() - self.worker = PMGLoopWorker(callback, iter_args, loop_times, step_args) - self.thread_mgr = PMGQThreadManager(worker=self.worker) - self.worker.signal_step_finished.connect(self.signal_step_finished.emit) - self.worker.signal_finished.connect(self.signal_finished.emit) - - -class PMGEndlessLoopThreadRunner(QObject): - signal_finished = Signal() - signal_step_finished = Signal(object) - - def __init__(self, callback: Callable, args: Iterable = None): - """ - 连续执行无限多次回调函数callback。函数每执行一次,将发出参数为callback返回值的信号`signal_step_finished`。 - 如果函数有多个返回值,则信号`signal_step_finished`的参数为一个元组,依次包含各个返回参数。 - Args: - callback: 回调函数。函数每执行一次,信号`signal_step_finished`将发出,信号只有一个参数,也就是我们输入的callback的返回值。 - args: - 注意:传入的callback函数不得在其中直接刷新UI(比如,调用文本框的setText方法),否则可能出现段错误。 - 段错误会立即导致界面崩溃,且无法使用try...catch...或者cgitb等手段进行处理! - - """ - super().__init__() - self.worker = PMGEndlessLoopWorker(callback, args=args) - self.thread_mgr = PMGQThreadManager(worker=self.worker) - self.worker.signal_step_finished.connect(self.signal_step_finished.emit) - self.worker.signal_finished.connect(self.signal_finished.emit) - - def is_running(self) -> bool: - return self.worker.thread().isRunning() - - def shut_down(self): - self.thread_mgr.shut_down() - - -if __name__ == '__main__': - from PySide2.QtWidgets import QTextEdit - - - def run(i, j): - time.sleep(0.1) - return i + j - - - class TextEdit(QTextEdit): - def __init__(self): - super(TextEdit, self).__init__() - self.oneshot = PMGLoopThreadRunner(run, iter_args=[(i, i + 1) for i in range(100)]) - self.oneshot.signal_step_finished.connect(self.on_step_finished) - self.oneshot.signal_finished.connect(self.on_finished) - - def on_step_finished(self, step, result): - self.append('step:%d,result:%s\n' % (step, repr(result))) - - def on_finished(self): - self.append('finished!') - - def closeEvent(self, a0: 'QCloseEvent') -> None: - super().closeEvent(a0) - - - app = QApplication(sys.argv) - textedit = TextEdit() - textedit.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/utilities/uilogics/tasks/minimal_thread.py b/pyminer/pmgwidgets/utilities/uilogics/tasks/minimal_thread.py deleted file mode 100644 index 6a3b18e0..00000000 --- a/pyminer/pmgwidgets/utilities/uilogics/tasks/minimal_thread.py +++ /dev/null @@ -1,127 +0,0 @@ -# coding=utf-8 -__author__ = '侯展意' - -import logging -import sys -import time - -from PySide2.QtGui import QCloseEvent, QKeyEvent -from PySide2.QtWidgets import QApplication -from PySide2.QtCore import QObject, QThread, Signal, QMutex, QWaitCondition - -logger = logging.getLogger(__name__) - - -class PMGQThreadManager(QObject): - signal_server_message_received = Signal(dict) - signal_data_changed = Signal(str) - signal_finished = Signal() - - def __init__(self, parent=None, worker: QObject = None): - super().__init__(parent) - self.thread_recv = QThread() - self.worker_recv = worker - self.worker_recv.moveToThread(self.thread_recv) - self.thread_recv.started.connect(self.worker_recv.work) - self.thread_recv.start() - self.thread_recv.finished.connect(self.signal_finished.emit) - - def shut_down(self): - """ - 关闭线程,并且退出。 - :return: - """ - self.worker_recv.on_exit() - self.thread_recv.quit() - self.thread_recv.wait(500) - - -if __name__ == '__main__': - from PySide2.QtWidgets import QTextEdit - - i = 0 - j = 0 - - - def work(p): - global i, j - j += 1 - mutex = QMutex() - print('start') - while (1): - mutex.lock() - # print(self.thread()) - # self.wait_condition.wait(self.mutex) - # for j in range(3): - # print(j) - i += 1 - p.signal_print.emit(repr(('thread:%d' % p.id, i))) - # print('thread:%d' % p.id, i, '\n') - p.thread().msleep(10) - - # mutex.unlock() - if i>100: - break - # while(1): - - - - class PMGThreadWorker(QObject): - """ - 利用mutex加锁 - - """ - signal_print = Signal(str) - - def __init__(self, worker_id: int): - super(PMGThreadWorker, self).__init__() - self.quit = False - self.id = worker_id - self.mutex = QMutex() - self.wait_condition = QWaitCondition() - - def work(self): - i = 0 - while (1): - self.mutex.lock() - print(self.thread()) - self.wait_condition.wait(self.mutex) - for i in range(3): - self.signal_print.emit(str(self.id) + ',' + str(i + 1)) - i += 1 - if self.quit: - break - self.mutex.unlock() - - def on_exit(self): - self.quit = True - self.wait_condition.wakeAll() - - def wake_all(self): - self.wait_condition.wakeAll() - - - class TextEdit(QTextEdit): - def __init__(self): - super(TextEdit, self).__init__() - self.worker = PMGThreadWorker(1) - self.thread_mgr = PMGQThreadManager(worker=self.worker) - self.worker.signal_print.connect(self.append) - - self.worker2 = PMGThreadWorker(2) - self.thread_mgr2 = PMGQThreadManager(worker=self.worker2) - self.worker2.signal_print.connect(self.append) - - def keyPressEvent(self, event: 'QKeyEvent') -> None: - super().keyPressEvent(event) - self.worker.wake_all() - - def closeEvent(self, a0: 'QCloseEvent') -> None: - super().closeEvent(a0) - self.thread_mgr.shut_down() - - - app = QApplication(sys.argv) - textedit = TextEdit() - textedit.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/utilities/uilogics/tasks/one_shot_background.py b/pyminer/pmgwidgets/utilities/uilogics/tasks/one_shot_background.py deleted file mode 100644 index 7b04de17..00000000 --- a/pyminer/pmgwidgets/utilities/uilogics/tasks/one_shot_background.py +++ /dev/null @@ -1,103 +0,0 @@ -# coding=utf-8 -__author__ = '侯展意' - -import logging -import sys -import time -from typing import Callable, Tuple - -from PySide2.QtGui import QCloseEvent -from PySide2.QtWidgets import QApplication -from PySide2.QtCore import QObject, Signal - -logger = logging.getLogger(__name__) -from pmgwidgets.utilities.uilogics.tasks.minimal_thread import PMGQThreadManager - - -class PMGOneShotWorker(QObject): - signal_finished = Signal(object) - - def __init__(self, work_fcn: Callable, args: Tuple = None): - super(PMGOneShotWorker, self).__init__() - self.quit = False - self.args = args - self.work_fcn: Callable = work_fcn - - def work(self): - assert callable(self.work_fcn) - if self.args is not None: - assert isinstance(self.args, (tuple, list)) - ret = self.work_fcn(*self.args) - else: - ret = self.work_fcn() - self.signal_finished.emit(ret) - - def on_exit(self): - pass - - -class PMGOneShotThreadRunner(QObject): - - signal_finished = Signal(object) - - def __init__(self, callback: Callable, args=None): - """ - Attension: Do not do UI operations in the callback.If callback contains operations for refresh UI, this method might - cause segmentation fault. - - Args: - callback: 传入函数对象 - args: 传入函数的参数,默认值为None。应当以元组形式依次传入。如果为None则不对函数传入参数。 - """ - - super().__init__() - self.worker = PMGOneShotWorker(callback, args) - self.thread_mgr = PMGQThreadManager(worker=self.worker) - self.worker.signal_finished.connect(self.slot_signal_finished) - - def slot_signal_finished(self, obj): - """ - When the single shot finished,this slot method will instantly be called. - - - Args: - obj: - - Returns: - - """ - self.signal_finished.emit(obj) - self.worker.thread().quit() - self.worker.thread().wait(500) - - def is_running(self): - return self.worker.thread().isRunning() - -if __name__ == '__main__': - from PySide2.QtWidgets import QTextEdit - - - def run(loop_times): - for i in range(loop_times): - print(i) - time.sleep(1) - return 'finished!!', 'aaaaaa', ['finished', 123] - - - class TextEdit(QTextEdit): - def __init__(self): - super(TextEdit, self).__init__() - self.oneshot = PMGOneShotThreadRunner(run, args=(5,)) - self.oneshot.signal_finished.connect(self.on_finished) - - def on_finished(self, obj): - self.append(repr(obj)) - - def closeEvent(self, a0: 'QCloseEvent') -> None: - super().closeEvent(a0) - - - app = QApplication(sys.argv) - textedit = TextEdit() - textedit.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/utilities/uilogics/tasks/threads.py b/pyminer/pmgwidgets/utilities/uilogics/tasks/threads.py deleted file mode 100644 index d9fedfac..00000000 --- a/pyminer/pmgwidgets/utilities/uilogics/tasks/threads.py +++ /dev/null @@ -1,108 +0,0 @@ -# coding=utf-8 -__author__ = '侯展意' - -import logging -import sys -import time -from typing import Callable - -logger = logging.getLogger(__name__) - -from PySide2.QtWidgets import QApplication -from PySide2.QtCore import QObject, QThread, Signal - - -class PMGThreadWorker(QObject): - def __init__(self): - super(PMGThreadWorker, self).__init__() - self.quit = False - self.work_loop_fcn = None - self.on_exit_fcn = None - - def work(self): - while (1): - self.work_loop_fcn() - if self.quit: - break - # self.thread().quit() - - def on_exit(self): - if callable(self.on_exit_fcn): - self.on_exit_fcn() - self.quit = True - - -class PMQThreadObject(QObject): - signal_server_message_received = Signal(dict) - signal_data_changed = Signal(str) - - def __init__(self, parent=None, worker: QObject = None): - super().__init__(parent) - self.thread = QThread() - self.worker = worker - self.worker.moveToThread(self.thread) - self.thread.started.connect(self.worker.work) # self.worker_recv.work) - self.thread.finished.connect(self.worker.deleteLater) - self.thread.finished.connect(self.thread.deleteLater) - self.thread.start() - - def terminate(self): - logger.info('client quit') - self.worker.on_exit() - - self.thread.quit() - self.thread.wait(500) - - -class PMQThreadManager(QObject): - signal_server_message_received = Signal(dict) - signal_data_changed = Signal(str) - - def __init__(self, parent=None, work_fcn: Callable = None, loop_fcn: Callable = None, exit_fcn: Callable = None): - super().__init__(parent) - self.thread_recv = QThread() - self.worker_recv = PMGThreadWorker() - - if work_fcn is not None and loop_fcn is not None: - raise ValueError('work_fcn and loop_fcn cannot be both not None at the same time!') - if work_fcn is not None: - self.worker_recv.work = work_fcn - else: - self.worker_recv.work_loop_fcn = loop_fcn - self.worker_recv.moveToThread(self.thread_recv) - self.thread_recv.started.connect(self.worker_recv.work) # self.worker_recv.work) - self.worker_recv.on_exit_fcn = exit_fcn - self.thread_recv.start() - - def shut_down(self): - logger.info('client quit') - self.worker_recv.on_exit() - # self.worker_recv.close_socket() - self.thread_recv.quit() - self.thread_recv.wait(500) - - -if __name__ == '__main__': - from PySide2.QtWidgets import QTextEdit - - - def loop(): - print(123) - time.sleep(0.4) - - - def exit(): - print('thread exits!') - - class TextEdit(QTextEdit): - def __init__(self): - super(TextEdit, self).__init__() - self.thread_mgr = PMQThreadManager() - - app = QApplication(sys.argv) - textedit = QTextEdit() - textedit.show() - c = PMQThreadManager(loop_fcn=loop, exit_fcn=exit) - time.sleep(2) - c.shut_down() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/utilities/uilogics/uidisplay.py b/pyminer/pmgwidgets/utilities/uilogics/uidisplay.py deleted file mode 100644 index 32fdcf4b..00000000 --- a/pyminer/pmgwidgets/utilities/uilogics/uidisplay.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding:utf-8 -*- -# @Time: 2021/3/29 10:55 -# @Author: Zhanyi Hou -# @Email: 1295752786@qq.com -# @File: uidisplay.py -from PySide2.QtCore import QObject, QCoreApplication - - -class TextDisplayUtil(QObject): - @staticmethod - def get_display_type(obj: object): - """ - 获取显示的类型 - :param obj: - :return: - """ - _translate = QCoreApplication.translate - if type(obj) == type(True): - return _translate("TextDisplayUtil", "bool") - elif type(obj) == type(0): - return _translate("TextDisplayUtil", "integer") - elif type(obj) == type(""): - return _translate("TextDisplayUtil", "integer") - elif type(obj) == type(1.0): - return _translate("TextDisplayUtil", "float") - else: - raise TypeError("Unrecognized type for var %s" % (obj,)) diff --git a/pyminer/pmgwidgets/utilities/uilogics/undomanager.py b/pyminer/pmgwidgets/utilities/uilogics/undomanager.py deleted file mode 100644 index b336a95e..00000000 --- a/pyminer/pmgwidgets/utilities/uilogics/undomanager.py +++ /dev/null @@ -1,65 +0,0 @@ -""" -用于撤销和重做的数据结构。 - -""" - -from typing import Any - - -class UndoManager: - """ - 用于撤销和重做的管理类 - """ - - def __init__(self, stack_size: int = 10): - self.pointer: int = 0 - self.content = [] - self.stack_size = stack_size - - def push(self, obj: Any): - """ - 压栈时指向栈顶,这里就是撤销时候的逻辑。 - :param obj: - :return: - """ - if self.pointer < len(self.content) - 1: - self.pointer += 1 - self.content[self.pointer] = obj - else: - self.content.append(obj) - self.pointer = len(self.content) - 1 - if len(self.content) > self.stack_size: - self.content.pop(0) - - def undo(self) -> Any: - if 0 < self.pointer <= len(self.content) - 1: - - obj = self.content[self.pointer] - self.pointer -= 1 - return obj - else: - if len(self.content) > 0: - self.pointer = 0 - return self.content[0] - else: - return None - - def redo(self) -> Any: - if 0 <= self.pointer < len(self.content) - 1: - self.pointer += 1 - return self.content[self.pointer] - else: - if len(self.content) > 0: - self.pointer = len(self.content) - 1 - return self.content[self.pointer] - else: - return None - - def last_value(self) -> Any: - try: - return self.content[self.pointer] - except: - return None - - def __len__(self): - return len(self.content) diff --git a/pyminer/pmgwidgets/utilities/uilogics/windowutils.py b/pyminer/pmgwidgets/utilities/uilogics/windowutils.py deleted file mode 100644 index 91cb0ed6..00000000 --- a/pyminer/pmgwidgets/utilities/uilogics/windowutils.py +++ /dev/null @@ -1,35 +0,0 @@ -from PySide2.QtCore import Qt -from PySide2.QtWidgets import QWidget, QDesktopWidget - - -def in_unit_test(): - """ - 判断是否在单元测试中。 - 方便控件单独测试。返回True的时候说明在单元测试;返回False的时候说明不在单元测试。 - 当PyMiner主程序启动后,它会将这个函数用lambda:False这个匿名函数覆盖掉。 - - :return: - """ - return True - - -def center_window(window: QWidget): - screen = QDesktopWidget().screenGeometry() - size = window.geometry() - window.move(int((screen.width() - size.width()) / 2), - int((screen.height() - size.height()) / 2)) - - -def set_always_on_top(window: QWidget): - flags = window.windowFlags() - window.setWindowFlags(flags | Qt.WindowStaysOnTopHint) # 窗体总在最前端 - - -def set_minimizable(window: QWidget): - flags = window.windowFlags() - window.setWindowFlags(flags | Qt.WindowMinMaxButtonsHint) - - -def set_closable(window: QWidget): - flags = window.windowFlags() - window.setWindowFlags(flags | Qt.WindowCloseButtonHint) diff --git a/pyminer/pmgwidgets/widgets/__init__.py b/pyminer/pmgwidgets/widgets/__init__.py deleted file mode 100644 index 72999c8c..00000000 --- a/pyminer/pmgwidgets/widgets/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -import time - -t0 = time.time() -from .basic import * -from .composited import * -from .extended import * diff --git a/pyminer/pmgwidgets/widgets/basic/__init__.py b/pyminer/pmgwidgets/widgets/basic/__init__.py deleted file mode 100644 index 8f3340d8..00000000 --- a/pyminer/pmgwidgets/widgets/basic/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from .browsers import * -from .buttons import * -from .containers import * -from .labels import * -from .others import * -from .plots import * -from .tables import * -from .texts import * -from .trees import * -from .dialogs import * diff --git a/pyminer/pmgwidgets/widgets/basic/browsers/__init__.py b/pyminer/pmgwidgets/widgets/basic/browsers/__init__.py deleted file mode 100644 index 42c47d01..00000000 --- a/pyminer/pmgwidgets/widgets/basic/browsers/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -import warnings -try: - from .browser import * -except ImportError: - warnings.warn('QWebEngine cannot import, maybe it was not installed.') - import traceback - traceback.print_exc() \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/basic/browsers/browser.py b/pyminer/pmgwidgets/widgets/basic/browsers/browser.py deleted file mode 100644 index 04ac8dba..00000000 --- a/pyminer/pmgwidgets/widgets/basic/browsers/browser.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -代码来源: -https://www.cnblogs.com/taostaryu/p/9772492.html - -""" -import sys -from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout, QToolBar, QLineEdit -from PySide2.QtCore import QUrl, Signal -from PySide2.QtWebEngineWidgets import QWebEngineView - - -class PMGWebBrowser(QWidget): - def __init__(self, parent=None, toolbar='standard'): - """ - - :param parent: - :param toolbar:多种选项:‘no’,‘standard’,'no_url_input','refresh_only' - """ - super().__init__(parent) - self.webview = PMGWebEngineView() - self.setLayout(QVBoxLayout()) - self.toolbar = QToolBar() - self.url_input = QLineEdit() - self.toolbar.addWidget(self.url_input) - self.toolbar.addAction('go').triggered.connect(lambda b: self.load_url()) - back_action = self.toolbar.addAction('back') - back_action.triggered.connect(self.webview.back) - - forward_action = self.toolbar.addAction('forward') - forward_action.triggered.connect(self.webview.forward) - self.layout().addWidget(self.toolbar) - if toolbar == 'no': - self.toolbar.hide() - elif toolbar == 'no_url_input': - self.url_input.hide() - elif toolbar == 'refresh_only': - self.url_input.hide() - back_action.setEnabled(False) - forward_action.setEnabled(True) - - self.layout().addWidget(self.webview) - self.setWindowTitle('My Browser') - self.showMaximized() - - # command:> - # jupyter notebook --port 5000 --no-browser --ip='*' --NotebookApp.token='' - # --NotebookApp.password='' c:\users\12957\ - - # self.webview.load(QUrl("http://127.0.0.1:5000/notebooks/desktop/Untitled.ipynb")) # 直接请求页面。 - # self.webview.load(QUrl("E:\Python\pyminer_bin\PyMiner\bin\pmgwidgets\display\browser\show_formula.html")) # 直接请求页面。 - # self.setCentralWidget(self.webview) - - def load_url(self, url: str = ''): - if url == '': - url = self.url_input.text().strip() - else: - self.url_input.setText(url) - self.webview.load(QUrl(url)) - - -class PMGWebEngineView(QWebEngineView): - windowList = [] - signal_new_window_created = Signal(PMGWebBrowser) - signal_load_url = Signal(str) - - # 重写createwindow() - def createWindow(self, QWebEnginePage_WebWindowType): - new_window = PMGWebBrowser() - self.windowList.append(new_window) # 注:没有这句会崩溃!!! - self.signal_new_window_created.emit(new_window) - return new_window.webview - - def load(self, request: QUrl) -> None: - print('load url', request, request.toString()) - self.signal_load_url.emit(request.toString()) - super(PMGWebEngineView, self).load(request) - - -if __name__ == "__main__": - app = QApplication(sys.argv) - - w = PMGWebBrowser() - w.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/browsers/translations/qt_zh_CN.ts b/pyminer/pmgwidgets/widgets/basic/browsers/translations/qt_zh_CN.ts deleted file mode 100644 index ccc96b05..00000000 --- a/pyminer/pmgwidgets/widgets/basic/browsers/translations/qt_zh_CN.ts +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/pyminer/pmgwidgets/widgets/basic/buttons/__init__.py b/pyminer/pmgwidgets/widgets/basic/buttons/__init__.py deleted file mode 100644 index d7bc07af..00000000 --- a/pyminer/pmgwidgets/widgets/basic/buttons/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .buttonpane import * -from .button import * diff --git a/pyminer/pmgwidgets/widgets/basic/buttons/button/__init__.py b/pyminer/pmgwidgets/widgets/basic/buttons/button/__init__.py deleted file mode 100644 index edfb3b86..00000000 --- a/pyminer/pmgwidgets/widgets/basic/buttons/button/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .toolbutton import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/basic/buttons/button/toolbutton.py b/pyminer/pmgwidgets/widgets/basic/buttons/button/toolbutton.py deleted file mode 100644 index 5d20e511..00000000 --- a/pyminer/pmgwidgets/widgets/basic/buttons/button/toolbutton.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -# -*- coding:utf-8 -*- -from PySide2.QtCore import QEvent, QTimer -from PySide2.QtGui import QColor -from PySide2.QtWidgets import QToolButton, QGraphicsDropShadowEffect, QMenu, QWidget, QHBoxLayout - - -class PMMenu(QMenu): - def __init__(self, tool_button: 'PMGToolButton' = None): - super().__init__() - self.tool_button = tool_button - - def leaveEvent(self, a0: QEvent) -> None: - print('leave menu', self.underMouse(), self.tool_button.underMouse()) - - QTimer.singleShot(50, self.tool_button.hide_menu) - - - -class PMGToolButton(QToolButton): - shadow = QGraphicsDropShadowEffect() # 实例阴影 - - def __init__(self, parent=None): - super().__init__(parent) - self.shadow.setColor(QColor(63, 72, 204)) # 设置阴影颜色 - self.shadow.setOffset(0, 0) # 设置阴影方向 - self.setMinimumWidth(60) - self.setMinimumHeight(40) - self.clicked.connect(self.set_btn_clicked_effect) - self.menu = PMMenu(tool_button=self) - self.setMenu(self.menu) - self.menu.addAction('新建行') - self.menu.addAction('新建列') - self.menu.addAction('删除行') - self.menu.addAction('删除列') - - def set_btn_clicked_effect(self): - # 设置模糊度并为按钮添加阴影 - self.shadow.setBlurRadius(20) - self.setGraphicsEffect(self.shadow) - - def unset_btn_clicked_effect(self): - # 设置模糊度为0 间接取消阴影 - self.shadow.setBlurRadius(0) - - def show_menu(self): - if self.underMouse() or self.menu.underMouse(): - self.menu.popup(self.mapToGlobal(self.pos())) - self.grabMouse() - - def hide_menu(self): - if not (self.underMouse() or self.menu.underMouse()): - self.menu.hide() - - -if __name__ == '__main__': - from PySide2.QtWidgets import QApplication - import sys - - app = QApplication(sys.argv) - w = QWidget() - layout = QHBoxLayout() - w.setLayout(layout) - for i in range(3): - w1 = PMGToolButton() - layout.addWidget(w1) - w1.setText('aaa') - w.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/buttons/buttonpane/__init__.py b/pyminer/pmgwidgets/widgets/basic/buttons/buttonpane/__init__.py deleted file mode 100644 index 5b3cc9f2..00000000 --- a/pyminer/pmgwidgets/widgets/basic/buttons/buttonpane/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .pushbuttonpane import * diff --git a/pyminer/pmgwidgets/widgets/basic/buttons/buttonpane/pushbuttonpane.py b/pyminer/pmgwidgets/widgets/basic/buttons/buttonpane/pushbuttonpane.py deleted file mode 100644 index 9684fc72..00000000 --- a/pyminer/pmgwidgets/widgets/basic/buttons/buttonpane/pushbuttonpane.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -pmpushbuttons是一个按钮组,专门负责向工具栏中插入按钮。 -其中PMPushButtonPane是按钮的载体,可以插入竖向排布的两个到三个按钮。 -作者:Zhanyi Hou -""" -from typing import List, Union - -from PySide2.QtCore import Qt -from PySide2.QtGui import QIcon -from PySide2.QtWidgets import QWidget, QVBoxLayout, QPushButton, QMenu, QLabel, QToolButton - -from pmgwidgets.utilities import create_icon - - -class PMPushButtonPane(QWidget): - def __init__(self): - super().__init__() - self.layout = QVBoxLayout() - self.setLayout(self.layout) - - def add_height_occu_buttons(self): - button_num = 3 - btn_list = [] - for i in range(button_num): - btn = QLabel() - btn.setText(' ') - btn.setProperty('qssp', 'occu') - btn_list.append(btn) - btn.setObjectName('space_occupation_button') - self.layout.addWidget(btn) - return btn_list - - def add_buttons(self, button_num: int = 2, text: list = None, icon_path: List[str] = None, - menu: list = None) -> List[QPushButton]: - if text is None: - text = [''] * button_num - if icon_path is None: - icon_path = [None] * button_num - if menu is None: - menu = [None] * button_num - if len(text) != button_num or len( - icon_path) != button_num or len(menu) != button_num: - raise Exception('text,icon和menu参数都必须为长为2的可迭代对象。') - qssproperty = "minibutton3" - if button_num == 2: - qssproperty = "minibutton2" - - btn_list = [] - for i in range(button_num): - btn = self.add_button(text=text[i], icon=create_icon(icon_path[i]), menu=menu[i], qssproperty=qssproperty) - btn_list.append(btn) - btn.setObjectName('stacked_tool_button') - return btn_list - - def add_button(self, text: str = '', icon: QIcon = None, menu: QMenu = None, qssproperty="minibutton3") \ - -> Union[QToolButton, QPushButton]: - """ - 添加按钮 - 由于QToolButton不支持同时添加图标和下拉菜单箭头,所以不得不使用QPushButton。 - [TODO!]QPushButton的样式仍然不好。 - :param text: - :param icon: - :param menu: - :param qssproperty: - :return: - """ - pbtn = QToolButton() - pbtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) - pbtn.setPopupMode(QToolButton.InstantPopup) - pbtn.setText(text) - - if icon is not None: - pbtn.setIcon(icon) - if menu is not None: - pbtn.setMenu(menu) - pbtn.setProperty("qssp", qssproperty) - self.layout.addWidget(pbtn) - return pbtn diff --git a/pyminer/pmgwidgets/widgets/basic/buttons/translations/qt_zh_CN.ts b/pyminer/pmgwidgets/widgets/basic/buttons/translations/qt_zh_CN.ts deleted file mode 100644 index ccc96b05..00000000 --- a/pyminer/pmgwidgets/widgets/basic/buttons/translations/qt_zh_CN.ts +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/pyminer/pmgwidgets/widgets/basic/containers/PMTab.py b/pyminer/pmgwidgets/widgets/basic/containers/PMTab.py deleted file mode 100644 index 51221896..00000000 --- a/pyminer/pmgwidgets/widgets/basic/containers/PMTab.py +++ /dev/null @@ -1,22 +0,0 @@ -from PySide2.QtWidgets import QTabWidget, QWidget - - -class PMTabWidget(QTabWidget): - def setup_ui(self): - for tab_id in range(self.count()): # 遍历所有的tab - w = self.widget(tab_id) - if hasattr(w, 'setup_ui'): - self.widget(tab_id).setup_ui() - - def addScrolledAreaTab(self, widget: QWidget, a1: str): - """ - 添加使用QScrollArea包裹的Tab。 - :param widget: - :param a1: - :return: - """ - from pmgwidgets import PMScrollArea - scroll = PMScrollArea() - scroll.setWidget(widget) - - super().addTab(scroll, a1) diff --git a/pyminer/pmgwidgets/widgets/basic/containers/__init__.py b/pyminer/pmgwidgets/widgets/basic/containers/__init__.py deleted file mode 100644 index 943814a8..00000000 --- a/pyminer/pmgwidgets/widgets/basic/containers/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .PMTab import PMTabWidget -from .pmscrollarea import PMScrollArea -from .flowarea import PMFlowArea -from .flowlayout import PMFlowLayout, PMFlowLayoutWithGrid -from .pmdockwidget import PMGDockWidget -from .pmtoolbox import PMGToolBox diff --git a/pyminer/pmgwidgets/widgets/basic/containers/flowarea.py b/pyminer/pmgwidgets/widgets/basic/containers/flowarea.py deleted file mode 100644 index 29cc0087..00000000 --- a/pyminer/pmgwidgets/widgets/basic/containers/flowarea.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -集成了流式布局、按钮排布的窗口。 -""" -from PySide2.QtWidgets import QScrollArea, QWidget, QToolButton, QVBoxLayout, QSpacerItem, QSizePolicy -from PySide2.QtCore import Qt, QSize -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from PySide2.QtGui import QResizeEvent - from pmgwidgets import PMFlowLayout - - -class PMFlowAreaWidget(QWidget): - def __init__(self): - super().__init__() - from pmgwidgets import PMFlowLayout - - self.outer_layout = QVBoxLayout() - - self.flow_layout = PMFlowLayout() - self.setMinimumWidth(100) - self.outer_layout.addLayout(self.flow_layout) - spacer_v = QSpacerItem(20, 20, QSizePolicy.Minimum, - QSizePolicy.Expanding) - - self.outer_layout.addItem(spacer_v) - self.setLayout(self.outer_layout) - - def add_widget(self, w: 'QWidget'): - self.flow_layout.add_widget(w) - - def setup_ui(self): - if hasattr(self.widget(), 'setup_ui'): - self.widget().setup_ui() - - def resizeEvent(self, a0: 'QResizeEvent') -> None: - super().resizeEvent(a0) - layout: 'PMFlowLayout' = self.flow_layout - layout.on_resize() - - -class PMFlowArea(QScrollArea): - def __init__(self, parent=None): - super().__init__(parent) - - self.flow_widget = PMFlowAreaWidget() - self.widgets_list = self.flow_widget.flow_layout.widgets_list - self.setWidget(self.flow_widget) - self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - self.setWidgetResizable(True) - - def set_layout_content_margins( - self, left: int, right: int, up: int, down: int): - self.flow_widget.flow_layout.setContentsMargins(left, right, up, down) - - def add_tool_button(self, name: str, text: str, icon_path: str = ''): - from pmgwidgets import create_icon - b = QToolButton() - b.setText(text) - icon = create_icon(icon_path) - b.setIcon(icon) - b.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) - b.setIconSize(QSize(40, 40)) - b.setMaximumWidth(80) - b.setMinimumWidth(80) - b.setMinimumHeight(60) - b.setMaximumHeight(60) - self.add_widget(b) - return b - - def add_widget(self, w: 'QWidget'): - self.widget().add_widget(w) - return w - - def setup_ui(self): - if hasattr(self.widget(), 'setup_ui'): - self.widget().setup_ui() - - -if __name__ == '__main__': - from PySide2.QtWidgets import QApplication, QPushButton - import sys - - app = QApplication(sys.argv) - sa = PMFlowArea() - for i in range(10): - w = sa.add_widget(QPushButton('ad%d' % i)) - w.setMaximumHeight(60) - w.setMinimumHeight(60) - w.setMinimumWidth(100) - w.setMaximumWidth(100) - sa.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/containers/flowlayout.py b/pyminer/pmgwidgets/widgets/basic/containers/flowlayout.py deleted file mode 100644 index dc1c2d7a..00000000 --- a/pyminer/pmgwidgets/widgets/basic/containers/flowlayout.py +++ /dev/null @@ -1,113 +0,0 @@ -from PySide2.QtWidgets import QGridLayout, QWidget, QSizePolicy - - -class PMFlowLayoutWithGrid(QGridLayout): - """ - 流式布局,继承自QGridLayout,以Grid的方式添加widget。 - 主要作用是在保证兼容代码的基础上,做到流式布局。 - """ - - def __init__(self, parent=None, column_width=100): - super().__init__(parent) - - self.column_width = column_width - self.widgets_list = [] - - def addWidget(self, w: QWidget, row: int, column: int, - rowSpan: int, columnSpan: int) -> None: - """ - 添加控件的方法。多了一个列表将所有的控件存储起来。当然,不允许重复添加。 - :param w: - :param row: - :param column: - :param rowSpan: - :param columnSpan: - :return: - """ - if w not in self.widgets_list: - self.widgets_list.append(w) - super().addWidget(w, row, column, rowSpan, columnSpan) - - def on_resize(self): - """ - 在界面放大缩小的时候,会将按钮重新排布。按照表格上从上到下、从左到右的顺序,就像下面这样: - 注意这个方法无法自动调用,只能依靠它的父控件。 - 1 2 3 4 - 5 6 7 8 - 9 - :return: - """ - geometry = self.geometry() - cols = int(geometry.width() / self.column_width) - - if cols == self.columnCount(): - return - row = 0 - col = 0 - for i in range(len(self.widgets_list)): - w = self.widgets_list[i] - self.removeWidget(w) - self.addWidget(w, row, col, 1, 1) - col += 1 - if col == cols: - row += 1 - col = 0 - - -class PMFlowLayout(QGridLayout): - def __init__(self, parent=None, initial_columns=3, column_width=100): - super().__init__(parent) - - self.column_width = column_width - self.widgets_list = [] - self.occupy_widget = QWidget() - self.occupy_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) - - def add_widget(self, w: QWidget) -> None: - """ - 添加控件的方法。多了一个列表将所有的控件存储起来。当然,不允许重复添加。 - :param w: - :param row: - :param column: - :param rowSpan: - :param columnSpan: - :return: - """ - - if w not in self.widgets_list: - self.widgets_list.append(w) - items = len(self.widgets_list) - geometry = self.geometry() - cols = int(geometry.width() / self.column_width) - if cols == 0: - cols = 3 - current_row = int(items / cols) - current_col = int(items % cols) - super().addWidget(w, current_row, current_col, 1, 1) - - def on_resize(self): - """ - 在界面放大缩小的时候,会将按钮重新排布。按照表格上从上到下、从左到右的顺序,就像下面这样: - 注意这个方法无法自动调用,只能依靠它的父控件。 - 1 2 3 4 - 5 6 7 8 - 9 - :return: - """ - geometry = self.geometry() - cols = int(geometry.width() / self.column_width) - - if cols == self.columnCount(): - return - row = 0 - col = 0 - for i in range(len(self.widgets_list)): - w = self.widgets_list[i] - self.removeWidget(w) - self.addWidget(w, row, col, 1, 1) - col += 1 - if col == cols: - row += 1 - col = 0 - self.removeWidget(self.occupy_widget) - self.addWidget(self.occupy_widget, row, col, 1, 1) diff --git a/pyminer/pmgwidgets/widgets/basic/containers/pmdockwidget.py b/pyminer/pmgwidgets/widgets/basic/containers/pmdockwidget.py deleted file mode 100644 index b09df36a..00000000 --- a/pyminer/pmgwidgets/widgets/basic/containers/pmdockwidget.py +++ /dev/null @@ -1,21 +0,0 @@ -from PySide2.QtWidgets import QDockWidget, QMainWindow - - -class PMGDockWidget(QDockWidget): - def __init__(self, name, text='', parent: QMainWindow = None): - super().__init__(text, parent) - self.parent = parent - self.name = name - - def keyPressEvent(self, a0) -> None: - super(PMGDockWidget, self).keyPressEvent(a0) - print(a0) - - def raise_into_view(self): - """ - 将控件提升到能直接看到的位置。特别适用于两个选项卡叠在一起的情况。 - :return: - """ - self.setVisible(True) - self.setFocus() - self.raise_() diff --git a/pyminer/pmgwidgets/widgets/basic/containers/pmscrollarea.py b/pyminer/pmgwidgets/widgets/basic/containers/pmscrollarea.py deleted file mode 100644 index 9b787ce6..00000000 --- a/pyminer/pmgwidgets/widgets/basic/containers/pmscrollarea.py +++ /dev/null @@ -1,13 +0,0 @@ -from PySide2.QtWidgets import QScrollArea -from PySide2.QtCore import Qt - - -class PMScrollArea(QScrollArea): - def __init__(self): - super().__init__() - self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - self.setWidgetResizable(True) - - def setup_ui(self): - if hasattr(self.widget(), 'setup_ui'): - self.widget().setup_ui() diff --git a/pyminer/pmgwidgets/widgets/basic/containers/pmtoolbox.py b/pyminer/pmgwidgets/widgets/basic/containers/pmtoolbox.py deleted file mode 100644 index 347a28b0..00000000 --- a/pyminer/pmgwidgets/widgets/basic/containers/pmtoolbox.py +++ /dev/null @@ -1,31 +0,0 @@ -from PySide2.QtWidgets import QToolBox, QWidget -from typing import Dict, Callable - - -class PMGToolBox(QToolBox): - group_widgets: Dict[str, QWidget] = {} - - def __init__(self, parent=None): - super().__init__(parent) - self.button_num = 0 - pass - - def set_group_text(self, group_name: str, text: str): - gw = self.group_widgets.get(group_name) - if gw is not None: - self.setItemText(self.indexOf(gw), text) - - def add_button(self, group_name: str, text: str, icon_path: str, action: Callable): - from pmgwidgets import PMFlowArea - if self.group_widgets.get(group_name) is None: - fa = PMFlowArea() - self.group_widgets[group_name] = fa - self.addItem(fa, group_name) - btn = fa.add_tool_button(name='button#%d' % self.button_num, text=text, icon_path=icon_path) - btn.clicked.connect(action) - self.button_num += 1 - else: - fa: PMFlowArea = self.group_widgets[group_name] - btn = fa.add_tool_button(name='button#%d' % self.button_num, text=text, icon_path=icon_path) - btn.clicked.connect(action) - self.button_num += 1 diff --git a/pyminer/pmgwidgets/widgets/basic/containers/translations/qt_zh_CN.ts b/pyminer/pmgwidgets/widgets/basic/containers/translations/qt_zh_CN.ts deleted file mode 100644 index ccc96b05..00000000 --- a/pyminer/pmgwidgets/widgets/basic/containers/translations/qt_zh_CN.ts +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/pyminer/pmgwidgets/widgets/basic/dialogs/__init__.py b/pyminer/pmgwidgets/widgets/basic/dialogs/__init__.py deleted file mode 100644 index 90afc909..00000000 --- a/pyminer/pmgwidgets/widgets/basic/dialogs/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding:utf-8 -*- -# @Time: 2021/2/10 10:12 -# @Author: Zhanyi Hou -# @Email: 1295752786@qq.com -# @File: __init__.py.py -from .textdialog import TextShowDialog \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/basic/dialogs/textdialog.py b/pyminer/pmgwidgets/widgets/basic/dialogs/textdialog.py deleted file mode 100644 index 3af4c2f4..00000000 --- a/pyminer/pmgwidgets/widgets/basic/dialogs/textdialog.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding:utf-8 -*- -# @Time: 2021/2/10 10:12 -# @Author: Zhanyi Hou -# @Email: 1295752786@qq.com -# @File: textdialog.py -from PySide2.QtCore import QSize -from PySide2.QtWidgets import QApplication, QDialog, QVBoxLayout, QTextBrowser - - -class TextShowDialog(QDialog): - def __init__(self, title: str, parent=None): - super(TextShowDialog, self).__init__(parent=parent) - self.setLayout(QVBoxLayout()) - self.setWindowTitle(title) - self.text_widget = QTextBrowser() - self.layout().addWidget(self.text_widget) - - def set_markdown(self, markdown: str): - self.text_widget.setMarkdown(markdown) - - def sizeHint(self) -> QSize: - return QSize(800, 600) diff --git a/pyminer/pmgwidgets/widgets/basic/images/__init__.py b/pyminer/pmgwidgets/widgets/basic/images/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/widgets/basic/images/imageview.py b/pyminer/pmgwidgets/widgets/basic/images/imageview.py deleted file mode 100644 index 796bc0ba..00000000 --- a/pyminer/pmgwidgets/widgets/basic/images/imageview.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- coding: utf-8 -*- -""" -This example demonstrates the use of ImageView, which is a high-level widget for -displaying and analyzing 2D and 3D data. ImageView provides: - - 1. A zoomable region (ViewBox) for displaying the image - 2. A combination histogram and gradient editor (HistogramLUTItem) for - controlling the visual appearance of the image - 3. A timeline for selecting the currently displayed frame (for 3D data only). - 4. Tools for very basic analysis of image data (see ROI and Norm buttons) - -""" -## Add path to library (just for examples; you do not need this) - - -from pyqtgraph.Qt import QtCore, QtGui -import pyqtgraph as pg -from PySide2.QtWidgets import QWidget, QVBoxLayout - - -class PMGImageViewer(QWidget): - def __init__(self, parent=None): - super(PMGImageViewer, self).__init__(parent) - self.image_view = pg.ImageView() - self.setLayout(QVBoxLayout()) - # QVBoxLayout.setC - self.layout().setContentsMargins(0, 0, 0, 0) - self.layout().addWidget(self.image_view) - - def set_image(self, img, xvals=None): - self.image_view.setImage(img) # , xvals=xvals) - - def set_color_map(self, colormap): - self.image_view.setColorMap(colormap=colormap) - - -if __name__ == '__main__': - import numpy as np - - # Interpret image data as row-major instead of col-major - pg.setConfigOptions(imageAxisOrder='row-major') - - app = QtGui.QApplication([]) - - ## Create window with ImageView widget - # win = QtGui.QMainWindow() - # win.resize(800, 800) - imv = PMGImageViewer() - imv.show() - imv.setWindowTitle('image view!') - # win.setCentralWidget(imv) - # win.show() - # win.setWindowTitle('pyqtgraph example: ImageView') - - ## Create random 3D data set with noisy signals - img = pg.gaussianFilter(np.random.normal(size=(200, 200)), (5, 5)) * 20 + 100 - img = img[np.newaxis, :, :] - decay = np.exp(-np.linspace(0, 0.3, 100))[:, np.newaxis, np.newaxis] - data = np.random.normal(size=(100, 200, 200)) - data += img * decay - data += 2 - - ## Add time-varying signal - sig = np.zeros(data.shape[0]) - sig[30:] += np.exp(-np.linspace(1, 10, 70)) - sig[40:] += np.exp(-np.linspace(1, 10, 60)) - sig[70:] += np.exp(-np.linspace(1, 10, 30)) - - sig = sig[:, np.newaxis, np.newaxis] * 3 - data[:, 50:60, 30:40] += sig - x = np.ones((1920, 1080, 3), dtype=np.uint8) + 50 - # x[:, :, 0] = np.zeros((1920, 1080)) + 200 - # x[:, :, 1] = 0 - # x[:, :, 2] = 0 - ## Display the data and assign each frame a time value from 1.0 to 3.0 - print(x.shape,x,data,data.shape) - imv.set_image(data) # , xvals=np.linspace(1., 3., data.shape[0])) - - ## Set a custom color map - colors = [ - (0, 0, 0), - (45, 5, 61), - (84, 42, 55), - (150, 87, 60), - (208, 171, 141), - (255, 255, 255) - ] - # cmap = pg.ColorMap(pos=np.linspace(0.0, 1.0, 6), color=colors) - # imv.set_color_map(cmap) - - ## Start Qt event loop unless running in interactive mode. - import sys - - if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): - QtGui.QApplication.instance().exec_() diff --git a/pyminer/pmgwidgets/widgets/basic/images/imageviewitem.py b/pyminer/pmgwidgets/widgets/basic/images/imageviewitem.py deleted file mode 100644 index 72dda37a..00000000 --- a/pyminer/pmgwidgets/widgets/basic/images/imageviewitem.py +++ /dev/null @@ -1,87 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Demonstrates very basic use of ImageItem to display image data inside a ViewBox. -""" - -## Add path to library (just for examples; you do not need this) -# from pyqtgraph.Qt import QtCore, QtGui -import pyqtgraph as pg -from PySide2.QtWidgets import QWidget, QVBoxLayout, QLabel, QScrollArea -from PySide2.QtGui import QImage, QPixmap -from PySide2.QtCore import Qt -import time -from typing import TYPE_CHECKING -from PIL import Image - -if TYPE_CHECKING: - import numpy as np - - -class PMGImageViewer(QWidget): - def __init__(self, parent=None): - """ - 这是一个可以用多种方式和数据类型设置、获取图片的控件。 - Args: - parent: - """ - super(QWidget, self).__init__(parent) - - self.setLayout(QVBoxLayout()) - self.img_show = QLabel() - self.img_show.setAlignment(Qt.AlignTop | Qt.AlignLeft) - self.scroll_widget = QScrollArea() - self.layout().addWidget(self.scroll_widget) - self.scroll_widget.setWidget(self.img_show) - - def set_image_qpixmap(self, pixmap): - self.img_show.setPixmap(pixmap) - self.img_show.setMinimumSize(pixmap.width() + 100, pixmap.height() + 100) - - def set_image_array(self, arr: 'np.ndarray'): - from PIL import Image - image2 = Image.fromarray(arr) - self.set_image_qpixmap(image2.toqpixmap()) - - def open_image(self, image_path): - from PIL import Image - img = Image.open(image_path) - # img.topixmap() - self.set_image_qpixmap(img.toqpixmap()) - - def get_image_qpixmap(self) -> QPixmap: - return self.img_show.pixmap() - - def get_image_array(self) -> 'np.ndarray': - from PIL import Image - img = Image.fromqpixmap(self.get_image_qpixmap()) - return np.array(img) - - -if __name__ == '__main__': - - from pyqtgraph.Qt import QtCore, QtGui - import numpy as np - import pyqtgraph as pg - import pyqtgraph.ptime as ptime - - app = QtGui.QApplication([]) - # read_figure() - - ## Create window with GraphicsView widget - win = PMGImageViewer() - win.showMaximized() ## show widget alone in its own window - win.setWindowTitle('pyqtgraph example: ImageItem') - - # updateData() - image = Image.open( - r'C:\Users\12957\Documents\Developing\Python\PyMiner_dev_kit\bin\pmgwidgets\doc_figures\pmflowarea_1.png') - # image = np.array(image) - # image2 = Image.fromarray(image) - # win.set_image(image2.toqpixmap()) - win.open_image( - r'C:\Users\12957\Documents\Developing\Python\PyMiner_dev_kit\bin\pmgwidgets\doc_figures\pmflowarea_1.png') - ## Start Qt event loop unless running in interactive mode. - import sys - - if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): - QtGui.QApplication.instance().exec_() diff --git a/pyminer/pmgwidgets/widgets/basic/labels/__init__.py b/pyminer/pmgwidgets/widgets/basic/labels/__init__.py deleted file mode 100644 index da270d58..00000000 --- a/pyminer/pmgwidgets/widgets/basic/labels/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .scrolllabel import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/basic/labels/scrolllabel.py b/pyminer/pmgwidgets/widgets/basic/labels/scrolllabel.py deleted file mode 100644 index 270f194f..00000000 --- a/pyminer/pmgwidgets/widgets/basic/labels/scrolllabel.py +++ /dev/null @@ -1,34 +0,0 @@ -from PySide2.QtWidgets import QWidget, QVBoxLayout, QLabel, QScrollArea - - -from PySide2.QtCore import Qt - - -class PMScrollableLabel(QWidget): - def __init__(self, parent=None): - super().__init__(parent) - layout = QVBoxLayout() - self.scroll_area = QScrollArea() - self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - self.label = QLabel() - layout_label = QVBoxLayout() - layout_label.addWidget(self.label) - self.scroll_area.setLayout(layout_label) - - layout.addWidget(self.scroll_area) - - self.setLayout(layout) - - self.setText = self.label.setText - self.setWordWrap = self.label.setWordWrap - - -if __name__ == '__main__': - from PySide2.QtWidgets import QApplication - import sys - app = QApplication(sys.argv) - w = PMScrollableLabel() - w.setWordWrap(True) - w.setText('aaaaaaaaa ' * 10000) - w.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/labels/translations/qt_zh_CN.ts b/pyminer/pmgwidgets/widgets/basic/labels/translations/qt_zh_CN.ts deleted file mode 100644 index ccc96b05..00000000 --- a/pyminer/pmgwidgets/widgets/basic/labels/translations/qt_zh_CN.ts +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/pyminer/pmgwidgets/widgets/basic/lists/__init__.py b/pyminer/pmgwidgets/widgets/basic/lists/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/widgets/basic/lists/combobasic.py b/pyminer/pmgwidgets/widgets/basic/lists/combobasic.py deleted file mode 100644 index a918a7f6..00000000 --- a/pyminer/pmgwidgets/widgets/basic/lists/combobasic.py +++ /dev/null @@ -1,62 +0,0 @@ -import sys -from PySide2.QtCore import * -from PySide2.QtWidgets import * -from PySide2.QtCore import * - - -class ComboxDemo(QWidget): - def __init__(self, parent=None): - super(ComboxDemo, self).__init__(parent) - # 设置标题 - self.setWindowTitle('ComBox例子') - # 设置初始界面大小 - self.resize(300, 90) - - # 垂直布局 - layout = QVBoxLayout() - # 创建标签,默认空白 - self.btn1 = QLabel('') - - # 实例化QComBox对象 - self.cb = QComboBox() - # 单个添加条目 - self.cb.addItem('C') - self.cb.addItem('C++') - self.cb.addItem('Python') - # 多个添加条目 - self.cb.addItems(['Java', 'C#', 'PHP']) - # 当下拉索引发生改变时发射信号触发绑定的事件 - self.cb.mousePressEvent = self.cb_mouse_pressed - self.cb.currentIndexChanged.connect(self.selectionchange) - - # 控件添加到布局中,设置布局 - layout.addWidget(self.cb) - layout.addWidget(self.btn1) - self.setLayout(layout) - - def cb_mouse_pressed(self, a0) -> None: - """ - 触发时自动改变选项。 - :param a0: - :return: - """ - self.cb.addItems(['A']) - QComboBox.mousePressEvent(self.cb, a0) - - def selectionchange(self, i): - # 标签用来显示选中的文本 - # currentText():返回选中选项的文本 - self.btn1.setText(self.cb.currentText()) - print('Items in the list are:') - # 输出选项集合中每个选项的索引与对应的内容 - # count():返回选项集合中的数目 - for count in range(self.cb.count()): - print('Item' + str(count) + '=' + self.cb.itemText(count)) - print('current index', i, 'selection changed', self.cb.currentText()) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - comboxDemo = ComboxDemo() - comboxDemo.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/lists/translations/qt_zh_CN.ts b/pyminer/pmgwidgets/widgets/basic/lists/translations/qt_zh_CN.ts deleted file mode 100644 index ccc96b05..00000000 --- a/pyminer/pmgwidgets/widgets/basic/lists/translations/qt_zh_CN.ts +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/pyminer/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py b/pyminer/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py deleted file mode 100644 index f29581fd..00000000 --- a/pyminer/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py +++ /dev/null @@ -1,97 +0,0 @@ -import os - -from PySide2 import QtCore -from PySide2.QtCore import QItemSelectionModel -from PySide2.QtWidgets import QApplication, QDialog -from .Ui_ConsoleHistoryDialog import Ui_ConsoleHistoryDialog - - -class ConsoleHistoryDialog(QDialog, Ui_ConsoleHistoryDialog): - """ - Class implementing the shell history dialog. - """ - - def __init__(self, console): - super().__init__() - self.setupUi(self) - self.__console = console - - self.deleteButton.clicked.connect(self.on_deleteButton_clicked) - self.copyButton.clicked.connect(self.on_copyButton_clicked) - self.reloadButton.clicked.connect(self.on_reloadButton_clicked) - self.historyList.itemSelectionChanged.connect( - self.on_historyList_itemSelectionChanged) - - self.reloadButton.click() - - @QtCore.Slot(QtCore.QModelIndex) - def select(self, item): - print(item.data()) - - @QtCore.Slot() - def on_historyList_itemSelectionChanged(self): - """ - Private slot to handle a change of the selection. - """ - selected = len(self.historyList.selectedItems()) > 0 - self.deleteButton.setEnabled(selected) - self.copyButton.setEnabled(selected) - self.executeButton.setEnabled(selected) - - @QtCore.Slot() - def on_deleteButton_clicked(self): - """ - Private slot to delete the selected entries from the history. - """ - for itm in self.historyList.selectedItems(): - ditm = self.historyList.takeItem(self.historyList.row(itm)) - del ditm - self.historyList.scrollToItem(self.historyList.currentItem()) - self.historyList.setFocus() - - @QtCore.Slot() - def on_copyButton_clicked(self): - cmds = self.selected_cmds() - QApplication.clipboard().setText(cmds) - - @QtCore.Slot() - def on_executeButton_clicked(self): - cmds = self.selected_cmds() - self.__console.hint_command(cmds) - self.__console.do_execute(cmds, True, '') - # reload the list because shell modified it - self.on_reloadButton_clicked() - - @QtCore.Slot() - def on_reloadButton_clicked(self): - """ - Private slot to reload the history. - """ - history = self.__console.history_tail(0) - - self.historyList.clear() - self.historyList.addItems(history) - self.historyList.setCurrentRow( - self.historyList.count() - 1, - QItemSelectionModel.SelectionFlag.Select) - - self.historyList.scrollToItem(self.historyList.currentItem()) - - @QtCore.Slot(QtCore.QModelIndex) - def on_historyList_doubleClicked(self, item): - self.on_executeButton_clicked() - - def get_history(self): - history = [] - for index in range(self.historyList.count()): - history.append(self.historyList.item(index).text()) - return history - - def selected_cmds(self): - lines = [] - for index in range(self.historyList.count()): - # selectedItems() doesn't seem to preserve the order - itm = self.historyList.item(index) - if itm.isSelected(): - lines.append(itm.text()) - return (os.linesep.join(lines) + os.linesep).rstrip(os.linesep) diff --git a/pyminer/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui b/pyminer/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui deleted file mode 100644 index 59fb2507..00000000 --- a/pyminer/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui +++ /dev/null @@ -1,158 +0,0 @@ - - ShellHistoryDialog - - - - 0 - 0 - 540 - 506 - - - - Shell History - - - true - - - - - - - Monospace - - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::ExtendedSelection - - - true - - - - - - - - - false - - - Delete the selected entries - - - &Delete - - - - - - - false - - - Copy the selected entries to the current editor - - - C&opy - - - - - - - false - - - Execute the selected entries - - - &Execute - - - - - - - Reload the history - - - &Reload - - - - - - - Qt::Vertical - - - - 72 - 208 - - - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - historyList - deleteButton - copyButton - executeButton - reloadButton - buttonBox - - - - - buttonBox - accepted() - ShellHistoryDialog - accept() - - - 333 - 487 - - - 323 - 505 - - - - - buttonBox - rejected() - ShellHistoryDialog - reject() - - - 167 - 490 - - - 169 - 504 - - - - - diff --git a/pyminer/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py b/pyminer/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py deleted file mode 100644 index e555d7ae..00000000 --- a/pyminer/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -# Form generated from reading UI file 'ConsoleHistoryDialog.ui' -## -# Created by: Qt User Interface Compiler version 6.1.0 -## -# WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide2.QtCore import * -from PySide2.QtGui import * -from PySide2.QtWidgets import * - - -class Ui_ConsoleHistoryDialog(object): - def setupUi(self, ConsoleHistoryDialog): - if not ConsoleHistoryDialog.objectName(): - ConsoleHistoryDialog.setObjectName(u"ConsoleHistoryDialog") - ConsoleHistoryDialog.resize(540, 506) - ConsoleHistoryDialog.setSizeGripEnabled(True) - self.gridLayout = QGridLayout(ConsoleHistoryDialog) - self.gridLayout.setObjectName(u"gridLayout") - self.historyList = QListWidget(ConsoleHistoryDialog) - self.historyList.setObjectName(u"historyList") - font = QFont() - font.setFamilies([u"Monospace"]) - self.historyList.setFont(font) - self.historyList.setEditTriggers(QAbstractItemView.NoEditTriggers) - self.historyList.setAlternatingRowColors(True) - self.historyList.setSelectionMode(QAbstractItemView.ExtendedSelection) - self.historyList.setWordWrap(True) - - self.gridLayout.addWidget(self.historyList, 0, 0, 1, 1) - - self.verticalLayout = QVBoxLayout() - self.verticalLayout.setObjectName(u"verticalLayout") - self.deleteButton = QPushButton(ConsoleHistoryDialog) - self.deleteButton.setObjectName(u"deleteButton") - self.deleteButton.setEnabled(False) - - self.verticalLayout.addWidget(self.deleteButton) - - self.copyButton = QPushButton(ConsoleHistoryDialog) - self.copyButton.setObjectName(u"copyButton") - self.copyButton.setEnabled(False) - - self.verticalLayout.addWidget(self.copyButton) - - self.executeButton = QPushButton(ConsoleHistoryDialog) - self.executeButton.setObjectName(u"executeButton") - self.executeButton.setEnabled(False) - - self.verticalLayout.addWidget(self.executeButton) - - self.reloadButton = QPushButton(ConsoleHistoryDialog) - self.reloadButton.setObjectName(u"reloadButton") - - self.verticalLayout.addWidget(self.reloadButton) - - self.verticalSpacer = QSpacerItem( - 72, 208, QSizePolicy.Minimum, QSizePolicy.Expanding) - - self.verticalLayout.addItem(self.verticalSpacer) - - self.gridLayout.addLayout(self.verticalLayout, 0, 1, 1, 1) - - self.buttonBox = QDialogButtonBox(ConsoleHistoryDialog) - self.buttonBox.setObjectName(u"buttonBox") - self.buttonBox.setStandardButtons( - QDialogButtonBox.Cancel | QDialogButtonBox.Ok) - - self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 2) - - QWidget.setTabOrder(self.historyList, self.deleteButton) - QWidget.setTabOrder(self.deleteButton, self.copyButton) - QWidget.setTabOrder(self.copyButton, self.executeButton) - QWidget.setTabOrder(self.executeButton, self.reloadButton) - QWidget.setTabOrder(self.reloadButton, self.buttonBox) - - self.retranslateUi(ConsoleHistoryDialog) - self.buttonBox.accepted.connect(ConsoleHistoryDialog.accept) - self.buttonBox.rejected.connect(ConsoleHistoryDialog.reject) - - QMetaObject.connectSlotsByName(ConsoleHistoryDialog) - # setupUi - - def retranslateUi(self, ConsoleHistoryDialog): - ConsoleHistoryDialog.setWindowTitle(QCoreApplication.translate( - "ConsoleHistoryDialog", u"Shell History", None)) -# if QT_CONFIG(tooltip) - self.deleteButton.setToolTip(QCoreApplication.translate( - "ConsoleHistoryDialog", u"Delete the selected entries", None)) -#endif // QT_CONFIG(tooltip) - self.deleteButton.setText(QCoreApplication.translate( - "ConsoleHistoryDialog", u"&Delete", None)) -# if QT_CONFIG(tooltip) - self.copyButton.setToolTip(QCoreApplication.translate( - "ConsoleHistoryDialog", u"Copy the selected entries to the current editor", None)) -#endif // QT_CONFIG(tooltip) - self.copyButton.setText(QCoreApplication.translate( - "ConsoleHistoryDialog", u"C&opy", None)) -# if QT_CONFIG(tooltip) - self.executeButton.setToolTip(QCoreApplication.translate( - "ConsoleHistoryDialog", u"Execute the selected entries", None)) -#endif // QT_CONFIG(tooltip) - self.executeButton.setText(QCoreApplication.translate( - "ConsoleHistoryDialog", u"&Execute", None)) -# if QT_CONFIG(tooltip) - self.reloadButton.setToolTip(QCoreApplication.translate( - "ConsoleHistoryDialog", u"Reload the history", None)) -#endif // QT_CONFIG(tooltip) - self.reloadButton.setText(QCoreApplication.translate( - "ConsoleHistoryDialog", u"&Reload", None)) - # retranslateUi diff --git a/pyminer/pmgwidgets/widgets/basic/others/__init__.py b/pyminer/pmgwidgets/widgets/basic/others/__init__.py deleted file mode 100644 index 1a3a3586..00000000 --- a/pyminer/pmgwidgets/widgets/basic/others/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -import typing -from .gauge import * -from .processconsole import PMGProcessConsoleWidget -from .instantbootconsole import PMGInstantBootConsoleWidget -if typing.TYPE_CHECKING: - import pmgwidgets.widgets.basic.others.console as console - - -def import_console_class() -> typing.Type['console.PMGIpythonConsole']: - """ - 导入这一步是耗时操作。为了节约pmgwidgets导入的时间,就使用了这种方式动态导入类。 - Returns: - - """ - import pmgwidgets.widgets.basic.others.console as console - return console.PMGIpythonConsole diff --git a/pyminer/pmgwidgets/widgets/basic/others/gauge.py b/pyminer/pmgwidgets/widgets/basic/others/gauge.py deleted file mode 100644 index 95543732..00000000 --- a/pyminer/pmgwidgets/widgets/basic/others/gauge.py +++ /dev/null @@ -1,223 +0,0 @@ -import random -import sys -import math -from typing import Tuple, Union, List - -from PySide2.QtCore import QTimer, Qt, QRectF, QPoint -from PySide2.QtGui import QPainter, QLinearGradient, QFontMetricsF, QPen, QFontMetrics, QRadialGradient, QConicalGradient, \ - QColor, QPolygon -from PySide2.QtWidgets import QWidget, QLCDNumber, QApplication - - -class PMGGauge(QWidget): - def __init__(self, val_range: Union[Tuple[Union[float, int], Union[float, int]], - List[Union[float, int]]] = None, - initial_value: float = None, title: str = 'Untitled', - warning_rate: float = 0.8): - super().__init__() - self._brush_color = Qt.black - if val_range is None: - val_range = (0, 100) - assert val_range[0] < val_range[1] - if initial_value is None: - initial_value = val_range[0] - - self._warning_rate = warning_rate - self.setWindowTitle("GaugePanel") - self.setMinimumWidth(200) - self.setMinimumHeight(200) - - self.lcd_display = QLCDNumber(self) - self.lcd_display.setDigitCount(4) - self.lcd_display.setMode(QLCDNumber.Dec) - self.lcd_display.setSegmentStyle(QLCDNumber.Flat) - self.lcd_display.setStyleSheet('border:2px solid green;color:green;background:silver') - - self._start_angle = 120 # 以QPainter坐标方向为准,建议画个草图看看 - self._end_angle = 60 # 以以QPainter坐标方向为准 - self._scale_main_num = 10 # 主刻度数 - self._scaleSubNum = 10 # 主刻度被分割份数 - self._min_value = val_range[0] - self._max_value = val_range[1] - self._title = title - self._value = initial_value - self._min_radio = 1 # 缩小比例,用于计算刻度数字 - self._decimals = 0 # 小数位数 - - def alert(self, alert_level: int): - """ - 1:严重警报 - 2:一般警报 - 其他值为正常 - :param alert_level: - :return: - """ - if alert_level == 2: - self._brush_color = QColor(200, 100, 40) - elif alert_level == 1: - self._brush_color = QColor(220, 50, 30) - else: - self._brush_color = Qt.black - self.update() - - def set_warning_rate(self, warning_rate: float): - assert 0 < warning_rate < 1 - self._warning_rate = warning_rate - - def set_min_max_value(self, min, max): - self._min_value = min - self._max_value = max - - def set_title(self, title): - self._title = title - - def set_value(self, value): - assert self._min_value <= value <= self._max_value, \ - f'Value %s is not in range [{self._min_value},{self._max_value}]' % (repr(value)) - self._value = value - self.update() - - def set_min_radio(self, min_radio): - self._min_radio = min_radio - - def set_decimals(self, decimals): - self._decimals = decimals - - def paintEvent(self, event): - side = min(self.width(), self.height()) - - painter = QPainter(self) - painter.setRenderHint(QPainter.Antialiasing) - painter.translate(self.width() / 2, self.height() / 2) # painter坐标系原点移至widget中央 - painter.scale(side / 200, side / 200) # 缩放painterwidget坐标系,使绘制的时钟位于widge中央,即钟表支持缩放 - - self.draw_panel(painter) # 画外框表盘 - self.draw_scale_num(painter) # 画刻度数字 - self.draw_scale_line(painter) # 画刻度线 - self.drawTitle(painter) # 画标题备注 - self.drawValue(painter) # 画数显 - self.drawIndicator(painter) # 画指针 - - def draw_panel(self, p): - p.save() - radius = 100 - lg = QLinearGradient(-radius, -radius, radius, radius) - lg.setColorAt(0, Qt.white) - lg.setColorAt(1, Qt.black) - p.setBrush(lg) - p.setPen(Qt.NoPen) - p.drawEllipse(-radius, -radius, radius * 2, radius * 2) - - p.setBrush(self._brush_color) - p.drawEllipse(-92, -92, 92 * 2, 92 * 2) - p.restore() - - def draw_scale_num(self, p): - sin = math.sin - cos = math.cos - p.save() - p.setPen(Qt.white) - start_rad = self._start_angle * (3.14 / 180) - step_rad = (360 - (self._start_angle - self._end_angle)) * (3.14 / 180) / self._scale_main_num - - fm = QFontMetricsF(p.font()) - for i in range(0, self._scale_main_num + 1): - sina = sin(start_rad + i * step_rad) - cosa = cos(start_rad + i * step_rad) - - tmp_val = i * ((self._max_value - self._min_value) / self._scale_main_num) + self._min_value - tmp_val = tmp_val / self._min_radio - s = '{:.0f}'.format(tmp_val) - w = fm.size(Qt.TextSingleLine, s).width() - h = fm.size(Qt.TextSingleLine, s).height() - x = 80 * cosa - w / 2 - y = 80 * sina - h / 2 - p.drawText(QRectF(x, y, w, h), s) - - p.restore() - - def draw_scale_line(self, p): - p.save() - p.rotate(self._start_angle) - scale_nums = self._scale_main_num * self._scaleSubNum - angle_step = (360 - (self._start_angle - self._end_angle)) / scale_nums - p.setPen(Qt.white) - - pen = QPen(Qt.white) - for i in range(0, scale_nums + 1): - if i >= self._warning_rate * scale_nums: - pen.setColor(Qt.red) - - if i % self._scale_main_num == 0: - pen.setWidth(2) - p.setPen(pen) - p.drawLine(64, 0, 72, 0) - else: - pen.setWidth(1) - p.setPen(pen) - p.drawLine(67, 0, 72, 0) - p.rotate(angle_step) - - p.restore() - - def drawTitle(self, p): - p.save() - p.setPen(Qt.white) - fm = QFontMetrics(p.font()) - w = fm.size(Qt.TextSingleLine, self._title).width() - p.drawText(int(-w / 2), -45, self._title) - p.restore() - - def drawValue(self, p): - side = min(self.width(), self.height()) - w, h = int(side / 2 * 0.4), int(side / 2 * 0.2) - x, y = int(self.width() / 2 - w / 2), int(self.height() / 2 + side / 2 * 0.55) - self.lcd_display.setGeometry(x, y, w, h) - - ss = '{:.' + str(self._decimals) + 'f}' - self.lcd_display.display(ss.format(self._value)) - - def drawIndicator(self, p): - p.save() - polygon = QPolygon([QPoint(0, -2), QPoint(0, 2), QPoint(60, 0)]) - deg_rotate = self._start_angle + (360 - (self._start_angle - self._end_angle)) / ( - self._max_value - self._min_value) * (self._value - self._min_value) - # 画指针 - p.rotate(deg_rotate) - halogd = QRadialGradient(0, 0, 60, 0, 0) - halogd.setColorAt(0, QColor(60, 60, 60)) - halogd.setColorAt(1, QColor(160, 160, 160)) - p.setPen(Qt.white) - p.setBrush(halogd) - p.drawConvexPolygon(polygon) - p.restore() - - # 画中心点 - p.save() - rad_gradient = QRadialGradient(0, 0, 10) - rad_gradient = QConicalGradient(0, 0, -90) - rad_gradient.setColorAt(0.0, Qt.darkGray) - rad_gradient.setColorAt(0.5, Qt.white) - rad_gradient.setColorAt(1.0, Qt.darkGray) - p.setPen(Qt.NoPen) - p.setBrush(rad_gradient) - p.drawEllipse(-5, -5, 10, 10) - p.restore() - - -if __name__ == "__main__": - import cgitb - - cgitb.enable() - app = QApplication(sys.argv) - gp = PMGGauge(val_range=(0, 100), initial_value=0, title='CPU占用%', warning_rate=0.75) - gp.show() - - timer = QTimer() - timer.start(100) - timer.timeout.connect(lambda: gp.set_value(random.randint(0, 100))) - - timer2 = QTimer() - timer2.start(1000) - timer2.timeout.connect(lambda: gp.alert(random.randint(0, 2))) - app.exec_() diff --git a/pyminer/pmgwidgets/widgets/basic/others/instantbootconsole.py b/pyminer/pmgwidgets/widgets/basic/others/instantbootconsole.py deleted file mode 100644 index 87fae315..00000000 --- a/pyminer/pmgwidgets/widgets/basic/others/instantbootconsole.py +++ /dev/null @@ -1,287 +0,0 @@ -""" -作者:侯展意 -有关QThread为什么行,为什么不行 -我也不知道啊... -""" -import os -import time -import sys -import logging -import socket - -from PySide2.QtCore import QThread, QObject, Signal, Qt -from PySide2.QtGui import QCloseEvent, QKeyEvent, QIcon -from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QCheckBox, QTextEdit - -logger = logging.getLogger(__name__) - -from pmgwidgets.utilities.platform.openprocess import PMGProcess - -def connect(): - address = ('127.0.0.1', 37789) # 服务端地址和端口 - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - s.connect(address) # 尝试连接服务端 - except Exception: - print('[!] Server not found ot not open') -class ProcessMonitorThread(QObject): - on_err = Signal(str) - on_out = Signal(str) - on_finished = Signal() - - def __init__(self): - super().__init__() - self.process_terminated = False - self.args = None - - def stop(self): - self.process.terminate = True - self.process_terminated = True - - def run(self): - self.process = PMGProcess(self.args) - self.q = self.process.q - idleLoops = 0 - while True: - if self.process_terminated == True: - return - if not self.q.empty(): - line = self.q.get() - if line[0] == '1': - self.on_out.emit(line[1:]) - else: - self.on_err.emit(line[1:]) - sys.stdout.flush() - else: - time.sleep(0.01) - if idleLoops >= 5: - idleLoops = 0 - if self.process.process.poll() is None: - pass - else: - self.on_finished.emit() - return - continue - idleLoops += 1 - - -class ProcessConsole(QTextEdit): - signal_stop_qthread = Signal() - signal_process_stopped = Signal() - signal_process_started = Signal() - - insert_mode = '' - - def __init__(self, args: list = None): - super().__init__() - self._is_running = False - self.auto_scroll = True - self.args = args # - self.setContentsMargins(20, 20, 0, 0) - self.monitor_thread: 'ProcessMonitorThread' = None - self.out_thread: 'QThread' = None - - def set_args(self, args: list = None): - self.args = args - - def is_running(self) -> bool: - """ - 返回进程是否在运行 - Returns: - - """ - if self.monitor_thread is not None: - process = self.get_subprocess() - if process is not None: - if process.poll() is None: - return True - return False - - def start_process(self): - if not self.is_running(): - self.out_thread = QThread(self) - self.monitor_thread = ProcessMonitorThread() - self.monitor_thread.args = self.args - self.monitor_thread.moveToThread(self.out_thread) - - self.out_thread.started.connect(self.monitor_thread.run) - self.out_thread.start() - - self.monitor_thread.on_out.connect(self.on_stdout) - self.monitor_thread.on_err.connect(self.on_stderr) - - self.signal_stop_qthread.connect(self.monitor_thread.stop) - - self.out_thread.finished.connect(self.out_thread.deleteLater) - self.out_thread.finished.connect(self.monitor_thread.deleteLater) - - self.monitor_thread.on_finished.connect(self.terminate_process) - - def on_stdout(self, text): - if self.insert_mode == 'error': - self.insertHtml('

' + '========' + '

') - self.insert_mode = 'stdout' - - self.insertPlainText(text) - if self.auto_scroll: - self.ensureCursorVisible() - - def on_stderr(self, text): - self.insert_mode = 'error' - self.insertHtml('

' + text + '

') - print(text) - if self.auto_scroll: - self.ensureCursorVisible() - - def terminate_process(self): - if self.monitor_thread is not None: - self.monitor_thread.process_terminated = True - self.monitor_thread.process.process.terminate() - if self.out_thread.isRunning(): - self.signal_stop_qthread.emit() - self.out_thread.quit() - self.out_thread.wait(500) - self.monitor_thread = None - self.out_thread = None - self.signal_process_stopped.emit() - - def keyPressEvent(self, e: 'QKeyEvent'): - if e.key() == Qt.Key_Backspace or e.key() == Qt.Key_Delete: - return - print(e.key(), e.text()) - if e.key() == Qt.Key_Return: - text = '\n' - else: - text = e.text() - if text != '' and self.monitor_thread is not None: - try: - print('sent:', text) - self.monitor_thread.process.process.stdin.write(text.encode('utf8')) - self.monitor_thread.process.process.stdin.flush() - except: - import traceback - traceback.print_exc() - super(ProcessConsole, self).keyPressEvent(e) - - def get_subprocess(self): - """ - 返回子进程 - Returns: - - """ - if hasattr(self.monitor_thread, 'process'): - proc = self.monitor_thread.process - if hasattr(proc, 'process'): - return proc.process - return None - - -class PMGInstantBootConsoleWidget(QWidget): - def __init__(self, file: str): - super().__init__() - self.hbox_layout = QHBoxLayout() - self.tool_widget = QWidget() - self.tool_widget.setLayout(QVBoxLayout()) - script_path = os.path.join(os.path.dirname(__file__), 'scripts', 'instant_boot.py') - assert os.path.exists(script_path) - self.process_console = ProcessConsole(args=[sys.executable, '-u', script_path, file]) - self.process_console.signal_process_stopped.connect(self.on_terminated) - - self.button_to_start = QPushButton() - self.button_to_start.setToolTip(self.tr('Start')) - icon_path = os.path.dirname(__file__) - self.button_to_start.setIcon(QIcon(os.path.join(icon_path, 'source', 'run.png'))) - self.tool_widget.layout().addWidget(self.button_to_start) - self.button_to_start.clicked.connect(self.start_process) - - self.button_to_terminate = QPushButton() - self.button_to_terminate.setToolTip(self.tr('Terminate')) - self.button_to_terminate.setIcon(QIcon(os.path.join(icon_path, 'source', 'stop.png'))) - self.tool_widget.layout().addWidget(self.button_to_terminate) - self.button_to_terminate.clicked.connect(self.terminate_and_restart_process) - - self.button_to_clear = QPushButton() - self.button_to_clear.setToolTip(self.tr('Clear')) - self.tool_widget.layout().addWidget(self.button_to_clear) - self.button_to_clear.setIcon(QIcon(os.path.join(icon_path, 'source', 'clear.png'))) - self.button_to_clear.clicked.connect(lambda: self.process_console.clear()) - - self.button_to_clear.setMaximumWidth(20) - self.button_to_start.setMaximumWidth(20) - self.button_to_terminate.setMaximumWidth(20) - self.autoscroll_checker = QCheckBox() - self.autoscroll_checker.setToolTip('autoscroll') - - self.tool_widget.layout().addWidget(self.autoscroll_checker) - self.autoscroll_checker.stateChanged.connect(self.set_autoscroll) - self.autoscroll_checker.setChecked(True) - self.set_autoscroll() - - self.hbox_layout.addWidget(self.tool_widget) - vbox = QVBoxLayout() - self.hbox_layout.addLayout(vbox) - vbox.addWidget(self.process_console) - # self.command_input = QLineEdit() - # vbox.addWidget() - self.setLayout(self.hbox_layout) - - self.process_console.start_process() - - def set_autoscroll(self): - print(self.autoscroll_checker.isChecked()) - self.process_console.auto_scroll = self.autoscroll_checker.isChecked() - - def on_terminated(self, close=False): - if not close: - self.process_console.start_process() - self.button_to_start.setEnabled(True) - self.button_to_terminate.setEnabled(False) - - def on_started(self): - self.button_to_start.setEnabled(False) - self.button_to_terminate.setEnabled(True) - - def start_process(self): - print('start this console!') - self.process_console.monitor_thread.process.process.stdin.write(b'run!\n\n') - self.process_console.monitor_thread.process.process.stdin.flush() - self.on_started() - - def terminate_and_restart_process(self): - self.terminate_process() - self.on_terminated() - - def terminate_process(self): - self.process_console.terminate_process() - - def is_process_running(self) -> bool: - return self.process_console.is_running() - - # def disconnect_events(self): - - - def closeEvent(self, a0: QCloseEvent) -> None: - - if self.process_console.is_running(): - self.process_console.signal_process_stopped.disconnect(self.on_terminated) - self.terminate_process() - super(PMGInstantBootConsoleWidget, self).closeEvent(a0) - - def set_args(self, args: list): - self.process_console.set_args(args) - - -if __name__ == '__main__': - import cgitb - import sys - - cgitb.enable(format='text') - from PySide2.QtWidgets import QApplication, QTextEdit - - app = QApplication(sys.argv) - - w = PMGInstantBootConsoleWidget(r'C:\Users\12957\Documents\Developing\Python\PyMiner_dev_kit\bin' - r'\pmgwidgets\widgets\basic\others\scripts\test1_instant_boot.py') - w.show() - - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/others/processconsole.py b/pyminer/pmgwidgets/widgets/basic/others/processconsole.py deleted file mode 100644 index 223b7ffd..00000000 --- a/pyminer/pmgwidgets/widgets/basic/others/processconsole.py +++ /dev/null @@ -1,319 +0,0 @@ -""" -作者:侯展意 -有关QThread为什么行,为什么不行 -我也不知道啊... -""" -import os -import re -import time -import sys -import logging - -from PySide2.QtCore import QThread, QObject, Signal, Qt, QUrl -from PySide2.QtGui import QCloseEvent, QKeyEvent, QIcon, QDesktopServices, QColor -from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QCheckBox, QTextEdit, QApplication, \ - QMessageBox - -logger = logging.getLogger(__name__) - -from pmgwidgets.utilities.platform.openprocess import PMGProcess - - -class ProcessMonitorThread(QObject): - on_err = Signal(str) - on_out = Signal(str) - on_finished = Signal() - - def __init__(self): - super().__init__() - self.process_terminated = False - self.args = None - - def stop(self): - self.process.terminate = True - self.process_terminated = True - - def run(self): - try: - self.process = PMGProcess(self.args) - self.q = self.process.q - idleLoops = 0 - while True: - if self.process_terminated == True: - return - if not self.q.empty(): - line = self.q.get() - if line[0] == '1': - self.on_out.emit(line[1:]) - else: - self.on_err.emit(line[1:]) - sys.stdout.flush() - else: - time.sleep(0.01) - if idleLoops >= 5: - idleLoops = 0 - if self.process.process.poll() is None: - pass - else: - self.on_finished.emit() - return - continue - idleLoops += 1 - except: - import traceback - traceback.print_exc() - - -class ProcessConsole(QTextEdit): - signal_stop_qthread = Signal() - signal_process_stopped = Signal() - signal_process_started = Signal() - signal_hyperlink_clicked = Signal(str) - signal_goto_file = Signal(str, int) - insert_mode = '' - - def __init__(self, args: list = None): - super().__init__() - self.anchor = None - self._is_running = False - self.auto_scroll = True - self.args = args # - self.setContentsMargins(20, 20, 0, 0) - self.monitor_thread: 'ProcessMonitorThread' = None - self.out_thread: 'QThread' = None - self.signal_hyperlink_clicked.connect(self.on_hyperlink_clicked) - - def set_args(self, args: list = None): - self.args = args - - def is_running(self): - if self.monitor_thread is not None: - if self.monitor_thread.process.process.poll() is None: - return True - return False - - def start_process(self): - if not self.is_running(): - self.out_thread = QThread(self) - self.monitor_thread = ProcessMonitorThread() - self.monitor_thread.args = self.args - self.monitor_thread.moveToThread(self.out_thread) - - self.out_thread.started.connect(self.monitor_thread.run) - self.out_thread.start() - - self.monitor_thread.on_out.connect(self.on_stdout) - self.monitor_thread.on_err.connect(self.on_stderr) - - self.signal_stop_qthread.connect(self.monitor_thread.stop) - - self.out_thread.finished.connect(self.out_thread.deleteLater) - self.out_thread.finished.connect(self.monitor_thread.deleteLater) - - self.monitor_thread.on_finished.connect(self.terminate_process) - self.clear() - self.insertHtml('

' + ' '.join(self.args) + '

') - self.insertHtml('

' + '' + '

') - - def on_stdout(self, text): - - if self.insert_mode == 'error': - self.insert_mode = 'stdout' - - self.insertHtml(self.insertHtml('

' + text + '

')) - if self.auto_scroll: - self.ensureCursorVisible() - - def on_stderr(self, text): - self.insert_mode = 'error' - # result = re.search(r'(/|([a-zA-Z]:((\\)|/))).*:[0-9].*', text) - result = re.search(r'(/|([a-zA-Z]:((\\)|/))).* line [0-9].*,', text) - print(result) - if result is None: - self.insertHtml('

' + text + '

') - else: - span = result.span() - self.insertHtml('

' + text[:span[0]] + '

') - print(result.group()) - self.insert_hyperlink(text[span[0]: span[1]]) - # self.insertHtml('

' + text[result[0]:result[1]] + '

') - self.insertHtml('

' + text[span[1]:] + '

') - if self.auto_scroll: - self.ensureCursorVisible() - - def terminate_process(self): - if self.monitor_thread is not None: - self.monitor_thread.process_terminated = True - self.monitor_thread.process.process.terminate() - if self.out_thread.isRunning(): - self.signal_stop_qthread.emit() - self.out_thread.quit() - self.out_thread.wait(500) - self.monitor_thread = None - self.out_thread = None - self.signal_process_stopped.emit() - - def keyPressEvent(self, e: 'QKeyEvent'): - if e.key() == Qt.Key_Backspace or e.key() == Qt.Key_Delete: - return - print(e.key(), e.text()) - if e.key() == Qt.Key_Return: - text = '\n' - else: - text = e.text() - if text != '' and self.monitor_thread is not None: - try: - print('sent:', text) - self.monitor_thread.process.process.stdin.write(text.encode('utf8')) - self.monitor_thread.process.process.stdin.flush() - except: - import traceback - traceback.print_exc() - super(ProcessConsole, self).keyPressEvent(e) - - def mousePressEvent(self, e): - super(ProcessConsole, self).mousePressEvent(e) - self.anchor = self.anchorAt(e.pos()) - # if self.anchor: - # QApplication.setOverrideCursor(Qt.PointingHandCursor) - - def mouseMoveEvent(self, e): - super(ProcessConsole, self).mouseMoveEvent(e) - self.anchor = self.anchorAt(e.pos()) - if not self.anchor: - QApplication.setOverrideCursor(Qt.ArrowCursor) - else: - QApplication.setOverrideCursor(Qt.PointingHandCursor) - - def mouseReleaseEvent(self, e): - super(ProcessConsole, self).mouseReleaseEvent(e) - if self.anchor: - # QDesktopServices.openUrl(QUrl(self.anchor)) - # QApplication.setOverrideCursor(Qt.ArrowCursor) - self.signal_hyperlink_clicked.emit(self.anchor) - self.anchor = None - - def insert_hyperlink(self, link: str, text=''): - cursor = self.textCursor() - fmt = cursor.charFormat() - fmt.setForeground(QColor('#0063c5')) - # address = 'http://example.com' - fmt.setAnchor(True) - fmt.setAnchorHref(link) - fmt.setToolTip(link) - if text == '': - cursor.insertText(link, fmt) - else: - cursor.insertText(text, fmt) - - def on_hyperlink_clicked(self, hyperlink_text: str): - if re.search(r'(/|([a-zA-Z]:((\\)|/))).* line [0-9].*,', hyperlink_text) is not None: - try: - l = hyperlink_text.split('line') - assert len(l) == 2, l - for i in [0, 1]: - l[i] = l[i].strip(', \"\'') - file_path, row_str = l - row = int(row_str) - if not os.path.exists(file_path): - QMessageBox.warning(self, self.tr('Warning'), self.tr('文件%s不存在!' % file_path)) - else: - self.signal_goto_file.emit(file_path, row) - logger.info('goto file %s, line %d' % (file_path, row)) - except: - import traceback - traceback.print_exc() - - -class PMGProcessConsoleWidget(QWidget): - signal_goto_file = Signal(str, int) - - def __init__(self, args: list = None): - super().__init__() - self.hbox_layout = QHBoxLayout() - self.tool_widget = QWidget() - self.tool_widget.setLayout(QVBoxLayout()) - self.process_console = ProcessConsole(args=args) - self.process_console.signal_goto_file.connect(self.signal_goto_file.emit) - self.process_console.signal_process_stopped.connect(self.on_terminated) - - self.button_to_start = QPushButton() - self.button_to_start.setToolTip(self.tr('Start')) - icon_path = os.path.dirname(__file__) - self.button_to_start.setIcon(QIcon(os.path.join(icon_path, 'source', 'run.png'))) - self.tool_widget.layout().addWidget(self.button_to_start) - self.button_to_start.clicked.connect(self.start_process) - - self.button_to_terminate = QPushButton() - self.button_to_terminate.setToolTip(self.tr('Terminate')) - self.button_to_terminate.setIcon(QIcon(os.path.join(icon_path, 'source', 'stop.png'))) - self.tool_widget.layout().addWidget(self.button_to_terminate) - self.button_to_terminate.clicked.connect(self.terminate_process) - - self.button_to_clear = QPushButton() - self.button_to_clear.setToolTip(self.tr('Clear')) - self.tool_widget.layout().addWidget(self.button_to_clear) - self.button_to_clear.setIcon(QIcon(os.path.join(icon_path, 'source', 'clear.png'))) - self.button_to_clear.clicked.connect(lambda: self.process_console.clear()) - - self.button_to_clear.setMaximumWidth(20) - self.button_to_start.setMaximumWidth(20) - self.button_to_terminate.setMaximumWidth(20) - self.autoscroll_checker = QCheckBox() - self.autoscroll_checker.setToolTip('autoscroll') - - self.tool_widget.layout().addWidget(self.autoscroll_checker) - self.autoscroll_checker.stateChanged.connect(self.set_autoscroll) - self.autoscroll_checker.setChecked(True) - self.set_autoscroll() - - self.hbox_layout.addWidget(self.tool_widget) - vbox = QVBoxLayout() - self.hbox_layout.addLayout(vbox) - vbox.addWidget(self.process_console) - # self.command_input = QLineEdit() - # vbox.addWidget() - self.setLayout(self.hbox_layout) - - def set_autoscroll(self): - self.process_console.auto_scroll = self.autoscroll_checker.isChecked() - - def on_terminated(self): - self.button_to_start.setEnabled(True) - self.button_to_terminate.setEnabled(False) - - def on_started(self): - self.button_to_start.setEnabled(False) - self.button_to_terminate.setEnabled(True) - - def start_process(self): - self.process_console.start_process() - self.on_started() - - def terminate_process(self): - self.process_console.terminate_process() - self.on_terminated() - - def is_process_running(self) -> bool: - return self.process_console.is_running() - - def closeEvent(self, a0: QCloseEvent) -> None: - self.terminate_process() - super(PMGProcessConsoleWidget, self).closeEvent(a0) - - def set_args(self, args: list): - self.process_console.set_args(args) - - -if __name__ == '__main__': - import cgitb - import sys - - cgitb.enable(format='text') - - app = QApplication(sys.argv) - w = PMGProcessConsoleWidget( - [sys.executable, '-u', os.path.join(os.path.dirname(__file__), 'scripts', 'test2_open_app.py')]) - w.show() - - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/others/source/clear.png b/pyminer/pmgwidgets/widgets/basic/others/source/clear.png deleted file mode 100644 index 97d20a373b8529370418907572e8ed143f25ebaa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10255 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 KWVN_y@c#j;E56MD diff --git a/pyminer/pmgwidgets/widgets/basic/others/source/run.png b/pyminer/pmgwidgets/widgets/basic/others/source/run.png deleted file mode 100644 index 045fd3387941d0f305715b9097bcd2736c40bf1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7956 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 diff --git a/pyminer/pmgwidgets/widgets/basic/others/source/stop.png b/pyminer/pmgwidgets/widgets/basic/others/source/stop.png deleted file mode 100644 index c2b9b96aa79a7d512887576d60c8454e24d8ef71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5258 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 diff --git a/pyminer/pmgwidgets/widgets/basic/others/translations/qt_zh_CN.ts b/pyminer/pmgwidgets/widgets/basic/others/translations/qt_zh_CN.ts deleted file mode 100644 index 2fbbd02a..00000000 --- a/pyminer/pmgwidgets/widgets/basic/others/translations/qt_zh_CN.ts +++ /dev/null @@ -1,69 +0,0 @@ - - - - PMGIpythonConsole - - - Cut - 剪切 - - - - Copy - 复制 - - - - Copy(Raw Text) - 复制(原始文本) - - - - Paste - 粘贴 - - - - Select All - 全选 - - - - Save as HTML/XML - 以HTML/XML存储 - - - - Print - 打印 - - - - Restart - 重启 - - - - Interrupt - 中断当前执行 - - - - PMGProcessConsoleWidget - - - Start - 启动 - - - - Terminate - 停止 - - - - Clear - 清除 - - - diff --git a/pyminer/pmgwidgets/widgets/basic/plots/__init__.py b/pyminer/pmgwidgets/widgets/basic/plots/__init__.py deleted file mode 100644 index ecbf1e9f..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .bars import * -from .lines import * -from .matplotlib import * -from .pyqtgraph import * diff --git a/pyminer/pmgwidgets/widgets/basic/plots/bars/__init__.py b/pyminer/pmgwidgets/widgets/basic/plots/bars/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/widgets/basic/plots/bars/histogram.py b/pyminer/pmgwidgets/widgets/basic/plots/bars/histogram.py deleted file mode 100644 index 29a64716..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/bars/histogram.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -""" -In this example we draw two different kinds of histogram. -""" -import numpy as np -import pyqtgraph as pg -import sys -from PySide2.QtWidgets import QApplication -from pmgwidgets.widgets.basic.plots import PMGPyQtGraphWidget -from pmgwidgets import color_str2tup - - -class PMGBarWidget(PMGPyQtGraphWidget): - def __init__(self, parent=None): - super().__init__(parent=parent) - self.plot_widget = pg.PlotWidget(self) - self.v_layout.addWidget(self.plot_widget) - - def plot(self, vals): - y, x = np.histogram(vals, bins=np.linspace(-3, 8, 40)) - self.plot_widget.plot(x, y, stepMode=True, fillLevel=0, fillOutline=True, - pen=pg.mkPen(self.border_color, width = self.border_width), - brush=color_str2tup(self.item_color)) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - demo = PMGBarWidget() - demo.show() - demo.border_width = 3 - demo.border_color = '#ffff00' - demo.plot(np.random.normal(size=500)) - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/plots/lines/__init__.py b/pyminer/pmgwidgets/widgets/basic/plots/lines/__init__.py deleted file mode 100644 index dd494875..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/lines/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -import warnings - -try: - from .timeseries import * -except ImportError as e: - warnings.warn(str(e)) diff --git a/pyminer/pmgwidgets/widgets/basic/plots/lines/timeseries.py b/pyminer/pmgwidgets/widgets/basic/plots/lines/timeseries.py deleted file mode 100644 index 8c93830e..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/lines/timeseries.py +++ /dev/null @@ -1,193 +0,0 @@ -import time -from random import randint - -from PySide2.QtGui import QBrush, QColor -from PySide2.QtWidgets import QHBoxLayout, QLabel, QSpacerItem, QSizePolicy -from typing import List, Union, Tuple -import pyqtgraph as pg -from PySide2.QtWidgets import QVBoxLayout, QWidget, QSpinBox -from pmgwidgets.widgets.basic.plots.pyqtgraph.base.pgplot import PMGPyQtGraphWidget -from pmgwidgets import color_str2tup, TYPE_RANGE -from pmgwidgets import iter_isinstance - - -def convert_time(time_stamp: Union[float, int]): - return time.strftime('%H:%M:%S', time.localtime(time_stamp)) - - -class TimeSeriesPGWidget(PMGPyQtGraphWidget): - """ - 性能很好的监视面板,300个点每分钟刷新一次,可以保持 - """ - - def __init__(self, parent=None, face_color=None, text_color=None): - super().__init__(parent, text_color=text_color) - self.face_color = face_color - self.text_color = text_color - self.plot_widget = pg.PlotWidget(self, axisItems={'bottom': pg.DateAxisItem()}, background=self.face_color) - - self.legend = self.plot_widget.addLegend(brush=QBrush(QColor(255, 255, 255)), offset=(-10, 10), - labelTextColor=self.text_color, labelTextSize=8) - self.v_layout.addWidget(self.plot_widget) - # self.setMinimumSize(300, 200) - # self.setMaximumSize(450, 300) - self.xlabel: str = '' - self.ylabel: str = '' - self.threshold_range: TYPE_RANGE = None - self.x_range: Tuple[float, float] = None - self.y_range: Tuple[float, float] = None - self.title: str = '' - self.ticks = 5 - self.show_data_num = 10 - self.max_data = 200 - self.timestamp_list = [] - self.value_list = [] - self.repaint_all = False - - def show_time_series(self, timestamps: List[float], values: List[List[float]], tags=None): - self.clear() - for value_list in values: - if value_list is not None: - assert len(timestamps) == len(value_list) - if tags is not None: - assert len(tags) == len(values) - else: - tags = [i + 1 for i in range(len(values))] - self.plot_widget.plotItem.setTitle(self.title) - self.plot(timestamps, values, tags) - - def gen_threshold_line(self, x): - return [self.threshold_range[0] for i in x], [self.threshold_range[1] for i in x] - - def get_threshold_line_num(self) -> int: - s = 0 - if self.threshold_range is None: - return s - if self.threshold_range[0] is not None: - s += 1 - if self.threshold_range[1] is not None: - s += 1 - return s - - def plot(self, x, ylist, tags: List = None): - """ - 绘图方法 - :param x: - :param ylist: - :param tags: 标签 - :return: - """ - if (len(ylist) + self.get_threshold_line_num() != len(self.lines) and self.threshold_range is not None) or \ - (len(ylist) != len(self.lines) and self.threshold_range is None): - - if tags is None: - tags = [None] * len(ylist) - - for line in self.lines: - line.clear() - self.lines = [] - if self.y_range is not None: - self.plot_widget.setYRange(*self.y_range) - self.legend.clear() - # if self.threshold_range - if self.threshold_range is not None: - threshold_lower, threshold_upper = self.gen_threshold_line(x) - if self.threshold_range[0] is not None: - l1 = self.plot_widget.plot(x, threshold_lower, pen='#ff0000') - self.lines.append(l1) - if self.threshold_range[1] is not None: - l2 = self.plot_widget.plot(x, threshold_upper, pen='#ff0000') - self.lines.append(l2) - assert len(self._symbols) >= len(ylist), 'Too much lines for monitor!' - for i, y in enumerate(ylist): - plot_data = self.plot_widget.plot(x, y, **self._symbols[i], name=tags[i]) - self.lines.append(plot_data) - self.legend.setBrush(QColor(*color_str2tup(self.legend_face_color), 100)) - # TODO add opacity settings choices! - else: - if self.threshold_range is not None: - - threshold_lower, threshold_upper = self.gen_threshold_line(x) - if self.threshold_range is not None: - threshold_lower, threshold_upper = self.gen_threshold_line(x) - if self.threshold_range[0] is not None and self.threshold_range[1] is not None: - self.lines[0].setData(x, threshold_lower) - self.lines[1].setData(x, threshold_upper) - else: - if self.threshold_range[1] is not None: - self.lines[0].setData(x, threshold_upper, pen='#ff0000') - - if self.threshold_range[0] is not None: - self.lines[0].setData(x, threshold_lower, pen='#ff0000') - - for i, y in enumerate(ylist): - self.lines[i + self.get_threshold_line_num()].setData(x, y) - else: - for i, y in enumerate(ylist): - self.lines[i].setData(x, y) - - -class PMGTimeSeriesPlot(QWidget): - def __init__(self, parent: QWidget = None, - threshold_range: TYPE_RANGE = None, face_color=None, text_color=None): - super(PMGTimeSeriesPlot, self).__init__(parent) - - self.threshold_range = threshold_range - layout = QVBoxLayout() - self.setLayout(layout) - layout.setContentsMargins(0, 0, 0, 0) - self.control_layout = QHBoxLayout() - self.control_layout.setContentsMargins(0, 0, 0, 0) - - self.time_series = TimeSeriesPGWidget(face_color=face_color, text_color=text_color) - self.layout().addWidget(self.time_series) - self.layout().addLayout(self.control_layout) - - def set_data(self, timestamps: List[float], values: List[List[float]], tags: List[str] = None): - self.time_series.show_time_series(timestamps, values, tags) - - def insert_data(self, timestamp: float, values: List[float], tags: List[float]): - raise NotImplementedError - self.time_series.insert_data(timestamp, values) - - def config_chart_text(self, title: str, xlabel: str, ylabel: str): - self.time_series.title = title - self.time_series.xlabel = xlabel - self.time_series.ylabel = ylabel - - def alert(self, alert_level: int): - if alert_level == 1: - self.time_series.face_color = '#dc321e' - elif alert_level == 2: - self.time_series.face_color = '#c86428' - else: - self.time_series.face_color = '#ffffff' - - -if __name__ == '__main__': - import sys - from PySide2.QtWidgets import QApplication - from PySide2.QtCore import QTimer - - app = QApplication(sys.argv) - pmqt5mplwgt = PMGTimeSeriesPlot() - pmqt5mplwgt.time_series.line_color = '#ff0000' - pmqt5mplwgt.time_series.border_color = '#ff0000' - pmqt5mplwgt.time_series.symbol = '圆' - pmqt5mplwgt.time_series.y_range = (0, 100) - pmqt5mplwgt.time_series.threshold_line = 0.8 * 100 - pmqt5mplwgt.config_chart_text(title='时间序列数据', xlabel='时间', ylabel='') - timer = QTimer() - - - def f(): - n = 300 - pmqt5mplwgt.set_data([i + 1 for i in range(n)], - [[randint(0, 30) for i in range(n)], [randint(0, 100) for i in range(n)]], - ['Cpu1', 'Cpu2']) - - - timer.timeout.connect(f) - timer.start(33) - pmqt5mplwgt.show() - app.exec_() diff --git a/pyminer/pmgwidgets/widgets/basic/plots/matplotlib/__init__.py b/pyminer/pmgwidgets/widgets/basic/plots/matplotlib/__init__.py deleted file mode 100644 index aa854a4a..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/matplotlib/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -import warnings -import os -try: - import matplotlib - from .base import * -except Exception as e: - warnings.warn(str(e)) diff --git a/pyminer/pmgwidgets/widgets/basic/plots/matplotlib/base/__init__.py b/pyminer/pmgwidgets/widgets/basic/plots/matplotlib/base/__init__.py deleted file mode 100644 index 9fde31f5..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/matplotlib/base/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .qt5aggplot import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/basic/plots/matplotlib/base/pmaggplot.py b/pyminer/pmgwidgets/widgets/basic/plots/matplotlib/base/pmaggplot.py deleted file mode 100644 index 3fdb9194..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/matplotlib/base/pmaggplot.py +++ /dev/null @@ -1,46 +0,0 @@ -import sys -from PySide2 import QtWidgets -import matplotlib.pyplot as plt -import random -import os - -f = os.path.dirname -s = __file__ -for i in range(7): - s = f(s) -sys.path.append(os.path.join(s, 'pyminer2/extensions/packages/pmagg')) -try: - import PMAgg -except: - import traceback - - traceback.print_exc() - - -class MainWindow(QtWidgets.QDialog): - def __init__(self, figure, config_path): - super().__init__() - layout = QtWidgets.QVBoxLayout() - mpl_app = PMAgg.Window(config_path) - # 只需要将mpl绘图产生的figure对象以及一个配置文件.cfg的路径传给PMAgg即可,配置文件可以留空。 - mpl_app.get_canvas(figure) - layout.addWidget(mpl_app) - # 一个额外的按钮 - self.button = QtWidgets.QPushButton('test') - layout.addWidget(self.button) - self.setLayout(layout) - - -if __name__ == '__main__': - # matplotlib 绘图 - fig = plt.figure() - ax = fig.add_subplot(111) - data = [random.random() for i in range(25)] - ax.plot(data, '*-') - # app - app = QtWidgets.QApplication(sys.argv) - config_path = os.path.join(r'/pyminer2/extensions/packages/pmagg', 'settings.cfg') - main = MainWindow(fig, config_path) - main.setWindowTitle('Simple PySide2 and PMAgg example') - main.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/plots/matplotlib/base/qt5aggplot.py b/pyminer/pmgwidgets/widgets/basic/plots/matplotlib/base/qt5aggplot.py deleted file mode 100644 index c88513aa..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/matplotlib/base/qt5aggplot.py +++ /dev/null @@ -1,50 +0,0 @@ -from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg -import matplotlib.pyplot as plt -from PySide2.QtWidgets import QVBoxLayout, QWidget -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from matplotlib.axes._subplots import Axes - - -class PMMatplotlibQt5Widget(QWidget): - def __init__(self, parent=None): - super().__init__(parent) - self.figure = plt.figure(facecolor='#FFD7C4') # 可选参数,facecolor为背景颜色 - self.canvas = FigureCanvasQTAgg(self.figure) - layout = QVBoxLayout() - layout.addWidget(self.canvas) - self.setLayout(layout) - - def add_subplot(self, param) -> 'Axes': - return self.figure.add_subplot(param) - - def draw(self) -> None: - self.canvas.draw() - - def clear(self): - self.figure.clf() - - -if __name__ == '__main__': - import sys - # from PySide2.QtWidgets import QApplication - from PySide2.QtWidgets import QApplication - from pmgwidgets.display import PMMatplotlibQt5Widget - - - def draw(): - ax = pmqt5mplwgt.add_subplot(121) - ax2 = pmqt5mplwgt.add_subplot(122) - ax.plot([1, 2, 3]) - ax.set_xlabel('test_x_label') - ax2.set_xlabel('test_2') - ax2.plot([1, 3, 1, 4, 15]) - pmqt5mplwgt.draw() - - - app = QApplication(sys.argv) - pmqt5mplwgt = PMMatplotlibQt5Widget() - pmqt5mplwgt.show() - draw() - app.exec_() diff --git a/pyminer/pmgwidgets/widgets/basic/plots/pyqtgraph/__init__.py b/pyminer/pmgwidgets/widgets/basic/plots/pyqtgraph/__init__.py deleted file mode 100644 index 512fd95e..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/pyqtgraph/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -import warnings - -try: - import pyqtgraph - from .base import * -except Exception as e: - warnings.warn(str(e)) diff --git a/pyminer/pmgwidgets/widgets/basic/plots/pyqtgraph/base/__init__.py b/pyminer/pmgwidgets/widgets/basic/plots/pyqtgraph/base/__init__.py deleted file mode 100644 index 5c16dae4..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/pyqtgraph/base/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .pgplot import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/basic/plots/pyqtgraph/base/pgplot.py b/pyminer/pmgwidgets/widgets/basic/plots/pyqtgraph/base/pgplot.py deleted file mode 100644 index db0a8704..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/pyqtgraph/base/pgplot.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -相关的元素设置 - -线: -颜色--line_color -线型--line_style -粗细--line_width - -图元item -边缘线的颜色--border_color -边缘线粗细--border_width -形状--symbol -颜色--item_color - -图窗颜色 -face_color - -['o', 's', 't', 't1', 't2', 't3', 'd', '+', 'x', 'p', 'h', 'star'] - # r_color = random.choice(['b', 'g', 'r', 'c', 'm', 'y', 'k', 'd', 'l', 's']) -""" -import sys -from typing import Union - -import pyqtgraph as pg -from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout -from pmgwidgets.utilities.source.graphicsitemutils import PMGPlotCustomizer - -symbols_dic = {'o': 'o', 's': 's', 't': 't', 't1': 't1', 't2': 't2', 't3': 't3', - 'd': 'd', '+': '+', 'x': 'x', 'p': 'p', 'h': 'h', 'star': 'star', - '圆': 'o', '方': 's', '正三角': 't1', '倒三角': 't', '五边形': 'p', '六边形': 'h', '星': 'star', - '五星': 'star', '菱形': 'd'} -random_symbols = [ - dict(pen=(0, 0, 200), symbolBrush=(0, 0, 200), symbolPen='w', symbol='o', symbolSize=8), - dict(pen=(0, 128, 0), symbolBrush=(0, 128, 0), symbolPen='w', symbol='t', symbolSize=8), - dict(pen=(19, 234, 201), symbolBrush=(19, 234, 201), symbolPen='w', symbol='t1', symbolSize=8), - dict(pen=(195, 46, 212), symbolBrush=(195, 46, 212), symbolPen='w', symbol='t2', symbolSize=8), - dict(pen=(250, 194, 5), symbolBrush=(250, 194, 5), symbolPen='w', symbol='t3', symbolSize=8), - dict(pen=(54, 55, 55), symbolBrush=(55, 55, 55), symbolPen='w', symbol='s', symbolSize=8), - dict(pen=(0, 114, 189), symbolBrush=(0, 114, 189), symbolPen='w', symbol='p', symbolSize=8), - dict(pen=(217, 83, 25), symbolBrush=(217, 83, 25), symbolPen='w', symbol='h', symbolSize=8), - dict(pen=(237, 177, 32), symbolBrush=(237, 177, 32), symbolPen='w', symbol='star', symbolSize=8), - dict(pen=(126, 47, 142), symbolBrush=(126, 47, 142), symbolPen='w', symbol='+', symbolSize=8), - dict(pen=(119, 172, 48), symbolBrush=(119, 172, 48), symbolPen='w', symbol='d', symbolSize=8), -] - - -class PMGPyQtGraphWidget(QWidget, PMGPlotCustomizer): - def __init__(self, parent=None, text_color=None): - super(PMGPyQtGraphWidget, self).__init__(parent) - self._symbols_dic = symbols_dic - self._symbols = random_symbols - self.resize(600, 600) - self.lines = [] - pg.setConfigOptions(leftButtonPan=False) - text_color = 'k' if text_color is None else text_color - pg.setConfigOption('foreground', text_color) - self.plot_widget: pg.PlotWidget = None - self.v_layout = QVBoxLayout() - self.v_layout.setContentsMargins(0, 0, 0, 0) - self.setLayout(self.v_layout) - - def plot(self, *args, **kwargs): - pass - - def baseplot(self, x, ylist): - for line in self.lines: - line.clear() - for y in ylist: - plot_data = self.plot_widget.plot(x, y, pen=None, symbol='+', symbolBrush='r') - self.lines.append(plot_data) - - def draw(self): - pass - - def clear(self): - pass - - -if __name__ == '__main__': - app = QApplication(sys.argv) - demo = PMGPyQtGraphWidget() - demo.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/plots/scatters/__init__.py b/pyminer/pmgwidgets/widgets/basic/plots/scatters/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/widgets/basic/plots/scatters/scatters.py b/pyminer/pmgwidgets/widgets/basic/plots/scatters/scatters.py deleted file mode 100644 index 82074ea8..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/scatters/scatters.py +++ /dev/null @@ -1,34 +0,0 @@ -import pyqtgraph as pg -import numpy as np -from PySide2.QtWidgets import QApplication -from pmgwidgets.widgets.basic.plots.pyqtgraph import PMGPyQtGraphWidget -from pmgwidgets import color_str2tup -import sys - - -class PMGScatterPlot(PMGPyQtGraphWidget): - def __init__(self, parent=None): - super(PMGScatterPlot, self).__init__(parent) - self.plot_widget = pg.PlotWidget(self) - self.v_layout.addWidget(self.plot_widget) - - def plot(self): - n = 300 - self.s1 = pg.ScatterPlotItem(size=10, - pen=pg.mkPen(self.border_color,width = self.border_width), - brush=color_str2tup(self.item_color)) - pos = np.random.normal(size=(2, n), scale=1e-5) - spots = [{'pos': pos[:, i], 'data': 1} for i in range(n)] + [{'pos': [0, 0], 'data': 1}] - print(spots) - self.s1.addPoints(spots) - self.plot_widget.addItem(self.s1) - print(self.plot_widget.getPlotItem()) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - pw = PMGScatterPlot() - pw.border_color = '#ff0000' - pw.show() - pw.plot() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/plots/translations/qt_zh_CN.ts b/pyminer/pmgwidgets/widgets/basic/plots/translations/qt_zh_CN.ts deleted file mode 100644 index ccc96b05..00000000 --- a/pyminer/pmgwidgets/widgets/basic/plots/translations/qt_zh_CN.ts +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/pyminer/pmgwidgets/widgets/basic/quick/__init__.py b/pyminer/pmgwidgets/widgets/basic/quick/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/widgets/basic/quick/demo1.py b/pyminer/pmgwidgets/widgets/basic/quick/demo1.py deleted file mode 100644 index 99cba18f..00000000 --- a/pyminer/pmgwidgets/widgets/basic/quick/demo1.py +++ /dev/null @@ -1,34 +0,0 @@ -from PySide2.QtCore import QUrl, QObject, Slot - -from PySide2.QtGui import QGuiApplication - -from PySide2.QtQuick import QQuickView - - -class MyClass(QObject): - - @Slot(int, result=str) # 声明为槽,输入参数为int类型,返回值为str类型 - def returnValue(self, value): - return str(value + 10) - - -if __name__ == '__main__': - path = 'src/demo1.qml' - - app = QGuiApplication([]) - - view = QQuickView() - - con = MyClass() - - context = view.rootContext() - - context.setContextProperty("con", con) - - view.engine().quit.connect(app.quit) - - view.setSource(QUrl(path)) - - view.show() - - app.exec_() diff --git a/pyminer/pmgwidgets/widgets/basic/tables/__init__.py b/pyminer/pmgwidgets/widgets/basic/tables/__init__.py deleted file mode 100644 index 7c90eb9d..00000000 --- a/pyminer/pmgwidgets/widgets/basic/tables/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .tableviews import * -from .tablewidgets import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/basic/tables/help/help.md b/pyminer/pmgwidgets/widgets/basic/tables/help/help.md deleted file mode 100644 index b8d270b8..00000000 --- a/pyminer/pmgwidgets/widgets/basic/tables/help/help.md +++ /dev/null @@ -1,44 +0,0 @@ -# 数据查看与编辑 帮助 Help -## 操作说明 -### 跳转到行: - -点击“跳转到行”按钮,或者快捷键`Ctrl+G`均可。 - -但是注意,很多时候pandas的Index是从0开始的。因此行的索引为399时,实际的行号应该是400. - - -# 高亮颜色说明 -### Pandas -Pandas的数据类型是相当复杂的,不同的数据类型之间常常发生混淆。 - -让我们考虑下面的情况:字符串`'2017-06-27'`和pandas的TimeStamp型数据`'2017-06-27'`,这两个数据其实是完全不同的。 -但是在数据集难以明显的区分出来。 -因此我们就用这样的高亮方式,方便区分数据集的数据类型。 - -在PyMiner对Pandas数据的高亮方式中,可以很好很方便的区分这个问题。 - -- 如果是字符串,就会用黄色背景这样显示:2017-06-27 - -- 如果是时间戳类型,则会用绿色背景这样显示:2017-06-27 - -高亮颜色的说明如下: -- 数值型: - - - 整数:123 - - 浮点数:3.1415 - - 复数:1+1j - -- 布尔型: -True -- 时间型: -2017-07-20 -- 字符串型:黄色 -John Strauss -- 其他类型:灰色 - - None - - person(自定义数据类型) - - NaN - - NaT - -### Numpy -目前没有高亮效果,未来的高亮效果计划以大小值为依据,配色方案参考pandas的方案。 \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/basic/tables/tableviews.py b/pyminer/pmgwidgets/widgets/basic/tables/tableviews.py deleted file mode 100644 index 1abb5252..00000000 --- a/pyminer/pmgwidgets/widgets/basic/tables/tableviews.py +++ /dev/null @@ -1,680 +0,0 @@ -""" -这是一个利用QT的MVC架构进行数据查看的表格。这个表格十分适合大量数据的查看,1000*1000规模的数据集可以做到秒开。 -其中定义了若干类。可以直接显示pd.DataFrame,np.array和list的TableView。 - -目前增加了切片索引查看功能和編輯功能。对dataframe而言,切片时可以编辑 -但是array在切片的时候编辑。 - -作者:侯展意 -""" -import os -import sys - -import typing -import logging -from PySide2.QtGui import QColor -from PySide2.QtWidgets import QSpacerItem, QComboBox, QSpinBox, QLabel -from PySide2.QtWidgets import QTableView, QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QPushButton, \ - QMessageBox, QInputDialog, QMenu, QDialog, QDialogButtonBox, QShortcut, QSizePolicy -from PySide2.QtCore import QAbstractTableModel, QModelIndex, Signal, QLocale, QCoreApplication -from PySide2.QtCore import Qt, QPoint -from PySide2.QtGui import QContextMenuEvent, QKeyEvent, QKeySequence - -from pmgwidgets.utilities.source.translation import create_translator -from pmgwidgets.widgets.basic.dialogs.textdialog import TextShowDialog - -if typing.TYPE_CHECKING: - import numpy as np - -logger = logging.getLogger(__name__) - - -class InputValueDialog(QDialog): - UP = -1 - DOWN = 1 - signal_move_cursor = Signal(int) - signal_edit_finished = Signal(str) - - def __init__(self, parent): - super(InputValueDialog, self).__init__(parent) - self.setLayout(QVBoxLayout()) - self.edit = QLineEdit() - self.layout().addWidget(self.edit) - self.edit.returnPressed.connect(self.edit_finished) - self.button_box = QDialogButtonBox() - self.button_box.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) - self.layout().addWidget(self.button_box) - self.button_box.rejected.connect(self.close) - self.button_box.accepted.connect(self.edit_finished) - - def edit_finished(self): - self.close() - self.signal_edit_finished.emit(self.edit.text()) - - def keyPressEvent(self, e: QKeyEvent): - if e.key() == Qt.Key_Up: - self.close() - self.signal_move_cursor.emit(self.UP) - e.accept() - elif e.key() == Qt.Key_Down: - self.close() - self.signal_move_cursor.emit(self.DOWN) - e.accept() - - super(InputValueDialog, self).keyPressEvent(e) - - -def to_decimal_str(cell_data: 'np.ndarray', decimals: int = 6): - import numpy as np - try: - rounded_data = np.around(cell_data, decimals) - return repr(rounded_data) - except: - return str(cell_data) - - -def dataformat(val, decimals=6, sci=False): - """ - 这只是暂时的strformat函数。如有可能,应当使用cython重写并且部署在动态链接库中,从而提升性能。 - Args: - val: - decimals: - sci: - - Returns: - - """ - global type_float_set - return to_decimal_str(val, decimals) - - -class BaseAbstractTableModel(QAbstractTableModel): - @property - def default_slicing_statement(self): - raise NotImplementedError - - -class TableModelForList(BaseAbstractTableModel): - """ - 输入为list的table model - """ - - def __init__(self, data: list): - super(TableModelForList, self).__init__() - import numpy as np - self._data: np.ndarray = data - - def data(self, index, role): - if role == Qt.DisplayRole: - return dataformat(self._data[index.row()][index.column()]) - - def rowCount(self, index): - return len(self._data) - - def columnCount(self, index): - return len(self._data[0]) - - -class TableModelForNumpyArray(BaseAbstractTableModel): - """ - 输入为pandas.DataFram的TableModel,用于在表格中显示数据。 - """ - - def __init__(self, data): - super(TableModelForNumpyArray, self).__init__() - self._data = data - self.horizontal_start: int = 0 - self.vertical_start: int = 0 - - def setData(self, index: 'QModelIndex', value: typing.Any = None, role='Qt.EditRole'): - """ - # View中编辑后,View会调用这个方法修改Model中的数据 - :param index: - :param value: - :param role: - :return: - """ - - if index.isValid() and 0 <= index.row() < self._data.shape[0] and value: - col = index.column() - row = index.row() - - if len(self._data.shape) == 1: # 一维矩阵 - self.beginResetModel() - self._data[row] = value - self.dirty = True - self.endResetModel() - return True - else: - if 0 <= col < self._data.shape[1]: - self.beginResetModel() - self._data[row, col] = value - - self.dirty = True - self.endResetModel() - return True - return False - - def data(self, index, role): - if role == Qt.DisplayRole: - if len(self._data.shape) >= 2: - value = self._data[index.row(), index.column()] - else: - value = self._data[index.column()] - return dataformat(value) - - def rowCount(self, index): - if len(self._data.shape) >= 2: - return self._data.shape[0] - else: - return 1 - # return self._data.shape[0] - - def columnCount(self, index): - if len(self._data.shape) == 1: - return self._data.shape[0] - else: - return self._data.shape[1] - - def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> typing.Any: - if role == Qt.DisplayRole: - if role == Qt.DisplayRole: - if orientation == Qt.Horizontal: - return str(self.horizontal_start + section) - if orientation == Qt.Vertical: - return str(self.vertical_start + section) - - @property - def default_slicing_statement(self): - """ - 默认切片数组 - :return: - """ - data_dim = len(self._data.shape) - if data_dim in (1, 2): - - return '[%s]' % (':,' * data_dim).strip(',') - else: - return '[%s]' % (':,:,' + '0,' * (data_dim - 2)).strip(',') - - -class TableModelForPandasDataframe(BaseAbstractTableModel): - """ - 输入为pandas.DataFram的TableModel,用于在表格中显示数据。 - """ - - def __init__(self, data, original_data): - super(TableModelForPandasDataframe, self).__init__() - self._data: 'pd.DataFrame' = data - self.original_data = original_data - self.colors = {'int': QColor(0, 0, 128, 100), 'bool': QColor(0, 200, 200, 100), - 'float': QColor(0, 64, 128, 100), 'str': QColor(200, 200, 0, 100), - 'timestamp': QColor(0, 200, 0, 100), - 'complex': QColor(100, 0, 128, 100) - } - - def get_color(self, data): - import numpy as np - import pandas as pd - if isinstance(data, (np.bool_, bool)): - return self.colors['bool'] - elif isinstance(data, (np.integer, int)): - return self.colors['int'] - elif isinstance(data, (np.inexact, float)): - if isinstance(data, np.complex_): - return self.colors['complex'] - return self.colors['float'] - elif isinstance(data, (str)): - return self.colors['str'] - elif isinstance(data, (pd.Timestamp)): - return self.colors['timestamp'] - elif data == np.nan: - return QColor(0, 0, 50, 100) - elif data == pd.NaT: - return QColor(0, 50, 0, 100) - - return QColor(0, 0, 0, 80) - - def data(self, index, role): - if role == Qt.DisplayRole: - value = self._data.iloc[index.row(), index.column()] - return dataformat(value) - if role == Qt.BackgroundRole: - data = self._data.iloc[index.row(), index.column()] - return self.get_color(data) - - def rowCount(self, index): - return self._data.shape[0] - - def columnCount(self, index): - return self._data.shape[1] - - def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> typing.Any: - if role == Qt.DisplayRole: - if role == Qt.DisplayRole: - if orientation == Qt.Horizontal: - return str(self._data.columns[section]) - if orientation == Qt.Vertical: - return str(self._data.index[section]) - - @property - def default_slicing_statement(self): - """ - 默认切片数组 - :return: - """ - data_dim = len(self._data.shape) - return '.iloc[%s]' % (':,' * data_dim).strip(',') - - def setData(self, index, value=None, role=Qt.EditRole): - # 编辑后更新模型中的数据 View中编辑后,View会调用这个方法修改Model中的数据 - if index.isValid() and 0 <= index.row() < self._data.shape[0] and value: - col = index.column() - row = index.row() - if 0 <= col < self._data.shape[1]: - self.beginResetModel() - col_label = self._data.columns[col] - row_label = self._data.index[row] - self.original_data.loc[row_label, col_label] = value - self._data.loc[row_label, col_label] = value - self.dirty = True - self.endResetModel() - return True - return False - - -class PMTableView(QTableView): - """ - 基类,用于显示数据。输入数据类型为列表。 - """ - INSERT_ROW = 0 - DELETE_ROW = 1 - INSERT_COLUMN = 2 - DELETE_COLUMN = 3 - - signal_need_save = Signal(bool) - - def __init__(self, data=None): - super().__init__() - self.translator = create_translator( - path=os.path.join(os.path.dirname(__file__), 'translations', - 'qt_{0}.qm'.format(QLocale.system().name()))) # translator - self.data = None - self.menu = QMenu() - self.action_insert_row = self.menu.addAction(QCoreApplication.translate('PMTableView', 'Insert Row')) - self.action_insert_row.triggered.connect(lambda: self.on_change_row_col(self.INSERT_ROW)) - self.action_delete_row = self.menu.addAction(QCoreApplication.translate('PMTableView', 'Delete Row')) - self.action_delete_row.triggered.connect(lambda: self.on_change_row_col(self.DELETE_ROW)) - self.action_insert_col = self.menu.addAction(QCoreApplication.translate('PMTableView', 'Insert Column')) - self.action_insert_col.triggered.connect(lambda: self.on_change_row_col(self.INSERT_COLUMN)) - self.action_delete_col = self.menu.addAction(QCoreApplication.translate('PMTableView', 'Delete Column')) - self.action_delete_col.triggered.connect(lambda: self.on_change_row_col(self.DELETE_COLUMN)) - # self.menu.addAction("aaaaaa") - if data is not None: - self.set_data(data) - - def on_change_row_col(self, operation: int): - """ - The slot for editting row or columns - Args: - operation: - - Returns: - - """ - import pandas as pd - import numpy as np - pd_data: pd.DataFrame = self.model._data - current_index = self.currentIndex() - row, column = current_index.row(), current_index.column() - if operation == self.INSERT_ROW: - prev = pd_data.iloc[:row] - lat = pd_data.iloc[row:] - self.model._data = pd.concat([prev, pd.DataFrame([[]]), lat]) - elif operation == self.DELETE_ROW: - prev = pd_data.iloc[:row] - lat = pd_data.iloc[row + 1:] - self.model._data = pd.concat([prev, lat]) - elif operation == self.INSERT_COLUMN: - col_name: str = '' - col_name, _ = QInputDialog.getText(self, QCoreApplication.translate('PMTableView', 'Input Column Title'), - QCoreApplication.translate('PMTableView', 'Title')) - if _: - if col_name.isdigit(): - col_name = int(col_name) - # if col_name in pd_data.columns: - # QMessageBox.warning(self, QCoreApplication.translate("PMTableView", "Warning"), - # QCoreApplication.translate("PMTableView", - # "Input value was integer, however the value will be converted to string." % col_name)) - # return - try: - pd_data.insert(column, col_name, np.nan) - except ValueError: - QMessageBox.warning(self, QCoreApplication.translate("PMTableView", "Error"), - QCoreApplication.translate("PMTableView", - "Column name \'%s\', type\'%s\' duplicated with existing column!" % ( - col_name, type(col_name)))) - - elif operation == self.DELETE_COLUMN: - # prev = pd_data.iloc[:row] - # lat = pd_data.iloc[row + 1:] - # self.model._data = pd.concat([prev, lat]) - self.model._data = pd_data.drop(columns=[column], axis=0) - else: - raise NotImplementedError - self.model.layoutChanged.emit() - self.signal_need_save.emit(True) - - def set_data(self, data): - self.data = data - self.show_data(data) - - def get_data(self): - return self.model._data - - def show_data(self, data): - """ - data可能是self.data,也可能是self.data的一部分。 - Args: - data: - - Returns: - - """ - import pandas as pd - import numpy as np - if isinstance(data, pd.DataFrame): - self.model = TableModelForPandasDataframe(data, self.data) - elif isinstance(data, np.ndarray): - self.model = TableModelForNumpyArray(data) - self.menu.setEnabled(False) - elif isinstance(data, list): - self.model = TableModelForList(data) - self.menu.setEnabled(True) - else: - raise Exception("data type %s is not supported in PMTableView.\ - \n Supported Types are: numpy.array,list and pandas.DataFrame." % type(data)) - self.setModel(self.model) - - def get_default_slicing_statement(self): - return self.model.default_slicing_statement - - def mouseDoubleClickEvent(self, event: 'QMouseEvent') -> None: - """ - Args: - event: - - Returns: - - """ - super().mouseDoubleClickEvent(event) - self.show_edit_dialog(self.currentIndex().row(), self.currentIndex().column()) - - def keyPressEvent(self, event: QKeyEvent) -> None: - super(PMTableView, self).keyPressEvent(event) - if event.key() == Qt.Key_Return: - self.show_edit_dialog(self.currentIndex().row(), self.currentIndex().column()) - - def show_edit_dialog(self, row, col): - import pandas as pd - import numpy as np - data = self.model._data - if isinstance(data, (pd.DataFrame, np.ndarray)): - def on_edited(text): - from pandas import Timestamp, Period, Interval - try: - result = eval(text) - if isinstance(data, pd.DataFrame): - data.iloc[row, col] = result - elif isinstance(data, np.ndarray): - data[row, col] = result - self.signal_need_save.emit(True) - except: - import traceback - QMessageBox.warning(self, QCoreApplication.translate('PMTableView', 'Warning'), - traceback.format_exc()) - return - - def on_move_current_cell(direction: int): - target_row = row + direction - if 0 <= target_row < self.model.rowCount(col): - self.setCurrentIndex(self.model.index(target_row, col)) - self.show_edit_dialog(target_row, col) - - if isinstance(data, pd.DataFrame): - original_data = data.iloc[row, col] - elif isinstance(data, np.ndarray): - original_data = data[row, col] - else: - raise NotImplementedError - - dlg = InputValueDialog(self) - dlg.setWindowTitle(QCoreApplication.translate('PMTableView', 'Input New Value')) - dlg.edit.setText(repr(original_data)) - dlg.signal_edit_finished.connect(on_edited) - dlg.signal_move_cursor.connect(on_move_current_cell) - global_pos = self.mapToGlobal( - QPoint(self.columnViewportPosition(col) + 50, self.rowViewportPosition(row) + 50)) - dlg.setGeometry(global_pos.x(), global_pos.y(), dlg.width(), dlg.height()) - dlg.exec_() - # QInputDialog.getText(self, QCoreApplication.translate('PMTableView','Input New Value'), '', QLineEdit.Normal, - # text=repr(original_data)) - - def contextMenuEvent(self, event: QContextMenuEvent): - import pandas as pd - if isinstance(self.model._data, pd.DataFrame): - self.menu.exec_(event.globalPos()) - - def on_goto_index(self, row: int, col: int = 0): - import pandas as pd - import numpy as np - - if isinstance(self.data, (pd.DataFrame, np.ndarray)): - assert 0 <= row <= self.model.rowCount(None) - self.setCurrentIndex(self.model.index(row, col)) - - -class PMGTableViewer(QWidget): - """ - 一个含有QTableView的控件。 - 有切片和保存两个按钮。点击Slice的时候可以切片查看,点击Save保存。 - """ - data_modified_signal = Signal() - signal_need_save = Signal(bool) - - def __init__(self, parent=None, table_view: 'PMTableView' = None): - super().__init__(parent) - - self.setLayout(QVBoxLayout()) - self.top_layout = QHBoxLayout() - self.layout().addLayout(self.top_layout) - self.table_view = table_view - self.slice_input = QLineEdit() - self.help_button = QPushButton(QCoreApplication.translate('PMGTableViewer', '帮助')) - self.slice_refresh_button = QPushButton(QCoreApplication.translate('PMGTableViewer', '切片')) - self.save_change_button = QPushButton(QCoreApplication.translate('PMGTableViewer', '保存')) - self.goto_cell_button = QPushButton(QCoreApplication.translate('PMGTableViewer', '前往单元格')) - - self.label_slice_axis2 = QLabel("高度索引:") - - self.slice_axis2 = QSpinBox() - self.slice_axis2.setMinimum(0) - self.slice_axis2.setSingleStep(1) - self.slice_axis2.setMaximum(0) - self.slice_axis2.valueChanged.connect(self.on_axis2_value_changed) - - self.save_change_button.clicked.connect(self.on_save) - self.slice_refresh_button.clicked.connect(self.slice) - self.help_button.clicked.connect(self.on_help) - self.goto_cell_button.clicked.connect(self.on_goto_cell) - self.slice_input.hide() - self.slice_refresh_button.hide() - - self.table_view.signal_need_save.connect(self.signal_need_save.emit) - self.signal_need_save.connect(self.on_signal_need_save) - - self.top_layout.addWidget(self.label_slice_axis2) - self.top_layout.addWidget(self.slice_axis2) - - self.label_slice_axis2.hide() - self.slice_axis2.hide() - - self.top_layout.addWidget(self.goto_cell_button) - self.top_layout.addWidget(self.save_change_button) - self.top_layout.addWidget(self.help_button) - self.top_layout.addWidget(self.slice_input) - self.top_layout.addWidget(self.slice_refresh_button) - self.top_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum)) - - if table_view is not None: - self.layout().addWidget(self.table_view) - - self.shortcut_save = QShortcut(QKeySequence.Save, self.table_view, context=Qt.WidgetShortcut) - self.shortcut_save.activated.connect(self.on_save) - - self.shortcut_goto = QShortcut(QKeySequence('Ctrl+G'), self.table_view, context=Qt.WidgetShortcut) - self.shortcut_goto.activated.connect(self.on_goto_cell) - - def on_axis2_value_changed(self): - """ - 当显示多维数组时,如果改变第三维的索引,就调用这个函数 - Returns: - - """ - import numpy as np - if isinstance(self.table_view.data, np.ndarray): - if len(self.table_view.data.shape) > 2: - self.table_view.show_data(self.table_view.data[self.slice_axis2.value(), :, :]) - - def on_high_dimensional_array(self, high_dimensional: bool): - self.label_slice_axis2.setVisible(high_dimensional) - self.slice_axis2.setVisible(high_dimensional) - - def on_help(self): - dlg = TextShowDialog(title=QCoreApplication.translate('PMGTableViewer', '帮助')) - with open(os.path.join(os.path.dirname(__file__), 'help', 'help.md'), 'r', encoding='utf8', - errors='replace') as f: - dlg.set_markdown(f.read()) - dlg.exec_() - - def on_signal_need_save(self, need_save: str): - title = self.windowTitle() - if need_save: - if not title.startswith('*'): - self.setWindowTitle('*' + title) - else: - if title.startswith('*'): - self.setWindowTitle(title.strip('*')) - - def on_save(self): - self.signal_need_save.emit(False) - self.data_modified_signal.emit() - - def set_data(self, data: typing.Any) -> bool: - """ - set_data方法在初次调用时,设置其内部的data参数; - 当后面调用的时候,不会更改内部的data参数。 - get_default_slicing_statement的意思是可以获取默认的切片索引。 - 这是因为表格一般只能显示二维的数据,当数组维数超过二维的时候,就需要尽可能地利用切片进行显示了。 - 比如对于四维np.array张量,返回的默认就是[:,:,0,0]。用户可以根据自己的需要进行切片。 - :param data: - :return: - """ - import numpy as np - if isinstance(data, np.ndarray): - if len(data.shape) > 3: - QMessageBox.warning(self, "提示", "目前只支持三维及以下数组的查看") - return False - elif len(data.shape) == 3: - self.slice_axis2.setMaximum(data.shape[0] - 1) - self.on_high_dimensional_array(len(data.shape) == 3) - - if self.table_view is not None: - self.table_view.set_data(data) - self.slice_input.setText(self.table_view.get_default_slicing_statement()) - - if isinstance(data, np.ndarray): - if len(data.shape) > 2: - self.on_axis2_value_changed() # 如果维度小于3,则默认进行以下切片操作。 - return True - - def get_data(self): - return self.table_view.data - - def slice(self): - """ - 切片操作。同时屏蔽可能出现的非法字符。 - 目前做不到对array数组进行索引。 - :return: - """ - data = self.table_view.data - text = self.slice_input.text().strip() - for char in text: - if not char in "[]:,.1234567890iloc": - QMessageBox.warning(self, QCoreApplication.translate('PMGTableViewer', 'Invalid Input'), - QCoreApplication.translate('PMGTableViewer', - "invalid character \"%s\" in slicing statement.") % char) - return - try: - data = eval('data' + text) - except Exception as exeption: - - QMessageBox.warning(self, QCoreApplication.translate('PMGTableViewer', 'Invalid Input'), - QCoreApplication.translate('PMGTableViewer', str(exeption))) - - self.table_view.show_data(data) - - def closeEvent(self, a0: 'QCloseEvent') -> None: - super().closeEvent(a0) - - def on_goto_cell(self): - if isinstance(self.table_view.model, (TableModelForPandasDataframe, TableModelForNumpyArray)): - min_row, max_row = 1, self.table_view.model.rowCount(None) - current_row = self.table_view.currentIndex().row() + 1 - current_col = self.table_view.currentIndex().column() + 1 - row, _ = QInputDialog.getInt(self, QCoreApplication.translate('PMGTableViewer', '输入行'), - QCoreApplication.translate('PMGTableViewer', - 'Target Row No.:({min}~{max})').format(min=min_row, - max=max_row), - current_row, - min_row, max_row, step=1) - if _: - self.table_view.on_goto_index(row - 1, 0) - else: - raise NotImplementedError - - -if __name__ == '__main__': - import datetime - import numpy as np - import pandas as pd - - app = QApplication(sys.argv) - - table = PMGTableViewer(table_view=PMTableView()) - data = np.arange(1, 17).reshape(2, 2, 4) - table.show() - ret = table.set_data(data) - - table2 = PMGTableViewer(table_view=PMTableView()) - data = np.arange(1, 17).reshape(2, 8) - table2.show() - ret = table2.set_data(data) - - table3 = PMGTableViewer(table_view=PMTableView()) - data = np.arange(1, 17) - table3.show() - ret = table3.set_data(data) - - if not ret: - table.close() - else: - app.exec_() - # table.setWindowTitle('Pandas数据集 显示多种数据') - - # data2 = pd.DataFrame(np.array([1 + 1j, 1 + 2j, 1 + 2.0j])) - # table2 = PMGTableViewer(table_view=PMTableView()) - # # table2.show() - # table2.setWindowTitle('Pandas数据集复数显示') - # table2.set_data(data2) - # print(data.dtypes) diff --git a/pyminer/pmgwidgets/widgets/basic/tables/tablewidgets.py b/pyminer/pmgwidgets/widgets/basic/tables/tablewidgets.py deleted file mode 100644 index 72a42a20..00000000 --- a/pyminer/pmgwidgets/widgets/basic/tables/tablewidgets.py +++ /dev/null @@ -1,106 +0,0 @@ -# 通用表格控件 -# 作者:侯展意 -# 带有加载数据集等等的功能,相对来讲比较方便。 -# 以PMG作为名字开头的控件,不依赖于主界面,只是会和主界面之间传递信号。 - -import sys - -from PySide2.QtCore import Signal -from PySide2.QtGui import QCloseEvent -from PySide2.QtWidgets import QApplication, QTabWidget, QTableWidget, QTableWidgetItem, \ - QAbstractItemView - -from typing import Sized, Iterable - - -class PMGTableWidget(QTableWidget): - data_name: str = '' - data_shown = Signal(str) - - def __init__(self, parent=None): - super().__init__(parent) - self.setRowCount(1) - self.setColumnCount(1) - self.verticalHeader().setDefaultSectionSize(30) - self.verticalHeader().setMinimumWidth(30) - self.horizontalHeader().setMinimumWidth(30) - - def closeEvent(self, a0: 'QCloseEvent') -> None: - super().closeEvent(a0) - - @staticmethod - def check_data_can_be_displayed_by_table(data: 'Sized') -> bool: - try: - if not hasattr(data, '__len__'): - return True - max_cols = 0 - for i, row_contents in enumerate(data): - if hasattr(row_contents, '__iter__'): - col_span = len(row_contents) - a = row_contents[i] # 尝试index第0项。 - else: - col_span = 1 - if col_span > max_cols: - max_cols = col_span - - for row, row_content in enumerate(data): - if hasattr(row_content, '__iter__'): - for col, content in enumerate(row_content): - data[row][col] - else: - data[row] - return True - - except: - return False - - def set_data_2d(self, data: 'Iterable', rows: int = None, - columns: int = None): - - if not hasattr(data, '__len__'): - item = QTableWidgetItem(str(data)) - self.setItem(0, 0, item) - return - if rows is None or columns is None: - rows = len(data) - max_cols = 0 - for row_contents in data: - if hasattr(row_contents, '__iter__'): - col_span = len(row_contents) - else: - col_span = 1 - if col_span > max_cols: - max_cols = col_span - columns = max_cols - self.setColumnCount(columns) - self.setRowCount(rows) - self.setSelectionBehavior(QAbstractItemView.SelectRows) - for row, row_content in enumerate(data): - if hasattr(row_content, '__iter__'): - for col, content in enumerate(row_content): - item = QTableWidgetItem(str(data[row][col])) - self.setItem(row, col, item) - else: - item = QTableWidgetItem(str(data[row])) - self.setItem(row, 0, item) - - -class PMGTableTabWidget(QTabWidget): - def __init__(self, parent=None): - super().__init__(parent) - - -if __name__ == '__main__': - app = QApplication(sys.argv) - list_to_display = ['hhhhhhhhhhhhhh', - ['a', 'v'], - [1, 2, 3, 4], - [3, 4, 5, 66, 7], - [123, '333', 'ffffffff'] - ] - demo = PMGTableWidget() - - demo.set_data_2d(list_to_display) - - demo.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/tables/translations/qt_zh_CN.ts b/pyminer/pmgwidgets/widgets/basic/tables/translations/qt_zh_CN.ts deleted file mode 100644 index f12b9f11..00000000 --- a/pyminer/pmgwidgets/widgets/basic/tables/translations/qt_zh_CN.ts +++ /dev/null @@ -1,89 +0,0 @@ - - - - PMGTableViewer - - - Slice - 切片 - - - - Save - 保存 - - - - Invalid Input - 无效输入 - - - - invalid character "%s" in slicing statement. - 输入的语句含有无效字符 "%s"。 - - - - Help - 帮助 - - - - Go To Cell - 前往单元格 - - - - Input Row - 输入跳转到的行 - - - - Target Row No.:({min}~{max}) - 目标行号:(范围{min}~{max}) - - - - PMTableView - - - Insert Row - 插入行 - - - - Delete Row - 删除行 - - - - Insert Column - 插入列 - - - - Delete Column - 删除列 - - - - Input Column Title - 输入列名称 - - - - Title - 标题 - - - - Warning - 警告 - - - - Input New Value - 输入新值 - - - diff --git a/pyminer/pmgwidgets/widgets/basic/texts/__init__.py b/pyminer/pmgwidgets/widgets/basic/texts/__init__.py deleted file mode 100644 index 139597f9..00000000 --- a/pyminer/pmgwidgets/widgets/basic/texts/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/pyminer/pmgwidgets/widgets/basic/texts/statusreport/__init__.py b/pyminer/pmgwidgets/widgets/basic/texts/statusreport/__init__.py deleted file mode 100644 index 3fbb7b8c..00000000 --- a/pyminer/pmgwidgets/widgets/basic/texts/statusreport/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .errroreport import show_error, ReportWidget diff --git a/pyminer/pmgwidgets/widgets/basic/texts/statusreport/errroreport.py b/pyminer/pmgwidgets/widgets/basic/texts/statusreport/errroreport.py deleted file mode 100644 index 17eb56ee..00000000 --- a/pyminer/pmgwidgets/widgets/basic/texts/statusreport/errroreport.py +++ /dev/null @@ -1,31 +0,0 @@ -from PySide2.QtWidgets import QWidget, QDialog, QVBoxLayout, QTextBrowser, QLabel, QPushButton - - -class ReportWidget(QDialog): - def __init__(self, parent: QWidget = None): - super(ReportWidget, self).__init__(parent) - self.setLayout(QVBoxLayout()) - self.label_brief = QLabel() - self.label_brief.setWordWrap(True) - self.layout().addWidget(self.label_brief) - self.detailed_info_show = QTextBrowser() - self.layout().addWidget(self.detailed_info_show) - self.ok_button = QPushButton() - self.ok_button.setText(self.tr('Ok')) - self.layout().addWidget(self.ok_button) - - self.ok_button.clicked.connect(self.close) - self.setMinimumWidth(400) - - def show_info(self, brief: str, detailed: str, title=''): - if title == '': - title = self.tr('Info') - self.label_brief.setText(brief) - self.detailed_info_show.setText(detailed) - self.setWindowTitle(title) - - -def show_error(parent: QWidget, brief: str, detailed: str, title: str = ''): - rw = ReportWidget(parent) - rw.show_info(brief, detailed, title) - rw.exec_() diff --git a/pyminer/pmgwidgets/widgets/basic/texts/webeditors/__init__.py b/pyminer/pmgwidgets/widgets/basic/texts/webeditors/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/widgets/basic/texts/webeditors/editor.py b/pyminer/pmgwidgets/widgets/basic/texts/webeditors/editor.py deleted file mode 100644 index cb05f4ef..00000000 --- a/pyminer/pmgwidgets/widgets/basic/texts/webeditors/editor.py +++ /dev/null @@ -1,412 +0,0 @@ -import os -import shutil -import sys - -sys.argv.append('--remote-debugging-port=10086') -from time import time -import json -import qdarkstyle -import qdarkstyle.style_rc # 导入pdarkstyle资源文件 -from PySide2 import QtCore -from PySide2.QtCore import Qt, QPoint, QUrl, Signal, QTimer, QEventLoop -from PySide2.QtWebChannel import QWebChannel -from PySide2.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings -from PySide2.QtWidgets import * -from PySide2.QtCore import Slot - -strategy_path = os.path.join(os.getcwd(), 'strategy') # 用于存放编辑文件的文件夹 -editor_path = os.path.join(os.path.dirname(__file__), 'quant', 'python_editor', 'editor.htm') - - -class WebEngineView(QWebEngineView): - customSignal = Signal(str, str) - saveSignal = Signal() - signal_open_file = Signal(str, str) - signal_request_text = Signal() - signal_text_got = Signal(str) - signal_save_as = Signal(str) - signal_set_autocomplete_apis = Signal(str) - - def __init__(self, *args, **kwargs): - super(WebEngineView, self).__init__(*args, **kwargs) - self._untitled_id = 0 - self.initSettings() - self.channel = QWebChannel(self) - # 把自身对象传递进去 - self.channel.registerObject('Bridge', self) - # 设置交互接口 - self.page().setWebChannel(self.channel) - - # self.signal_set_autocomplete_apis.emit({"keywords": ["aaaaa", "bbbbbb"]}) - - @Slot(str, str) - def on_text_received(self, path, text): - print(text) - self.signal_text_got.emit(text) - - # 注意pyqtSlot用于把该函数暴露给js可以调用 - @Slot(str) - def print_from_js(self, text): - print('print from js', text) - - @Slot(str, str) - def callFromJs(self, file, text): - print('call from js!') - try: - with open(file, mode='w', encoding='utf-8') as f: - f.write(text.replace('\r', '')) - f.close() - except Exception as e: - print(e) - - @Slot(str, str) - def on_save(self, file_name: str, text: str): - if os.path.isabs(file_name): - pass - else: - file_name, ext = QFileDialog.getSaveFileName(self, "aaa", "/home/hzy/Desktop", "All Files(*)") - print(file_name, text) - with open(file_name, 'w') as f: - f.write(text) - self.signal_save_as.emit(file_name) - - def open_file(self, file: str): - """ - 打开文件 - Args: - file: - - Returns: - - """ - with open(file, 'r', encoding='utf-8') as f: - text = f.read() - self.signal_open_file.emit(file, text) - - def new_file(self): - self._untitled_id += 1 - self.signal_open_file.emit("Untitled-%d.py" % self._untitled_id, "") - - def sendCustomSignal(self, file): - # 发送自定义信号 - with open(file, 'r', encoding='utf-8') as f: - text = f.read() - self.customSignal.emit(file, text) - - def sendSaveSignal(self): - self.saveSignal.emit() - - # @Slot(str) - # @Slot(QUrl) - def load(self, url): - ''' - eg: load("https://PySide2.com") - :param url: 网址 - ''' - return super(WebEngineView, self).load(QUrl(url)) - - def initSettings(self): - ''' - eg: 初始化设置 - ''' - # 获取浏览器默认设置 - settings = QWebEngineSettings.globalSettings() - # 设置默认编码utf8 - settings.setDefaultTextEncoding("utf-8") - # 自动加载图片,默认开启 - # settings.setAttribute(QWebEngineSettings.AutoLoadImages,True) - # 自动加载图标,默认开启 - # settings.setAttribute(QWebEngineSettings.AutoLoadIconsForPage,True) - # 开启js,默认开启 - # settings.setAttribute(QWebEngineSettings.JavascriptEnabled,True) - # js可以访问剪贴板 - settings.setAttribute( - QWebEngineSettings.JavascriptCanAccessClipboard, True) - # js可以打开窗口,默认开启 - # settings.setAttribute(QWebEngineSettings.JavascriptCanOpenWindows,True) - # 链接获取焦点时的状态,默认开启 - # settings.setAttribute(QWebEngineSettings.LinksIncludedInFocusChain,True) - # 本地储存,默认开启 - # settings.setAttribute(QWebEngineSettings.LocalStorageEnabled,True) - # 本地访问远程 - settings.setAttribute( - QWebEngineSettings.LocalContentCanAccessRemoteUrls, True) - # 本地加载,默认开启 - # settings.setAttribute(QWebEngineSettings.LocalContentCanAccessFileUrls,True) - # 监控负载要求跨站点脚本,默认关闭 - # settings.setAttribute(QWebEngineSettings.XSSAuditingEnabled,False) - # 空间导航特性,默认关闭 - # settings.setAttribute(QWebEngineSettings.SpatialNavigationEnabled,False) - # 支持平超链接属性,默认关闭 - # settings.setAttribute(QWebEngineSettings.HyperlinkAuditingEnabled,False) - # 使用滚动动画,默认关闭 - settings.setAttribute(QWebEngineSettings.ScrollAnimatorEnabled, True) - # 支持错误页面,默认启用 - # settings.setAttribute(QWebEngineSettings.ErrorPageEnabled, True) - # 支持插件,默认关闭 - settings.setAttribute(QWebEngineSettings.PluginsEnabled, True) - # 支持全屏应用程序,默认关闭 - settings.setAttribute( - QWebEngineSettings.FullScreenSupportEnabled, True) - # 支持屏幕截屏,默认关闭 - settings.setAttribute(QWebEngineSettings.ScreenCaptureEnabled, True) - # 支持html5 WebGl,默认开启 - settings.setAttribute(QWebEngineSettings.WebGLEnabled, True) - # 支持2d绘制,默认开启 - settings.setAttribute( - QWebEngineSettings.Accelerated2dCanvasEnabled, True) - # 支持图标触摸,默认关闭 - settings.setAttribute(QWebEngineSettings.TouchIconsEnabled, True) - - -class Editor(QWidget): - def __init__(self): - super().__init__() - self.mainLayout = QGridLayout() # 上方布局 - self.bottomLayout = QGridLayout() # 下方布局 - self.create_stragety_vbox() - self.create_content_vbox() - self.mainLayout = QGridLayout() # 主布局为垂直布局 - self.mainLayout.setSpacing(5) # 主布局添加补白 - - self.mainLayout.addWidget(self.strategy_vbox, 0, 0, 1, 1) - self.mainLayout.addWidget(self.content_vbox, 0, 1, 1, 1) - - self.mainLayout.setColumnStretch(0, 2) - self.mainLayout.setColumnStretch(1, 6) - - self.setLayout(self.mainLayout) - self.setGeometry(200, 200, 1200, 800) - self.setWindowTitle('编辑器') - self.show() - - # 策略信息 - self.strategy_path = None - - with open(r'qdark.qss', encoding='utf-8') as f: - self.setStyleSheet(f.read()) - - def create_stragety_vbox(self): - # 策略树 - self.strategy_vbox = QGroupBox('策略') - self.strategy_layout = QHBoxLayout() - self.strategy_tree = QTreeView() - self.model = QFileSystemModel() - self.model.setRootPath(QtCore.QDir.rootPath()) - self.strategy_tree.setModel(self.model) - self.strategy_tree.setEditTriggers(QAbstractItemView.NoEditTriggers) - self.strategy_tree.setRootIndex(self.model.index(r'/home/hzy/Desktop')) - # self.strategy_tree.setColumnCount(1) - # self.strategy_tree.setHeaderLabels(['策略']) - self.strategy_tree.setDragDropMode(QAbstractItemView.InternalMove) - self.model.setReadOnly(False) - self.strategy_tree.setHeaderHidden(True) - self.strategy_tree.hideColumn(1) - self.strategy_tree.hideColumn(2) - self.strategy_tree.hideColumn(3) - - self.strategy_tree.setContextMenuPolicy(Qt.CustomContextMenu) - self.strategy_tree.customContextMenuRequested[QPoint].connect(self.strategy_tree_right_menu) - - # for d in os.listdir(strategy_path): - # root = QTreeWidgetItem(self.strategy_tree) - # root.setText(0, d) - # for file in os.listdir(os.path.join(strategy_path, d)): - # child = QTreeWidgetItem(root) - # child.setText(0, file) - # self.list_strategy(strategy_path, self.strategy_tree) - self.strategy_tree.doubleClicked.connect(self.strategy_tree_clicked) - self.strategy_layout.addWidget(self.strategy_tree) - self.strategy_vbox.setLayout(self.strategy_layout) - - # 策略右键菜单 - def strategy_tree_right_menu(self, point): - self.strategy_tree.popMenu = QMenu() - self.strategy_tree.addType = QMenu(self.strategy_tree.popMenu) - self.strategy_tree.addType.setTitle('新建') - rename = QAction('重命名', self.strategy_tree) - delete = QAction('删除', self.strategy_tree) - add_strategy = QAction('新建策略') - add_group = QAction('新建分组') - refresh = QAction('刷新', self.strategy_tree) - self.strategy_tree.popMenu.addMenu(self.strategy_tree.addType) - self.strategy_tree.addType.addAction(add_strategy) - self.strategy_tree.addType.addAction(add_group) - self.strategy_tree.popMenu.addAction(rename) - self.strategy_tree.popMenu.addAction(delete) - self.strategy_tree.popMenu.addAction(refresh) - - # 右键动作 - action = self.strategy_tree.popMenu.exec_(self.strategy_tree.mapToGlobal(point)) - if action == add_strategy: - index = self.strategy_tree.currentIndex() - model = index.model() # 请注意这里可以获得model的对象 - item_path = model.filePath(index) - if item_path and os.path.isdir(item_path): - value = '' - while True: - value, ok = QInputDialog.getText(self, '新建文件', '策略名称', QLineEdit.Normal) - path = os.path.join(item_path, value + '.py') - if os.path.exists(path) and ok: - QMessageBox.warning(self, '提示', '策略名在选择的分组%s已经存在!!!' % value, QMessageBox.Yes) - elif not ok: - break - else: - with open(path, 'w', encoding='utf-8') as w: - pass - break - elif not os.path.isdir(item_path): - value = '' - while True: - value, ok = QInputDialog.getText(self, '新建文件', '策略名称', QLineEdit.Normal) - path = os.path.join(os.path.split(item_path)[1], value + '.py') - if os.path.exists(path) and ok: - QMessageBox.warning(self, '提示', '策略名在选择的分组%s已经存在!!!' % value, QMessageBox.Yes) - elif not ok: - break - else: - with open(path, 'w', encoding='utf-8') as w: - pass - break - else: - QMessageBox.warning(self, '提示', '请选择分组!!!', QMessageBox.Yes) - - elif action == add_group: - value = '' - flag = self.strategy_tree.indexAt(point) # 判断鼠标点击位置标志位 - while True: - if not flag.isValid(): # 鼠标点击位置不在目录树叶子上 - item_path = strategy_path # 新建文件夹位置在根目录 - else: - index = self.strategy_tree.currentIndex() - model = index.model() # 请注意这里可以获得model的对象 - item_path = model.filePath(index) - value, ok = QInputDialog.getText(self, '新建文件夹', '分组名称', QLineEdit.Normal, value) - if os.path.isdir(item_path): - path = os.path.join(item_path, value) - else: - path = os.path.join(os.path.split(item_path)[0], value) - if os.path.exists(path) and ok: - QMessageBox.warning(self, '提示', '分组%s已经存在!!!' % value, QMessageBox.Yes) - elif not ok: - break - else: - os.mkdir(path) - break - - elif action == refresh: - index = self.strategy_tree.currentIndex() - model = index.model() # 请注意这里可以获得model的对象 - model.dataChanged.emit(index, index) - elif action == rename: - index = self.strategy_tree.currentIndex() - model = index.model() # 请注意这里可以获得model的对象 - item_path = model.filePath(index) - if not os.path.isdir(item_path): # 修改策略名 - value = '' - (file_path, filename) = os.path.split(item_path) - while True: - value, ok = QInputDialog.getText(self, '修改%s策略名' % filename, '策略名称', QLineEdit.Normal, value) - new_path = os.path.join(file_path, value + '.py') - if os.path.exists(new_path) and ok: - QMessageBox.warning(self, '提示', '策略名在此分组中%s已经存在!!!' % value, QMessageBox.Yes) - elif not ok: - break - else: - os.rename(item_path, new_path) - break - else: - value = '' - (dir_path, dir_name) = os.path.split(item_path) - while True: - value, ok = QInputDialog.getText(self, '修改%s文件夹' % dir_name, '分组名称', QLineEdit.Normal, value) - new_path = os.path.join(dir_path, value) - if os.path.exists(new_path) and ok: - QMessageBox.warning(self, '提示', '分组%s已经存在!!!' % value, QMessageBox.Yes) - elif not ok: - break - else: - os.rename(item_path, new_path) - break - elif action == delete: - index = self.strategy_tree.currentIndex() - model = index.model() # 请注意这里可以获得model的对象 - item_path = model.filePath(index) - if item_path and os.path.isdir(item_path): - reply = QMessageBox.question(self, '提示', '确定删除分组及目录下的所有文件吗?', QMessageBox.Yes | QMessageBox.No) - if reply == QMessageBox.Yes: - shutil.rmtree(item_path) - elif item_path and not os.path.isdir(item_path): - reply = QMessageBox.question(self, '提示', '确定删除文件%s吗?' % item_path, QMessageBox.Yes | QMessageBox.No) - if reply == QMessageBox.Yes: - os.remove(item_path) - else: - pass - else: - pass - - def create_content_vbox(self): - self.content_vbox = QGroupBox('内容') - self.content_layout = QGridLayout() - self.save_btn = QPushButton('保存') - self.run_btn = QPushButton('运行') - self.update_api = QPushButton('更新api') - self.refresh_btn = QPushButton('重新加载') - self.new_btn = QPushButton('新建') - self.refresh_btn.clicked.connect( - lambda: self.contentEdit.load(QUrl.fromLocalFile(os.path.abspath(editor_path)))) - self.contentEdit = WebEngineView() - self.contentEdit.load(QUrl.fromLocalFile(os.path.abspath(editor_path))) - self.save_btn.setMaximumSize(80, 60) - self.run_btn.setMaximumSize(80, 60) - self.content_layout.addWidget(self.run_btn, 0, 1, 1, 1) - self.content_layout.addWidget(self.save_btn, 0, 2, 1, 1) - self.content_layout.addWidget(self.refresh_btn, 0, 3, 1, 1) - self.content_layout.addWidget(self.new_btn, 0, 4, 1, 1) - self.content_layout.addWidget(self.update_api, 0, 5, 1, 1) - self.content_layout.addWidget(self.contentEdit, 2, 0, 1, 5) - self.content_vbox.setLayout(self.content_layout) - self.save_btn.clicked.connect(self.emit_custom_signal) - self.new_btn.clicked.connect(lambda: self.contentEdit.new_file()) - self.update_api.clicked.connect( - lambda: self.contentEdit.signal_set_autocomplete_apis.emit( - json.dumps({"python": {"keywords": {"mode": "add", "content": ["import", "def", "class"]}}}))) - - def emit_custom_signal(self): - self.contentEdit.sendSaveSignal() - - def strategy_tree_clicked(self): - # 策略双击槽函数 - index = self.strategy_tree.currentIndex() - model = index.model() # 请注意这里可以获得model的对象 - item_path = model.filePath(index) - if not os.path.isdir(item_path): - self.contentEdit.open_file(item_path) # sendCustomSignal(item_path) - self.strategy_path = item_path - - def get_text(self) -> str: - """ - 获取文本内容 - :return: - """ - self.contentEdit.signal_request_text.emit() - self.loop = QEventLoop() - _text = '' - - def f(text): - self.loop.quit() - _text = text - - self.contentEdit.signal_text_got.connect(f) - self.loop.exec_() - return _text - - -if __name__ == "__main__": - app = QApplication(sys.argv) - form = Editor() - form.show() - timer = QTimer() - timer.start(1000) - # timer.timeout.connect(lambda: print(form.get_text())) - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/trees/__init__.py b/pyminer/pmgwidgets/widgets/basic/trees/__init__.py deleted file mode 100644 index 47682075..00000000 --- a/pyminer/pmgwidgets/widgets/basic/trees/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .filetree import * -from .jsontree import PMGJsonTree -from .treecheck import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/basic/trees/filetree.py b/pyminer/pmgwidgets/widgets/basic/trees/filetree.py deleted file mode 100644 index 3ced79ed..00000000 --- a/pyminer/pmgwidgets/widgets/basic/trees/filetree.py +++ /dev/null @@ -1,564 +0,0 @@ -import os -from typing import List - -from PySide2.QtCore import Qt, QModelIndex, Signal, QLocale, QTranslator, QMimeData, QUrl -from PySide2.QtGui import QCursor, QKeySequence, QClipboard -from PySide2.QtWidgets import QTreeView, QFileSystemModel, QMenu, QApplication, QMessageBox, QInputDialog, \ - QLineEdit, QDialog, QVBoxLayout, QDialogButtonBox, QPushButton, QHBoxLayout, QLabel, QShortcut, QCheckBox -from pmgwidgets.widgets.basic.trees.treecheck import PMCheckTree -from pmgwidgets.utilities.source.translation import create_translator -from pmgwidgets.utilities.platform import open_file_manager - - -class InputFilenameDialog(QDialog): - def __init__(self, parent=None, title: str = '', ext: str = ''): - super().__init__(parent) - layout = QVBoxLayout() - self.name_input = QLineEdit() - self.ok_button = QPushButton(self.tr('Ok')) - self.cancel_button = QPushButton(self.tr('Cancel')) - self.button_layout = QHBoxLayout() - self.button_layout.addWidget(self.ok_button) - self.button_layout.addWidget(self.cancel_button) - layout.addWidget(QLabel(title)) - layout.addWidget(self.name_input) - layout.addLayout(self.button_layout) - initial_name = 'Untitled' - if ext != '': - ext = '.' + ext - self.name_input.setText(initial_name + ext) - self.name_input.setSelection(0, len(initial_name)) - else: - self.name_input.setText(initial_name) - self.name_input.setSelection(0, len(initial_name)) - self.ok_button.clicked.connect(self.on_ok) - self.cancel_button.clicked.connect(self.on_cancel) - self.status = False - self.setLayout(layout) - - def on_ok(self): - self.status = True - self.close() - - def on_cancel(self): - self.status = False - self.close() - - -class PMFileSystemModel(QFileSystemModel): - def __init__(self, parent=None): - super().__init__(parent) - # self.setFilter(QDir.Dirs | QDir.AllDirs) - - def headerData(self, p_int, qt_orientation, role=None): - if (p_int == 0) and (role == Qt.DisplayRole): - return self.tr('Name') - elif (p_int == 1) and (role == Qt.DisplayRole): - return self.tr('Size') - elif (p_int == 2) and (role == Qt.DisplayRole): - return self.tr('Type') - elif (p_int == 3) and (role == Qt.DisplayRole): - return self.tr('Last Modified') - else: - return super().headerData(p_int, qt_orientation, role) - - def columnCount(self, parent: QModelIndex = ...) -> int: - return 1 - - -class PMGFilesTreeview(QTreeView): - """ - 文件树 - """ - open_signal = Signal(str) - open_folder_signal = Signal(str) - new_file_signal = Signal(str) - new_folder_signal = Signal(str) - delete_file_signal = Signal(str) - rename_file_signal = Signal(str, str) - - signal_ext_filter_adapt = Signal(bool) - signal_ext_filter_changed = Signal(dict) - - def __init__(self, initial_dir: str = '', parent=None): - super().__init__(parent) - self.initial_dir = initial_dir - self.setup_ui() - self.bind_events() - - self.filter_exts = True - self.exts_to_filter = { - 'Program Scripts': {'.pyx': True, '.py': True, '.c': True, '.pyi': True, '.dll': True, - '.h': True, '.cpp': True, '.ipynb': True, '.sh': True, '.cmd': True, '.bat': True - }, - 'Documents': {'.txt': True, '.md': True, '.doc': True, '.docx': True, '.ppt': True, '.pptx': True, - '.html': True - }, - 'Data Files': {'.csv': True, '.xls': True, '.xlsx': True, '.tab': True, '.dat': True, '.tsv': True, - '.sav': True, '.zsav': True, '.sas7bdat': True, '.pkl': True, '.json': True, '.mat': True, - '.pmjson': True, '.pmd': True}, - 'Medias': {'.mp3': False, '.mp4': False, '.avi': False, '.wma': False, '.png': True, '.jpg': True, - '.svg': True}, - 'Resources': {'.qm': True, '.ts': True} - - } - - def setup_ui(self): - """ - 界面初始化 - :return: - """ - - self.translator = create_translator( - path=os.path.join(os.path.dirname(__file__), 'translations', - 'qt_{0}.qm'.format(QLocale.system().name()))) # translator - - self.setTabKeyNavigation(True) - self.setDragEnabled(True) - self.setDragDropOverwriteMode(True) - self.setAlternatingRowColors(False) - self.setUniformRowHeights(True) - self.setSortingEnabled(True) - self.setAnimated(True) - self.setAllColumnsShowFocus(False) - self.setWordWrap(False) - self.setHeaderHidden(False) - self.setObjectName("treeView_files") - self.header().setSortIndicatorShown(True) - - self.model = PMFileSystemModel() - self.model.setRootPath(self.initial_dir) - - self.setModel(self.model) - self.setRootIndex(self.model.index(self.initial_dir)) - self.setAnimated(False) - self.setSortingEnabled(True) # 启用排序 - self.header().setSortIndicatorShown(True) # 启用标题排序 - self.setContextMenuPolicy(Qt.CustomContextMenu) - self.customContextMenuRequested.connect(self.show_context_menu) - self.init_context_menu() - - def bind_events(self): - """ - 回调、事件与信号初始化 - :return: - """ - self.doubleClicked.connect(lambda index: self.on_open()) - - self.openAction.triggered.connect(self.on_open) - self.importAction.triggered.connect(self.on_import) - self.renameAction.triggered.connect(self.on_rename) - self.deleteAction.triggered.connect(self.on_delete) - - self.copyAction.triggered.connect(self.on_copy) - self.pasteAction.triggered.connect(self.on_paste) - self.filterAction.triggered.connect(self.show_ext_filter_selection_dialog) - - self.copyPathAction.triggered.connect(self.copy_path) - self.new_file_action.triggered.connect(lambda: self.on_new_file('')) - self.new_python_file_action.triggered.connect(lambda: self.on_new_file('py')) - self.new_folder_action.triggered.connect(self.on_new_folder) - self.open_file_manager_action.triggered.connect(self.on_open_file_manager) - - self.rename_shortcut.activated.connect(self.on_rename) - self.paste_shortcut.activated.connect(self.on_paste) - self.copy_shortcut.activated.connect(self.on_copy) - self.open_shortcut.activated.connect(self.on_open) - self.delete_shortcut.activated.connect(self.on_delete) - self.goto_parent_path_shortcut.activated.connect(self.slot_goto_parent_path) - - self.customContextMenuRequested.connect(self.show_context_menu) - - def init_context_menu(self): - """ - 初始化右键菜单 - :return: - """ - self.contextMenu = QMenu(self) - self.openAction = self.contextMenu.addAction(self.tr('Open')) - - self.importAction = self.contextMenu.addAction(self.tr('Import')) - self.importAction.setEnabled(False) - - self.new_file_or_folder_menu = QMenu(self.tr('New..')) - self.contextMenu.addMenu(self.new_file_or_folder_menu) - self.new_file_action = self.new_file_or_folder_menu.addAction(self.tr('File..')) - self.new_python_file_action = self.new_file_or_folder_menu.addAction(self.tr('Python File')) - self.new_folder_action = self.new_file_or_folder_menu.addAction(self.tr('Folder')) - self.new_file_or_folder_menu.addSeparator() - - self.copyAction = self.contextMenu.addAction(self.tr("Copy")) - self.pasteAction = self.contextMenu.addAction(self.tr("Paste")) - self.pasteAction.setEnabled(False) - - self.renameAction = self.contextMenu.addAction(self.tr('Rename')) - self.deleteAction = self.contextMenu.addAction(self.tr('Delete')) - - self.filterAction = self.contextMenu.addAction(self.tr('Filter')) - self.copyPathAction = self.contextMenu.addAction(self.tr('Copy Path')) - - self.open_file_manager_action = self.contextMenu.addAction(self.tr('Open Explorer')) - - self.renameAction.setShortcut(QKeySequence('F2')) - self.copyAction.setShortcut(QKeySequence('Ctrl+C')) - self.pasteAction.setShortcut(QKeySequence('Ctrl+V')) - self.deleteAction.setShortcut(QKeySequence('Delete')) - - self.rename_shortcut = QShortcut(QKeySequence('F2'), self, context=Qt.WidgetShortcut) - self.copy_shortcut = QShortcut(QKeySequence.Copy, self, context=Qt.WidgetShortcut) - self.paste_shortcut = QShortcut(QKeySequence.Paste, self, context=Qt.WidgetShortcut) - self.delete_shortcut = QShortcut(QKeySequence('Delete'), self, context=Qt.WidgetShortcut) - self.open_shortcut = QShortcut(QKeySequence('Return'), self, context=Qt.WidgetShortcut) - self.goto_parent_path_shortcut = QShortcut(QKeySequence('Backspace'), self, context=Qt.WidgetShortcut) - - def show_context_menu(self): - """ - 显示上下文右键菜单 - :return: - """ - self.contextMenu.popup(QCursor.pos()) - self.contextMenu.show() - - def get_current_file_path(self): - """ - 获取当前选中文件的路径。 - 如果当前没有选中的文件,就返回根路径。 - :return: - """ - if len(self.selectedIndexes()) > 0: - index = self.currentIndex() - file_info = self.model.fileInfo(index) - return file_info.absoluteFilePath() - else: - return self.get_root_path() - - def get_root_path(self): - """ - 获取根路径 - :return: - """ - return self.model.rootPath() - - def set_item_focus(self, file_path: str): - """ - set item focus in TreeView - :param file_path: File or Dir - :return: - """ - self.setCurrentIndex(self.model.index(file_path)) - - def on_open_file_manager(self): - path = self.get_current_file_path() - print(path) - if os.path.isdir(path): - open_file_manager(path) - else: - open_file_manager(os.path.dirname(path)) - - # if os.path.exists(new_folder_path): - # self.set_item_focus(new_folder_path) # 设置focus liugang 200923 - # QMessageBox.critical(self, self.tr('Error'), - # self.tr('Folder %s already exists!' % name)) - # return - # else: - # os.mkdir(new_folder_path) - # self.new_folder_signal[str].emit(new_folder_path) - # self.set_item_focus(new_folder_path) # 设置focus liugang 200923 - - def on_new_folder(self): - """ - 新建文件夹时出发的回调 - :return: - """ - path = self.get_current_file_path() - name, stat = QInputDialog.getText(self, self.tr('Please Input folder name'), '', QLineEdit.Normal, '') - if name.find('.') != -1: - QMessageBox.critical(self, self.tr('Error'), - self.tr('Folder name %s is illeagal!' % name)) - return - if stat: - if os.path.isdir(path): - new_folder_path = os.path.join(path, name) - else: - new_folder_path = os.path.join(os.path.dirname(path), name) - - if os.path.exists(new_folder_path): - self.set_item_focus(new_folder_path) # 设置focus liugang 200923 - QMessageBox.critical(self, self.tr('Error'), - self.tr('Folder %s already exists!' % name)) - return - else: - os.mkdir(new_folder_path) - self.new_folder_signal[str].emit(new_folder_path) - self.set_item_focus(new_folder_path) # 设置focus liugang 200923 - - def on_new_file(self, ext: str = ''): - """ - 新建文件时触发的回调 - :return: - """ - path = self.get_current_file_path() - dlg = InputFilenameDialog(parent=self, title=self.tr('Please input file name'), ext=ext) - - dlg.exec_() - name = dlg.name_input.text() - stat = dlg.status - if stat: - if os.path.isdir(path): - new_file_path = os.path.join(path, name) - else: - new_file_path = os.path.join(os.path.dirname(path), name) - - if os.path.exists(new_file_path): - self.set_item_focus(new_file_path) # 设置focus liugang 200923 - QMessageBox.critical(self, self.tr('Error'), - self.tr('File %s already exists!' % name)) - return - with open(new_file_path, 'wb') as f: - f.close() - self.new_file_signal[str].emit(new_file_path) - - self.set_item_focus(new_file_path) - self.on_open() # 创建文件后打开 liugang 200923 - - def on_open(self): - """ - 点击‘open’时候触发的回调, 等效的方式还有双击以及按下回车键。 - :return: - """ - path = self.get_current_file_path() - if os.path.isdir(path): - self.open_folder_signal.emit(path) - else: - self.open_signal[str].emit(path) - - def on_import(self): - """ - - :return: - """ - pass - - def on_rename(self): - """ - 点击’重命名‘时候的回调。 - :return: - """ - from pmgwidgets import rename_file - path = self.get_current_file_path() - basename = os.path.basename(path) - dir_name = os.path.dirname(path) - name, stat = QInputDialog.getText(self, self.tr('Please Input file name'), '', QLineEdit.Normal, basename) - if stat: - new_absolute_path = os.path.join(dir_name, name) - rename_result = rename_file(path, new_absolute_path) - if not rename_result: - QMessageBox.critical(self, self.tr('Error'), - self.tr('Unable to Rename this file.')) - else: - self.rename_file_signal[str, str].emit(path, new_absolute_path) - - def on_delete(self): - """ - 点击’删除‘时的回调 - :return: - """ - from pmgwidgets import move_to_trash - path = self.get_current_file_path() - - moved_successful = move_to_trash(path) - if not moved_successful: - QMessageBox.critical(self, self.tr('Error'), - self.tr('Unable to Move this file to recycle bin.')) - else: - self.delete_file_signal[str].emit(path) - - def on_copy(self): - """ - copy file or dir , save path in pasteAction data. - :return: - """ - path = self.get_current_file_path() - self.pasteAction.setEnabled(True) - self.pasteAction.setData(path) - - data = QMimeData() - data.setUrls([QUrl.fromLocalFile(path)]) # 复制到系统剪贴板 - - clip = QApplication.clipboard() - clip.setMimeData(data) - - def on_paste(self): - """ - Paste file or dir in pasteAction data - :return: - """ - from pmgwidgets import copy_paste - path = self.get_current_file_path() - target_dir_name = path if os.path.isdir(path) else os.path.dirname(path) - url: QUrl = None - - mimedata = QApplication.clipboard().mimeData(mode=QClipboard.Clipboard) - print(mimedata) - urls: List[QUrl] = mimedata.urls() - for url in urls: - source_path = url.toLocalFile() # self.pasteAction.data() - # File - if os.path.isfile(source_path): - source_file_name = os.path.basename(source_path) - # if exist ,rename to copy_xxx - if os.path.isfile(os.path.join(target_dir_name, source_file_name)): - target_file_name = "copy_{0}".format(source_file_name) - else: - target_file_name = source_file_name - target_path = os.path.join(target_dir_name, target_file_name) - # Directory - else: - last_dir_name = os.path.split(source_path)[-1] - # if exist , rename dir copy_xxxx - if os.path.isdir(os.path.join(target_dir_name, last_dir_name)): - target_name = "copy_{0}".format(last_dir_name) - else: - target_name = last_dir_name - target_path = os.path.join(target_dir_name, target_name) - - copy_succ = copy_paste(source_path, target_path) - if not copy_succ: - QMessageBox.critical(self, self.tr('Error'), - self.tr('Copy File or Directory Error.')) - else: - self.set_item_focus(target_path) - - def show_ext_filter_selection_dialog(self): - - self.dlg = QDialog(self) - self.dlg.setWindowTitle(self.tr('Extension Name To Show')) - self.dlg.setLayout(QVBoxLayout()) - self.dlg.layout().addWidget(QLabel('过滤文件名')) - check_box = QCheckBox() - self.dlg.check_box = check_box - check_box.setChecked(self.filter_exts) - self.dlg.layout().addWidget(check_box) - check_box.stateChanged.connect(lambda stat: self.signal_ext_filter_adapt.emit(stat)) - check_widget = PMCheckTree(data=self.exts_to_filter) - self.dlg.check_widget = check_widget - self.dlg.layout().addWidget(check_widget) - buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) - - buttonBox.accepted.connect(self.on_ext_filter_changed) - buttonBox.rejected.connect(self.dlg.deleteLater) - # 清除选择功能不完善目前禁用 - # button_clear = buttonBox.addButton(self.tr('Clear Filter'), QDialogButtonBox.ApplyRole) - # button_clear.clicked.connect(self.clear_ext_filter) - self.dlg.layout().addWidget(buttonBox) - self.dlg.exec_() - - def on_ext_filter_changed(self): - """ - 当扩展名过滤改变的时候。 - :return: - """ - self.exts_to_filter = self.dlg.check_widget.get_data() - self.filter_exts = self.dlg.check_box.isChecked() - self.update_ext_filter() - self.dlg.deleteLater() - self.signal_ext_filter_changed.emit(self.exts_to_filter) - - def clear_ext_filter(self): - self.set_ext_filter(None) - self.dlg.deleteLater() - - def update_ext_filter(self): - """ - 刷新扩展名过滤。 - :return: - """ - ext_list = [] - for key in self.exts_to_filter.keys(): - for name in self.exts_to_filter[key].keys(): - if self.exts_to_filter[key][name]: - ext_list.append('*' + name) - self.set_ext_filter(ext_list) - - def set_ext_filter(self, ext_names: List[str]): - """ - 文件名过滤 - 例如要过滤出.py和.pyx文件,就是ext_names=['*.py','*.pyx'] - discard功能不太完善,目前先禁用。 - :param ext_names: - :return: - """ - if ext_names is not None and self.filter_exts: - self.model.setNameFilterDisables(False) - self.model.setNameFilters(ext_names) - else: - self.model.setNameFilterDisables(True) - self.model.setNameFilters(["*"]) - - def slot_goto_parent_path(self): - """ - - Returns: - - """ - root = self.get_root_path() - parent = os.path.dirname(root) - if os.path.exists(parent): - pass - self.open_folder_signal.emit(parent) - - def copy_path(self): - """ - 复制当前文件的路径的回调 - Returns: - - """ - path = self.get_current_file_path() - # data = QMimeData() - clipboard = QApplication.clipboard() - clipboard.setText(path) - - -class Stack(object): - - def __init__(self): - # 创建空列表实现栈 - self.__list = [] - - def is_empty(self): - # 判断是否为空 - return self.__list == [] - - def push(self, item): - # 压栈,添加元素 - self.__list.append(item) - - def pop(self): - # 弹栈,弹出最后压入栈的元素 - if self.is_empty(): - return - else: - return self.__list.pop() - - def top(self): - # 取最后压入栈的元素 - if self.is_empty(): - return - else: - return self.__list[-1] - - def __len__(self): - return len(self.__list) - - def __str__(self): - return str(self.__list) - - -if __name__ == '__main__': - import sys - - app = QApplication(sys.argv) - - tree = PMGFilesTreeview(os.path.join(os.path.expanduser('~'), 'Desktop', 'cloud'), None) - tree.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/trees/jsontree.py b/pyminer/pmgwidgets/widgets/basic/trees/jsontree.py deleted file mode 100644 index a7f24b6d..00000000 --- a/pyminer/pmgwidgets/widgets/basic/trees/jsontree.py +++ /dev/null @@ -1,233 +0,0 @@ -""" -专门显示JSON的树状控件。 -""" -import os -import time -from typing import Dict, Callable, Any - -from PySide2.QtWidgets import QTreeWidget, QTreeWidgetItem, QMenu -from PySide2.QtCore import Signal, Qt, QTimer, QLocale -from pmgwidgets.utilities.source.translation import create_translator - - -class PMGJsonTree(QTreeWidget): - signal_show_data_value = Signal(str) - signal_data_saveas = Signal(str) - signal_data_open = Signal(str) - - def __init__(self, parent=None): - super().__init__(parent=None) - self.select_data_callbacks = [] - self.filter_all_upper_case = False - self.filter_all_callables = True - self.setup_ui() - self.expanding_stat: Dict[str, bool] = {} - - def setup_ui(self): - self.translator = create_translator( - path=os.path.join(os.path.dirname(__file__), 'translations', - 'qt_{0}.qm'.format(QLocale.system().name()))) # translator - self.nodes: Dict[str, 'QTreeWidgetItem'] = {} - self.setColumnCount(2) - header_item = QTreeWidgetItem() - header_item.setText(0, self.tr('Name')) - self.setColumnWidth(0, 200) - header_item.setText(1, self.tr('Value')) - header_item.setTextAlignment(0, Qt.AlignCenter) - header_item.setTextAlignment(1, Qt.AlignCenter) - self.setHeaderItem(header_item) - self.auto_expand = False - - self.itemClicked.connect(self.on_item_clicked) - self.itemDoubleClicked.connect(self.on_item_double_clicked) - self.customContextMenuRequested.connect(self.on_right_clicked) - self.setContextMenuPolicy(Qt.CustomContextMenu) - - self.context_menu = QMenu() - show_action = self.context_menu.addAction(self.tr('View')) - save_action = self.context_menu.addAction(self.tr('Save as ')) - cancel_action = self.context_menu.addAction(self.tr('Undo')) - redo_action = self.context_menu.addAction(self.tr('Redo')) - delete_action = self.context_menu.addAction(self.tr('Delete')) - show_action.triggered.connect(self.on_show_data_by_context_menu) - - def memorize_expanding_stat(self): - for k, node in self.nodes.items(): - self.expanding_stat[k] = node.isExpanded() - - def on_item_clicked(self, item: QTreeWidgetItem, col: int) -> None: - """ - 点击条目时的回调函数。会顺次执行self.select_data_callbacks,而self.select_data_callbacks - 是由插件的add_select_data_callback(self, callback: Callable)方式加入的。 - """ - if item.isExpanded(): - self.collapseItem(item) - else: - self.expandItem(item) - - if col == 0 and item.text(0) in self.nodes.keys(): - for callback in self.select_data_callbacks: - callback(item.text(0)) - - def add_select_data_callback(self, callback: Callable): - """ - 加入回调函数。 - """ - - self.select_data_callbacks.append(callback) - - def on_item_double_clicked(self, item: QTreeWidgetItem, col: int) -> None: - """ - 双击条目的事件,触发数据显示。 - """ - if col == 0 and item.text(0) in self.nodes.keys(): - return - # self.show_data(item.text(0)) - - def on_right_clicked(self, pos): - """ - 右键点击某一条目的事件,此时会弹出菜单。 - """ - item = self.currentItem() - if item is not None and item.text(0) in self.nodes.keys(): - self.context_menu.exec_(self.mapToGlobal(pos)) - - def on_show_data_by_context_menu(self, action: 'QAction'): - """ - 右键菜单点击‘显示数据’所触发的事件。 - """ - item = self.currentItem() - if item is not None and item.text(0) in self.nodes.keys(): - return - - def autorepr(self, obj: Any, max_length=80) -> str: - """ - 封装了repr方法,数据过长的时候,取较短的。 - """ - if isinstance(obj, str): - return obj - else: - return repr(obj).replace('\n', '').replace('\r', '')[:max_length] - - def get_size(self, data: Any): - """ - 获取数据的尺寸。 - 有‘shape’这一属性的,size就等于data.shape - 有‘__len__’这个属性的,返回len(data) - 否则返回1. - """ - size = 1 - if hasattr(data, 'shape'): - size = data.shape - elif isinstance(data, str): - size = 1 - elif hasattr(data, '__len__'): - try: - size = len(data) - except: - pass - - return size - - def set_data_dic(self, data_dic: Dict[str, object]) -> None: - """ - 显示数据 - :param data_dic:所有数据的字典{变量名:变量对象} - :return: - """ - self.expanding_stat = {} - self.memorize_expanding_stat() - self.clear() - self.nodes = {} - - for data_name in data_dic: - - data = data_dic[data_name] - text = str(data_name) - size = self.get_size(data) - """ - 如果变量不在变量列表中,就新建一个节点,并通过递归方式创建变量的各个属性。 - """ - child = QTreeWidgetItem(self) - child.item_id = text - self.nodes[child.item_id] = child - child.setText(0, text) - self.try_expand_item(child) - if isinstance(data, dict): - self.set_data_view(data, child) - - def get_hier(self, item: QTreeWidgetItem) -> int: - i = 0 - all_nodes = [self.nodes[k] for k in self.nodes.keys()] - while (1): - if item.parent() not in all_nodes: - i += 1 - item = item.parent() - else: - return i - - def set_data_view(self, data_dic: Dict[str, object], root: 'QTreeWidgetItem'): - """ - 递归方式显示json。 - 显示的时候要注意层级。 - :param data_dic: - :param root: - :return: - """ - for k in data_dic.keys(): - if isinstance(data_dic[k], dict): - child = QTreeWidgetItem(root) - child.setText(0, str(k)) - child.item_id = root.item_id + '-' + child.text(0) - self.nodes[child.item_id] = child - self.set_data_view(data_dic[k], child) - else: - child = QTreeWidgetItem(root) - child.setText(0, str(k)) - child.item_id = root.item_id + '-' + child.text(0) - self.nodes[child.item_id] = child - - child.setText(1, self.autorepr(data_dic[k])) - self.try_expand_item(child) - - def try_expand_item(self, item: QTreeWidgetItem): - """ - 如果状态为展开则展开,否则不展开 - :param item: - :return: - """ - expanding_stat = self.expanding_stat.get(item.item_id) - if expanding_stat is not None: - item.setExpanded(expanding_stat) - else: - item.setExpanded(False) - - -if __name__ == '__main__': - from PySide2.QtWidgets import QApplication - import sys - - app = QApplication(sys.argv) - sa = PMGJsonTree() - sa.show() - sa.setup_ui() - a = 123 - data_dic = { - 'p%d' % i: {'type': str(type(123)), - 'value': 123, - 'attributes': {name: str(getattr(a, name)) for name in dir(a)} - } for i in range(100)} - data_dic['aaaaaa'] = 'aaaaa ' - - - def f(): - data_dic['p10']['value'] = time.time() - sa.set_data_dic(data_dic) - - - sa.set_data_dic(data_dic) - sa.memorize_expanding_stat() - timer = QTimer() - timer.start(1000) - timer.timeout.connect(f) - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/trees/translations/qt_zh_CN.ts b/pyminer/pmgwidgets/widgets/basic/trees/translations/qt_zh_CN.ts deleted file mode 100644 index 3c8de54f..00000000 --- a/pyminer/pmgwidgets/widgets/basic/trees/translations/qt_zh_CN.ts +++ /dev/null @@ -1,257 +0,0 @@ - - - - - InputFilenameDialog - - - Ok - 确定 - - - - Cancel - 取消 - - - - PMFileSystemModel - - - Name - 名称 - - - - Size - 大小 - - - - Type - 类型 - - - - Last Modified - 上次修改 - - - - PMGAttrTree - - - Name - 名称 - - - - Size - 大小 - - - - Value - - - - - View - 查看 - - - - Save as - 保存为 - - - - Undo - 撤销 - - - - Redo - 重做 - - - - Delete - 删除 - - - - PMGFilesTreeview - - - Open - 打开 - - - - Import - 导入 - - - - New.. - 新建.. - - - - Folder - 文件夹 - - - - Rename - 重命名 - - - - Delete - 删除 - - - - Please Input file name - 请输入文件名 - - - - Error - 错误 - - - - Folder name %s is illeagal! - 文件夹名称%s不合规范! - - - - Folder %s already exists! - 文件夹%s 已经存在! - - - - File %s already exists! - 文件%s已经存在! - - - - Unable to Rename this file. - 无法重命名这个文件。 - - - - Unable to Move this file to recycle bin. - 无法将这个文件移动到回收站。 - - - - Copy - 复制 - - - - Paste - 粘贴 - - - - Copy File or Directory Error. - 无法复制文件或文件夹。 - - - - Filter - 过滤文件类型 - - - - Extension Name To Show - 显示的文件类型 - - - - File.. - 文件.. - - - - Python File - Python文件 - - - - Copy Path - 复制路径 - - - - Open Explorer - 打开文件管理器 - - - - Please input file name - 请输入文件路径 - - - - PMGJsonTree - - - Name - 名称 - - - - Value - - - - - View - 查看 - - - - Save as - 储存为 - - - - Undo - 撤销 - - - - Redo - 重做 - - - - Delete - 删除 - - - - app - - - Program Scripts - 程序脚本 - - - - Documents - 办公文件 - - - - Data Files - 数据文件 - - - diff --git a/pyminer/pmgwidgets/widgets/basic/trees/treecheck.py b/pyminer/pmgwidgets/widgets/basic/trees/treecheck.py deleted file mode 100644 index 9d59c392..00000000 --- a/pyminer/pmgwidgets/widgets/basic/trees/treecheck.py +++ /dev/null @@ -1,88 +0,0 @@ -""" -树状选择 -作者:侯展意 -""" -import os -from typing import Dict -from PySide2.QtCore import Qt, QLocale -from PySide2.QtWidgets import QTreeWidget, QTreeWidgetItem, QApplication, QTreeWidgetItemIterator -import sys -from pmgwidgets.utilities.source.translation import create_translator - - -class PMCheckTree(QTreeWidget): - def __init__(self, parent=None, data: Dict = None): - super().__init__(parent) - self.translator = create_translator( - path=os.path.join(os.path.dirname(__file__), 'translations', - 'qt_{0}.qm'.format(QLocale.system().name()))) # translator - self.tree_data = data - self.set_data(data) - self.clicked.connect(self.on_item_clicked) - self.expandAll() - - def set_data(self, data: Dict[str, Dict]): - self.tree_data = data - self.refresh_tree() - - def refresh_tree(self): - data = self.tree_data - for k in data.keys(): - parent = QTreeWidgetItem(self) - print(self.tr(k)) - parent.setText(0, self.tr(k)) - parent.setFlags(parent.flags() - | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) - for x in data[k].keys(): - child = QTreeWidgetItem(parent) - child.setFlags(child.flags() | Qt.ItemIsUserCheckable) - child.setText(0, x) - child.k = k - child.x = x - if data[k][x] == True: - child.setCheckState(0, Qt.Checked) - else: - child.setCheckState(0, Qt.Unchecked) - - def on_item_clicked(self, index): - - item = self.itemFromIndex(index) - if hasattr(item, 'x') and hasattr(item, 'k'): - if item.checkState(0) == Qt.Checked: - self.tree_data[item.k][item.x] = True - else: - self.tree_data[item.k][item.x] = False - print(self.tree_data) - - def get_data(self): - iter = QTreeWidgetItemIterator(self) - while iter.value(): - item = iter.value() - if hasattr(item, 'x') and hasattr(item, 'k'): - if item.checkState(0) == Qt.Checked: - self.tree_data[item.k][item.x] = True - else: - self.tree_data[item.k][item.x] = False - iter.__iadd__(1) - return self.tree_data - - def closeEvent(self, a0: 'QCloseEvent') -> None: - pass - - -if __name__ == '__main__': - app = QApplication(sys.argv) - app.tr('Program Scripts') - app.tr('Documents') - app.tr('Data Files') - foods = { - 'Program Scripts': {'.pyx': True, '.py': True, '.c': True, '.pyi': True, '.dll': True, - '.h': True, '.cpp': True, '.ipynb': True}, - 'Documents': {'.txt': True, '.md': True, '.doc': True, '.docx': True, '.ppt': True, '.pptx': True}, - 'Data Files': {'.csv': True, '.xls': True, '.xlsx': True, '.tab': True, '.dat': True, '.tsv': True, - '.sav': True, '.zsav': True, '.sas7bdat': True} - } - - tree = PMCheckTree(data=foods) - tree.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/basic/trees/varattrtree.py b/pyminer/pmgwidgets/widgets/basic/trees/varattrtree.py deleted file mode 100644 index 60c33ba3..00000000 --- a/pyminer/pmgwidgets/widgets/basic/trees/varattrtree.py +++ /dev/null @@ -1,218 +0,0 @@ -import os -from typing import Dict, TYPE_CHECKING, Callable, Any - -from PySide2.QtWidgets import QTreeWidget, QTreeWidgetItem, QWidget, QVBoxLayout, QPushButton, QHBoxLayout, QMenu -from PySide2.QtCore import Signal, Qt, QLocale - - -class PMGAttrTree(QTreeWidget): - signal_show_data_value = Signal(str) - signal_data_saveas = Signal(str) - signal_data_open = Signal(str) - select_data_callbacks = [] - extension_lib: 'extension_lib' = None - - def __init__(self, parent=None): - super().__init__(parent=None) - - self.filter_all_upper_case = False - self.filter_all_callables = True - self.setup_ui() - - # def is_item_legal(self, name: str, obj: object): - # return (not (callable(obj) and self.filter_all_callables)) and \ - # (not (name.isupper() and self.filter_all_upper_case)) - - def setup_ui(self): - self.nodes: Dict[str, 'QTreeWidgetItem'] = {} - self.setColumnCount(3) - header_item = QTreeWidgetItem() - header_item.setText(0, self.tr('Name')) - self.setColumnWidth(0, 10 * 10) - header_item.setText(1, self.tr('Size')) - self.setColumnWidth(1, 10 * 10) - header_item.setText(2, self.tr('Value')) - header_item.setTextAlignment(0, Qt.AlignCenter) - header_item.setTextAlignment(1, Qt.AlignCenter) - header_item.setTextAlignment(2, Qt.AlignCenter) - self.setHeaderItem(header_item) - self.auto_expand = False - - self.itemClicked.connect(self.on_item_clicked) - self.itemDoubleClicked.connect(self.on_item_double_clicked) - self.customContextMenuRequested.connect(self.on_right_clicked) - self.setContextMenuPolicy(Qt.CustomContextMenu) - - self.context_menu = QMenu() - show_action = self.context_menu.addAction(self.tr('View')) - save_action = self.context_menu.addAction(self.tr('Save as ')) - cancel_action = self.context_menu.addAction(self.tr('Undo')) - redo_action = self.context_menu.addAction(self.tr('Redo')) - delete_action = self.context_menu.addAction(self.tr('Delete')) - show_action.triggered.connect(self.on_show_data_by_context_menu) - - def on_item_clicked(self, item: QTreeWidgetItem, col: int) -> None: - """ - 点击条目时的回调函数。会顺次执行self.select_data_callbacks,而self.select_data_callbacks - 是由插件的add_select_data_callback(self, callback: Callable)方式加入的。 - """ - if item.isExpanded(): - self.collapseItem(item) - else: - self.expandItem(item) - - if col == 0 and item.text(0) in self.nodes.keys(): - for callback in self.select_data_callbacks: - callback(item.text(0)) - - def add_select_data_callback(self, callback: Callable): - """ - 加入回调函数。 - """ - - self.select_data_callbacks.append(callback) - - def on_item_double_clicked(self, item: QTreeWidgetItem, col: int) -> None: - """ - 双击条目的事件,触发数据显示。 - """ - if col == 0 and item.text(0) in self.nodes.keys(): - self.show_data(item.text(0)) - - def on_right_clicked(self, pos): - """ - 右键点击某一条目的事件,此时会弹出菜单。 - """ - item = self.currentItem() - if item is not None and item.text(0) in self.nodes.keys(): - self.context_menu.exec_(self.mapToGlobal(pos)) - - def on_show_data_by_context_menu(self, action: 'QAction'): - """ - 右键菜单点击‘显示数据’所触发的事件。 - """ - item = self.currentItem() - if item is not None and item.text(0) in self.nodes.keys(): - self.show_data(item.text(0)) - - def autorepr(self, obj: Any, max_length=80) -> str: - """ - 封装了repr方法,数据过长的时候,取较短的。 - """ - return repr(obj).replace('\n', '').replace('\r', '')[:max_length] - - def get_size(self, data: Any): - """ - 获取数据的尺寸。 - 有‘shape’这一属性的,size就等于data.shape - 有‘__len__’这个属性的,返回len(data) - 否则返回1. - """ - size = 1 - if hasattr(data, 'shape'): - size = data.shape - elif hasattr(data, '__len__'): - try: - size = len(data) - except: - pass - return size - - def set_data_dic(self, data_dic: Dict[str, object]) -> None: - """ - 显示数据 - :param data_dic:所有数据的字典{变量名:变量对象} - :return: - """ - for data_name in data_dic: - - data = data_dic[data_name] - text = repr(data_name) - size = self.get_size(data) - data_str = f'<{size}>\t{self.autorepr(data)}' - - if text in self.nodes.keys(): - """ - 如果变量在变量列表中,就刷新这个变量位置显示的文字信息,并通过递归方式创建变量的各个属性。 - """ - data_node = self.nodes[text] - data_node.setText(0, text) - data_node.setText(1, repr(size)) - data_node.setText(2, self.autorepr(data)) - data_node.takeChildren() - else: - """ - 如果变量不在变量列表中,就新建一个节点,并通过递归方式创建变量的各个属性。 - """ - child = QTreeWidgetItem(self) - self.nodes[text] = child - child.setText(0, text) - child.setText(1, str(size)) - child.setText(2, self.autorepr(data)) - - if isinstance(data, dict): - self.set_data_view(data, child) - if self.auto_expand: - self.expandItem(child) - else: - self.collapseItem(child) - - def get_hier(self, item: QTreeWidgetItem) -> int: - i = 0 - all_nodes = [self.nodes[k] for k in self.nodes.keys()] - while (1): - print(item.parent()) - if item.parent() not in all_nodes: - i += 1 - item = item.parent() - else: - return i - - def set_data_view(self, data_dic: Dict[str, object], root: 'QTreeWidgetItem'): - """ - 递归方式显示json。 - 显示的时候要注意层级。 - :param data_dic: - :param root: - :return: - """ - for k in data_dic.keys(): - print(k) - if type(data_dic[k]) == dict: - child = QTreeWidgetItem(root) - child.setText(0, repr(k)) - self.set_data_view(data_dic[k], child) - elif not isinstance(data_dic[k], str): - print(k) - d = {attr_name: str(getattr(data_dic[k], attr_name)) for attr_name in dir(data_dic[k])} - - child = QTreeWidgetItem(root) - child.setText(0, repr(k)) - self.set_data_view(d, child) - else: - child = QTreeWidgetItem(root) - child.setText(0, repr(k)) - child.setText(1, str(self.get_size(data_dic[k]))) - child.setText(2, data_dic[k]) - - -if __name__ == '__main__': - from PySide2.QtWidgets import QApplication, QTableWidget - import sys - - app = QApplication(sys.argv) - sa = PMGAttrTree() - sa.show() - sa.setup_ui() - data_dic = {'a': {'type': 'statespace', - 'A': {'type': 'timeseries', 'time': '[1,2,3]', 'mdata': '[3,2,1]'}, - 'B': {'type': 'matrix', 'value': '[[2],[1]]', 'aaaa': {'a': 'aa', 0: {'a': 'a'}}}, - 'C': {'type': 'matrix', 'value': '[[1,2]]', }, - 'D': {'type': 'matrix', 'value': '[[0]]', }, - 'row': ['left', 'x2'], 'column': ['column'], 'u': ['u'], 'sys': 'str'}, - 'b': 100, - 55: {123: 456, 'ff': {3333: 555}}, - 'sa': sa} - # sa.set_data_dic(data_dic) - sa.set_data_view(data_dic, sa) - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/composited/__init__.py b/pyminer/pmgwidgets/widgets/composited/__init__.py deleted file mode 100644 index 5a23169c..00000000 --- a/pyminer/pmgwidgets/widgets/composited/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -""" -综合控件 -""" -from .generalpanel import * -from .fastui import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/composited/buttonpanel.py b/pyminer/pmgwidgets/widgets/composited/buttonpanel.py deleted file mode 100644 index 3d679174..00000000 --- a/pyminer/pmgwidgets/widgets/composited/buttonpanel.py +++ /dev/null @@ -1,18 +0,0 @@ -from PySide2.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton - - -class PMGButtonPanel(QWidget): - def __init__(self, parent=None, layout_dir: str = 'v'): - super().__init__(parent=parent) - if layout_dir == 'v': - self.setLayout(QVBoxLayout()) - else: - self.setLayout(QHBoxLayout()) - - def add_button(self, text: str, callback: str = None, icon: str = None) -> QPushButton: - b = QPushButton() - b.setText(text) - self.layout().addWidget(b) - if callback is not None: - b.clicked.connect(callback) - return b \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/composited/fastui.py b/pyminer/pmgwidgets/widgets/composited/fastui.py deleted file mode 100644 index 6f3a80a7..00000000 --- a/pyminer/pmgwidgets/widgets/composited/fastui.py +++ /dev/null @@ -1,273 +0,0 @@ -""" -这是定义基类的基础文件,里面是用代码生成方式来制作功能性面板的示例。比如 -可以参阅同一目录下的其他文件。这些面板默认样式为悬浮在最上方,即使面板弹出,也可以操作主界面。 - -面板文件与PyMiner主程序完全解耦,启动PyMiner主程序后,可以直接运行此文件,或者fastui文件夹下的任何.py文件, -以此调试面板。此时,需要确保PyMiner的工作空间中有pandas.DataFrame类型的数据。 - -如datamerge.py(数据集合并)/ dropdata.py(去除缺失值)/ fillna(填充缺失值) 等。 - -最底层基类是BaseOperationDialog,是一个QDialog对话框基类,里面定义了一系列的基础方法,比如变量获取等。它是一个完全空白的对话框。 -次底层基类是DFOperationDialog,是用于数据集操作的基类。它定义有一个变量选择下拉菜单self.combo_box、一个参数输入面板self.panel,以及一个带有 -四个按钮(预览、保存、关闭和帮助)的按钮面板。 - -数据合并的面板继承于BaseOperationDialog,其余面板都继承于DFOperationDialog。这是因为数据合并面板需要多个选择数据的下拉框,用后者满足不了要求。 - -有关底层基类中的相关方法,请移步相应类定义的位置。 - -这些面板生成的函数,应当是一个有返回值的函数,参数为工作空间中的变量,或者是字符串、数字等。 - -比如,工作空间中有函数a、b。数据合并面板希望生成一个横向合并a和b的函数。那么,最终生成的代码应该为: -pd.concat([a,b],axis=0) - -这段函数有两种执行方式。一种是预览(preview),由preview按钮触发,调用基类的preview方法,直接执行pd.concat([a,b],axis=0);另一种是储存(store), -由“Save to var“按钮触发,调用基类store方法,要求用户输入一个新的变量名,然后执行代码f = pd.concat([a,b],axis=0),(f为用户输入的变量名)。 - -pd.concat函数有返回值。在点击“preview” - -@Time: 2021/2/8 12:54 -@Author: Zhanyi Hou -@Email: 1295752786@qq.com -@File: pmgui.py -""" -from abc import abstractmethod -from typing import List - -from PySide2.QtCore import Qt, QCoreApplication, Signal -from PySide2.QtWidgets import QDialog, QVBoxLayout, QApplication, QPushButton, QComboBox, QHBoxLayout, QLabel, \ - QTextBrowser - -from pyminer_comm import get_var_names, run_command, call_interface -from utils import input_identifier, bind_combo_with_workspace - - -def kwargs_to_str(kwargs: dict) -> str: - """ - 将字典参数转化为字符串的简易方法 - Args: - kwargs: - - Returns: - - """ - args_str = '' - for k, v in kwargs.items(): - args_str += '{k}={v},'.format(k=k, v=repr(v)) - return args_str - - -class BaseOperationDialog(QDialog): - """ - 最底层的功能面板基类。 - 定义了代码生成的有关方法。 - - """ - signal_update_combo = Signal() - - def __init__(self): - from pmgwidgets.utilities import PMGOneShotThreadRunner - self.thrunner: PMGOneShotThreadRunner = None - super(BaseOperationDialog, self).__init__() - - def store(self): - """ - 执行存储到变量的命令。 - - Returns: - - """ - code = self.get_assignment_code() - if code != '': - run_command(command=code, hint_text=self.get_prompt_template() + code, hidden=False) - - def preview(self) -> None: - """ - 预览分析结果。 - Returns: - - """ - code = self.get_value_code() - if code != '': - run_command(command=code, hint_text=self.get_prompt_template() + code, hidden=False) - - def help(self) -> None: - """ - 弹出帮助面板 - Returns: None - - """ - dlg = QDialog() - dlg.setLayout(QVBoxLayout()) - textBrowser = QTextBrowser(self) - dlg.layout().addWidget(textBrowser) - textBrowser.setMarkdown(self.get_help_content()) - dlg.exec_() - - def get_help_content(self) -> str: - """ - 生成帮助内容 - - 为markdown格式 - - Notes:子类最好重写这个方法 - Returns: - - """ - return """# 帮助\n\n暂未定义帮助""" - - def get_prompt_template(self) -> str: - """ - 获取提示模板 - - Notes:子类可以不重写这个方法 - Returns: - """ - return '' - - def kwargs_to_str(self, kwargs: dict) -> str: - """ - 将字典参数转化为字符串的简易方法 - Args: - kwargs: - - Returns: - - """ - args_str = '' - for k, v in kwargs.items(): - args_str += '{k}={v},'.format(k=k, v=repr(v)) - return args_str - - @abstractmethod - def get_value_code(self) -> str: - """ - 获取一段代码,这段代码应当有返回值,而不是赋值代码。 - 例如, “a = pd.concat([c,d])” - - Notes:子类必须重写这个方法。 - - Returns: - """ - return '' - - def get_assignment_code(self) -> str: - """ - 获取赋值语句。实际上就是先让用户输入一个变量名,然后将这个变量名和赋值语句放在get_value_code方法 - 生成的代码的左侧。 - - 倘若用户输入的变量名是“a”,get_value_code方法生成的代码为“pd.concat([c,d])”,那么这个方法生成的代码就是: - “a = pd.concat([c,d])” - - 子类中通常无需重写这个方法 - - Returns: 合并好的代码 - """ - code = self.get_value_code() - identifier = input_identifier(parent=self, default_name=self.combo_box.currentText(), allow_existing_name=True) - if identifier != '': - code = identifier + ' = ' + code - return code - return '' - - def get_selected_variables(self) -> List[str]: - """ - 获取当前界面上选中的变量。 - 当界面为PyMiner调用时,此方法不能在主进程中调用,否则会阻塞消息循环。 - Returns: 当前界面上选中的变量,可能是一个列表。 - """ - return call_interface('workspace_inspector', 'get_selected_variables', {}, request_ret=True) - - def showEvent(self, arg__1: 'QShowEvent') -> None: - from pmgwidgets.utilities import PMGOneShotThreadRunner - if self.thrunner is None or not self.thrunner.is_running(): - self.thrunner = PMGOneShotThreadRunner(callback=self.get_selected_variables) - self.thrunner.signal_finished.connect(self.on_update_combo) - - -class DFOperationDialog(BaseOperationDialog): - signal_update_combo = Signal() - - def __init__(self): - from pmgwidgets.widgets.composited import PMGPanel - super(DFOperationDialog, self).__init__() - self.setLayout(QVBoxLayout()) - self.combo_box = QComboBox() - bind_combo_with_workspace(self.combo_box) - self.panel = PMGPanel() - self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint) - self.button_layout = QHBoxLayout() - - self.button_preview = QPushButton(QCoreApplication.translate('BaseDFOperationDialog', "预览")) - self.button_store = QPushButton(QCoreApplication.translate('BaseDFOperationDialog', "保存到变量")) - self.button_close = QPushButton(QCoreApplication.translate('BaseDFOperationDialog', "关闭")) - self.button_help = QPushButton(QCoreApplication.translate('BaseDFOperationDialog', "帮助")) - - # self.button_box.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Help) - self.button_layout.addWidget(self.button_preview) - self.button_layout.addWidget(self.button_store) - self.button_layout.addWidget(self.button_help) - self.button_layout.addWidget(self.button_close) - - self.button_preview.clicked.connect(self.preview) # 预览 - self.button_store.clicked.connect(self.store) # 储存 - self.button_close.clicked.connect(self.close) # 关闭对话框 - self.button_help.clicked.connect(self.help) # 显示帮助 - - self.hint_label = QLabel(self.tr('选择变量')) - self.layout().addWidget(self.hint_label) - self.layout().addWidget(self.combo_box) - self.layout().addWidget(self.panel) - self.layout().addLayout(self.button_layout) - - def on_update_combo(self, vars: List[str]): - self.combo_box.clear() - self.combo_box.addItems(get_var_names()) - if len(vars) > 0: - self.combo_box.setCurrentText(vars[0]) - - -class FunctionGUIDialog(DFOperationDialog): - def __init__(self, dic): - super(FunctionGUIDialog, self).__init__() - self.func_name = dic["func_name"] - self.with_object = dic["with_object"] - if not self.with_object: - self.combo_box.hide() - self.setWindowTitle(dic["title"]) - views = [] - optional_names = [] - for arg in dic["args"]: - views.append("-" * 60) - if arg["optional"]: - optional_names.append(arg["name"]) - views.append(("check_ctrl", arg["name"] + "#enable", "", True)) - arg["ctrl"]["name"] = arg["name"] - views.append(arg["ctrl"]) - - self.panel.set_items(views) - for op_name in optional_names: - self.panel.set_as_controller(op_name + "#enable", [op_name], True, ) - - def get_value_code(self) -> str: - values = self.panel.get_value_with_filter() # 只获取使能并且可见的控件的值 - print(values,self.panel.widgets_dic) - values = {k: v for k, v in values.items() if k.isidentifier()} - varname = self.combo_box.currentText() - args_str = '' - for k, v in values.items(): - args_str += '{k}={v},'.format(k=k, v=repr(v)) - if not self.with_object: - code = '{func_name}({args})'.format(func_name=self.func_name, args=args_str) - else: - code = '{var_name}.{method_name}({args})'.format(var_name=varname, - method_name=self.func_name, - args=args_str) - print(code,values) - return code - - -if __name__ == '__main__': - app = QApplication([]) - md = DFOperationDialog() - md.show() - app.exec_() diff --git a/pyminer/pmgwidgets/widgets/composited/generalpanel.py b/pyminer/pmgwidgets/widgets/composited/generalpanel.py deleted file mode 100644 index df345e0f..00000000 --- a/pyminer/pmgwidgets/widgets/composited/generalpanel.py +++ /dev/null @@ -1,458 +0,0 @@ -""" -命名规范: - -PMG+控件类型+功能类型 -控件类型可以是一词或者两个词。 - -相关设计思想来自ImagePy团队的SciWx中的normal控件,对接口做出相关调整,增加了json解码解包的部分。 - -作者:侯展意 -qq:1295752786@qq.com -""" - -import logging -from typing import Any, List, Tuple, Dict, Callable, Union, Optional - -from PySide2.QtCore import Signal -from PySide2.QtGui import QCloseEvent -from PySide2.QtWidgets import QSpacerItem, QSizePolicy, QDialog, QFrame, QVBoxLayout, QHBoxLayout, QDialogButtonBox, \ - QApplication, QLabel - -from pmgwidgets.widgets.extended import (BaseExtendedWidget, PMGCheckCtrl, PMGColorCtrl, PMGEvalCtrl, PMGComboCtrl, - PMGFileCtrl, PMGMultiTypeCtrl, PMGVariablesComboCtrl, - PMGKeyMapCtrl, PMGFolderCtrl, PMGLineCtrl, PMGNumberCtrl, PMGPasswordCtrl, - PMGListCtrl, PMGDateCtrl, PMGTimeCtrl, PMGDateTimeCtrl, PMGNumberSpinCtrl, - PMGTableShow, PMGLabelShow, PMGRuleCtrl) - -try: - from pmgwidgets.widgets.extended import PMGTimeSeriesShow -except ImportError: - PMGTimeSeriesShow = None - -from pmgwidgets.utilities.uilogics.codechecking import iter_isinstance, ErrorReporter - -logger = logging.getLogger(__name__) -views_dic = {} -views_dic.update({'color_ctrl': PMGColorCtrl, - 'eval_ctrl': PMGEvalCtrl, - 'file_ctrl': PMGFileCtrl, - 'keymap_ctrl': PMGKeyMapCtrl, - 'folder_ctrl': PMGFolderCtrl, - 'line_ctrl': PMGLineCtrl, - 'number_ctrl': PMGNumberCtrl, - 'password_ctrl': PMGPasswordCtrl, - 'multitype_ctrl': PMGMultiTypeCtrl, - "vars_combo_ctrl": PMGVariablesComboCtrl}) - -views_dic.update({'editor_ctrl': globals().get('PMGEditorCtrl'), - 'check_ctrl': PMGCheckCtrl, - 'combo_ctrl': PMGComboCtrl, - 'list_ctrl': PMGListCtrl, - 'time_ctrl': PMGTimeCtrl, - 'date_ctrl': PMGDateCtrl, - 'datetime_ctrl': PMGDateTimeCtrl, - 'numberspin_ctrl': PMGNumberSpinCtrl - }) - -views_dic.update({'timeseries_show': PMGTimeSeriesShow, - 'label_show': PMGLabelShow, - 'table_show': PMGTableShow, - 'rules_ctrl': PMGRuleCtrl - }) - -PANEL_VIEW_CLASS = List[Union[ - Tuple[Any], - List[Any], - Dict[str, Any] -]] - - -class PMGPanel(QFrame): - widgets_dic: Dict[str, BaseExtendedWidget] = {} - signal_settings_changed = Signal(dict) - - def __init__(self, parent=None, views: PANEL_VIEW_CLASS = None, layout_dir: str = 'v', with_spacer: bool = True, - with_aux_spacer=False, - spacing: int = 0, - margins: Union[int, Tuple[int, int, int, int]] = 0): - super(PMGPanel, self).__init__(parent) - self._initial_style_sheet = self.styleSheet() - self.layout_dir = layout_dir - self.with_spacer = with_spacer - self.with_aux_spacer = with_aux_spacer - - if layout_dir == 'v': - self.setLayout(QVBoxLayout()) - else: - self.setLayout(QHBoxLayout()) - - self.layout().setSpacing(spacing) - if isinstance(margins, tuple): - assert iter_isinstance(margins, int), \ - ErrorReporter.create_invalid_parameter_type_message('margins', type(margins), int) - self.layout().setContentsMargins(*margins) - elif isinstance(margins, int): - margins = [margins] * 4 - self.layout().setContentsMargins(*margins) - else: - raise TypeError(ErrorReporter.create_invalid_parameter_type_message('margins', type(margins), - 'int or Tuple[int,int,int,int]')) - self.layout() - self.set_items(views) - - self._param_changd_callbacks: Dict[str, List[Callable]] = {} - - def set_param_changed_callback(self, param: str, callback: Callable): - """ - - Args: - param: - callback: - - Returns: - - """ - # assert param not in self._param_changd_callbacks.keys(), \ - # repr(param) + ' is already in callback dict\'s keys: %s ' % (repr(self._param_changd_callbacks.keys())) - assert param in self.widgets_dic.keys(), 'widget with param \'%s\' is not found in this PMGPanel' % param - if param not in self._param_changd_callbacks.keys(): - self._param_changd_callbacks[param] = [callback] - else: - self._param_changd_callbacks[param].append(callback) - - def on_param_changed(self, param): - if param in self._param_changd_callbacks.keys(): - for callback in self._param_changd_callbacks[param]: - callback(self.get_value()) - - def set_debug_mode(self, debug: bool): - """ - :param debug:将debug设置为True,即可进入debug模式。该模式下,PMGPanel会用醒目(但是很丑)的颜色显示出其上的不同控件,方便布局调整。 - :return: - """ - if debug: - self._initial_style_sheet = self.styleSheet() - red = 100 + random.randint(0, 155) - self.setStyleSheet( - 'PMGPanel{background-color:#%s0000;}QLabel{background-color:yellow;}BaseExtendedWidget{background-color:green;}' % hex( - red)[2:]) - else: - self.setStyleSheet(self._initial_style_sheet) - - def emit_settings_changed_signal(self): - """ - 发出设置已改变的信号 - :return: - """ - self.signal_settings_changed.emit(self.get_value()) - - def on_settings_changed(self, name): - self.signal_settings_changed.emit(self.get_value()) - self.on_param_changed(name) - - def add_widget(self, argument: Union[List, Tuple, Dict], layout: Union[QHBoxLayout, QVBoxLayout]) -> None: - """ - 创建控件,并且将其添加到控件字典中。 - :param argument: - :return: - """ - if isinstance(argument, str): - layout.addWidget(QLabel(argument)) - elif isinstance(argument, (tuple, list)): - name = argument[1] - try: - widget = views_dic[argument[0]](self.layout_dir, *argument[2:]) - except: - import traceback - traceback.print_exc() - raise ValueError(repr(argument) + 'is invalid!') - if self.widgets_dic.get(name) is None: - self.widgets_dic[name] = widget - widget.signal_param_changed.connect(self.on_settings_changed) - widget.name = name - layout.addWidget(widget) - elif isinstance(argument, dict): - widget_type = views_dic.get(argument['type']) - assert widget_type is not None, repr(argument) + 'is of invalid widget type!!' - name = argument['name'] - title = argument.get('title') if 'title' in argument.keys() else '' - initial_value = argument.get('init') - preserved_params = ['type', 'name', 'title', 'init'] - kwargs = {k: v for k, v in argument.items() if k not in preserved_params} - widget = widget_type(self.layout_dir, title, initial_value, **kwargs) - if self.widgets_dic.get(name) is None: - self.widgets_dic[name] = widget - widget.name = name - widget.signal_param_changed.connect(self.on_settings_changed) - layout.addWidget(widget) - pass - else: - raise TypeError('Argument %s should be ') - - def _set_items(self, views: PANEL_VIEW_CLASS = None): - """ - Clear all items on the panel and then add items from argument 'views'. - Args: - views: - - Returns: - - """ - if views is None: - return - self.widgets_dic: Dict[str, QWidget] = {} - self.layout().setContentsMargins(0, 0, 0, 0) - for v in views: - if isinstance(v, dict): - self.add_widget(v, self.layout()) - elif isinstance(v[0], str): - self.add_widget(v, self.layout()) - - elif isinstance(v[0], (list, tuple, dict)): - sub_layout = None - if self.layout_dir == 'v': - sub_layout = QHBoxLayout() - self.layout().addLayout(sub_layout) - else: - sub_layout = QVBoxLayout() - self.layout().addLayout(sub_layout) - for subv in v: - self.add_widget(subv, sub_layout) - if self.with_aux_spacer: - if self.layout_dir == 'h': - sub_layout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) - else: - sub_layout.addItem(QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)) - if self.with_spacer: - if self.layout_dir == 'v': - self.layout().addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) - else: - self.layout().addItem(QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)) - - def set_items(self, items: PANEL_VIEW_CLASS = None): - self.widgets_dic = {} - for i in range(self.layout().count()): - widget = self.layout().itemAt(i).widget() - layout = self.layout().itemAt(i).layout() - if widget is not None: - widget.deleteLater() - if layout is not None: - for j in range(layout.count()): - widget = layout.itemAt(j).widget() - if widget is not None: - widget.deleteLater() - layout.deleteLater() - self._set_items(items) - - def get_ctrl(self, ctrl_name: str) -> 'BaseExtendedWidget': - return self.widgets_dic.get(ctrl_name) - - def get_value(self): - result = {} - for k in self.widgets_dic: - result[k] = self.widgets_dic[k].get_value() - return result - - def get_value_with_filter(self, filter: str = 'enabled_and_visible'): - assert filter in {'enabled', 'visible', 'enabled_and_visible'} - result = {} - for k in self.widgets_dic: - widget = self.widgets_dic[k] - if filter == 'enabled_and_visible' and widget.isEnabled() and widget.isVisible(): - result[k] = widget.get_value() - elif (widget.isVisible() and filter == 'visible') or (widget.isEnabled() and filter == 'enabled'): - result[k] = widget.get_value() - return result - - def set_as_controller(self, controller_param: str, target_params: List[str], - trigger_value: [Any, Callable[[Any], bool]], - action='enable'): - assert action in ['enable', 'disable', 'show', 'hide'] - assert isinstance(target_params, list) - trigger_condition_func: Callable[[Any], bool] = None - if not callable(trigger_value): - trigger_condition_func = lambda obj: obj == trigger_value - else: - trigger_condition_func = trigger_value - _condition_func = lambda params: trigger_condition_func(params[controller_param]) - for target_param in target_params: - assert target_param in self.widgets_dic.keys(), 'Widget %s does not exist!, all widgets: %s' % ( - target_param, self.widgets_dic) - - if action == 'enable' or action == 'show': - condition_func = lambda params: _condition_func(params) - else: - condition_func = lambda params: not _condition_func(params) - - def callback(params): - for target_param in target_params: - if action == 'enable' or action == 'disable': - self.get_ctrl(target_param).setEnabled(condition_func(params)) - else: - self.get_ctrl(target_param).setVisible(condition_func(params)) - - self.set_param_changed_callback(controller_param, callback) - callback(self.get_value()) # 设置时会被调用一次,以自动刷新界面。 - - def set_value(self, values: Dict[str, Union[int, str, List, float, Tuple]]): - """ - 设置值。如果values中键对应的控件不存在,那么也不会报错,而是会忽略这一项。 - :param values:字典。如果values中键对应的控件不存在,那么也不会报错,而是会忽略这一项。 - :return: - """ - for k in values.keys(): - w = self.widgets_dic.get(k) - if w is not None: - w.set_value(values[k]) - - def closeEvent(self, a0: QCloseEvent) -> None: - super().closeEvent(a0) - self.deleteLater() - self.signal_settings_changed.emit(self.get_value()) - - -class PMGPanelDialog(QDialog): - """ - 一个对话框,直接弹出PMGPanel。 - TODO:要求如果有不合法的数值,就不可关闭。 - """ - - def __init__(self, parent, views, with_spacer=False): - super().__init__(parent) - self.panel = PMGPanel(parent=self, views=views, with_spacer=with_spacer) - self.setLayout(QVBoxLayout()) - self.layout().addWidget(self.panel) - button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) - - button_box.accepted.connect(self.accept) - button_box.rejected.connect(self.reject) - self.layout().addWidget(button_box) - self.changes_accepted = False - - def get_value(self) -> Dict[str, Any]: - return self.panel.get_value() - - def set_value(self, values: Dict[str, Any]) -> None: - self.panel.set_value(values) - - def accept(self): - if self.verify(self.get_value()): - self.changes_accepted = True - super().accept() - - def verify(self, values) -> bool: - return True - - -def is_standard_widget_name(widget_name: str) -> bool: - """ - 返回字符串是否对应一个标准化的PMGPanel控件。 - :return: - """ - return views_dic.get(widget_name) is not None - - -def parse_simplified_pmgjson(identifier, data, params) -> Optional[List[Union[int, str]]]: - """ - 解析简化版的json数据! - :param identifier: - :param data: - :param params: - :return: - """ - if len(params) > 0: - if is_standard_widget_name(params[0]): - return [params[0], identifier, 'Input Value', data] + params[1:] - - if isinstance(data, bool): - return ['check_ctrl', identifier, 'Input Bool', data] - - elif isinstance(data, (int, float)): - - return ['numberspin_ctrl', identifier, 'Input Value', data] + params - - elif isinstance(data, str): - return ['line_ctrl', identifier, 'Input String', data] - - -if __name__ == '__main__': - import sys - - app = QApplication(sys.argv) - # 类型;名称;显示的提示文字;初始值;//单位;范围 - views1 = [('line_ctrl', 'name', 'What\'s your name?', 'hzy'), - {'type': 'line_ctrl', 'name': 'your_name', 'title': 'what is your name?', 'init': 'hzy'}, - ('password_ctrl', 'password', 'What\'s your password?', '123456'), - ('file_ctrl', 'file_dir', 'File Name', '/home/hzy/Desktop/123.txt'), - # ('editor_ctrl', 'code', 'Input Python Code', 'print(123)', 'sql'), - ('number_ctrl', 'age', 'How old are you?', 88, 'years old', (0, 150)), - ('number_ctrl', 'height', 'How High could This Plane fly?', 12000, 'm', (10, 20000)), - ('check_ctrl', 'sport', 'do you like sport', True), - ('numberspin_ctrl', 'eyesight', '视力', 4.0, '度', (3.0, 5.5), 0.1), - ('numberspin_ctrl', 'apple_num', '苹果数量', 4, '个', (0, 10), 1), ] - views2 = [('combo_ctrl', 'plane_type', 'plane type', 'f22', ['f22', 'f18', 'j20', 'su57'], - ['f22战斗机', 'f18战斗轰炸机', 'j20战斗机', 'su57战斗机']), - ('color_ctrl', 'color', 'Which color do u like?', (0, 200, 0)), - ('list_ctrl', 'inputs', 'Set Inputs', [['1', '2', '3'], ['#1', '#2', '#3']], lambda: str(123)), - ('list_ctrl', 'inputs_2', 'Set Inputs', [[None, None, None], ['##1', '##2', '##3'], ], lambda: None), - ('date_ctrl', 'date', '设置时间', (1970, 7, 21)), - [ - ('eval_ctrl', 'code_eval', 'Evaluate this code', 123 + 456, 'normal'), - ('eval_ctrl', 'code_eval2', 'Evaluate this code', (1, 2, 3), 'safe') - ], - # ('keymap_ctrl', 'key_map2', 'Key For Find', 'Ctrl+F'), - ] - sp = PMGPanel(views=views1, layout_dir='v') - sp.set_items(views1) - sp.signal_settings_changed.connect(lambda settings: print('views1-settings', settings)) - # sp.show() - - sp2 = PMGPanel(views=views2, layout_dir='v') - sp2.signal_settings_changed.connect(lambda settings: print('views2-settings', settings)) - sp2.set_items(views2) - # sp2.show() - - import random - - views3 = \ - [ - # {'type': 'timeseries_show', - # 'name': 'cpu_occupation', - # 'title': 'CPU占用', - # 'init': {'timestamps': [i + 1 for i in range(10)], - # 'line1': {'tag': 'CPU利用率1', - # 'data': [random.randint(0, 100) for i in - # range(10)]}, - # 'line2': {'tag': 'CPU利用率2', - # 'data': [random.randint(0, 100) for i in - # range(10)]} - # }, - # 'y_range': (0, 100), - # 'xlabel': '时间', - # 'ylabel': '占用率', - # 'threshold_range': (0, 78), - # 'legend_face_color': "#00ff00" - # }, - ("vars_combo_ctrl", "variables", "选择变量", ""), - ("multitype_ctrl", "multiple_types", "多种类型", [[None, None, None], ['诶诶诶', '嗷嗷喊', 'qq']], [{ - "type_title": "字符串列表", - "ctrls": [ - ("list_ctrl", "list_ctrl", 'input list of strings', [[None, None, None], ['##1', '##2', '##3']], - lambda: None), - ], - "on_ok": lambda values: values["list_ctrl"][1]}, - { - "type_title": "字符串", - "ctrls": [ - ("line_ctrl", "aaaa", 'input a string', "Please input a string"), - ], - "on_ok": None - } - ]) - ] - sp3 = PMGPanel(views=views3, layout_dir='v') - sp3.signal_settings_changed.connect(lambda settings: print('views2-settings', settings)) - sp3.set_items(views3) - sp3.show() - - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/extended/__init__.py b/pyminer/pmgwidgets/widgets/extended/__init__.py deleted file mode 100644 index a3e91d89..00000000 --- a/pyminer/pmgwidgets/widgets/extended/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from .base import * -from .checkbuttons import * -from .comboboxes import * -from .entries import * -from .labels import * -from .lists import * -from .others import * -from .plots import * -from .radiobuttons import * -from .spins import * -from .tables import * -from .texts import * -from .trees import * diff --git a/pyminer/pmgwidgets/widgets/extended/base/__init__.py b/pyminer/pmgwidgets/widgets/extended/base/__init__.py deleted file mode 100644 index 92290609..00000000 --- a/pyminer/pmgwidgets/widgets/extended/base/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .baseextendedwidget import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/extended/base/baseextendedwidget.py b/pyminer/pmgwidgets/widgets/extended/base/baseextendedwidget.py deleted file mode 100644 index b5a97448..00000000 --- a/pyminer/pmgwidgets/widgets/extended/base/baseextendedwidget.py +++ /dev/null @@ -1,95 +0,0 @@ -import os -import string -import sys -import time -from typing import List, Dict, Tuple, Union, Callable, Any -from PySide2.QtCore import Signal -from PySide2.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QFrame - - -class BaseExtendedWidget(QFrame): - """ - 基础参数控件的类型。所有的参数控件都在其上派生而来。 - """ - signal_param_changed = Signal(str) - NORMAL = 0 - WARNING = 1 - ERROR = 2 - - def __init__(self, layout_dir='v'): - super(BaseExtendedWidget, self).__init__() - - self._initial_stylesheet = self.styleSheet() - # if layout_dir == 'v': - self.name = '' - self.central_layout = QVBoxLayout() - # else: - # self.central_layout = QHBoxLayout() - self.setLayout(self.central_layout) - self.central_layout.setContentsMargins(0, 0, 0, 0) - - self.on_para_change = None - self.__app = None # SciApp。初始化控件的时候指定,并且在调用set_app的时候传入。 - - def para_changed(self): - if (self.on_para_change is not None) and (self.__app is not None): - self.on_para_change(self.__app) - - def set_app(self, app): - """ - 在sciwx中,需要指定SciApp。但是在PyMiner中目前还没有这种需求。 - :param app: - :return: - """ - self.__app = app - - def is_key(self, event, type=''): - """ - 'dir':判断方向键 - 'alpha':判断是否为26个字母 - 'hex':判断是否为十六进制数字或者字母 - 'digit':判断是否为数字0~9 - 'valid':包含数字、字母或者退格键。 - """ - - type = type.lower() - if type == '': - return True - elif type.startswith('dir'): - return event.keysym.lower() in ('left', 'right', 'up', 'down') - elif type.startswith('alpha'): - return event.keysym in string.ascii_lowercase - elif type.startswith('hex'): - return event.keysym in string.hexdigits - elif type.startswith(('digit')): - return event.keysym in string.digits - - def set_value(self, value: Any): - pass - - def get_value(self): - pass - - def set_params(self, *args, **kwargs): - pass - - def alert(self, level: str, *args, **kwargs): - """ - alert - Args: - level: str - 'normal' - 'warning' - 'error' - - Returns: - - """ - if level == 'normal': - self.setStyleSheet(self._initial_stylesheet) - elif level == 'error': - self.setStyleSheet('QWidget{background-color:#ff0000;}') - elif level == 'warning': - self.setStyleSheet('QWidget{background-color:#ffff00;}') - else: - raise ValueError('alert not defined!!') diff --git a/pyminer/pmgwidgets/widgets/extended/checkbuttons/__init__.py b/pyminer/pmgwidgets/widgets/extended/checkbuttons/__init__.py deleted file mode 100644 index d95717ed..00000000 --- a/pyminer/pmgwidgets/widgets/extended/checkbuttons/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .check import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/extended/checkbuttons/check.py b/pyminer/pmgwidgets/widgets/extended/checkbuttons/check.py deleted file mode 100644 index 86686bf4..00000000 --- a/pyminer/pmgwidgets/widgets/extended/checkbuttons/check.py +++ /dev/null @@ -1,30 +0,0 @@ -from PySide2.QtWidgets import QLabel, QHBoxLayout, QCheckBox -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGCheckCtrl(BaseExtendedWidget): - """ - bool, 'sport', 'do you like sport',True - """ - - def __init__(self, layout_dir: str, title: str, initial_value: bool): - super().__init__(layout_dir) - - # layout = QHBoxLayout() - # layout.setContentsMargins(0, 0, 0, 0) - self.on_check_callback = None - check = QCheckBox(text=title) - check.stateChanged.connect(self.on_check) - # layout.addWidget(check) - self.check = check - self.central_layout.addWidget(check) - self.set_value(initial_value) - - def get_value(self) -> bool: - return self.check.isChecked() - - def set_value(self, value: bool): - self.check.setChecked(value) - - def on_check(self): - self.signal_param_changed.emit(self.name) diff --git a/pyminer/pmgwidgets/widgets/extended/comboboxes/__init__.py b/pyminer/pmgwidgets/widgets/extended/comboboxes/__init__.py deleted file mode 100644 index 89123c2f..00000000 --- a/pyminer/pmgwidgets/widgets/extended/comboboxes/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .combo import * -from .variables_combo import PMGVariablesComboCtrl \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/extended/comboboxes/combo.py b/pyminer/pmgwidgets/widgets/extended/comboboxes/combo.py deleted file mode 100644 index 3671b5ac..00000000 --- a/pyminer/pmgwidgets/widgets/extended/comboboxes/combo.py +++ /dev/null @@ -1,62 +0,0 @@ -from typing import List, Any - -from PySide2.QtWidgets import QLabel, QHBoxLayout, QComboBox -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGComboCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title: str, initial_value: Any, choices: list, texts=None): - """ - ComboBox control to select values - Args: - layout_dir: - title: - initial_value: - choices: - texts: - """ - super().__init__(layout_dir) - self.choices = [] - self.text_list = [] - - lab_title = QLabel(text=title) - layout = QHBoxLayout() - self.central_layout.addWidget(lab_title) - self.on_check_callback = None - check = QComboBox() - - check.currentIndexChanged.connect(self.on_value_changed) - - layout.addWidget(check) - self.central_layout.addLayout(layout) - self.check = check - self.set_choices(choices, texts) - self.set_value(initial_value) - - def set_choices(self, choices: list, texts: list = None): - self.check.clear() - self.choices = choices - self.text_list = [] - if texts is None: - for choice in choices: - self.text_list.append(str(choice)) - else: - if len(texts) != len(choices): - raise Exception('Length of argument \'choices\'(len=%d) and \'texts\'(len=%d) are not same!' % - (len(choices), len(texts))) - else: - self.text_list = texts - self.check.addItems(self.text_list) - - def on_value_changed(self): - self.signal_param_changed.emit(self.name) - - def set_value(self, value: Any): - index = self.choices.index(value) - self.check.setCurrentIndex(index) - - def get_value(self) -> Any: - try: - return self.choices[self.check.currentIndex()] - except: - return None diff --git a/pyminer/pmgwidgets/widgets/extended/comboboxes/variables_combo.py b/pyminer/pmgwidgets/widgets/extended/comboboxes/variables_combo.py deleted file mode 100644 index c0b30124..00000000 --- a/pyminer/pmgwidgets/widgets/extended/comboboxes/variables_combo.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Any - -from .combo import PMGComboCtrl - - -class Var(): - def __init__(self, name: str): - self.name = name - - def __repr__(self): - return self.name - - -class PMGVariablesComboCtrl(PMGComboCtrl): - def __init__(self, layout_dir: str, title: str, initial_value: Any = ""): - """ - ComboBox control to select values - Args: - layout_dir: - title: - initial_value: - """ - from utils import bind_panel_combo_ctrl_with_workspace - super().__init__(layout_dir, title, initial_value, [""], [""]) - bind_panel_combo_ctrl_with_workspace(self) - - def get_value(self) ->str: - return Var(super().get_value()) diff --git a/pyminer/pmgwidgets/widgets/extended/entries/__init__.py b/pyminer/pmgwidgets/widgets/extended/entries/__init__.py deleted file mode 100644 index 886c5f38..00000000 --- a/pyminer/pmgwidgets/widgets/extended/entries/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from .colorctrl import * -from .evalctrl import * -from .filectrl import * -from .folderctrl import * -from .keymappingctrl import * -from .linectrl import * -from .numctrl import * -from .passwordctrl import * diff --git a/pyminer/pmgwidgets/widgets/extended/entries/baseentryctrl.py b/pyminer/pmgwidgets/widgets/extended/entries/baseentryctrl.py deleted file mode 100644 index 88aafca2..00000000 --- a/pyminer/pmgwidgets/widgets/extended/entries/baseentryctrl.py +++ /dev/null @@ -1,14 +0,0 @@ -from PySide2.QtWidgets import QLineEdit -from ..base import BaseExtendedWidget - - -class PMGBaseEntryCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str): - super().__init__(layout_dir) - self.ctrl: 'QLineEdit' = None - - def set_ctrl_warning(self, warning: bool): - if warning == True: - self.ctrl.setStyleSheet("background-color:#ff0000;") - else: - self.ctrl.setStyleSheet("") diff --git a/pyminer/pmgwidgets/widgets/extended/entries/colorctrl.py b/pyminer/pmgwidgets/widgets/extended/entries/colorctrl.py deleted file mode 100644 index ace118eb..00000000 --- a/pyminer/pmgwidgets/widgets/extended/entries/colorctrl.py +++ /dev/null @@ -1,91 +0,0 @@ -from typing import Tuple - -from PySide2.QtGui import QColor -from PySide2.QtWidgets import QLineEdit, QLabel, QHBoxLayout, QPushButton, QColorDialog -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGColorCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title: str, initial_value: str): - super().__init__(layout_dir) - self.on_check_callback = None - self.prefix = QLabel(text=title) - - entryLayout = QHBoxLayout() - - self.ctrl = QLineEdit() - self.ctrl.textChanged.connect(self.ontext) - - self.color_button = QPushButton() - self.color_button.clicked.connect(self.oncolor) - self.central_layout.addWidget(self.prefix) - self.central_layout.addLayout(entryLayout) - entryLayout.addWidget(self.ctrl) - entryLayout.addWidget(self.color_button) - self.set_value(initial_value) - - def ontext(self, event): - if self.get_value() is None: - self.color_button.setStyleSheet("background-color:#ff0000;") - self.ctrl.setStyleSheet("background-color:#ff0000;") - else: - self.ctrl.setStyleSheet('background-color:#ffffff;') - self.color_button.setStyleSheet("background-color:%s;" % self.colorTup2Str(self.get_value())) - self.para_changed() - self.ctrl.update() - if callable(self.on_check_callback): - self.on_check_callback() - - def oncolor(self, event): - color = QColorDialog.getColor(initial=QColor(*self.get_value())) - self.set_value(self.colorStr2Tup(color.name())) - if callable(self.on_check_callback): - self.on_check_callback() - - def set_value(self, color: Tuple = None): - if color is None: - color = (255, 255, 255) - strcolor = self.colorTup2Str(color) - self.color_button.setStyleSheet('background-color:%s;' % strcolor) - self.ctrl.clear() - self.ctrl.setText(strcolor) - - def get_value(self): - rgb = self.ctrl.text().strip() - if len(rgb) != 7 or rgb[0] != '#': - return None - try: - int(rgb[1:], 16) - except: - import traceback - traceback.print_exc() - return None - return self.colorStr2Tup(rgb) - - def colorStr2Tup(self, value: str) -> tuple: # pos或者wh的输入都是tuple - def convert(c): - v = ord(c) - if (48 <= v <= 57): - return v - 48 - else: - return v - 87 # 返回a的值。 - - value = value.lower() - c0 = convert(value[1]) - c1 = convert(value[2]) - c2 = convert(value[3]) - c3 = convert(value[4]) - c4 = convert(value[5]) - c5 = convert(value[6]) - a1 = c0 * 16 + c1 - a2 = c2 * 16 + c3 - a3 = c4 * 16 + c5 - return (a1, a2, a3) - - def colorTup2Str(self, value: tuple) -> str: - if value is None: - return None - strcolor = '#' - for i in value: - strcolor += hex(int(i))[-2:].replace('x', '0') - return strcolor diff --git a/pyminer/pmgwidgets/widgets/extended/entries/evalctrl.py b/pyminer/pmgwidgets/widgets/extended/entries/evalctrl.py deleted file mode 100644 index 4bc69d7f..00000000 --- a/pyminer/pmgwidgets/widgets/extended/entries/evalctrl.py +++ /dev/null @@ -1,64 +0,0 @@ -from typing import Any - -from PySide2.QtWidgets import QLineEdit, QLabel, QHBoxLayout, QPushButton, QMessageBox -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGEvalCtrl(BaseExtendedWidget): - """ - type: - safe--can only input ',[](){}:1234567890.' - """ - - def __init__(self, layout_dir: str, title: str, initial_value: str, type='normal'): - super().__init__(layout_dir) - self.allowed_chars = set(' ,[](){}:1234567890.+-*/') - self.on_check_callback = None - self.prefix = QLabel(text=title) - self.type = type - entryLayout = QHBoxLayout() - - self.ctrl = QLineEdit() - - self.color_button = QPushButton() - self.color_button.clicked.connect(self.on_eval_test) - - self.central_layout.addWidget(self.prefix) - self.central_layout.addLayout(entryLayout) - entryLayout.addWidget(self.ctrl) - entryLayout.addWidget(self.color_button) - self.set_value(initial_value) - - def get_code(self) -> str: - text = self.ctrl.text() - if self.type == 'safe': - for char in text: - if char not in self.allowed_chars: - return None - return text - - def set_value(self, obj: Any): - try: - self.ctrl.setText(repr(obj)) - except: - import traceback - traceback.print_exc() - - def get_value(self) -> object: - if self.get_code() is not None: - try: - return eval(self.ctrl.text()) - except: - import traceback - traceback.print_exc() - return None - else: - return None - - def on_eval_test(self): - """ - 点击计算按钮,弹出对话框显示计算结果。 - :return: - """ - val = self.get_value() - QMessageBox.information(self, self.tr('Result'), repr(val), QMessageBox.Ok) diff --git a/pyminer/pmgwidgets/widgets/extended/entries/filectrl.py b/pyminer/pmgwidgets/widgets/extended/entries/filectrl.py deleted file mode 100644 index 37f0f097..00000000 --- a/pyminer/pmgwidgets/widgets/extended/entries/filectrl.py +++ /dev/null @@ -1,65 +0,0 @@ -import os -from PySide2.QtWidgets import QPushButton, QLineEdit, QLabel, QHBoxLayout, QFileDialog -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGFileCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title, initial_value: str = '', filt="All Files (*);;Text Files (*.txt)", - initial_dir: str = '', mode: str = 'open'): - super().__init__(layout_dir) - self.prefix = lab_title = QLabel(text=title) - path_layout = QHBoxLayout() - self.layout().addWidget(lab_title) - self.filter = filt - - self.ctrl = QLineEdit() - self.mode = mode - self.current_dir = initial_dir - if os.path.exists(initial_value): - self.ctrl.setText(initial_value) - self.current_dir = os.path.dirname(self.current_dir) - else: - self.current_dir = initial_dir - path_layout.addWidget(self.ctrl) - self.file_choose_button = QPushButton('..') - self.file_choose_button.clicked.connect(self.select_file) - self.file_choose_button.setMaximumWidth(30) - path_layout.addWidget(self.file_choose_button) - self.central_layout.addLayout(path_layout) - self.ctrl.textChanged.connect(self.on_text_changed) - - def select_file(self): - if self.mode == 'open': - name, ext = QFileDialog.getOpenFileName(self, self.tr("Select File"), - self.current_dir, # 起始路径 - self.filter) - elif self.mode == 'save': - name, ext = QFileDialog.getSaveFileName(self, self.tr("Save File"), self.current_dir, - self.filter) - else: - raise ValueError - if name != '': - self.ctrl.setText(name) - self.current_dir = os.path.dirname(name) - - def on_text_changed(self, event): - """ - - Args: - event: - - Returns: - - """ - # self.para_changed() - path = self.ctrl.text().strip() - if self.mode == 'open' and os.path.isfile(path): - self.signal_param_changed.emit(self.name) - elif self.mode == 'save': - self.signal_param_changed.emit(self.name) - - def set_value(self, value: str): - self.ctrl.setText(value) - - def get_value(self) -> str: - return self.ctrl.text() diff --git a/pyminer/pmgwidgets/widgets/extended/entries/folderctrl.py b/pyminer/pmgwidgets/widgets/extended/entries/folderctrl.py deleted file mode 100644 index 486c29d1..00000000 --- a/pyminer/pmgwidgets/widgets/extended/entries/folderctrl.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -from PySide2.QtWidgets import QPushButton, QLineEdit, QLabel, QHBoxLayout, QFileDialog -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGFolderCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title, initial_value: str = '', filt=None): - super().__init__(layout_dir) - self.prefix = lab_title = QLabel(text=title) - path_layout = QHBoxLayout() - path_layout.addWidget(lab_title) - - self.ctrl = QLineEdit() - self.ctrl.setText(initial_value) - path_layout.addWidget(self.ctrl) - self.file_choose_button = QPushButton('..') - self.file_choose_button.clicked.connect(self.select_file) - path_layout.addWidget(self.file_choose_button) - self.central_layout.addLayout(path_layout) - - def select_file(self): - name = QFileDialog.getExistingDirectory(self, self.tr("Select File"), - os.path.dirname(self.get_value()), # 起始路径 - ) - if name != '': - self.ctrl.setText(name) - - def ontext(self, event): - self.para_changed() - - def set_value(self, value: str): - self.ctrl.setText(value) - - def get_value(self) -> str: - return self.ctrl.text() diff --git a/pyminer/pmgwidgets/widgets/extended/entries/funcctrl.py b/pyminer/pmgwidgets/widgets/extended/entries/funcctrl.py deleted file mode 100644 index a3820c22..00000000 --- a/pyminer/pmgwidgets/widgets/extended/entries/funcctrl.py +++ /dev/null @@ -1,101 +0,0 @@ -import ast -import astunparse -from typing import Any, Tuple, List - -from PySide2.QtWidgets import QLineEdit, QLabel, QHBoxLayout, QPushButton, QMessageBox - -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class CodeVisitor(ast.NodeVisitor): - def __init__(self): - super(CodeVisitor, self).__init__() - self.preserved = {"pi", "e"} - self.called = set() - self.func_args = set() - self._names = set() - - def visit_Name(self, node: ast.Name) -> Any: - self._names.add(node.id) - - - def visit_Call(self, node: ast.Call) -> Any: - self.generic_visit(node) - self.called.add(node.func.id) - - def get_result(self) -> Tuple[List[str], List[str]]: - """ - - Returns: 定义的名称,以及调用的ID名称。 - - """ - names = self._names.copy() - names.difference_update(self.preserved) - names.difference_update(self.called) - return list(names), list(self.called) - - -# n = ast.parse("x*cos(v,sin(2*pi*x))") -# print(CodeVisitor().visit(n)) -# print(cv := CodeVisitor()) -# cv.visit(n) -# print(cv.get_result()) -# # # print(ast.get_source_segment("x*cos(v,sin(2*pi*x))",n)) -# # print(ast.dump(n)) -# # print(astunparse.unparse(n)) - - -class PMGFuncCtrl(BaseExtendedWidget): - """ - - 输入:一个有效的函数表达式。 - 其中,里面的变量名会自动进行检测。 - - """ - - def __init__(self, layout_dir: str, title: str, initial_value: str): - super().__init__(layout_dir) - self.allowed_chars = set(' ,[](){}:1234567890.+-*/') - self.on_check_callback = None - self.prefix = QLabel(text=title) - self.type = type - entryLayout = QHBoxLayout() - self.ctrl = QLineEdit() - self.central_layout.addWidget(self.prefix) - self.central_layout.addLayout(entryLayout) - entryLayout.addWidget(self.ctrl) - self.set_value(initial_value) - - def get_code(self) -> str: - text = self.ctrl.text() - if self.type == 'safe': - for char in text: - if char not in self.allowed_chars: - return None - return text - - def set_value(self, obj: Any): - try: - self.ctrl.setText(repr(obj)) - except: - import traceback - traceback.print_exc() - - def get_value(self) -> object: - if self.get_code() is not None: - try: - return eval(self.ctrl.text()) - except: - import traceback - traceback.print_exc() - return None - else: - return None - - def on_eval_test(self): - """ - 点击计算按钮,弹出对话框显示计算结果。 - :return: - """ - val = self.get_value() - QMessageBox.information(self, self.tr('Result'), repr(val), QMessageBox.Ok) diff --git a/pyminer/pmgwidgets/widgets/extended/entries/keymappingctrl.py b/pyminer/pmgwidgets/widgets/extended/entries/keymappingctrl.py deleted file mode 100644 index e2d35022..00000000 --- a/pyminer/pmgwidgets/widgets/extended/entries/keymappingctrl.py +++ /dev/null @@ -1,46 +0,0 @@ -from PySide2.QtCore import Qt -from PySide2.QtGui import QKeyEvent, QKeySequence -from PySide2.QtWidgets import QLineEdit, QLabel, QHBoxLayout -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGKeyMapCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title: str, initial_value: str): - super().__init__(layout_dir) - self.on_check_callback = None - # self.modifiers = {Qt.ControlModifier: Qt.CTRL, Qt.AltModifier: Qt.ALT, Qt.ShiftModifier: Qt.SHIFT, - # Qt.AltModifier | Qt.ControlModifier: Qt.ALT + Qt.CTRL, - # Qt.ControlModifier | Qt.ShiftModifier: Qt.SHIFT + Qt.CTRL - # } - self.modifiers = {} - self.prefix = QLabel(text=title) - - entryLayout = QHBoxLayout() - entryLayout.setContentsMargins(0, 0, 0, 0) - self.ctrl = QLineEdit() - self.ctrl.keyPressEvent = self.key_press - # self.ctrl.textChanged.connect(self.ontext) - - self.central_layout.addWidget(self.prefix) - self.central_layout.addLayout(entryLayout) - entryLayout.addWidget(self.ctrl) - self.set_value(initial_value) - - def key_press(self, event: QKeyEvent): - k = self.modifiers.get(event.modifiers()) - if k is not None: - key_seq = QKeySequence(k + event.key()) - try: - text = key_seq.toString() - self.ctrl.setText(text) - except: - import traceback - traceback.print_exc() - - def set_value(self, value: str): - # key_seq = QKeySequence(value) - # key_seq.keyBindings() - self.ctrl.setText(value) - - def get_value(self): - return self.ctrl.text() diff --git a/pyminer/pmgwidgets/widgets/extended/entries/linectrl.py b/pyminer/pmgwidgets/widgets/extended/entries/linectrl.py deleted file mode 100644 index 02f8629f..00000000 --- a/pyminer/pmgwidgets/widgets/extended/entries/linectrl.py +++ /dev/null @@ -1,33 +0,0 @@ -from PySide2.QtWidgets import QLineEdit, QLabel, QHBoxLayout -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGLineCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title: str, initial_value: str): - super().__init__(layout_dir) - self.on_check_callback = None - - self.prefix = QLabel(text=title) - - entryLayout = QHBoxLayout() - entryLayout.setContentsMargins(0, 0, 0, 0) - self.ctrl = QLineEdit() - self.ctrl.textChanged.connect(self.ontext) - - self.central_layout.addWidget(self.prefix) - self.central_layout.addLayout(entryLayout) - entryLayout.addWidget(self.ctrl) - self.set_value(initial_value) - - def param_changed(self, event): - pass - - def ontext(self, event): - self.para_changed() - - def set_value(self, text: str): - self.ctrl.clear() - self.ctrl.setText(text) - - def get_value(self) -> str: - return self.ctrl.text() diff --git a/pyminer/pmgwidgets/widgets/extended/entries/numctrl.py b/pyminer/pmgwidgets/widgets/extended/entries/numctrl.py deleted file mode 100644 index 2fea84d0..00000000 --- a/pyminer/pmgwidgets/widgets/extended/entries/numctrl.py +++ /dev/null @@ -1,73 +0,0 @@ -import math -from typing import Tuple, Union - -from PySide2.QtWidgets import QLineEdit, QLabel, QHBoxLayout - -from .baseentryctrl import PMGBaseEntryCtrl - - -class PMGNumberCtrl(PMGBaseEntryCtrl): - """ - 用于输入数值。 - """ - - def __init__(self, layout_dir: str, title: str, initial_value: Union[int, float], unit: str = '', - range: Tuple[Union[int, float], Union[int, float]] = None): - super().__init__(layout_dir=layout_dir) - self.on_check_callback = None - if range is None: - range = (float('-inf'), float('inf')) - - if isinstance(initial_value, int) and isinstance(range[0], int) and isinstance(range[1], int): - self.num_type = int - else: - self.num_type = float - - self.prefix = QLabel(text=title) - entryLayout = QHBoxLayout() - entryLayout.setContentsMargins(0, 0, 0, 0) - - self.ctrl = QLineEdit() - self.ctrl.textChanged.connect(self.ontext) - - self.postfix = QLabel(text=unit) - - self.central_layout.addWidget(self.prefix) - self.central_layout.addLayout(entryLayout) - entryLayout.addWidget(self.ctrl) - entryLayout.addWidget(self.postfix) - - self.min, self.max = range - self.accury = initial_value - self.set_value(initial_value) - - def ontext(self, event): - if self.get_value() is None: - self.set_ctrl_warning(True) - else: - self.set_ctrl_warning(False) - self.para_changed() - self.ctrl.update() - if callable(self.on_check_callback): - self.on_check_callback() - self.signal_param_changed.emit(self.name) - - def set_value(self, n): - self.ctrl.clear() - self.ctrl.setText(str(n)) - - def get_value(self): - text = self.ctrl.text() - try: - if text.lower() == "e": - return math.e - elif text.lower() == "pi": - return math.pi - num = self.num_type(text) - except ValueError: - import traceback - traceback.print_exc() - return None - if num < self.min or num > self.max: - return None - return num diff --git a/pyminer/pmgwidgets/widgets/extended/entries/passwordctrl.py b/pyminer/pmgwidgets/widgets/extended/entries/passwordctrl.py deleted file mode 100644 index 4a77f18d..00000000 --- a/pyminer/pmgwidgets/widgets/extended/entries/passwordctrl.py +++ /dev/null @@ -1,34 +0,0 @@ -from PySide2.QtWidgets import QLineEdit, QLabel, QHBoxLayout -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGPasswordCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title: str, initial_value: str): - super().__init__(layout_dir) - self.on_check_callback = None - - self.prefix = QLabel(text=title) - - entryLayout = QHBoxLayout() - entryLayout.setContentsMargins(0, 0, 0, 0) - self.ctrl = QLineEdit() - self.ctrl.setEchoMode(QLineEdit.Password) - self.ctrl.textChanged.connect(self.ontext) - - self.central_layout.addWidget(self.prefix) - self.central_layout.addLayout(entryLayout) - entryLayout.addWidget(self.ctrl) - self.set_value(initial_value) - - def param_changed(self, event): - pass - - def ontext(self, event): - self.para_changed() - - def set_value(self, text: str): - self.ctrl.clear() - self.ctrl.setText(text) - - def get_value(self) -> str: - return self.ctrl.text() diff --git a/pyminer/pmgwidgets/widgets/extended/labels/__init__.py b/pyminer/pmgwidgets/widgets/extended/labels/__init__.py deleted file mode 100644 index b6650e54..00000000 --- a/pyminer/pmgwidgets/widgets/extended/labels/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .label import PMGLabelShow \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/extended/labels/label.py b/pyminer/pmgwidgets/widgets/extended/labels/label.py deleted file mode 100644 index 0482aeba..00000000 --- a/pyminer/pmgwidgets/widgets/extended/labels/label.py +++ /dev/null @@ -1,23 +0,0 @@ -from PySide2.QtWidgets import QLabel, QVBoxLayout, QSpacerItem, QSizePolicy -from ..base import BaseExtendedWidget - - -class PMGLabelShow(BaseExtendedWidget): - def __init__(self, layout_dir: str, title: str, initial_value: str): - super().__init__(layout_dir=layout_dir) - self.on_check_callback = None - layout = QVBoxLayout() - self.prefix = QLabel(text=title) - self.ctrl = QLabel() - - self.ctrl.setStyleSheet('QLabel{font-size:20px;}') - self.central_layout.addLayout(layout) - # layout.addWidget(QLabel(' ')) - layout.addWidget(self.prefix) - layout.addWidget(self.ctrl) - # layout.addItem(QSpacerItem(20, 20, QSizePolicy.Ignored, QSizePolicy.Expanding)) - - self.set_value(initial_value) - - def set_value(self, value: str): - self.ctrl.setText(value) diff --git a/pyminer/pmgwidgets/widgets/extended/lists/__init__.py b/pyminer/pmgwidgets/widgets/extended/lists/__init__.py deleted file mode 100644 index 69b1cc78..00000000 --- a/pyminer/pmgwidgets/widgets/extended/lists/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .listwgt import PMGListCtrl diff --git a/pyminer/pmgwidgets/widgets/extended/lists/listwgt.py b/pyminer/pmgwidgets/widgets/extended/lists/listwgt.py deleted file mode 100644 index 46d14e75..00000000 --- a/pyminer/pmgwidgets/widgets/extended/lists/listwgt.py +++ /dev/null @@ -1,109 +0,0 @@ -from typing import List, Callable - -from PySide2.QtCore import Qt, QStringListModel -from PySide2.QtGui import QMouseEvent -from PySide2.QtWidgets import QLabel, QHBoxLayout, QListWidget, QVBoxLayout, QPushButton, QLineEdit -from PySide2.QtWidgets import QListWidgetItem, QCompleter - -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGListCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title: str, initial_value: List[List[str]] = None, - new_id_func: Callable = None): - super().__init__(layout_dir) - self.choices = [] - initial_value = initial_value if initial_value is not None else [[], []] - self.text_list = [] - lab_title = QLabel(text=title) - layout = QHBoxLayout() - self.central_layout.addWidget(lab_title) - self.on_check_callback = None - self.list_widget = QListWidget() - self.list_widget.mouseDoubleClickEvent = self.on_listwidget_double_cicked - # if initial_value is not None: - - self.set_value(initial_value) - layout_tools = QVBoxLayout() - self.button_add_item = QPushButton('+') - self.button_delete_item = QPushButton('-') - self.button_delete_item.clicked.connect(self.delete_row) - self.button_add_item.clicked.connect(self.add_row) - self.button_add_item.setMaximumWidth(20) - self.button_delete_item.setMaximumWidth(20) - layout_tools.addWidget(self.button_add_item) - layout_tools.addWidget(self.button_delete_item) - layout.addLayout(layout_tools) - layout.addWidget(self.list_widget) - self.central_layout.addLayout(layout) - self.data = initial_value - self.new_id_func = new_id_func - - self.text_edit = QLineEdit(parent=self.list_widget) - self.text_edit.setWindowFlags(self.text_edit.windowFlags() | Qt.Dialog | Qt.FramelessWindowHint) - self.text_edit.hide() - self.completer = QCompleter() - self.text_edit.setCompleter(self.completer) - self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) - - def set_completions(self, completions: List[str]): - """ - 设置补全内容 - Args: - completions: - - Returns: - - """ - self.completer.setModel(QStringListModel(completions)) - - def new_id(self): - if callable(self.new_id_func): - return self.new_id_func() - else: - return None - - def add_row(self): - self.data = self.get_value() - self.data[0].append(self.new_id()) - self.data[1].append('Unnamed') - self.list_widget.addItem(QListWidgetItem('Unnamed')) - - def delete_row(self): - index = self.list_widget.currentIndex().row() - self.data[0].pop(index) - self.data[1].pop(index) - self.list_widget.takeItem(index) - - def on_listwidget_double_cicked(self, evt: QMouseEvent): - print('edit', evt) - pos = evt.globalPos() - current_item: QListWidgetItem = self.list_widget.currentItem() - - def set_value(): - current_item.setText(self.text_edit.text()) - self.text_edit.hide() - self.text_edit.returnPressed.disconnect(set_value) - - item: QListWidgetItem = self.list_widget.currentItem() - - self.text_edit.setGeometry(pos.x(), pos.y(), 200, 20) - self.text_edit.returnPressed.connect(set_value) - self.text_edit.show() - # self.list_widget.editItem(item) - - def get_value(self): - text = [] - for i in range(self.list_widget.count()): - text.append(self.list_widget.item(i).text()) - self.data[1] = text - assert len(self.data[1]) == len(self.data[0]), repr(self.data) - return self.data - - def set_value(self, data: List[List[str]]): - assert isinstance(data, list), data - self.list_widget.clear() - self.list_widget.addItems(data[1]) - self.data = data - for index in range(self.list_widget.count()): - item: QListWidgetItem = self.list_widget.item(index) diff --git a/pyminer/pmgwidgets/widgets/extended/others/__init__.py b/pyminer/pmgwidgets/widgets/extended/others/__init__.py deleted file mode 100644 index 975bf08b..00000000 --- a/pyminer/pmgwidgets/widgets/extended/others/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .multitypeparaminput import PMGMultiTypeCtrl \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/extended/others/monitors/__init__.py b/pyminer/pmgwidgets/widgets/extended/others/monitors/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/widgets/extended/others/multitypeparaminput.py b/pyminer/pmgwidgets/widgets/extended/others/multitypeparaminput.py deleted file mode 100644 index 65f20666..00000000 --- a/pyminer/pmgwidgets/widgets/extended/others/multitypeparaminput.py +++ /dev/null @@ -1,103 +0,0 @@ -from typing import List, Any, Dict - -from PySide2.QtWidgets import QApplication, QRadioButton, QLayout -from PySide2.QtWidgets import QLabel - -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGMultiTypeCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title: str, initial_value: Any=None, types: List[Dict]=None): - super().__init__(layout_dir) - from pmgwidgets.widgets.composited.generalpanel import PMGPanel - self.on_check_callback = None - - self.prefix = QLabel(text=title) - - self.central_layout.addWidget(self.prefix) - - self.radio_buttons: List[QRadioButton] = [] - self.ctrls = types - radiobtn_texts = [self.ctrls[i]["type_title"] for i in range(len(self.ctrls))] - for i, ctrl in enumerate(self.ctrls): - radio_button = QRadioButton(radiobtn_texts[i]) - radio_button.toggled.connect(self.on_type_changed) - self.radio_buttons.append(radio_button) - self.central_layout.addWidget(radio_button) - - self.sub_panel = PMGPanel() - self.central_layout.addWidget(self.sub_panel) - - self.set_value(initial_value) - - def on_type_changed(self, event): - - index = self.get_type_index() - self.sub_panel.set_items([self.ctrls[index]["ctrls"]]) - - # print(self.get_value()) - # self.setFixedSize(0) - - def on_param_changed(self, event): - print(self.get_value()) - - def ontext(self, event): - self.para_changed() - - def set_type_index(self, index: int): - self.radio_buttons[index].setChecked(True) - - def get_type_index(self) -> int: - for i, btn in enumerate(self.radio_buttons): - if btn.isChecked(): - return i - - def set_value(self, value: Any): - for i, ctrl in enumerate(self.ctrls): - try: - self.set_type_index(i) - keys = list(self.sub_panel.widgets_dic.keys()) - assert len(keys) == 1 - print(i, ctrl, {keys[0]: value}) - self.sub_panel.set_value({keys[0]: value}) - break - except: - import traceback - traceback.print_exc() - - def get_value(self) -> Any: - values = self.sub_panel.get_value() - fcn = self.ctrls[self.get_type_index()].get("on_ok") - if fcn is None: - if len(list(values.keys())) == 1: - return values[list(values.keys())[0]] - else: - return values - else: - return fcn(values) - - -if __name__ == '__main__': - app = QApplication() - types = [{ - "type_title": "字符串列表", - "ctrls": [ - ("list_ctrl", "list_ctrl", 'input list of strings',), - ], - "on_ok": lambda values: values["list_ctrl"][1] - }, - { - "type_title": "字符串", - "ctrls": [ - ("line_ctrl", "aaaa", 'input a string', "Please input a string"), - ], - "on_ok": None - } - ] - - e = PMGMultiTypeCtrl("v", "aaaaaa", [[None, None, None], ["aaaaaa", "aaaaaa", "aaaaaa"]], types) - - # e.set_value([[None, None, None], ["aaaaaa", "aaaaaa", "aaaaaa"]]) - e.show() - - app.exec_() diff --git a/pyminer/pmgwidgets/widgets/extended/plots/__init__.py b/pyminer/pmgwidgets/widgets/extended/plots/__init__.py deleted file mode 100644 index 06b6e4b8..00000000 --- a/pyminer/pmgwidgets/widgets/extended/plots/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -try: - from .lines import * -except ImportError as e: - import warnings - warnings.warn(str(e)) \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/extended/plots/lines/__init__.py b/pyminer/pmgwidgets/widgets/extended/plots/lines/__init__.py deleted file mode 100644 index fb0d359c..00000000 --- a/pyminer/pmgwidgets/widgets/extended/plots/lines/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .timeseries import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/extended/plots/lines/timeseries.py b/pyminer/pmgwidgets/widgets/extended/plots/lines/timeseries.py deleted file mode 100644 index 46d576a6..00000000 --- a/pyminer/pmgwidgets/widgets/extended/plots/lines/timeseries.py +++ /dev/null @@ -1,64 +0,0 @@ -from typing import List, Dict, Tuple - -import pyqtgraph as pg -from PySide2.QtWidgets import QHBoxLayout -from pmgwidgets.widgets.extended.base import BaseExtendedWidget -from pmgwidgets import iter_isinstance, TYPE_RANGE - - -class PMGTimeSeriesShow(BaseExtendedWidget): - def __init__(self, layout_dir: str, title: str, initial_value: Dict[str, List[float]], - y_range: Tuple[int, int] = None, threshold_range: TYPE_RANGE = None, - xlabel: str = '', ylabel: str = '', - face_color: str = '#ffffff', legend_face_color: str = '#dddddd', x_range: Tuple[int, int] = None, - text_color: str = 'k'): - super().__init__(layout_dir=layout_dir) - from pmgwidgets import PMGTimeSeriesPlot - entryLayout = QHBoxLayout() - entryLayout.setContentsMargins(0, 0, 0, 0) - - self.ctrl = PMGTimeSeriesPlot(parent=None, threshold_range=threshold_range, face_color=face_color, - text_color=text_color) - self.ctrl.time_series.xlabel = xlabel - self.ctrl.time_series.ylabel = ylabel - self.ctrl.time_series.title = title - self.ctrl.time_series.x_range = x_range - self.ctrl.time_series.y_range = y_range - self.ctrl.time_series.threshold_range = threshold_range - self.ctrl.time_series.face_color = face_color - pg.setConfigOption('background', face_color) - self.ctrl.time_series.legend_face_color = legend_face_color - self.central_layout.addLayout(entryLayout) - entryLayout.addWidget(self.ctrl) - - self.accury = initial_value - if initial_value is not None: - self.set_value(initial_value) - - def set_value(self, values: Dict[str, List[float]]): - """ - {'timestamps':[...], - 'info1':{name:'unnamed','data':[...]} - } - :param values: - :return: - """ - timestamps = values['timestamps'] - values_list = [] - tags_list = [] - length = len(timestamps) - for k in values: - if k != 'timestamps': - assert len(values[k]['data']) == length, 'timestamps and datas may not be of same length!' - assert values[k].get('data') is not None - assert values[k].get('tag') is not None - values_list.append(values[k]['data']) - tags_list.append(values[k]['tag']) - self.ctrl.set_data(timestamps, values=values_list, tags=tags_list) - - def alert(self, alert_level: int): - self.ctrl.alert(alert_level) - - def set_threshold_y(self, threshold: Tuple[int, int]): - self.ctrl.time_series.y_range = threshold - self.ctrl.time_series.threshold_range = threshold diff --git a/pyminer/pmgwidgets/widgets/extended/radiobuttons/__init__.py b/pyminer/pmgwidgets/widgets/extended/radiobuttons/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/widgets/extended/radiobuttons/radiobuttonctrl.py b/pyminer/pmgwidgets/widgets/extended/radiobuttons/radiobuttonctrl.py deleted file mode 100644 index 26c8a0c8..00000000 --- a/pyminer/pmgwidgets/widgets/extended/radiobuttons/radiobuttonctrl.py +++ /dev/null @@ -1,63 +0,0 @@ -import sys -from typing import List - -from PySide2.QtWidgets import * -from PySide2.QtWidgets import QApplication -from PySide2.QtWidgets import QLabel - -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGRadioCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title: str, initial_value: str, - choices: list, texts=None): - super().__init__(layout_dir) - if texts is not None: - assert len(choices) == len(texts) - else: - texts = [str(c) for c in choices] - self.on_check_callback = None - - self.prefix = QLabel(text=title) - - # entryLayout = QHBoxLayout() - # entryLayout.setContentsMargins(0, 0, 0, 0) - # self.ctrl = QLineEdit() - # self.ctrl.textChanged.connect(self.ontext) - - # self.central_layout.addWidget(self.prefix) - # self.central_layout.addLayout(entryLayout) - # entryLayout.addWidget(self.ctrl) - self.radio_buttons: List[QRadioButton] = [] - self.choices = choices - self.texts = texts - for text in texts: - radio_button = QRadioButton(text) - radio_button.toggled.connect(self.on_param_changed) - self.radio_buttons.append(radio_button) - self.central_layout.addWidget(radio_button) - - self.set_value(initial_value) - - def on_param_changed(self, event): - if event: - self.para_changed() - - def set_value(self, value: str): - for i, c in enumerate(self.choices): - if c == value: - self.radio_buttons[i].setChecked(True) - - def get_value(self) -> str: - for i, btn in enumerate(self.radio_buttons): - if btn.isChecked(): - return self.choices[i] - raise ValueError(self.choices) - - -if __name__ == '__main__': - app = QApplication() - radioDemo = PMGRadioCtrl("v", "Radio Demo", "aaa", ["aaa", "bbb", "ccc"], ["啊啊啊", "波波波", "呲呲呲"]) - radioDemo.set_value("bbb") - radioDemo.show() - sys.exit(app.exec_()) diff --git a/pyminer/pmgwidgets/widgets/extended/spins/__init__.py b/pyminer/pmgwidgets/widgets/extended/spins/__init__.py deleted file mode 100644 index f6a43a7f..00000000 --- a/pyminer/pmgwidgets/widgets/extended/spins/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .datetime import * -from .numberspin import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/extended/spins/datetime.py b/pyminer/pmgwidgets/widgets/extended/spins/datetime.py deleted file mode 100644 index 5ee083e2..00000000 --- a/pyminer/pmgwidgets/widgets/extended/spins/datetime.py +++ /dev/null @@ -1,114 +0,0 @@ -import time -from typing import Union, Tuple - -from PySide2.QtCore import QCalendar, QDate -from PySide2.QtWidgets import QLabel, QHBoxLayout, QDateEdit -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGDateCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title, initial_date): - super().__init__(layout_dir) - self.prefix = lab_title = QLabel(text=title) - path_layout = QHBoxLayout() - path_layout.addWidget(lab_title) - - self.ctrl = QDateEdit() - path_layout.addWidget(self.ctrl) - - calendar_widget = QCalendar() - self.ctrl.setCalendar(calendar_widget) - - self.central_layout.addLayout(path_layout) - self.set_value(initial_date) - - def set_value(self, value: Union[Tuple[int, int, int], float, int]): - if isinstance(value, tuple): - assert len(value) == 3 - date = QDate(*value) - elif isinstance(value, (float, int)): - loc_time = time.localtime(value) - print(loc_time) - date = QDate(loc_time.tm_year, loc_time.tm_mon, loc_time.tm_mday) - else: - raise ValueError("value is not allowed", value) - self.ctrl.setDate(date) - - def get_value(self) -> float: - """ - 计算值 - :return: - """ - return time.mktime(self.ctrl.date().toPyDate().timetuple()) - - -class PMGDateTimeCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title, initial_date): - super().__init__(layout_dir) - self.prefix = lab_title = QLabel(text=title) - path_layout = QHBoxLayout() - path_layout.addWidget(lab_title) - - self.ctrl = QDateEdit() - path_layout.addWidget(self.ctrl) - - calendar_widget = QCalendar() - self.ctrl.setCalendar(calendar_widget) - - self.central_layout.addLayout(path_layout) - self.set_value(initial_date) - - def set_value(self, value: Union[Tuple[int, int, int], float, int]): - if isinstance(value, tuple): - assert len(value) == 3 - date = QDate(*value) - elif isinstance(value, (float, int)): - loc_time = time.localtime(value) - print(loc_time) - date = QDate(loc_time.tm_year, loc_time.tm_mon, loc_time.tm_mday) - else: - raise ValueError("value is not allowed", value) - self.ctrl.setDate(date) - - def get_value(self) -> float: - """ - 计算值 - :return: - """ - return time.mktime(self.ctrl.date().toPyDate().timetuple()) - - -class PMGTimeCtrl(BaseExtendedWidget): - def __init__(self, layout_dir: str, title, initial_date): - super().__init__(layout_dir) - self.prefix = lab_title = QLabel(text=title) - path_layout = QHBoxLayout() - path_layout.addWidget(lab_title) - - self.ctrl = QDateEdit() - path_layout.addWidget(self.ctrl) - - calendar_widget = QCalendar() - self.ctrl.setCalendar(calendar_widget) - - self.central_layout.addLayout(path_layout) - self.set_value(initial_date) - - def set_value(self, value: Union[Tuple[int, int, int], float, int]): - if isinstance(value, tuple): - assert len(value) == 3 - date = QDate(*value) - elif isinstance(value, (float, int)): - loc_time = time.localtime(value) - print(loc_time) - date = QDate(loc_time.tm_year, loc_time.tm_mon, loc_time.tm_mday) - else: - raise ValueError("value is not allowed", value) - self.ctrl.setDate(date) - - def get_value(self) -> float: - """ - 计算值 - :return: - """ - return time.mktime(self.ctrl.date().toPyDate().timetuple()) diff --git a/pyminer/pmgwidgets/widgets/extended/spins/numberspin.py b/pyminer/pmgwidgets/widgets/extended/spins/numberspin.py deleted file mode 100644 index 2900f755..00000000 --- a/pyminer/pmgwidgets/widgets/extended/spins/numberspin.py +++ /dev/null @@ -1,53 +0,0 @@ -from typing import Union, Tuple - -from PySide2.QtWidgets import QLabel, QHBoxLayout, QSpinBox, QDoubleSpinBox -from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget - - -class PMGNumberSpinCtrl(BaseExtendedWidget): - """ - 利用spinbox的控制面板,当最大值、最小值、初始值和步长均为整数的时候,类型为整数;、反之只要有任意一个是float, - 类型就是浮点数了。 - """ - - def __init__(self, layout_dir: str, title: str, initial_value: Union[int, float], unit: str = '', - val_range: Tuple[Union[float, int], Union[float, int]] = (None, None), - step: int = 1): - super().__init__(layout_dir) - self.on_check_callback = None - - self.prefix = QLabel(text=title) - entryLayout = QHBoxLayout() - entryLayout.setContentsMargins(0, 0, 0, 0) - - self.min, self.max = val_range - self.step = step - if isinstance(self.min, int) and isinstance(self.max, int) and isinstance(self.step, int) \ - and isinstance(initial_value, int): - self.ctrl = QSpinBox() - else: - self.ctrl = QDoubleSpinBox() - self.ctrl.valueChanged.connect(self.on_value_changed) - self.postfix = QLabel(text=unit) - - # self.central_layout.addWidget(self.prefix) - self.central_layout.addLayout(entryLayout) - entryLayout.addWidget(self.prefix) - entryLayout.addWidget(self.ctrl) - entryLayout.addWidget(self.postfix) - if self.min is not None: - self.ctrl.setMinimum(self.min) - if self.max is not None: - self.ctrl.setMaximum(self.max) - self.ctrl.setSingleStep(step) - self.accury = initial_value - self.set_value(initial_value) - - def set_value(self, value: Union[float, int]) -> None: - self.ctrl.setValue(value) - - def get_value(self) -> Union[int, float]: - return self.ctrl.value() - - def on_value_changed(self): - self.signal_param_changed.emit(self.name) diff --git a/pyminer/pmgwidgets/widgets/extended/tables/__init__.py b/pyminer/pmgwidgets/widgets/extended/tables/__init__.py deleted file mode 100644 index c962dad5..00000000 --- a/pyminer/pmgwidgets/widgets/extended/tables/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .tableshow import * -from .rulesctrl import PMGRuleCtrl diff --git a/pyminer/pmgwidgets/widgets/extended/tables/rulesctrl.py b/pyminer/pmgwidgets/widgets/extended/tables/rulesctrl.py deleted file mode 100644 index e68eeca4..00000000 --- a/pyminer/pmgwidgets/widgets/extended/tables/rulesctrl.py +++ /dev/null @@ -1,124 +0,0 @@ -""" -规则编辑面板 -""" -import sys -from typing import List, Union, Tuple, Dict, TYPE_CHECKING, Callable, Optional - -from PySide2.QtWidgets import QWidget, QVBoxLayout, QTableWidget, QHBoxLayout, QPushButton, QTableWidgetItem, QHeaderView -if TYPE_CHECKING: - import pandas as pd - from pmgwidgets import PANEL_VIEW_CLASS -if __name__ == '__main__': - from pmgwidgets.widgets.extended.base import BaseExtendedWidget -else: - from ..base import BaseExtendedWidget - - - -def parse_simplified_expression(identifier, title, data) -> Optional[List[Union[int, str, float, bool]]]: - """ - 解析简化版的json数据! - :param identifier: - :param data: - :param params: - :return: - """ - - if isinstance(data, bool): - return ['check_ctrl', identifier, title, data] - - elif isinstance(data, (int, float)): - - return ['numberspin_ctrl', identifier, title, data] - - elif isinstance(data, str): - return ['line_ctrl', identifier, title, data] - - else: - raise ValueError('cannot parse' + repr(data)) - - -class PMGRuleCtrl(BaseExtendedWidget): - """ - rules: - {'name':'regex', - 'text':'匹配正则表达式', - 'init':False - } - """ - - def __init__(self, layout_dir='v', title='', rules: List[Dict[str, Union[bool, int, float, str]]] = None): - super().__init__(layout_dir) - self.table_h_headers = [] - self.table_keys = [] - self.initial_values = [] - for rule in rules: - self.table_h_headers.append(rule['text']) - self.table_keys.append(rule['name']) - self.initial_values.append(rule['init']) - self.regulations_table = QTableWidget(0, len(self.table_h_headers)) - self.regulations_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - self.regulations_table.setHorizontalHeaderLabels(self.table_h_headers) - - self.layout().addWidget(self.regulations_table) - self.set_layout = QHBoxLayout() - self.layout().addLayout(self.set_layout) - self.button_add = QPushButton('Add') - self.button_remove = QPushButton('Remove') - self.set_layout.addWidget(self.button_add) - self.set_layout.addWidget(self.button_remove) - self.button_add.clicked.connect(self.add_regulation) - self.button_remove.clicked.connect(self.remove_regulation) - - def load_regulations(self, regulations: List[Dict[str, Union[int, str, float, bool]]]): - row_count = len(regulations) - self.regulations_table.setRowCount(row_count) - for i, regulation in enumerate(regulations): - l = [regulation[k] for k in self.table_keys] - for j, obj in enumerate(l): - item = QTableWidgetItem() - item.setData(0, obj) - self.regulations_table.setItem(i, j, item) - - def add_regulation(self): - rc = self.regulations_table.rowCount() - self.regulations_table.setRowCount(rc + 1) - for i, obj in enumerate(self.initial_values): - item = QTableWidgetItem() - item.setData(0, obj) - self.regulations_table.setItem(rc, i, item) - - def remove_regulation(self): - self.regulations_table.removeRow(self.regulations_table.currentRow()) - - def get_value(self) -> List[Dict]: - l = [] - for i in range(self.regulations_table.rowCount()): - dic = {} - for j in range(self.regulations_table.columnCount()): - item = self.regulations_table.item(i, j) - dic[self.table_keys[j]] = item.data(0) - l.append(dic) - return l - - def set_value(self, value): - self.load_regulations(value) - - -if __name__ == '__main__': - from PySide2.QtWidgets import QApplication - - app = QApplication([]) - rc = PMGRuleCtrl(rules=[ - {'name': 'property1', 'text': '属性1', 'init': '字符串属性'}, - {'name': 'property2', 'text': '属性2', 'init': True}, - {'name': 'property3', 'text': '属性3', 'init': False}, - {'name': 'property4', 'text': '属性4', 'init': 0}, - ]) - rc.show() - rc.set_value([ - {'property1': 'aaa', 'property2': False, 'property3': True, 'property4': 1}, - {'property1': 'whatif', 'property2': False, 'property3': False, 'property4': 12} - ]) - print(rc.get_value()) - app.exec_() diff --git a/pyminer/pmgwidgets/widgets/extended/tables/tableshow.py b/pyminer/pmgwidgets/widgets/extended/tables/tableshow.py deleted file mode 100644 index 2ca2303e..00000000 --- a/pyminer/pmgwidgets/widgets/extended/tables/tableshow.py +++ /dev/null @@ -1,119 +0,0 @@ -from typing import List, Union - -from PySide2.QtCore import Qt -from PySide2.QtGui import QBrush, QColor -from PySide2.QtWidgets import QHBoxLayout, QTableWidget, QTableWidgetItem, QHeaderView -from ..base import BaseExtendedWidget -from pmgwidgets.utilities import color_str2tup - - -class PMGTableShow(BaseExtendedWidget): - default_bg = QTableWidgetItem().background() - default_fg = QTableWidgetItem().foreground() - - def __init__(self, layout_dir: str, title: List[str], - initial_value: List[List[Union[int, float, str]]], - size_restricted=False, header_adaption_h=False, header_adaption_v=False, - background_color: List[List[Union[str]]] = None, - foreground_color: List[List[Union[str]]] = None): - super().__init__(layout_dir=layout_dir) - - self.maximum_rows = 100 - self.size_restricted = size_restricted - self.header_adaption_h = header_adaption_h - self.header_adaption_v = header_adaption_v - self.background_color = background_color if background_color is not None else '' - self.foreground_color = foreground_color if foreground_color is not None else '' - self.char_width = 15 - self.on_check_callback = None - self.title_list = title - entryLayout = QHBoxLayout() - entryLayout.setContentsMargins(0, 0, 0, 0) - - self.ctrl = QTableWidget() - self.ctrl.verticalHeader().setVisible(False) - self.set_params(size_restricted, header_adaption_h, header_adaption_v) - self.ctrl.setColumnCount(len(title)) - - self.ctrl.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) - for i, text in enumerate(title): - self.ctrl.setColumnWidth(i, len(text) * self.char_width + 10) - self.ctrl.setHorizontalHeaderItem(i, QTableWidgetItem(text)) - - self.central_layout.addLayout(entryLayout) - entryLayout.addWidget(self.ctrl) - - if initial_value is not None: - for sublist in initial_value: - assert len(sublist) == len(title), \ - 'title is not as long as sublist,%s,%s' % (repr(title), sublist) - self.ctrl.setRowCount(len(initial_value)) - self.set_value(initial_value) - - def set_params(self, size_restricted=False, header_adaption_h=False, header_adaption_v=False): - self.size_restricted = size_restricted - self.header_adaption_h = header_adaption_h - self.header_adaption_v = header_adaption_v - if header_adaption_h: - self.ctrl.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - if header_adaption_v: - self.ctrl.verticalHeader().setSectionResizeMode(QHeaderView.Stretch) - - def check_data(self, value: List[List[Union[int, float, str]]]): - for sublist in value: - assert len(sublist) == len(self.title_list),\ - '%s,%s' % (repr(sublist), repr(self.title_list)) - - def set_value(self, value: List[List[Union[int, float, str]]]): - self.check_data(value) - self.ctrl.setRowCount(len(value)) - cols = len(value[0]) - if isinstance(self.foreground_color, str): - fg = [[self.foreground_color for i in range(cols)] for j in range(len(value))] - - else: - fg = self.foreground_color - if isinstance(self.background_color, str): - bg = [[self.background_color for i in range(cols)] for j in range(len(value))] - else: - bg = self.background_color - for row, row_list in enumerate(value): - for col, content in enumerate(row_list): - if len(str(content)) * self.char_width > self.ctrl.columnWidth(col): - self.ctrl.setColumnWidth(col, len(str(content)) * self.char_width + 10) - table_item = QTableWidgetItem(str(content)) - table_item.setTextAlignment(Qt.AlignCenter) - # 字体颜色(红色) - if fg[row][col] == '': - table_item.setForeground(self.default_fg) - else: - table_item.setForeground(QBrush(QColor(*color_str2tup(fg[row][col])))) - - # 背景颜色(红色) - if bg[row][col] == '': - table_item.setBackground(self.default_bg) - else: - table_item.setBackground(QBrush(QColor(*color_str2tup(bg[row][col])))) - self.ctrl.setItem(row, col, table_item) - - if self.size_restricted: - if self.header_adaption_h: - self.ctrl.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - scrollbar_area_width = 0 - else: - self.ctrl.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) - scrollbar_area_width = 10 - self.ctrl.setMaximumHeight((self.ctrl.rowCount() + 1) * 30 + scrollbar_area_width) - self.setMaximumHeight((self.ctrl.rowCount() + 1) * 30 + scrollbar_area_width) - - def alert(self, alert_level: int): - self.ctrl.alert(alert_level) - - def add_row(self, row: List): - assert len(row) == self.ctrl.columnCount() - rc = self.ctrl.rowCount() - self.ctrl.setRowCount(rc + 1) - for i, val in enumerate(row): - self.ctrl.setItem(rc, i, QTableWidgetItem(str(val))) - if self.ctrl.rowCount() > self.maximum_rows: - self.ctrl.removeRow(0) diff --git a/pyminer/pmgwidgets/widgets/extended/texts/__init__.py b/pyminer/pmgwidgets/widgets/extended/texts/__init__.py deleted file mode 100644 index 6fa30ac8..00000000 --- a/pyminer/pmgwidgets/widgets/extended/texts/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .htmlshow import * -from .markdownshow import * \ No newline at end of file diff --git a/pyminer/pmgwidgets/widgets/extended/texts/htmlshow.py b/pyminer/pmgwidgets/widgets/extended/texts/htmlshow.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/widgets/extended/texts/markdownshow.py b/pyminer/pmgwidgets/widgets/extended/texts/markdownshow.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pmgwidgets/widgets/extended/trees/__init__.py b/pyminer/pmgwidgets/widgets/extended/trees/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyminer/pyminer.pro b/pyminer/pyminer.pro index 8dd4d3e5..fbc4233c 100644 --- a/pyminer/pyminer.pro +++ b/pyminer/pyminer.pro @@ -1,18 +1,18 @@ SOURCES = app2.py \ pyminer.py \ pmgui.py \ - check_dependency.py \ - features/base.py\ + lib/check_dependency.py \ + lib/base.py\ -FORMS = features/ui/base/aboutMe.ui \ - features/ui/base/first_form.ui\ - features/ui/base/option.ui \ - features/ui/base/project_wizard.ui\ - features/ui/base/pm_marketplace/main.ui\ - features/ui/base/pm_marketplace/install.ui\ - features/ui/base/pm_marketplace/uninstall.ui\ - features/ui/base/pm_marketplace/package_manager_main.ui\ +FORMS = lib/ui/base/aboutMe.ui \ + lib/ui/base/first_form.ui\ + lib/ui/base/option.ui \ + lib/ui/base/project_wizard.ui\ + lib/ui/base/pm_marketplace/main.ui\ + lib/ui/base/pm_marketplace/install.ui\ + lib/ui/base/pm_marketplace/uninstall.ui\ + lib/ui/base/pm_marketplace/package_manager_main.ui\ TRANSLATIONS = languages/en/en.ts \ languages/zh_CN/zh_CN.ts \ diff --git a/pyminer/pyminer_comm/data_client/__init__.py b/pyminer/pyminer_comm/data_client/__init__.py deleted file mode 100644 index 9c75ed72..00000000 --- a/pyminer/pyminer_comm/data_client/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from pyminer_comm.data_client.data_client import set_vars, get_vars, get_var_names, shm_get_vars, \ - set_vars, shm_set_vars, del_vars, del_var, set_var, get_var, get_data_descs diff --git a/pyminer/resources/README.md b/pyminer/resources/README.md new file mode 100644 index 00000000..135d89b4 --- /dev/null +++ b/pyminer/resources/README.md @@ -0,0 +1 @@ +resources文件夹下是项目用到的资源文件,包含网页模板等。 \ No newline at end of file diff --git a/pyminer/static/css/iview.min.css b/pyminer/resources/css/iview.min.css similarity index 100% rename from pyminer/static/css/iview.min.css rename to pyminer/resources/css/iview.min.css diff --git a/pyminer/static/js/echarts.min.js b/pyminer/resources/js/echarts.min.js similarity index 100% rename from pyminer/static/js/echarts.min.js rename to pyminer/resources/js/echarts.min.js diff --git a/pyminer/static/js/element-ui/CHANGELOG.en-US.md b/pyminer/resources/js/element-ui/CHANGELOG.en-US.md similarity index 100% rename from pyminer/static/js/element-ui/CHANGELOG.en-US.md rename to pyminer/resources/js/element-ui/CHANGELOG.en-US.md diff --git a/pyminer/static/js/element-ui/CHANGELOG.es.md b/pyminer/resources/js/element-ui/CHANGELOG.es.md similarity index 100% rename from pyminer/static/js/element-ui/CHANGELOG.es.md rename to pyminer/resources/js/element-ui/CHANGELOG.es.md diff --git a/pyminer/static/js/element-ui/CHANGELOG.fr-FR.md b/pyminer/resources/js/element-ui/CHANGELOG.fr-FR.md similarity index 100% rename from pyminer/static/js/element-ui/CHANGELOG.fr-FR.md rename to pyminer/resources/js/element-ui/CHANGELOG.fr-FR.md diff --git a/pyminer/static/js/element-ui/CHANGELOG.zh-CN.md b/pyminer/resources/js/element-ui/CHANGELOG.zh-CN.md similarity index 100% rename from pyminer/static/js/element-ui/CHANGELOG.zh-CN.md rename to pyminer/resources/js/element-ui/CHANGELOG.zh-CN.md diff --git a/pyminer/static/js/element-ui/README.md b/pyminer/resources/js/element-ui/README.md similarity index 100% rename from pyminer/static/js/element-ui/README.md rename to pyminer/resources/js/element-ui/README.md diff --git a/pyminer/static/js/element-ui/lib/alert.js b/pyminer/resources/js/element-ui/lib/alert.js similarity index 100% rename from pyminer/static/js/element-ui/lib/alert.js rename to pyminer/resources/js/element-ui/lib/alert.js diff --git a/pyminer/static/js/element-ui/lib/aside.js b/pyminer/resources/js/element-ui/lib/aside.js similarity index 100% rename from pyminer/static/js/element-ui/lib/aside.js rename to pyminer/resources/js/element-ui/lib/aside.js diff --git a/pyminer/static/js/element-ui/lib/autocomplete.js b/pyminer/resources/js/element-ui/lib/autocomplete.js similarity index 100% rename from pyminer/static/js/element-ui/lib/autocomplete.js rename to pyminer/resources/js/element-ui/lib/autocomplete.js diff --git a/pyminer/static/js/element-ui/lib/avatar.js b/pyminer/resources/js/element-ui/lib/avatar.js similarity index 100% rename from pyminer/static/js/element-ui/lib/avatar.js rename to pyminer/resources/js/element-ui/lib/avatar.js diff --git a/pyminer/static/js/element-ui/lib/backtop.js b/pyminer/resources/js/element-ui/lib/backtop.js similarity index 100% rename from pyminer/static/js/element-ui/lib/backtop.js rename to pyminer/resources/js/element-ui/lib/backtop.js diff --git a/pyminer/static/js/element-ui/lib/badge.js b/pyminer/resources/js/element-ui/lib/badge.js similarity index 100% rename from pyminer/static/js/element-ui/lib/badge.js rename to pyminer/resources/js/element-ui/lib/badge.js diff --git a/pyminer/static/js/element-ui/lib/breadcrumb-item.js b/pyminer/resources/js/element-ui/lib/breadcrumb-item.js similarity index 100% rename from pyminer/static/js/element-ui/lib/breadcrumb-item.js rename to pyminer/resources/js/element-ui/lib/breadcrumb-item.js diff --git a/pyminer/static/js/element-ui/lib/breadcrumb.js b/pyminer/resources/js/element-ui/lib/breadcrumb.js similarity index 100% rename from pyminer/static/js/element-ui/lib/breadcrumb.js rename to pyminer/resources/js/element-ui/lib/breadcrumb.js diff --git a/pyminer/static/js/element-ui/lib/button-group.js b/pyminer/resources/js/element-ui/lib/button-group.js similarity index 100% rename from pyminer/static/js/element-ui/lib/button-group.js rename to pyminer/resources/js/element-ui/lib/button-group.js diff --git a/pyminer/static/js/element-ui/lib/button.js b/pyminer/resources/js/element-ui/lib/button.js similarity index 100% rename from pyminer/static/js/element-ui/lib/button.js rename to pyminer/resources/js/element-ui/lib/button.js diff --git a/pyminer/static/js/element-ui/lib/calendar.js b/pyminer/resources/js/element-ui/lib/calendar.js similarity index 100% rename from pyminer/static/js/element-ui/lib/calendar.js rename to pyminer/resources/js/element-ui/lib/calendar.js diff --git a/pyminer/static/js/element-ui/lib/card.js b/pyminer/resources/js/element-ui/lib/card.js similarity index 100% rename from pyminer/static/js/element-ui/lib/card.js rename to pyminer/resources/js/element-ui/lib/card.js diff --git a/pyminer/static/js/element-ui/lib/carousel-item.js b/pyminer/resources/js/element-ui/lib/carousel-item.js similarity index 100% rename from pyminer/static/js/element-ui/lib/carousel-item.js rename to pyminer/resources/js/element-ui/lib/carousel-item.js diff --git a/pyminer/static/js/element-ui/lib/carousel.js b/pyminer/resources/js/element-ui/lib/carousel.js similarity index 100% rename from pyminer/static/js/element-ui/lib/carousel.js rename to pyminer/resources/js/element-ui/lib/carousel.js diff --git a/pyminer/static/js/element-ui/lib/cascader-panel.js b/pyminer/resources/js/element-ui/lib/cascader-panel.js similarity index 100% rename from pyminer/static/js/element-ui/lib/cascader-panel.js rename to pyminer/resources/js/element-ui/lib/cascader-panel.js diff --git a/pyminer/static/js/element-ui/lib/cascader.js b/pyminer/resources/js/element-ui/lib/cascader.js similarity index 100% rename from pyminer/static/js/element-ui/lib/cascader.js rename to pyminer/resources/js/element-ui/lib/cascader.js diff --git a/pyminer/static/js/element-ui/lib/checkbox-button.js b/pyminer/resources/js/element-ui/lib/checkbox-button.js similarity index 100% rename from pyminer/static/js/element-ui/lib/checkbox-button.js rename to pyminer/resources/js/element-ui/lib/checkbox-button.js diff --git a/pyminer/static/js/element-ui/lib/checkbox-group.js b/pyminer/resources/js/element-ui/lib/checkbox-group.js similarity index 100% rename from pyminer/static/js/element-ui/lib/checkbox-group.js rename to pyminer/resources/js/element-ui/lib/checkbox-group.js diff --git a/pyminer/static/js/element-ui/lib/checkbox.js b/pyminer/resources/js/element-ui/lib/checkbox.js similarity index 100% rename from pyminer/static/js/element-ui/lib/checkbox.js rename to pyminer/resources/js/element-ui/lib/checkbox.js diff --git a/pyminer/static/js/element-ui/lib/col.js b/pyminer/resources/js/element-ui/lib/col.js similarity index 100% rename from pyminer/static/js/element-ui/lib/col.js rename to pyminer/resources/js/element-ui/lib/col.js diff --git a/pyminer/static/js/element-ui/lib/collapse-item.js b/pyminer/resources/js/element-ui/lib/collapse-item.js similarity index 100% rename from pyminer/static/js/element-ui/lib/collapse-item.js rename to pyminer/resources/js/element-ui/lib/collapse-item.js diff --git a/pyminer/static/js/element-ui/lib/collapse.js b/pyminer/resources/js/element-ui/lib/collapse.js similarity index 100% rename from pyminer/static/js/element-ui/lib/collapse.js rename to pyminer/resources/js/element-ui/lib/collapse.js diff --git a/pyminer/static/js/element-ui/lib/color-picker.js b/pyminer/resources/js/element-ui/lib/color-picker.js similarity index 100% rename from pyminer/static/js/element-ui/lib/color-picker.js rename to pyminer/resources/js/element-ui/lib/color-picker.js diff --git a/pyminer/static/js/element-ui/lib/container.js b/pyminer/resources/js/element-ui/lib/container.js similarity index 100% rename from pyminer/static/js/element-ui/lib/container.js rename to pyminer/resources/js/element-ui/lib/container.js diff --git a/pyminer/static/js/element-ui/lib/date-picker.js b/pyminer/resources/js/element-ui/lib/date-picker.js similarity index 100% rename from pyminer/static/js/element-ui/lib/date-picker.js rename to pyminer/resources/js/element-ui/lib/date-picker.js diff --git a/pyminer/static/js/element-ui/lib/dialog.js b/pyminer/resources/js/element-ui/lib/dialog.js similarity index 100% rename from pyminer/static/js/element-ui/lib/dialog.js rename to pyminer/resources/js/element-ui/lib/dialog.js diff --git a/pyminer/static/js/element-ui/lib/directives/mousewheel.js b/pyminer/resources/js/element-ui/lib/directives/mousewheel.js similarity index 100% rename from pyminer/static/js/element-ui/lib/directives/mousewheel.js rename to pyminer/resources/js/element-ui/lib/directives/mousewheel.js diff --git a/pyminer/static/js/element-ui/lib/directives/repeat-click.js b/pyminer/resources/js/element-ui/lib/directives/repeat-click.js similarity index 100% rename from pyminer/static/js/element-ui/lib/directives/repeat-click.js rename to pyminer/resources/js/element-ui/lib/directives/repeat-click.js diff --git a/pyminer/static/js/element-ui/lib/divider.js b/pyminer/resources/js/element-ui/lib/divider.js similarity index 100% rename from pyminer/static/js/element-ui/lib/divider.js rename to pyminer/resources/js/element-ui/lib/divider.js diff --git a/pyminer/static/js/element-ui/lib/drawer.js b/pyminer/resources/js/element-ui/lib/drawer.js similarity index 100% rename from pyminer/static/js/element-ui/lib/drawer.js rename to pyminer/resources/js/element-ui/lib/drawer.js diff --git a/pyminer/static/js/element-ui/lib/dropdown-item.js b/pyminer/resources/js/element-ui/lib/dropdown-item.js similarity index 100% rename from pyminer/static/js/element-ui/lib/dropdown-item.js rename to pyminer/resources/js/element-ui/lib/dropdown-item.js diff --git a/pyminer/static/js/element-ui/lib/dropdown-menu.js b/pyminer/resources/js/element-ui/lib/dropdown-menu.js similarity index 100% rename from pyminer/static/js/element-ui/lib/dropdown-menu.js rename to pyminer/resources/js/element-ui/lib/dropdown-menu.js diff --git a/pyminer/static/js/element-ui/lib/dropdown.js b/pyminer/resources/js/element-ui/lib/dropdown.js similarity index 100% rename from pyminer/static/js/element-ui/lib/dropdown.js rename to pyminer/resources/js/element-ui/lib/dropdown.js diff --git a/pyminer/static/js/element-ui/lib/element-ui.common.js b/pyminer/resources/js/element-ui/lib/element-ui.common.js similarity index 100% rename from pyminer/static/js/element-ui/lib/element-ui.common.js rename to pyminer/resources/js/element-ui/lib/element-ui.common.js diff --git a/pyminer/static/js/element-ui/lib/footer.js b/pyminer/resources/js/element-ui/lib/footer.js similarity index 100% rename from pyminer/static/js/element-ui/lib/footer.js rename to pyminer/resources/js/element-ui/lib/footer.js diff --git a/pyminer/static/js/element-ui/lib/form-item.js b/pyminer/resources/js/element-ui/lib/form-item.js similarity index 100% rename from pyminer/static/js/element-ui/lib/form-item.js rename to pyminer/resources/js/element-ui/lib/form-item.js diff --git a/pyminer/static/js/element-ui/lib/form.js b/pyminer/resources/js/element-ui/lib/form.js similarity index 100% rename from pyminer/static/js/element-ui/lib/form.js rename to pyminer/resources/js/element-ui/lib/form.js diff --git a/pyminer/static/js/element-ui/lib/header.js b/pyminer/resources/js/element-ui/lib/header.js similarity index 100% rename from pyminer/static/js/element-ui/lib/header.js rename to pyminer/resources/js/element-ui/lib/header.js diff --git a/pyminer/static/js/element-ui/lib/icon.js b/pyminer/resources/js/element-ui/lib/icon.js similarity index 100% rename from pyminer/static/js/element-ui/lib/icon.js rename to pyminer/resources/js/element-ui/lib/icon.js diff --git a/pyminer/static/js/element-ui/lib/image.js b/pyminer/resources/js/element-ui/lib/image.js similarity index 100% rename from pyminer/static/js/element-ui/lib/image.js rename to pyminer/resources/js/element-ui/lib/image.js diff --git a/pyminer/static/js/element-ui/lib/index.js b/pyminer/resources/js/element-ui/lib/index.js similarity index 100% rename from pyminer/static/js/element-ui/lib/index.js rename to pyminer/resources/js/element-ui/lib/index.js diff --git a/pyminer/static/js/element-ui/lib/infinite-scroll.js b/pyminer/resources/js/element-ui/lib/infinite-scroll.js similarity index 100% rename from pyminer/static/js/element-ui/lib/infinite-scroll.js rename to pyminer/resources/js/element-ui/lib/infinite-scroll.js diff --git a/pyminer/static/js/element-ui/lib/input-number.js b/pyminer/resources/js/element-ui/lib/input-number.js similarity index 100% rename from pyminer/static/js/element-ui/lib/input-number.js rename to pyminer/resources/js/element-ui/lib/input-number.js diff --git a/pyminer/static/js/element-ui/lib/input.js b/pyminer/resources/js/element-ui/lib/input.js similarity index 100% rename from pyminer/static/js/element-ui/lib/input.js rename to pyminer/resources/js/element-ui/lib/input.js diff --git a/pyminer/static/js/element-ui/lib/link.js b/pyminer/resources/js/element-ui/lib/link.js similarity index 100% rename from pyminer/static/js/element-ui/lib/link.js rename to pyminer/resources/js/element-ui/lib/link.js diff --git a/pyminer/static/js/element-ui/lib/loading.js b/pyminer/resources/js/element-ui/lib/loading.js similarity index 100% rename from pyminer/static/js/element-ui/lib/loading.js rename to pyminer/resources/js/element-ui/lib/loading.js diff --git a/pyminer/static/js/element-ui/lib/locale/format.js b/pyminer/resources/js/element-ui/lib/locale/format.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/format.js rename to pyminer/resources/js/element-ui/lib/locale/format.js diff --git a/pyminer/static/js/element-ui/lib/locale/index.js b/pyminer/resources/js/element-ui/lib/locale/index.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/index.js rename to pyminer/resources/js/element-ui/lib/locale/index.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/af-ZA.js b/pyminer/resources/js/element-ui/lib/locale/lang/af-ZA.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/af-ZA.js rename to pyminer/resources/js/element-ui/lib/locale/lang/af-ZA.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/ar.js b/pyminer/resources/js/element-ui/lib/locale/lang/ar.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/ar.js rename to pyminer/resources/js/element-ui/lib/locale/lang/ar.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/bg.js b/pyminer/resources/js/element-ui/lib/locale/lang/bg.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/bg.js rename to pyminer/resources/js/element-ui/lib/locale/lang/bg.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/ca.js b/pyminer/resources/js/element-ui/lib/locale/lang/ca.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/ca.js rename to pyminer/resources/js/element-ui/lib/locale/lang/ca.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/cs-CZ.js b/pyminer/resources/js/element-ui/lib/locale/lang/cs-CZ.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/cs-CZ.js rename to pyminer/resources/js/element-ui/lib/locale/lang/cs-CZ.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/da.js b/pyminer/resources/js/element-ui/lib/locale/lang/da.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/da.js rename to pyminer/resources/js/element-ui/lib/locale/lang/da.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/de.js b/pyminer/resources/js/element-ui/lib/locale/lang/de.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/de.js rename to pyminer/resources/js/element-ui/lib/locale/lang/de.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/ee.js b/pyminer/resources/js/element-ui/lib/locale/lang/ee.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/ee.js rename to pyminer/resources/js/element-ui/lib/locale/lang/ee.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/el.js b/pyminer/resources/js/element-ui/lib/locale/lang/el.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/el.js rename to pyminer/resources/js/element-ui/lib/locale/lang/el.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/en.js b/pyminer/resources/js/element-ui/lib/locale/lang/en.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/en.js rename to pyminer/resources/js/element-ui/lib/locale/lang/en.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/eo.js b/pyminer/resources/js/element-ui/lib/locale/lang/eo.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/eo.js rename to pyminer/resources/js/element-ui/lib/locale/lang/eo.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/es.js b/pyminer/resources/js/element-ui/lib/locale/lang/es.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/es.js rename to pyminer/resources/js/element-ui/lib/locale/lang/es.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/eu.js b/pyminer/resources/js/element-ui/lib/locale/lang/eu.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/eu.js rename to pyminer/resources/js/element-ui/lib/locale/lang/eu.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/fa.js b/pyminer/resources/js/element-ui/lib/locale/lang/fa.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/fa.js rename to pyminer/resources/js/element-ui/lib/locale/lang/fa.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/fi.js b/pyminer/resources/js/element-ui/lib/locale/lang/fi.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/fi.js rename to pyminer/resources/js/element-ui/lib/locale/lang/fi.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/fr.js b/pyminer/resources/js/element-ui/lib/locale/lang/fr.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/fr.js rename to pyminer/resources/js/element-ui/lib/locale/lang/fr.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/he.js b/pyminer/resources/js/element-ui/lib/locale/lang/he.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/he.js rename to pyminer/resources/js/element-ui/lib/locale/lang/he.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/hr.js b/pyminer/resources/js/element-ui/lib/locale/lang/hr.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/hr.js rename to pyminer/resources/js/element-ui/lib/locale/lang/hr.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/hu.js b/pyminer/resources/js/element-ui/lib/locale/lang/hu.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/hu.js rename to pyminer/resources/js/element-ui/lib/locale/lang/hu.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/hy-AM.js b/pyminer/resources/js/element-ui/lib/locale/lang/hy-AM.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/hy-AM.js rename to pyminer/resources/js/element-ui/lib/locale/lang/hy-AM.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/id.js b/pyminer/resources/js/element-ui/lib/locale/lang/id.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/id.js rename to pyminer/resources/js/element-ui/lib/locale/lang/id.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/it.js b/pyminer/resources/js/element-ui/lib/locale/lang/it.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/it.js rename to pyminer/resources/js/element-ui/lib/locale/lang/it.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/ja.js b/pyminer/resources/js/element-ui/lib/locale/lang/ja.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/ja.js rename to pyminer/resources/js/element-ui/lib/locale/lang/ja.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/kg.js b/pyminer/resources/js/element-ui/lib/locale/lang/kg.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/kg.js rename to pyminer/resources/js/element-ui/lib/locale/lang/kg.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/km.js b/pyminer/resources/js/element-ui/lib/locale/lang/km.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/km.js rename to pyminer/resources/js/element-ui/lib/locale/lang/km.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/ko.js b/pyminer/resources/js/element-ui/lib/locale/lang/ko.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/ko.js rename to pyminer/resources/js/element-ui/lib/locale/lang/ko.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/ku.js b/pyminer/resources/js/element-ui/lib/locale/lang/ku.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/ku.js rename to pyminer/resources/js/element-ui/lib/locale/lang/ku.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/kz.js b/pyminer/resources/js/element-ui/lib/locale/lang/kz.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/kz.js rename to pyminer/resources/js/element-ui/lib/locale/lang/kz.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/lt.js b/pyminer/resources/js/element-ui/lib/locale/lang/lt.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/lt.js rename to pyminer/resources/js/element-ui/lib/locale/lang/lt.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/lv.js b/pyminer/resources/js/element-ui/lib/locale/lang/lv.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/lv.js rename to pyminer/resources/js/element-ui/lib/locale/lang/lv.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/mn.js b/pyminer/resources/js/element-ui/lib/locale/lang/mn.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/mn.js rename to pyminer/resources/js/element-ui/lib/locale/lang/mn.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/nb-NO.js b/pyminer/resources/js/element-ui/lib/locale/lang/nb-NO.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/nb-NO.js rename to pyminer/resources/js/element-ui/lib/locale/lang/nb-NO.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/nl.js b/pyminer/resources/js/element-ui/lib/locale/lang/nl.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/nl.js rename to pyminer/resources/js/element-ui/lib/locale/lang/nl.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/pl.js b/pyminer/resources/js/element-ui/lib/locale/lang/pl.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/pl.js rename to pyminer/resources/js/element-ui/lib/locale/lang/pl.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/pt-br.js b/pyminer/resources/js/element-ui/lib/locale/lang/pt-br.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/pt-br.js rename to pyminer/resources/js/element-ui/lib/locale/lang/pt-br.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/pt.js b/pyminer/resources/js/element-ui/lib/locale/lang/pt.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/pt.js rename to pyminer/resources/js/element-ui/lib/locale/lang/pt.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/ro.js b/pyminer/resources/js/element-ui/lib/locale/lang/ro.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/ro.js rename to pyminer/resources/js/element-ui/lib/locale/lang/ro.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/ru-RU.js b/pyminer/resources/js/element-ui/lib/locale/lang/ru-RU.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/ru-RU.js rename to pyminer/resources/js/element-ui/lib/locale/lang/ru-RU.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/sk.js b/pyminer/resources/js/element-ui/lib/locale/lang/sk.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/sk.js rename to pyminer/resources/js/element-ui/lib/locale/lang/sk.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/sl.js b/pyminer/resources/js/element-ui/lib/locale/lang/sl.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/sl.js rename to pyminer/resources/js/element-ui/lib/locale/lang/sl.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/sr.js b/pyminer/resources/js/element-ui/lib/locale/lang/sr.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/sr.js rename to pyminer/resources/js/element-ui/lib/locale/lang/sr.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/sv-SE.js b/pyminer/resources/js/element-ui/lib/locale/lang/sv-SE.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/sv-SE.js rename to pyminer/resources/js/element-ui/lib/locale/lang/sv-SE.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/ta.js b/pyminer/resources/js/element-ui/lib/locale/lang/ta.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/ta.js rename to pyminer/resources/js/element-ui/lib/locale/lang/ta.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/th.js b/pyminer/resources/js/element-ui/lib/locale/lang/th.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/th.js rename to pyminer/resources/js/element-ui/lib/locale/lang/th.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/tk.js b/pyminer/resources/js/element-ui/lib/locale/lang/tk.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/tk.js rename to pyminer/resources/js/element-ui/lib/locale/lang/tk.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/tr-TR.js b/pyminer/resources/js/element-ui/lib/locale/lang/tr-TR.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/tr-TR.js rename to pyminer/resources/js/element-ui/lib/locale/lang/tr-TR.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/ua.js b/pyminer/resources/js/element-ui/lib/locale/lang/ua.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/ua.js rename to pyminer/resources/js/element-ui/lib/locale/lang/ua.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/ug-CN.js b/pyminer/resources/js/element-ui/lib/locale/lang/ug-CN.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/ug-CN.js rename to pyminer/resources/js/element-ui/lib/locale/lang/ug-CN.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/uz-UZ.js b/pyminer/resources/js/element-ui/lib/locale/lang/uz-UZ.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/uz-UZ.js rename to pyminer/resources/js/element-ui/lib/locale/lang/uz-UZ.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/vi.js b/pyminer/resources/js/element-ui/lib/locale/lang/vi.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/vi.js rename to pyminer/resources/js/element-ui/lib/locale/lang/vi.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/zh-CN.js b/pyminer/resources/js/element-ui/lib/locale/lang/zh-CN.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/zh-CN.js rename to pyminer/resources/js/element-ui/lib/locale/lang/zh-CN.js diff --git a/pyminer/static/js/element-ui/lib/locale/lang/zh-TW.js b/pyminer/resources/js/element-ui/lib/locale/lang/zh-TW.js similarity index 100% rename from pyminer/static/js/element-ui/lib/locale/lang/zh-TW.js rename to pyminer/resources/js/element-ui/lib/locale/lang/zh-TW.js diff --git a/pyminer/static/js/element-ui/lib/main.js b/pyminer/resources/js/element-ui/lib/main.js similarity index 100% rename from pyminer/static/js/element-ui/lib/main.js rename to pyminer/resources/js/element-ui/lib/main.js diff --git a/pyminer/static/js/element-ui/lib/menu-item-group.js b/pyminer/resources/js/element-ui/lib/menu-item-group.js similarity index 100% rename from pyminer/static/js/element-ui/lib/menu-item-group.js rename to pyminer/resources/js/element-ui/lib/menu-item-group.js diff --git a/pyminer/static/js/element-ui/lib/menu-item.js b/pyminer/resources/js/element-ui/lib/menu-item.js similarity index 100% rename from pyminer/static/js/element-ui/lib/menu-item.js rename to pyminer/resources/js/element-ui/lib/menu-item.js diff --git a/pyminer/static/js/element-ui/lib/menu.js b/pyminer/resources/js/element-ui/lib/menu.js similarity index 100% rename from pyminer/static/js/element-ui/lib/menu.js rename to pyminer/resources/js/element-ui/lib/menu.js diff --git a/pyminer/static/js/element-ui/lib/message-box.js b/pyminer/resources/js/element-ui/lib/message-box.js similarity index 100% rename from pyminer/static/js/element-ui/lib/message-box.js rename to pyminer/resources/js/element-ui/lib/message-box.js diff --git a/pyminer/static/js/element-ui/lib/message.js b/pyminer/resources/js/element-ui/lib/message.js similarity index 100% rename from pyminer/static/js/element-ui/lib/message.js rename to pyminer/resources/js/element-ui/lib/message.js diff --git a/pyminer/static/js/element-ui/lib/mixins/emitter.js b/pyminer/resources/js/element-ui/lib/mixins/emitter.js similarity index 100% rename from pyminer/static/js/element-ui/lib/mixins/emitter.js rename to pyminer/resources/js/element-ui/lib/mixins/emitter.js diff --git a/pyminer/static/js/element-ui/lib/mixins/focus.js b/pyminer/resources/js/element-ui/lib/mixins/focus.js similarity index 100% rename from pyminer/static/js/element-ui/lib/mixins/focus.js rename to pyminer/resources/js/element-ui/lib/mixins/focus.js diff --git a/pyminer/static/js/element-ui/lib/mixins/locale.js b/pyminer/resources/js/element-ui/lib/mixins/locale.js similarity index 100% rename from pyminer/static/js/element-ui/lib/mixins/locale.js rename to pyminer/resources/js/element-ui/lib/mixins/locale.js diff --git a/pyminer/static/js/element-ui/lib/mixins/migrating.js b/pyminer/resources/js/element-ui/lib/mixins/migrating.js similarity index 100% rename from pyminer/static/js/element-ui/lib/mixins/migrating.js rename to pyminer/resources/js/element-ui/lib/mixins/migrating.js diff --git a/pyminer/static/js/element-ui/lib/notification.js b/pyminer/resources/js/element-ui/lib/notification.js similarity index 100% rename from pyminer/static/js/element-ui/lib/notification.js rename to pyminer/resources/js/element-ui/lib/notification.js diff --git a/pyminer/static/js/element-ui/lib/option-group.js b/pyminer/resources/js/element-ui/lib/option-group.js similarity index 100% rename from pyminer/static/js/element-ui/lib/option-group.js rename to pyminer/resources/js/element-ui/lib/option-group.js diff --git a/pyminer/static/js/element-ui/lib/option.js b/pyminer/resources/js/element-ui/lib/option.js similarity index 100% rename from pyminer/static/js/element-ui/lib/option.js rename to pyminer/resources/js/element-ui/lib/option.js diff --git a/pyminer/static/js/element-ui/lib/page-header.js b/pyminer/resources/js/element-ui/lib/page-header.js similarity index 100% rename from pyminer/static/js/element-ui/lib/page-header.js rename to pyminer/resources/js/element-ui/lib/page-header.js diff --git a/pyminer/static/js/element-ui/lib/pagination.js b/pyminer/resources/js/element-ui/lib/pagination.js similarity index 100% rename from pyminer/static/js/element-ui/lib/pagination.js rename to pyminer/resources/js/element-ui/lib/pagination.js diff --git a/pyminer/static/js/element-ui/lib/popconfirm.js b/pyminer/resources/js/element-ui/lib/popconfirm.js similarity index 100% rename from pyminer/static/js/element-ui/lib/popconfirm.js rename to pyminer/resources/js/element-ui/lib/popconfirm.js diff --git a/pyminer/static/js/element-ui/lib/popover.js b/pyminer/resources/js/element-ui/lib/popover.js similarity index 100% rename from pyminer/static/js/element-ui/lib/popover.js rename to pyminer/resources/js/element-ui/lib/popover.js diff --git a/pyminer/static/js/element-ui/lib/progress.js b/pyminer/resources/js/element-ui/lib/progress.js similarity index 100% rename from pyminer/static/js/element-ui/lib/progress.js rename to pyminer/resources/js/element-ui/lib/progress.js diff --git a/pyminer/static/js/element-ui/lib/radio-button.js b/pyminer/resources/js/element-ui/lib/radio-button.js similarity index 100% rename from pyminer/static/js/element-ui/lib/radio-button.js rename to pyminer/resources/js/element-ui/lib/radio-button.js diff --git a/pyminer/static/js/element-ui/lib/radio-group.js b/pyminer/resources/js/element-ui/lib/radio-group.js similarity index 100% rename from pyminer/static/js/element-ui/lib/radio-group.js rename to pyminer/resources/js/element-ui/lib/radio-group.js diff --git a/pyminer/static/js/element-ui/lib/radio.js b/pyminer/resources/js/element-ui/lib/radio.js similarity index 100% rename from pyminer/static/js/element-ui/lib/radio.js rename to pyminer/resources/js/element-ui/lib/radio.js diff --git a/pyminer/static/js/element-ui/lib/rate.js b/pyminer/resources/js/element-ui/lib/rate.js similarity index 100% rename from pyminer/static/js/element-ui/lib/rate.js rename to pyminer/resources/js/element-ui/lib/rate.js diff --git a/pyminer/static/js/element-ui/lib/row.js b/pyminer/resources/js/element-ui/lib/row.js similarity index 100% rename from pyminer/static/js/element-ui/lib/row.js rename to pyminer/resources/js/element-ui/lib/row.js diff --git a/pyminer/static/js/element-ui/lib/scrollbar.js b/pyminer/resources/js/element-ui/lib/scrollbar.js similarity index 100% rename from pyminer/static/js/element-ui/lib/scrollbar.js rename to pyminer/resources/js/element-ui/lib/scrollbar.js diff --git a/pyminer/static/js/element-ui/lib/select.js b/pyminer/resources/js/element-ui/lib/select.js similarity index 100% rename from pyminer/static/js/element-ui/lib/select.js rename to pyminer/resources/js/element-ui/lib/select.js diff --git a/pyminer/static/js/element-ui/lib/slider.js b/pyminer/resources/js/element-ui/lib/slider.js similarity index 100% rename from pyminer/static/js/element-ui/lib/slider.js rename to pyminer/resources/js/element-ui/lib/slider.js diff --git a/pyminer/static/js/element-ui/lib/spinner.js b/pyminer/resources/js/element-ui/lib/spinner.js similarity index 100% rename from pyminer/static/js/element-ui/lib/spinner.js rename to pyminer/resources/js/element-ui/lib/spinner.js diff --git a/pyminer/static/js/element-ui/lib/step.js b/pyminer/resources/js/element-ui/lib/step.js similarity index 100% rename from pyminer/static/js/element-ui/lib/step.js rename to pyminer/resources/js/element-ui/lib/step.js diff --git a/pyminer/static/js/element-ui/lib/steps.js b/pyminer/resources/js/element-ui/lib/steps.js similarity index 100% rename from pyminer/static/js/element-ui/lib/steps.js rename to pyminer/resources/js/element-ui/lib/steps.js diff --git a/pyminer/static/js/element-ui/lib/submenu.js b/pyminer/resources/js/element-ui/lib/submenu.js similarity index 100% rename from pyminer/static/js/element-ui/lib/submenu.js rename to pyminer/resources/js/element-ui/lib/submenu.js diff --git a/pyminer/static/js/element-ui/lib/switch.js b/pyminer/resources/js/element-ui/lib/switch.js similarity index 100% rename from pyminer/static/js/element-ui/lib/switch.js rename to pyminer/resources/js/element-ui/lib/switch.js diff --git a/pyminer/static/js/element-ui/lib/tab-pane.js b/pyminer/resources/js/element-ui/lib/tab-pane.js similarity index 100% rename from pyminer/static/js/element-ui/lib/tab-pane.js rename to pyminer/resources/js/element-ui/lib/tab-pane.js diff --git a/pyminer/static/js/element-ui/lib/table-column.js b/pyminer/resources/js/element-ui/lib/table-column.js similarity index 100% rename from pyminer/static/js/element-ui/lib/table-column.js rename to pyminer/resources/js/element-ui/lib/table-column.js diff --git a/pyminer/static/js/element-ui/lib/table.js b/pyminer/resources/js/element-ui/lib/table.js similarity index 100% rename from pyminer/static/js/element-ui/lib/table.js rename to pyminer/resources/js/element-ui/lib/table.js diff --git a/pyminer/static/js/element-ui/lib/tabs.js b/pyminer/resources/js/element-ui/lib/tabs.js similarity index 100% rename from pyminer/static/js/element-ui/lib/tabs.js rename to pyminer/resources/js/element-ui/lib/tabs.js diff --git a/pyminer/static/js/element-ui/lib/tag.js b/pyminer/resources/js/element-ui/lib/tag.js similarity index 100% rename from pyminer/static/js/element-ui/lib/tag.js rename to pyminer/resources/js/element-ui/lib/tag.js diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/alert.css b/pyminer/resources/js/element-ui/lib/theme-chalk/alert.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/alert.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/alert.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/aside.css b/pyminer/resources/js/element-ui/lib/theme-chalk/aside.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/aside.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/aside.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/autocomplete.css b/pyminer/resources/js/element-ui/lib/theme-chalk/autocomplete.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/autocomplete.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/autocomplete.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/avatar.css b/pyminer/resources/js/element-ui/lib/theme-chalk/avatar.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/avatar.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/avatar.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/backtop.css b/pyminer/resources/js/element-ui/lib/theme-chalk/backtop.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/backtop.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/backtop.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/badge.css b/pyminer/resources/js/element-ui/lib/theme-chalk/badge.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/badge.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/badge.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/base.css b/pyminer/resources/js/element-ui/lib/theme-chalk/base.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/base.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/base.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/breadcrumb-item.css b/pyminer/resources/js/element-ui/lib/theme-chalk/breadcrumb-item.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/breadcrumb-item.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/breadcrumb-item.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/breadcrumb.css b/pyminer/resources/js/element-ui/lib/theme-chalk/breadcrumb.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/breadcrumb.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/breadcrumb.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/button-group.css b/pyminer/resources/js/element-ui/lib/theme-chalk/button-group.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/button-group.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/button-group.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/button.css b/pyminer/resources/js/element-ui/lib/theme-chalk/button.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/button.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/button.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/calendar.css b/pyminer/resources/js/element-ui/lib/theme-chalk/calendar.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/calendar.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/calendar.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/card.css b/pyminer/resources/js/element-ui/lib/theme-chalk/card.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/card.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/card.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/carousel-item.css b/pyminer/resources/js/element-ui/lib/theme-chalk/carousel-item.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/carousel-item.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/carousel-item.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/carousel.css b/pyminer/resources/js/element-ui/lib/theme-chalk/carousel.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/carousel.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/carousel.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/cascader-panel.css b/pyminer/resources/js/element-ui/lib/theme-chalk/cascader-panel.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/cascader-panel.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/cascader-panel.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/cascader.css b/pyminer/resources/js/element-ui/lib/theme-chalk/cascader.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/cascader.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/cascader.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/checkbox-button.css b/pyminer/resources/js/element-ui/lib/theme-chalk/checkbox-button.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/checkbox-button.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/checkbox-button.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/checkbox-group.css b/pyminer/resources/js/element-ui/lib/theme-chalk/checkbox-group.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/checkbox-group.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/checkbox-group.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/checkbox.css b/pyminer/resources/js/element-ui/lib/theme-chalk/checkbox.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/checkbox.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/checkbox.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/col.css b/pyminer/resources/js/element-ui/lib/theme-chalk/col.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/col.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/col.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/collapse-item.css b/pyminer/resources/js/element-ui/lib/theme-chalk/collapse-item.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/collapse-item.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/collapse-item.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/collapse.css b/pyminer/resources/js/element-ui/lib/theme-chalk/collapse.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/collapse.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/collapse.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/color-picker.css b/pyminer/resources/js/element-ui/lib/theme-chalk/color-picker.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/color-picker.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/color-picker.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/container.css b/pyminer/resources/js/element-ui/lib/theme-chalk/container.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/container.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/container.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/date-picker.css b/pyminer/resources/js/element-ui/lib/theme-chalk/date-picker.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/date-picker.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/date-picker.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/dialog.css b/pyminer/resources/js/element-ui/lib/theme-chalk/dialog.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/dialog.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/dialog.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/display.css b/pyminer/resources/js/element-ui/lib/theme-chalk/display.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/display.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/display.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/divider.css b/pyminer/resources/js/element-ui/lib/theme-chalk/divider.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/divider.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/divider.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/drawer.css b/pyminer/resources/js/element-ui/lib/theme-chalk/drawer.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/drawer.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/drawer.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/dropdown-item.css b/pyminer/resources/js/element-ui/lib/theme-chalk/dropdown-item.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/dropdown-item.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/dropdown-item.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/dropdown-menu.css b/pyminer/resources/js/element-ui/lib/theme-chalk/dropdown-menu.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/dropdown-menu.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/dropdown-menu.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/dropdown.css b/pyminer/resources/js/element-ui/lib/theme-chalk/dropdown.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/dropdown.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/dropdown.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/fonts/element-icons.ttf b/pyminer/resources/js/element-ui/lib/theme-chalk/fonts/element-icons.ttf similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/fonts/element-icons.ttf rename to pyminer/resources/js/element-ui/lib/theme-chalk/fonts/element-icons.ttf diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/fonts/element-icons.woff b/pyminer/resources/js/element-ui/lib/theme-chalk/fonts/element-icons.woff similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/fonts/element-icons.woff rename to pyminer/resources/js/element-ui/lib/theme-chalk/fonts/element-icons.woff diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/footer.css b/pyminer/resources/js/element-ui/lib/theme-chalk/footer.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/footer.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/footer.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/form-item.css b/pyminer/resources/js/element-ui/lib/theme-chalk/form-item.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/form-item.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/form-item.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/form.css b/pyminer/resources/js/element-ui/lib/theme-chalk/form.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/form.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/form.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/header.css b/pyminer/resources/js/element-ui/lib/theme-chalk/header.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/header.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/header.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/icon.css b/pyminer/resources/js/element-ui/lib/theme-chalk/icon.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/icon.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/icon.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/image.css b/pyminer/resources/js/element-ui/lib/theme-chalk/image.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/image.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/image.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/index.css b/pyminer/resources/js/element-ui/lib/theme-chalk/index.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/index.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/index.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/infinite-scroll.css b/pyminer/resources/js/element-ui/lib/theme-chalk/infinite-scroll.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/infinite-scroll.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/infinite-scroll.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/infiniteScroll.css b/pyminer/resources/js/element-ui/lib/theme-chalk/infiniteScroll.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/infiniteScroll.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/infiniteScroll.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/input-number.css b/pyminer/resources/js/element-ui/lib/theme-chalk/input-number.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/input-number.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/input-number.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/input.css b/pyminer/resources/js/element-ui/lib/theme-chalk/input.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/input.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/input.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/link.css b/pyminer/resources/js/element-ui/lib/theme-chalk/link.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/link.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/link.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/loading.css b/pyminer/resources/js/element-ui/lib/theme-chalk/loading.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/loading.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/loading.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/main.css b/pyminer/resources/js/element-ui/lib/theme-chalk/main.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/main.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/main.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/menu-item-group.css b/pyminer/resources/js/element-ui/lib/theme-chalk/menu-item-group.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/menu-item-group.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/menu-item-group.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/menu-item.css b/pyminer/resources/js/element-ui/lib/theme-chalk/menu-item.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/menu-item.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/menu-item.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/menu.css b/pyminer/resources/js/element-ui/lib/theme-chalk/menu.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/menu.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/menu.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/message-box.css b/pyminer/resources/js/element-ui/lib/theme-chalk/message-box.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/message-box.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/message-box.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/message.css b/pyminer/resources/js/element-ui/lib/theme-chalk/message.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/message.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/message.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/notification.css b/pyminer/resources/js/element-ui/lib/theme-chalk/notification.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/notification.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/notification.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/option-group.css b/pyminer/resources/js/element-ui/lib/theme-chalk/option-group.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/option-group.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/option-group.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/option.css b/pyminer/resources/js/element-ui/lib/theme-chalk/option.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/option.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/option.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/page-header.css b/pyminer/resources/js/element-ui/lib/theme-chalk/page-header.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/page-header.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/page-header.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/pagination.css b/pyminer/resources/js/element-ui/lib/theme-chalk/pagination.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/pagination.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/pagination.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/popconfirm.css b/pyminer/resources/js/element-ui/lib/theme-chalk/popconfirm.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/popconfirm.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/popconfirm.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/popover.css b/pyminer/resources/js/element-ui/lib/theme-chalk/popover.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/popover.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/popover.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/popper.css b/pyminer/resources/js/element-ui/lib/theme-chalk/popper.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/popper.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/popper.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/progress.css b/pyminer/resources/js/element-ui/lib/theme-chalk/progress.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/progress.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/progress.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/radio-button.css b/pyminer/resources/js/element-ui/lib/theme-chalk/radio-button.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/radio-button.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/radio-button.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/radio-group.css b/pyminer/resources/js/element-ui/lib/theme-chalk/radio-group.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/radio-group.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/radio-group.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/radio.css b/pyminer/resources/js/element-ui/lib/theme-chalk/radio.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/radio.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/radio.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/rate.css b/pyminer/resources/js/element-ui/lib/theme-chalk/rate.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/rate.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/rate.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/reset.css b/pyminer/resources/js/element-ui/lib/theme-chalk/reset.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/reset.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/reset.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/row.css b/pyminer/resources/js/element-ui/lib/theme-chalk/row.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/row.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/row.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/scrollbar.css b/pyminer/resources/js/element-ui/lib/theme-chalk/scrollbar.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/scrollbar.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/scrollbar.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/select-dropdown.css b/pyminer/resources/js/element-ui/lib/theme-chalk/select-dropdown.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/select-dropdown.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/select-dropdown.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/select.css b/pyminer/resources/js/element-ui/lib/theme-chalk/select.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/select.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/select.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/slider.css b/pyminer/resources/js/element-ui/lib/theme-chalk/slider.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/slider.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/slider.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/spinner.css b/pyminer/resources/js/element-ui/lib/theme-chalk/spinner.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/spinner.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/spinner.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/step.css b/pyminer/resources/js/element-ui/lib/theme-chalk/step.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/step.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/step.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/steps.css b/pyminer/resources/js/element-ui/lib/theme-chalk/steps.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/steps.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/steps.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/submenu.css b/pyminer/resources/js/element-ui/lib/theme-chalk/submenu.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/submenu.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/submenu.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/switch.css b/pyminer/resources/js/element-ui/lib/theme-chalk/switch.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/switch.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/switch.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/tab-pane.css b/pyminer/resources/js/element-ui/lib/theme-chalk/tab-pane.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/tab-pane.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/tab-pane.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/table-column.css b/pyminer/resources/js/element-ui/lib/theme-chalk/table-column.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/table-column.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/table-column.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/table.css b/pyminer/resources/js/element-ui/lib/theme-chalk/table.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/table.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/table.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/tabs.css b/pyminer/resources/js/element-ui/lib/theme-chalk/tabs.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/tabs.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/tabs.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/tag.css b/pyminer/resources/js/element-ui/lib/theme-chalk/tag.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/tag.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/tag.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/time-picker.css b/pyminer/resources/js/element-ui/lib/theme-chalk/time-picker.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/time-picker.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/time-picker.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/time-select.css b/pyminer/resources/js/element-ui/lib/theme-chalk/time-select.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/time-select.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/time-select.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/timeline-item.css b/pyminer/resources/js/element-ui/lib/theme-chalk/timeline-item.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/timeline-item.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/timeline-item.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/timeline.css b/pyminer/resources/js/element-ui/lib/theme-chalk/timeline.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/timeline.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/timeline.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/tooltip.css b/pyminer/resources/js/element-ui/lib/theme-chalk/tooltip.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/tooltip.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/tooltip.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/transfer.css b/pyminer/resources/js/element-ui/lib/theme-chalk/transfer.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/transfer.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/transfer.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/tree.css b/pyminer/resources/js/element-ui/lib/theme-chalk/tree.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/tree.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/tree.css diff --git a/pyminer/static/js/element-ui/lib/theme-chalk/upload.css b/pyminer/resources/js/element-ui/lib/theme-chalk/upload.css similarity index 100% rename from pyminer/static/js/element-ui/lib/theme-chalk/upload.css rename to pyminer/resources/js/element-ui/lib/theme-chalk/upload.css diff --git a/pyminer/static/js/element-ui/lib/time-picker.js b/pyminer/resources/js/element-ui/lib/time-picker.js similarity index 100% rename from pyminer/static/js/element-ui/lib/time-picker.js rename to pyminer/resources/js/element-ui/lib/time-picker.js diff --git a/pyminer/static/js/element-ui/lib/time-select.js b/pyminer/resources/js/element-ui/lib/time-select.js similarity index 100% rename from pyminer/static/js/element-ui/lib/time-select.js rename to pyminer/resources/js/element-ui/lib/time-select.js diff --git a/pyminer/static/js/element-ui/lib/timeline-item.js b/pyminer/resources/js/element-ui/lib/timeline-item.js similarity index 100% rename from pyminer/static/js/element-ui/lib/timeline-item.js rename to pyminer/resources/js/element-ui/lib/timeline-item.js diff --git a/pyminer/static/js/element-ui/lib/timeline.js b/pyminer/resources/js/element-ui/lib/timeline.js similarity index 100% rename from pyminer/static/js/element-ui/lib/timeline.js rename to pyminer/resources/js/element-ui/lib/timeline.js diff --git a/pyminer/static/js/element-ui/lib/tooltip.js b/pyminer/resources/js/element-ui/lib/tooltip.js similarity index 100% rename from pyminer/static/js/element-ui/lib/tooltip.js rename to pyminer/resources/js/element-ui/lib/tooltip.js diff --git a/pyminer/static/js/element-ui/lib/transfer.js b/pyminer/resources/js/element-ui/lib/transfer.js similarity index 100% rename from pyminer/static/js/element-ui/lib/transfer.js rename to pyminer/resources/js/element-ui/lib/transfer.js diff --git a/pyminer/static/js/element-ui/lib/transitions/collapse-transition.js b/pyminer/resources/js/element-ui/lib/transitions/collapse-transition.js similarity index 100% rename from pyminer/static/js/element-ui/lib/transitions/collapse-transition.js rename to pyminer/resources/js/element-ui/lib/transitions/collapse-transition.js diff --git a/pyminer/static/js/element-ui/lib/tree.js b/pyminer/resources/js/element-ui/lib/tree.js similarity index 100% rename from pyminer/static/js/element-ui/lib/tree.js rename to pyminer/resources/js/element-ui/lib/tree.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/af-ZA.js b/pyminer/resources/js/element-ui/lib/umd/locale/af-ZA.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/af-ZA.js rename to pyminer/resources/js/element-ui/lib/umd/locale/af-ZA.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/ar.js b/pyminer/resources/js/element-ui/lib/umd/locale/ar.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/ar.js rename to pyminer/resources/js/element-ui/lib/umd/locale/ar.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/bg.js b/pyminer/resources/js/element-ui/lib/umd/locale/bg.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/bg.js rename to pyminer/resources/js/element-ui/lib/umd/locale/bg.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/ca.js b/pyminer/resources/js/element-ui/lib/umd/locale/ca.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/ca.js rename to pyminer/resources/js/element-ui/lib/umd/locale/ca.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/cs-CZ.js b/pyminer/resources/js/element-ui/lib/umd/locale/cs-CZ.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/cs-CZ.js rename to pyminer/resources/js/element-ui/lib/umd/locale/cs-CZ.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/da.js b/pyminer/resources/js/element-ui/lib/umd/locale/da.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/da.js rename to pyminer/resources/js/element-ui/lib/umd/locale/da.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/de.js b/pyminer/resources/js/element-ui/lib/umd/locale/de.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/de.js rename to pyminer/resources/js/element-ui/lib/umd/locale/de.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/ee.js b/pyminer/resources/js/element-ui/lib/umd/locale/ee.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/ee.js rename to pyminer/resources/js/element-ui/lib/umd/locale/ee.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/el.js b/pyminer/resources/js/element-ui/lib/umd/locale/el.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/el.js rename to pyminer/resources/js/element-ui/lib/umd/locale/el.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/en.js b/pyminer/resources/js/element-ui/lib/umd/locale/en.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/en.js rename to pyminer/resources/js/element-ui/lib/umd/locale/en.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/eo.js b/pyminer/resources/js/element-ui/lib/umd/locale/eo.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/eo.js rename to pyminer/resources/js/element-ui/lib/umd/locale/eo.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/es.js b/pyminer/resources/js/element-ui/lib/umd/locale/es.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/es.js rename to pyminer/resources/js/element-ui/lib/umd/locale/es.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/eu.js b/pyminer/resources/js/element-ui/lib/umd/locale/eu.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/eu.js rename to pyminer/resources/js/element-ui/lib/umd/locale/eu.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/fa.js b/pyminer/resources/js/element-ui/lib/umd/locale/fa.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/fa.js rename to pyminer/resources/js/element-ui/lib/umd/locale/fa.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/fi.js b/pyminer/resources/js/element-ui/lib/umd/locale/fi.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/fi.js rename to pyminer/resources/js/element-ui/lib/umd/locale/fi.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/fr.js b/pyminer/resources/js/element-ui/lib/umd/locale/fr.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/fr.js rename to pyminer/resources/js/element-ui/lib/umd/locale/fr.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/he.js b/pyminer/resources/js/element-ui/lib/umd/locale/he.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/he.js rename to pyminer/resources/js/element-ui/lib/umd/locale/he.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/hr.js b/pyminer/resources/js/element-ui/lib/umd/locale/hr.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/hr.js rename to pyminer/resources/js/element-ui/lib/umd/locale/hr.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/hu.js b/pyminer/resources/js/element-ui/lib/umd/locale/hu.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/hu.js rename to pyminer/resources/js/element-ui/lib/umd/locale/hu.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/hy-AM.js b/pyminer/resources/js/element-ui/lib/umd/locale/hy-AM.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/hy-AM.js rename to pyminer/resources/js/element-ui/lib/umd/locale/hy-AM.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/id.js b/pyminer/resources/js/element-ui/lib/umd/locale/id.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/id.js rename to pyminer/resources/js/element-ui/lib/umd/locale/id.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/it.js b/pyminer/resources/js/element-ui/lib/umd/locale/it.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/it.js rename to pyminer/resources/js/element-ui/lib/umd/locale/it.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/ja.js b/pyminer/resources/js/element-ui/lib/umd/locale/ja.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/ja.js rename to pyminer/resources/js/element-ui/lib/umd/locale/ja.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/kg.js b/pyminer/resources/js/element-ui/lib/umd/locale/kg.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/kg.js rename to pyminer/resources/js/element-ui/lib/umd/locale/kg.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/km.js b/pyminer/resources/js/element-ui/lib/umd/locale/km.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/km.js rename to pyminer/resources/js/element-ui/lib/umd/locale/km.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/ko.js b/pyminer/resources/js/element-ui/lib/umd/locale/ko.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/ko.js rename to pyminer/resources/js/element-ui/lib/umd/locale/ko.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/ku.js b/pyminer/resources/js/element-ui/lib/umd/locale/ku.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/ku.js rename to pyminer/resources/js/element-ui/lib/umd/locale/ku.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/kz.js b/pyminer/resources/js/element-ui/lib/umd/locale/kz.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/kz.js rename to pyminer/resources/js/element-ui/lib/umd/locale/kz.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/lt.js b/pyminer/resources/js/element-ui/lib/umd/locale/lt.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/lt.js rename to pyminer/resources/js/element-ui/lib/umd/locale/lt.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/lv.js b/pyminer/resources/js/element-ui/lib/umd/locale/lv.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/lv.js rename to pyminer/resources/js/element-ui/lib/umd/locale/lv.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/mn.js b/pyminer/resources/js/element-ui/lib/umd/locale/mn.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/mn.js rename to pyminer/resources/js/element-ui/lib/umd/locale/mn.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/nb-NO.js b/pyminer/resources/js/element-ui/lib/umd/locale/nb-NO.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/nb-NO.js rename to pyminer/resources/js/element-ui/lib/umd/locale/nb-NO.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/nl.js b/pyminer/resources/js/element-ui/lib/umd/locale/nl.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/nl.js rename to pyminer/resources/js/element-ui/lib/umd/locale/nl.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/pl.js b/pyminer/resources/js/element-ui/lib/umd/locale/pl.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/pl.js rename to pyminer/resources/js/element-ui/lib/umd/locale/pl.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/pt-br.js b/pyminer/resources/js/element-ui/lib/umd/locale/pt-br.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/pt-br.js rename to pyminer/resources/js/element-ui/lib/umd/locale/pt-br.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/pt.js b/pyminer/resources/js/element-ui/lib/umd/locale/pt.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/pt.js rename to pyminer/resources/js/element-ui/lib/umd/locale/pt.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/ro.js b/pyminer/resources/js/element-ui/lib/umd/locale/ro.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/ro.js rename to pyminer/resources/js/element-ui/lib/umd/locale/ro.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/ru-RU.js b/pyminer/resources/js/element-ui/lib/umd/locale/ru-RU.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/ru-RU.js rename to pyminer/resources/js/element-ui/lib/umd/locale/ru-RU.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/sk.js b/pyminer/resources/js/element-ui/lib/umd/locale/sk.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/sk.js rename to pyminer/resources/js/element-ui/lib/umd/locale/sk.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/sl.js b/pyminer/resources/js/element-ui/lib/umd/locale/sl.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/sl.js rename to pyminer/resources/js/element-ui/lib/umd/locale/sl.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/sr.js b/pyminer/resources/js/element-ui/lib/umd/locale/sr.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/sr.js rename to pyminer/resources/js/element-ui/lib/umd/locale/sr.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/sv-SE.js b/pyminer/resources/js/element-ui/lib/umd/locale/sv-SE.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/sv-SE.js rename to pyminer/resources/js/element-ui/lib/umd/locale/sv-SE.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/ta.js b/pyminer/resources/js/element-ui/lib/umd/locale/ta.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/ta.js rename to pyminer/resources/js/element-ui/lib/umd/locale/ta.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/th.js b/pyminer/resources/js/element-ui/lib/umd/locale/th.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/th.js rename to pyminer/resources/js/element-ui/lib/umd/locale/th.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/tk.js b/pyminer/resources/js/element-ui/lib/umd/locale/tk.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/tk.js rename to pyminer/resources/js/element-ui/lib/umd/locale/tk.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/tr-TR.js b/pyminer/resources/js/element-ui/lib/umd/locale/tr-TR.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/tr-TR.js rename to pyminer/resources/js/element-ui/lib/umd/locale/tr-TR.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/ua.js b/pyminer/resources/js/element-ui/lib/umd/locale/ua.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/ua.js rename to pyminer/resources/js/element-ui/lib/umd/locale/ua.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/ug-CN.js b/pyminer/resources/js/element-ui/lib/umd/locale/ug-CN.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/ug-CN.js rename to pyminer/resources/js/element-ui/lib/umd/locale/ug-CN.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/uz-UZ.js b/pyminer/resources/js/element-ui/lib/umd/locale/uz-UZ.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/uz-UZ.js rename to pyminer/resources/js/element-ui/lib/umd/locale/uz-UZ.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/vi.js b/pyminer/resources/js/element-ui/lib/umd/locale/vi.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/vi.js rename to pyminer/resources/js/element-ui/lib/umd/locale/vi.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/zh-CN.js b/pyminer/resources/js/element-ui/lib/umd/locale/zh-CN.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/zh-CN.js rename to pyminer/resources/js/element-ui/lib/umd/locale/zh-CN.js diff --git a/pyminer/static/js/element-ui/lib/umd/locale/zh-TW.js b/pyminer/resources/js/element-ui/lib/umd/locale/zh-TW.js similarity index 100% rename from pyminer/static/js/element-ui/lib/umd/locale/zh-TW.js rename to pyminer/resources/js/element-ui/lib/umd/locale/zh-TW.js diff --git a/pyminer/static/js/element-ui/lib/upload.js b/pyminer/resources/js/element-ui/lib/upload.js similarity index 100% rename from pyminer/static/js/element-ui/lib/upload.js rename to pyminer/resources/js/element-ui/lib/upload.js diff --git a/pyminer/static/js/element-ui/lib/utils/after-leave.js b/pyminer/resources/js/element-ui/lib/utils/after-leave.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/after-leave.js rename to pyminer/resources/js/element-ui/lib/utils/after-leave.js diff --git a/pyminer/static/js/element-ui/lib/utils/aria-dialog.js b/pyminer/resources/js/element-ui/lib/utils/aria-dialog.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/aria-dialog.js rename to pyminer/resources/js/element-ui/lib/utils/aria-dialog.js diff --git a/pyminer/static/js/element-ui/lib/utils/aria-utils.js b/pyminer/resources/js/element-ui/lib/utils/aria-utils.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/aria-utils.js rename to pyminer/resources/js/element-ui/lib/utils/aria-utils.js diff --git a/pyminer/static/js/element-ui/lib/utils/clickoutside.js b/pyminer/resources/js/element-ui/lib/utils/clickoutside.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/clickoutside.js rename to pyminer/resources/js/element-ui/lib/utils/clickoutside.js diff --git a/pyminer/static/js/element-ui/lib/utils/date-util.js b/pyminer/resources/js/element-ui/lib/utils/date-util.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/date-util.js rename to pyminer/resources/js/element-ui/lib/utils/date-util.js diff --git a/pyminer/static/js/element-ui/lib/utils/date.js b/pyminer/resources/js/element-ui/lib/utils/date.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/date.js rename to pyminer/resources/js/element-ui/lib/utils/date.js diff --git a/pyminer/static/js/element-ui/lib/utils/dom.js b/pyminer/resources/js/element-ui/lib/utils/dom.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/dom.js rename to pyminer/resources/js/element-ui/lib/utils/dom.js diff --git a/pyminer/static/js/element-ui/lib/utils/menu/aria-menubar.js b/pyminer/resources/js/element-ui/lib/utils/menu/aria-menubar.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/menu/aria-menubar.js rename to pyminer/resources/js/element-ui/lib/utils/menu/aria-menubar.js diff --git a/pyminer/static/js/element-ui/lib/utils/menu/aria-menuitem.js b/pyminer/resources/js/element-ui/lib/utils/menu/aria-menuitem.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/menu/aria-menuitem.js rename to pyminer/resources/js/element-ui/lib/utils/menu/aria-menuitem.js diff --git a/pyminer/static/js/element-ui/lib/utils/menu/aria-submenu.js b/pyminer/resources/js/element-ui/lib/utils/menu/aria-submenu.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/menu/aria-submenu.js rename to pyminer/resources/js/element-ui/lib/utils/menu/aria-submenu.js diff --git a/pyminer/static/js/element-ui/lib/utils/merge.js b/pyminer/resources/js/element-ui/lib/utils/merge.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/merge.js rename to pyminer/resources/js/element-ui/lib/utils/merge.js diff --git a/pyminer/static/js/element-ui/lib/utils/popper.js b/pyminer/resources/js/element-ui/lib/utils/popper.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/popper.js rename to pyminer/resources/js/element-ui/lib/utils/popper.js diff --git a/pyminer/static/js/element-ui/lib/utils/popup/index.js b/pyminer/resources/js/element-ui/lib/utils/popup/index.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/popup/index.js rename to pyminer/resources/js/element-ui/lib/utils/popup/index.js diff --git a/pyminer/static/js/element-ui/lib/utils/popup/popup-manager.js b/pyminer/resources/js/element-ui/lib/utils/popup/popup-manager.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/popup/popup-manager.js rename to pyminer/resources/js/element-ui/lib/utils/popup/popup-manager.js diff --git a/pyminer/static/js/element-ui/lib/utils/resize-event.js b/pyminer/resources/js/element-ui/lib/utils/resize-event.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/resize-event.js rename to pyminer/resources/js/element-ui/lib/utils/resize-event.js diff --git a/pyminer/static/js/element-ui/lib/utils/scroll-into-view.js b/pyminer/resources/js/element-ui/lib/utils/scroll-into-view.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/scroll-into-view.js rename to pyminer/resources/js/element-ui/lib/utils/scroll-into-view.js diff --git a/pyminer/static/js/element-ui/lib/utils/scrollbar-width.js b/pyminer/resources/js/element-ui/lib/utils/scrollbar-width.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/scrollbar-width.js rename to pyminer/resources/js/element-ui/lib/utils/scrollbar-width.js diff --git a/pyminer/static/js/element-ui/lib/utils/shared.js b/pyminer/resources/js/element-ui/lib/utils/shared.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/shared.js rename to pyminer/resources/js/element-ui/lib/utils/shared.js diff --git a/pyminer/static/js/element-ui/lib/utils/types.js b/pyminer/resources/js/element-ui/lib/utils/types.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/types.js rename to pyminer/resources/js/element-ui/lib/utils/types.js diff --git a/pyminer/static/js/element-ui/lib/utils/util.js b/pyminer/resources/js/element-ui/lib/utils/util.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/util.js rename to pyminer/resources/js/element-ui/lib/utils/util.js diff --git a/pyminer/static/js/element-ui/lib/utils/vdom.js b/pyminer/resources/js/element-ui/lib/utils/vdom.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/vdom.js rename to pyminer/resources/js/element-ui/lib/utils/vdom.js diff --git a/pyminer/static/js/element-ui/lib/utils/vue-popper.js b/pyminer/resources/js/element-ui/lib/utils/vue-popper.js similarity index 100% rename from pyminer/static/js/element-ui/lib/utils/vue-popper.js rename to pyminer/resources/js/element-ui/lib/utils/vue-popper.js diff --git a/pyminer/static/js/element-ui/package.json b/pyminer/resources/js/element-ui/package.json similarity index 100% rename from pyminer/static/js/element-ui/package.json rename to pyminer/resources/js/element-ui/package.json diff --git a/pyminer/static/js/form-create.min.js b/pyminer/resources/js/form-create.min.js similarity index 100% rename from pyminer/static/js/form-create.min.js rename to pyminer/resources/js/form-create.min.js diff --git a/pyminer/static/js/iview.min.js b/pyminer/resources/js/iview.min.js similarity index 100% rename from pyminer/static/js/iview.min.js rename to pyminer/resources/js/iview.min.js diff --git a/pyminer/static/js/jquery-3.5.1.min.js b/pyminer/resources/js/jquery-3.5.1.min.js similarity index 100% rename from pyminer/static/js/jquery-3.5.1.min.js rename to pyminer/resources/js/jquery-3.5.1.min.js diff --git a/pyminer/static/js/vue.min.js b/pyminer/resources/js/vue.min.js similarity index 100% rename from pyminer/static/js/vue.min.js rename to pyminer/resources/js/vue.min.js diff --git a/pyminer/static/tutorials_page.html b/pyminer/resources/tutorials_page.html similarity index 100% rename from pyminer/static/tutorials_page.html rename to pyminer/resources/tutorials_page.html diff --git a/pyminer/static/README.md b/pyminer/static/README.md deleted file mode 100644 index 7b3676b8..00000000 --- a/pyminer/static/README.md +++ /dev/null @@ -1 +0,0 @@ -static文件夹下是项目用到的Web资源文件,包含网页模板等。 \ No newline at end of file diff --git a/pyminer/utils/debug/pmdebug.py b/pyminer/utils/debug/pmdebug.py index 86039e6f..c7bce24c 100644 --- a/pyminer/utils/debug/pmdebug.py +++ b/pyminer/utils/debug/pmdebug.py @@ -20,7 +20,7 @@ def get_attributes_dic(name: str, var: Any) -> Dict[str, Union[str, Dict]]: def insight(var_dic: dict): - from pyminer_comm import set_var + from lib.comm import set_var # t0 = time.time() vars = {} callables = {} diff --git a/pyminer/utils/ui/uiutil/workspaceutil.py b/pyminer/utils/ui/uiutil/workspaceutil.py index 4fd4e4d6..ea1af9ff 100644 --- a/pyminer/utils/ui/uiutil/workspaceutil.py +++ b/pyminer/utils/ui/uiutil/workspaceutil.py @@ -13,7 +13,7 @@ def input_identifier(parent: QWidget, default_name: str = '', allow_existing_nam :param default_name: :return: """ - from pyminer_comm import get_var_names + from lib.comm import get_var_names assert default_name.isidentifier() var_names = get_var_names() if var_names is None: @@ -52,7 +52,7 @@ def bind_combo_with_workspace(combo: QComboBox, type_filter: str = ''): 默认值为‘’也就是空字符串,此时将返回所有的变量名。 :return: """ - from pyminer_comm import get_var_names + from lib.comm import get_var_names def on_combo_var_name_mouse_pressed(event): """ @@ -83,7 +83,7 @@ def bind_panel_combo_ctrl_with_workspace(combo_ctrl: "PMGComboCtrl", type_filter 可以直接指定type字符串中含有什么内容。 :return: """ - from pyminer_comm import get_data_descs + from lib.comm import get_data_descs from widgets import PMGComboCtrl assert isinstance(combo_ctrl, PMGComboCtrl), combo_ctrl combo = combo_ctrl.check diff --git a/pyminer/utils/ui/variableselect.py b/pyminer/utils/ui/variableselect.py index e110c754..ca796f9c 100644 --- a/pyminer/utils/ui/variableselect.py +++ b/pyminer/utils/ui/variableselect.py @@ -1,7 +1,7 @@ from typing import List, Union, TYPE_CHECKING, ClassVar from PySide2.QtWidgets import QWidget, QSplitter, QApplication, QVBoxLayout, QComboBox from utils.ui.uiutil.workspaceutil import bind_combo_with_workspace -from pyminer_comm import get_var +from lib.comm import get_var if TYPE_CHECKING: import pandas as pd diff --git a/pyminer/widgets/utilities/platform/pmdebug.py b/pyminer/widgets/utilities/platform/pmdebug.py index 463ce7bb..c4c4ad83 100644 --- a/pyminer/widgets/utilities/platform/pmdebug.py +++ b/pyminer/widgets/utilities/platform/pmdebug.py @@ -14,7 +14,7 @@ def test(): def insight(name, var): - from pyminer_comm import set_var + from lib.comm import set_var if name not in ['globals', 'os'] and (not name.startswith('__')): try: diff --git a/pyminer/widgets/widgets/composited/fastui.py b/pyminer/widgets/widgets/composited/fastui.py index 0ede79a6..7f0219ea 100644 --- a/pyminer/widgets/widgets/composited/fastui.py +++ b/pyminer/widgets/widgets/composited/fastui.py @@ -37,7 +37,7 @@ from PySide2.QtCore import Qt, QCoreApplication, Signal from PySide2.QtWidgets import QDialog, QVBoxLayout, QApplication, QPushButton, QComboBox, QHBoxLayout, QLabel, \ QTextBrowser -from pyminer_comm import get_var_names, run_command, call_interface +from lib.comm import get_var_names, run_command, call_interface from utils import input_identifier, bind_combo_with_workspace -- Gitee