setiastrosuitepro 1.6.5.post3__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.
- setiastro/__init__.py +2 -0
- setiastro/data/SASP_data.fits +0 -0
- setiastro/data/catalogs/List_of_Galaxies_with_Distances_Gly.csv +488 -0
- setiastro/data/catalogs/astrobin_filters.csv +890 -0
- setiastro/data/catalogs/astrobin_filters_page1_local.csv +51 -0
- setiastro/data/catalogs/cali2.csv +63 -0
- setiastro/data/catalogs/cali2color.csv +65 -0
- setiastro/data/catalogs/celestial_catalog - original.csv +16471 -0
- setiastro/data/catalogs/celestial_catalog.csv +24031 -0
- setiastro/data/catalogs/detected_stars.csv +24784 -0
- setiastro/data/catalogs/fits_header_data.csv +46 -0
- setiastro/data/catalogs/test.csv +8 -0
- setiastro/data/catalogs/updated_celestial_catalog.csv +16471 -0
- setiastro/images/Astro_Spikes.png +0 -0
- setiastro/images/Background_startup.jpg +0 -0
- setiastro/images/HRDiagram.png +0 -0
- setiastro/images/LExtract.png +0 -0
- setiastro/images/LInsert.png +0 -0
- setiastro/images/Oxygenation-atm-2.svg.png +0 -0
- setiastro/images/RGB080604.png +0 -0
- setiastro/images/abeicon.png +0 -0
- setiastro/images/aberration.png +0 -0
- setiastro/images/andromedatry.png +0 -0
- setiastro/images/andromedatry_satellited.png +0 -0
- setiastro/images/annotated.png +0 -0
- setiastro/images/aperture.png +0 -0
- setiastro/images/astrosuite.ico +0 -0
- setiastro/images/astrosuite.png +0 -0
- setiastro/images/astrosuitepro.icns +0 -0
- setiastro/images/astrosuitepro.ico +0 -0
- setiastro/images/astrosuitepro.png +0 -0
- setiastro/images/background.png +0 -0
- setiastro/images/background2.png +0 -0
- setiastro/images/benchmark.png +0 -0
- setiastro/images/big_moon_stabilizer_timeline.png +0 -0
- setiastro/images/big_moon_stabilizer_timeline_clean.png +0 -0
- setiastro/images/blaster.png +0 -0
- setiastro/images/blink.png +0 -0
- setiastro/images/clahe.png +0 -0
- setiastro/images/collage.png +0 -0
- setiastro/images/colorwheel.png +0 -0
- setiastro/images/contsub.png +0 -0
- setiastro/images/convo.png +0 -0
- setiastro/images/copyslot.png +0 -0
- setiastro/images/cosmic.png +0 -0
- setiastro/images/cosmicsat.png +0 -0
- setiastro/images/crop1.png +0 -0
- setiastro/images/cropicon.png +0 -0
- setiastro/images/curves.png +0 -0
- setiastro/images/cvs.png +0 -0
- setiastro/images/debayer.png +0 -0
- setiastro/images/denoise_cnn_custom.png +0 -0
- setiastro/images/denoise_cnn_graph.png +0 -0
- setiastro/images/disk.png +0 -0
- setiastro/images/dse.png +0 -0
- setiastro/images/exoicon.png +0 -0
- setiastro/images/eye.png +0 -0
- setiastro/images/fliphorizontal.png +0 -0
- setiastro/images/flipvertical.png +0 -0
- setiastro/images/font.png +0 -0
- setiastro/images/freqsep.png +0 -0
- setiastro/images/functionbundle.png +0 -0
- setiastro/images/graxpert.png +0 -0
- setiastro/images/green.png +0 -0
- setiastro/images/gridicon.png +0 -0
- setiastro/images/halo.png +0 -0
- setiastro/images/hdr.png +0 -0
- setiastro/images/histogram.png +0 -0
- setiastro/images/hubble.png +0 -0
- setiastro/images/imagecombine.png +0 -0
- setiastro/images/invert.png +0 -0
- setiastro/images/isophote.png +0 -0
- setiastro/images/isophote_demo_figure.png +0 -0
- setiastro/images/isophote_demo_image.png +0 -0
- setiastro/images/isophote_demo_model.png +0 -0
- setiastro/images/isophote_demo_residual.png +0 -0
- setiastro/images/jwstpupil.png +0 -0
- setiastro/images/linearfit.png +0 -0
- setiastro/images/livestacking.png +0 -0
- setiastro/images/mask.png +0 -0
- setiastro/images/maskapply.png +0 -0
- setiastro/images/maskcreate.png +0 -0
- setiastro/images/maskremove.png +0 -0
- setiastro/images/morpho.png +0 -0
- setiastro/images/mosaic.png +0 -0
- setiastro/images/multiscale_decomp.png +0 -0
- setiastro/images/nbtorgb.png +0 -0
- setiastro/images/neutral.png +0 -0
- setiastro/images/nuke.png +0 -0
- setiastro/images/openfile.png +0 -0
- setiastro/images/pedestal.png +0 -0
- setiastro/images/pen.png +0 -0
- setiastro/images/pixelmath.png +0 -0
- setiastro/images/platesolve.png +0 -0
- setiastro/images/ppp.png +0 -0
- setiastro/images/pro.png +0 -0
- setiastro/images/project.png +0 -0
- setiastro/images/psf.png +0 -0
- setiastro/images/redo.png +0 -0
- setiastro/images/redoicon.png +0 -0
- setiastro/images/rescale.png +0 -0
- setiastro/images/rgbalign.png +0 -0
- setiastro/images/rgbcombo.png +0 -0
- setiastro/images/rgbextract.png +0 -0
- setiastro/images/rotate180.png +0 -0
- setiastro/images/rotatearbitrary.png +0 -0
- setiastro/images/rotateclockwise.png +0 -0
- setiastro/images/rotatecounterclockwise.png +0 -0
- setiastro/images/satellite.png +0 -0
- setiastro/images/script.png +0 -0
- setiastro/images/selectivecolor.png +0 -0
- setiastro/images/simbad.png +0 -0
- setiastro/images/slot0.png +0 -0
- setiastro/images/slot1.png +0 -0
- setiastro/images/slot2.png +0 -0
- setiastro/images/slot3.png +0 -0
- setiastro/images/slot4.png +0 -0
- setiastro/images/slot5.png +0 -0
- setiastro/images/slot6.png +0 -0
- setiastro/images/slot7.png +0 -0
- setiastro/images/slot8.png +0 -0
- setiastro/images/slot9.png +0 -0
- setiastro/images/spcc.png +0 -0
- setiastro/images/spin_precession_vs_lunar_distance.png +0 -0
- setiastro/images/spinner.gif +0 -0
- setiastro/images/stacking.png +0 -0
- setiastro/images/staradd.png +0 -0
- setiastro/images/staralign.png +0 -0
- setiastro/images/starnet.png +0 -0
- setiastro/images/starregistration.png +0 -0
- setiastro/images/starspike.png +0 -0
- setiastro/images/starstretch.png +0 -0
- setiastro/images/statstretch.png +0 -0
- setiastro/images/supernova.png +0 -0
- setiastro/images/uhs.png +0 -0
- setiastro/images/undoicon.png +0 -0
- setiastro/images/upscale.png +0 -0
- setiastro/images/viewbundle.png +0 -0
- setiastro/images/whitebalance.png +0 -0
- setiastro/images/wimi_icon_256x256.png +0 -0
- setiastro/images/wimilogo.png +0 -0
- setiastro/images/wims.png +0 -0
- setiastro/images/wrench_icon.png +0 -0
- setiastro/images/xisfliberator.png +0 -0
- setiastro/qml/ResourceMonitor.qml +126 -0
- setiastro/saspro/__init__.py +20 -0
- setiastro/saspro/__main__.py +958 -0
- setiastro/saspro/_generated/__init__.py +7 -0
- setiastro/saspro/_generated/build_info.py +3 -0
- setiastro/saspro/abe.py +1346 -0
- setiastro/saspro/abe_preset.py +196 -0
- setiastro/saspro/aberration_ai.py +698 -0
- setiastro/saspro/aberration_ai_preset.py +224 -0
- setiastro/saspro/accel_installer.py +218 -0
- setiastro/saspro/accel_workers.py +30 -0
- setiastro/saspro/add_stars.py +624 -0
- setiastro/saspro/astrobin_exporter.py +1010 -0
- setiastro/saspro/astrospike.py +153 -0
- setiastro/saspro/astrospike_python.py +1841 -0
- setiastro/saspro/autostretch.py +198 -0
- setiastro/saspro/backgroundneutral.py +611 -0
- setiastro/saspro/batch_convert.py +328 -0
- setiastro/saspro/batch_renamer.py +522 -0
- setiastro/saspro/blemish_blaster.py +491 -0
- setiastro/saspro/blink_comparator_pro.py +3149 -0
- setiastro/saspro/bundles.py +61 -0
- setiastro/saspro/bundles_dock.py +114 -0
- setiastro/saspro/cheat_sheet.py +213 -0
- setiastro/saspro/clahe.py +368 -0
- setiastro/saspro/comet_stacking.py +1442 -0
- setiastro/saspro/common_tr.py +107 -0
- setiastro/saspro/config.py +38 -0
- setiastro/saspro/config_bootstrap.py +40 -0
- setiastro/saspro/config_manager.py +316 -0
- setiastro/saspro/continuum_subtract.py +1617 -0
- setiastro/saspro/convo.py +1400 -0
- setiastro/saspro/convo_preset.py +414 -0
- setiastro/saspro/copyastro.py +190 -0
- setiastro/saspro/cosmicclarity.py +1589 -0
- setiastro/saspro/cosmicclarity_preset.py +407 -0
- setiastro/saspro/crop_dialog_pro.py +983 -0
- setiastro/saspro/crop_preset.py +189 -0
- setiastro/saspro/curve_editor_pro.py +2562 -0
- setiastro/saspro/curves_preset.py +375 -0
- setiastro/saspro/debayer.py +673 -0
- setiastro/saspro/debug_utils.py +29 -0
- setiastro/saspro/dnd_mime.py +35 -0
- setiastro/saspro/doc_manager.py +2664 -0
- setiastro/saspro/exoplanet_detector.py +2166 -0
- setiastro/saspro/file_utils.py +284 -0
- setiastro/saspro/fitsmodifier.py +748 -0
- setiastro/saspro/fix_bom.py +32 -0
- setiastro/saspro/free_torch_memory.py +48 -0
- setiastro/saspro/frequency_separation.py +1349 -0
- setiastro/saspro/function_bundle.py +1596 -0
- setiastro/saspro/generate_translations.py +3092 -0
- setiastro/saspro/ghs_dialog_pro.py +663 -0
- setiastro/saspro/ghs_preset.py +284 -0
- setiastro/saspro/graxpert.py +637 -0
- setiastro/saspro/graxpert_preset.py +287 -0
- setiastro/saspro/gui/__init__.py +0 -0
- setiastro/saspro/gui/main_window.py +8792 -0
- setiastro/saspro/gui/mixins/__init__.py +33 -0
- setiastro/saspro/gui/mixins/dock_mixin.py +375 -0
- setiastro/saspro/gui/mixins/file_mixin.py +450 -0
- setiastro/saspro/gui/mixins/geometry_mixin.py +503 -0
- setiastro/saspro/gui/mixins/header_mixin.py +441 -0
- setiastro/saspro/gui/mixins/mask_mixin.py +421 -0
- setiastro/saspro/gui/mixins/menu_mixin.py +390 -0
- setiastro/saspro/gui/mixins/theme_mixin.py +367 -0
- setiastro/saspro/gui/mixins/toolbar_mixin.py +1619 -0
- setiastro/saspro/gui/mixins/update_mixin.py +323 -0
- setiastro/saspro/gui/mixins/view_mixin.py +435 -0
- setiastro/saspro/gui/statistics_dialog.py +47 -0
- setiastro/saspro/halobgon.py +488 -0
- setiastro/saspro/header_viewer.py +448 -0
- setiastro/saspro/headless_utils.py +88 -0
- setiastro/saspro/histogram.py +756 -0
- setiastro/saspro/history_explorer.py +941 -0
- setiastro/saspro/i18n.py +168 -0
- setiastro/saspro/image_combine.py +417 -0
- setiastro/saspro/image_peeker_pro.py +1604 -0
- setiastro/saspro/imageops/__init__.py +37 -0
- setiastro/saspro/imageops/mdi_snap.py +292 -0
- setiastro/saspro/imageops/scnr.py +36 -0
- setiastro/saspro/imageops/starbasedwhitebalance.py +210 -0
- setiastro/saspro/imageops/stretch.py +236 -0
- setiastro/saspro/isophote.py +1182 -0
- setiastro/saspro/layers.py +208 -0
- setiastro/saspro/layers_dock.py +714 -0
- setiastro/saspro/lazy_imports.py +193 -0
- setiastro/saspro/legacy/__init__.py +2 -0
- setiastro/saspro/legacy/image_manager.py +2360 -0
- setiastro/saspro/legacy/numba_utils.py +3676 -0
- setiastro/saspro/legacy/xisf.py +1213 -0
- setiastro/saspro/linear_fit.py +537 -0
- setiastro/saspro/live_stacking.py +1854 -0
- setiastro/saspro/log_bus.py +5 -0
- setiastro/saspro/logging_config.py +460 -0
- setiastro/saspro/luminancerecombine.py +510 -0
- setiastro/saspro/main_helpers.py +201 -0
- setiastro/saspro/mask_creation.py +1086 -0
- setiastro/saspro/masks_core.py +56 -0
- setiastro/saspro/mdi_widgets.py +353 -0
- setiastro/saspro/memory_utils.py +666 -0
- setiastro/saspro/metadata_patcher.py +75 -0
- setiastro/saspro/mfdeconv.py +3909 -0
- setiastro/saspro/mfdeconv_earlystop.py +71 -0
- setiastro/saspro/mfdeconvcudnn.py +3312 -0
- setiastro/saspro/mfdeconvsport.py +2459 -0
- setiastro/saspro/minorbodycatalog.py +567 -0
- setiastro/saspro/morphology.py +407 -0
- setiastro/saspro/multiscale_decomp.py +1747 -0
- setiastro/saspro/nbtorgb_stars.py +541 -0
- setiastro/saspro/numba_utils.py +3145 -0
- setiastro/saspro/numba_warmup.py +141 -0
- setiastro/saspro/ops/__init__.py +9 -0
- setiastro/saspro/ops/command_help_dialog.py +623 -0
- setiastro/saspro/ops/command_runner.py +217 -0
- setiastro/saspro/ops/commands.py +1594 -0
- setiastro/saspro/ops/script_editor.py +1105 -0
- setiastro/saspro/ops/scripts.py +1476 -0
- setiastro/saspro/ops/settings.py +637 -0
- setiastro/saspro/parallel_utils.py +554 -0
- setiastro/saspro/pedestal.py +121 -0
- setiastro/saspro/perfect_palette_picker.py +1105 -0
- setiastro/saspro/pipeline.py +110 -0
- setiastro/saspro/pixelmath.py +1604 -0
- setiastro/saspro/plate_solver.py +2445 -0
- setiastro/saspro/project_io.py +797 -0
- setiastro/saspro/psf_utils.py +136 -0
- setiastro/saspro/psf_viewer.py +549 -0
- setiastro/saspro/pyi_rthook_astroquery.py +95 -0
- setiastro/saspro/remove_green.py +331 -0
- setiastro/saspro/remove_stars.py +1599 -0
- setiastro/saspro/remove_stars_preset.py +446 -0
- setiastro/saspro/resources.py +503 -0
- setiastro/saspro/rgb_combination.py +208 -0
- setiastro/saspro/rgb_extract.py +19 -0
- setiastro/saspro/rgbalign.py +723 -0
- setiastro/saspro/runtime_imports.py +7 -0
- setiastro/saspro/runtime_torch.py +754 -0
- setiastro/saspro/save_options.py +73 -0
- setiastro/saspro/selective_color.py +1611 -0
- setiastro/saspro/sfcc.py +1472 -0
- setiastro/saspro/shortcuts.py +3116 -0
- setiastro/saspro/signature_insert.py +1102 -0
- setiastro/saspro/stacking_suite.py +19066 -0
- setiastro/saspro/star_alignment.py +7380 -0
- setiastro/saspro/star_alignment_preset.py +329 -0
- setiastro/saspro/star_metrics.py +49 -0
- setiastro/saspro/star_spikes.py +765 -0
- setiastro/saspro/star_stretch.py +507 -0
- setiastro/saspro/stat_stretch.py +538 -0
- setiastro/saspro/status_log_dock.py +78 -0
- setiastro/saspro/subwindow.py +3407 -0
- setiastro/saspro/supernovaasteroidhunter.py +1719 -0
- setiastro/saspro/swap_manager.py +134 -0
- setiastro/saspro/torch_backend.py +89 -0
- setiastro/saspro/torch_rejection.py +434 -0
- setiastro/saspro/translations/all_source_strings.json +4726 -0
- setiastro/saspro/translations/ar_translations.py +4096 -0
- setiastro/saspro/translations/de_translations.py +3728 -0
- setiastro/saspro/translations/es_translations.py +4169 -0
- setiastro/saspro/translations/fr_translations.py +4090 -0
- setiastro/saspro/translations/hi_translations.py +3803 -0
- setiastro/saspro/translations/integrate_translations.py +271 -0
- setiastro/saspro/translations/it_translations.py +4728 -0
- setiastro/saspro/translations/ja_translations.py +3834 -0
- setiastro/saspro/translations/pt_translations.py +3847 -0
- setiastro/saspro/translations/ru_translations.py +3082 -0
- setiastro/saspro/translations/saspro_ar.qm +0 -0
- setiastro/saspro/translations/saspro_ar.ts +16019 -0
- setiastro/saspro/translations/saspro_de.qm +0 -0
- setiastro/saspro/translations/saspro_de.ts +14548 -0
- setiastro/saspro/translations/saspro_es.qm +0 -0
- setiastro/saspro/translations/saspro_es.ts +16202 -0
- setiastro/saspro/translations/saspro_fr.qm +0 -0
- setiastro/saspro/translations/saspro_fr.ts +15870 -0
- setiastro/saspro/translations/saspro_hi.qm +0 -0
- setiastro/saspro/translations/saspro_hi.ts +14855 -0
- setiastro/saspro/translations/saspro_it.qm +0 -0
- setiastro/saspro/translations/saspro_it.ts +19046 -0
- setiastro/saspro/translations/saspro_ja.qm +0 -0
- setiastro/saspro/translations/saspro_ja.ts +14980 -0
- setiastro/saspro/translations/saspro_pt.qm +0 -0
- setiastro/saspro/translations/saspro_pt.ts +15024 -0
- setiastro/saspro/translations/saspro_ru.qm +0 -0
- setiastro/saspro/translations/saspro_ru.ts +11835 -0
- setiastro/saspro/translations/saspro_sw.qm +0 -0
- setiastro/saspro/translations/saspro_sw.ts +15237 -0
- setiastro/saspro/translations/saspro_uk.qm +0 -0
- setiastro/saspro/translations/saspro_uk.ts +15248 -0
- setiastro/saspro/translations/saspro_zh.qm +0 -0
- setiastro/saspro/translations/saspro_zh.ts +15289 -0
- setiastro/saspro/translations/sw_translations.py +3897 -0
- setiastro/saspro/translations/uk_translations.py +3929 -0
- setiastro/saspro/translations/zh_translations.py +3910 -0
- setiastro/saspro/versioning.py +77 -0
- setiastro/saspro/view_bundle.py +1558 -0
- setiastro/saspro/wavescale_hdr.py +645 -0
- setiastro/saspro/wavescale_hdr_preset.py +101 -0
- setiastro/saspro/wavescalede.py +680 -0
- setiastro/saspro/wavescalede_preset.py +230 -0
- setiastro/saspro/wcs_update.py +374 -0
- setiastro/saspro/whitebalance.py +513 -0
- setiastro/saspro/widgets/__init__.py +48 -0
- setiastro/saspro/widgets/common_utilities.py +306 -0
- setiastro/saspro/widgets/graphics_views.py +122 -0
- setiastro/saspro/widgets/image_utils.py +518 -0
- setiastro/saspro/widgets/minigame/game.js +991 -0
- setiastro/saspro/widgets/minigame/index.html +53 -0
- setiastro/saspro/widgets/minigame/style.css +241 -0
- setiastro/saspro/widgets/preview_dialogs.py +280 -0
- setiastro/saspro/widgets/resource_monitor.py +263 -0
- setiastro/saspro/widgets/spinboxes.py +290 -0
- setiastro/saspro/widgets/themed_buttons.py +13 -0
- setiastro/saspro/widgets/wavelet_utils.py +331 -0
- setiastro/saspro/wimi.py +7996 -0
- setiastro/saspro/wims.py +578 -0
- setiastro/saspro/window_shelf.py +185 -0
- setiastro/saspro/xisf.py +1213 -0
- setiastrosuitepro-1.6.5.post3.dist-info/METADATA +278 -0
- setiastrosuitepro-1.6.5.post3.dist-info/RECORD +368 -0
- setiastrosuitepro-1.6.5.post3.dist-info/WHEEL +4 -0
- setiastrosuitepro-1.6.5.post3.dist-info/entry_points.txt +6 -0
- setiastrosuitepro-1.6.5.post3.dist-info/licenses/LICENSE +674 -0
- setiastrosuitepro-1.6.5.post3.dist-info/licenses/license.txt +2580 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# pro/gui/mixins/__init__.py
|
|
2
|
+
"""
|
|
3
|
+
GUI Mixins for AstroSuiteProMainWindow.
|
|
4
|
+
|
|
5
|
+
This package contains modular mixins that separate different aspects of the main window
|
|
6
|
+
into logical, maintainable components.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from .dock_mixin import DockMixin
|
|
11
|
+
from .menu_mixin import MenuMixin
|
|
12
|
+
from .toolbar_mixin import ToolbarMixin
|
|
13
|
+
from .file_mixin import FileMixin
|
|
14
|
+
from .theme_mixin import ThemeMixin
|
|
15
|
+
from .geometry_mixin import GeometryMixin
|
|
16
|
+
from .view_mixin import ViewMixin
|
|
17
|
+
from .header_mixin import HeaderMixin
|
|
18
|
+
from .mask_mixin import MaskMixin
|
|
19
|
+
from .update_mixin import UpdateMixin
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"DockMixin",
|
|
23
|
+
"MenuMixin",
|
|
24
|
+
"ToolbarMixin",
|
|
25
|
+
"FileMixin",
|
|
26
|
+
"ThemeMixin",
|
|
27
|
+
"GeometryMixin",
|
|
28
|
+
"ViewMixin",
|
|
29
|
+
"HeaderMixin",
|
|
30
|
+
"MaskMixin",
|
|
31
|
+
"UpdateMixin",
|
|
32
|
+
]
|
|
33
|
+
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# pro/gui/mixins/dock_mixin.py
|
|
2
|
+
"""
|
|
3
|
+
Dock management mixin for AstroSuiteProMainWindow.
|
|
4
|
+
|
|
5
|
+
This mixin contains all dock-related functionality: initialization,
|
|
6
|
+
visibility management, and registration in menus.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
from PyQt6.QtCore import Qt, QTimer
|
|
12
|
+
from PyQt6.QtWidgets import (
|
|
13
|
+
QDockWidget, QPlainTextEdit, QTreeWidget, QTreeWidgetItem,
|
|
14
|
+
QVBoxLayout, QWidget, QTextEdit, QListWidget, QListWidgetItem,
|
|
15
|
+
QAbstractItemView, QApplication
|
|
16
|
+
)
|
|
17
|
+
from PyQt6.QtGui import QTextCursor, QAction
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from PyQt6.QtWidgets import QAction
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DockMixin:
|
|
24
|
+
"""
|
|
25
|
+
Mixin for dock widget management.
|
|
26
|
+
|
|
27
|
+
Provides methods for creating, managing, and synchronizing dock widgets
|
|
28
|
+
in the main window.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def _init_log_dock(self):
|
|
32
|
+
"""Initialize the system log dock widget."""
|
|
33
|
+
self.log_dock = QDockWidget(self.tr("System Log"), self)
|
|
34
|
+
self.log_dock.setObjectName("LogDock")
|
|
35
|
+
self.log_dock.setAllowedAreas(
|
|
36
|
+
Qt.DockWidgetArea.BottomDockWidgetArea
|
|
37
|
+
| Qt.DockWidgetArea.TopDockWidgetArea
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
self.log_text = QPlainTextEdit(self.log_dock)
|
|
41
|
+
self.log_text.setReadOnly(True)
|
|
42
|
+
self.log_text.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
|
|
43
|
+
self.log_dock.setWidget(self.log_text)
|
|
44
|
+
|
|
45
|
+
self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.log_dock)
|
|
46
|
+
|
|
47
|
+
self.act_toggle_log = self.log_dock.toggleViewAction()
|
|
48
|
+
self.act_toggle_log.setText(self.tr("Show System Log Panel"))
|
|
49
|
+
|
|
50
|
+
def _append_log_text(self, text: str):
|
|
51
|
+
"""Append text to the system log dock."""
|
|
52
|
+
if not text:
|
|
53
|
+
return
|
|
54
|
+
# Append to the bottom and keep view scrolled
|
|
55
|
+
cursor = self.log_text.textCursor()
|
|
56
|
+
cursor.movePosition(QTextCursor.MoveOperation.End)
|
|
57
|
+
cursor.insertText(text)
|
|
58
|
+
self.log_text.setTextCursor(cursor)
|
|
59
|
+
self.log_text.ensureCursorVisible()
|
|
60
|
+
|
|
61
|
+
def _hook_stdout_stderr(self):
|
|
62
|
+
"""Hook stdout/stderr to redirect to the system log dock."""
|
|
63
|
+
import sys
|
|
64
|
+
from setiastro.saspro.mdi_widgets import QtLogStream
|
|
65
|
+
|
|
66
|
+
# Remember original streams so we still print to real console.
|
|
67
|
+
self._orig_stdout = sys.stdout
|
|
68
|
+
self._orig_stderr = sys.stderr
|
|
69
|
+
|
|
70
|
+
self._qt_stdout = QtLogStream(self._orig_stdout, self)
|
|
71
|
+
self._qt_stderr = QtLogStream(self._orig_stderr, self)
|
|
72
|
+
|
|
73
|
+
self._qt_stdout.text_emitted.connect(self._append_log_text)
|
|
74
|
+
self._qt_stderr.text_emitted.connect(self._append_log_text)
|
|
75
|
+
|
|
76
|
+
sys.stdout = self._qt_stdout
|
|
77
|
+
sys.stderr = self._qt_stderr
|
|
78
|
+
|
|
79
|
+
def _register_dock_in_view_menu(self, dock: QDockWidget, action: QAction | None = None):
|
|
80
|
+
"""
|
|
81
|
+
Register a dock widget's toggle action in the View → Panels menu.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
dock: The QDockWidget to register
|
|
85
|
+
action: Optional custom action (if None, uses dock.toggleViewAction())
|
|
86
|
+
"""
|
|
87
|
+
if not hasattr(self, "_view_panels_menu"):
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
if action is None:
|
|
91
|
+
action = dock.toggleViewAction()
|
|
92
|
+
|
|
93
|
+
self._view_panels_menu.addAction(action)
|
|
94
|
+
|
|
95
|
+
def _remove_dock_from_view_menu(self, action: QAction):
|
|
96
|
+
"""
|
|
97
|
+
Remove a dock's toggle action from the View → Panels menu.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
action: The action to remove
|
|
101
|
+
"""
|
|
102
|
+
if not hasattr(self, "_view_panels_menu"):
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
self._view_panels_menu.removeAction(action)
|
|
106
|
+
|
|
107
|
+
def _init_explorer_dock(self):
|
|
108
|
+
self.explorer = QListWidget()
|
|
109
|
+
# Enter/Return or single-activation: focus if open, else open
|
|
110
|
+
self.explorer.itemActivated.connect(self._activate_or_open_from_explorer)
|
|
111
|
+
# Double-click: same behavior
|
|
112
|
+
self.explorer.itemDoubleClicked.connect(self._activate_or_open_from_explorer)
|
|
113
|
+
|
|
114
|
+
dock = QDockWidget(self.tr("Explorer"), self)
|
|
115
|
+
dock.setWidget(self.explorer)
|
|
116
|
+
dock.setObjectName("ExplorerDock")
|
|
117
|
+
self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, dock)
|
|
118
|
+
|
|
119
|
+
def _init_console_dock(self):
|
|
120
|
+
self.console = QListWidget()
|
|
121
|
+
|
|
122
|
+
# Allow multi-row selection so Select All actually highlights everything
|
|
123
|
+
self.console.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
|
124
|
+
|
|
125
|
+
# Right-click context menu
|
|
126
|
+
self.console.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
|
127
|
+
self.console.customContextMenuRequested.connect(self._on_console_context_menu)
|
|
128
|
+
|
|
129
|
+
dock = QDockWidget(self.tr("Console / Status"), self)
|
|
130
|
+
dock.setWidget(self.console)
|
|
131
|
+
dock.setObjectName("ConsoleDock")
|
|
132
|
+
self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, dock)
|
|
133
|
+
|
|
134
|
+
def _init_status_log_dock(self):
|
|
135
|
+
from setiastro.saspro.status_log_dock import StatusLogDock
|
|
136
|
+
from setiastro.saspro.log_bus import LogBus
|
|
137
|
+
|
|
138
|
+
# Create the dock
|
|
139
|
+
self.status_log_dock = StatusLogDock(self) # your dock widget class
|
|
140
|
+
self.status_log_dock.setObjectName("StatusLogDock") # stable name for restoreState/menu
|
|
141
|
+
self.status_log_dock.setAllowedAreas(
|
|
142
|
+
Qt.DockWidgetArea.LeftDockWidgetArea
|
|
143
|
+
| Qt.DockWidgetArea.RightDockWidgetArea
|
|
144
|
+
| Qt.DockWidgetArea.BottomDockWidgetArea
|
|
145
|
+
| Qt.DockWidgetArea.TopDockWidgetArea
|
|
146
|
+
)
|
|
147
|
+
# Default area (will be overridden by restoreState if present)
|
|
148
|
+
self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.status_log_dock)
|
|
149
|
+
|
|
150
|
+
# Expose the dock globally so dialogs can show/raise it
|
|
151
|
+
app = QApplication.instance()
|
|
152
|
+
app._sasd_status_console = self.status_log_dock
|
|
153
|
+
|
|
154
|
+
# Ensure a global log bus and wire bus -> dock (queued; thread-safe)
|
|
155
|
+
if not hasattr(app, "_sasd_log_bus"):
|
|
156
|
+
app._sasd_log_bus = LogBus()
|
|
157
|
+
app._sasd_log_bus.posted.connect(
|
|
158
|
+
self.status_log_dock.append_line,
|
|
159
|
+
type=Qt.ConnectionType.QueuedConnection
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# First-run placement (only if no prior saved layout)
|
|
163
|
+
self._first_place_status_log_if_needed()
|
|
164
|
+
|
|
165
|
+
def _init_layers_dock(self):
|
|
166
|
+
from setiastro.saspro.layers_dock import LayersDock
|
|
167
|
+
|
|
168
|
+
self.layers_dock = LayersDock(self)
|
|
169
|
+
self.layers_dock.setObjectName("LayersDock")
|
|
170
|
+
# put it on the right, *below* header viewer if you dock that at right too
|
|
171
|
+
self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.layers_dock)
|
|
172
|
+
# ensure the header viewer sits above, layers below
|
|
173
|
+
try:
|
|
174
|
+
self.splitDockWidget(self.header_dock, self.layers_dock, Qt.Orientation.Vertical)
|
|
175
|
+
except Exception:
|
|
176
|
+
pass
|
|
177
|
+
|
|
178
|
+
def _init_header_viewer_dock(self):
|
|
179
|
+
from setiastro.saspro.header_viewer import HeaderViewerDock
|
|
180
|
+
|
|
181
|
+
self.header_viewer = HeaderViewerDock(self)
|
|
182
|
+
self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.header_viewer)
|
|
183
|
+
|
|
184
|
+
# Bind the dock to DocManager so it tracks the ACTIVE subwindow only.
|
|
185
|
+
# Make sure self.doc_manager.set_mdi_area(mdi) was already called.
|
|
186
|
+
self.header_viewer.attach_doc_manager(self.doc_manager)
|
|
187
|
+
|
|
188
|
+
# Optional: keep it strictly active-only (default). Flip to True to restore hover-follow behavior.
|
|
189
|
+
# self.header_viewer.set_follow_hover(False)
|
|
190
|
+
|
|
191
|
+
# Seed once with whatever is currently active.
|
|
192
|
+
try:
|
|
193
|
+
self.header_viewer.set_document(self.doc_manager.get_active_document())
|
|
194
|
+
except Exception:
|
|
195
|
+
pass
|
|
196
|
+
|
|
197
|
+
def _init_resource_monitor_overlay(self):
|
|
198
|
+
"""Initialize the QML System Resource Monitor as a floating overlay."""
|
|
199
|
+
try:
|
|
200
|
+
from setiastro.saspro.widgets.resource_monitor import SystemMonitorWidget
|
|
201
|
+
|
|
202
|
+
# Create as a child of the central widget or self to sit on top
|
|
203
|
+
# Using self (QMainWindow) allows it to float over everything including status bar if we want,
|
|
204
|
+
# but usually we want it over MDI area. Let's try self first for "floating" feel.
|
|
205
|
+
self.resource_monitor = SystemMonitorWidget(self)
|
|
206
|
+
self.resource_monitor.setObjectName("ResourceMonitorOverlay")
|
|
207
|
+
|
|
208
|
+
# Make it a proper independent window to allow true transparency (translucent background)
|
|
209
|
+
# without black artifacts from parent composition.
|
|
210
|
+
# Fixed: Removed WindowStaysOnTopHint to allow it to be obscured by other apps (Alt-Tab support)
|
|
211
|
+
self.resource_monitor.setWindowFlags(
|
|
212
|
+
Qt.WindowType.Window |
|
|
213
|
+
Qt.WindowType.FramelessWindowHint |
|
|
214
|
+
Qt.WindowType.Tool
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
# Sizing and Transparency
|
|
218
|
+
self.resource_monitor.setFixedSize(200, 60)
|
|
219
|
+
# self.resource_monitor.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, True) # Optional: if we want click-through
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
# Initial placement (will be updated by resizeEvent)
|
|
223
|
+
self._update_monitor_position()
|
|
224
|
+
|
|
225
|
+
# Defer visibility to MainWindow.showEvent to prevent appearing before main window
|
|
226
|
+
# visible = self.settings.value("ui/resource_monitor_visible", True, type=bool)
|
|
227
|
+
# if visible:
|
|
228
|
+
# self.resource_monitor.show()
|
|
229
|
+
# else:
|
|
230
|
+
# self.resource_monitor.hide()
|
|
231
|
+
except Exception as e:
|
|
232
|
+
print(f"WARNING: Could not initialize System Monitor overlay: {e}")
|
|
233
|
+
self.resource_monitor = None
|
|
234
|
+
|
|
235
|
+
def _toggle_resource_monitor(self, checked: bool):
|
|
236
|
+
"""Toggle floating monitor visibility."""
|
|
237
|
+
if hasattr(self, 'resource_monitor') and self.resource_monitor:
|
|
238
|
+
if checked:
|
|
239
|
+
self.resource_monitor.show()
|
|
240
|
+
self._update_monitor_position()
|
|
241
|
+
else:
|
|
242
|
+
self.resource_monitor.hide()
|
|
243
|
+
self.settings.setValue("ui/resource_monitor_visible", checked)
|
|
244
|
+
|
|
245
|
+
def _update_monitor_position(self):
|
|
246
|
+
"""Snap monitor to bottom-right corner or restore saved position."""
|
|
247
|
+
if hasattr(self, 'resource_monitor') and self.resource_monitor:
|
|
248
|
+
from PyQt6.QtCore import QPoint
|
|
249
|
+
|
|
250
|
+
# Check for saved position first
|
|
251
|
+
saved_x = self.settings.value("ui/resource_monitor_pos_x", type=int)
|
|
252
|
+
saved_y = self.settings.value("ui/resource_monitor_pos_y", type=int)
|
|
253
|
+
|
|
254
|
+
if saved_x != 0 and saved_y != 0: # Basic validity check (0,0 is unlikely to be desired but also default if missing)
|
|
255
|
+
# Actually 0,0 is valid but type=int returns 0 if missing.
|
|
256
|
+
# Let's check string existence to be safer or just accept 0 if set.
|
|
257
|
+
# Checking existence via `contains` is better but value() logic is ok for now.
|
|
258
|
+
if self.settings.contains("ui/resource_monitor_pos_x"):
|
|
259
|
+
self.resource_monitor.move(saved_x, saved_y)
|
|
260
|
+
self.resource_monitor.raise_()
|
|
261
|
+
return
|
|
262
|
+
|
|
263
|
+
m = 5 # margin
|
|
264
|
+
|
|
265
|
+
screen = self.screen()
|
|
266
|
+
geom = screen.availableGeometry()
|
|
267
|
+
|
|
268
|
+
mw = self.resource_monitor.width()
|
|
269
|
+
mh = self.resource_monitor.height()
|
|
270
|
+
|
|
271
|
+
x = geom.x() + geom.width() - mw - m
|
|
272
|
+
y = geom.y() + geom.height() - mh - m
|
|
273
|
+
|
|
274
|
+
self.resource_monitor.move(x, y)
|
|
275
|
+
self.resource_monitor.raise_()
|
|
276
|
+
|
|
277
|
+
# We need to hook resizeEvent to call _update_monitor_position.
|
|
278
|
+
# Since this is a mixin, we can't easily override resizeEvent of the MainWindow without being careful.
|
|
279
|
+
# Best way: install an event filter on self, or since we are a mixin mixed into MainWindow,
|
|
280
|
+
# we can rely on MainWindow calling a specific method or we can patch it...
|
|
281
|
+
# Actually, MainWindow likely has resizeEvent.
|
|
282
|
+
# simpler: QTimer check? No.
|
|
283
|
+
# Correct way for Mixin: The MainWindow class should call something.
|
|
284
|
+
# BUT, I can just installEventFilter(self) ? No, infinite loop risk.
|
|
285
|
+
#
|
|
286
|
+
# Let's use the 'GeometryMixin' or just add a standard method `_on_resize_for_monitor`
|
|
287
|
+
# and assume I can hook it in MainWindow.py.
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
# ⌠Remove this old line; it let random mouse-over updates hijack the dock:
|
|
291
|
+
# self.currentDocumentChanged.disconnect(self.header_viewer.set_document) # if previously connected
|
|
292
|
+
# (If you prefer to keep the signal for explicit tab switches, it's fine to leave
|
|
293
|
+
# it connected--the dock's new guard will ignore non-active/hover docs.)
|
|
294
|
+
|
|
295
|
+
def _populate_view_panels_menu(self):
|
|
296
|
+
"""Rebuild 'View Panels' with all current dock widgets (ordered nicely)."""
|
|
297
|
+
menu = self._ensure_view_panels_menu()
|
|
298
|
+
menu.clear()
|
|
299
|
+
self._view_panels_actions = {}
|
|
300
|
+
|
|
301
|
+
# Collect every QDockWidget that exists right now
|
|
302
|
+
docks: list[QDockWidget] = self.findChildren(QDockWidget)
|
|
303
|
+
|
|
304
|
+
# Friendly ordering for common ones; others follow alphabetically.
|
|
305
|
+
order_hint = {
|
|
306
|
+
self.tr("Explorer"): 10,
|
|
307
|
+
self.tr("Console / Status"): 20,
|
|
308
|
+
self.tr("Header Viewer"): 30,
|
|
309
|
+
self.tr("Layers"): 40,
|
|
310
|
+
self.tr("Window Shelf"): 50,
|
|
311
|
+
self.tr("Command Search"): 60,
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
# Add special action for overlay monitor
|
|
315
|
+
mon_act = QAction(self.tr("System Monitor"), self)
|
|
316
|
+
mon_act.setCheckable(True)
|
|
317
|
+
mon_act.setChecked(self.settings.value("ui/resource_monitor_visible", True, type=bool))
|
|
318
|
+
mon_act.triggered.connect(self._toggle_resource_monitor)
|
|
319
|
+
|
|
320
|
+
# We need to insert it into the logic that populates the menu.
|
|
321
|
+
# But 'dock_mixin' automates menu from self.findChildren(QDockWidget).
|
|
322
|
+
# So we have to manually inject this action into the "Panels" menu if possible
|
|
323
|
+
# or expose it such that main_window can add it.
|
|
324
|
+
#
|
|
325
|
+
# Easier: allow main_window to add it, or ...
|
|
326
|
+
# If I can't easily see where menu is built, I'll bind it to self.act_toggle_monitor = mon_act
|
|
327
|
+
self.act_toggle_monitor = mon_act
|
|
328
|
+
|
|
329
|
+
def key_fn(d: QDockWidget):
|
|
330
|
+
t = d.windowTitle()
|
|
331
|
+
return (order_hint.get(t, 1000), t.lower())
|
|
332
|
+
|
|
333
|
+
for dock in sorted(docks, key=key_fn):
|
|
334
|
+
self._register_dock_in_view_menu(dock)
|
|
335
|
+
|
|
336
|
+
if hasattr(self, "act_toggle_monitor"):
|
|
337
|
+
menu.addSeparator()
|
|
338
|
+
menu.addAction(self.act_toggle_monitor)
|
|
339
|
+
|
|
340
|
+
def _add_doc_to_explorer(self, doc):
|
|
341
|
+
base = self._normalize_base_doc(doc)
|
|
342
|
+
|
|
343
|
+
# de-dupe by identity on base
|
|
344
|
+
for i in range(self.explorer.count()):
|
|
345
|
+
it = self.explorer.item(i)
|
|
346
|
+
if it.data(Qt.ItemDataRole.UserRole) is base:
|
|
347
|
+
# refresh text in case dims/name changed
|
|
348
|
+
it.setText(self._format_explorer_title(base))
|
|
349
|
+
return
|
|
350
|
+
|
|
351
|
+
item = QListWidgetItem(self._format_explorer_title(base))
|
|
352
|
+
item.setData(Qt.ItemDataRole.UserRole, base)
|
|
353
|
+
fp = (base.metadata or {}).get("file_path")
|
|
354
|
+
if fp:
|
|
355
|
+
item.setToolTip(fp)
|
|
356
|
+
self.explorer.addItem(item)
|
|
357
|
+
|
|
358
|
+
# keep row label in sync with edits/resizes/renames
|
|
359
|
+
try:
|
|
360
|
+
base.changed.connect(lambda *_: self._update_explorer_item_for_doc(base))
|
|
361
|
+
except Exception:
|
|
362
|
+
pass
|
|
363
|
+
|
|
364
|
+
def _remove_doc_from_explorer(self, doc):
|
|
365
|
+
"""
|
|
366
|
+
Remove either the exact doc or its base (handles ROI proxies).
|
|
367
|
+
"""
|
|
368
|
+
base = self._normalize_base_doc(doc)
|
|
369
|
+
for i in range(self.explorer.count()):
|
|
370
|
+
it = self.explorer.item(i)
|
|
371
|
+
d = it.data(Qt.ItemDataRole.UserRole)
|
|
372
|
+
if d is doc or d is base:
|
|
373
|
+
self.explorer.takeItem(i)
|
|
374
|
+
break
|
|
375
|
+
|