Beispiel #1
0
class DrtGlueDemo(object):
    def __init__(self, examples):
        # Set up the main window.
        self._top = Tk()
        self._top.title('DRT Glue Demo')

        # Set up key bindings.
        self._init_bindings()

        # Initialize the fonts.self._error = None
        self._init_fonts(self._top)

        self._examples = examples
        self._readingCache = [None for example in examples]

        # The user can hide the grammar.
        self._show_grammar = IntVar(self._top)
        self._show_grammar.set(1)

        # Set the data to None
        self._curExample = -1
        self._readings = []
        self._drs = None
        self._drsWidget = None
        self._error = None

        self._init_glue()

        # Create the basic frames.
        self._init_menubar(self._top)
        self._init_buttons(self._top)
        self._init_exampleListbox(self._top)
        self._init_readingListbox(self._top)
        self._init_canvas(self._top)

        # Resize callback
        self._canvas.bind('<Configure>', self._configure)

    #########################################
    ##  Initialization Helpers
    #########################################

    def _init_glue(self):
        tagger = RegexpTagger([
            ('^(David|Mary|John)$', 'NNP'),
            ('^(walks|sees|eats|chases|believes|gives|sleeps|chases|persuades|tries|seems|leaves)$',
             'VB'), ('^(go|order|vanish|find|approach)$', 'VB'),
            ('^(a)$', 'ex_quant'), ('^(every)$', 'univ_quant'),
            ('^(sandwich|man|dog|pizza|unicorn|cat|senator)$', 'NN'),
            ('^(big|gray|former)$', 'JJ'), ('^(him|himself)$', 'PRP')
        ])

        depparser = MaltParser(tagger=tagger)
        self._glue = DrtGlue(depparser=depparser, remove_duplicates=False)

    def _init_fonts(self, root):
        # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html>
        self._sysfont = Font(font=Button()["font"])
        root.option_add("*Font", self._sysfont)

        # TWhat's our font size (default=same as sysfont)
        self._size = IntVar(root)
        self._size.set(self._sysfont.cget('size'))

        self._boldfont = Font(family='helvetica',
                              weight='bold',
                              size=self._size.get())
        self._font = Font(family='helvetica', size=self._size.get())
        if self._size.get() < 0: big = self._size.get() - 2
        else: big = self._size.get() + 2
        self._bigfont = Font(family='helvetica', weight='bold', size=big)

    def _init_exampleListbox(self, parent):
        self._exampleFrame = listframe = Frame(parent)
        self._exampleFrame.pack(fill='both', side='left', padx=2)
        self._exampleList_label = Label(self._exampleFrame,
                                        font=self._boldfont,
                                        text='Examples')
        self._exampleList_label.pack()
        self._exampleList = Listbox(self._exampleFrame,
                                    selectmode='single',
                                    relief='groove',
                                    background='white',
                                    foreground='#909090',
                                    font=self._font,
                                    selectforeground='#004040',
                                    selectbackground='#c0f0c0')

        self._exampleList.pack(side='right', fill='both', expand=1)

        for example in self._examples:
            self._exampleList.insert('end', ('  %s' % example))
        self._exampleList.config(height=min(len(self._examples), 25), width=40)

        # Add a scrollbar if there are more than 25 examples.
        if len(self._examples) > 25:
            listscroll = Scrollbar(self._exampleFrame, orient='vertical')
            self._exampleList.config(yscrollcommand=listscroll.set)
            listscroll.config(command=self._exampleList.yview)
            listscroll.pack(side='left', fill='y')

        # If they select a example, apply it.
        self._exampleList.bind('<<ListboxSelect>>', self._exampleList_select)

    def _init_readingListbox(self, parent):
        self._readingFrame = listframe = Frame(parent)
        self._readingFrame.pack(fill='both', side='left', padx=2)
        self._readingList_label = Label(self._readingFrame,
                                        font=self._boldfont,
                                        text='Readings')
        self._readingList_label.pack()
        self._readingList = Listbox(self._readingFrame,
                                    selectmode='single',
                                    relief='groove',
                                    background='white',
                                    foreground='#909090',
                                    font=self._font,
                                    selectforeground='#004040',
                                    selectbackground='#c0f0c0')

        self._readingList.pack(side='right', fill='both', expand=1)

        # Add a scrollbar if there are more than 25 examples.
        listscroll = Scrollbar(self._readingFrame, orient='vertical')
        self._readingList.config(yscrollcommand=listscroll.set)
        listscroll.config(command=self._readingList.yview)
        listscroll.pack(side='right', fill='y')

        self._populate_readingListbox()

    def _populate_readingListbox(self):
        # Populate the listbox with integers
        self._readingList.delete(0, 'end')
        for i in range(len(self._readings)):
            self._readingList.insert('end', ('  %s' % (i + 1)))
        self._readingList.config(height=min(len(self._readings), 25), width=5)

        # If they select a example, apply it.
        self._readingList.bind('<<ListboxSelect>>', self._readingList_select)

    def _init_bindings(self):
        # Key bindings are a good thing.
        self._top.bind('<Control-q>', self.destroy)
        self._top.bind('<Control-x>', self.destroy)
        self._top.bind('<Escape>', self.destroy)
        self._top.bind('n', self.next)
        self._top.bind('<space>', self.next)
        self._top.bind('p', self.prev)
        self._top.bind('<BackSpace>', self.prev)

    def _init_buttons(self, parent):
        # Set up the frames.
        self._buttonframe = buttonframe = Frame(parent)
        buttonframe.pack(fill='none', side='bottom', padx=3, pady=2)
        Button(
            buttonframe,
            text='Prev',
            background='#90c0d0',
            foreground='black',
            command=self.prev,
        ).pack(side='left')
        Button(
            buttonframe,
            text='Next',
            background='#90c0d0',
            foreground='black',
            command=self.next,
        ).pack(side='left')

    def _configure(self, event):
        self._autostep = 0
        (x1, y1, x2, y2) = self._cframe.scrollregion()
        y2 = event.height - 6
        self._canvas['scrollregion'] = '%d %d %d %d' % (x1, y1, x2, y2)
        self._redraw()

    def _init_canvas(self, parent):
        self._cframe = CanvasFrame(
            parent,
            background='white',
            #width=525, height=250,
            closeenough=10,
            border=2,
            relief='sunken')
        self._cframe.pack(expand=1, fill='both', side='top', pady=2)
        canvas = self._canvas = self._cframe.canvas()

        # Initially, there's no tree or text
        self._tree = None
        self._textwidgets = []
        self._textline = None

    def _init_menubar(self, parent):
        menubar = Menu(parent)

        filemenu = Menu(menubar, tearoff=0)
        filemenu.add_command(label='Exit',
                             underline=1,
                             command=self.destroy,
                             accelerator='q')
        menubar.add_cascade(label='File', underline=0, menu=filemenu)

        actionmenu = Menu(menubar, tearoff=0)
        actionmenu.add_command(label='Next',
                               underline=0,
                               command=self.next,
                               accelerator='n, Space')
        actionmenu.add_command(label='Previous',
                               underline=0,
                               command=self.prev,
                               accelerator='p, Backspace')
        menubar.add_cascade(label='Action', underline=0, menu=actionmenu)

        optionmenu = Menu(menubar, tearoff=0)
        optionmenu.add_checkbutton(label='Remove Duplicates',
                                   underline=0,
                                   variable=self._glue.remove_duplicates,
                                   command=self._toggle_remove_duplicates,
                                   accelerator='r')
        menubar.add_cascade(label='Options', underline=0, menu=optionmenu)

        viewmenu = Menu(menubar, tearoff=0)
        viewmenu.add_radiobutton(label='Tiny',
                                 variable=self._size,
                                 underline=0,
                                 value=10,
                                 command=self.resize)
        viewmenu.add_radiobutton(label='Small',
                                 variable=self._size,
                                 underline=0,
                                 value=12,
                                 command=self.resize)
        viewmenu.add_radiobutton(label='Medium',
                                 variable=self._size,
                                 underline=0,
                                 value=14,
                                 command=self.resize)
        viewmenu.add_radiobutton(label='Large',
                                 variable=self._size,
                                 underline=0,
                                 value=18,
                                 command=self.resize)
        viewmenu.add_radiobutton(label='Huge',
                                 variable=self._size,
                                 underline=0,
                                 value=24,
                                 command=self.resize)
        menubar.add_cascade(label='View', underline=0, menu=viewmenu)

        helpmenu = Menu(menubar, tearoff=0)
        helpmenu.add_command(label='About', underline=0, command=self.about)
        menubar.add_cascade(label='Help', underline=0, menu=helpmenu)

        parent.config(menu=menubar)

    #########################################
    ##  Main draw procedure
    #########################################

    def _redraw(self):
        canvas = self._canvas

        # Delete the old DRS, widgets, etc.
        if self._drsWidget is not None:
            self._drsWidget.clear()

        if self._drs:
            self._drsWidget = DrsWidget(self._canvas, self._drs)
            self._drsWidget.draw()

        if self._error:
            self._drsWidget = DrsWidget(self._canvas, self._error)
            self._drsWidget.draw()

    #########################################
    ##  Button Callbacks
    #########################################

    def destroy(self, *e):
        self._autostep = 0
        if self._top is None: return
        self._top.destroy()
        self._top = None

    def prev(self, *e):
        selection = self._readingList.curselection()
        readingListSize = self._readingList.size()

        # there are readings
        if readingListSize > 0:
            # if one reading is currently selected
            if len(selection) == 1:
                index = int(selection[0])

                # if it's on (or before) the first item
                if index <= 0:
                    self._select_previous_example()
                else:
                    self._readingList_store_selection(index - 1)

            else:
                #select its first reading
                self._readingList_store_selection(readingListSize - 1)

        else:
            self._select_previous_example()

    def _select_previous_example(self):
        #if the current example is not the first example
        if self._curExample > 0:
            self._exampleList_store_selection(self._curExample - 1)
        else:
            #go to the last example
            self._exampleList_store_selection(len(self._examples) - 1)

    def next(self, *e):
        selection = self._readingList.curselection()
        readingListSize = self._readingList.size()

        # if there are readings
        if readingListSize > 0:
            # if one reading is currently selected
            if len(selection) == 1:
                index = int(selection[0])

                # if it's on (or past) the last item
                if index >= (readingListSize - 1):
                    self._select_next_example()
                else:
                    self._readingList_store_selection(index + 1)

            else:
                #select its first reading
                self._readingList_store_selection(0)

        else:
            self._select_next_example()

    def _select_next_example(self):
        #if the current example is not the last example
        if self._curExample < len(self._examples) - 1:
            self._exampleList_store_selection(self._curExample + 1)
        else:
            #go to the first example
            self._exampleList_store_selection(0)

    def about(self, *e):
        ABOUT = (
            "NLTK Discourse Representation Theory (DRT) Glue Semantics Demo\n"
            + "Written by Daniel H. Garrette")
        TITLE = 'About: NLTK DRT Glue Demo'
        try:
            from six.moves.tkinter_messagebox import Message
            Message(message=ABOUT, title=TITLE).show()
        except:
            ShowText(self._top, TITLE, ABOUT)

    def postscript(self, *e):
        self._autostep = 0
        self._cframe.print_to_file()

    def mainloop(self, *args, **kwargs):
        """
        Enter the Tkinter mainloop.  This function must be called if
        this demo is created from a non-interactive program (e.g.
        from a secript); otherwise, the demo will close as soon as
        the script completes.
        """
        if in_idle(): return
        self._top.mainloop(*args, **kwargs)

    def resize(self, size=None):
        if size is not None: self._size.set(size)
        size = self._size.get()
        self._font.configure(size=-(abs(size)))
        self._boldfont.configure(size=-(abs(size)))
        self._sysfont.configure(size=-(abs(size)))
        self._bigfont.configure(size=-(abs(size + 2)))
        self._redraw()

    def _toggle_remove_duplicates(self):
        self._glue.remove_duplicates = not self._glue.remove_duplicates

        self._exampleList.selection_clear(0, 'end')
        self._readings = []
        self._populate_readingListbox()
        self._readingCache = [None for ex in self._examples]
        self._curExample = -1
        self._error = None

        self._drs = None
        self._redraw()

    def _exampleList_select(self, event):
        selection = self._exampleList.curselection()
        if len(selection) != 1: return
        self._exampleList_store_selection(int(selection[0]))

    def _exampleList_store_selection(self, index):
        self._curExample = index
        example = self._examples[index]

        self._exampleList.selection_clear(0, 'end')
        if example:
            cache = self._readingCache[index]
            if cache:
                if isinstance(cache, list):
                    self._readings = cache
                    self._error = None
                else:
                    self._readings = []
                    self._error = cache
            else:
                try:
                    self._readings = self._glue.parse_to_meaning(example)
                    self._error = None
                    self._readingCache[index] = self._readings
                except Exception as e:
                    self._readings = []
                    self._error = DrtVariableExpression(
                        Variable('Error: ' + str(e)))
                    self._readingCache[index] = self._error

                    #add a star to the end of the example
                    self._exampleList.delete(index)
                    self._exampleList.insert(index, ('  %s *' % example))
                    self._exampleList.config(height=min(
                        len(self._examples), 25),
                                             width=40)

            self._populate_readingListbox()

            self._exampleList.selection_set(index)

            self._drs = None
            self._redraw()

    def _readingList_select(self, event):
        selection = self._readingList.curselection()
        if len(selection) != 1: return
        self._readingList_store_selection(int(selection[0]))

    def _readingList_store_selection(self, index):
        reading = self._readings[index]

        self._readingList.selection_clear(0, 'end')
        if reading:
            self._readingList.selection_set(index)

            self._drs = reading.simplify().normalize().resolve_anaphora()

            self._redraw()
