Home | History | Annotate | Download | only in idlelib
      1 """About Dialog for IDLE
      2 
      3 """
      4 import os
      5 import sys
      6 from platform import python_version, architecture
      7 
      8 from tkinter import Toplevel, Frame, Label, Button, PhotoImage
      9 from tkinter import SUNKEN, TOP, BOTTOM, LEFT, X, BOTH, W, EW, NSEW, E
     10 
     11 from idlelib import textview
     12 
     13 
     14 def build_bits():
     15     "Return bits for platform."
     16     if sys.platform == 'darwin':
     17         return '64' if sys.maxsize > 2**32 else '32'
     18     else:
     19         return architecture()[0][:2]
     20 
     21 
     22 class AboutDialog(Toplevel):
     23     """Modal about dialog for idle
     24 
     25     """
     26     def __init__(self, parent, title=None, *, _htest=False, _utest=False):
     27         """Create popup, do not return until tk widget destroyed.
     28 
     29         parent - parent of this dialog
     30         title - string which is title of popup dialog
     31         _htest - bool, change box location when running htest
     32         _utest - bool, don't wait_window when running unittest
     33         """
     34         Toplevel.__init__(self, parent)
     35         self.configure(borderwidth=5)
     36         # place dialog below parent if running htest
     37         self.geometry("+%d+%d" % (
     38                         parent.winfo_rootx()+30,
     39                         parent.winfo_rooty()+(30 if not _htest else 100)))
     40         self.bg = "#bbbbbb"
     41         self.fg = "#000000"
     42         self.create_widgets()
     43         self.resizable(height=False, width=False)
     44         self.title(title or
     45                    f'About IDLE {python_version()} ({build_bits()} bit)')
     46         self.transient(parent)
     47         self.grab_set()
     48         self.protocol("WM_DELETE_WINDOW", self.ok)
     49         self.parent = parent
     50         self.button_ok.focus_set()
     51         self.bind('<Return>', self.ok)  # dismiss dialog
     52         self.bind('<Escape>', self.ok)  # dismiss dialog
     53         self._current_textview = None
     54         self._utest = _utest
     55 
     56         if not _utest:
     57             self.deiconify()
     58             self.wait_window()
     59 
     60     def create_widgets(self):
     61         frame = Frame(self, borderwidth=2, relief=SUNKEN)
     62         frame_buttons = Frame(self)
     63         frame_buttons.pack(side=BOTTOM, fill=X)
     64         frame.pack(side=TOP, expand=True, fill=BOTH)
     65         self.button_ok = Button(frame_buttons, text='Close',
     66                                 command=self.ok)
     67         self.button_ok.pack(padx=5, pady=5)
     68 
     69         frame_background = Frame(frame, bg=self.bg)
     70         frame_background.pack(expand=True, fill=BOTH)
     71 
     72         header = Label(frame_background, text='IDLE', fg=self.fg,
     73                        bg=self.bg, font=('courier', 24, 'bold'))
     74         header.grid(row=0, column=0, sticky=E, padx=10, pady=10)
     75 
     76         tk_patchlevel = self.tk.call('info', 'patchlevel')
     77         ext = '.png' if tk_patchlevel >= '8.6' else '.gif'
     78         icon = os.path.join(os.path.abspath(os.path.dirname(__file__)),
     79                             'Icons', f'idle_48{ext}')
     80         self.icon_image = PhotoImage(master=self._root(), file=icon)
     81         logo = Label(frame_background, image=self.icon_image, bg=self.bg)
     82         logo.grid(row=0, column=0, sticky=W, rowspan=2, padx=10, pady=10)
     83 
     84         byline_text = "Python's Integrated Development\nand Learning Environment" + 5*'\n'
     85         byline = Label(frame_background, text=byline_text, justify=LEFT,
     86                        fg=self.fg, bg=self.bg)
     87         byline.grid(row=2, column=0, sticky=W, columnspan=3, padx=10, pady=5)
     88         email = Label(frame_background, text='email:  idle-dev (at] python.org',
     89                       justify=LEFT, fg=self.fg, bg=self.bg)
     90         email.grid(row=6, column=0, columnspan=2, sticky=W, padx=10, pady=0)
     91         docs = Label(frame_background, text='https://docs.python.org/' +
     92                      python_version()[:3] + '/library/idle.html',
     93                      justify=LEFT, fg=self.fg, bg=self.bg)
     94         docs.grid(row=7, column=0, columnspan=2, sticky=W, padx=10, pady=0)
     95 
     96         Frame(frame_background, borderwidth=1, relief=SUNKEN,
     97               height=2, bg=self.bg).grid(row=8, column=0, sticky=EW,
     98                                          columnspan=3, padx=5, pady=5)
     99 
    100         pyver = Label(frame_background,
    101                       text='Python version:  ' + python_version(),
    102                       fg=self.fg, bg=self.bg)
    103         pyver.grid(row=9, column=0, sticky=W, padx=10, pady=0)
    104         tkver = Label(frame_background, text='Tk version:  ' + tk_patchlevel,
    105                       fg=self.fg, bg=self.bg)
    106         tkver.grid(row=9, column=1, sticky=W, padx=2, pady=0)
    107         py_buttons = Frame(frame_background, bg=self.bg)
    108         py_buttons.grid(row=10, column=0, columnspan=2, sticky=NSEW)
    109         self.py_license = Button(py_buttons, text='License', width=8,
    110                                  highlightbackground=self.bg,
    111                                  command=self.show_py_license)
    112         self.py_license.pack(side=LEFT, padx=10, pady=10)
    113         self.py_copyright = Button(py_buttons, text='Copyright', width=8,
    114                                    highlightbackground=self.bg,
    115                                    command=self.show_py_copyright)
    116         self.py_copyright.pack(side=LEFT, padx=10, pady=10)
    117         self.py_credits = Button(py_buttons, text='Credits', width=8,
    118                                  highlightbackground=self.bg,
    119                                  command=self.show_py_credits)
    120         self.py_credits.pack(side=LEFT, padx=10, pady=10)
    121 
    122         Frame(frame_background, borderwidth=1, relief=SUNKEN,
    123               height=2, bg=self.bg).grid(row=11, column=0, sticky=EW,
    124                                          columnspan=3, padx=5, pady=5)
    125 
    126         idlever = Label(frame_background,
    127                         text='IDLE version:   ' + python_version(),
    128                         fg=self.fg, bg=self.bg)
    129         idlever.grid(row=12, column=0, sticky=W, padx=10, pady=0)
    130         idle_buttons = Frame(frame_background, bg=self.bg)
    131         idle_buttons.grid(row=13, column=0, columnspan=3, sticky=NSEW)
    132         self.readme = Button(idle_buttons, text='README', width=8,
    133                              highlightbackground=self.bg,
    134                              command=self.show_readme)
    135         self.readme.pack(side=LEFT, padx=10, pady=10)
    136         self.idle_news = Button(idle_buttons, text='NEWS', width=8,
    137                                 highlightbackground=self.bg,
    138                                 command=self.show_idle_news)
    139         self.idle_news.pack(side=LEFT, padx=10, pady=10)
    140         self.idle_credits = Button(idle_buttons, text='Credits', width=8,
    141                                    highlightbackground=self.bg,
    142                                    command=self.show_idle_credits)
    143         self.idle_credits.pack(side=LEFT, padx=10, pady=10)
    144 
    145     # License, copyright, and credits are of type _sitebuiltins._Printer
    146     def show_py_license(self):
    147         "Handle License button event."
    148         self.display_printer_text('About - License', license)
    149 
    150     def show_py_copyright(self):
    151         "Handle Copyright button event."
    152         self.display_printer_text('About - Copyright', copyright)
    153 
    154     def show_py_credits(self):
    155         "Handle Python Credits button event."
    156         self.display_printer_text('About - Python Credits', credits)
    157 
    158     # Encode CREDITS.txt to utf-8 for proper version of Loewis.
    159     # Specify others as ascii until need utf-8, so catch errors.
    160     def show_idle_credits(self):
    161         "Handle Idle Credits button event."
    162         self.display_file_text('About - Credits', 'CREDITS.txt', 'utf-8')
    163 
    164     def show_readme(self):
    165         "Handle Readme button event."
    166         self.display_file_text('About - Readme', 'README.txt', 'ascii')
    167 
    168     def show_idle_news(self):
    169         "Handle News button event."
    170         self.display_file_text('About - NEWS', 'NEWS.txt', 'utf-8')
    171 
    172     def display_printer_text(self, title, printer):
    173         """Create textview for built-in constants.
    174 
    175         Built-in constants have type _sitebuiltins._Printer.  The
    176         text is extracted from the built-in and then sent to a text
    177         viewer with self as the parent and title as the title of
    178         the popup.
    179         """
    180         printer._Printer__setup()
    181         text = '\n'.join(printer._Printer__lines)
    182         self._current_textview = textview.view_text(
    183             self, title, text, _utest=self._utest)
    184 
    185     def display_file_text(self, title, filename, encoding=None):
    186         """Create textview for filename.
    187 
    188         The filename needs to be in the current directory.  The path
    189         is sent to a text viewer with self as the parent, title as
    190         the title of the popup, and the file encoding.
    191         """
    192         fn = os.path.join(os.path.abspath(os.path.dirname(__file__)), filename)
    193         self._current_textview = textview.view_file(
    194             self, title, fn, encoding, _utest=self._utest)
    195 
    196     def ok(self, event=None):
    197         "Dismiss help_about dialog."
    198         self.grab_release()
    199         self.destroy()
    200 
    201 
    202 if __name__ == '__main__':
    203     from unittest import main
    204     main('idlelib.idle_test.test_help_about', verbosity=2, exit=False)
    205 
    206     from idlelib.idle_test.htest import run
    207     run(AboutDialog)
    208