FreeCAD
160 строк · 7.2 Кб
1# SPDX-License-Identifier: LGPL-2.1-or-later
2# ***************************************************************************
3# * *
4# * Copyright (c) 2022-2024 FreeCAD Project Association *
5# * *
6# * This file is part of FreeCAD. *
7# * *
8# * FreeCAD is free software: you can redistribute it and/or modify it *
9# * under the terms of the GNU Lesser General Public License as *
10# * published by the Free Software Foundation, either version 2.1 of the *
11# * License, or (at your option) any later version. *
12# * *
13# * FreeCAD is distributed in the hope that it will be useful, but *
14# * WITHOUT ANY WARRANTY; without even the implied warranty of *
15# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16# * Lesser General Public License for more details. *
17# * *
18# * You should have received a copy of the GNU Lesser General Public *
19# * License along with FreeCAD. If not, see *
20# * <https://www.gnu.org/licenses/>. *
21# * *
22# ***************************************************************************
23
24""" Provides a class for showing the list view and detail view at the same time. """
25
26import base6427
28from addonmanager_freecad_interface import Preferences29
30from Addon import Addon31from Widgets.addonmanager_widget_package_details_view import PackageDetailsView32from addonmanager_package_details_controller import PackageDetailsController33from Widgets.addonmanager_widget_view_selector import AddonManagerDisplayStyle34from package_list import PackageList35
36# Get whatever version of PySide we can
37try:38import PySide # Use the FreeCAD wrapper39except ImportError:40try:41import PySide6 # Outside FreeCAD, try Qt6 first42
43PySide = PySide644except ImportError:45import PySide2 # Fall back to Qt5 (if this fails, Python will kill this module's import)46
47PySide = PySide248
49from PySide import QtCore, QtWidgets50
51
52class CompositeView(QtWidgets.QWidget):53"""A widget that displays the Addon Manager's top bar, the list of Addons, and the detail54view. Depending on the view mode selected, these may all be displayed at once, or selecting
55an addon in the list may case the list to hide and the detail view to show."""
56
57install = QtCore.Signal(Addon)58uninstall = QtCore.Signal(Addon)59update = QtCore.Signal(Addon)60execute = QtCore.Signal(Addon)61update_status = QtCore.Signal(Addon)62check_for_update = QtCore.Signal(Addon)63
64def __init__(self, parent=None):65super().__init__(parent)66self.package_details = PackageDetailsView(self)67self.package_details_controller = PackageDetailsController(self.package_details)68self.package_list = PackageList(self)69prefs = Preferences()70self.display_style = prefs.get("ViewStyle")71self.main_layout = QtWidgets.QHBoxLayout(self)72self.splitter = QtWidgets.QSplitter(self)73self.splitter.addWidget(self.package_list)74self.package_list.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)75self.splitter.addWidget(self.package_details)76self.package_details.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)77self.splitter.setOrientation(QtCore.Qt.Horizontal)78self.splitter.setContentsMargins(0, 0, 0, 0)79self.splitter.setSizePolicy(80QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding81)82self.main_layout.addWidget(self.splitter)83self.layout().setContentsMargins(0, 0, 0, 0)84self._setup_ui()85self._setup_connections()86self._restore_splitter_state()87
88def _save_splitter_state(self):89"""Write the splitter state into an Addon manager preference, CompositeSplitterState"""90prefs = Preferences()91state = self.splitter.saveState()92encoded = base64.b64encode(state).decode("ASCII")93prefs.set("CompositeSplitterState", encoded)94
95def _restore_splitter_state(self):96"""Restore the splitter state from CompositeSplitterState"""97prefs = Preferences()98encoded = prefs.get("CompositeSplitterState")99if encoded:100state = base64.b64decode(encoded)101self.splitter.restoreState(state)102
103def setModel(self, model):104self.package_list.setModel(model)105
106def set_display_style(self, style: AddonManagerDisplayStyle):107self.display_style = style108self._setup_ui()109
110def _setup_ui(self):111if self.display_style == AddonManagerDisplayStyle.EXPANDED:112self._setup_expanded_ui()113elif self.display_style == AddonManagerDisplayStyle.COMPACT:114self._setup_compact_ui()115elif self.display_style == AddonManagerDisplayStyle.COMPOSITE:116self._setup_composite_ui()117else:118raise RuntimeError("Invalid display style")119self.package_list.set_view_style(self.display_style)120
121def _setup_expanded_ui(self):122self.package_list.show()123self.package_details.hide()124self.package_details.button_bar.set_show_back_button(True)125
126def _setup_compact_ui(self):127self.package_list.show()128self.package_details.hide()129self.package_details.button_bar.set_show_back_button(True)130
131def _setup_composite_ui(self):132self.package_list.show()133self.package_details.show()134self.package_details.button_bar.set_show_back_button(False)135
136def _setup_connections(self):137self.package_list.itemSelected.connect(self.addon_selected)138self.package_details_controller.back.connect(self._back_button_clicked)139self.package_details_controller.install.connect(self.install)140self.package_details_controller.uninstall.connect(self.uninstall)141self.package_details_controller.update.connect(self.update)142self.package_details_controller.execute.connect(self.execute)143self.package_details_controller.update_status.connect(self.update_status)144self.package_list.ui.view_bar.view_changed.connect(self.set_display_style)145self.splitter.splitterMoved.connect(self._splitter_moved)146
147def addon_selected(self, addon):148self.package_details_controller.show_repo(addon)149if self.display_style != AddonManagerDisplayStyle.COMPOSITE:150self.package_list.hide()151self.package_details.show()152self.package_details.button_bar.set_show_back_button(True)153
154def _back_button_clicked(self):155if self.display_style != AddonManagerDisplayStyle.COMPOSITE:156self.package_list.show()157self.package_details.hide()158
159def _splitter_moved(self, position: int, index: int) -> None:160self._save_splitter_state()161