Beispiel #1
0
 def __init__(self, text):
     self.text = text
     self.redir = WidgetRedirector(text)
     self.top = self.bottom = Delegator(text)
     self.bottom.insert = self.redir.register('insert', self.insert)
     self.bottom.delete = self.redir.register('delete', self.delete)
     self.filters = []
Beispiel #2
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.redirector = WidgetRedirector(self)
        self.insert = self.redirector.register("insert", lambda *args, **kw: "break")
        self.delete = self.redirector.register("delete", lambda *args, **kw: "break")

        self.bind("<Control-a>", self._on_ctrl_a)
Beispiel #3
0
 def __init__(self, *args, **kwargs):
     tkinter.Text.__init__(self, *args, **kwargs)
     self.redirector = WidgetRedirector(self)
     self.insert = \
         self.redirector.register("insert", lambda *args, **kw: "break")
     self.delete = \
         self.redirector.register("delete", lambda *args, **kw: "break")
Beispiel #4
0
 def __init__(self, master=None, **kwargs):
     ScrolledText.__init__(self, master, **kwargs)
     self.redirector = WidgetRedirector(self)
     self.insert = self.redirector.register("insert",
                                            lambda *args, **kw: "break")
     self.delete = self.redirector.register("delete",
                                            lambda *args, **kw: "break")
Beispiel #5
0
    class _ReadOnlyText(tk.Text):
        """Subclass of tk.Text that is read-only."""
        def __init__(self, *args, **kwargs):
            """Replace insert and delete bindings."""
            # subclass to tk.Text
            import tkinter as tk
            tk.Text.__init__(self, *args, **kwargs)
            self.SEL = tk.SEL
            self.END = tk.END
            self.INSERT = tk.INSERT
            from idlelib.redirector import WidgetRedirector
            self.redirector = WidgetRedirector(self)
            # freeze user changes
            self.insert = self.redirector.register('insert',
                                                   lambda *args, **kw: 'break')
            self.delete = self.redirector.register('delete',
                                                   lambda *args, **kw: 'break')
            # bind ctrl-a as select all
            self.bind("<Control-Key-a>", self.select_all)

        def select_all(self, event):
            """Select all event bound to ctrl-a."""
            # select all text
            self.tag_add(self.SEL, '1.0', self.END)
            self.mark_set(self.INSERT, '1.0')
            self.see(self.INSERT)
            return 'break'
Beispiel #6
0
 def __init__(self, text):
     # XXX would be nice to inherit from Delegator
     self.text = text
     self.redir = WidgetRedirector(text)
     self.top = self.bottom = Delegator(text)
     self.bottom.insert = self.redir.register("insert", self.insert)
     self.bottom.delete = self.redir.register("delete", self.delete)
     self.filters = []
Beispiel #7
0
class TextReadOnly(Text):
    def __init__(self, *args, **kwargs):
        Text.__init__(self, *args, **kwargs)
        self.redirector = WidgetRedirector(self)
        self.insert = self.redirector.register("insert",
                                               lambda *args, **kw: "break")
        self.delete = self.redirector.register("delete",
                                               lambda *args, **kw: "break")
Beispiel #8
0
class Percolator:

    def __init__(self, text):
        # XXX would be nice to inherit from Delegator
        self.text = text
        self.redir = WidgetRedirector(text)
        self.top = self.bottom = Delegator(text)
        self.bottom.insert = self.redir.register("insert", self.insert)
        self.bottom.delete = self.redir.register("delete", self.delete)
        self.filters = []

    def close(self):
        while self.top is not self.bottom:
            self.removefilter(self.top)
        self.top = None
        self.bottom.setdelegate(None)
        self.bottom = None
        self.redir.close()
        self.redir = None
        self.text = None

    def insert(self, index, chars, tags=None):
        # Could go away if inheriting from Delegator
        self.top.insert(index, chars, tags)

    def delete(self, index1, index2=None):
        # Could go away if inheriting from Delegator
        self.top.delete(index1, index2)

    def insertfilter(self, filter):
        # Perhaps rename to pushfilter()?
        assert isinstance(filter, Delegator)
        assert filter.delegate is None
        filter.setdelegate(self.top)
        self.top = filter

    def removefilter(self, filter):
        # XXX Perhaps should only support popfilter()?
        assert isinstance(filter, Delegator)
        assert filter.delegate is not None
        f = self.top
        if f is filter:
            self.top = filter.delegate
            filter.setdelegate(None)
        else:
            while f.delegate is not filter:
                assert f is not self.bottom
                f.resetcache()
                f = f.delegate
            f.setdelegate(filter.delegate)
            filter.setdelegate(None)
