datalab-platform 0.0.1.dev0__py3-none-any.whl → 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- datalab/__init__.py +35 -2
- datalab/adapters_metadata/__init__.py +31 -0
- datalab/adapters_metadata/base_adapter.py +316 -0
- datalab/adapters_metadata/common.py +422 -0
- datalab/adapters_metadata/geometry_adapter.py +98 -0
- datalab/adapters_metadata/table_adapter.py +84 -0
- datalab/adapters_plotpy/__init__.py +54 -0
- datalab/adapters_plotpy/annotations.py +124 -0
- datalab/adapters_plotpy/base.py +110 -0
- datalab/adapters_plotpy/converters.py +86 -0
- datalab/adapters_plotpy/factories.py +80 -0
- datalab/adapters_plotpy/objects/__init__.py +0 -0
- datalab/adapters_plotpy/objects/base.py +197 -0
- datalab/adapters_plotpy/objects/image.py +157 -0
- datalab/adapters_plotpy/objects/scalar.py +565 -0
- datalab/adapters_plotpy/objects/signal.py +264 -0
- datalab/adapters_plotpy/roi/__init__.py +0 -0
- datalab/adapters_plotpy/roi/base.py +146 -0
- datalab/adapters_plotpy/roi/factory.py +93 -0
- datalab/adapters_plotpy/roi/image.py +207 -0
- datalab/adapters_plotpy/roi/signal.py +72 -0
- datalab/app.py +98 -0
- datalab/config.py +817 -0
- datalab/control/__init__.py +0 -0
- datalab/control/baseproxy.py +776 -0
- datalab/control/proxy.py +343 -0
- datalab/control/remote.py +1005 -0
- datalab/data/doc/DataLab_en.pdf +0 -0
- datalab/data/doc/DataLab_fr.pdf +0 -0
- datalab/data/icons/analysis/delete_results.svg +109 -0
- datalab/data/icons/analysis/fw1e2.svg +156 -0
- datalab/data/icons/analysis/fwhm.svg +156 -0
- datalab/data/icons/analysis/histogram.svg +49 -0
- datalab/data/icons/analysis/peak_detect.svg +160 -0
- datalab/data/icons/analysis/plot_results.svg +151 -0
- datalab/data/icons/analysis/show_results.svg +83 -0
- datalab/data/icons/analysis/stats.svg +49 -0
- datalab/data/icons/analysis.svg +120 -0
- datalab/data/icons/apply.svg +3 -0
- datalab/data/icons/check_all.svg +15 -0
- datalab/data/icons/collapse.svg +44 -0
- datalab/data/icons/collapse_selection.svg +63 -0
- datalab/data/icons/console.svg +101 -0
- datalab/data/icons/create/1d-normal.svg +8 -0
- datalab/data/icons/create/1d-poisson.svg +9 -0
- datalab/data/icons/create/1d-uniform.svg +8 -0
- datalab/data/icons/create/1d-zero.svg +57 -0
- datalab/data/icons/create/2d-gaussian.svg +56 -0
- datalab/data/icons/create/2d-normal.svg +38 -0
- datalab/data/icons/create/2d-poisson.svg +38 -0
- datalab/data/icons/create/2d-ramp.svg +90 -0
- datalab/data/icons/create/2d-sinc.svg +62 -0
- datalab/data/icons/create/2d-uniform.svg +38 -0
- datalab/data/icons/create/2d-zero.svg +13 -0
- datalab/data/icons/create/checkerboard.svg +39 -0
- datalab/data/icons/create/cosine.svg +12 -0
- datalab/data/icons/create/exponential.svg +55 -0
- datalab/data/icons/create/gaussian.svg +12 -0
- datalab/data/icons/create/grating.svg +29 -0
- datalab/data/icons/create/linear_chirp.svg +7 -0
- datalab/data/icons/create/logistic.svg +7 -0
- datalab/data/icons/create/lorentzian.svg +12 -0
- datalab/data/icons/create/planck.svg +12 -0
- datalab/data/icons/create/polynomial.svg +7 -0
- datalab/data/icons/create/pulse.svg +12 -0
- datalab/data/icons/create/ring.svg +18 -0
- datalab/data/icons/create/sawtooth.svg +7 -0
- datalab/data/icons/create/siemens.svg +35 -0
- datalab/data/icons/create/sinc.svg +12 -0
- datalab/data/icons/create/sine.svg +7 -0
- datalab/data/icons/create/square.svg +7 -0
- datalab/data/icons/create/square_pulse.svg +7 -0
- datalab/data/icons/create/step.svg +7 -0
- datalab/data/icons/create/step_pulse.svg +12 -0
- datalab/data/icons/create/triangle.svg +7 -0
- datalab/data/icons/create/voigt.svg +12 -0
- datalab/data/icons/edit/annotations.svg +72 -0
- datalab/data/icons/edit/annotations_copy.svg +114 -0
- datalab/data/icons/edit/annotations_delete.svg +83 -0
- datalab/data/icons/edit/annotations_edit.svg +98 -0
- datalab/data/icons/edit/annotations_export.svg +85 -0
- datalab/data/icons/edit/annotations_import.svg +85 -0
- datalab/data/icons/edit/annotations_paste.svg +100 -0
- datalab/data/icons/edit/copy_titles.svg +109 -0
- datalab/data/icons/edit/delete.svg +84 -0
- datalab/data/icons/edit/delete_all.svg +214 -0
- datalab/data/icons/edit/duplicate.svg +64 -0
- datalab/data/icons/edit/goto_source.svg +60 -0
- datalab/data/icons/edit/metadata.svg +60 -0
- datalab/data/icons/edit/metadata_add.svg +80 -0
- datalab/data/icons/edit/metadata_copy.svg +96 -0
- datalab/data/icons/edit/metadata_delete.svg +62 -0
- datalab/data/icons/edit/metadata_export.svg +68 -0
- datalab/data/icons/edit/metadata_import.svg +68 -0
- datalab/data/icons/edit/metadata_paste.svg +79 -0
- datalab/data/icons/edit/move_down.svg +55 -0
- datalab/data/icons/edit/move_up.svg +54 -0
- datalab/data/icons/edit/new_group.svg +76 -0
- datalab/data/icons/edit/recompute.svg +60 -0
- datalab/data/icons/edit/rename.svg +49 -0
- datalab/data/icons/edit.svg +16 -0
- datalab/data/icons/expand.svg +44 -0
- datalab/data/icons/expand_selection.svg +63 -0
- datalab/data/icons/fit/cdf_fit.svg +56 -0
- datalab/data/icons/fit/exponential_fit.svg +55 -0
- datalab/data/icons/fit/gaussian_fit.svg +62 -0
- datalab/data/icons/fit/interactive_fit.svg +101 -0
- datalab/data/icons/fit/linear_fit.svg +57 -0
- datalab/data/icons/fit/lorentzian_fit.svg +209 -0
- datalab/data/icons/fit/multigaussian_fit.svg +85 -0
- datalab/data/icons/fit/multilorentzian_fit.svg +85 -0
- datalab/data/icons/fit/piecewiseexponential_fit.svg +209 -0
- datalab/data/icons/fit/planckian_fit.svg +62 -0
- datalab/data/icons/fit/polynomial_fit.svg +59 -0
- datalab/data/icons/fit/sigmoid_fit.svg +56 -0
- datalab/data/icons/fit/sinusoidal_fit.svg +72 -0
- datalab/data/icons/fit/twohalfgaussian_fit.svg +63 -0
- datalab/data/icons/fit/voigt_fit.svg +57 -0
- datalab/data/icons/group.svg +56 -0
- datalab/data/icons/h5/h5array.svg +59 -0
- datalab/data/icons/h5/h5attrs.svg +75 -0
- datalab/data/icons/h5/h5browser.svg +133 -0
- datalab/data/icons/h5/h5file.svg +69 -0
- datalab/data/icons/h5/h5group.svg +49 -0
- datalab/data/icons/h5/h5scalar.svg +1 -0
- datalab/data/icons/help_pdf.svg +46 -0
- datalab/data/icons/history.svg +7 -0
- datalab/data/icons/image.svg +135 -0
- datalab/data/icons/io/fileopen_directory.svg +60 -0
- datalab/data/icons/io/fileopen_h5.svg +84 -0
- datalab/data/icons/io/fileopen_ima.svg +187 -0
- datalab/data/icons/io/fileopen_py.svg +123 -0
- datalab/data/icons/io/fileopen_sig.svg +138 -0
- datalab/data/icons/io/filesave_h5.svg +97 -0
- datalab/data/icons/io/filesave_ima.svg +200 -0
- datalab/data/icons/io/filesave_py.svg +136 -0
- datalab/data/icons/io/filesave_sig.svg +151 -0
- datalab/data/icons/io/import_text.svg +144 -0
- datalab/data/icons/io/save_to_directory.svg +134 -0
- datalab/data/icons/io.svg +84 -0
- datalab/data/icons/libre-camera-flash-off.svg +1 -0
- datalab/data/icons/libre-camera-flash-on.svg +1 -0
- datalab/data/icons/libre-gui-about.svg +1 -0
- datalab/data/icons/libre-gui-action-delete.svg +1 -0
- datalab/data/icons/libre-gui-add.svg +1 -0
- datalab/data/icons/libre-gui-arrow-down.svg +1 -0
- datalab/data/icons/libre-gui-arrow-left.svg +1 -0
- datalab/data/icons/libre-gui-arrow-right.svg +1 -0
- datalab/data/icons/libre-gui-arrow-up.svg +1 -0
- datalab/data/icons/libre-gui-close.svg +40 -0
- datalab/data/icons/libre-gui-cogs.svg +1 -0
- datalab/data/icons/libre-gui-globe.svg +1 -0
- datalab/data/icons/libre-gui-help.svg +1 -0
- datalab/data/icons/libre-gui-link.svg +1 -0
- datalab/data/icons/libre-gui-menu.svg +1 -0
- datalab/data/icons/libre-gui-pencil.svg +1 -0
- datalab/data/icons/libre-gui-plugin.svg +1 -0
- datalab/data/icons/libre-gui-questions.svg +1 -0
- datalab/data/icons/libre-gui-settings.svg +1 -0
- datalab/data/icons/libre-gui-unlink.svg +1 -0
- datalab/data/icons/libre-tech-ram.svg +1 -0
- datalab/data/icons/libre-toolbox.svg +1 -0
- datalab/data/icons/logs.svg +1 -0
- datalab/data/icons/markers.svg +74 -0
- datalab/data/icons/menu.svg +13 -0
- datalab/data/icons/new_ima.svg +148 -0
- datalab/data/icons/new_sig.svg +123 -0
- datalab/data/icons/operations/abs.svg +116 -0
- datalab/data/icons/operations/arithmetic.svg +123 -0
- datalab/data/icons/operations/average.svg +124 -0
- datalab/data/icons/operations/complex_from_magnitude_phase.svg +116 -0
- datalab/data/icons/operations/complex_from_real_imag.svg +124 -0
- datalab/data/icons/operations/constant.svg +116 -0
- datalab/data/icons/operations/constant_add.svg +109 -0
- datalab/data/icons/operations/constant_divide.svg +109 -0
- datalab/data/icons/operations/constant_multiply.svg +109 -0
- datalab/data/icons/operations/constant_subtract.svg +109 -0
- datalab/data/icons/operations/convert_dtype.svg +117 -0
- datalab/data/icons/operations/convolution.svg +46 -0
- datalab/data/icons/operations/deconvolution.svg +57 -0
- datalab/data/icons/operations/derivative.svg +127 -0
- datalab/data/icons/operations/difference.svg +52 -0
- datalab/data/icons/operations/division.svg +139 -0
- datalab/data/icons/operations/exp.svg +116 -0
- datalab/data/icons/operations/flip_horizontally.svg +69 -0
- datalab/data/icons/operations/flip_vertically.svg +74 -0
- datalab/data/icons/operations/im.svg +124 -0
- datalab/data/icons/operations/integral.svg +50 -0
- datalab/data/icons/operations/inverse.svg +143 -0
- datalab/data/icons/operations/log10.svg +109 -0
- datalab/data/icons/operations/phase.svg +116 -0
- datalab/data/icons/operations/power.svg +118 -0
- datalab/data/icons/operations/product.svg +124 -0
- datalab/data/icons/operations/profile.svg +379 -0
- datalab/data/icons/operations/profile_average.svg +399 -0
- datalab/data/icons/operations/profile_radial.svg +261 -0
- datalab/data/icons/operations/profile_segment.svg +262 -0
- datalab/data/icons/operations/quadratic_difference.svg +84 -0
- datalab/data/icons/operations/re.svg +124 -0
- datalab/data/icons/operations/rotate_left.svg +72 -0
- datalab/data/icons/operations/rotate_right.svg +72 -0
- datalab/data/icons/operations/signals_to_image.svg +314 -0
- datalab/data/icons/operations/sqrt.svg +110 -0
- datalab/data/icons/operations/std.svg +124 -0
- datalab/data/icons/operations/sum.svg +102 -0
- datalab/data/icons/play_demo.svg +9 -0
- datalab/data/icons/processing/axis_transform.svg +62 -0
- datalab/data/icons/processing/bandpass.svg +79 -0
- datalab/data/icons/processing/bandstop.svg +71 -0
- datalab/data/icons/processing/binning.svg +126 -0
- datalab/data/icons/processing/clip.svg +119 -0
- datalab/data/icons/processing/detrending.svg +173 -0
- datalab/data/icons/processing/distribute_on_grid.svg +769 -0
- datalab/data/icons/processing/edge_detection.svg +46 -0
- datalab/data/icons/processing/erase.svg +1 -0
- datalab/data/icons/processing/exposure.svg +143 -0
- datalab/data/icons/processing/fourier.svg +104 -0
- datalab/data/icons/processing/highpass.svg +59 -0
- datalab/data/icons/processing/interpolation.svg +71 -0
- datalab/data/icons/processing/level_adjustment.svg +70 -0
- datalab/data/icons/processing/lowpass.svg +60 -0
- datalab/data/icons/processing/morphology.svg +49 -0
- datalab/data/icons/processing/noise_addition.svg +114 -0
- datalab/data/icons/processing/noise_reduction.svg +38 -0
- datalab/data/icons/processing/normalize.svg +84 -0
- datalab/data/icons/processing/offset_correction.svg +131 -0
- datalab/data/icons/processing/resampling1d.svg +101 -0
- datalab/data/icons/processing/resampling2d.svg +240 -0
- datalab/data/icons/processing/reset_positions.svg +185 -0
- datalab/data/icons/processing/resize.svg +9 -0
- datalab/data/icons/processing/reverse_signal_x.svg +171 -0
- datalab/data/icons/processing/stability.svg +11 -0
- datalab/data/icons/processing/swap_x_y.svg +65 -0
- datalab/data/icons/processing/thresholding.svg +63 -0
- datalab/data/icons/processing/windowing.svg +45 -0
- datalab/data/icons/properties.svg +26 -0
- datalab/data/icons/reset.svg +9 -0
- datalab/data/icons/restore.svg +40 -0
- datalab/data/icons/roi/roi.svg +76 -0
- datalab/data/icons/roi/roi_coordinate.svg +78 -0
- datalab/data/icons/roi/roi_copy.svg +112 -0
- datalab/data/icons/roi/roi_delete.svg +81 -0
- datalab/data/icons/roi/roi_export.svg +87 -0
- datalab/data/icons/roi/roi_graphical.svg +78 -0
- datalab/data/icons/roi/roi_grid.svg +67 -0
- datalab/data/icons/roi/roi_ima.svg +188 -0
- datalab/data/icons/roi/roi_import.svg +87 -0
- datalab/data/icons/roi/roi_new.svg +81 -0
- datalab/data/icons/roi/roi_new_circle.svg +95 -0
- datalab/data/icons/roi/roi_new_polygon.svg +110 -0
- datalab/data/icons/roi/roi_new_rectangle.svg +70 -0
- datalab/data/icons/roi/roi_paste.svg +98 -0
- datalab/data/icons/roi/roi_sig.svg +124 -0
- datalab/data/icons/shapes.svg +134 -0
- datalab/data/icons/signal.svg +103 -0
- datalab/data/icons/table.svg +85 -0
- datalab/data/icons/table_unavailable.svg +102 -0
- datalab/data/icons/to_signal.svg +124 -0
- datalab/data/icons/tour/next.svg +44 -0
- datalab/data/icons/tour/previous.svg +44 -0
- datalab/data/icons/tour/rewind.svg +51 -0
- datalab/data/icons/tour/stop.svg +47 -0
- datalab/data/icons/tour/tour.svg +16 -0
- datalab/data/icons/uncheck_all.svg +78 -0
- datalab/data/icons/view/curve_antialiasing.svg +50 -0
- datalab/data/icons/view/new_window.svg +98 -0
- datalab/data/icons/view/refresh-auto.svg +57 -0
- datalab/data/icons/view/refresh-manual.svg +51 -0
- datalab/data/icons/view/reset_curve_styles.svg +96 -0
- datalab/data/icons/view/show_first.svg +55 -0
- datalab/data/icons/view/show_titles.svg +46 -0
- datalab/data/icons/visualization.svg +51 -0
- datalab/data/logo/DataLab-Banner-150.png +0 -0
- datalab/data/logo/DataLab-Banner-200.png +0 -0
- datalab/data/logo/DataLab-Banner2-100.png +0 -0
- datalab/data/logo/DataLab-Splash.png +0 -0
- datalab/data/logo/DataLab-watermark.png +0 -0
- datalab/data/logo/DataLab.svg +83 -0
- datalab/data/tests/reordering_test.h5 +0 -0
- datalab/data/tutorials/fabry_perot/fabry-perot1.jpg +0 -0
- datalab/data/tutorials/fabry_perot/fabry-perot2.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_13.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_18.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_23.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_30.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_35.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_40.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_45.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_50.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_55.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_60.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_65.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_70.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_75.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_80.jpg +0 -0
- datalab/env.py +542 -0
- datalab/gui/__init__.py +89 -0
- datalab/gui/actionhandler.py +1701 -0
- datalab/gui/docks.py +473 -0
- datalab/gui/h5io.py +150 -0
- datalab/gui/macroeditor.py +310 -0
- datalab/gui/main.py +2081 -0
- datalab/gui/newobject.py +217 -0
- datalab/gui/objectview.py +766 -0
- datalab/gui/panel/__init__.py +48 -0
- datalab/gui/panel/base.py +3254 -0
- datalab/gui/panel/image.py +157 -0
- datalab/gui/panel/macro.py +607 -0
- datalab/gui/panel/signal.py +164 -0
- datalab/gui/plothandler.py +800 -0
- datalab/gui/processor/__init__.py +84 -0
- datalab/gui/processor/base.py +2456 -0
- datalab/gui/processor/catcher.py +75 -0
- datalab/gui/processor/image.py +1214 -0
- datalab/gui/processor/signal.py +755 -0
- datalab/gui/profiledialog.py +333 -0
- datalab/gui/roieditor.py +633 -0
- datalab/gui/roigrideditor.py +208 -0
- datalab/gui/settings.py +612 -0
- datalab/gui/tour.py +908 -0
- datalab/h5/__init__.py +12 -0
- datalab/h5/common.py +314 -0
- datalab/h5/generic.py +580 -0
- datalab/h5/native.py +39 -0
- datalab/h5/utils.py +95 -0
- datalab/objectmodel.py +640 -0
- datalab/plugins/_readme_.txt +9 -0
- datalab/plugins/datalab_imageformats.py +175 -0
- datalab/plugins/datalab_testdata.py +190 -0
- datalab/plugins.py +355 -0
- datalab/tests/__init__.py +199 -0
- datalab/tests/backbone/__init__.py +1 -0
- datalab/tests/backbone/config_unit_test.py +170 -0
- datalab/tests/backbone/config_versioning_unit_test.py +34 -0
- datalab/tests/backbone/dictlistserial_app_test.py +38 -0
- datalab/tests/backbone/errorcatcher_unit_test.py +69 -0
- datalab/tests/backbone/errormsgbox_unit_test.py +50 -0
- datalab/tests/backbone/execenv_unit.py +262 -0
- datalab/tests/backbone/loadtest_gdi.py +147 -0
- datalab/tests/backbone/long_callback.py +96 -0
- datalab/tests/backbone/main_app_test.py +137 -0
- datalab/tests/backbone/memory_leak.py +43 -0
- datalab/tests/backbone/procisolation1_unit.py +128 -0
- datalab/tests/backbone/procisolation2_unit.py +171 -0
- datalab/tests/backbone/procisolation_unit_test.py +22 -0
- datalab/tests/backbone/profiling_app.py +27 -0
- datalab/tests/backbone/strings_unit_test.py +65 -0
- datalab/tests/backbone/title_formatting_unit_test.py +82 -0
- datalab/tests/conftest.py +131 -0
- datalab/tests/features/__init__.py +1 -0
- datalab/tests/features/applauncher/__init__.py +1 -0
- datalab/tests/features/applauncher/launcher1_app_test.py +28 -0
- datalab/tests/features/applauncher/launcher2_app_test.py +30 -0
- datalab/tests/features/common/__init__.py +1 -0
- datalab/tests/features/common/add_metadata_app_test.py +134 -0
- datalab/tests/features/common/add_metadata_unit_test.py +267 -0
- datalab/tests/features/common/annotations_management_unit_test.py +152 -0
- datalab/tests/features/common/auto_analysis_recompute_unit_test.py +240 -0
- datalab/tests/features/common/createobject_unit_test.py +50 -0
- datalab/tests/features/common/geometry_results_app_test.py +135 -0
- datalab/tests/features/common/interactive_processing_test.py +1109 -0
- datalab/tests/features/common/io_app_test.py +75 -0
- datalab/tests/features/common/large_results_app_test.py +187 -0
- datalab/tests/features/common/metadata_all_patterns_test.py +103 -0
- datalab/tests/features/common/metadata_app_test.py +139 -0
- datalab/tests/features/common/metadata_io_unit_test.py +60 -0
- datalab/tests/features/common/misc_app_test.py +236 -0
- datalab/tests/features/common/multiple_geometry_results_unit_test.py +122 -0
- datalab/tests/features/common/multiple_table_results_unit_test.py +64 -0
- datalab/tests/features/common/operation_modes_app_test.py +392 -0
- datalab/tests/features/common/plot_results_app_test.py +278 -0
- datalab/tests/features/common/reorder_app_test.py +75 -0
- datalab/tests/features/common/result_deletion_unit_test.py +96 -0
- datalab/tests/features/common/result_merged_label_unit_test.py +154 -0
- datalab/tests/features/common/result_shape_settings_unit_test.py +223 -0
- datalab/tests/features/common/roi_plotitem_unit_test.py +64 -0
- datalab/tests/features/common/roieditor_unit_test.py +102 -0
- datalab/tests/features/common/save_to_dir_app_test.py +163 -0
- datalab/tests/features/common/save_to_dir_unit_test.py +474 -0
- datalab/tests/features/common/stat_app_test.py +40 -0
- datalab/tests/features/common/stats_tools_unit_test.py +77 -0
- datalab/tests/features/common/table_results_app_test.py +52 -0
- datalab/tests/features/common/textimport_unit_test.py +131 -0
- datalab/tests/features/common/uuid_preservation_test.py +281 -0
- datalab/tests/features/common/worker_unit_test.py +402 -0
- datalab/tests/features/control/__init__.py +1 -0
- datalab/tests/features/control/connect_dialog.py +28 -0
- datalab/tests/features/control/embedded1_unit_test.py +304 -0
- datalab/tests/features/control/embedded2_unit_test.py +52 -0
- datalab/tests/features/control/remoteclient_app_test.py +219 -0
- datalab/tests/features/control/remoteclient_unit.py +75 -0
- datalab/tests/features/control/simpleclient_unit_test.py +321 -0
- datalab/tests/features/hdf5/__init__.py +1 -0
- datalab/tests/features/hdf5/h5browser1_unit_test.py +31 -0
- datalab/tests/features/hdf5/h5browser2_unit.py +55 -0
- datalab/tests/features/hdf5/h5browser_app_test.py +77 -0
- datalab/tests/features/hdf5/h5import_app_test.py +25 -0
- datalab/tests/features/hdf5/h5importer_app_test.py +34 -0
- datalab/tests/features/image/__init__.py +1 -0
- datalab/tests/features/image/annotations_app_test.py +28 -0
- datalab/tests/features/image/annotations_unit_test.py +80 -0
- datalab/tests/features/image/average_app_test.py +46 -0
- datalab/tests/features/image/background_dialog_test.py +70 -0
- datalab/tests/features/image/blobs_app_test.py +50 -0
- datalab/tests/features/image/contour_app_test.py +42 -0
- datalab/tests/features/image/contour_fabryperot_app_test.py +51 -0
- datalab/tests/features/image/denoise_app_test.py +31 -0
- datalab/tests/features/image/distribute_on_grid_app_test.py +95 -0
- datalab/tests/features/image/edges_app_test.py +31 -0
- datalab/tests/features/image/erase_app_test.py +21 -0
- datalab/tests/features/image/fft2d_app_test.py +27 -0
- datalab/tests/features/image/flatfield_app_test.py +40 -0
- datalab/tests/features/image/geometry_transform_unit_test.py +396 -0
- datalab/tests/features/image/imagetools_app_test.py +51 -0
- datalab/tests/features/image/imagetools_unit_test.py +27 -0
- datalab/tests/features/image/load_app_test.py +73 -0
- datalab/tests/features/image/morph_app_test.py +32 -0
- datalab/tests/features/image/offsetcorrection_app_test.py +30 -0
- datalab/tests/features/image/peak2d_app_test.py +53 -0
- datalab/tests/features/image/profile_app_test.py +73 -0
- datalab/tests/features/image/profile_dialog_test.py +56 -0
- datalab/tests/features/image/roi_app_test.py +98 -0
- datalab/tests/features/image/roi_circ_app_test.py +62 -0
- datalab/tests/features/image/roi_manipulation_app_test.py +268 -0
- datalab/tests/features/image/roigrid_unit_test.py +60 -0
- datalab/tests/features/image/side_by_side_app_test.py +52 -0
- datalab/tests/features/macro/__init__.py +1 -0
- datalab/tests/features/macro/macro_app_test.py +28 -0
- datalab/tests/features/macro/macroeditor_unit_test.py +102 -0
- datalab/tests/features/signal/__init__.py +1 -0
- datalab/tests/features/signal/baseline_dialog_test.py +53 -0
- datalab/tests/features/signal/deltax_dialog_unit_test.py +34 -0
- datalab/tests/features/signal/fft1d_app_test.py +26 -0
- datalab/tests/features/signal/filter_app_test.py +44 -0
- datalab/tests/features/signal/fitdialog_unit_test.py +50 -0
- datalab/tests/features/signal/interpolation_app_test.py +110 -0
- datalab/tests/features/signal/loadbigsignal_app_test.py +80 -0
- datalab/tests/features/signal/multiple_rois_unit_test.py +132 -0
- datalab/tests/features/signal/pulse_features_app_test.py +118 -0
- datalab/tests/features/signal/pulse_features_roi_app_test.py +55 -0
- datalab/tests/features/signal/roi_app_test.py +78 -0
- datalab/tests/features/signal/roi_manipulation_app_test.py +261 -0
- datalab/tests/features/signal/select_xy_cursor_unit_test.py +46 -0
- datalab/tests/features/signal/signalpeakdetection_dialog_test.py +33 -0
- datalab/tests/features/signal/signals_to_image_app_test.py +98 -0
- datalab/tests/features/signal/xarray_compat_app_test.py +128 -0
- datalab/tests/features/tour_unit_test.py +22 -0
- datalab/tests/features/utilities/__init__.py +1 -0
- datalab/tests/features/utilities/installconf_unit_test.py +21 -0
- datalab/tests/features/utilities/logview_app_test.py +21 -0
- datalab/tests/features/utilities/logview_error.py +24 -0
- datalab/tests/features/utilities/logview_unit_test.py +21 -0
- datalab/tests/features/utilities/memstatus_app_test.py +42 -0
- datalab/tests/features/utilities/settings_unit_test.py +88 -0
- datalab/tests/scenarios/__init__.py +1 -0
- datalab/tests/scenarios/beautiful_app.py +121 -0
- datalab/tests/scenarios/common.py +463 -0
- datalab/tests/scenarios/demo.py +212 -0
- datalab/tests/scenarios/example_app_test.py +47 -0
- datalab/tests/scenarios/scenario_h5_app_test.py +75 -0
- datalab/tests/scenarios/scenario_ima1_app_test.py +34 -0
- datalab/tests/scenarios/scenario_ima2_app_test.py +34 -0
- datalab/tests/scenarios/scenario_mac_app_test.py +58 -0
- datalab/tests/scenarios/scenario_sig1_app_test.py +36 -0
- datalab/tests/scenarios/scenario_sig2_app_test.py +35 -0
- datalab/utils/__init__.py +1 -0
- datalab/utils/conf.py +304 -0
- datalab/utils/dephash.py +105 -0
- datalab/utils/qthelpers.py +633 -0
- datalab/utils/strings.py +34 -0
- datalab/utils/tests.py +0 -0
- datalab/widgets/__init__.py +1 -0
- datalab/widgets/connection.py +138 -0
- datalab/widgets/filedialog.py +91 -0
- datalab/widgets/fileviewer.py +84 -0
- datalab/widgets/fitdialog.py +788 -0
- datalab/widgets/h5browser.py +1048 -0
- datalab/widgets/imagebackground.py +111 -0
- datalab/widgets/instconfviewer.py +175 -0
- datalab/widgets/logviewer.py +80 -0
- datalab/widgets/signalbaseline.py +90 -0
- datalab/widgets/signalcursor.py +208 -0
- datalab/widgets/signaldeltax.py +151 -0
- datalab/widgets/signalpeak.py +199 -0
- datalab/widgets/status.py +249 -0
- datalab/widgets/textimport.py +786 -0
- datalab/widgets/warningerror.py +223 -0
- datalab/widgets/wizard.py +286 -0
- datalab_platform-1.0.1.dist-info/METADATA +121 -0
- datalab_platform-1.0.1.dist-info/RECORD +494 -0
- datalab_platform-0.0.1.dev0.dist-info/METADATA +0 -67
- datalab_platform-0.0.1.dev0.dist-info/RECORD +0 -7
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/WHEEL +0 -0
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/entry_points.txt +0 -0
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
.. Macro panel (see parent package :mod:`datalab.gui.panel`)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# pylint: disable=invalid-name # Allows short reference names like x, y, ...
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os.path as osp
|
|
12
|
+
import re
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
from guidata.config import CONF
|
|
16
|
+
from guidata.configtools import get_font, get_icon
|
|
17
|
+
from guidata.qthelpers import add_actions, create_action
|
|
18
|
+
from guidata.widgets.console.shell import PythonShellWidget
|
|
19
|
+
from guidata.widgets.dockable import DockableWidgetMixin
|
|
20
|
+
from qtpy import QtCore as QC
|
|
21
|
+
from qtpy import QtWidgets as QW
|
|
22
|
+
from qtpy.compat import getopenfilename, getsavefilename
|
|
23
|
+
|
|
24
|
+
from datalab.config import Conf, _
|
|
25
|
+
from datalab.env import execenv
|
|
26
|
+
from datalab.gui.macroeditor import Macro
|
|
27
|
+
from datalab.gui.panel.base import AbstractPanel
|
|
28
|
+
from datalab.utils.qthelpers import (
|
|
29
|
+
create_menu_button,
|
|
30
|
+
qt_try_loadsave_file,
|
|
31
|
+
save_restore_stds,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
if TYPE_CHECKING:
|
|
35
|
+
from guidata.widgets.codeeditor import CodeEditor
|
|
36
|
+
|
|
37
|
+
from datalab.h5.native import NativeH5Reader, NativeH5Writer
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class MacroTabs(QW.QTabWidget):
|
|
41
|
+
"""Macro tabwidget
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
parent (QWidget): Parent widget
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
SIG_CONTEXT_MENU = QC.Signal(QC.QPoint)
|
|
48
|
+
SIG_RENAME = QC.Signal(int)
|
|
49
|
+
SIG_REMOVE = QC.Signal(int)
|
|
50
|
+
|
|
51
|
+
def __init__(self, parent=None) -> None:
|
|
52
|
+
super().__init__(parent)
|
|
53
|
+
self.setTabsClosable(True)
|
|
54
|
+
self.setMovable(True)
|
|
55
|
+
self.tabBarDoubleClicked.connect(self.__rename)
|
|
56
|
+
self.tabCloseRequested.connect(self.__remove)
|
|
57
|
+
self.__titles: list[str] = []
|
|
58
|
+
|
|
59
|
+
def clear(self) -> None:
|
|
60
|
+
"""Override Qt method"""
|
|
61
|
+
super().clear()
|
|
62
|
+
self.__titles.clear()
|
|
63
|
+
|
|
64
|
+
def contextMenuEvent(self, event): # pylint: disable=C0103
|
|
65
|
+
"""Override Qt method"""
|
|
66
|
+
self.SIG_CONTEXT_MENU.emit(event.globalPos())
|
|
67
|
+
|
|
68
|
+
def __rename(self, index: int) -> None:
|
|
69
|
+
"""Rename tab
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
index: Index of the tab
|
|
73
|
+
"""
|
|
74
|
+
self.SIG_RENAME.emit(index + 1)
|
|
75
|
+
|
|
76
|
+
def __remove(self, index: int) -> None:
|
|
77
|
+
"""Remove tab
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
index: Index of the tab
|
|
81
|
+
"""
|
|
82
|
+
self.SIG_REMOVE.emit(index + 1)
|
|
83
|
+
|
|
84
|
+
def __update_tab_titles(self) -> None:
|
|
85
|
+
"""Update tab titles"""
|
|
86
|
+
for number, title in enumerate(self.__titles, 1):
|
|
87
|
+
self.setTabText(number - 1, f"{number:02d}: {title}")
|
|
88
|
+
|
|
89
|
+
def add_tab(self, macro: Macro) -> int:
|
|
90
|
+
"""Add tab
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
macro: Macro object
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
int: Number of the tab (starting at 1)
|
|
97
|
+
"""
|
|
98
|
+
self.__titles.append(macro.title)
|
|
99
|
+
index = self.addTab(macro.editor, "")
|
|
100
|
+
self.__update_tab_titles()
|
|
101
|
+
return index + 1 # Numbering starts at 1
|
|
102
|
+
|
|
103
|
+
def remove_tab(self, number: int) -> None:
|
|
104
|
+
"""Remove tab
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
number: Number of the tab (starting at 1)
|
|
108
|
+
"""
|
|
109
|
+
self.removeTab(number - 1)
|
|
110
|
+
self.__titles.pop(number - 1)
|
|
111
|
+
self.__update_tab_titles()
|
|
112
|
+
|
|
113
|
+
def get_widget(self, number: int) -> CodeEditor:
|
|
114
|
+
"""Return macro editor widget at number
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
number: Number of the tab (starting at 1)
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Macro editor widget
|
|
121
|
+
"""
|
|
122
|
+
return self.widget(number - 1)
|
|
123
|
+
|
|
124
|
+
def set_current_number(self, number: int) -> None:
|
|
125
|
+
"""Set current tab number
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
number: Number of the tab (starting at 1)
|
|
129
|
+
"""
|
|
130
|
+
self.setCurrentIndex(number - 1)
|
|
131
|
+
|
|
132
|
+
def get_current_number(self) -> int:
|
|
133
|
+
"""Return current tab number
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
int: Number of the tab (starting at 1)
|
|
137
|
+
"""
|
|
138
|
+
return self.currentIndex() + 1
|
|
139
|
+
|
|
140
|
+
def set_tab_title(self, number: int, name: str) -> None:
|
|
141
|
+
"""Set tab title
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
number: Number of the tab (starting at 1)
|
|
145
|
+
name: Macro name
|
|
146
|
+
"""
|
|
147
|
+
self.__titles[number - 1] = name
|
|
148
|
+
self.__update_tab_titles()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class MacroPanel(AbstractPanel, DockableWidgetMixin):
|
|
152
|
+
"""Macro Panel widget
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
parent (QWidget): Parent widget
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
LOCATION = QC.Qt.RightDockWidgetArea
|
|
159
|
+
PANEL_STR = _("Macro panel")
|
|
160
|
+
|
|
161
|
+
H5_PREFIX = "DataLab_Mac"
|
|
162
|
+
|
|
163
|
+
SIG_OBJECT_MODIFIED = QC.Signal()
|
|
164
|
+
|
|
165
|
+
FILE_FILTERS = f"{_('Python files')} (*.py)"
|
|
166
|
+
|
|
167
|
+
def __init__(self, parent: QW.QMainWindow) -> None:
|
|
168
|
+
super().__init__(parent)
|
|
169
|
+
self.setWindowTitle(self.PANEL_STR)
|
|
170
|
+
self.setWindowIcon(get_icon("libre-gui-cogs.svg"))
|
|
171
|
+
self.setOrientation(QC.Qt.Vertical)
|
|
172
|
+
|
|
173
|
+
self.context_menu = QW.QMenu()
|
|
174
|
+
self.tabwidget_tb = QW.QToolBar(self)
|
|
175
|
+
self.tabwidget_tb.setOrientation(QC.Qt.Vertical)
|
|
176
|
+
|
|
177
|
+
self.console = PythonShellWidget(self, read_only=True)
|
|
178
|
+
self.console.setMaximumBlockCount(5000)
|
|
179
|
+
font = get_font(CONF, "console")
|
|
180
|
+
font.setPointSize(10)
|
|
181
|
+
self.console.set_font(font)
|
|
182
|
+
self.console.write(_("-***- Macro Console -***-"), prompt=True)
|
|
183
|
+
|
|
184
|
+
self.tabwidget = MacroTabs(self)
|
|
185
|
+
self.tabwidget.SIG_RENAME.connect(self.rename_macro)
|
|
186
|
+
self.tabwidget.SIG_REMOVE.connect(self.remove_macro)
|
|
187
|
+
self.tabwidget.currentChanged.connect(self.__update_actions)
|
|
188
|
+
|
|
189
|
+
tabwidget_with_tb = QW.QWidget(self)
|
|
190
|
+
tabwidget_with_tb.setLayout(QW.QHBoxLayout())
|
|
191
|
+
tabwidget_with_tb.layout().addWidget(self.tabwidget_tb)
|
|
192
|
+
tabwidget_with_tb.layout().addWidget(self.tabwidget)
|
|
193
|
+
|
|
194
|
+
# Put console in a groupbox to have a title
|
|
195
|
+
console_groupbox = QW.QGroupBox(_("Console"), self)
|
|
196
|
+
console_groupbox.setLayout(QW.QHBoxLayout())
|
|
197
|
+
console_groupbox.layout().addWidget(self.console)
|
|
198
|
+
# Put console groupbox in a frame to have a nice margin
|
|
199
|
+
console_frame = QW.QFrame(self)
|
|
200
|
+
console_frame.setLayout(QW.QHBoxLayout())
|
|
201
|
+
console_frame.layout().addWidget(console_groupbox)
|
|
202
|
+
|
|
203
|
+
for widget in (tabwidget_with_tb, console_frame):
|
|
204
|
+
self.addWidget(widget)
|
|
205
|
+
self.setStretchFactor(0, 2)
|
|
206
|
+
self.setStretchFactor(1, 1)
|
|
207
|
+
|
|
208
|
+
self.run_action = None
|
|
209
|
+
self.stop_action = None
|
|
210
|
+
self.obj_actions: list[QW.QAction] = [] # Object-dependent actions
|
|
211
|
+
self.__macros: list[Macro] = []
|
|
212
|
+
|
|
213
|
+
self.setup_actions()
|
|
214
|
+
|
|
215
|
+
def update_color_mode(self) -> None:
|
|
216
|
+
"""Update color mode according to the current theme"""
|
|
217
|
+
self.console.update_color_mode()
|
|
218
|
+
for macro in self.__macros:
|
|
219
|
+
macro.editor.update_color_mode()
|
|
220
|
+
|
|
221
|
+
# ------AbstractPanel interface-----------------------------------------------------
|
|
222
|
+
# pylint: disable=unused-argument
|
|
223
|
+
def get_serializable_name(self, obj: Macro) -> str:
|
|
224
|
+
"""Return serializable name of object"""
|
|
225
|
+
title = re.sub("[^-a-zA-Z0-9_.() ]+", "", obj.title.replace("/", "_"))
|
|
226
|
+
name = f"{obj.PREFIX}{(self.__macros.index(obj) + 1):03d}: {title}"
|
|
227
|
+
return name
|
|
228
|
+
|
|
229
|
+
def serialize_to_hdf5(self, writer: NativeH5Writer) -> None:
|
|
230
|
+
"""Serialize whole panel to a HDF5 file
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
writer: HDF5 writer
|
|
234
|
+
"""
|
|
235
|
+
with writer.group(self.H5_PREFIX):
|
|
236
|
+
for obj in self.__macros:
|
|
237
|
+
self.serialize_object_to_hdf5(obj, writer)
|
|
238
|
+
|
|
239
|
+
def deserialize_from_hdf5(
|
|
240
|
+
self, reader: NativeH5Reader, reset_all: bool = False
|
|
241
|
+
) -> None:
|
|
242
|
+
"""Deserialize whole panel from a HDF5 file
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
reader: HDF5 reader
|
|
246
|
+
reset_all: If True, preserve original UUIDs (workspace reload).
|
|
247
|
+
If False, regenerate UUIDs (importing objects).
|
|
248
|
+
"""
|
|
249
|
+
with reader.group(self.H5_PREFIX):
|
|
250
|
+
for name in reader.h5.get(self.H5_PREFIX, []):
|
|
251
|
+
# Contrary to signal or image panels, macros are not stored
|
|
252
|
+
# in a group but directly in the root of the HDF5 file
|
|
253
|
+
obj = self.deserialize_object_from_hdf5(reader, name, reset_all)
|
|
254
|
+
self.add_object(obj)
|
|
255
|
+
|
|
256
|
+
def __len__(self) -> int:
|
|
257
|
+
"""Return number of objects"""
|
|
258
|
+
return len(self.__macros)
|
|
259
|
+
|
|
260
|
+
def __getitem__(self, nb: int) -> Macro:
|
|
261
|
+
"""Return object from its number (1 to N)"""
|
|
262
|
+
return self.__macros[nb - 1]
|
|
263
|
+
|
|
264
|
+
def __iter__(self):
|
|
265
|
+
"""Iterate over objects"""
|
|
266
|
+
return iter(self.__macros)
|
|
267
|
+
|
|
268
|
+
def create_object(self) -> Macro:
|
|
269
|
+
"""Create object.
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
Macro object
|
|
273
|
+
"""
|
|
274
|
+
macro = Macro(self.console)
|
|
275
|
+
macro.objectNameChanged.connect(self.macro_name_changed)
|
|
276
|
+
macro.STARTED.connect(
|
|
277
|
+
lambda orig_macro=macro: self.macro_state_changed(orig_macro, True)
|
|
278
|
+
)
|
|
279
|
+
macro.FINISHED.connect(
|
|
280
|
+
lambda orig_macro=macro: self.macro_state_changed(orig_macro, False)
|
|
281
|
+
)
|
|
282
|
+
macro.MODIFIED.connect(self.macro_contents_changed)
|
|
283
|
+
return macro
|
|
284
|
+
|
|
285
|
+
def add_object(self, obj: Macro) -> None:
|
|
286
|
+
"""Add object.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
obj: Macro object
|
|
290
|
+
"""
|
|
291
|
+
self.__macros.append(obj)
|
|
292
|
+
number = self.tabwidget.add_tab(obj)
|
|
293
|
+
self.SIG_OBJECT_ADDED.emit()
|
|
294
|
+
self.tabwidget.set_current_number(number)
|
|
295
|
+
|
|
296
|
+
def remove_all_objects(self) -> None:
|
|
297
|
+
"""Remove all objects"""
|
|
298
|
+
self.tabwidget.clear()
|
|
299
|
+
self.__macros.clear()
|
|
300
|
+
super().remove_all_objects()
|
|
301
|
+
|
|
302
|
+
# ---- Macro panel API -------------------------------------------------------------
|
|
303
|
+
def setup_actions(self) -> None:
|
|
304
|
+
"""Setup macro menu actions"""
|
|
305
|
+
self.run_action = create_action(
|
|
306
|
+
self,
|
|
307
|
+
_("Run macro"),
|
|
308
|
+
icon=get_icon("libre-camera-flash-on.svg"),
|
|
309
|
+
triggered=self.run_macro,
|
|
310
|
+
shortcut="Ctrl+F5",
|
|
311
|
+
)
|
|
312
|
+
self.stop_action = create_action(
|
|
313
|
+
self,
|
|
314
|
+
_("Stop macro"),
|
|
315
|
+
icon=get_icon("libre-camera-flash-off.svg"),
|
|
316
|
+
triggered=self.stop_macro,
|
|
317
|
+
shortcut="Shift+F5",
|
|
318
|
+
)
|
|
319
|
+
self.stop_action.setDisabled(True)
|
|
320
|
+
add_act = create_action(
|
|
321
|
+
self,
|
|
322
|
+
_("New macro"),
|
|
323
|
+
icon=get_icon("libre-gui-add.svg"),
|
|
324
|
+
triggered=self.add_macro,
|
|
325
|
+
)
|
|
326
|
+
ren_act = create_action(
|
|
327
|
+
self,
|
|
328
|
+
_("Rename macro"),
|
|
329
|
+
icon=get_icon("libre-gui-pencil.svg"),
|
|
330
|
+
triggered=self.rename_macro,
|
|
331
|
+
)
|
|
332
|
+
imp_act = create_action(
|
|
333
|
+
self,
|
|
334
|
+
_("Import macro from file"),
|
|
335
|
+
icon=get_icon("fileopen_py.svg"),
|
|
336
|
+
triggered=self.import_macro_from_file,
|
|
337
|
+
)
|
|
338
|
+
exp_act = create_action(
|
|
339
|
+
self,
|
|
340
|
+
_("Export macro to file"),
|
|
341
|
+
icon=get_icon("filesave_py.svg"),
|
|
342
|
+
triggered=self.export_macro_to_file,
|
|
343
|
+
)
|
|
344
|
+
rem_act = create_action(
|
|
345
|
+
self,
|
|
346
|
+
_("Remove macro"),
|
|
347
|
+
icon=get_icon("libre-gui-action-delete.svg"),
|
|
348
|
+
triggered=self.remove_macro,
|
|
349
|
+
)
|
|
350
|
+
self.obj_actions += [
|
|
351
|
+
self.run_action,
|
|
352
|
+
self.stop_action,
|
|
353
|
+
ren_act,
|
|
354
|
+
exp_act,
|
|
355
|
+
rem_act,
|
|
356
|
+
]
|
|
357
|
+
|
|
358
|
+
self.tabwidget.SIG_CONTEXT_MENU.connect(self.context_menu.popup)
|
|
359
|
+
|
|
360
|
+
tabwidget_corner = QW.QToolBar(_("Macro editor toolbar"), self)
|
|
361
|
+
self.context_menu.aboutToShow.connect(self.__update_actions)
|
|
362
|
+
tabwidget_menu_btn = create_menu_button(self, self.context_menu)
|
|
363
|
+
tabwidget_corner.addWidget(tabwidget_menu_btn)
|
|
364
|
+
self.tabwidget.setCornerWidget(tabwidget_corner)
|
|
365
|
+
|
|
366
|
+
main_actions = [
|
|
367
|
+
self.run_action,
|
|
368
|
+
self.stop_action,
|
|
369
|
+
None,
|
|
370
|
+
add_act,
|
|
371
|
+
ren_act,
|
|
372
|
+
imp_act,
|
|
373
|
+
exp_act,
|
|
374
|
+
]
|
|
375
|
+
add_actions(tabwidget_corner, [self.run_action, self.stop_action])
|
|
376
|
+
add_actions(self.tabwidget_tb, main_actions)
|
|
377
|
+
add_actions(self.context_menu, main_actions + [None, rem_act])
|
|
378
|
+
|
|
379
|
+
self.__update_actions()
|
|
380
|
+
|
|
381
|
+
def __update_actions(self) -> None:
|
|
382
|
+
"""Update actions"""
|
|
383
|
+
not_empty = self.tabwidget.count() > 0
|
|
384
|
+
for action in self.obj_actions:
|
|
385
|
+
action.setEnabled(not_empty)
|
|
386
|
+
if not_empty:
|
|
387
|
+
macro = self.get_macro()
|
|
388
|
+
if macro is not None:
|
|
389
|
+
macro: Macro
|
|
390
|
+
self.macro_state_changed(macro, macro.is_running())
|
|
391
|
+
|
|
392
|
+
def get_macro(self, number_or_title: int | str | None = None) -> Macro | None:
|
|
393
|
+
"""Return macro at number (if number is None, return current macro)
|
|
394
|
+
|
|
395
|
+
Args:
|
|
396
|
+
number: Number of the macro (starting at 1) or title of the macro.
|
|
397
|
+
Defaults to None (current macro).
|
|
398
|
+
|
|
399
|
+
Returns:
|
|
400
|
+
Macro object or None (if not found)
|
|
401
|
+
"""
|
|
402
|
+
if number_or_title is None:
|
|
403
|
+
number_or_title = self.tabwidget.get_current_number()
|
|
404
|
+
if isinstance(number_or_title, str):
|
|
405
|
+
return self.get_macro(self.get_number_from_title(number_or_title))
|
|
406
|
+
for macro in self.__macros:
|
|
407
|
+
if self.tabwidget.get_widget(number_or_title) is macro.editor:
|
|
408
|
+
return macro
|
|
409
|
+
return None
|
|
410
|
+
|
|
411
|
+
def get_number_from_title(self, title: str) -> int | None:
|
|
412
|
+
"""Return macro number from title
|
|
413
|
+
|
|
414
|
+
Args:
|
|
415
|
+
title: Title of the macro
|
|
416
|
+
|
|
417
|
+
Returns:
|
|
418
|
+
Number of the macro (starting at 1) or None (if not found)
|
|
419
|
+
"""
|
|
420
|
+
for number in range(1, self.tabwidget.count() + 1):
|
|
421
|
+
if self.tabwidget.tabText(number - 1).endswith(title):
|
|
422
|
+
return number
|
|
423
|
+
return None
|
|
424
|
+
|
|
425
|
+
def get_number_from_macro(self, macro: Macro) -> int | None:
|
|
426
|
+
"""Return macro number from macro object
|
|
427
|
+
|
|
428
|
+
Args:
|
|
429
|
+
macro: Macro object
|
|
430
|
+
|
|
431
|
+
Returns:
|
|
432
|
+
Number of the macro (starting at 1) or None (if not found)
|
|
433
|
+
"""
|
|
434
|
+
for number in range(1, self.tabwidget.count() + 1):
|
|
435
|
+
if self.tabwidget.get_widget(number) is macro.editor:
|
|
436
|
+
return number
|
|
437
|
+
return None
|
|
438
|
+
|
|
439
|
+
def get_macro_titles(self) -> list[str]:
|
|
440
|
+
"""Return list of macro titles"""
|
|
441
|
+
return [macro.title for macro in self.__macros]
|
|
442
|
+
|
|
443
|
+
def macro_contents_changed(self) -> None:
|
|
444
|
+
"""One of the macro contents has changed"""
|
|
445
|
+
self.SIG_OBJECT_MODIFIED.emit()
|
|
446
|
+
|
|
447
|
+
def run_macro(self, number_or_title: int | str | None = None) -> None:
|
|
448
|
+
"""Run current macro
|
|
449
|
+
|
|
450
|
+
Args:
|
|
451
|
+
number: Number of the macro (starting at 1). Defaults to None (run
|
|
452
|
+
current macro, or does nothing if there is no macro).
|
|
453
|
+
"""
|
|
454
|
+
macro = self.get_macro(number_or_title)
|
|
455
|
+
if macro is not None:
|
|
456
|
+
macro: Macro
|
|
457
|
+
macro.run()
|
|
458
|
+
|
|
459
|
+
def stop_macro(self, number_or_title: int | str | None = None) -> None:
|
|
460
|
+
"""Stop current macro
|
|
461
|
+
|
|
462
|
+
Args:
|
|
463
|
+
number: Number of the macro (starting at 1). Defaults to None (run
|
|
464
|
+
current macro, or does nothing if there is no macro).
|
|
465
|
+
"""
|
|
466
|
+
macro = self.get_macro(number_or_title)
|
|
467
|
+
if macro is not None:
|
|
468
|
+
macro: Macro
|
|
469
|
+
macro.kill()
|
|
470
|
+
|
|
471
|
+
def macro_state_changed(self, orig_macro: Macro, state: bool) -> None:
|
|
472
|
+
"""Macro state has changed (True: started, False: stopped)
|
|
473
|
+
|
|
474
|
+
Args:
|
|
475
|
+
orig_macro: Macro object
|
|
476
|
+
state: State of the macro
|
|
477
|
+
"""
|
|
478
|
+
macro = self.get_macro()
|
|
479
|
+
if macro is orig_macro:
|
|
480
|
+
self.run_action.setEnabled(not state)
|
|
481
|
+
self.stop_action.setEnabled(state)
|
|
482
|
+
|
|
483
|
+
def add_macro(self) -> Macro:
|
|
484
|
+
"""Add macro, optionally with name
|
|
485
|
+
|
|
486
|
+
Returns:
|
|
487
|
+
Macro object
|
|
488
|
+
"""
|
|
489
|
+
macro = self.create_object()
|
|
490
|
+
self.add_object(macro)
|
|
491
|
+
if not macro.title:
|
|
492
|
+
self.rename_macro()
|
|
493
|
+
return macro
|
|
494
|
+
|
|
495
|
+
def macro_name_changed(self, name: str) -> None:
|
|
496
|
+
"""Macro name has been changed
|
|
497
|
+
|
|
498
|
+
Args:
|
|
499
|
+
name: New name of the macro
|
|
500
|
+
"""
|
|
501
|
+
number = self.get_number_from_macro(self.sender())
|
|
502
|
+
if number is not None:
|
|
503
|
+
self.tabwidget.set_tab_title(number, name)
|
|
504
|
+
|
|
505
|
+
def rename_macro(self, number: int | None = None, title: str | None = None) -> None:
|
|
506
|
+
"""Rename macro
|
|
507
|
+
|
|
508
|
+
Args:
|
|
509
|
+
number: Number of the macro (starting at 1). Defaults to None.
|
|
510
|
+
title: Title of the macro. Defaults to None.
|
|
511
|
+
"""
|
|
512
|
+
macro = self.get_macro(number)
|
|
513
|
+
assert isinstance(macro, Macro)
|
|
514
|
+
if title is None:
|
|
515
|
+
title, valid = QW.QInputDialog.getText(
|
|
516
|
+
self,
|
|
517
|
+
_("Rename"),
|
|
518
|
+
_("New title:"),
|
|
519
|
+
QW.QLineEdit.Normal,
|
|
520
|
+
macro.title,
|
|
521
|
+
)
|
|
522
|
+
title = title if valid else None
|
|
523
|
+
if title:
|
|
524
|
+
macro.title = title
|
|
525
|
+
if number is not None:
|
|
526
|
+
self.tabwidget.set_current_number(number)
|
|
527
|
+
|
|
528
|
+
def export_macro_to_file(
|
|
529
|
+
self, number_or_title: int | str | None = None, filename: str | None = None
|
|
530
|
+
) -> None:
|
|
531
|
+
"""Export macro to file
|
|
532
|
+
|
|
533
|
+
Args:
|
|
534
|
+
number_or_title: Number of the macro (starting at 1) or title of the macro.
|
|
535
|
+
Defaults to None.
|
|
536
|
+
filename: Filename. Defaults to None.
|
|
537
|
+
|
|
538
|
+
Raises:
|
|
539
|
+
ValueError: If title is not found
|
|
540
|
+
"""
|
|
541
|
+
macro = self.get_macro(number_or_title)
|
|
542
|
+
assert isinstance(macro, Macro)
|
|
543
|
+
if filename is None:
|
|
544
|
+
basedir = Conf.main.base_dir.get()
|
|
545
|
+
with save_restore_stds():
|
|
546
|
+
filename, _filt = getsavefilename(
|
|
547
|
+
self, _("Save as"), basedir, self.FILE_FILTERS
|
|
548
|
+
)
|
|
549
|
+
if filename:
|
|
550
|
+
with qt_try_loadsave_file(self.parentWidget(), filename, "save"):
|
|
551
|
+
Conf.main.base_dir.set(filename)
|
|
552
|
+
macro.title = osp.basename(filename)
|
|
553
|
+
macro.to_file(filename)
|
|
554
|
+
|
|
555
|
+
def import_macro_from_file(self, filename: str | None = None) -> int:
|
|
556
|
+
"""Import macro from file
|
|
557
|
+
|
|
558
|
+
Args:
|
|
559
|
+
filename: Filename. Defaults to None.
|
|
560
|
+
|
|
561
|
+
Returns:
|
|
562
|
+
Number of the macro (starting at 1)
|
|
563
|
+
"""
|
|
564
|
+
if filename is None:
|
|
565
|
+
basedir = Conf.main.base_dir.get()
|
|
566
|
+
with save_restore_stds():
|
|
567
|
+
filename, _filt = getopenfilename(
|
|
568
|
+
self, _("Open"), basedir, self.FILE_FILTERS
|
|
569
|
+
)
|
|
570
|
+
if filename:
|
|
571
|
+
with qt_try_loadsave_file(self.parentWidget(), filename, "load"):
|
|
572
|
+
Conf.main.base_dir.set(filename)
|
|
573
|
+
macro = self.add_macro()
|
|
574
|
+
macro.from_file(filename)
|
|
575
|
+
return self.get_number_from_macro(macro)
|
|
576
|
+
return -1
|
|
577
|
+
|
|
578
|
+
def remove_macro(self, number_or_title: int | str | None = None) -> None:
|
|
579
|
+
"""Remove macro
|
|
580
|
+
|
|
581
|
+
Args:
|
|
582
|
+
number_or_title: Number of the macro (starting at 1) or title of the macro.
|
|
583
|
+
Defaults to None.
|
|
584
|
+
"""
|
|
585
|
+
if number_or_title is None:
|
|
586
|
+
number_or_title = self.tabwidget.get_current_number()
|
|
587
|
+
if isinstance(number_or_title, str):
|
|
588
|
+
number_or_title = self.get_number_from_title(number_or_title)
|
|
589
|
+
txt = "<br>".join(
|
|
590
|
+
[
|
|
591
|
+
_(
|
|
592
|
+
"When closed, the macro is <u>permanently destroyed</u>, "
|
|
593
|
+
"unless it has been exported first."
|
|
594
|
+
),
|
|
595
|
+
"",
|
|
596
|
+
_("Do you want to continue?"),
|
|
597
|
+
]
|
|
598
|
+
)
|
|
599
|
+
btns = QW.QMessageBox.StandardButton.Yes | QW.QMessageBox.StandardButton.No
|
|
600
|
+
if execenv.unattended:
|
|
601
|
+
choice = QW.QMessageBox.StandardButton.Yes
|
|
602
|
+
else:
|
|
603
|
+
choice = QW.QMessageBox.warning(self, self.windowTitle(), txt, btns)
|
|
604
|
+
if choice == QW.QMessageBox.StandardButton.Yes:
|
|
605
|
+
self.tabwidget.remove_tab(number_or_title)
|
|
606
|
+
self.__macros.pop(number_or_title - 1)
|
|
607
|
+
self.SIG_OBJECT_REMOVED.emit()
|