summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTerry Jan Reedy <tjreedy@udel.edu>2016-06-11 06:06:18 (GMT)
committerTerry Jan Reedy <tjreedy@udel.edu>2016-06-11 06:06:18 (GMT)
commit3b6a53256b18d141f0dda35724cf437282f7e0ca (patch)
treea40239af6b5c1d47c27e143296c501376b8c39d2
parenta0f2295e0ad5eef71fb095d78c556e97d05a39f6 (diff)
downloadcpython-3b6a53256b18d141f0dda35724cf437282f7e0ca.zip
cpython-3b6a53256b18d141f0dda35724cf437282f7e0ca.tar.gz
cpython-3b6a53256b18d141f0dda35724cf437282f7e0ca.tar.bz2
Issue #5124: Paste with selection should always replace.
This is how paste work on Windows, Mac, modern Linux apps, and ttk widgets. The exception was X11 tk widgets. Original patch by Serhiy Storchake.
-rwxr-xr-xLib/idlelib/PyShell.py15
-rw-r--r--Lib/idlelib/idle_test/test_editmenu.py98
2 files changed, 112 insertions, 1 deletions
diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py
index ea0d7de..3ea1a7d 100755
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -1408,6 +1408,17 @@ class PseudoInputFile(PseudoFile):
self.shell.close()
+def fix_x11_paste(root):
+ "Make paste replace selection on x11. See issue #5124."
+ if root._windowingsystem == 'x11':
+ for cls in 'Text', 'Entry', 'Spinbox':
+ root.bind_class(
+ cls,
+ '<<Paste>>',
+ 'catch {%W delete sel.first sel.last}\n' +
+ root.bind_class(cls, '<<Paste>>'))
+
+
usage_msg = """\
USAGE: idle [-deins] [-t title] [file]*
@@ -1537,8 +1548,10 @@ def main():
'editor-on-startup', type='bool')
enable_edit = enable_edit or edit_start
enable_shell = enable_shell or not enable_edit
+
# start editor and/or shell windows:
root = Tk(className="Idle")
+ root.withdraw()
# set application icon
icondir = os.path.join(os.path.dirname(__file__), 'Icons')
@@ -1553,7 +1566,7 @@ def main():
root.tk.call('wm', 'iconphoto', str(root), "-default", *icons)
fixwordbreaks(root)
- root.withdraw()
+ fix_x11_paste(root)
flist = PyShellFileList(root)
macosxSupport.setupApp(root, flist)
diff --git a/Lib/idlelib/idle_test/test_editmenu.py b/Lib/idlelib/idle_test/test_editmenu.py
new file mode 100644
index 0000000..d352240
--- /dev/null
+++ b/Lib/idlelib/idle_test/test_editmenu.py
@@ -0,0 +1,98 @@
+'''Test (selected) IDLE Edit menu items.
+
+Edit modules have their own test files files
+'''
+from test.test_support import requires
+requires('gui')
+import Tkinter as tk
+import unittest
+from idlelib import PyShell
+
+class PasteTest(unittest.TestCase):
+ '''Test pasting into widgets that allow pasting.
+
+ On X11, replacing selections requires tk fix.
+ '''
+ @classmethod
+ def setUpClass(cls):
+ cls.root = root = tk.Tk()
+ PyShell.fix_x11_paste(root)
+ cls.text = tk.Text(root)
+ cls.entry = tk.Entry(root)
+ cls.spin = tk.Spinbox(root)
+ root.clipboard_clear()
+ root.clipboard_append('two')
+
+ @classmethod
+ def tearDownClass(cls):
+ del cls.text, cls.entry, cls.spin
+ cls.root.clipboard_clear()
+ cls.root.update_idletasks()
+ cls.root.update()
+ cls.root.destroy()
+ del cls.root
+
+ def test_paste_text_no_selection(self):
+ "Test pasting into text without a selection."
+ text = self.text
+ tag, ans = '', 'onetwo\n'
+ text.delete('1.0', 'end')
+ text.insert('1.0', 'one', tag)
+ text.event_generate('<<Paste>>')
+ self.assertEqual(text.get('1.0', 'end'), ans)
+
+ def test_paste_text_selection(self):
+ "Test pasting into text with a selection."
+ text = self.text
+ tag, ans = 'sel', 'two\n'
+ text.delete('1.0', 'end')
+ text.insert('1.0', 'one', tag)
+ text.event_generate('<<Paste>>')
+ self.assertEqual(text.get('1.0', 'end'), ans)
+
+ def test_paste_entry_no_selection(self):
+ "Test pasting into an entry without a selection."
+ # On 3.6, generated <<Paste>> fails without empty select range
+ # for 'no selection'. Live widget works fine.
+ entry = self.entry
+ end, ans = 0, 'onetwo'
+ entry.delete(0, 'end')
+ entry.insert(0, 'one')
+ entry.select_range(0, end) # see note
+ entry.event_generate('<<Paste>>')
+ self.assertEqual(entry.get(), ans)
+
+ def test_paste_entry_selection(self):
+ "Test pasting into an entry with a selection."
+ entry = self.entry
+ end, ans = 'end', 'two'
+ entry.delete(0, 'end')
+ entry.insert(0, 'one')
+ entry.select_range(0, end)
+ entry.event_generate('<<Paste>>')
+ self.assertEqual(entry.get(), ans)
+
+ def test_paste_spin_no_selection(self):
+ "Test pasting into a spinbox without a selection."
+ # See note above for entry.
+ spin = self.spin
+ end, ans = 0, 'onetwo'
+ spin.delete(0, 'end')
+ spin.insert(0, 'one')
+ spin.selection('range', 0, end) # see note
+ spin.event_generate('<<Paste>>')
+ self.assertEqual(spin.get(), ans)
+
+ def test_paste_spin_selection(self):
+ "Test pasting into a spinbox with a selection."
+ spin = self.spin
+ end, ans = 'end', 'two'
+ spin.delete(0, 'end')
+ spin.insert(0, 'one')
+ spin.selection('range', 0, end)
+ spin.event_generate('<<Paste>>')
+ self.assertEqual(spin.get(), ans)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)