Beispiel #9
0
class Percolator:
    def __init__(self, text):
        # XXX would be nice to inherit from Delegator
        self.text = text
        self.redir = WidgetRedirector(text)
        self.top = self.bottom = Delegator(text)
        self.bottom.insert = self.redir.register("insert", self.insert)
        self.bottom.delete = self.redir.register("delete", self.delete)
        self.filters = []

    def close(self):
        while self.top is not self.bottom:
            self.removefilter(self.top)
        self.top = None
        self.bottom.setdelegate(None)
        self.bottom = None
        self.redir.close()
        self.redir = None
        self.text = None

    def insert(self, index, chars, tags=None):
        # Could go away if inheriting from Delegator
        self.top.insert(index, chars, tags)

    def delete(self, index1, index2=None):
        # Could go away if inheriting from Delegator
        self.top.delete(index1, index2)

    def insertfilter(self, filter):
        # Perhaps rename to pushfilter()?
        assert isinstance(filter, Delegator)
        assert filter.delegate is None
        filter.setdelegate(self.top)
        self.top = filter

    def removefilter(self, filter):
        # XXX Perhaps should only support popfilter()?
        assert isinstance(filter, Delegator)
        assert filter.delegate is not None
        f = self.top
        if f is filter:
            self.top = filter.delegate
            filter.setdelegate(None)
        else:
            while f.delegate is not filter:
                assert f is not self.bottom
                f.resetcache()
                f = f.delegate
            f.setdelegate(filter.delegate)
            filter.setdelegate(None)
Beispiel #10
0
 def __init__(self, text):
     # XXX would be nice to inherit from Delegator
     self.text = text
     self.redir = WidgetRedirector(text)
     self.top = self.bottom = Delegator(text)
     self.bottom.insert = self.redir.register("insert", self.insert)
     self.bottom.delete = self.redir.register("delete", self.delete)
     self.filters = []
Beispiel #11
0
 def __init__(self, *args, **kwargs):
     """Replace insert and delete bindings."""
     # subclass to tk.Text
     import tkinter as tk
     tk.Text.__init__(self, *args, **kwargs)
     self.SEL = tk.SEL
     self.END = tk.END
     self.INSERT = tk.INSERT
     from idlelib.redirector import WidgetRedirector
     self.redirector = WidgetRedirector(self)
     # freeze user changes
     self.insert = self.redirector.register('insert',
                                            lambda *args, **kw: 'break')
     self.delete = self.redirector.register('delete',
                                            lambda *args, **kw: 'break')
     # bind ctrl-a as select all
     self.bind("<Control-Key-a>", self.select_all)
Beispiel #12
0
class Percolator:
    def __init__(self, text):
        self.text = text
        self.redir = WidgetRedirector(text)
        self.top = self.bottom = Delegator(text)
        self.bottom.insert = self.redir.register('insert', self.insert)
        self.bottom.delete = self.redir.register('delete', self.delete)
        self.filters = []

    def close(self):
        while self.top is not self.bottom:
            self.removefilter(self.top)
        self.top = None
        self.bottom.setdelegate(None)
        self.bottom = None
        self.redir.close()
        self.redir = None
        self.text = None

    def insert(self, index, chars, tags=None):
        self.top.insert(index, chars, tags)

    def delete(self, index1, index2=None):
        self.top.delete(index1, index2)

    def insertfilter(self, filter):
        assert isinstance(filter, Delegator)
        assert filter.delegate is None
        filter.setdelegate(self.top)
        self.top = filter

    def removefilter(self, filter):
        assert isinstance(filter, Delegator)
        assert filter.delegate is not None
        f = self.top
        if f is filter:
            self.top = filter.delegate
            filter.setdelegate(None)
        else:
            while f.delegate is not filter:
                assert f is not self.bottom
                f.resetcache()
                f = f.delegate
            f.setdelegate(filter.delegate)
            filter.setdelegate(None)
