mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	bpo-39885: Make IDLE context menu cut and copy work again (GH-18951)
Leave selection when right click within. This exception to clearing selections when right-clicking was omitted from the previous commit,4ca060d. I did not realize that this completely disabled the context menu entries, and I should have merged a minimal fix immediately. An automated test should follow. (cherry picked from commit97e4e0f53d) Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
This commit is contained in:
		
							parent
							
								
									805fa54676
								
							
						
					
					
						commit
						9f3f70fd0b
					
				
					 4 changed files with 52 additions and 16 deletions
				
			
		|  | @ -12,8 +12,9 @@ when fetching a calltip. | |||
| bpo-27115: For 'Go to Line', use a Query entry box subclass with | ||||
| IDLE standard behavior and improved error checking. | ||||
| 
 | ||||
| bpo-39885: Since clicking to get an IDLE context menu moves the | ||||
| cursor, any text selection should be and now is cleared. | ||||
| bpo-39885: When a context menu is invoked by right-clicking outside | ||||
| of a selection, clear the selection and move the cursor.  Cut and | ||||
| Copy require that the click be within the selection. | ||||
| 
 | ||||
| bpo-39852: Edit "Go to line" now clears any selection, preventing | ||||
| accidental deletion.  It also updates Ln and Col on the status bar. | ||||
|  |  | |||
|  | @ -499,15 +499,23 @@ def handle_yview(self, event, *args): | |||
|     rmenu = None | ||||
| 
 | ||||
|     def right_menu_event(self, event): | ||||
|         self.text.tag_remove("sel", "1.0", "end") | ||||
|         self.text.mark_set("insert", "@%d,%d" % (event.x, event.y)) | ||||
|         text = self.text | ||||
|         newdex = text.index(f'@{event.x},{event.y}') | ||||
|         try: | ||||
|             in_selection = (text.compare('sel.first', '<=', newdex) and | ||||
|                            text.compare(newdex, '<=',  'sel.last')) | ||||
|         except TclError: | ||||
|             in_selection = False | ||||
|         if not in_selection: | ||||
|             text.tag_remove("sel", "1.0", "end") | ||||
|             text.mark_set("insert", newdex) | ||||
|         if not self.rmenu: | ||||
|             self.make_rmenu() | ||||
|         rmenu = self.rmenu | ||||
|         self.event = event | ||||
|         iswin = sys.platform[:3] == 'win' | ||||
|         if iswin: | ||||
|             self.text.config(cursor="arrow") | ||||
|             text.config(cursor="arrow") | ||||
| 
 | ||||
|         for item in self.rmenu_specs: | ||||
|             try: | ||||
|  | @ -520,7 +528,6 @@ def right_menu_event(self, event): | |||
|             state = getattr(self, verify_state)() | ||||
|             rmenu.entryconfigure(label, state=state) | ||||
| 
 | ||||
| 
 | ||||
|         rmenu.tk_popup(event.x_root, event.y_root) | ||||
|         if iswin: | ||||
|             self.text.config(cursor="ibeam") | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| from collections import namedtuple | ||||
| from test.support import requires | ||||
| from tkinter import Tk | ||||
| from idlelib.idle_test.mock_idle import Func | ||||
| 
 | ||||
| Editor = editor.EditorWindow | ||||
| 
 | ||||
|  | @ -92,6 +93,12 @@ def test_tabwidth_8(self): | |||
|                 ) | ||||
| 
 | ||||
| 
 | ||||
| def insert(text, string): | ||||
|     text.delete('1.0', 'end') | ||||
|     text.insert('end', string) | ||||
|     text.update()  # Force update for colorizer to finish. | ||||
| 
 | ||||
| 
 | ||||
| class IndentAndNewlineTest(unittest.TestCase): | ||||
| 
 | ||||
|     @classmethod | ||||
|  | @ -113,13 +120,6 @@ def tearDownClass(cls): | |||
|         cls.root.destroy() | ||||
|         del cls.root | ||||
| 
 | ||||
|     def insert(self, text): | ||||
|         t = self.window.text | ||||
|         t.delete('1.0', 'end') | ||||
|         t.insert('end', text) | ||||
|         # Force update for colorizer to finish. | ||||
|         t.update() | ||||
| 
 | ||||
|     def test_indent_and_newline_event(self): | ||||
|         eq = self.assertEqual | ||||
|         w = self.window | ||||
|  | @ -170,13 +170,13 @@ def test_indent_and_newline_event(self): | |||
|         w.prompt_last_line = '' | ||||
|         for test in tests: | ||||
|             with self.subTest(label=test.label): | ||||
|                 self.insert(test.text) | ||||
|                 insert(text, test.text) | ||||
|                 text.mark_set('insert', test.mark) | ||||
|                 nl(event=None) | ||||
|                 eq(get('1.0', 'end'), test.expected) | ||||
| 
 | ||||
|         # Selected text. | ||||
|         self.insert('  def f1(self, a, b):\n    return a + b') | ||||
|         insert(text, '  def f1(self, a, b):\n    return a + b') | ||||
|         text.tag_add('sel', '1.17', '1.end') | ||||
|         nl(None) | ||||
|         # Deletes selected text before adding new line. | ||||
|  | @ -184,11 +184,37 @@ def test_indent_and_newline_event(self): | |||
| 
 | ||||
|         # Preserves the whitespace in shell prompt. | ||||
|         w.prompt_last_line = '>>> ' | ||||
|         self.insert('>>> \t\ta =') | ||||
|         insert(text, '>>> \t\ta =') | ||||
|         text.mark_set('insert', '1.5') | ||||
|         nl(None) | ||||
|         eq(get('1.0', 'end'), '>>> \na =\n') | ||||
| 
 | ||||
| 
 | ||||
| class RMenuTest(unittest.TestCase): | ||||
| 
 | ||||
|     @classmethod | ||||
|     def setUpClass(cls): | ||||
|         requires('gui') | ||||
|         cls.root = Tk() | ||||
|         cls.root.withdraw() | ||||
|         cls.window = Editor(root=cls.root) | ||||
| 
 | ||||
|     @classmethod | ||||
|     def tearDownClass(cls): | ||||
|         cls.window._close() | ||||
|         del cls.window | ||||
|         cls.root.update_idletasks() | ||||
|         for id in cls.root.tk.call('after', 'info'): | ||||
|             cls.root.after_cancel(id) | ||||
|         cls.root.destroy() | ||||
|         del cls.root | ||||
| 
 | ||||
|     class DummyRMenu: | ||||
|         def tk_popup(x, y): pass | ||||
| 
 | ||||
|     def test_rclick(self): | ||||
|         pass | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     unittest.main(verbosity=2) | ||||
|  |  | |||
|  | @ -0,0 +1,2 @@ | |||
| Make context menu Cut and Copy work again when right-clicking within a | ||||
| selection. | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Miss Islington (bot)
						Miss Islington (bot)