Example #1
0
class NamedWindow:
    """
  This creates a window for the Tkui which you can then write to 
  programmatically.  This allows modules to spin off new named windows
  and write to them.
  """

    def __init__(self, windowname, master, partk):
        """
    Initializes the window

    @param windowname: the name of the new window
    @type  windowname: string

    @param master: the main tk window
    @type  master: toplevel
    """
        self._parent = master
        self._tk = Toplevel(partk)
        self._windowname = windowname

        # map of session -> (bold, foreground, background)
        self._currcolors = {}

        # ses -> string
        self._unfinishedcolor = {}

        self._do_i_echo = 1

        self._tk.geometry("500x300")
        self._tk.title("Lyntin -- " + self._windowname)

        self._tk.protocol("WM_DELETE_WINDOW", self.close)

        if os.name == "posix":
            fontname = "Courier"
        else:
            fontname = "Fixedsys"
        fnt = tkFont.Font(family=fontname, size=12)

        self._txt = ScrolledText(self._tk, fg="white", bg="black", font=fnt, height=20)
        self._txt.pack(side=TOP, fill=BOTH, expand=1)

        # handles improper keypresses
        self._txt.bind("<KeyPress>", self._ignoreThis)

        # initialize color tags
        self._initColorTags()

    def convertColor(self, name):
        """
    Tk has this really weird color palatte.  So I switched to using
    color names in most cases and rgb values in cases where I couldn't
    find a good color name.

    This method allows me to specify either an rgb or a color name
    and it converts the color names to rgb.

    @param name: either an rgb value or a name
    @type  name: string

    @returns: the rgb color value
    @rtype: string
    """
        if name[0] == "#":
            return name

        rgb = self._tk._getints(self._tk.tk.call("winfo", "rgb", self._txt, name))
        rgb = "#%02x%02x%02x" % (rgb[0] / 256, rgb[1] / 256, rgb[2] / 256)
        print name, "converted to: ", rgb

        return rgb

    def _initColorTags(self):
        """ Sets up Tk tags for the text widget (fg/bg)."""
        for ck in fg_color_codes.keys():
            color = self.convertColor(fg_color_codes[ck])
            self._txt.tag_config(ck, foreground=color)

        for ck in bg_color_codes.keys():
            self._txt.tag_config(ck, background=bg_color_codes[ck])

        self._txt.tag_config("u", underline=1)

    def _ignoreThis(self, tkevent):
        """
    This catches keypresses to this window.
    """
        return "break"

    def close(self):
        """
    Closes and destroys references to this window.
    """
        self._parent.removeWindow(self._windowname)
        self._tk.destroy()

    def _yadjust(self):
        """Handles y scrolling after text insertion."""
        self._txt.yview("moveto", "1")
        # if os.name != 'posix':
        self._txt.yview("scroll", "20", "units")

    def _clipText(self):
        """
    Scrolls the text buffer up so that the new text written at
    the bottom of the text buffer can be seen.
    """
        temp = self._txt.index("end")
        ind = temp.find(".")
        temp = temp[:ind]
        if temp.isdigit() and int(temp) > 800:
            self._txt.delete("1.0", "100.end")

    def write(self, msg):
        """
    This writes text to the text buffer for viewing by the user.

    This is overridden from the 'base.BaseUI'.
    """
        if type(msg) == types.TupleType:
            msg = msg[0]

        if type(msg) == types.StringType:
            msg = message.Message(msg, message.LTDATA)

        line = msg.data
        ses = msg.session

        if line == "":
            return

        color, leftover = buffer_write(msg, self._txt, self._currcolors, self._unfinishedcolor)

        if msg.type == message.MUDDATA:
            self._unfinishedcolor[ses] = leftover
            self._currcolors[ses] = color

        self._clipText()
        self._yadjust()
