blob: 464e6ac6b94e3172e98daaf3a6bafb0fb03182ab [file] [log] [blame]
Kurt B. Kaiser09cb74b2003-06-12 04:20:56 +00001"""Simple text browser for IDLE
2
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00003"""
csabella42bc8be2017-06-29 18:42:17 -04004from tkinter import Toplevel, Text
5from tkinter.ttk import Frame, Scrollbar, Button
Terry Jan Reedy82c46152016-06-22 04:54:18 -04006from tkinter.messagebox import showerror
Steven M. Gava44d3d1a2001-07-31 06:59:02 +00007
Tal Einatc87d9f42018-09-23 15:23:15 +03008from idlelib.colorizer import color_config
9
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -040010
csabella42bc8be2017-06-29 18:42:17 -040011class TextFrame(Frame):
12 "Display text with scrollbar."
13
14 def __init__(self, parent, rawtext):
15 """Create a frame for Textview.
16
17 parent - parent widget for this frame
18 rawtext - text to display
19 """
20 super().__init__(parent)
21 self['relief'] = 'sunken'
22 self['height'] = 700
csabella42bc8be2017-06-29 18:42:17 -040023
Tal Einatc87d9f42018-09-23 15:23:15 +030024 self.text = text = Text(self, wrap='word', highlightthickness=0)
25 color_config(text)
csabella42bc8be2017-06-29 18:42:17 -040026 self.scroll = scroll = Scrollbar(self, orient='vertical',
27 takefocus=False, command=text.yview)
28 text['yscrollcommand'] = scroll.set
29 text.insert(0.0, rawtext)
30 text['state'] = 'disabled'
31 text.focus_set()
32
33 scroll.pack(side='right', fill='y')
34 text.pack(side='left', expand=True, fill='both')
35
36
37class ViewFrame(Frame):
38 "Display TextFrame and Close button."
39 def __init__(self, parent, text):
40 super().__init__(parent)
41 self.parent = parent
42 self.bind('<Return>', self.ok)
43 self.bind('<Escape>', self.ok)
44 self.textframe = TextFrame(self, text)
45 self.button_ok = button_ok = Button(
46 self, text='Close', command=self.ok, takefocus=False)
47 self.textframe.pack(side='top', expand=True, fill='both')
48 button_ok.pack(side='bottom')
49
50 def ok(self, event=None):
51 """Dismiss text viewer dialog."""
52 self.parent.destroy()
53
54
55class ViewWindow(Toplevel):
Terry Jan Reedya3623c82016-08-31 19:45:39 -040056 "A simple text viewer dialog for IDLE."
Kurt B. Kaiser09cb74b2003-06-12 04:20:56 +000057
Louie Luba365da2017-05-18 05:51:31 +080058 def __init__(self, parent, title, text, modal=True,
Terry Jan Reedybfebfd82017-09-30 17:37:53 -040059 *, _htest=False, _utest=False):
Louie Luba365da2017-05-18 05:51:31 +080060 """Show the given text in a scrollable window with a 'close' button.
Guido van Rossum8ce8a782007-11-01 19:42:39 +000061
Louie Luba365da2017-05-18 05:51:31 +080062 If modal is left True, users cannot interact with other windows
63 until the textview window is closed.
Terry Jan Reedy537e2c82014-06-05 03:38:34 -040064
csabella0aa0a062017-05-28 06:50:55 -040065 parent - parent of this dialog
66 title - string which is title of popup dialog
67 text - text to display in dialog
Terry Jan Reedy537e2c82014-06-05 03:38:34 -040068 _htest - bool; change box location when running htest.
Louie Luba365da2017-05-18 05:51:31 +080069 _utest - bool; don't wait_window when running unittest.
Steven M. Gavad721c482001-07-31 10:46:53 +000070 """
csabella42bc8be2017-06-29 18:42:17 -040071 super().__init__(parent)
72 self['borderwidth'] = 5
Terry Jan Reedya3623c82016-08-31 19:45:39 -040073 # Place dialog below parent if running htest.
csabella42bc8be2017-06-29 18:42:17 -040074 x = parent.winfo_rootx() + 10
75 y = parent.winfo_rooty() + (10 if not _htest else 100)
76 self.geometry(f'=750x500+{x}+{y}')
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000077
Steven M. Gavad721c482001-07-31 10:46:53 +000078 self.title(title)
csabella42bc8be2017-06-29 18:42:17 -040079 self.viewframe = ViewFrame(self, text)
csabella0aa0a062017-05-28 06:50:55 -040080 self.protocol("WM_DELETE_WINDOW", self.ok)
csabella42bc8be2017-06-29 18:42:17 -040081 self.button_ok = button_ok = Button(self, text='Close',
82 command=self.ok, takefocus=False)
83 self.viewframe.pack(side='top', expand=True, fill='both')
Terry Jan Reedye91e7632012-02-05 15:14:20 -050084
Tal Einatdd743692018-08-02 10:30:06 +030085 self.is_modal = modal
86 if self.is_modal:
Terry Jan Reedye91e7632012-02-05 15:14:20 -050087 self.transient(parent)
88 self.grab_set()
Louie Luba365da2017-05-18 05:51:31 +080089 if not _utest:
90 self.wait_window()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000091
csabella0aa0a062017-05-28 06:50:55 -040092 def ok(self, event=None):
93 """Dismiss text viewer dialog."""
Tal Einatdd743692018-08-02 10:30:06 +030094 if self.is_modal:
95 self.grab_release()
Steven M. Gavad721c482001-07-31 10:46:53 +000096 self.destroy()
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000097
Guido van Rossum8ce8a782007-11-01 19:42:39 +000098
Louie Luba365da2017-05-18 05:51:31 +080099def view_text(parent, title, text, modal=True, _utest=False):
csabella42bc8be2017-06-29 18:42:17 -0400100 """Create text viewer for given text.
csabella0aa0a062017-05-28 06:50:55 -0400101
102 parent - parent of this dialog
103 title - string which is the title of popup dialog
104 text - text to display in this dialog
105 modal - controls if users can interact with other windows while this
106 dialog is displayed
107 _utest - bool; controls wait_window on unittest
108 """
csabella42bc8be2017-06-29 18:42:17 -0400109 return ViewWindow(parent, title, text, modal, _utest=_utest)
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000110
csabella0aa0a062017-05-28 06:50:55 -0400111
Terry Jan Reedy688722c2018-02-12 17:42:41 -0500112def view_file(parent, title, filename, encoding, modal=True, _utest=False):
csabella42bc8be2017-06-29 18:42:17 -0400113 """Create text viewer for text in filename.
csabella0aa0a062017-05-28 06:50:55 -0400114
115 Return error message if file cannot be read. Otherwise calls view_text
116 with contents of the file.
117 """
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000118 try:
Éric Araujoccf03a12011-08-01 17:29:36 +0200119 with open(filename, 'r', encoding=encoding) as file:
120 contents = file.read()
Terry Jan Reedy82c46152016-06-22 04:54:18 -0400121 except OSError:
122 showerror(title='File Load Error',
csabella42bc8be2017-06-29 18:42:17 -0400123 message=f'Unable to load file {filename!r} .',
Terry Jan Reedy82c46152016-06-22 04:54:18 -0400124 parent=parent)
125 except UnicodeDecodeError as err:
126 showerror(title='Unicode Decode Error',
127 message=str(err),
128 parent=parent)
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000129 else:
Louie Luba365da2017-05-18 05:51:31 +0800130 return view_text(parent, title, contents, modal, _utest=_utest)
terryjreedy295304d2017-05-17 22:59:46 -0400131 return None
Louie Luba365da2017-05-18 05:51:31 +0800132
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000133
Steven M. Gava44d3d1a2001-07-31 06:59:02 +0000134if __name__ == '__main__':
Terry Jan Reedy4d921582018-06-19 19:12:52 -0400135 from unittest import main
136 main('idlelib.idle_test.test_textview', verbosity=2, exit=False)
137
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400138 from idlelib.idle_test.htest import run
csabella42bc8be2017-06-29 18:42:17 -0400139 run(ViewWindow)