Beispiel #13
0
    def __init__(self, master, **opt):

        opt['exportselection'] = 0  # Don't let it write to clipboard
        opt['takefocus'] = 0  # Ignore when tabbing
        super().__init__(master, **opt)

        self.redirector = redir = WidgetRedirector(self)
        # These two TK commands are used for all text operations,
        # so cancelling them stops anything from happening.
        self.insert = redir.register('insert', event_cancel)
        self.delete = redir.register('delete', event_cancel)
Beispiel #14
0
class ReadOnlyText(Text):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.redirector = WidgetRedirector(self)
        self.insert = self.redirector.register("insert", lambda *args, **kw: "break")
        self.delete = self.redirector.register("delete", lambda *args, **kw: "break")

        self.bind("<Control-a>", self._on_ctrl_a)

    def _on_ctrl_a(self, ev):
        self.tag_add("sel", "1.0", "end")
        return "break"
Beispiel #15
0
    def __init__(self, master: Widget, document: FileDocument, **kwargs) \
            -> None:
        """
        Creates a live preview widget.

        :param master: the parent widget
        :param document: the model for the current KnitScript document
        """
        super().__init__(master, **kwargs)
        self.pack_propagate(False)
        self._text = Text(self,
                          font=_get_default_font(),
                          wrap=WORD,
                          padx=5,
                          pady=5,
                          relief=FLAT,
                          bg=("systemSheetBackground" if platform.system()
                              == "Darwin" else "systemMenu"),
                          highlightthickness=0)

        menu = _create_edit_menu(self._text)
        self._text.bind(_BUTTONS["context_menu"],
                        partial(_show_context_menu, menu),
                        add=True)

        redirector = WidgetRedirector(self._text)
        redirector.register("insert", lambda *args: "break")
        redirector.register("delete", lambda *args: "break")

        scrollbar = Scrollbar(self, command=self._text.yview)
        self._text.configure(yscrollcommand=scrollbar.set)
        scrollbar.pack(side=RIGHT, fill=Y)
        self._text.pack(side=LEFT, expand=YES, fill=BOTH)

        self._document = document
        self._document.bind("<<Opened>>", self._preview, add=True)
        self._document.bind("<<Set>>",
                            _debounce(master, 500)(self._preview),
                            add=True)
        self._preview()
class WidgetRedirectorTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        requires('gui')
        cls.root = Tk()
        cls.root.withdraw()
        cls.text = Text(cls.root)

    @classmethod
    def tearDownClass(cls):
        del cls.text
        cls.root.update_idletasks()
        cls.root.destroy()
        del cls.root

    def setUp(self):
        self.redir = WidgetRedirector(self.text)
        self.func = Func()
        self.orig_insert = self.redir.register('insert', self.func)
        self.text.insert('insert', 'asdf')

    def tearDown(self):
        self.text.delete('1.0', 'end')
        self.redir.close()

    def test_repr(self):
        self.assertIn('Redirector', repr(self.redir))
        self.assertIn('Original', repr(self.orig_insert))

    def test_register(self):
        self.assertEqual(self.text.get('1.0', 'end'), '\n')
        self.assertEqual(self.func.args, ('insert', 'asdf'))
        self.assertIn('insert', self.redir._operations)
        self.assertIn('insert', self.text.__dict__)
        self.assertEqual(self.text.insert, self.func)

    def test_original_command(self):
        self.assertEqual(self.orig_insert.operation, 'insert')
        self.assertEqual(self.orig_insert.tk_call, self.text.tk.call)
        self.orig_insert('insert', 'asdf')
        self.assertEqual(self.text.get('1.0', 'end'), 'asdf\n')

    def test_unregister(self):
        self.assertIsNone(self.redir.unregister('invalid operation name'))
        self.assertEqual(self.redir.unregister('insert'), self.func)
        self.assertNotIn('insert', self.redir._operations)
        self.assertNotIn('insert', self.text.__dict__)

    def test_unregister_no_attribute(self):
        del self.text.insert
        self.assertEqual(self.redir.unregister('insert'), self.func)

    def test_dispatch_intercept(self):
        self.func.__init__(True)
        self.assertTrue(self.redir.dispatch('insert', False))
        self.assertFalse(self.func.args[0])

    def test_dispatch_bypass(self):
        self.orig_insert('insert', 'asdf')
        self.assertEqual(self.redir.dispatch('delete', '1.0', 'end'), '')
        self.assertEqual(self.text.get('1.0', 'end'), '\n')

    def test_dispatch_error(self):
        self.func.__init__(TclError())
        self.assertEqual(self.redir.dispatch('insert', False), '')
        self.assertEqual(self.redir.dispatch('invalid'), '')

    def test_command_dispatch(self):
        self.root.call(self.text._w, 'insert', 'hello')
        self.assertEqual(self.func.args, ('hello', ))
        self.assertEqual(self.text.get('1.0', 'end'), '\n')
        self.func.__init__(TclError())
        self.assertEqual(self.root.call(self.text._w, 'insert', 'boo'), '')