Beispiel #2
0
class LintGui(object):
    """Build and control a window to interact with pylint"""
    def __init__(self, root=None):
        """init"""
        self.root = root or Tk()
        self.root.title('Pylint')
        #reporter
        self.reporter = None
        #message queue for output from reporter
        self.msg_queue = six.moves.queue.Queue()
        self.msgs = []
        self.visible_msgs = []
        self.filenames = []
        self.rating = StringVar()
        self.tabs = {}
        self.report_stream = BasicStream(self)
        #gui objects
        self.lb_messages = None
        self.showhistory = None
        self.results = None
        self.btnRun = None
        self.information_box = None
        self.convention_box = None
        self.refactor_box = None
        self.warning_box = None
        self.error_box = None
        self.fatal_box = None
        self.txtModule = None
        self.status = None
        self.msg_type_dict = None
        self.init_gui()

    def init_gui(self):
        """init helper"""

        window = PanedWindow(self.root, orient="vertical")
        window.pack(side=TOP, fill=BOTH, expand=True)

        top_pane = Frame(window)
        window.add(top_pane)
        mid_pane = Frame(window)
        window.add(mid_pane)
        bottom_pane = Frame(window)
        window.add(bottom_pane)

        #setting up frames
        top_frame = Frame(top_pane)
        mid_frame = Frame(top_pane)
        history_frame = Frame(top_pane)
        radio_frame = Frame(mid_pane)
        rating_frame = Frame(mid_pane)
        res_frame = Frame(mid_pane)
        check_frame = Frame(bottom_pane)
        msg_frame = Frame(bottom_pane)
        btn_frame = Frame(bottom_pane)
        top_frame.pack(side=TOP, fill=X)
        mid_frame.pack(side=TOP, fill=X)
        history_frame.pack(side=TOP, fill=BOTH, expand=True)
        radio_frame.pack(side=TOP, fill=X)
        rating_frame.pack(side=TOP, fill=X)
        res_frame.pack(side=TOP, fill=BOTH, expand=True)
        check_frame.pack(side=TOP, fill=X)
        msg_frame.pack(side=TOP, fill=BOTH, expand=True)
        btn_frame.pack(side=TOP, fill=X)

        # Binding F5 application-wide to run lint
        self.root.bind('<F5>', self.run_lint)

        #Message ListBox
        rightscrollbar = Scrollbar(msg_frame)
        rightscrollbar.pack(side=RIGHT, fill=Y)
        bottomscrollbar = Scrollbar(msg_frame, orient=HORIZONTAL)
        bottomscrollbar.pack(side=BOTTOM, fill=X)
        self.lb_messages = Listbox(msg_frame,
                                   yscrollcommand=rightscrollbar.set,
                                   xscrollcommand=bottomscrollbar.set,
                                   bg="white")
        self.lb_messages.bind("<Double-Button-1>", self.show_sourcefile)
        self.lb_messages.pack(expand=True, fill=BOTH)
        rightscrollbar.config(command=self.lb_messages.yview)
        bottomscrollbar.config(command=self.lb_messages.xview)

        #History ListBoxes
        rightscrollbar2 = Scrollbar(history_frame)
        rightscrollbar2.pack(side=RIGHT, fill=Y)
        bottomscrollbar2 = Scrollbar(history_frame, orient=HORIZONTAL)
        bottomscrollbar2.pack(side=BOTTOM, fill=X)
        self.showhistory = Listbox(history_frame,
                                   yscrollcommand=rightscrollbar2.set,
                                   xscrollcommand=bottomscrollbar2.set,
                                   bg="white")
        self.showhistory.pack(expand=True, fill=BOTH)
        rightscrollbar2.config(command=self.showhistory.yview)
        bottomscrollbar2.config(command=self.showhistory.xview)
        self.showhistory.bind('<Double-Button-1>', self.select_recent_file)
        self.set_history_window()

        #status bar
        self.status = Label(self.root, text="", bd=1, relief=SUNKEN, anchor=W)
        self.status.pack(side=BOTTOM, fill=X)

        #labelbl_ratingls
        lbl_rating_label = Label(rating_frame, text='Rating:')
        lbl_rating_label.pack(side=LEFT)
        lbl_rating = Label(rating_frame, textvariable=self.rating)
        lbl_rating.pack(side=LEFT)
        Label(mid_frame, text='Recently Used:').pack(side=LEFT)
        Label(top_frame, text='Module or package').pack(side=LEFT)

        #file textbox
        self.txt_module = Entry(top_frame, background='white')
        self.txt_module.bind('<Return>', self.run_lint)
        self.txt_module.pack(side=LEFT, expand=True, fill=X)

        #results box
        rightscrollbar = Scrollbar(res_frame)
        rightscrollbar.pack(side=RIGHT, fill=Y)
        bottomscrollbar = Scrollbar(res_frame, orient=HORIZONTAL)
        bottomscrollbar.pack(side=BOTTOM, fill=X)
        self.results = Listbox(res_frame,
                               yscrollcommand=rightscrollbar.set,
                               xscrollcommand=bottomscrollbar.set,
                               bg="white",
                               font="Courier")
        self.results.pack(expand=True, fill=BOTH, side=BOTTOM)
        rightscrollbar.config(command=self.results.yview)
        bottomscrollbar.config(command=self.results.xview)

        #buttons
        Button(top_frame, text='Open', command=self.file_open).pack(side=LEFT)
        Button(top_frame,
               text='Open Package',
               command=(lambda: self.file_open(package=True))).pack(side=LEFT)

        self.btnRun = Button(top_frame, text='Run', command=self.run_lint)
        self.btnRun.pack(side=LEFT)
        Button(btn_frame, text='Quit', command=self.quit).pack(side=BOTTOM)

        #radio buttons
        self.information_box = IntVar()
        self.convention_box = IntVar()
        self.refactor_box = IntVar()
        self.warning_box = IntVar()
        self.error_box = IntVar()
        self.fatal_box = IntVar()
        i = Checkbutton(check_frame,
                        text="Information",
                        fg=COLORS['(I)'],
                        variable=self.information_box,
                        command=self.refresh_msg_window)
        c = Checkbutton(check_frame,
                        text="Convention",
                        fg=COLORS['(C)'],
                        variable=self.convention_box,
                        command=self.refresh_msg_window)
        r = Checkbutton(check_frame,
                        text="Refactor",
                        fg=COLORS['(R)'],
                        variable=self.refactor_box,
                        command=self.refresh_msg_window)
        w = Checkbutton(check_frame,
                        text="Warning",
                        fg=COLORS['(W)'],
                        variable=self.warning_box,
                        command=self.refresh_msg_window)
        e = Checkbutton(check_frame,
                        text="Error",
                        fg=COLORS['(E)'],
                        variable=self.error_box,
                        command=self.refresh_msg_window)
        f = Checkbutton(check_frame,
                        text="Fatal",
                        fg=COLORS['(F)'],
                        variable=self.fatal_box,
                        command=self.refresh_msg_window)
        i.select()
        c.select()
        r.select()
        w.select()
        e.select()
        f.select()
        i.pack(side=LEFT)
        c.pack(side=LEFT)
        r.pack(side=LEFT)
        w.pack(side=LEFT)
        e.pack(side=LEFT)
        f.pack(side=LEFT)

        #check boxes
        self.box = StringVar()
        # XXX should be generated
        report = Radiobutton(radio_frame,
                             text="Report",
                             variable=self.box,
                             value="Report",
                             command=self.refresh_results_window)
        raw_met = Radiobutton(radio_frame,
                              text="Raw metrics",
                              variable=self.box,
                              value="Raw metrics",
                              command=self.refresh_results_window)
        dup = Radiobutton(radio_frame,
                          text="Duplication",
                          variable=self.box,
                          value="Duplication",
                          command=self.refresh_results_window)
        ext = Radiobutton(radio_frame,
                          text="External dependencies",
                          variable=self.box,
                          value="External dependencies",
                          command=self.refresh_results_window)
        stat = Radiobutton(radio_frame,
                           text="Statistics by type",
                           variable=self.box,
                           value="Statistics by type",
                           command=self.refresh_results_window)
        msg_cat = Radiobutton(radio_frame,
                              text="Messages by category",
                              variable=self.box,
                              value="Messages by category",
                              command=self.refresh_results_window)
        msg = Radiobutton(radio_frame,
                          text="Messages",
                          variable=self.box,
                          value="Messages",
                          command=self.refresh_results_window)
        source_file = Radiobutton(radio_frame,
                                  text="Source File",
                                  variable=self.box,
                                  value="Source File",
                                  command=self.refresh_results_window)
        report.select()
        report.grid(column=0, row=0, sticky=W)
        raw_met.grid(column=1, row=0, sticky=W)
        dup.grid(column=2, row=0, sticky=W)
        msg.grid(column=3, row=0, sticky=W)
        stat.grid(column=0, row=1, sticky=W)
        msg_cat.grid(column=1, row=1, sticky=W)
        ext.grid(column=2, row=1, sticky=W)
        source_file.grid(column=3, row=1, sticky=W)

        #dictionary for check boxes and associated error term
        self.msg_type_dict = {
            'I': lambda: self.information_box.get() == 1,
            'C': lambda: self.convention_box.get() == 1,
            'R': lambda: self.refactor_box.get() == 1,
            'E': lambda: self.error_box.get() == 1,
            'W': lambda: self.warning_box.get() == 1,
            'F': lambda: self.fatal_box.get() == 1
        }
        self.txt_module.focus_set()

    def select_recent_file(self, event):  # pylint: disable=unused-argument
        """adds the selected file in the history listbox to the Module box"""
        if not self.showhistory.size():
            return

        selected = self.showhistory.curselection()
        item = self.showhistory.get(selected)
        #update module
        self.txt_module.delete(0, END)
        self.txt_module.insert(0, item)

    def refresh_msg_window(self):
        """refresh the message window with current output"""
        #clear the window
        self.lb_messages.delete(0, END)
        self.visible_msgs = []
        for msg in self.msgs:
            if self.msg_type_dict.get(msg.C)():
                self.visible_msgs.append(msg)
                msg_str = convert_to_string(msg)
                self.lb_messages.insert(END, msg_str)
                fg_color = COLORS.get(msg_str[:3], 'black')
                self.lb_messages.itemconfigure(END, fg=fg_color)

    def refresh_results_window(self):
        """refresh the results window with current output"""
        #clear the window
        self.results.delete(0, END)
        try:
            for res in self.tabs[self.box.get()]:
                self.results.insert(END, res)
        except KeyError:
            pass

    def process_incoming(self):
        """process the incoming messages from running pylint"""
        while self.msg_queue.qsize():
            try:
                msg = self.msg_queue.get(0)
                if msg == "DONE":
                    self.report_stream.output_contents()
                    return False

                #adding message to list of msgs
                self.msgs.append(msg)

                #displaying msg if message type is selected in check box
                if self.msg_type_dict.get(msg.C)():
                    self.visible_msgs.append(msg)
                    msg_str = convert_to_string(msg)
                    self.lb_messages.insert(END, msg_str)
                    fg_color = COLORS.get(msg_str[:3], 'black')
                    self.lb_messages.itemconfigure(END, fg=fg_color)

            except six.moves.queue.Empty:
                pass
        return True

    def periodic_call(self):
        """determine when to unlock the run button"""
        if self.process_incoming():
            self.root.after(100, self.periodic_call)
        else:
            #enabling button so it can be run again
            self.btnRun.config(state=NORMAL)

    def mainloop(self):
        """launch the mainloop of the application"""
        self.root.mainloop()

    def quit(self, _=None):
        """quit the application"""
        self.root.quit()

    def halt(self):  # pylint: disable=no-self-use
        """program halt placeholder"""
        return

    def file_open(self, package=False, _=None):
        """launch a file browser"""
        if not package:
            filename = askopenfilename(parent=self.root,
                                       filetypes=[('pythonfiles', '*.py'),
                                                  ('allfiles', '*')],
                                       title='Select Module')
        else:
            filename = askdirectory(title="Select A Folder", mustexist=1)

        if filename == ():
            return

        self.txt_module.delete(0, END)
        self.txt_module.insert(0, filename)

    def update_filenames(self):
        """update the list of recent filenames"""
        filename = self.txt_module.get()
        if not filename:
            filename = os.getcwd()
        if filename + '\n' in self.filenames:
            index = self.filenames.index(filename + '\n')
            self.filenames.pop(index)

        #ensure only 10 most recent are stored
        if len(self.filenames) == 10:
            self.filenames.pop()
        self.filenames.insert(0, filename + '\n')

    def set_history_window(self):
        """update the history window with info from the history file"""
        #clear the window
        self.showhistory.delete(0, END)
        # keep the last 10 most recent files
        try:
            view_history = open(HOME + HISTORY, 'r')
            for hist in view_history.readlines():
                if hist not in self.filenames:
                    self.filenames.append(hist)
                self.showhistory.insert(END, hist.split('\n')[0])
            view_history.close()
        except IOError:
            # do nothing since history file will be created later
            return

    def run_lint(self, _=None):
        """launches pylint"""
        self.update_filenames()
        self.root.configure(cursor='watch')
        self.reporter = GUIReporter(self, output=self.report_stream)
        module = self.txt_module.get()
        if not module:
            module = os.getcwd()

        #cleaning up msgs and windows
        self.msgs = []
        self.visible_msgs = []
        self.lb_messages.delete(0, END)
        self.tabs = {}
        self.results.delete(0, END)
        self.btnRun.config(state=DISABLED)

        #setting up a worker thread to run pylint
        worker = Thread(target=lint_thread,
                        args=(
                            module,
                            self.reporter,
                            self,
                        ))
        self.periodic_call()
        worker.start()

        # Overwrite the .pylint-gui-history file with all the new recently added files
        # in order from filenames but only save last 10 files
        write_history = open(HOME + HISTORY, 'w')
        write_history.writelines(self.filenames)
        write_history.close()
        self.set_history_window()

        self.root.configure(cursor='')

    def show_sourcefile(self, event=None):  # pylint: disable=unused-argument
        selected = self.lb_messages.curselection()
        if not selected:
            return

        msg = self.visible_msgs[int(selected[0])]
        scroll = msg.line - 3
        if scroll < 0:
            scroll = 0

        self.tabs["Source File"] = open(msg.path, "r").readlines()
        self.box.set("Source File")
        self.refresh_results_window()
        self.results.yview(scroll)
        self.results.select_set(msg.line - 1)