Example #2
0
class MyThing (Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pack()
        self.createWidgets()

    def createWidgets(self):
        self.textBox = ScrolledText(self, height=30, width=85)
        self.textBox.pack()
        self.addText()

    def leftMouseClick(self,event):
        print "got a click"
        mouseIndex =  "@%d,%d" % (event.x, event.y)
        current = self.textBox.index(mouseIndex)
        row = current.split(".")[0] + ".0"
        rowFl = float(row)+1.0
        row = str(rowFl)
        target = self.rowIndex[row]
        target = float(target)+12.0
        target = str(target)
        print "moving to target",target
        self.textBox.see(target)

    def rightMouseClick(self,event):
        self.textBox.see("0.0")



    def addText(self):
        f=open("help.txt",'r')
        lines = f.readlines()
        f.close()
        flag = 1
        i=0
        sectionOrder = {}
        sectionHeads = {}
        outlines = {} 
        targetId = 0
        defaultTarget = ""
        tocEntries = []
        lineId=0
        for line in lines:
            if line[0:1] =="#":
                tocEntries.append(line)
                if flag:
                    top = lineId
                    flag = 0
            lineId+=1



        self.tocEntries = tocEntries
        # header text
        header = lines[0:top]

        for line in header:
            hid=self.textBox.insert(END,line,"header")
            self.textBox.tag_config("header",foreground=FGCOLOR)
            self.textBox.tag_config("header",background=BGCOLOR)

        

        self.textBox.insert(END,"Table of Contents\n","toc")
        self.textBox.tag_config("toc",foreground="red")
        self.textBox.tag_config("toc",background=BGCOLOR)
        self.textBox.insert(END,
            "(Left-click entry to navigate, right-click to return)\n\n","directions")
        self.textBox.tag_config("directions",background=BGCOLOR)
        self.textBox.tag_config("directions",foreground="purple")



        sectionDict = {}
        rowIndex = {}
        for tocEntry in tocEntries:
            if tocEntry[0:2] == "##":
                line = "\t"+tocEntry[2:]
            else:
                line = tocEntry[1:]
            rowPosition = self.textBox.index(END).split(".")[0] + ".0"
            rowIndex[rowPosition] = "0.0"
            sectionDict[tocEntry] = rowPosition
            self.textBox.insert(END,line,"tocEntry")

        self.textBox.tag_bind("tocEntry",'<ButtonRelease-1>',
                               self.leftMouseClick)
        self.textBox.tag_config("tocEntry",background=BGCOLOR)
        self.textBox.tag_config("tocEntry",foreground=hfg)
        for i in range(50):
            self.textBox.insert(END,"\n","regular")

        lines = lines[top:]
        for line in lines:
            if sectionDict.has_key(line):
                print "section id",line
                position = self.textBox.index(END)
                tocPosition = sectionDict[line]
                rowIndex[tocPosition] = position
                line = line.replace("#","")

            self.textBox.insert(END,line,"regular")

        self.rowIndex = rowIndex

        self.sectionDict = sectionDict

        self.textBox.see("0.0")

        self.textBox.bind_all('<ButtonRelease-3>',
                              self.rightMouseClick)
        self.textBox.tag_config("regular",background=BGCOLOR)
        self.textBox.tag_config("regular",foreground="black")
Example #3
0
class Tkui(base.BaseUI):
    """
  This is a ui class which handles the complete Tk user interface.
  """

    def __init__(self):
        """ Initializes."""
        base.BaseUI.__init__(self)

        # internal ui queue
        self._event_queue = Queue.Queue()

        # map of session -> (bold, foreground, background)
        self._currcolors = {}

        # ses -> string
        self._unfinishedcolor = {}

        self._viewhistory = 0
        self._do_i_echo = 1

        # holds a map of window names -> window references
        self._windows = {}

        # instantiate all the widgets
        self._tk = Tk()
        self._tk.geometry("800x600")

        self.settitle()

        if os.name == "posix":
            fnt = tkFont.Font(family="Courier", size=12)
        else:
            fnt = tkFont.Font(family="Fixedsys", size=12)

        self._entry = CommandEntry(
            self._tk, self, fg="white", bg="black", insertbackground="yellow", font=fnt, insertwidth="2"
        )
        self._entry.pack(side="bottom", fill="both")

        self._topframe = Frame(self._tk)
        self._topframe.pack(side="top", fill="both", expand=1)

        self._txt = ScrolledText(self._topframe, fg="white", bg="black", font=fnt, height=20)
        self._txt.pack(side="bottom", fill="both", expand=1)

        self._txt.bind("<KeyPress>", self._ignoreThis)
        self._txtbuffer = ScrolledText(self._topframe, fg="white", bg="black", font=fnt, height=20)
        self._txtbuffer.bind("<KeyPress-Escape>", self.escape)
        self._txtbuffer.bind("<KeyPress>", self._ignoreThis)

        self._entry.focus_set()
        self._initColorTags()
        self.dequeue()

        exported.hook_register("config_change_hook", self.configChangeHandler)
        exported.hook_register("to_user_hook", self.write)

        # FIXME - fix this explanation.  this is just terrible.
        tc = config.BoolConfig(
            "saveinputhighlight",
            0,
            1,
            "Allows you to change the behavior of the command entry.  When "
            "saveinputhighlight is off, we discard whatever is on the entry "
            "line.  When it is on, we will retain the contents allowing you "
            "to press the enter key to do whatever you typed again.",
        )
        exported.add_config("saveinputhighlight", tc)

        self._quit = 0

    def runui(self):
        global HELP_TEXT
        exported.add_help("tkui", HELP_TEXT)
        exported.write_message('For tk help type "#help tkui".')
        exported.add_command("colorcheck", colorcheck_cmd)

        # run the tk mainloop here
        self._tk.mainloop()

    def wantMainThread(self):
        # The tkui needs the main thread of execution so we return
        # a 1 here.
        return 1

    def quit(self):
        if not self._quit:
            self._quit = 1
            self._topframe.quit()

    def dequeue(self):
        qsize = self._event_queue.qsize()
        if qsize > 10:
            qsize = 10

        for i in range(qsize):
            ev = self._event_queue.get_nowait()
            ev.execute(self)

        self._tk.after(25, self.dequeue)

    def settitle(self, title=""):
        """
    Sets the title bar to the Lyntin title plus the given string.

    @param title: the title to set
    @type  title: string
    """
        if title:
            title = constants.LYNTINTITLE + title
        else:
            title = constants.LYNTINTITLE
        self._event_queue.put(_TitleEvent(self._tk, title))

    def removeWindow(self, windowname):
        """
    This removes a NamedWindow from our list of NamedWindows.

    @param windowname: the name of the window to write to
    @type  windowname: string
    """
        if self._windows.has_key(windowname):
            del self._windows[windowname]

    def writeWindow(self, windowname, message):
        """
    This writes to the window named "windowname".  If the window
    does not exist, we spin one off.  It handles ansi text and
    messages just like writing to the main window.

    @param windowname: the name of the window to write to
    @type  windowname: string

    @param message: the message to write to the window
    @type  message: string or Message instance
    """
        self._event_queue.put(_WriteWindowEvent(windowname, message))

    def writeWindow_internal(self, windowname, message):
        if not self._windows.has_key(windowname):
            self._windows[windowname] = NamedWindow(windowname, self, self._tk)
        self._windows[windowname].write(message)

    def _ignoreThis(self, tkevent):
        """ This catches keypresses from the history buffer."""
        # kludge so that ctrl-c doesn't get caught allowing windows
        # users to copy the buffer....
        if tkevent.keycode == 17 or tkevent.keycode == 67:
            return

        self._entry.focus()
        if tkevent.char:
            # we do this little song and dance so as to pass events
            # we don't want to deal with to the entry widget essentially
            # by creating a new event and tossing it in the event list.
            # it only sort of works--but it's the best code we've got
            # so far.
            args = ("event", "generate", self._entry, "<KeyPress>")
            args = args + ("-rootx", tkevent.x_root)
            args = args + ("-rooty", tkevent.y_root)
            args = args + ("-keycode", tkevent.keycode)
            args = args + ("-keysym", tkevent.keysym)

            self._tk.tk.call(args)

        return "break"

    def pageUp(self):
        """ Handles prior (Page-Up) events."""
        if self._viewhistory == 0:
            self._txtbuffer.pack(side="top", fill="both", expand=1)

            self._viewhistory = 1
            self._txtbuffer.delete("1.0", "end")
            lotofstuff = self._txt.get("1.0", "end")
            self._txtbuffer.insert("end", lotofstuff)
            for t in self._txt.tag_names():
                taux = None
                tst = 0
                for e in self._txt.tag_ranges(t):
                    if tst == 0:
                        taux = e
                        tst = 1
                    else:
                        tst = 0
                        self._txtbuffer.tag_add(t, str(taux), str(e))

            self._txtbuffer.yview("moveto", "1")
            if os.name != "posix":
                self._txtbuffer.yview("scroll", "20", "units")
            self._tk.update_idletasks()
            self._txt.yview("moveto", "1.0")
            if os.name != "posix":
                self._txt.yview("scroll", "220", "units")

        else:
            # yscroll up stuff
            self._txtbuffer.yview("scroll", "-15", "units")

    def pageDown(self):
        """ Handles next (Page-Down) events."""
        if self._viewhistory == 1:
            # yscroll down stuff
            self._txtbuffer.yview("scroll", "15", "units")

    def escape(self, tkevent):
        """ Handles escape (Escape) events."""
        if self._viewhistory == 1:
            self._txtbuffer.forget()
            self._viewhistory = 0
        else:
            self._entry.clearInput()

    def configChangeHandler(self, args):
        """ This handles config changes including mudecho. """
        name = args["name"]
        newvalue = args["newvalue"]

        if name == "mudecho":
            if newvalue == 1:
                # echo on
                self._do_i_echo = 1
                self._entry.configure(show="")
            else:
                # echo off
                self._do_i_echo = 0
                self._entry.configure(show="*")

    def _yadjust(self):
        """Handles y scrolling after text insertion."""
        self._txt.yview("moveto", "1")
        # if os.name != 'posix':
        self._txt.yview("scroll", "20", "units")

    def _clipText(self):
        """
    Scrolls the text buffer up so that the new text written at
    the bottom of the text buffer can be seen.
    """
        temp = self._txt.index("end")
        ind = temp.find(".")
        temp = temp[:ind]
        if temp.isdigit() and int(temp) > 800:
            self._txt.delete("1.0", "100.end")

    def write(self, args):
        """
    This writes text to the text buffer for viewing by the user.

    This is overridden from the 'base.BaseUI'.
    """
        self._event_queue.put(_OutputEvent(args))

    def write_internal(self, args):
        mess = args["message"]
        if type(mess) == types.StringType:
            mess = message.Message(mess, message.LTDATA)

        line = mess.data
        ses = mess.session

        if line == "" or self.showTextForSession(ses) == 0:
            return

        color, leftover = buffer_write(mess, self._txt, self._currcolors, self._unfinishedcolor)

        if mess.type == message.MUDDATA:
            self._unfinishedcolor[ses] = leftover
            self._currcolors[ses] = color

        self._clipText()
        self._yadjust()

    def convertColor(self, name):
        """
    Tk has this really weird color palatte.  So I switched to using
    color names in most cases and rgb values in cases where I couldn't
    find a good color name.

    This method allows me to specify either an rgb or a color name
    and it converts the color names to rgb.

    @param name: either an rgb value or a name
    @type  name: string

    @returns: the rgb color value
    @rtype: string
    """
        if name.startswith("#"):
            return name

        rgb = self._tk._getints(self._tk.tk.call("winfo", "rgb", self._txt, name))
        rgb = "#%02x%02x%02x" % (rgb[0] / 256, rgb[1] / 256, rgb[2] / 256)
        print name, "converted to: ", rgb

        return rgb

    def _initColorTags(self):
        """ Sets up Tk tags for the text widget (fg/bg/u)."""
        for ck in fg_color_codes.keys():
            color = self.convertColor(fg_color_codes[ck])
            self._txt.tag_config(ck, foreground=color)
            self._txtbuffer.tag_config(ck, foreground=color)

        for ck in bg_color_codes.keys():
            self._txt.tag_config(ck, background=bg_color_codes[ck])
            self._txtbuffer.tag_config(ck, background=bg_color_codes[ck])

        self._txt.tag_config("u", underline=1)
        self._txtbuffer.tag_config("u", underline=1)

    def colorCheck(self):
        """
    Goes through and displays all the combinations of fg and bg
    with the text string involved.  Purely for debugging
    purposes.
    """
        fgkeys = ["30", "31", "32", "33", "34", "35", "36", "37"]
        bgkeys = ["40", "41", "42", "43", "44", "45", "46", "47"]

        self._txt.insert("end", "color check:\n")
        for bg in bgkeys:
            for fg in fgkeys:
                self._txt.insert("end", str(fg), (fg, bg))
                self._txt.insert("end", str("b" + fg), ("b" + fg, bg))
            self._txt.insert("end", "\n")

            for fg in fgkeys:
                self._txt.insert("end", str(fg), (fg, "b" + bg))
                self._txt.insert("end", str("b" + fg), ("b" + fg, "b" + bg))
            self._txt.insert("end", "\n")

        self._txt.insert("end", "\n")
        self._txt.insert("end", "\n")
Example #4
0
class Tkui(base.BaseUI):
    """
  This is a ui class which handles the complete Tk user interface.
  """
    def __init__(self):
        """ Initializes."""
        base.BaseUI.__init__(self)

        # internal ui queue
        self._event_queue = Queue.Queue()

        # map of session -> (bold, foreground, background)
        self._currcolors = {}

        # ses -> string
        self._unfinishedcolor = {}

        self._viewhistory = 0
        self._do_i_echo = 1

        # holds a map of window names -> window references
        self._windows = {}

        # instantiate all the widgets
        self._tk = Tk()
        self._tk.geometry("800x600")

        self.settitle()

        if os.name == 'posix':
            fnt = tkFont.Font(family="Courier", size=12)
        else:
            fnt = tkFont.Font(family="Fixedsys", size=12)

        self._entry = CommandEntry(self._tk,
                                   self,
                                   fg='white',
                                   bg='black',
                                   insertbackground='yellow',
                                   font=fnt,
                                   insertwidth='2')
        self._entry.pack(side='bottom', fill='both')

        self._topframe = Frame(self._tk)
        self._topframe.pack(side='top', fill='both', expand=1)

        self._txt = ScrolledText(self._topframe,
                                 fg='white',
                                 bg='black',
                                 font=fnt,
                                 height=20)
        self._txt.pack(side='bottom', fill='both', expand=1)

        self._txt.bind("<KeyPress>", self._ignoreThis)
        self._txtbuffer = ScrolledText(self._topframe,
                                       fg='white',
                                       bg='black',
                                       font=fnt,
                                       height=20)
        self._txtbuffer.bind("<KeyPress-Escape>", self.escape)
        self._txtbuffer.bind("<KeyPress>", self._ignoreThis)

        self._entry.focus_set()
        self._initColorTags()
        self.dequeue()

        exported.hook_register("config_change_hook", self.configChangeHandler)
        exported.hook_register("to_user_hook", self.write)

        # FIXME - fix this explanation.  this is just terrible.
        tc = config.BoolConfig(
            "saveinputhighlight", 0, 1,
            "Allows you to change the behavior of the command entry.  When "
            "saveinputhighlight is off, we discard whatever is on the entry "
            "line.  When it is on, we will retain the contents allowing you "
            "to press the enter key to do whatever you typed again.")
        exported.add_config("saveinputhighlight", tc)

        self._quit = 0

    def runui(self):
        global HELP_TEXT
        exported.add_help("tkui", HELP_TEXT)
        exported.write_message("For tk help type \"#help tkui\".")
        exported.add_command("colorcheck", colorcheck_cmd)

        # run the tk mainloop here
        self._tk.mainloop()

    def wantMainThread(self):
        # The tkui needs the main thread of execution so we return
        # a 1 here.
        return 1

    def quit(self):
        if not self._quit:
            self._quit = 1
            self._topframe.quit()

    def dequeue(self):
        qsize = self._event_queue.qsize()
        if qsize > 10:
            qsize = 10

        for i in range(qsize):
            ev = self._event_queue.get_nowait()
            ev.execute(self)

        self._tk.after(25, self.dequeue)

    def settitle(self, title=""):
        """
    Sets the title bar to the Lyntin title plus the given string.

    @param title: the title to set
    @type  title: string
    """
        if title:
            title = constants.LYNTINTITLE + title
        else:
            title = constants.LYNTINTITLE
        self._event_queue.put(_TitleEvent(self._tk, title))

    def removeWindow(self, windowname):
        """
    This removes a NamedWindow from our list of NamedWindows.

    @param windowname: the name of the window to write to
    @type  windowname: string
    """
        if self._windows.has_key(windowname):
            del self._windows[windowname]

    def writeWindow(self, windowname, message):
        """
    This writes to the window named "windowname".  If the window
    does not exist, we spin one off.  It handles ansi text and
    messages just like writing to the main window.

    @param windowname: the name of the window to write to
    @type  windowname: string

    @param message: the message to write to the window
    @type  message: string or Message instance
    """
        self._event_queue.put(_WriteWindowEvent(windowname, message))

    def writeWindow_internal(self, windowname, message):
        if not self._windows.has_key(windowname):
            self._windows[windowname] = NamedWindow(windowname, self, self._tk)
        self._windows[windowname].write(message)

    def _ignoreThis(self, tkevent):
        """ This catches keypresses from the history buffer."""
        # kludge so that ctrl-c doesn't get caught allowing windows
        # users to copy the buffer....
        if tkevent.keycode == 17 or tkevent.keycode == 67:
            return

        self._entry.focus()
        if tkevent.char:
            # we do this little song and dance so as to pass events
            # we don't want to deal with to the entry widget essentially
            # by creating a new event and tossing it in the event list.
            # it only sort of works--but it's the best code we've got
            # so far.
            args = ('event', 'generate', self._entry, "<KeyPress>")
            args = args + ('-rootx', tkevent.x_root)
            args = args + ('-rooty', tkevent.y_root)
            args = args + ('-keycode', tkevent.keycode)
            args = args + ('-keysym', tkevent.keysym)

            self._tk.tk.call(args)

        return "break"

    def pageUp(self):
        """ Handles prior (Page-Up) events."""
        if self._viewhistory == 0:
            self._txtbuffer.pack(side='top', fill='both', expand=1)

            self._viewhistory = 1
            self._txtbuffer.delete("1.0", "end")
            lotofstuff = self._txt.get('1.0', 'end')
            self._txtbuffer.insert('end', lotofstuff)
            for t in self._txt.tag_names():
                taux = None
                tst = 0
                for e in self._txt.tag_ranges(t):
                    if tst == 0:
                        taux = e
                        tst = 1
                    else:
                        tst = 0
                        self._txtbuffer.tag_add(t, str(taux), str(e))

            self._txtbuffer.yview('moveto', '1')
            if os.name != 'posix':
                self._txtbuffer.yview('scroll', '20', 'units')
            self._tk.update_idletasks()
            self._txt.yview('moveto', '1.0')
            if os.name != 'posix':
                self._txt.yview('scroll', '220', 'units')

        else:
            # yscroll up stuff
            self._txtbuffer.yview('scroll', '-15', 'units')

    def pageDown(self):
        """ Handles next (Page-Down) events."""
        if self._viewhistory == 1:
            # yscroll down stuff
            self._txtbuffer.yview('scroll', '15', 'units')

    def escape(self, tkevent):
        """ Handles escape (Escape) events."""
        if self._viewhistory == 1:
            self._txtbuffer.forget()
            self._viewhistory = 0
        else:
            self._entry.clearInput()

    def configChangeHandler(self, args):
        """ This handles config changes including mudecho. """
        name = args["name"]
        newvalue = args["newvalue"]

        if name == "mudecho":
            if newvalue == 1:
                # echo on
                self._do_i_echo = 1
                self._entry.configure(show='')
            else:
                # echo off
                self._do_i_echo = 0
                self._entry.configure(show='*')

    def _yadjust(self):
        """Handles y scrolling after text insertion."""
        self._txt.yview('moveto', '1')
        # if os.name != 'posix':
        self._txt.yview('scroll', '20', 'units')

    def _clipText(self):
        """
    Scrolls the text buffer up so that the new text written at
    the bottom of the text buffer can be seen.
    """
        temp = self._txt.index("end")
        ind = temp.find(".")
        temp = temp[:ind]
        if (temp.isdigit() and int(temp) > 800):
            self._txt.delete("1.0", "100.end")

    def write(self, args):
        """
    This writes text to the text buffer for viewing by the user.

    This is overridden from the 'base.BaseUI'.
    """
        self._event_queue.put(_OutputEvent(args))

    def write_internal(self, args):
        mess = args["message"]
        if type(mess) == types.StringType:
            mess = message.Message(mess, message.LTDATA)

        line = mess.data
        ses = mess.session

        if line == '' or self.showTextForSession(ses) == 0:
            return

        color, leftover = buffer_write(mess, self._txt, self._currcolors,
                                       self._unfinishedcolor)

        if mess.type == message.MUDDATA:
            self._unfinishedcolor[ses] = leftover
            self._currcolors[ses] = color

        self._clipText()
        self._yadjust()

    def convertColor(self, name):
        """
    Tk has this really weird color palatte.  So I switched to using
    color names in most cases and rgb values in cases where I couldn't
    find a good color name.

    This method allows me to specify either an rgb or a color name
    and it converts the color names to rgb.

    @param name: either an rgb value or a name
    @type  name: string

    @returns: the rgb color value
    @rtype: string
    """
        if name.startswith("#"):
            return name

        rgb = self._tk._getints(
            self._tk.tk.call('winfo', 'rgb', self._txt, name))
        rgb = "#%02x%02x%02x" % (rgb[0] / 256, rgb[1] / 256, rgb[2] / 256)
        print name, "converted to: ", rgb

        return rgb

    def _initColorTags(self):
        """ Sets up Tk tags for the text widget (fg/bg/u)."""
        for ck in fg_color_codes.keys():
            color = self.convertColor(fg_color_codes[ck])
            self._txt.tag_config(ck, foreground=color)
            self._txtbuffer.tag_config(ck, foreground=color)

        for ck in bg_color_codes.keys():
            self._txt.tag_config(ck, background=bg_color_codes[ck])
            self._txtbuffer.tag_config(ck, background=bg_color_codes[ck])

        self._txt.tag_config("u", underline=1)
        self._txtbuffer.tag_config("u", underline=1)

    def colorCheck(self):
        """
    Goes through and displays all the combinations of fg and bg
    with the text string involved.  Purely for debugging
    purposes.
    """
        fgkeys = ['30', '31', '32', '33', '34', '35', '36', '37']
        bgkeys = ['40', '41', '42', '43', '44', '45', '46', '47']

        self._txt.insert('end', 'color check:\n')
        for bg in bgkeys:
            for fg in fgkeys:
                self._txt.insert('end', str(fg), (fg, bg))
                self._txt.insert('end', str("b" + fg), ("b" + fg, bg))
            self._txt.insert('end', '\n')

            for fg in fgkeys:
                self._txt.insert('end', str(fg), (fg, "b" + bg))
                self._txt.insert('end', str("b" + fg), ("b" + fg, "b" + bg))
            self._txt.insert('end', '\n')

        self._txt.insert('end', '\n')
        self._txt.insert('end', '\n')
Example #5
0
class NamedWindow:
    """
  This creates a window for the Tkui which you can then write to 
  programmatically.  This allows modules to spin off new named windows
  and write to them.
  """
    def __init__(self, windowname, master, partk):
        """
    Initializes the window

    @param windowname: the name of the new window
    @type  windowname: string

    @param master: the main tk window
    @type  master: toplevel
    """
        self._parent = master
        self._tk = Toplevel(partk)
        self._windowname = windowname

        # map of session -> (bold, foreground, background)
        self._currcolors = {}

        # ses -> string
        self._unfinishedcolor = {}

        self._do_i_echo = 1

        self._tk.geometry("500x300")
        self._tk.title("Lyntin -- " + self._windowname)

        self._tk.protocol("WM_DELETE_WINDOW", self.close)

        if os.name == "posix":
            fontname = "Courier"
        else:
            fontname = "Fixedsys"
        fnt = tkFont.Font(family=fontname, size=12)

        self._txt = ScrolledText(self._tk,
                                 fg="white",
                                 bg="black",
                                 font=fnt,
                                 height=20)
        self._txt.pack(side=TOP, fill=BOTH, expand=1)

        # handles improper keypresses
        self._txt.bind("<KeyPress>", self._ignoreThis)

        # initialize color tags
        self._initColorTags()

    def convertColor(self, name):
        """
    Tk has this really weird color palatte.  So I switched to using
    color names in most cases and rgb values in cases where I couldn't
    find a good color name.

    This method allows me to specify either an rgb or a color name
    and it converts the color names to rgb.

    @param name: either an rgb value or a name
    @type  name: string

    @returns: the rgb color value
    @rtype: string
    """
        if name[0] == "#":
            return name

        rgb = self._tk._getints(
            self._tk.tk.call('winfo', 'rgb', self._txt, name))
        rgb = "#%02x%02x%02x" % (rgb[0] / 256, rgb[1] / 256, rgb[2] / 256)
        print name, "converted to: ", rgb

        return rgb

    def _initColorTags(self):
        """ Sets up Tk tags for the text widget (fg/bg)."""
        for ck in fg_color_codes.keys():
            color = self.convertColor(fg_color_codes[ck])
            self._txt.tag_config(ck, foreground=color)

        for ck in bg_color_codes.keys():
            self._txt.tag_config(ck, background=bg_color_codes[ck])

        self._txt.tag_config("u", underline=1)

    def _ignoreThis(self, tkevent):
        """
    This catches keypresses to this window.
    """
        return "break"

    def close(self):
        """
    Closes and destroys references to this window.
    """
        self._parent.removeWindow(self._windowname)
        self._tk.destroy()

    def _yadjust(self):
        """Handles y scrolling after text insertion."""
        self._txt.yview('moveto', '1')
        # if os.name != 'posix':
        self._txt.yview('scroll', '20', 'units')

    def _clipText(self):
        """
    Scrolls the text buffer up so that the new text written at
    the bottom of the text buffer can be seen.
    """
        temp = self._txt.index("end")
        ind = temp.find(".")
        temp = temp[:ind]
        if (temp.isdigit() and int(temp) > 800):
            self._txt.delete("1.0", "100.end")

    def write(self, msg):
        """
    This writes text to the text buffer for viewing by the user.

    This is overridden from the 'base.BaseUI'.
    """
        if type(msg) == types.TupleType:
            msg = msg[0]

        if type(msg) == types.StringType:
            msg = message.Message(msg, message.LTDATA)

        line = msg.data
        ses = msg.session

        if line == '':
            return

        color, leftover = buffer_write(msg, self._txt, self._currcolors,
                                       self._unfinishedcolor)

        if msg.type == message.MUDDATA:
            self._unfinishedcolor[ses] = leftover
            self._currcolors[ses] = color

        self._clipText()
        self._yadjust()
Example #6
0
class Globby_Text_Editor(tk.Frame):
    def __init__(self, parent_widget, settings):
        # some initial values
        # TODO this Values are obsolete since Project_Settings covers them
        # --> self.settings.projects_path
        self.hash_opened_filename = None
        self.opened_filename = None
        self.settings = settings

        self.edit_button_list=[
            {'text':'new page', 'cmd':self.on_new_page,
                'keytxt':'CTRL+n','hotkey':'<Control-n>'},
            {'text':'del page', 'cmd':self.on_del_page,
                'keytxt':'CTRL+n','hotkey':'<DELETE>'} ,
            {'text':'save', 'cmd':self.on_save,
                'keytxt':'CTRL+s','hotkey':'<Control-s>'},
            {'text':'undo', 'cmd':self.on_undo,
                'keytxt':'CTRL+z','hotkey':'<Control-z>'},
            {'text':'redo', 'cmd':self.on_redo,
                'keytxt':'CTRL+y','hotkey':'<Control-y>'}]

        self.syntax_button_list=[
            {'text':'**bold**', 'cmd':self.on_tag_insert, 'open_tag':'**',
                'close_tag':'**','keytxt':'CTRL+b','hotkey':'<Control-b>'},
            {'text':'//italic//', 'cmd':self.on_tag_insert, 'open_tag':'//',
                'close_tag':'//', 'keytxt':'CTRL+i','hotkey':'<Control-i>'},
            {'text':'__underline__', 'cmd':self.on_tag_insert, 'open_tag':'__',
                'close_tag':'__', 'keytxt':'CTRL+u','hotkey':'<Control-u>'},
            {'text':'[Link]', 'cmd':self.on_tag_insert, 'open_tag':'[',
                'close_tag':']', 'keytxt':'CTRL+l','hotkey':'<Control-l>'},
            {'text':'¸¸sub¸¸', 'cmd':self.on_tag_insert, 'open_tag':'¸¸',
                'close_tag':'¸¸', 'keytxt':'CTRL+d','hotkey':'<Control-d>'},
            {'text':'^^upper^^', 'cmd':self.on_tag_insert, 'open_tag':'^^',
                'close_tag':'^^', 'keytxt':'CTRL+q','hotkey':'<Control-q>'},
            {'text':'-~smaller~-', 'cmd':self.on_tag_insert, 'open_tag':'-~',
                'close_tag':'~-', 'keytxt':'CTRL+w','hotkey':'<Control-w>'},
            {'text':'+~bigger~+', 'cmd':self.on_tag_insert, 'open_tag':'+~',
                'close_tag':'~+', 'keytxt':'CTRL+e','hotkey':'<Control-e>'},
            {'text':'~~strike_thru~~', 'cmd':self.on_tag_insert, 'open_tag':'~~',
                'close_tag':'~~', 'keytxt':'CTRL+t','hotkey':'<Control-t>'} ]

        # build Widgets
        tk.Frame.__init__(self, parent_widget)
        self.pack(fill=tk.BOTH, expand=tk.YES)

        #self.baseframe = tk.Frame(parent_widget)
        #self.baseframe.pack(fill=tk.BOTH, expand=tk.YES)
        self.editor()
        self.button_frame()

        # start tracking text changes inside the editfield
        thread.start_new_thread(self.on_txt_changes, ('',))



    def editor(self):
        """ combine some Widgets to an enhanced editor (incl. Scrollbar)

        --> self.text
                the text widget itself

        --> self.opened_file_label
                Label on top of the editfield to show the name of the current
                opened File
                It can be used to show textchanges
        """
        # build widgets
        self.txtfrm = tk.Frame(self)
        self.txtfrm.pack(fill=tk.BOTH, side=tk.LEFT, expand=tk.YES)
        self.opened_file_label = tk.Label(self.txtfrm, text="No File chosen")
        self.opened_file_label.pack(fill=tk.X)
        self.text = ScrolledText(self.txtfrm, bg="white",
                                undo=1, maxundo=30,
                                wrap=tk.WORD)
        self.text.pack(fill=tk.BOTH, expand=tk.YES, side=tk.LEFT)
        self.text.insert(1.0, u"Please open a File to edit")

        # build first(reference -- new name??) hash for comparison on changes
        self.hash_opened_filename = hash(self.text.get(1.0,tk.END))

        # Set focus on textwidget and move cursor to the upper left
        self.text.focus_set()
        self.text.mark_set(tk.INSERT, '0.0')      # goto line
        self.text.see(tk.INSERT)                  # scroll to line


    def label_button_row(self, parent_widget=None,
                            btnlst=None, start_count=0):
        """Build a 2 column table with a label beside each button in a row.
        Bind a keyboard sequence to the button command.
        Display this keyboard sequence on the label.

        todo:
            - think about a parameter for the widget to bind the Hotkeys
            - rename to: labled_button_row, draw_labled_button_row

        Parameter:
        --> parent_widget:
                Parent widget to place the table

        --> btnlst:
                Type: List of dicts representing a button
                Example:
                    {'text':'**bold**',     # displayed on the Button (string)
                    'cmd':self.on_tag_insert,   # command
                    'open_tag':'**',        # chars representing the beginning
                                            # of a tag for inserting (string)
                    'close_tag':'**',       # chars representing the end
                                            # of a tag for inserting (string)
                    'keytxt':'CTRL+b',      # displayed on the Label (string)
                    'hotkey':'<Control-b>'} # keyboard sequence (string)
                Note:
                    The existence of 'open_tag' and 'close_tag' in btnlst
                    decides which command is bound to the Button.
                    If they aren't there 'cmd' must be a function without
                    parameters!!!
                    otherwise 'cmd' needs following parameters:
                        otag = btn['open_tag']
                        ctag = btn['close_tag']
                        event = None  # Placeholder for a keysequence

        --> start_count:
                Type: int

                Description:
                    The table is relized with tkinter grid layout manager.
                    start_count is used if there is already a grid
                    (with a Label beside a button).
                    start_count can add the automatic genrated
                    buttons under the existing.
                    In Globby_Editor it is used to put a label_button_row
                    under a Tkinter menubutton(file choose, headlines).
        """
        i = start_count
        for btn in btnlst:
            try:
                otag = btn['open_tag']
                ctag = btn['close_tag']
                event = None
                doit = lambda e=event, o=otag, c=ctag:self.on_tag_insert(e,o,c)
                tk.Button(parent_widget, text=btn['text'], command=doit,
                        relief=tk.RIDGE
                        ).grid(column=0, row=i, sticky=tk.W+tk.E)
                self.text.bind(btn['hotkey'],doit)
            except KeyError:
                tk.Button(parent_widget, text=btn['text'], command=btn['cmd'],
                        relief=tk.RIDGE
                        ).grid(column=0, row=i, sticky=tk.W+tk.E)
            tk.Label(parent_widget, text=btn['keytxt'], relief=tk.FLAT
                ).grid(column=1, row=i, sticky=tk.W)
            i +=1


    def button_frame(self):
        """draws a frame to hold a edit- and syntax-buttons under each other
        """
        self.btnfrm = tk.Frame(self)
        self.btnfrm.pack(fill=tk.BOTH, side=tk.LEFT)
        self.edit_buttons()
        self.syntax_buttons()


    def edit_buttons(self):
        """draws a frame with buttons for editing (save, undo, redo, open)
        """

        # genrate a labelframe
        self.efrm = tk.LabelFrame(self.btnfrm, text="Edit Buttons")
        self.efrm.pack(fill=tk.BOTH, padx=5, pady=5)

        # generate a button with a pulldown menue to open a file to edit
        self.file_open_mbtn = tk.Menubutton(self.efrm, text='Open File')
        # generate the pulldown menue
        self.file_open_menu = tk.Menu(self.file_open_mbtn,
                                        postcommand=self.gen_file2edit_menu)
        # bind the pulldown menue to the menubutton
        self.file_open_mbtn.config(menu=self.file_open_menu, relief=tk.RIDGE)


        self.file_open_mbtn.grid(column=0,row=0, sticky=tk.W+tk.E)

        # label beside the Button to display the associated keyboard shortcut
        self.file_open_lbl = tk.Label(self.efrm, text='CTRL+o', relief=tk.FLAT)
        self.file_open_lbl.grid(column=1, row=0, sticky=tk.W+tk.E)


        # generate buttons as described in self.edit_button_list
        self.label_button_row(self.efrm, self.edit_button_list, 2)


        # bind keyboard shortcut to the menue
        self.text.bind('<Control-o>',
                lambda e: self.file_open_menu.tk_popup(e.x_root, e.y_root))


    def gen_file2edit_menu(self):
        """generates a (new) menu bound to the file chooser button
        so every time when a project is created or deleted
        gen_choose_project_menu should be called
        """
        # delete all existing menue entrys
        self.file_open_menu.delete(0,tk.END)
        proj_path = os.path.join(self.settings.projects_path,
                                self.settings.current_project )
        print "proj_path", proj_path
        for this_file in os.listdir(proj_path):
            splitted = os.path.splitext(this_file)
            if splitted[1] == ".txt" and splitted[0] != "menue":
                #print "this_file",this_file
                open_file = os.path.join(proj_path, this_file)
                do_it = lambda bla = open_file:self.on_open(bla)
                self.file_open_menu.add_command(label=splitted, command=do_it)




    def syntax_buttons(self):
        """draws a frame with buttons for insert (wiki)markup

        idea: new parameter for on_tag_insert()
            jump_in_between=True/False so a pulldown list for different levels
            of headlines arn't necessary
        """

        # genrate a labelframe
        self.sfrm = tk.LabelFrame(self.btnfrm, text="Syntax Buttons")
        self.sfrm.pack(fill=tk.BOTH, padx=5, pady=5)

        # generate a button with a pulldown menue für headline Syntax
        self.headln_menubtn = tk.Menubutton(self.sfrm, text='= Headlines =')
        # generate the pulldown menue
        self.headln_menu = tk.Menu(self.headln_menubtn)
        # bind the pulldown menue to the menubutton
        self.headln_menubtn.config(menu=self.headln_menu, relief=tk.RIDGE)
        # generate menue entrys
        i=1
        for entry in ('h1','h2','h3','h4','h5','h6'):
            otag = '\n\n'+'='*i+' '
            ctag = ' '+'='*i+'\n\n'
            doit = lambda event=None, o=otag, c=ctag:self.on_tag_insert(event,o,c)
            self.headln_menu.add_command(label=entry, command=doit)
            i+=1
        self.headln_menubtn.grid(column=0,row=0, sticky=tk.W+tk.E)

        # label beside the Button to display the associated keyboard shortcut
        self.headln_lbl = tk.Label(self.sfrm, text='CTRL+h', relief=tk.FLAT)
        self.headln_lbl.grid(column=1, row=0, sticky=tk.W+tk.E)

        # generate buttons as described in self.edit_button_list
        self.label_button_row(self.sfrm, self.syntax_button_list, 1)

        # bind keyboard shortcut to the menue
        self.text.bind('<Control-h>',
                lambda e: self.headln_menu.tk_popup(e.x_root, e.y_root))


    def on_txt_changes(self, dummy_value=tk.NONE):
        """ tracks text changes inside the editfield by comparing hash values
        new name: visualize_txt_changes???
        """
        while True:
            new_hash = hash(self.text.get(1.0, tk.END))
            if new_hash != self.hash_opened_filename:
                #print "changes"
                self.opened_file_label.configure(fg="red")
            else:
                #print "no changes"
                self.opened_file_label.configure(fg="black")
            sleep(0.2)


    def on_open(self, file_to_open=None):
        """- opens a *.txt file from project folder
        - generates a reference hash.
        - Brings the cursor to the upper left and show this position
          in the textfield

        Parameter:
        --> file_to_open:
                complete path for file to open
        idea:
            - rename file_to_open to openfile or file_to_open
        """
        self.opened_file_to_open = file_to_open
        self.opened_file_label.configure(text=file_to_open)
        self.text.delete(1.0, tk.END)

        self.opened_filename = os.path.basename(file_to_open)


        # write file content into the editfield
        editfile = codecs.open(file_to_open,'r', 'utf-8')
        self.text.insert(1.0, editfile.read())
        editfile.close()

        # generate reference hash for a comparison to track text changes
        self.hash_opened_filename = hash(self.text.get(1.0,tk.END))

        self.text.edit_reset()                  # clear tk's undo/redo stacks
        self.text.focus_set()                   # focus to textfield
        self.text.mark_set(tk.INSERT, '0.0')    # place cursor to upper left
        self.text.see(tk.INSERT)                # and display this line


    def on_save(self):
        """ Safes the current edited file"""
        if self.opened_filename:
            print "on_safe_"
            print "  self.opened_filename",self.opened_filename

            self.hash_opened_filename = hash(self.text.get(1.0,tk.END))


            path_to_safe_file = os.path.join(self.settings.projects_path,
                                    self.settings.current_project,
                                    self.opened_filename)

            safefile = codecs.open(path_to_safe_file,'w', 'utf-8')
            safefile.write(self.text.get(1.0,tk.END))
            safefile.close()
            self.text.edit_reset()        #clear tk's undo/redo stacks
        else:
            showinfo('Globby Text Editor','No File to save \n\n'
                    'You need to choose a File before editing')


    def on_undo(self):
        try:                                    # tk8.4 keeps undo/redo stacks
            self.text.edit_undo( )              # exception if stacks empty
        except tk.TclError:
            showinfo('Globby Text Editor', 'Nothing to undo')


    def on_redo(self):
        print "redo"
        try:                                  # tk8.4 keeps undo/redo stacks
            self.text.edit_redo()             # exception if stacks empty
        except tk.TclError:
            showinfo('Globby Text Editor', 'Nothing to redo')


    def on_new_page(self):
        """ Ask the user to name the new File, create a blank File and load it
        into the Editorwidget

        TODO:   check if file with the new filename allready exists
                check if Filename contains Specialchars
        """
        print "on_new_page"
        nfile_name = tkSimpleDialog.askstring("New File Name",
                                    "Fill in a new File Name")
        proj_path = os.path.join(self.settings.projects_path,
                                self.settings.current_project)
        nfile_name = os.path.join(proj_path, nfile_name.strip()+'.txt')
        nfile = codecs.open(nfile_name, 'w', 'utf-8')

        current_project = self.settings.current_project
        infostring1 = u'# Diese Datei wurde automatisch mit '
        infostring2 = u'dem Projekt "%s" erstellt' % current_project
        nfile.write(infostring1+infostring2 )
        nfile.close()

        self.on_open(nfile_name)

    def on_del_page(self):
        """"""
        print "del page"
        # self.settings.current_project
        del_file = os.path.join(self.settings.projects_path,
                                    self.settings.current_project,
                                    self.opened_filename)

        del_page = askyesno("Do you really want to delete ", del_file)

        if del_page:
            #self.set_project(self.new_project_name)
            print "%s geloescht" % del_file
            os.remove(del_file)


    def on_tag_insert(self, event=None, open_tag=None, close_tag=None):
        """ inserts a (wiki)tag to the current cursor position.

        If there is no text marked in the editfield, open_tag and close_tag
        are inserted to the current cursor position behind each other and the
        cursor jumps in between.
        Otherwise the marked string is enclosed by open_tag and close_tag and
        inserted to the current cursor position. Here the new cursor position
        is right behind the complete inserted string with tags.

        At this moment this behavior is quite buggy :-(

        idea:
            - new parameter for on_tag_insert()
              jump_in_between=True/False so a pulldown list for different levels
              of headlines arn't necessary
            - rename to: on_insert_tag?? on_tag_insert

        Parameter:
        --> event                       # keyboard shortcut
        --> open_tag                    # string
        --> close_tag                   # string

        """
        #print 'event',event
        #print 'open_tag',open_tag
        #print 'close_tag',close_tag

        ## when no String is selected:
        if not self.text.tag_ranges(tk.SEL):
            print "no String is selected"
            insert_point = self.text.index('insert')
            insertline = insert_point.split('.')[0]
            addit = 1
            if event != None:
                print "event not None"
                addit = 2
            insertrow = str(int(insert_point.split('.')[1])+len(open_tag)+addit)
            new_insert_point = insertline+'.'+ insertrow
            self.text.insert(insert_point, open_tag+''+close_tag)
            # place cursor to insert_point
            self.text.mark_set(tk.INSERT, new_insert_point)
            # display this position on the editfield
            self.text.see(tk.INSERT)

        ## when a String is selected:
        else:
            #print "im else"
            marked_text = self.text.get(self.text.index(tk.SEL_FIRST),
                                        self.text.index(tk.SEL_LAST))
            replace_index = self.text.index(tk.SEL_FIRST)
            print "replace_index in selected", replace_index
            self.text.delete(self.text.index(tk.SEL_FIRST),
                            self.text.index(tk.SEL_LAST))
            self.text.insert(replace_index, open_tag+marked_text+close_tag)
Example #7
0
class MyThing(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pack()
        self.createWidgets()

    def createWidgets(self):
        self.textBox = ScrolledText(self, height=30, width=85)
        self.textBox.pack()
        self.addText()

    def leftMouseClick(self, event):
        print "got a click"
        mouseIndex = "@%d,%d" % (event.x, event.y)
        current = self.textBox.index(mouseIndex)
        row = current.split(".")[0] + ".0"
        rowFl = float(row) + 1.0
        row = str(rowFl)
        target = self.rowIndex[row]
        target = float(target) + 12.0
        target = str(target)
        print "moving to target", target
        self.textBox.see(target)

    def rightMouseClick(self, event):
        self.textBox.see("0.0")

    def addText(self):
        f = open("help.txt", 'r')
        lines = f.readlines()
        f.close()
        flag = 1
        i = 0
        sectionOrder = {}
        sectionHeads = {}
        outlines = {}
        targetId = 0
        defaultTarget = ""
        tocEntries = []
        lineId = 0
        for line in lines:
            if line[0:1] == "#":
                tocEntries.append(line)
                if flag:
                    top = lineId
                    flag = 0
            lineId += 1

        self.tocEntries = tocEntries
        # header text
        header = lines[0:top]

        for line in header:
            hid = self.textBox.insert(END, line, "header")
            self.textBox.tag_config("header", foreground=FGCOLOR)
            self.textBox.tag_config("header", background=BGCOLOR)

        self.textBox.insert(END, "Table of Contents\n", "toc")
        self.textBox.tag_config("toc", foreground="red")
        self.textBox.tag_config("toc", background=BGCOLOR)
        self.textBox.insert(
            END, "(Left-click entry to navigate, right-click to return)\n\n",
            "directions")
        self.textBox.tag_config("directions", background=BGCOLOR)
        self.textBox.tag_config("directions", foreground="purple")

        sectionDict = {}
        rowIndex = {}
        for tocEntry in tocEntries:
            if tocEntry[0:2] == "##":
                line = "\t" + tocEntry[2:]
            else:
                line = tocEntry[1:]
            rowPosition = self.textBox.index(END).split(".")[0] + ".0"
            rowIndex[rowPosition] = "0.0"
            sectionDict[tocEntry] = rowPosition
            self.textBox.insert(END, line, "tocEntry")

        self.textBox.tag_bind("tocEntry", '<ButtonRelease-1>',
                              self.leftMouseClick)
        self.textBox.tag_config("tocEntry", background=BGCOLOR)
        self.textBox.tag_config("tocEntry", foreground=hfg)
        for i in range(50):
            self.textBox.insert(END, "\n", "regular")

        lines = lines[top:]
        for line in lines:
            if sectionDict.has_key(line):
                print "section id", line
                position = self.textBox.index(END)
                tocPosition = sectionDict[line]
                rowIndex[tocPosition] = position
                line = line.replace("#", "")

            self.textBox.insert(END, line, "regular")

        self.rowIndex = rowIndex

        self.sectionDict = sectionDict

        self.textBox.see("0.0")

        self.textBox.bind_all('<ButtonRelease-3>', self.rightMouseClick)
        self.textBox.tag_config("regular", background=BGCOLOR)
        self.textBox.tag_config("regular", foreground="black")
Example #8
0
class TermWindow(Frame):
    EOL = None

    ##
    # constructor method
    def __init__(self, master=None, **cnf):
        apply(Frame.__init__, (self, master), cnf)
        self.__create_widgets__()
        self.rxWaitPattern = ""
        self.localEcho = False
        self.logFile = None
        self.inQueue = Queue.Queue()
        self.outQueue = Queue.Queue()
        self.update_thread_safe()

    def update_thread_safe(self):
        while not self.inQueue.empty():
            element = self.inQueue.get_nowait()
            if element is not None:
                msg, tag = element
                self.__display__(msg, tag)
            self.st_trm.update_idletasks()
        self.st_trm.after(100, self.update_thread_safe)

    ##
    #
    def __create_widgets__(self):
        dfl_font = 'Courier 10'

        # the title frame of the terminal
        self.f_title = Frame(self)
        self.f_title.pack(fill=BOTH)
        self.f_title.configure(FRAMEBORDER)
        self.shVar = StringVar()
        # show/hide button
        self.b_sh = Button(self.f_title,
                           textvariable=self.shVar,
                           font=dfl_font)
        self.b_sh.pack(side=RIGHT)
        self.b_sh['command'] = self.show_hide_cont
        # clear screen button
        self.b_cls = Button(self.f_title,
                            text="CLS",
                            font=dfl_font,
                            underline=0)
        self.b_cls.pack(side=RIGHT)
        self.b_cls['command'] = self.clear_screen
        # echo on/off button
        self.al_echo = Label(self.f_title,
                             text="ECHO",
                             relief=RAISED,
                             font=dfl_font,
                             padx='3m',
                             pady='1m',
                             underline=0)
        self.al_echo.pack(side=RIGHT, padx=1, pady=1, fill=BOTH)
        self.al_echo.bind("<Button-1>", self.__echo_handler__)
        # log on/off button
        self.al_log = Label(self.f_title,
                            text="LOG",
                            relief=RAISED,
                            font=dfl_font,
                            padx='3m',
                            pady='1m',
                            underline=0)
        self.al_log.pack(side=RIGHT, padx=1, pady=1, fill=BOTH)
        self.al_log.bind("<Button-1>", self.__log_handler__)
        # device connect button
        self.al_connect = Label(self.f_title,
                                text="CONNECT",
                                relief=RAISED,
                                font=dfl_font,
                                padx='3m',
                                pady='1m',
                                underline=1)
        self.al_connect.pack(side=RIGHT, padx=1, pady=1, fill=BOTH)
        self.al_connect.bind("<Button-1>", self.__connect_handler__)

        self.mb_macros = Menubutton(self.f_title, text="Macros", relief=RAISED)
        self.mb_macros.pack(side=RIGHT, padx=1, pady=1, fill=BOTH)
        self.mb_macros.menu = Menu(self.mb_macros, tearoff=0)
        self.mb_macros["menu"] = self.mb_macros.menu

        # title of terminal window
        self.tVar = StringVar()
        self.l_title = Label(self.f_title, text="foo", font=dfl_font)
        self.l_title['textvariable'] = self.tVar
        self.l_title.pack(side=LEFT, expand=1, fill=X)
        self.l_title['width'] = 42
        self.update_title("------ XXX ------")
        # frame for scrolled text window
        # (this frame handle needs to be kept fo show_hide_cont())
        self.f_cont = Frame(self)
        # IO data scrolled text window
        self.st_trm = ScrolledText(self.f_cont,
                                   height=10,
                                   state=DISABLED,
                                   wrap=NONE)
        self.st_trm.pack(expand=1, fill=BOTH)
        self.st_trm['font'] = dfl_font
        self.st_trm.tag_config('E', foreground="blue")
        self.st_trm.tag_config('M', foreground="magenta")

        tframe = Frame(self.f_cont)
        tframe.pack(expand=0, fill=X)
        self.cmdVar = StringVar()
        self.ent_trm = Entry(tframe, textvariable=self.cmdVar, font=dfl_font)
        self.ent_trm.pack(side=LEFT, expand=1, fill=X)
        self.ent_trm.bind("<Control-l>", self.__log_handler__)
        self.ent_trm.bind("<Control-e>", self.__echo_handler__)
        self.ent_trm.bind("<Control-o>", self.__connect_handler__)
        self.ent_trm.bind("<Control-c>", self.clear_screen)
        self.ent_trm.bind("<Control-x>", self.show_hide_cont)
        self.ent_trm.bind("<Control-m>", lambda *args: self.do_macro("M"))
        self.ent_trm.bind("<KeyPress>", self.__input_handler__)

        self.gui_elements = [
            self.b_sh, self.b_cls, self.al_echo, self.al_log, self.al_connect,
            self.mb_macros, self.l_title, self.st_trm, self.ent_trm
        ]
        self.show_cont()

    def add_macro(self, id, title, text=None, function=None, params=None):
        if text:
            cmd = lambda *args: self.do_macro(text)
        if function:
            user_func = eval(function)
            if params:
                params = eval(str(params))
            else:
                params = {}
            cmd = lambda *args: user_func(self, DEVICES, **params)
        mb = self.mb_macros.menu.add_command(label=title, command=cmd)

    def _configure_(self, **args):
        for e in self.gui_elements:
            e.configure(args)

    def __input_handler__(self, *args):
        for i in args:
            self.terminal_device_write(i.char)

    def terminal_device_write(self, *args):
        for i in args:
            if self.localEcho:
                self.display(i, "E")
            if len(i):
                if i == "\r" or i == "\n":
                    self.device.write(self.EOL)
                    self.display(self.EOL, "E")
                    self.cmdVar.set("")
                else:
                    self.device.write(i)
        self.st_trm.update_idletasks()

    def __echo_handler__(self, *args):
        if self.localEcho:
            self.localEcho = False
            self.al_echo['relief'] = RAISED
            self.message("Local Echo OFF")
        else:
            self.localEcho = True
            self.al_echo['relief'] = SUNKEN
            self.message("Local Echo ON")

    def __log_handler__(self, *args):
        try:
            do_open = self.logFile.closed
            logname = self.logFile.name
        except:
            do_open = True
            logname = ""
        if do_open:
            if self.device.logname:
                logname = self.device.logname
                self.message("logfile from config file %s " % logname)
            else:
                fd = FileDialog(self)
                logname = fd.go(logname)
            try:
                if self.device.logmode not in "wa":
                    self.device.logmode = "a"
                    _print(3, "force _a_ppend")
                self.logFile = open(logname, self.device.logmode)
                self.al_log['relief'] = SUNKEN
                self.message("Logging ON: %s" % self.logFile.name)
            except:
                self.message("Error open logfile: %s" % logname)

        else:
            self.message("Logging OFF: %s" % self.logFile.name)
            self.logFile.flush()
            self.logFile.close()
            self.al_log['relief'] = RAISED

    def __connect_handler__(self, *args):
        if self.device.isConnected:
            self.device.disconnect()
            self.al_connect['relief'] = RAISED
            self.message("Disconnected")
        else:
            try:
                self.device.connect()
                self.al_connect['relief'] = SUNKEN
                self.message("Connected")
                self.al_connect['fg'] = "black"
            except:
                self.device.isConnected = False
                self.message(str(sys.exc_info()[1]))
                self.al_connect['fg'] = "red"

    def clear_screen(self, *args):
        self.st_trm['state'] = NORMAL
        self.st_trm.delete("0.0", END)
        self.st_trm['state'] = DISABLED

    def set_device(self, device):
        self.device = device
        self.device.configure(TxQueue=self.outQueue, RxQueue=self.inQueue)
        self.update_title(self.device)

        if self.device.log:
            self.__log_handler__()
        if self.device.auto_connect:
            self.__connect_handler__()

    def update_title(self, title):
        self.tVar.set(title)

    def show_cont(self):
        self.shVar.set("X")
        self.f_cont.pack(expand=1, fill=BOTH)

    def hide_cont(self):
        self.shVar.set("+")
        self.f_cont.pack_forget()

    def show_hide_cont(self, *args):
        if self.shVar.get() == "X":
            self.hide_cont()
        else:
            self.show_cont()

    def do_macro(self, *args):
        if self.localEcho:
            self.display(args[0] + "\n", "E")
        self.device.write(args[0] + "\n")

    def write(self, data):
        self.outQueue.put((data, None))

    def message(self, text, tag='M'):
        msg = "[%s:%s:%s]\n" % (time.asctime(), self.device.name, text)
        if self.st_trm.index(AtInsert()).find(".0") < 1:
            msg = "\n" + msg
        self.inQueue.put((msg, tag))

    def display(self, text, tag=None):
        self.inQueue.put((text, tag))

    def __display__(self, msg, tag=None):
        self.st_trm['state'] = NORMAL
        here = self.st_trm.index(AtInsert())
        for d in re.split("([\r\v\t\n])", msg):
            if len(d):
                if d != '\r':
                    self.st_trm.insert(END, d)
        if tag:
            self.st_trm.tag_add(tag, here, AtInsert())
        self.st_trm.see(END)
        self.st_trm['state'] = DISABLED
        try:
            self.logFile.write(msg)
            self.logFile.flush()
        except:
            pass
class GUI_hcheck:

    # do everything!
	def __init__(self):
		self.top = Tk()
		self.top.title('Health Check Tool')
		self.top.geometry('1400x800')

		#------- Label,Entry defination ----------#
		self.l1 = Label(self.top, text="IP:").grid(row=1, column=1, sticky="w")
		self.e1 = Entry(self.top)
		self.e1.grid(row=1, column=2,sticky="ew")
		self.l2 = Label(self.top, text="User:"******"w")
		self.e2 = Entry(self.top)
		self.e2.grid(row=2, column=2,sticky="ew")
		self.l3 = Label(self.top, text="Passwd:").grid(row=3, column=1, sticky="w")
		self.e3 = Entry(self.top)
		self.e3['show'] = '*'
		self.e3.grid(row=3, column=2,sticky="ew")
		self.l4 = Label(self.top, text="Command pool:").grid(row=4, column=1, sticky="e")
		self.l5 = Label(self.top, text="To be run command:").grid(row=4, column=5, sticky="e")
		self.e4 = Entry(self.top, width=30)
		self.e4.grid(row=16, column=0, columnspan=3, sticky="ew")

		#------- Checkbutton defination ----------#
		self.cb1State = IntVar()
		self.cb1 = Checkbutton(self.top, variable=self.cb1State, text = "Always Yes", command=self.callCheckbutton)
		self.cb1.grid(row=21, column=16)

		#------- Listbox defination ----------#
		self.cmdfm = Frame(self.top)
		self.cmdsb = Scrollbar(self.cmdfm)
		self.cmdsb_x = Scrollbar(self.cmdfm,orient = HORIZONTAL)
		self.cmdsb.pack(side=RIGHT, fill=Y)
		self.cmdsb_x.pack(side=BOTTOM, fill=X)
		self.cmdls = Listbox(self.cmdfm, selectmode=EXTENDED, height=25, width=40, xscrollcommand=self.cmdsb_x.set, yscrollcommand=self.cmdsb.set)
		self.cmdsb.config(command=self.cmdls.yview)
		self.cmdsb_x.config(command=self.cmdls.xview)
		self.cmdls.pack(side=LEFT, fill=BOTH)
		self.cmdfm.grid(row=5, rowspan=10, column=0,columnspan=4,sticky="ew")
		self.db_file = os.path.join(os.getcwd(),'%s' % constants.DB_NAME)
		flist = utility.load_file(self.db_file)
		if flist != None:
			log.debug ("db file found, start load command")
			for element in flist:
				element = element.strip('\n')
				if element == '' or element.startswith('#'):
					continue
				self.cmdls.insert(END, element)
		else:
			log.debug ("db file doesn't existed, initail cmd")
			for element in constants.CMD_LIST_COMM:
				self.cmdls.insert(END, element)

		self.dirfm = Frame(self.top)
		self.dirsb = Scrollbar(self.dirfm)
		self.dirsb_x = Scrollbar(self.dirfm,orient = HORIZONTAL)
		self.dirsb.pack(side=RIGHT, fill=Y)
		self.dirsb_x.pack(side=BOTTOM, fill=X)
		self.dirs = Listbox(self.dirfm, selectmode=EXTENDED, height=25, width=40, xscrollcommand=self.dirsb_x.set,yscrollcommand=self.dirsb.set)
		self.dirsb.config(command=self.dirs.yview)
		self.dirsb_x.config(command=self.dirs.xview)
		self.dirs.pack(side=LEFT, fill=BOTH)
		self.dirfm.grid(row=5, rowspan=10, column=5,columnspan=4,sticky="ew")

		#------- Buttion defination ----------#
		# add command button
		self.b1 = Button(self.top,text=">>",width=6,borderwidth=3,relief=RAISED, command=self.move_cmd)
		self.b1.grid(row=7, column=4)
		# del command button
		self.b2 = Button(self.top,text="<<",width=6,borderwidth=3,relief=RAISED, command=self.del_cmd)
		self.b2.grid(row=8, column=4)
		# move up command button
		self.b3 = Button(self.top,text="up",width=6,borderwidth=3,relief=RAISED, command=self.up_cmd)
		self.b3.grid(row=7, column=10)
		# move down command button
		self.b4 = Button(self.top,text="down",width=6,borderwidth=3,relief=RAISED, command=self.down_cmd)
		self.b4.grid(row=8, column=10)
		# start command button
		self.b5 = Button(self.top,text="Start",bg='red',width=10,borderwidth=3,relief=RAISED, command=self.start_process)
		self.b5.grid(row=2, column=11)
		# yes button
		self.b6 = Button(self.top,text="Yes",width=6,borderwidth=3,relief=RAISED, command=self.set_confirm_yes)
		self.b6.grid(row=21, column=13)
		# No button
		self.b7 = Button(self.top,text="No",width=6,borderwidth=3,relief=RAISED, command=self.set_confirm_no)
		self.b7.grid(row=21, column=14)
		# Skip button
		self.b8 = Button(self.top,text="Skip",width=6,borderwidth=3,relief=RAISED, command=self.set_confirm_skip)
		self.b8.grid(row=21, column=15)
		# Add button
		self.b9 = Button(self.top,text="add cmd",width=10,borderwidth=3,relief=RAISED, command=self.add_command)
		self.b9.grid(row=15, column=1)
		# Del button
		self.b10 = Button(self.top,text="del cmd",width=10,borderwidth=3,relief=RAISED, command=self.del_command)
		self.b10.grid(row=15, column=2)
		# Manual button
		self.manual = False
		self.b11 = Button(self.top,text="Manual model",width=10,borderwidth=3,relief=RAISED, command=self.manual_mode)
		self.b11.grid(row=2, column=12)

		#------- ScrolledText defination ----------#
		self.sfm = Frame(self.top)
		self.console = ScrolledText(self.sfm,height=45, width=86,bg='black',fg='green',insertbackground='green')
		self.console['font'] = ('lucida console','10')
		self.console.bind("<Return>", self.process_input)
		self.console.pack()
		self.sfm.grid(row=4, rowspan=15, column=11,columnspan=10,sticky="ew")

		self.redir = redirect(self.console)
		sys.stdout = self.redir
		sys.stderr = self.redir
		self.fconsole = logging.StreamHandler(sys.stdout)
		self.fconsole.setLevel(logging.INFO)
		logging.getLogger('').addHandler(self.fconsole)

		#------- Menu defination ----------#
		self.menubar = Menu()
		# file menu
		self.fmenu = Menu()
		#self.fmenu.add_command(label = 'New',command=self.new_win)
		self.fmenu.add_command(label = 'Import cmd',command=self.load_cmd)
		self.fmenu.add_command(label = 'Export cmd',command=self.export_cmd)
		self.menubar.add_cascade(label = 'File', menu = self.fmenu)
		# edit menu
		self.emenu = Menu()
		self.cmenu = Menu()
		self.cvar = StringVar()
		for item in ['white/black', 'black/white', 'green/black']:
			self.cmenu.add_radiobutton(label = item, variable=self.cvar, value=item, command=self.sel_color_style)
		self.emenu.add_cascade(label = 'console style', menu = self.cmenu)
		self.emenu.add_command(label = 'reset cmd pool',command=self.reset_cmd_pool)
		self.menubar.add_cascade(label = 'Edit', menu = self.emenu)

		self.top['menu'] = self.menubar

	def new_win(self):
		#GUI_hcheck()
		pass

	def sel_color_style(self):
		log.debug ("select console color style: %s " % self.cvar.get())
		color = self.cvar.get()
		if color == 'white/black':
			self.console.config(bg='black',fg='white',insertbackground='white')
		elif color == 'black/white':
			self.console.config(bg='white',fg='black',insertbackground='black')
		elif color == 'green/black':
			self.console.config(bg='black',fg='green',insertbackground='green')

	def move_cmd(self):
		if self.cmdls.curselection() != ():
			for i in self.cmdls.curselection():
				if utility.elemet_exists(self.dirs.get(0,END), self.cmdls.get(i)) == None:
					self.dirs.insert(END,self.cmdls.get(i))
					log.debug ("move command %s" % self.cmdls.get(i))
		else:
			tkMessageBox.showwarning('Message', 'Please select at lease one item')

	def load_cmd(self):
		file = tkFileDialog.askopenfilename()
		flist = utility.load_file(file)
		if flist != None:
			self.dirs.delete(0,END)
			for element in flist:
				element = element.strip('\n')
				if element == '' or element.startswith('#'):
					continue
				if utility.elemet_exists(self.dirs.get(0,END), element) == None:
					self.dirs.insert(END, element)
		else:
			tkMessageBox.showerror('Message', 'import failed')

	def export_cmd(self):
		file = tkFileDialog.askopenfilename()
		if utility.export_file(self.dirs.get(0,END), file) == True:
			tkMessageBox.showinfo('Message', 'export finish')
		else:
			tkMessageBox.showerror('Message', 'export failed')

	def del_cmd(self):
		if self.dirs.curselection() != ():
			for i in self.dirs.curselection():
				self.dirs.delete(i)
		else:
			tkMessageBox.showwarning('Message', 'Please select at lease one item')

	def up_cmd(self):
		select = self.dirs.curselection()
		if (len(select)) >= 2:
			tkMessageBox.showwarning('Message', 'Only one select is supported')
			return
		log.debug ("move up select pos: %s" % str(select))
		if select != () and select != (0,):
			element = self.dirs.get(select)
			self.dirs.delete(select)
			self.dirs.insert((select[0] - 1), element)
			self.dirs.select_set(select[0] - 1)

	def down_cmd(self):
		select = self.dirs.curselection()
		if (len(select)) >= 2:
			tkMessageBox.showwarning('Message', 'Only one select is supported')
			return
		log.debug ("move down select pos: %s" % str(select))
		if select != () and select != (END,):
			element = self.dirs.get(select)
			self.dirs.delete(select)
			self.dirs.insert((select[0] + 1), element)
			self.dirs.select_set(select[0] + 1)

	def start_process(self):
		log.debug ("current thread total numbers: %d" % threading.activeCount())
		response = tkMessageBox.askokcancel('Message', 'Will start healthcheck, please click OK to continue, or cancel')
		if response == False:
			return
		th = threading.Thread(target=self.start_cmd)
		th.setDaemon(True)
		th.start()

	def start_cmd(self):
		self.manual = False
		cmd = list(self.dirs.get(0,END))
		if len(cmd) == 0:
			log.info ("To be run cmd numbers none, quit...")
			return
		log.debug ("fetch cmd list from GUI: %s" % cmd)
		(ip, port) = utility.getipinfo(self.e1.get())
		log.debug ("get ip infor-> ip: %s, port:%s" % (ip,port))
		if ip == False:
			log.error ("Given ip infor is wrong! The right ip address: xxx.xxx.xxx.xxx or IP:port ")
			return
		self.b5.config(state=DISABLED)
		self.b11.config(state=DISABLED)
		self.console.delete('1.0',END)
		try:
			self.wf = Workflow(cmd, ip, self.e2.get(), self.e3.get(), port)
			self.wf.start()
		except:
			pass
		self.b5.config(state=NORMAL)
		self.b11.config(state=NORMAL)

	def manual_mode(self):
		cmd = []
		(ip, port) = utility.getipinfo(self.e1.get())
		log.debug ("get ip infor-> ip: %s, port:%s" % (ip,port))
		if ip == False:
			log.error ("Given ip infor is wrong! The right ip address: xxx.xxx.xxx.xxx or IP:port ")
			return
		self.wf_manual = Workflow(cmd, ip, self.e2.get(), self.e3.get(), port)
		if self.wf_manual.setup_ssh(self.wf_manual.hostip) == False:
			log.error ("\nssh setup error! please check ip/user/passwd and network is okay")
			del self.wf_manual
			return
		self.console.delete('1.0',END)
		self.console.insert(END, "Switch to manual mode...\n\
Please input command directly after \">>> \"\n\n")
		self.prompt = ">>> "
		self.insert_prompt()
		self.manual = True
		self.b5.config(state=DISABLED)
		self.b11.config(state=DISABLED)

	def set_confirm_yes(self):
		try:
			self.wf.set_confirm('Yes')
		except AttributeError:
			log.debug("wf doesn't existed")
	def set_confirm_no(self):
		try:
			self.wf.set_confirm('No')
		except AttributeError:
			log.debug("wf doesn't existed")
	def set_confirm_skip(self):
		try:
			self.wf.set_confirm('Skip')
		except AttributeError:
			log.debug("wf doesn't existed")

	def callCheckbutton(self):
		try:
			if self.cb1State.get() == 1:
				self.wf.set_automatic(5)
			else:
				self.wf.set_automatic(None)
		except AttributeError:
			log.debug("wf doesn't existed")
			self.cb1.deselect()
			tkMessageBox.showwarning('Message', 'please press start button first')

	def saveinfo(self):
		pass

	def add_command(self):
		item = self.e4.get()
		if item != '':
			if utility.elemet_exists(self.cmdls.get(0,END), item) == None:
				self.cmdls.insert(END,item)
				self.cmdls.see(END)
				log.debug ("add new command %s" % item)
				self.save_command()
		else:
			tkMessageBox.showwarning('Message', 'entry can not empty')

	def del_command(self):
		if self.cmdls.curselection() != ():
			for i in self.cmdls.curselection():
				self.cmdls.delete(i)
				self.save_command()
		else:
			tkMessageBox.showwarning('Message', 'Please select at lease one item')

	def save_command(self):
		if utility.export_file(self.cmdls.get(0,END), self.db_file) != True:
			log.error ("save command pool failed")

	def reset_cmd_pool(self):
		log.debug ("start to reset command pool list")
		self.cmdls.delete(0,END)
		for element in constants.CMD_LIST_COMM:
			self.cmdls.insert(END, element)
		self.save_command()

	def insert_prompt(self):
		c = self.console.get("end-2c")
		if c != "\n":
			self.console.insert("end", "\n")
		self.console.insert("end", self.prompt, ("prompt",))
		#self.text.insert("end", self.prompt)
		# this mark lets us find the end of the prompt, and thus
		# the beggining of the user input
		self.console.mark_set("end-of-prompt", "end-1c")
		self.console.mark_gravity("end-of-prompt", "left")

	def process_input(self,event):
		index = self.console.index("end-1c linestart")
		line = self.console.get(index,'end-1c')
		log.debug ("last line: %s" % line)
		if self.manual == True:
			self.console.insert("end", "\n")
			command = self.console.get("end-of-prompt", "end-1c")
			command = command.strip()
			if command != '':
				if command == 'bye' or command == 'exit':
					log.info ("quit from manual mode...")
					self.wf_manual.ssh.close()
					self.manual = False
					self.b5.config(state=NORMAL)
					self.b11.config(state=NORMAL)
					return
				elif command == 'help':
					log.info ("This is used for run command on target server by ssh, for example: >>> df -h, >>> svcs -xv")
				elif self.wf_manual.remote_cmd(command) == 1:
					log.error ("command %s execute failed" % command)
			self.insert_prompt()
			self.console.see("end")
			# this prevents the class binding from firing, since we 
			# inserted the newline in this method
			return "break"
		else:
			if line == 'Yes' or line == 'y' or line == 'yes': 
				self.set_confirm_yes()
			elif line == 'No' or line == 'n' or line == 'no':
				self.set_confirm_no()
			elif line == 'Skip' or line == 's' or line == 'skip':
				self.set_confirm_skip()
			else:
				pass
Example #10
0
class TermWindow(Frame):
    ##
    # constructor method
    def __init__(self, master = None, **cnf):
        apply(Frame.__init__, (self, master), cnf)
        self.__create_widgets__()
        self.rxThread = None
        self.rxWaitEvent = threading.Event()
        self.rxWaitPattern = ""
        self.localEcho = False
        self.logFile = None
        self.textQueue = Queue.Queue()
        self.update_thread_safe()

    def update_thread_safe(self):
        try:
            while 1:
                element = self.textQueue.get_nowait()
                if element is not None:
                    msg,tag = element
                    self.__display__(msg,tag)
                self.st_trm.update_idletasks()
        except Queue.Empty:
            pass
        self.st_trm.after(100, self.update_thread_safe)

    ##
    # worker function for threaded reading from the input of
    # the assigned device
    #
    def __thrd_reader__(self):
        self.waitbuf = ""
        while 1:
            try:
                x = self.device.read()
                if len(x):
                    cmd = self.cmdVar.get()
                    if len(cmd):
                        self.cmdVar.set("")
                    self.write(x)
                    if self.rxWaitEvent.isSet():
                        self.waitbuf += x
                        if self.waitbuf.find(self.rxWaitPattern) > -1:
                            self.rxWaitEvent.clear()
                            while not self.rxWaitEvent.isSet():
                                pass
                            self.rxWaitEvent.clear()
            except:
                traceback.print_exc()
                time.sleep(1)
            else:
                # this infinitesimal sleep keeps the GUI update alive
                time.sleep(.01)

    def waitfor(self, pattern, maxwait=10):
        self.waitbuf = ""
        self.rxWaitPattern = pattern
        self.rxWaitEvent.set()
        self.maxwait = 10
        while self.rxWaitEvent.isSet() and self.maxwait > 0:
            time.sleep(1)
            self.maxwait -= 1
        if self.maxwait == 0:
            self.message("PatternNotFound")
        self.rxWaitEvent.set()

    ##
    #
    def __create_widgets__(self):
        dfl_font = 'Courier 10'

        # the title frame of the terminal
        self.f_title = Frame(self)
        self.f_title.pack(fill=BOTH)
        self.f_title.configure(FRAMEBORDER)
        self.shVar = StringVar()
        # show/hide button
        self.b_sh = Button(self.f_title, textvariable=self.shVar, font=dfl_font)
        self.b_sh.pack(side=RIGHT)
        self.b_sh['command'] = self.show_hide_cont
        # clear screen button
        self.b_cls = Button(self.f_title, text="CLS", font=dfl_font, underline=0)
        self.b_cls.pack(side=RIGHT)
        self.b_cls['command'] = self.clear_screen
        # echo on/off button
        self.al_echo = Label(self.f_title, text = "ECHO", relief = RAISED,
                             font = dfl_font, padx='3m', pady='1m', underline=0)
        self.al_echo.pack(side=RIGHT, padx=1, pady=1, fill=BOTH)
        self.al_echo.bind("<Button-1>", self.__echo_handler__)
        # log on/off button
        self.al_log = Label(self.f_title, text = "LOG", relief = RAISED,
                            font = dfl_font, padx='3m', pady='1m', underline=0)
        self.al_log.pack(side=RIGHT, padx=1, pady=1, fill=BOTH)
        self.al_log.bind("<Button-1>", self.__log_handler__)
        # device connect button
        self.al_connect = Label(self.f_title, text = "CONNECT", relief = RAISED,
                                font = dfl_font, padx='3m', pady='1m', underline=1)
        self.al_connect.pack(side=RIGHT, padx=1, pady=1, fill=BOTH)
        self.al_connect.bind("<Button-1>", self.__connect_handler__)

        self.mb_macros = Menubutton(self.f_title, text = "Macros", relief=RAISED)
        self.mb_macros.pack(side=RIGHT, padx=1, pady=1, fill=BOTH)
        self.mb_macros.menu = Menu(self.mb_macros, tearoff = 0)
        self.mb_macros["menu"] = self.mb_macros.menu


        # title of terminal window
        self.tVar = StringVar()
        self.l_title = Label(self.f_title, text="foo", font=dfl_font)
        self.l_title['textvariable'] = self.tVar
        self.l_title.pack(side=LEFT, expand=1, fill=X)
        self.l_title['width'] = 42
        self.update_title("------ XXX ------")
        # frame for scrolled text window
        # (this frame handle needs to be kept fo show_hide_cont())
        self.f_cont = Frame(self)
        # IO data scrolled text window
        self.st_trm = ScrolledText(self.f_cont, height=10, state=DISABLED, wrap=NONE)
        self.st_trm.pack(expand=1,fill=BOTH)
        self.st_trm['font'] = dfl_font
        self.st_trm.tag_config('E', foreground="blue")
        self.st_trm.tag_config('M', foreground="magenta")


        tframe = Frame(self.f_cont)
        tframe.pack(expand = 0, fill = X)
        self.cmdVar = StringVar()
        self.ent_trm = Entry(tframe, textvariable=self.cmdVar, font=dfl_font)
        self.ent_trm.pack(side=LEFT, expand =1, fill = X)
        self.ent_trm.bind("<Control-l>", self.__log_handler__)
        self.ent_trm.bind("<Control-e>", self.__echo_handler__)
        self.ent_trm.bind("<Control-o>", self.__connect_handler__)
        self.ent_trm.bind("<Control-c>", self.clear_screen)
        self.ent_trm.bind("<Control-x>", self.show_hide_cont)
        self.ent_trm.bind("<Control-m>", lambda *args: self.do_macro("M"))
        self.ent_trm.bind("<KeyPress>", self.__input_handler__)

        self.gui_elements = [ self.b_sh,
                              self.b_cls,
                              self.al_echo,
                              self.al_log,
                              self.al_connect,
                              self.mb_macros,
                              self.l_title,
                              self.st_trm,
                              self.ent_trm]
        self.show_cont()

    def add_macro(self, id, title, text = None, function = None, params = None):
        if text:
            cmd = lambda *args: self.do_macro(text)
        if function:
            user_func = eval(function)
            params = eval(str(params))
            cmd = lambda *args: user_func(DEVICES, **params)
        mb = self.mb_macros.menu.add_command(label = title, command = cmd)

    def _configure_(self,**args):
        for e in self.gui_elements:
            e.configure(args)

    def __input_handler__(self, *args):
        for i in args:
            if self.localEcho:
                self.display(i.char, "E")
            if len(i.char):
                if i.char == "\r":
                    self.device.write("\r\n")
                    self.cmdVar.set("")
                else:
                    self.device.write(i.char)

    def __echo_handler__(self, *args):
        if self.localEcho:
            self.localEcho = False
            self.al_echo['relief'] = RAISED
            self.message("Local Echo OFF")
        else:
            self.localEcho = True
            self.al_echo['relief'] = SUNKEN
            self.message("Local Echo ON")

    def __log_handler__(self, *args):
        try:
            do_open = self.logFile.closed
            logname = self.logFile.name
        except:
            do_open = True
            logname = ""
        if do_open:
            if self.device.logname:
                logname = self.device.logname
                self.message("logfile from config file %s " % logname)
            else:
                fd = FileDialog(self)
                logname = fd.go(logname)
            try:
                if self.device.logmode not in "wa":
                    self.device.logmode = "a"
                    print "force _a_ppend"
                self.logFile = open(logname, self.device.logmode)
                self.al_log['relief'] = SUNKEN
                self.message("Logging ON: %s" % self.logFile.name)
            except:
                self.message("Error open logfile: %s" % logname)

        else:
            self.message("Logging OFF: %s" % self.logFile.name)
            self.logFile.flush()
            self.logFile.close()
            self.al_log['relief'] = RAISED

    def __connect_handler__(self, *args):
        if self.device.isConnected:
            self.device.disconnect()
            self.al_connect['relief'] = RAISED
            self.message("Disconnected")
        else:
            try:
                self.device.connect()
                self.al_connect['relief'] = SUNKEN
                self.message("Connected")
                self.al_connect['fg'] = "black"
            except:
                self.device.isConnected = False
                self.message( str(sys.exc_info()[1]) )
                self.al_connect['fg'] = "red"

    def clear_screen(self, *args):
        self.st_trm['state'] = NORMAL
        self.st_trm.delete("0.0",END)
        self.st_trm['state'] = DISABLED

    def set_device(self,device):
        self.device = device
        self.rxThread = threading.Thread(target = self.__thrd_reader__)
        # if a thread is not a daemon, the program needs to join all
        self.rxThread.setDaemon(1)
        print "**",self.device, self.device.name
        self.rxThread.setName("GUI_RX_%s" % self.device.name)
        self.rxThread.start()
        self.update_title(self.device)
        #
        if self.device.echo:
            self.localEcho = 0
            self.__echo_handler__()
        if self.device.log:
            self.__log_handler__()
        if self.device.auto_connect:
            self.__connect_handler__()

    def update_title(self, title):
        self.tVar.set(title)

    def show_cont(self):
        self.shVar.set("X")
        self.f_cont.pack(expand=1,fill=BOTH)

    def hide_cont(self):
        self.shVar.set("+")
        self.f_cont.pack_forget()

    def show_hide_cont(self, *args):
        if self.shVar.get() == "X":
            self.hide_cont()
        else:
            self.show_cont()

    def do_macro(self, *args):
        if self.localEcho:
            self.display(args[0] + "\n", "E")
        self.device.write(args[0]+ "\n")

    def write(self, data):
        self.textQueue.put((data, None))

    def message(self, text, tag='M'):
        msg = "[%s:%s:%s]\n" % (time.asctime(),self.device.name, text)
        if self.st_trm.index(AtInsert()).find(".0")  < 1:
            msg = "\n" + msg
        self.textQueue.put((msg, tag))

    def display(self, text, tag = None):
        self.textQueue.put((text, tag))

    def __display__(self, msg, tag = None):
        self.st_trm['state'] = NORMAL
        here =  self.st_trm.index(AtInsert())
        for d in re.split("([\r\v\t\n])", msg):
            if len(d):
                if d != '\r':
                    self.st_trm.insert(END, d)
        if tag:
            self.st_trm.tag_add(tag, here, AtInsert())
        self.st_trm.see(END)
        self.st_trm['state'] = DISABLED
        try:
            self.logFile.write(msg)
            self.logFile.flush()
        except:
            pass