Beispiel #17
0
 def setUp(self):
     self.redir = WidgetRedirector(self.text)
     self.func = Func()
     self.orig_insert = self.redir.register('insert', self.func)
     self.text.insert('insert', 'asdf')  # leaves self.text empty
Beispiel #18
0
 def test_close(self):
     redir = WidgetRedirector(self.text)
     redir.register('insert', Func)
     redir.close()
     self.assertEqual(redir._operations, {})
     self.assertFalse(hasattr(self.text, 'widget'))
Beispiel #19
0
class WidgetRedirectorTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        requires('gui')
        cls.root = Tk()
        cls.root.withdraw()
        cls.text = Text(cls.root)

    @classmethod
    def tearDownClass(cls):
        del cls.text
        cls.root.update_idletasks()
        cls.root.destroy()
        del cls.root

    def setUp(self):
        self.redir = WidgetRedirector(self.text)
        self.func = Func()
        self.orig_insert = self.redir.register('insert', self.func)
        self.text.insert('insert', 'asdf')  # leaves self.text empty

    def tearDown(self):
        self.text.delete('1.0', 'end')
        self.redir.close()

    def test_repr(self):  # partly for 100% coverage
        self.assertIn('Redirector', repr(self.redir))
        self.assertIn('Original', repr(self.orig_insert))

    def test_register(self):
        self.assertEqual(self.text.get('1.0', 'end'), '\n')
        self.assertEqual(self.func.args, ('insert', 'asdf'))
        self.assertIn('insert', self.redir._operations)
        self.assertIn('insert', self.text.__dict__)
        self.assertEqual(self.text.insert, self.func)

    def test_original_command(self):
        self.assertEqual(self.orig_insert.operation, 'insert')
        self.assertEqual(self.orig_insert.tk_call, self.text.tk.call)
        self.orig_insert('insert', 'asdf')
        self.assertEqual(self.text.get('1.0', 'end'), 'asdf\n')

    def test_unregister(self):
        self.assertIsNone(self.redir.unregister('invalid operation name'))
        self.assertEqual(self.redir.unregister('insert'), self.func)
        self.assertNotIn('insert', self.redir._operations)
        self.assertNotIn('insert', self.text.__dict__)

    def test_unregister_no_attribute(self):
        del self.text.insert
        self.assertEqual(self.redir.unregister('insert'), self.func)

    def test_dispatch_intercept(self):
        self.func.__init__(True)
        self.assertTrue(self.redir.dispatch('insert', False))
        self.assertFalse(self.func.args[0])

    def test_dispatch_bypass(self):
        self.orig_insert('insert', 'asdf')
        # tk.call returns '' where Python would return None
        self.assertEqual(self.redir.dispatch('delete', '1.0', 'end'), '')
        self.assertEqual(self.text.get('1.0', 'end'), '\n')

    def test_dispatch_error(self):
        self.func.__init__(TclError())
        self.assertEqual(self.redir.dispatch('insert', False), '')
        self.assertEqual(self.redir.dispatch('invalid'), '')

    def test_command_dispatch(self):
        # Test that .__init__ causes redirection of tk calls
        # through redir.dispatch
        self.root.call(self.text._w, 'insert', 'hello')
        self.assertEqual(self.func.args, ('hello', ))
        self.assertEqual(self.text.get('1.0', 'end'), '\n')
        # Ensure that called through redir .dispatch and not through
        # self.text.insert by having mock raise TclError.
        self.func.__init__(TclError())
        self.assertEqual(self.root.call(self.text._w, 'insert', 'boo'), '')
