blob: e3b55065c6d9cceb246652f941cc01d3cb6994f2 [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
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -04008
csabella42bc8be2017-06-29 18:42:17 -04009class TextFrame(Frame):
10 "Display text with scrollbar."
11
12 def __init__(self, parent, rawtext):
13 """Create a frame for Textview.
14
15 parent - parent widget for this frame
16 rawtext - text to display
17 """
18 super().__init__(parent)
19 self['relief'] = 'sunken'
20 self['height'] = 700
21 # TODO: get fg/bg from theme.
22 self.bg = '#ffffff'
23 self.fg = '#000000'
24
25 self.text = text = Text(self, wrap='word', highlightthickness=0,
26 fg=self.fg, bg=self.bg)
27 self.scroll = scroll = Scrollbar(self, orient='vertical',
28 takefocus=False, command=text.yview)
29 text['yscrollcommand'] = scroll.set
30 text.insert(0.0, rawtext)
31 text['state'] = 'disabled'
32 text.focus_set()
33
34 scroll.pack(side='right', fill='y')
35 text.pack(side='left', expand=True, fill='both')
36
37
38class ViewFrame(Frame):
39 "Display TextFrame and Close button."
40 def __init__(self, parent, text):
41 super().__init__(parent)
42 self.parent = parent
43 self.bind('<Return>', self.ok)
44 self.bind('<Escape>', self.ok)
45 self.textframe = TextFrame(self, text)
46 self.button_ok = button_ok = Button(
47 self, text='Close', command=self.ok, takefocus=False)
48 self.textframe.pack(side='top', expand=True, fill='both')
49 button_ok.pack(side='bottom')
50
51 def ok(self, event=None):
52 """Dismiss text viewer dialog."""
53 self.parent.destroy()
54
55
56class ViewWindow(Toplevel):
Terry Jan Reedya3623c82016-08-31 19:45:39 -040057 "A simple text viewer dialog for IDLE."
Kurt B. Kaiser09cb74b2003-06-12 04:20:56 +000058
Louie Luba365da2017-05-18 05:51:31 +080059 def __init__(self, parent, title, text, modal=True,
Terry Jan Reedybfebfd82017-09-30 17:37:53 -040060 *, _htest=False, _utest=False):
Louie Luba365da2017-05-18 05:51:31 +080061 """Show the given text in a scrollable window with a 'close' button.
Guido van Rossum8ce8a782007-11-01 19:42:39 +000062
Louie Luba365da2017-05-18 05:51:31 +080063 If modal is left True, users cannot interact with other windows
64 until the textview window is closed.
Terry Jan Reedy537e2c82014-06-05 03:38:34 -040065
csabella0aa0a062017-05-28 06:50:55 -040066 parent - parent of this dialog
67 title - string which is title of popup dialog
68 text - text to display in dialog
Terry Jan Reedy537e2c82014-06-05 03:38:34 -040069 _htest - bool; change box location when running htest.
Louie Luba365da2017-05-18 05:51:31 +080070 _utest - bool; don't wait_window when running unittest.
Steven M. Gavad721c482001-07-31 10:46:53 +000071 """
csabella42bc8be2017-06-29 18:42:17 -040072 super().__init__(parent)
73 self['borderwidth'] = 5
Terry Jan Reedya3623c82016-08-31 19:45:39 -040074 # Place dialog below parent if running htest.
csabella42bc8be2017-06-29 18:42:17 -040075 x = parent.winfo_rootx() + 10
76 y = parent.winfo_rooty() + (10 if not _htest else 100)
77 self.geometry(f'=750x500+{x}+{y}')
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000078
Steven M. Gavad721c482001-07-31 10:46:53 +000079 self.title(title)
csabella42bc8be2017-06-29 18:42:17 -040080 self.viewframe = ViewFrame(self, text)
csabella0aa0a062017-05-28 06:50:55 -040081 self.protocol("WM_DELETE_WINDOW", self.ok)
csabella42bc8be2017-06-29 18:42:17 -040082 self.button_ok = button_ok = Button(self, text='Close',
83 command=self.ok, takefocus=False)
84 self.viewframe.pack(side='top', expand=True, fill='both')
Terry Jan Reedye91e7632012-02-05 15:14:20 -050085
86 if modal:
87 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."""
Steven M. Gavad721c482001-07-31 10:46:53 +000094 self.destroy()
Steven M. Gava44d3d1a2001-07-31 06:59:02 +000095
Guido van Rossum8ce8a782007-11-01 19:42:39 +000096
Louie Luba365da2017-05-18 05:51:31 +080097def view_text(parent, title, text, modal=True, _utest=False):
csabella42bc8be2017-06-29 18:42:17 -040098 """Create text viewer for given text.
csabella0aa0a062017-05-28 06:50:55 -040099
100 parent - parent of this dialog
101 title - string which is the title of popup dialog
102 text - text to display in this dialog
103 modal - controls if users can interact with other windows while this
104 dialog is displayed
105 _utest - bool; controls wait_window on unittest
106 """
csabella42bc8be2017-06-29 18:42:17 -0400107 return ViewWindow(parent, title, text, modal, _utest=_utest)
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000108
csabella0aa0a062017-05-28 06:50:55 -0400109
Louie Luba365da2017-05-18 05:51:31 +0800110def view_file(parent, title, filename, encoding=None, modal=True, _utest=False):
csabella42bc8be2017-06-29 18:42:17 -0400111 """Create text viewer for text in filename.
csabella0aa0a062017-05-28 06:50:55 -0400112
113 Return error message if file cannot be read. Otherwise calls view_text
114 with contents of the file.
115 """
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000116 try:
Éric Araujoccf03a12011-08-01 17:29:36 +0200117 with open(filename, 'r', encoding=encoding) as file:
118 contents = file.read()
Terry Jan Reedy82c46152016-06-22 04:54:18 -0400119 except OSError:
120 showerror(title='File Load Error',
csabella42bc8be2017-06-29 18:42:17 -0400121 message=f'Unable to load file {filename!r} .',
Terry Jan Reedy82c46152016-06-22 04:54:18 -0400122 parent=parent)
123 except UnicodeDecodeError as err:
124 showerror(title='Unicode Decode Error',
125 message=str(err),
126 parent=parent)
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000127 else:
Louie Luba365da2017-05-18 05:51:31 +0800128 return view_text(parent, title, contents, modal, _utest=_utest)
terryjreedy295304d2017-05-17 22:59:46 -0400129 return None
Louie Luba365da2017-05-18 05:51:31 +0800130
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000131
Steven M. Gava44d3d1a2001-07-31 06:59:02 +0000132if __name__ == '__main__':
Terry Jan Reedy537e2c82014-06-05 03:38:34 -0400133 import unittest
134 unittest.main('idlelib.idle_test.test_textview', verbosity=2, exit=False)
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400135 from idlelib.idle_test.htest import run
csabella42bc8be2017-06-29 18:42:17 -0400136 run(ViewWindow)