Beispiel #3
0
class LintGui(object):
    """Build and control a window to interact with pylint"""

    def __init__(self, root=None):
        """init"""
        self.root = root or Tk()
        self.root.title('Pylint')
        #reporter
        self.reporter = None
        #message queue for output from reporter
        self.msg_queue = six.moves.queue.Queue()
        self.msgs = []
        self.visible_msgs = []
        self.filenames = []
        self.rating = StringVar()
        self.tabs = {}
        self.report_stream = BasicStream(self)
        #gui objects
        self.lb_messages = None
        self.showhistory = None
        self.results = None
        self.btnRun = None
        self.information_box = None
        self.convention_box = None
        self.refactor_box = None
        self.warning_box = None
        self.error_box = None
        self.fatal_box = None
        self.txtModule = None
        self.status = None
        self.msg_type_dict = None
        self.init_gui()

    def init_gui(self):
        """init helper"""

        window = PanedWindow(self.root, orient="vertical")
        window.pack(side=TOP, fill=BOTH, expand=True)

        top_pane = Frame(window)
        window.add(top_pane)
        mid_pane = Frame(window)
        window.add(mid_pane)
        bottom_pane = Frame(window)
        window.add(bottom_pane)

        #setting up frames
        top_frame = Frame(top_pane)
        mid_frame = Frame(top_pane)
        history_frame = Frame(top_pane)
        radio_frame = Frame(mid_pane)
        rating_frame = Frame(mid_pane)
        res_frame = Frame(mid_pane)
        check_frame = Frame(bottom_pane)
        msg_frame = Frame(bottom_pane)
        btn_frame = Frame(bottom_pane)
        top_frame.pack(side=TOP, fill=X)
        mid_frame.pack(side=TOP, fill=X)
        history_frame.pack(side=TOP, fill=BOTH, expand=True)
        radio_frame.pack(side=TOP, fill=X)
        rating_frame.pack(side=TOP, fill=X)
        res_frame.pack(side=TOP, fill=BOTH, expand=True)
        check_frame.pack(side=TOP, fill=X)
        msg_frame.pack(side=TOP, fill=BOTH, expand=True)
        btn_frame.pack(side=TOP, fill=X)

        # Binding F5 application-wide to run lint
        self.root.bind('<F5>', self.run_lint)

        #Message ListBox
        rightscrollbar = Scrollbar(msg_frame)
        rightscrollbar.pack(side=RIGHT, fill=Y)
        bottomscrollbar = Scrollbar(msg_frame, orient=HORIZONTAL)
        bottomscrollbar.pack(side=BOTTOM, fill=X)
        self.lb_messages = Listbox(
            msg_frame,
            yscrollcommand=rightscrollbar.set,
            xscrollcommand=bottomscrollbar.set,
            bg="white")
        self.lb_messages.bind("<Double-Button-1>", self.show_sourcefile)
        self.lb_messages.pack(expand=True, fill=BOTH)
        rightscrollbar.config(command=self.lb_messages.yview)
        bottomscrollbar.config(command=self.lb_messages.xview)

        #History ListBoxes
        rightscrollbar2 = Scrollbar(history_frame)
        rightscrollbar2.pack(side=RIGHT, fill=Y)
        bottomscrollbar2 = Scrollbar(history_frame, orient=HORIZONTAL)
        bottomscrollbar2.pack(side=BOTTOM, fill=X)
        self.showhistory = Listbox(
            history_frame,
            yscrollcommand=rightscrollbar2.set,
            xscrollcommand=bottomscrollbar2.set,
            bg="white")
        self.showhistory.pack(expand=True, fill=BOTH)
        rightscrollbar2.config(command=self.showhistory.yview)
        bottomscrollbar2.config(command=self.showhistory.xview)
        self.showhistory.bind('<Double-Button-1>', self.select_recent_file)
        self.set_history_window()

        #status bar
        self.status = Label(self.root, text="", bd=1, relief=SUNKEN, anchor=W)
        self.status.pack(side=BOTTOM, fill=X)

        #labelbl_ratingls
        lbl_rating_label = Label(rating_frame, text='Rating:')
        lbl_rating_label.pack(side=LEFT)
        lbl_rating = Label(rating_frame, textvariable=self.rating)
        lbl_rating.pack(side=LEFT)
        Label(mid_frame, text='Recently Used:').pack(side=LEFT)
        Label(top_frame, text='Module or package').pack(side=LEFT)

        #file textbox
        self.txt_module = Entry(top_frame, background='white')
        self.txt_module.bind('<Return>', self.run_lint)
        self.txt_module.pack(side=LEFT, expand=True, fill=X)

        #results box
        rightscrollbar = Scrollbar(res_frame)
        rightscrollbar.pack(side=RIGHT, fill=Y)
        bottomscrollbar = Scrollbar(res_frame, orient=HORIZONTAL)
        bottomscrollbar.pack(side=BOTTOM, fill=X)
        self.results = Listbox(
            res_frame,
            yscrollcommand=rightscrollbar.set,
            xscrollcommand=bottomscrollbar.set,
            bg="white", font="Courier")
        self.results.pack(expand=True, fill=BOTH, side=BOTTOM)
        rightscrollbar.config(command=self.results.yview)
        bottomscrollbar.config(command=self.results.xview)

        #buttons
        Button(top_frame, text='Open', command=self.file_open).pack(side=LEFT)
        Button(top_frame, text='Open Package',
               command=(lambda: self.file_open(package=True))).pack(side=LEFT)

        self.btnRun = Button(top_frame, text='Run', command=self.run_lint)
        self.btnRun.pack(side=LEFT)
        Button(btn_frame, text='Quit', command=self.quit).pack(side=BOTTOM)

        #radio buttons
        self.information_box = IntVar()
        self.convention_box = IntVar()
        self.refactor_box = IntVar()
        self.warning_box = IntVar()
        self.error_box = IntVar()
        self.fatal_box = IntVar()
        i = Checkbutton(check_frame, text="Information", fg=COLORS['(I)'],
                        variable=self.information_box, command=self.refresh_msg_window)
        c = Checkbutton(check_frame, text="Convention", fg=COLORS['(C)'],
                        variable=self.convention_box, command=self.refresh_msg_window)
        r = Checkbutton(check_frame, text="Refactor", fg=COLORS['(R)'],
                        variable=self.refactor_box, command=self.refresh_msg_window)
        w = Checkbutton(check_frame, text="Warning", fg=COLORS['(W)'],
                        variable=self.warning_box, command=self.refresh_msg_window)
        e = Checkbutton(check_frame, text="Error", fg=COLORS['(E)'],
                        variable=self.error_box, command=self.refresh_msg_window)
        f = Checkbutton(check_frame, text="Fatal", fg=COLORS['(F)'],
                        variable=self.fatal_box, command=self.refresh_msg_window)
        i.select()
        c.select()
        r.select()
        w.select()
        e.select()
        f.select()
        i.pack(side=LEFT)
        c.pack(side=LEFT)
        r.pack(side=LEFT)
        w.pack(side=LEFT)
        e.pack(side=LEFT)
        f.pack(side=LEFT)

        #check boxes
        self.box = StringVar()
        # XXX should be generated
        report = Radiobutton(
            radio_frame, text="Report", variable=self.box,
            value="Report", command=self.refresh_results_window)
        raw_met = Radiobutton(
            radio_frame, text="Raw metrics", variable=self.box,
            value="Raw metrics", command=self.refresh_results_window)
        dup = Radiobutton(
            radio_frame, text="Duplication", variable=self.box,
            value="Duplication", command=self.refresh_results_window)
        ext = Radiobutton(
            radio_frame, text="External dependencies",
            variable=self.box, value="External dependencies",
            command=self.refresh_results_window)
        stat = Radiobutton(
            radio_frame, text="Statistics by type",
            variable=self.box, value="Statistics by type",
            command=self.refresh_results_window)
        msg_cat = Radiobutton(
            radio_frame, text="Messages by category",
            variable=self.box, value="Messages by category",
            command=self.refresh_results_window)
        msg = Radiobutton(
            radio_frame, text="Messages", variable=self.box,
            value="Messages", command=self.refresh_results_window)
        source_file = Radiobutton(
            radio_frame, text="Source File", variable=self.box,
            value="Source File", command=self.refresh_results_window)
        report.select()
        report.grid(column=0, row=0, sticky=W)
        raw_met.grid(column=1, row=0, sticky=W)
        dup.grid(column=2, row=0, sticky=W)
        msg.grid(column=3, row=0, sticky=W)
        stat.grid(column=0, row=1, sticky=W)
        msg_cat.grid(column=1, row=1, sticky=W)
        ext.grid(column=2, row=1, sticky=W)
        source_file.grid(column=3, row=1, sticky=W)

        #dictionary for check boxes and associated error term
        self.msg_type_dict = {
            'I': lambda: self.information_box.get() == 1,
            'C': lambda: self.convention_box.get() == 1,
            'R': lambda: self.refactor_box.get() == 1,
            'E': lambda: self.error_box.get() == 1,
            'W': lambda: self.warning_box.get() == 1,
            'F': lambda: self.fatal_box.get() == 1
        }
        self.txt_module.focus_set()


    def select_recent_file(self, event): # pylint: disable=unused-argument
        """adds the selected file in the history listbox to the Module box"""
        if not self.showhistory.size():
            return

        selected = self.showhistory.curselection()
        item = self.showhistory.get(selected)
        #update module
        self.txt_module.delete(0, END)
        self.txt_module.insert(0, item)

    def refresh_msg_window(self):
        """refresh the message window with current output"""
        #clear the window
        self.lb_messages.delete(0, END)
        self.visible_msgs = []
        for msg in self.msgs:
            if self.msg_type_dict.get(msg.C)():
                self.visible_msgs.append(msg)
                msg_str = convert_to_string(msg)
                self.lb_messages.insert(END, msg_str)
                fg_color = COLORS.get(msg_str[:3], 'black')
                self.lb_messages.itemconfigure(END, fg=fg_color)

    def refresh_results_window(self):
        """refresh the results window with current output"""
        #clear the window
        self.results.delete(0, END)
        try:
            for res in self.tabs[self.box.get()]:
                self.results.insert(END, res)
        except KeyError:
            pass

    def process_incoming(self):
        """process the incoming messages from running pylint"""
        while self.msg_queue.qsize():
            try:
                msg = self.msg_queue.get(0)
                if msg == "DONE":
                    self.report_stream.output_contents()
                    return False

                #adding message to list of msgs
                self.msgs.append(msg)

                #displaying msg if message type is selected in check box
                if self.msg_type_dict.get(msg.C)():
                    self.visible_msgs.append(msg)
                    msg_str = convert_to_string(msg)
                    self.lb_messages.insert(END, msg_str)
                    fg_color = COLORS.get(msg_str[:3], 'black')
                    self.lb_messages.itemconfigure(END, fg=fg_color)

            except six.moves.queue.Empty:
                pass
        return True

    def periodic_call(self):
        """determine when to unlock the run button"""
        if self.process_incoming():
            self.root.after(100, self.periodic_call)
        else:
            #enabling button so it can be run again
            self.btnRun.config(state=NORMAL)

    def mainloop(self):
        """launch the mainloop of the application"""
        self.root.mainloop()

    def quit(self, _=None):
        """quit the application"""
        self.root.quit()

    def halt(self): # pylint: disable=no-self-use
        """program halt placeholder"""
        return

    def file_open(self, package=False, _=None):
        """launch a file browser"""
        if not package:
            filename = askopenfilename(parent=self.root,
                                       filetypes=[('pythonfiles', '*.py'),
                                                  ('allfiles', '*')],
                                       title='Select Module')
        else:
            filename = askdirectory(title="Select A Folder", mustexist=1)

        if filename == ():
            return

        self.txt_module.delete(0, END)
        self.txt_module.insert(0, filename)

    def update_filenames(self):
        """update the list of recent filenames"""
        filename = self.txt_module.get()
        if not filename:
            filename = os.getcwd()
        if filename+'\n' in self.filenames:
            index = self.filenames.index(filename+'\n')
            self.filenames.pop(index)

        #ensure only 10 most recent are stored
        if len(self.filenames) == 10:
            self.filenames.pop()
        self.filenames.insert(0, filename+'\n')

    def set_history_window(self):
        """update the history window with info from the history file"""
        #clear the window
        self.showhistory.delete(0, END)
        # keep the last 10 most recent files
        try:
            view_history = open(HOME+HISTORY, 'r')
            for hist in view_history.readlines():
                if not hist in self.filenames:
                    self.filenames.append(hist)
                self.showhistory.insert(END, hist.split('\n')[0])
            view_history.close()
        except IOError:
            # do nothing since history file will be created later
            return

    def run_lint(self, _=None):
        """launches pylint"""
        self.update_filenames()
        self.root.configure(cursor='watch')
        self.reporter = GUIReporter(self, output=self.report_stream)
        module = self.txt_module.get()
        if not module:
            module = os.getcwd()

        #cleaning up msgs and windows
        self.msgs = []
        self.visible_msgs = []
        self.lb_messages.delete(0, END)
        self.tabs = {}
        self.results.delete(0, END)
        self.btnRun.config(state=DISABLED)

        #setting up a worker thread to run pylint
        worker = Thread(target=lint_thread, args=(module, self.reporter, self,))
        self.periodic_call()
        worker.start()

        # Overwrite the .pylint-gui-history file with all the new recently added files
        # in order from filenames but only save last 10 files
        write_history = open(HOME+HISTORY, 'w')
        write_history.writelines(self.filenames)
        write_history.close()
        self.set_history_window()

        self.root.configure(cursor='')

    def show_sourcefile(self, event=None):  # pylint: disable=unused-argument
        selected = self.lb_messages.curselection()
        if not selected:
            return

        msg = self.visible_msgs[int(selected[0])]
        scroll = msg.line - 3
        if scroll < 0:
            scroll = 0

        self.tabs["Source File"] = open(msg.path, "r").readlines()
        self.box.set("Source File")
        self.refresh_results_window()
        self.results.yview(scroll)
        self.results.select_set(msg.line - 1)