Beispiel #20
0
 def test_init(self):
     redir = WidgetRedirector(self.text)
     self.assertEqual(redir.widget, self.text)
     self.assertEqual(redir.tk, self.text.tk)
     self.assertRaises(TclError, WidgetRedirector, self.text)
     redir.close()  # restore self.tk, self.text
Beispiel #21
0
    def __init__(self, master: Widget, document: FileDocument, **kwargs) \
            -> None:
        """
        Creates a text editor widget.

        :param master: the parent widget
        :param document: the model for the current KnitScript document
        """
        super().__init__(master, **kwargs)
        self.pack_propagate(False)
        text = Text(self,
                    undo=True,
                    font=_get_fixed_font(),
                    wrap=WORD,
                    padx=5,
                    pady=5,
                    relief=FLAT,
                    highlightthickness=0)

        menu = _create_edit_menu(text)
        text.bind(_BUTTONS["context_menu"],
                  partial(_show_context_menu, menu),
                  add=True)

        scrollbar = Scrollbar(self, command=text.yview)
        text.configure(yscrollcommand=scrollbar.set)
        scrollbar.pack(side=RIGHT, fill=Y)
        text.pack(side=LEFT, expand=YES, fill=BOTH)
        self.bind("<FocusIn>", lambda event: text.focus_set())

        # TODO:
        #  This is kind of a hack to stop Ctrl-O from inserting a new line. :/
        if platform.system() != "Darwin":

            def on_open(_event: Event) -> str:
                self.master.open()
                return "break"

            text.bind("<Control-o>", on_open)

        def on_enter(_event: Event) -> str:
            # Keep the indent on the new line the same as the current line.
            line = text.get("insert linestart", "insert lineend")
            indent = " " * sum(1 for _ in takewhile(lambda c: c == " ", line))
            if text.tag_ranges(SEL) == ():
                text.insert(INSERT, "\n" + indent)
            else:
                text.replace(SEL_FIRST, SEL_LAST, "\n" + indent)
            return "break"

        text.bind("<Return>", on_enter)

        def on_change(operation: Callable[..., None], *args) -> None:
            operation(*args)
            document.text = _strip_trailing_newline(text.get("1.0", END))
            document.modified = text.edit_modified()

        redirector = WidgetRedirector(text)
        insert = redirector.register("insert", None)
        delete = redirector.register("delete", None)
        replace = redirector.register("replace", None)
        redirector.register("insert", partial(on_change, insert))
        redirector.register("delete", partial(on_change, delete))
        redirector.register("replace", partial(on_change, replace))

        def bind_text_modified() -> None:
            def on_text_modified(_event: Event) -> None:
                document.modified = text.edit_modified()

            text.edit_modified(False)
            text.bind("<<Modified>>", on_text_modified, add=True)

        text.insert("1.0", document.text)
        self.after_idle(bind_text_modified)

        def on_document_opened(_event: Event) -> None:
            text.replace("1.0", END, document.text)
            text.edit_modified(False)

        def on_document_modified(_event: Event) -> None:
            if document.modified != text.edit_modified():
                text.edit_modified(document.modified)

        document.bind("<<Opened>>", on_document_opened, add=True)
        document.bind("<<Modified>>", on_document_modified, add=True)
