|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +""" |
| 4 | +This file is part of Ardupilot methodic configurator. https://github.com/ArduPilot/MethodicConfigurator |
| 5 | +
|
| 6 | +SPDX-FileCopyrightText: 2024 Amilcar do Carmo Lucas <[email protected]> |
| 7 | +
|
| 8 | +SPDX-License-Identifier: GPL-3.0-or-later |
| 9 | +""" |
| 10 | + |
| 11 | +import tkinter as tk |
| 12 | +from tkinter import ttk |
| 13 | + |
| 14 | +# from logging import debug as logging_debug |
| 15 | +# from logging import critical as logging_critical |
| 16 | +from webbrowser import open as webbrowser_open # to open the blog post documentation |
| 17 | + |
| 18 | +from MethodicConfigurator import _ |
| 19 | +from MethodicConfigurator.backend_filesystem import LocalFilesystem |
| 20 | +from MethodicConfigurator.backend_filesystem_program_settings import ProgramSettings |
| 21 | +from MethodicConfigurator.frontend_tkinter_base import ( |
| 22 | + show_tooltip, |
| 23 | +) |
| 24 | + |
| 25 | + |
| 26 | +class DocumentationFrame: # pylint: disable=too-few-public-methods |
| 27 | + """ |
| 28 | + A class to manage and display documentation within the GUI. |
| 29 | +
|
| 30 | + This class is responsible for creating a frame that displays |
| 31 | + documentation links related to the current file being edited. It updates |
| 32 | + the documentation links based on the current file and provides |
| 33 | + functionality to open these links in a web browser. |
| 34 | + """ |
| 35 | + |
| 36 | + def __init__(self, root: tk.Widget, local_filesystem: LocalFilesystem, current_file: str) -> None: |
| 37 | + self.root = root |
| 38 | + self.local_filesystem = local_filesystem |
| 39 | + self.current_file = current_file |
| 40 | + self.documentation_frame: ttk.LabelFrame |
| 41 | + self.documentation_labels: dict[str, ttk.Label] = {} |
| 42 | + self.auto_open_var = tk.BooleanVar(value=bool(ProgramSettings.get_setting("auto_open_doc_in_browser"))) |
| 43 | + self.__create_documentation_frame() |
| 44 | + |
| 45 | + def __create_documentation_frame(self) -> None: |
| 46 | + self.documentation_frame = ttk.LabelFrame(self.root, text=_("Documentation")) |
| 47 | + self.documentation_frame.pack(side=tk.TOP, fill="x", expand=False, pady=(4, 4), padx=(4, 4)) |
| 48 | + |
| 49 | + # Create a grid structure within the documentation_frame |
| 50 | + documentation_grid = ttk.Frame(self.documentation_frame) |
| 51 | + documentation_grid.pack(fill="both", expand=True) |
| 52 | + |
| 53 | + descriptive_texts = [_("Forum Blog:"), _("Wiki:"), _("External tool:"), _("Mandatory:")] |
| 54 | + descriptive_tooltips = [ |
| 55 | + _("ArduPilot's forum Methodic configuration Blog post relevant for the current file"), |
| 56 | + _("ArduPilot's wiki page relevant for the current file"), |
| 57 | + _("External tool or documentation relevant for the current file"), |
| 58 | + _( |
| 59 | + "Mandatory level of the current file,\n 100% you MUST use this file to configure the " |
| 60 | + "vehicle,\n 0% you can ignore this file if it does not apply to your vehicle" |
| 61 | + ), |
| 62 | + ] |
| 63 | + for i, text in enumerate(descriptive_texts): |
| 64 | + # Create labels for the first column with static descriptive text |
| 65 | + label = ttk.Label(documentation_grid, text=text) |
| 66 | + label.grid(row=i, column=0, sticky="w") |
| 67 | + show_tooltip(label, descriptive_tooltips[i]) |
| 68 | + |
| 69 | + if i == 3: |
| 70 | + bottom_frame = ttk.Frame(documentation_grid) |
| 71 | + bottom_frame.grid(row=i, column=1, sticky="ew") # ew to stretch horizontally |
| 72 | + |
| 73 | + self.documentation_labels[text] = ttk.Label(bottom_frame) |
| 74 | + self.documentation_labels[text].pack(side=tk.LEFT, fill="x", expand=True) |
| 75 | + auto_open_checkbox = ttk.Checkbutton( |
| 76 | + bottom_frame, |
| 77 | + text=_("Automatically open documentation links in browser"), |
| 78 | + variable=self.auto_open_var, |
| 79 | + command=lambda: ProgramSettings.set_setting("auto_open_doc_in_browser", self.auto_open_var.get()), |
| 80 | + ) |
| 81 | + show_tooltip( |
| 82 | + auto_open_checkbox, |
| 83 | + _( |
| 84 | + "Automatically open all the above documentation links in a browser\n" |
| 85 | + "whenever the current intermediate parameter file changes" |
| 86 | + ), |
| 87 | + ) |
| 88 | + auto_open_checkbox.pack(side=tk.LEFT, expand=False) |
| 89 | + else: |
| 90 | + # Create labels for the second column with the documentation links |
| 91 | + self.documentation_labels[text] = ttk.Label(documentation_grid) |
| 92 | + self.documentation_labels[text].grid(row=i, column=1, sticky="ew") |
| 93 | + documentation_grid.columnconfigure(0, weight=0) |
| 94 | + documentation_grid.columnconfigure(1, weight=1) |
| 95 | + |
| 96 | + # Dynamically update the documentation text and URL links |
| 97 | + self.update_documentation_labels(self.current_file) |
| 98 | + |
| 99 | + def update_documentation_labels(self, current_file: str) -> None: |
| 100 | + self.current_file = current_file |
| 101 | + if current_file: |
| 102 | + title = _("{current_file} Documentation") |
| 103 | + frame_title = title.format(**locals()) |
| 104 | + else: |
| 105 | + frame_title = _("Documentation") |
| 106 | + self.documentation_frame.config(text=frame_title) |
| 107 | + |
| 108 | + blog_text, blog_url = self.local_filesystem.get_documentation_text_and_url(current_file, "blog") |
| 109 | + self.__update_documentation_label(_("Forum Blog:"), blog_text, blog_url) |
| 110 | + wiki_text, wiki_url = self.local_filesystem.get_documentation_text_and_url(current_file, "wiki") |
| 111 | + self.__update_documentation_label(_("Wiki:"), wiki_text, wiki_url) |
| 112 | + external_tool_text, external_tool_url = self.local_filesystem.get_documentation_text_and_url( |
| 113 | + current_file, "external_tool" |
| 114 | + ) |
| 115 | + self.__update_documentation_label(_("External tool:"), external_tool_text, external_tool_url) |
| 116 | + mandatory_text, mandatory_url = self.local_filesystem.get_documentation_text_and_url(current_file, "mandatory") |
| 117 | + self.__update_documentation_label(_("Mandatory:"), mandatory_text, mandatory_url, False) |
| 118 | + |
| 119 | + if self.auto_open_var.get(): |
| 120 | + if wiki_url: |
| 121 | + webbrowser_open(url=wiki_url, new=0, autoraise=False) |
| 122 | + if external_tool_url: |
| 123 | + webbrowser_open(url=external_tool_url, new=0, autoraise=False) |
| 124 | + if blog_url: |
| 125 | + webbrowser_open(url=blog_url, new=0, autoraise=True) |
| 126 | + |
| 127 | + def __update_documentation_label(self, label_key, text, url, url_expected=True) -> None: |
| 128 | + label = self.documentation_labels[label_key] |
| 129 | + if url: |
| 130 | + label.config(text=text, foreground="blue", cursor="hand2", underline=True) |
| 131 | + label.bind("<Button-1>", lambda event, url=url: webbrowser_open(url)) # type: ignore |
| 132 | + show_tooltip(label, url) |
| 133 | + else: |
| 134 | + label.config(text=text, foreground="black", cursor="arrow", underline=False) |
| 135 | + label.bind("<Button-1>", lambda event: None) |
| 136 | + if url_expected: |
| 137 | + show_tooltip(label, _("Documentation URL not available")) |
0 commit comments