class DrtGlueDemo(object):
    def __init__(self, examples):
        # Set up the main window.
        self._top = Tk()
        self._top.title('DRT Glue Demo')

        # Set up key bindings.
        self._init_bindings()

        # Initialize the fonts.self._error = None
        self._init_fonts(self._top)

        self._examples = examples
        self._readingCache = [None for example in examples]

        # The user can hide the grammar.
        self._show_grammar = IntVar(self._top)
        self._show_grammar.set(1)

        # Set the data to None
        self._curExample = -1
        self._readings = []
        self._drs = None
        self._drsWidget = None
        self._error = None

        self._init_glue()

        # Create the basic frames.
        self._init_menubar(self._top)
        self._init_buttons(self._top)
        self._init_exampleListbox(self._top)
        self._init_readingListbox(self._top)
        self._init_canvas(self._top)

        # Resize callback
        self._canvas.bind('<Configure>', self._configure)

    #########################################
    ##  Initialization Helpers
    #########################################

    def _init_glue(self):
        tagger = RegexpTagger(
            [('^(David|Mary|John)$', 'NNP'),
             ('^(walks|sees|eats|chases|believes|gives|sleeps|chases|persuades|tries|seems|leaves)$', 'VB'),
             ('^(go|order|vanish|find|approach)$', 'VB'),
             ('^(a)$', 'ex_quant'),
             ('^(every)$', 'univ_quant'),
             ('^(sandwich|man|dog|pizza|unicorn|cat|senator)$', 'NN'),
             ('^(big|gray|former)$', 'JJ'),
             ('^(him|himself)$', 'PRP')
        ])

        depparser = MaltParser(tagger=tagger)
        self._glue = DrtGlue(depparser=depparser, remove_duplicates=False)

    def _init_fonts(self, root):
        # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html>
        self._sysfont = Font(font=Button()["font"])
        root.option_add("*Font", self._sysfont)

        # TWhat's our font size (default=same as sysfont)
        self._size = IntVar(root)
        self._size.set(self._sysfont.cget('size'))

        self._boldfont = Font(family='helvetica', weight='bold',
                                    size=self._size.get())
        self._font = Font(family='helvetica',
                                    size=self._size.get())
        if self._size.get() < 0: big = self._size.get()-2
        else: big = self._size.get()+2
        self._bigfont = Font(family='helvetica', weight='bold',
                                    size=big)

    def _init_exampleListbox(self, parent):
        self._exampleFrame = listframe = Frame(parent)
        self._exampleFrame.pack(fill='both', side='left', padx=2)
        self._exampleList_label = Label(self._exampleFrame, font=self._boldfont,
                                     text='Examples')
        self._exampleList_label.pack()
        self._exampleList = Listbox(self._exampleFrame, selectmode='single',
                                 relief='groove', background='white',
                                 foreground='#909090', font=self._font,
                                 selectforeground='#004040',
                                 selectbackground='#c0f0c0')

        self._exampleList.pack(side='right', fill='both', expand=1)

        for example in self._examples:
            self._exampleList.insert('end', ('  %s' % example))
        self._exampleList.config(height=min(len(self._examples), 25), width=40)

        # Add a scrollbar if there are more than 25 examples.
        if len(self._examples) > 25:
            listscroll = Scrollbar(self._exampleFrame,
                                   orient='vertical')
            self._exampleList.config(yscrollcommand = listscroll.set)
            listscroll.config(command=self._exampleList.yview)
            listscroll.pack(side='left', fill='y')

        # If they select a example, apply it.
        self._exampleList.bind('<<ListboxSelect>>', self._exampleList_select)

    def _init_readingListbox(self, parent):
        self._readingFrame = listframe = Frame(parent)
        self._readingFrame.pack(fill='both', side='left', padx=2)
        self._readingList_label = Label(self._readingFrame, font=self._boldfont,
                                     text='Readings')
        self._readingList_label.pack()
        self._readingList = Listbox(self._readingFrame, selectmode='single',
                                 relief='groove', background='white',
                                 foreground='#909090', font=self._font,
                                 selectforeground='#004040',
                                 selectbackground='#c0f0c0')

        self._readingList.pack(side='right', fill='both', expand=1)

        # Add a scrollbar if there are more than 25 examples.
        listscroll = Scrollbar(self._readingFrame,
                               orient='vertical')
        self._readingList.config(yscrollcommand = listscroll.set)
        listscroll.config(command=self._readingList.yview)
        listscroll.pack(side='right', fill='y')

        self._populate_readingListbox()

    def _populate_readingListbox(self):
        # Populate the listbox with integers
        self._readingList.delete(0, 'end')
        for i in range(len(self._readings)):
            self._readingList.insert('end', ('  %s' % (i+1)))
        self._readingList.config(height=min(len(self._readings), 25), width=5)

        # If they select a example, apply it.
        self._readingList.bind('<<ListboxSelect>>', self._readingList_select)

    def _init_bindings(self):
        # Key bindings are a good thing.
        self._top.bind('<Control-q>', self.destroy)
        self._top.bind('<Control-x>', self.destroy)
        self._top.bind('<Escape>', self.destroy)
        self._top.bind('n', self.next)
        self._top.bind('<space>', self.next)
        self._top.bind('p', self.prev)
        self._top.bind('<BackSpace>', self.prev)

    def _init_buttons(self, parent):
        # Set up the frames.
        self._buttonframe = buttonframe = Frame(parent)
        buttonframe.pack(fill='none', side='bottom', padx=3, pady=2)
        Button(buttonframe, text='Prev',
               background='#90c0d0', foreground='black',
               command=self.prev,).pack(side='left')
        Button(buttonframe, text='Next',
               background='#90c0d0', foreground='black',
               command=self.next,).pack(side='left')

    def _configure(self, event):
        self._autostep = 0
        (x1, y1, x2, y2) = self._cframe.scrollregion()
        y2 = event.height - 6
        self._canvas['scrollregion'] = '%d %d %d %d' % (x1,y1,x2,y2)
        self._redraw()

    def _init_canvas(self, parent):
        self._cframe = CanvasFrame(parent, background='white',
                                   #width=525, height=250,
                                   closeenough=10,
                                   border=2, relief='sunken')
        self._cframe.pack(expand=1, fill='both', side='top', pady=2)
        canvas = self._canvas = self._cframe.canvas()

        # Initially, there's no tree or text
        self._tree = None
        self._textwidgets = []
        self._textline = None

    def _init_menubar(self, parent):
        menubar = Menu(parent)

        filemenu = Menu(menubar, tearoff=0)
        filemenu.add_command(label='Exit', underline=1,
                             command=self.destroy, accelerator='q')
        menubar.add_cascade(label='File', underline=0, menu=filemenu)

        actionmenu = Menu(menubar, tearoff=0)
        actionmenu.add_command(label='Next', underline=0,
                               command=self.next, accelerator='n, Space')
        actionmenu.add_command(label='Previous', underline=0,
                               command=self.prev, accelerator='p, Backspace')
        menubar.add_cascade(label='Action', underline=0, menu=actionmenu)

        optionmenu = Menu(menubar, tearoff=0)
        optionmenu.add_checkbutton(label='Remove Duplicates', underline=0,
                                   variable=self._glue.remove_duplicates,
                                   command=self._toggle_remove_duplicates,
                                   accelerator='r')
        menubar.add_cascade(label='Options', underline=0, menu=optionmenu)

        viewmenu = Menu(menubar, tearoff=0)
        viewmenu.add_radiobutton(label='Tiny', variable=self._size,
                                 underline=0, value=10, command=self.resize)
        viewmenu.add_radiobutton(label='Small', variable=self._size,
                                 underline=0, value=12, command=self.resize)
        viewmenu.add_radiobutton(label='Medium', variable=self._size,
                                 underline=0, value=14, command=self.resize)
        viewmenu.add_radiobutton(label='Large', variable=self._size,
                                 underline=0, value=18, command=self.resize)
        viewmenu.add_radiobutton(label='Huge', variable=self._size,
                                 underline=0, value=24, command=self.resize)
        menubar.add_cascade(label='View', underline=0, menu=viewmenu)

        helpmenu = Menu(menubar, tearoff=0)
        helpmenu.add_command(label='About', underline=0,
                             command=self.about)
        menubar.add_cascade(label='Help', underline=0, menu=helpmenu)

        parent.config(menu=menubar)

    #########################################
    ##  Main draw procedure
    #########################################

    def _redraw(self):
        canvas = self._canvas

        # Delete the old DRS, widgets, etc.
        if self._drsWidget is not None:
            self._drsWidget.clear()

        if self._drs:
            self._drsWidget = DrsWidget( self._canvas, self._drs )
            self._drsWidget.draw()

        if self._error:
            self._drsWidget = DrsWidget( self._canvas, self._error )
            self._drsWidget.draw()

    #########################################
    ##  Button Callbacks
    #########################################

    def destroy(self, *e):
        self._autostep = 0
        if self._top is None: return
        self._top.destroy()
        self._top = None

    def prev(self, *e):
        selection = self._readingList.curselection()
        readingListSize = self._readingList.size()

        # there are readings
        if readingListSize > 0:
            # if one reading is currently selected
            if len(selection) == 1:
                index = int(selection[0])

                # if it's on (or before) the first item
                if index <= 0:
                    self._select_previous_example()
                else:
                    self._readingList_store_selection(index-1)

            else:
                #select its first reading
                self._readingList_store_selection(readingListSize-1)

        else:
            self._select_previous_example()


    def _select_previous_example(self):
        #if the current example is not the first example
        if self._curExample > 0:
            self._exampleList_store_selection(self._curExample-1)
        else:
            #go to the last example
            self._exampleList_store_selection(len(self._examples)-1)

    def next(self, *e):
        selection = self._readingList.curselection()
        readingListSize = self._readingList.size()

        # if there are readings
        if readingListSize > 0:
            # if one reading is currently selected
            if len(selection) == 1:
                index = int(selection[0])

                # if it's on (or past) the last item
                if index >= (readingListSize-1):
                    self._select_next_example()
                else:
                    self._readingList_store_selection(index+1)

            else:
                #select its first reading
                self._readingList_store_selection(0)

        else:
            self._select_next_example()

    def _select_next_example(self):
        #if the current example is not the last example
        if self._curExample < len(self._examples)-1:
            self._exampleList_store_selection(self._curExample+1)
        else:
            #go to the first example
            self._exampleList_store_selection(0)


    def about(self, *e):
        ABOUT = ("NLTK Discourse Representation Theory (DRT) Glue Semantics Demo\n"+
                 "Written by Daniel H. Garrette")
        TITLE = 'About: NLTK DRT Glue Demo'
        try:
            from six.moves.tkinter_messagebox import Message
            Message(message=ABOUT, title=TITLE).show()
        except:
            ShowText(self._top, TITLE, ABOUT)

    def postscript(self, *e):
        self._autostep = 0
        self._cframe.print_to_file()

    def mainloop(self, *args, **kwargs):
        """
        Enter the Tkinter mainloop.  This function must be called if
        this demo is created from a non-interactive program (e.g.
        from a secript); otherwise, the demo will close as soon as
        the script completes.
        """
        if in_idle(): return
        self._top.mainloop(*args, **kwargs)

    def resize(self, size=None):
        if size is not None: self._size.set(size)
        size = self._size.get()
        self._font.configure(size=-(abs(size)))
        self._boldfont.configure(size=-(abs(size)))
        self._sysfont.configure(size=-(abs(size)))
        self._bigfont.configure(size=-(abs(size+2)))
        self._redraw()

    def _toggle_remove_duplicates(self):
        self._glue.remove_duplicates = not self._glue.remove_duplicates

        self._exampleList.selection_clear(0, 'end')
        self._readings = []
        self._populate_readingListbox()
        self._readingCache = [None for ex in self._examples]
        self._curExample = -1
        self._error = None

        self._drs = None
        self._redraw()


    def _exampleList_select(self, event):
        selection = self._exampleList.curselection()
        if len(selection) != 1: return
        self._exampleList_store_selection(int(selection[0]))

    def _exampleList_store_selection(self, index):
        self._curExample = index
        example = self._examples[index]

        self._exampleList.selection_clear(0, 'end')
        if example:
            cache = self._readingCache[index]
            if cache:
                if isinstance(cache, list):
                    self._readings = cache
                    self._error = None
                else:
                    self._readings = []
                    self._error = cache
            else:
                try:
                    self._readings = self._glue.parse_to_meaning(example)
                    self._error = None
                    self._readingCache[index] = self._readings
                except Exception as e:
                    self._readings = []
                    self._error = DrtVariableExpression(Variable('Error: ' + str(e)))
                    self._readingCache[index] = self._error

                    #add a star to the end of the example
                    self._exampleList.delete(index)
                    self._exampleList.insert(index, ('  %s *' % example))
                    self._exampleList.config(height=min(len(self._examples), 25), width=40)

            self._populate_readingListbox()

            self._exampleList.selection_set(index)

            self._drs = None
            self._redraw()


    def _readingList_select(self, event):
        selection = self._readingList.curselection()
        if len(selection) != 1: return
        self._readingList_store_selection(int(selection[0]))

    def _readingList_store_selection(self, index):
        reading = self._readings[index]

        self._readingList.selection_clear(0, 'end')
        if reading:
            self._readingList.selection_set(index)

            self._drs = reading.simplify().normalize().resolve_anaphora()

            self._redraw()