Beispiel #22
0
 def test_init(self):
     redir = WidgetRedirector(self.text)
     self.assertEqual(redir.widget, self.text)
     self.assertEqual(redir.tk, self.text.tk)
     self.assertRaises(TclError, WidgetRedirector, self.text)
     redir.close()  # restore self.tk, self.text
Beispiel #23
0
 def setUp(self):
     self.redir = WidgetRedirector(self.text)
     self.func = Func()
     self.orig_insert = self.redir.register('insert', self.func)
     self.text.insert('insert', 'asdf')  # leaves self.text empty
Beispiel #24
0
 def test_close(self):
     redir = WidgetRedirector(self.text)
     redir.register('insert', Func)
     redir.close()
     self.assertEqual(redir._operations, {})
     self.assertFalse(hasattr(self.text, 'widget'))
Beispiel #25
0
class WidgetRedirectorTest(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        requires('gui')
        cls.tk = Tk()
        cls.text = Text(cls.tk)

    @classmethod
    def tearDownClass(cls):
        cls.text.destroy()
        cls.tk.destroy()
        del cls.text, cls.tk

    def setUp(self):
        self.redir = WidgetRedirector(self.text)
        self.func = Func()
        self.orig_insert = self.redir.register('insert', self.func)
        self.text.insert('insert', 'asdf')  # leaves self.text empty

    def tearDown(self):
        self.text.delete('1.0', 'end')
        self.redir.close()

    def test_repr(self):  # partly for 100% coverage
        self.assertIn('Redirector', repr(self.redir))
        self.assertIn('Original', repr(self.orig_insert))

    def test_register(self):
        self.assertEqual(self.text.get('1.0', 'end'), '\n')
        self.assertEqual(self.func.args, ('insert', 'asdf'))
        self.assertIn('insert', self.redir._operations)
        self.assertIn('insert', self.text.__dict__)
        self.assertEqual(self.text.insert, self.func)

    def test_original_command(self):
        self.assertEqual(self.orig_insert.operation, 'insert')
        self.assertEqual(self.orig_insert.tk_call, self.text.tk.call)
        self.orig_insert('insert', 'asdf')
        self.assertEqual(self.text.get('1.0', 'end'), 'asdf\n')

    def test_unregister(self):
        self.assertIsNone(self.redir.unregister('invalid operation name'))
        self.assertEqual(self.redir.unregister('insert'), self.func)
        self.assertNotIn('insert', self.redir._operations)
        self.assertNotIn('insert', self.text.__dict__)

    def test_unregister_no_attribute(self):
        del self.text.insert
        self.assertEqual(self.redir.unregister('insert'), self.func)

    def test_dispatch_intercept(self):
        self.func.__init__(True)
        self.assertTrue(self.redir.dispatch('insert', False))
        self.assertFalse(self.func.args[0])

    def test_dispatch_bypass(self):
        self.orig_insert('insert', 'asdf')
        # tk.call returns '' where Python would return None
        self.assertEqual(self.redir.dispatch('delete', '1.0', 'end'), '')
        self.assertEqual(self.text.get('1.0', 'end'), '\n')

    def test_dispatch_error(self):
        self.func.__init__(TclError())
        self.assertEqual(self.redir.dispatch('insert', False), '')
        self.assertEqual(self.redir.dispatch('invalid'), '')

    def test_command_dispatch(self):
        # Test that .__init__ causes redirection of tk calls
        # through redir.dispatch
        self.tk.call(self.text._w, 'insert', 'hello')
        self.assertEqual(self.func.args, ('hello',))
        self.assertEqual(self.text.get('1.0', 'end'), '\n')
        # Ensure that called through redir .dispatch and not through
        # self.text.insert by having mock raise TclError.
        self.func.__init__(TclError())
        self.assertEqual(self.tk.call(self.text._w, 'insert', 'boo'), '')
Beispiel #26
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self.redirector = WidgetRedirector(self)
     self.insert = self.redirector.register("insert", lambda *a, **k: BREAK)
     self.delete = self.redirector.register("delete", lambda *a, **k: BREAK)