Esempio n. 1
0
    def __init__(self, parent, title=None, content=""):
        Toplevel.__init__(self, parent)
        self.transient(parent)
        self.log = logging.getLogger(__name__)

        if title:
            self.title(title)

        self.parent = parent
        self.body = Frame(self)
        self.fill_body(content)
        self.body.pack(padx=5, pady=5)

        self.create_buttonbox()

        self.grab_set()

        self.protocol("WM_DELETE_WINDOW", self.ok)

        self.geometry("+%d+%d" %
                      (parent.winfo_rootx() + 50, parent.winfo_rooty() + 50))

        self.focus_set()

        self.wait_window(self)
 def __init__(self, message, value=None, **extra):
     self._prevent_execution_with_timeouts()
     self._parent = self._get_parent()
     Toplevel.__init__(self, self._parent)
     self._initialize_dialog()
     self._create_body(message, value, **extra)
     self._create_buttons()
     self._result = None
Esempio n. 3
0
 def __init__(self, message, value=None, **extra):
     self._prevent_execution_with_timeouts()
     self._parent = self._get_parent()
     Toplevel.__init__(self, self._parent)
     self._initialize_dialog()
     self._create_body(message, value, **extra)
     self._create_buttons()
     self._result = None
Esempio n. 4
0
    def __init__(self, sms):
        Toplevel.__init__(self)

        self._sms = sms

        self.title("SMS from %s" % sms["address"])

        v = SMSView(sms, self)
        v.pack(fill=BOTH, expand=True)
Esempio n. 5
0
    def __init__(self, parent, cfg=None, set_cfg_callback=None):
        self._parent = parent
        if cfg is not None: self._cfg = cfg
        else: self._cfg = CFG(Nonterminal('S'), [])
        self._set_cfg_callback = set_cfg_callback

        self._highlight_matching_nonterminals = 1

        # Create the top-level window.
        self._top = Toplevel(parent)
        self._init_bindings()

        self._init_startframe()
        self._startframe.pack(side='top', fill='x', expand=0)
        self._init_prodframe()
        self._prodframe.pack(side='top', fill='both', expand=1)
        self._init_buttons()
        self._buttonframe.pack(side='bottom', fill='x', expand=0)

        self._textwidget.focus()
Esempio n. 6
0
    def title(self, value = None):
        if value is None:
            return self.var or Toplevel.title(self)

        if not isinstance(value, variables): # anything else, e.g. `str`
            if self.var:
                self.var.set(value)
            else:
                Toplevel.title(self, value)
            return

        if value is self.var:
            return

        if self.var is not None:
            self.var.trace_vdelete("w", self.observer_name)
        self.var = value
        self.observer_name = value.trace_variable(
            "w",
            self.on_var_changed
        )

        self.on_var_changed()
Esempio n. 7
0
    def __create_content(self):
        self.__rootFrame = TKTk()
        self.__rootFrame.withdraw()

        self.__top = TKToplevel(self.__rootFrame)
        self.__top.title("Login")
        self.__top.protocol("WM_DELETE_WINDOW", self.__rootFrame.destroy)

        self.__top.bind('<Return>', self.__enter_action)

        self.__top.update_idletasks()
        width = self.__top.winfo_width()
        height = self.__top.winfo_height()
        x = (self.__top.winfo_screenwidth() // 2) - (width // 2)
        y = (self.__top.winfo_screenheight() // 2) - (height // 2)

        self.__top.geometry("+%d+%d" % (x, y))

        row = 0
        expLabel = TKLabel(self.__top, text='Login to host:')
        expLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2)

        row = row + 1
        urlLabel = TKLabel(self.__top, text=self.__host)
        urlLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2)

        row = row + 1
        usrLabel = TKLabel(self.__top, text='User')
        usrLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5)
        self.__usrEntry = TKEntry(self.__top, width=20)
        self.__usrEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5)

        row = row + 1
        pwdLabel = TKLabel(self.__top, text='Password')
        pwdLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5)
        self.__pwdEntry = TKEntry(self.__top, width=20, show="*")
        self.__pwdEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5)

        row = row + 1
        cancelButton = TKButton(self.__top,
                                text='Cancel',
                                command=self.__cancel_action)
        cancelButton.grid(row=row, column=1, padx=5, pady=5)
        loginButton = TKButton(self.__top,
                               text='Login',
                               command=self.__login_action)
        loginButton.grid(row=row, column=2, padx=5, pady=5)
Esempio n. 8
0
    def __create_content(self):
        self.__rootFrame = TKTk()
        self.__rootFrame.withdraw()

        self.__top = TKToplevel(self.__rootFrame)
        self.__top.title("Login")
        self.__top.protocol("WM_DELETE_WINDOW", self.__rootFrame.destroy)

        self.__top.bind('<Return>', self.__enter_action)

        self.__top.update_idletasks()
        width = self.__top.winfo_width()
        height = self.__top.winfo_height()
        x = (self.__top.winfo_screenwidth() // 2) - (width // 2)
        y = (self.__top.winfo_screenheight() // 2) - (height // 2)

        self.__top.geometry("+%d+%d" % (x, y))

        row = 0
        expLabel = TKLabel(self.__top, text='Login to host:')
        expLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2)

        row = row+1
        urlLabel = TKLabel(self.__top, text=self.__host)
        urlLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2)

        row = row+1
        usrLabel = TKLabel(self.__top, text='User')
        usrLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5)
        self.__usrEntry = TKEntry(self.__top, width=20)
        self.__usrEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5)

        row = row+1
        pwdLabel = TKLabel(self.__top, text='Password')
        pwdLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5)
        self.__pwdEntry = TKEntry(self.__top, width=20, show="*")
        self.__pwdEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5)

        row = row+1
        cancelButton = TKButton(self.__top, text='Cancel', command=self.__cancel_action)
        cancelButton.grid(row=row, column=1, padx=5, pady=5)
        loginButton = TKButton(self.__top, text='Login', command=self.__login_action)
        loginButton.grid(row=row, column=2, padx=5, pady=5)
Esempio n. 9
0
    def __init__(self, parent, cfg=None, set_cfg_callback=None):
        self._parent = parent
        if cfg is not None: self._cfg = cfg
        else: self._cfg = CFG(Nonterminal('S'), [])
        self._set_cfg_callback = set_cfg_callback

        self._highlight_matching_nonterminals = 1

        # Create the top-level window.
        self._top = Toplevel(parent)
        self._init_bindings()

        self._init_startframe()
        self._startframe.pack(side='top', fill='x', expand=0)
        self._init_prodframe()
        self._prodframe.pack(side='top', fill='both', expand=1)
        self._init_buttons()
        self._buttonframe.pack(side='bottom', fill='x', expand=0)

        self._textwidget.focus()
Esempio n. 10
0
class TkWindowNode(BaseWindowNode):
    '''The base class of all the Window Node in the WaveSyn Object Model.
Properties:
    tk_object: The underlying Tk Toplevel object;
    node_path: The path of this node on the WaveSyn Object Model Tree.
Properties inherited from ModelNode:
    root_node: The root node of the WaveSyn Object Model Tree.
'''
    window_name = ''

    _xmlrpcexport_  = ['close']    
    
    def __init__(self, *args, **kwargs):
        super(TkWindowNode, self).__init__(*args, **kwargs)
        self.__tk_object = Toplevel()
        self.__tk_object.title(eval_format('{self.window_name} id={id(self)}'))        
        self.__tk_object.protocol('WM_DELETE_WINDOW', self.on_close)
                
    method_name_map   = {
        'update':'update', 
        'set_window_attributes':'wm_attributes'
    }
    
    for method_name in method_name_map:
        locals()[method_name] = MethodDelegator('tk_object', 
                                                method_name_map[method_name])        
        
    @Scripting.printable
    def close(self):
        Scripting.root_node.on_window_quit(self)
        # For Toplevel objects, use destroy rather than quit.
        self.__tk_object.destroy() 
        
    def on_close(self):
        with code_printer:
            self.close()
        
    @property
    def node_path(self):
        if isinstance(self.parent_node, WindowDict):
            return eval_format('{self.parent_node.node_path}[{id(self)}]')
        else:
            return ModelNode.node_path.__get__(self)
            
    @property
    def tk_object(self):
        return self.__tk_object
Esempio n. 11
0
class LoginDialog(object):

    def __init__(self, host):
        self.__interna_init()
        self.__host = host
        self.__create_content()

    def __interna_init(self):
        self.__rootFrame = None
        self.__top = None
        self.__usrEntry = None
        self.__pwdEntry = None
        self.__accepted = False
        self.__host = None
        self.__usr = None
        self.__pwd = None

    def __cancel_action(self):
        self.__accepted = False
        self.__rootFrame.destroy()

    def __login_action(self):
        self.__accepted = True
        self.__usr = self.__usrEntry.get()
        self.__pwd = self.__pwdEntry.get()
        self.__rootFrame.destroy()

    def __enter_action(self, event):
        self.__login_action()

    def __create_content(self):
        self.__rootFrame = TKTk()
        self.__rootFrame.withdraw()

        self.__top = TKToplevel(self.__rootFrame)
        self.__top.title("Login")
        self.__top.protocol("WM_DELETE_WINDOW", self.__rootFrame.destroy)

        self.__top.bind('<Return>', self.__enter_action)

        self.__top.update_idletasks()
        width = self.__top.winfo_width()
        height = self.__top.winfo_height()
        x = (self.__top.winfo_screenwidth() // 2) - (width // 2)
        y = (self.__top.winfo_screenheight() // 2) - (height // 2)

        self.__top.geometry("+%d+%d" % (x, y))

        row = 0
        expLabel = TKLabel(self.__top, text='Login to host:')
        expLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2)

        row = row+1
        urlLabel = TKLabel(self.__top, text=self.__host)
        urlLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2)

        row = row+1
        usrLabel = TKLabel(self.__top, text='User')
        usrLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5)
        self.__usrEntry = TKEntry(self.__top, width=20)
        self.__usrEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5)

        row = row+1
        pwdLabel = TKLabel(self.__top, text='Password')
        pwdLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5)
        self.__pwdEntry = TKEntry(self.__top, width=20, show="*")
        self.__pwdEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5)

        row = row+1
        cancelButton = TKButton(self.__top, text='Cancel', command=self.__cancel_action)
        cancelButton.grid(row=row, column=1, padx=5, pady=5)
        loginButton = TKButton(self.__top, text='Login', command=self.__login_action)
        loginButton.grid(row=row, column=2, padx=5, pady=5)

    def show_login(self):
        self.__usrEntry.focus_set()
        self.__rootFrame.mainloop()

    def is_accepted(self):
        return self.__accepted

    def get_user(self):
        return self.__usr

    def get_password(self):
        return self.__pwd
Esempio n. 12
0
class CFGEditor(object):
    """
    A dialog window for creating and editing context free grammars.
    ``CFGEditor`` imposes the following restrictions:

    - All nonterminals must be strings consisting of word
      characters.
    - All terminals must be strings consisting of word characters
      and space characters.
    """
    # Regular expressions used by _analyze_line.  Precompile them, so
    # we can process the text faster.
    ARROW = SymbolWidget.SYMBOLS['rightarrow']
    _LHS_RE = re.compile(r"(^\s*\w+\s*)(->|("+ARROW+"))")
    _ARROW_RE = re.compile("\s*(->|("+ARROW+"))\s*")
    _PRODUCTION_RE = re.compile(r"(^\s*\w+\s*)" +              # LHS
                                "(->|("+ARROW+"))\s*" +        # arrow
                                r"((\w+|'[\w ]*'|\"[\w ]*\"|\|)\s*)*$") # RHS
    _TOKEN_RE = re.compile("\\w+|->|'[\\w ]+'|\"[\\w ]+\"|("+ARROW+")")
    _BOLD = ('helvetica', -12, 'bold')

    def __init__(self, parent, cfg=None, set_cfg_callback=None):
        self._parent = parent
        if cfg is not None: self._cfg = cfg
        else: self._cfg = CFG(Nonterminal('S'), [])
        self._set_cfg_callback = set_cfg_callback

        self._highlight_matching_nonterminals = 1

        # Create the top-level window.
        self._top = Toplevel(parent)
        self._init_bindings()

        self._init_startframe()
        self._startframe.pack(side='top', fill='x', expand=0)
        self._init_prodframe()
        self._prodframe.pack(side='top', fill='both', expand=1)
        self._init_buttons()
        self._buttonframe.pack(side='bottom', fill='x', expand=0)

        self._textwidget.focus()

    def _init_startframe(self):
        frame = self._startframe = Frame(self._top)
        self._start = Entry(frame)
        self._start.pack(side='right')
        Label(frame, text='Start Symbol:').pack(side='right')
        Label(frame, text='Productions:').pack(side='left')
        self._start.insert(0, self._cfg.start().symbol())

    def _init_buttons(self):
        frame = self._buttonframe = Frame(self._top)
        Button(frame, text='Ok', command=self._ok,
               underline=0, takefocus=0).pack(side='left')
        Button(frame, text='Apply', command=self._apply,
               underline=0, takefocus=0).pack(side='left')
        Button(frame, text='Reset', command=self._reset,
               underline=0, takefocus=0,).pack(side='left')
        Button(frame, text='Cancel', command=self._cancel,
               underline=0, takefocus=0).pack(side='left')
        Button(frame, text='Help', command=self._help,
               underline=0, takefocus=0).pack(side='right')

    def _init_bindings(self):
        self._top.title('CFG Editor')
        self._top.bind('<Control-q>', self._cancel)
        self._top.bind('<Alt-q>', self._cancel)
        self._top.bind('<Control-d>', self._cancel)
        #self._top.bind('<Control-x>', self._cancel)
        self._top.bind('<Alt-x>', self._cancel)
        self._top.bind('<Escape>', self._cancel)
        #self._top.bind('<Control-c>', self._cancel)
        self._top.bind('<Alt-c>', self._cancel)

        self._top.bind('<Control-o>', self._ok)
        self._top.bind('<Alt-o>', self._ok)
        self._top.bind('<Control-a>', self._apply)
        self._top.bind('<Alt-a>', self._apply)
        self._top.bind('<Control-r>', self._reset)
        self._top.bind('<Alt-r>', self._reset)
        self._top.bind('<Control-h>', self._help)
        self._top.bind('<Alt-h>', self._help)
        self._top.bind('<F1>', self._help)

    def _init_prodframe(self):
        self._prodframe = Frame(self._top)

        # Create the basic Text widget & scrollbar.
        self._textwidget = Text(self._prodframe, background='#e0e0e0',
                                exportselection=1)
        self._textscroll = Scrollbar(self._prodframe, takefocus=0,
                                     orient='vertical')
        self._textwidget.config(yscrollcommand = self._textscroll.set)
        self._textscroll.config(command=self._textwidget.yview)
        self._textscroll.pack(side='right', fill='y')
        self._textwidget.pack(expand=1, fill='both', side='left')

        # Initialize the colorization tags.  Each nonterminal gets its
        # own tag, so they aren't listed here.
        self._textwidget.tag_config('terminal', foreground='#006000')
        self._textwidget.tag_config('arrow', font='symbol')
        self._textwidget.tag_config('error', background='red')

        # Keep track of what line they're on.  We use that to remember
        # to re-analyze a line whenever they leave it.
        self._linenum = 0

        # Expand "->" to an arrow.
        self._top.bind('>', self._replace_arrows)

        # Re-colorize lines when appropriate.
        self._top.bind('<<Paste>>', self._analyze)
        self._top.bind('<KeyPress>', self._check_analyze)
        self._top.bind('<ButtonPress>', self._check_analyze)

        # Tab cycles focus. (why doesn't this work??)
        def cycle(e, textwidget=self._textwidget):
            textwidget.tk_focusNext().focus()
        self._textwidget.bind('<Tab>', cycle)

        prod_tuples = [(p.lhs(),[p.rhs()]) for p in self._cfg.productions()]
        for i in range(len(prod_tuples)-1,0,-1):
            if (prod_tuples[i][0] == prod_tuples[i-1][0]):
                if () in prod_tuples[i][1]: continue
                if () in prod_tuples[i-1][1]: continue
                print(prod_tuples[i-1][1])
                print(prod_tuples[i][1])
                prod_tuples[i-1][1].extend(prod_tuples[i][1])
                del prod_tuples[i]

        for lhs, rhss in prod_tuples:
            print(lhs, rhss)
            s = '%s ->' % lhs
            for rhs in rhss:
                for elt in rhs:
                    if isinstance(elt, Nonterminal): s += ' %s' % elt
                    else: s += ' %r' % elt
                s += ' |'
            s = s[:-2] + '\n'
            self._textwidget.insert('end', s)

        self._analyze()

#         # Add the producitons to the text widget, and colorize them.
#         prod_by_lhs = {}
#         for prod in self._cfg.productions():
#             if len(prod.rhs()) > 0:
#                 prod_by_lhs.setdefault(prod.lhs(),[]).append(prod)
#         for (lhs, prods) in prod_by_lhs.items():
#             self._textwidget.insert('end', '%s ->' % lhs)
#             self._textwidget.insert('end', self._rhs(prods[0]))
#             for prod in prods[1:]:
#                 print '\t|'+self._rhs(prod),
#                 self._textwidget.insert('end', '\t|'+self._rhs(prod))
#             print
#             self._textwidget.insert('end', '\n')
#         for prod in self._cfg.productions():
#             if len(prod.rhs()) == 0:
#                 self._textwidget.insert('end', '%s' % prod)
#         self._analyze()

#     def _rhs(self, prod):
#         s = ''
#         for elt in prod.rhs():
#             if isinstance(elt, Nonterminal): s += ' %s' % elt.symbol()
#             else: s += ' %r' % elt
#         return s

    def _clear_tags(self, linenum):
        """
        Remove all tags (except ``arrow`` and ``sel``) from the given
        line of the text widget used for editing the productions.
        """
        start = '%d.0'%linenum
        end = '%d.end'%linenum
        for tag in self._textwidget.tag_names():
            if tag not in ('arrow', 'sel'):
                self._textwidget.tag_remove(tag, start, end)

    def _check_analyze(self, *e):
        """
        Check if we've moved to a new line.  If we have, then remove
        all colorization from the line we moved to, and re-colorize
        the line that we moved from.
        """
        linenum = int(self._textwidget.index('insert').split('.')[0])
        if linenum != self._linenum:
            self._clear_tags(linenum)
            self._analyze_line(self._linenum)
            self._linenum = linenum

    def _replace_arrows(self, *e):
        """
        Replace any ``'->'`` text strings with arrows (char \\256, in
        symbol font).  This searches the whole buffer, but is fast
        enough to be done anytime they press '>'.
        """
        arrow = '1.0'
        while True:
            arrow = self._textwidget.search('->', arrow, 'end+1char')
            if arrow == '': break
            self._textwidget.delete(arrow, arrow+'+2char')
            self._textwidget.insert(arrow, self.ARROW, 'arrow')
            self._textwidget.insert(arrow, '\t')

        arrow = '1.0'
        while True:
            arrow = self._textwidget.search(self.ARROW, arrow+'+1char',
                                            'end+1char')
            if arrow == '': break
            self._textwidget.tag_add('arrow', arrow, arrow+'+1char')

    def _analyze_token(self, match, linenum):
        """
        Given a line number and a regexp match for a token on that
        line, colorize the token.  Note that the regexp match gives us
        the token's text, start index (on the line), and end index (on
        the line).
        """
        # What type of token is it?
        if match.group()[0] in "'\"": tag = 'terminal'
        elif match.group() in ('->', self.ARROW): tag = 'arrow'
        else:
            # If it's a nonterminal, then set up new bindings, so we
            # can highlight all instances of that nonterminal when we
            # put the mouse over it.
            tag = 'nonterminal_'+match.group()
            if tag not in self._textwidget.tag_names():
                self._init_nonterminal_tag(tag)

        start = '%d.%d' % (linenum, match.start())
        end = '%d.%d' % (linenum, match.end())
        self._textwidget.tag_add(tag, start, end)

    def _init_nonterminal_tag(self, tag, foreground='blue'):
        self._textwidget.tag_config(tag, foreground=foreground,
                                    font=CFGEditor._BOLD)
        if not self._highlight_matching_nonterminals:
            return
        def enter(e, textwidget=self._textwidget, tag=tag):
            textwidget.tag_config(tag, background='#80ff80')
        def leave(e, textwidget=self._textwidget, tag=tag):
            textwidget.tag_config(tag, background='')
        self._textwidget.tag_bind(tag, '<Enter>', enter)
        self._textwidget.tag_bind(tag, '<Leave>', leave)

    def _analyze_line(self, linenum):
        """
        Colorize a given line.
        """
        # Get rid of any tags that were previously on the line.
        self._clear_tags(linenum)

        # Get the line line's text string.
        line = self._textwidget.get(repr(linenum)+'.0', repr(linenum)+'.end')

        # If it's a valid production, then colorize each token.
        if CFGEditor._PRODUCTION_RE.match(line):
            # It's valid; Use _TOKEN_RE to tokenize the production,
            # and call analyze_token on each token.
            def analyze_token(match, self=self, linenum=linenum):
                self._analyze_token(match, linenum)
                return ''
            CFGEditor._TOKEN_RE.sub(analyze_token, line)
        elif line.strip() != '':
            # It's invalid; show the user where the error is.
            self._mark_error(linenum, line)

    def _mark_error(self, linenum, line):
        """
        Mark the location of an error in a line.
        """
        arrowmatch = CFGEditor._ARROW_RE.search(line)
        if not arrowmatch:
            # If there's no arrow at all, highlight the whole line.
            start = '%d.0' % linenum
            end = '%d.end' % linenum
        elif not CFGEditor._LHS_RE.match(line):
            # Otherwise, if the LHS is bad, highlight it.
            start = '%d.0' % linenum
            end = '%d.%d' % (linenum, arrowmatch.start())
        else:
            # Otherwise, highlight the RHS.
            start = '%d.%d' % (linenum, arrowmatch.end())
            end = '%d.end' % linenum

        # If we're highlighting 0 chars, highlight the whole line.
        if self._textwidget.compare(start, '==', end):
            start = '%d.0' % linenum
            end = '%d.end' % linenum
        self._textwidget.tag_add('error', start, end)

    def _analyze(self, *e):
        """
        Replace ``->`` with arrows, and colorize the entire buffer.
        """
        self._replace_arrows()
        numlines = int(self._textwidget.index('end').split('.')[0])
        for linenum in range(1, numlines+1):  # line numbers start at 1.
            self._analyze_line(linenum)

    def _parse_productions(self):
        """
        Parse the current contents of the textwidget buffer, to create
        a list of productions.
        """
        productions = []

        # Get the text, normalize it, and split it into lines.
        text = self._textwidget.get('1.0', 'end')
        text = re.sub(self.ARROW, '->', text)
        text = re.sub('\t', ' ', text)
        lines = text.split('\n')

        # Convert each line to a CFG production
        for line in lines:
            line = line.strip()
            if line=='': continue
            productions += _read_cfg_production(line)
            #if line.strip() == '': continue
            #if not CFGEditor._PRODUCTION_RE.match(line):
            #    raise ValueError('Bad production string %r' % line)
            #
            #(lhs_str, rhs_str) = line.split('->')
            #lhs = Nonterminal(lhs_str.strip())
            #rhs = []
            #def parse_token(match, rhs=rhs):
            #    token = match.group()
            #    if token[0] in "'\"": rhs.append(token[1:-1])
            #    else: rhs.append(Nonterminal(token))
            #    return ''
            #CFGEditor._TOKEN_RE.sub(parse_token, rhs_str)
            #
            #productions.append(Production(lhs, *rhs))

        return productions

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

    def _ok(self, *e):
        self._apply()
        self._destroy()

    def _apply(self, *e):
        productions = self._parse_productions()
        start = Nonterminal(self._start.get())
        cfg = CFG(start, productions)
        if self._set_cfg_callback is not None:
            self._set_cfg_callback(cfg)

    def _reset(self, *e):
        self._textwidget.delete('1.0', 'end')
        for production in self._cfg.productions():
            self._textwidget.insert('end', '%s\n' % production)
        self._analyze()
        if self._set_cfg_callback is not None:
            self._set_cfg_callback(self._cfg)

    def _cancel(self, *e):
        try: self._reset()
        except: pass
        self._destroy()

    def _help(self, *e):
        # The default font's not very legible; try using 'fixed' instead.
        try:
            ShowText(self._parent, 'Help: Chart Parser Demo',
                     (_CFGEditor_HELP).strip(), width=75, font='fixed')
        except:
            ShowText(self._parent, 'Help: Chart Parser Demo',
                     (_CFGEditor_HELP).strip(), width=75)
Esempio n. 13
0
 def __init__(self, *args, **kw):
     self.var = None
     Toplevel.__init__(self, *args, **kw)
Esempio n. 14
0
class LoginDialog(object):
    def __init__(self, host):
        self.__interna_init()
        self.__host = host
        self.__initialized = False
        if TKTk is not None:
            self.__create_content()
            self.__initialized = True

    def __interna_init(self):
        self.__rootFrame = None
        self.__top = None
        self.__usrEntry = None
        self.__pwdEntry = None
        self.__accepted = False
        self.__host = None
        self.__usr = None
        self.__pwd = None

    def __cancel_action(self):
        self.__accepted = False
        self.__rootFrame.destroy()

    def __login_action(self):
        self.__accepted = True
        self.__usr = self.__usrEntry.get()
        self.__pwd = self.__pwdEntry.get()
        self.__rootFrame.destroy()

    def __enter_action(self, event):
        self.__login_action()

    def __create_content(self):
        self.__rootFrame = TKTk()
        self.__rootFrame.withdraw()

        self.__top = TKToplevel(self.__rootFrame)
        self.__top.title("Login")
        self.__top.protocol("WM_DELETE_WINDOW", self.__rootFrame.destroy)

        self.__top.bind('<Return>', self.__enter_action)

        self.__top.update_idletasks()
        width = self.__top.winfo_width()
        height = self.__top.winfo_height()
        x = (self.__top.winfo_screenwidth() // 2) - (width // 2)
        y = (self.__top.winfo_screenheight() // 2) - (height // 2)

        self.__top.geometry("+%d+%d" % (x, y))

        row = 0
        expLabel = TKLabel(self.__top, text='Login to host:')
        expLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2)

        row = row + 1
        urlLabel = TKLabel(self.__top, text=self.__host)
        urlLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2)

        row = row + 1
        usrLabel = TKLabel(self.__top, text='User')
        usrLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5)
        self.__usrEntry = TKEntry(self.__top, width=20)
        self.__usrEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5)

        row = row + 1
        pwdLabel = TKLabel(self.__top, text='Password')
        pwdLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5)
        self.__pwdEntry = TKEntry(self.__top, width=20, show="*")
        self.__pwdEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5)

        row = row + 1
        cancelButton = TKButton(self.__top,
                                text='Cancel',
                                command=self.__cancel_action)
        cancelButton.grid(row=row, column=1, padx=5, pady=5)
        loginButton = TKButton(self.__top,
                               text='Login',
                               command=self.__login_action)
        loginButton.grid(row=row, column=2, padx=5, pady=5)

    def show_login(self):
        if self.__initialized:
            self.__usrEntry.focus_set()
            self.__rootFrame.mainloop()
        else:
            print("tkinter python module is not available.\n\
            Please, install tkinter module or use command line login utility.")

    def is_accepted(self):
        return self.__accepted

    def get_user(self):
        return self.__usr

    def get_password(self):
        return self.__pwd
Esempio n. 15
0
 def on_var_changed(self, *_):
     Toplevel.title(self, self.var.get())
Esempio n. 16
0
class CFGEditor(object):
    """
    A dialog window for creating and editing context free grammars.
    ``CFGEditor`` imposes the following restrictions:

    - All nonterminals must be strings consisting of word
      characters.
    - All terminals must be strings consisting of word characters
      and space characters.
    """

    # Regular expressions used by _analyze_line.  Precompile them, so
    # we can process the text faster.
    ARROW = SymbolWidget.SYMBOLS['rightarrow']
    _LHS_RE = re.compile(r"(^\s*\w+\s*)(->|(" + ARROW + "))")
    _ARROW_RE = re.compile("\s*(->|(" + ARROW + "))\s*")
    _PRODUCTION_RE = re.compile(
        r"(^\s*\w+\s*)"
        + "(->|("  # LHS
        + ARROW
        + "))\s*"
        + r"((\w+|'[\w ]*'|\"[\w ]*\"|\|)\s*)*$"  # arrow
    )  # RHS
    _TOKEN_RE = re.compile("\\w+|->|'[\\w ]+'|\"[\\w ]+\"|(" + ARROW + ")")
    _BOLD = ('helvetica', -12, 'bold')

    def __init__(self, parent, cfg=None, set_cfg_callback=None):
        self._parent = parent
        if cfg is not None:
            self._cfg = cfg
        else:
            self._cfg = CFG(Nonterminal('S'), [])
        self._set_cfg_callback = set_cfg_callback

        self._highlight_matching_nonterminals = 1

        # Create the top-level window.
        self._top = Toplevel(parent)
        self._init_bindings()

        self._init_startframe()
        self._startframe.pack(side='top', fill='x', expand=0)
        self._init_prodframe()
        self._prodframe.pack(side='top', fill='both', expand=1)
        self._init_buttons()
        self._buttonframe.pack(side='bottom', fill='x', expand=0)

        self._textwidget.focus()

    def _init_startframe(self):
        frame = self._startframe = Frame(self._top)
        self._start = Entry(frame)
        self._start.pack(side='right')
        Label(frame, text='Start Symbol:').pack(side='right')
        Label(frame, text='Productions:').pack(side='left')
        self._start.insert(0, self._cfg.start().symbol())

    def _init_buttons(self):
        frame = self._buttonframe = Frame(self._top)
        Button(frame, text='Ok', command=self._ok, underline=0, takefocus=0).pack(
            side='left'
        )
        Button(frame, text='Apply', command=self._apply, underline=0, takefocus=0).pack(
            side='left'
        )
        Button(frame, text='Reset', command=self._reset, underline=0, takefocus=0).pack(
            side='left'
        )
        Button(
            frame, text='Cancel', command=self._cancel, underline=0, takefocus=0
        ).pack(side='left')
        Button(frame, text='Help', command=self._help, underline=0, takefocus=0).pack(
            side='right'
        )

    def _init_bindings(self):
        self._top.title('CFG Editor')
        self._top.bind('<Control-q>', self._cancel)
        self._top.bind('<Alt-q>', self._cancel)
        self._top.bind('<Control-d>', self._cancel)
        # self._top.bind('<Control-x>', self._cancel)
        self._top.bind('<Alt-x>', self._cancel)
        self._top.bind('<Escape>', self._cancel)
        # self._top.bind('<Control-c>', self._cancel)
        self._top.bind('<Alt-c>', self._cancel)

        self._top.bind('<Control-o>', self._ok)
        self._top.bind('<Alt-o>', self._ok)
        self._top.bind('<Control-a>', self._apply)
        self._top.bind('<Alt-a>', self._apply)
        self._top.bind('<Control-r>', self._reset)
        self._top.bind('<Alt-r>', self._reset)
        self._top.bind('<Control-h>', self._help)
        self._top.bind('<Alt-h>', self._help)
        self._top.bind('<F1>', self._help)

    def _init_prodframe(self):
        self._prodframe = Frame(self._top)

        # Create the basic Text widget & scrollbar.
        self._textwidget = Text(
            self._prodframe, background='#e0e0e0', exportselection=1
        )
        self._textscroll = Scrollbar(self._prodframe, takefocus=0, orient='vertical')
        self._textwidget.config(yscrollcommand=self._textscroll.set)
        self._textscroll.config(command=self._textwidget.yview)
        self._textscroll.pack(side='right', fill='y')
        self._textwidget.pack(expand=1, fill='both', side='left')

        # Initialize the colorization tags.  Each nonterminal gets its
        # own tag, so they aren't listed here.
        self._textwidget.tag_config('terminal', foreground='#006000')
        self._textwidget.tag_config('arrow', font='symbol')
        self._textwidget.tag_config('error', background='red')

        # Keep track of what line they're on.  We use that to remember
        # to re-analyze a line whenever they leave it.
        self._linenum = 0

        # Expand "->" to an arrow.
        self._top.bind('>', self._replace_arrows)

        # Re-colorize lines when appropriate.
        self._top.bind('<<Paste>>', self._analyze)
        self._top.bind('<KeyPress>', self._check_analyze)
        self._top.bind('<ButtonPress>', self._check_analyze)

        # Tab cycles focus. (why doesn't this work??)
        def cycle(e, textwidget=self._textwidget):
            textwidget.tk_focusNext().focus()

        self._textwidget.bind('<Tab>', cycle)

        prod_tuples = [(p.lhs(), [p.rhs()]) for p in self._cfg.productions()]
        for i in range(len(prod_tuples) - 1, 0, -1):
            if prod_tuples[i][0] == prod_tuples[i - 1][0]:
                if () in prod_tuples[i][1]:
                    continue
                if () in prod_tuples[i - 1][1]:
                    continue
                print(prod_tuples[i - 1][1])
                print(prod_tuples[i][1])
                prod_tuples[i - 1][1].extend(prod_tuples[i][1])
                del prod_tuples[i]

        for lhs, rhss in prod_tuples:
            print(lhs, rhss)
            s = '%s ->' % lhs
            for rhs in rhss:
                for elt in rhs:
                    if isinstance(elt, Nonterminal):
                        s += ' %s' % elt
                    else:
                        s += ' %r' % elt
                s += ' |'
            s = s[:-2] + '\n'
            self._textwidget.insert('end', s)

        self._analyze()

    #         # Add the producitons to the text widget, and colorize them.
    #         prod_by_lhs = {}
    #         for prod in self._cfg.productions():
    #             if len(prod.rhs()) > 0:
    #                 prod_by_lhs.setdefault(prod.lhs(),[]).append(prod)
    #         for (lhs, prods) in prod_by_lhs.items():
    #             self._textwidget.insert('end', '%s ->' % lhs)
    #             self._textwidget.insert('end', self._rhs(prods[0]))
    #             for prod in prods[1:]:
    #                 print '\t|'+self._rhs(prod),
    #                 self._textwidget.insert('end', '\t|'+self._rhs(prod))
    #             print
    #             self._textwidget.insert('end', '\n')
    #         for prod in self._cfg.productions():
    #             if len(prod.rhs()) == 0:
    #                 self._textwidget.insert('end', '%s' % prod)
    #         self._analyze()

    #     def _rhs(self, prod):
    #         s = ''
    #         for elt in prod.rhs():
    #             if isinstance(elt, Nonterminal): s += ' %s' % elt.symbol()
    #             else: s += ' %r' % elt
    #         return s

    def _clear_tags(self, linenum):
        """
        Remove all tags (except ``arrow`` and ``sel``) from the given
        line of the text widget used for editing the productions.
        """
        start = '%d.0' % linenum
        end = '%d.end' % linenum
        for tag in self._textwidget.tag_names():
            if tag not in ('arrow', 'sel'):
                self._textwidget.tag_remove(tag, start, end)

    def _check_analyze(self, *e):
        """
        Check if we've moved to a new line.  If we have, then remove
        all colorization from the line we moved to, and re-colorize
        the line that we moved from.
        """
        linenum = int(self._textwidget.index('insert').split('.')[0])
        if linenum != self._linenum:
            self._clear_tags(linenum)
            self._analyze_line(self._linenum)
            self._linenum = linenum

    def _replace_arrows(self, *e):
        """
        Replace any ``'->'`` text strings with arrows (char \\256, in
        symbol font).  This searches the whole buffer, but is fast
        enough to be done anytime they press '>'.
        """
        arrow = '1.0'
        while True:
            arrow = self._textwidget.search('->', arrow, 'end+1char')
            if arrow == '':
                break
            self._textwidget.delete(arrow, arrow + '+2char')
            self._textwidget.insert(arrow, self.ARROW, 'arrow')
            self._textwidget.insert(arrow, '\t')

        arrow = '1.0'
        while True:
            arrow = self._textwidget.search(self.ARROW, arrow + '+1char', 'end+1char')
            if arrow == '':
                break
            self._textwidget.tag_add('arrow', arrow, arrow + '+1char')

    def _analyze_token(self, match, linenum):
        """
        Given a line number and a regexp match for a token on that
        line, colorize the token.  Note that the regexp match gives us
        the token's text, start index (on the line), and end index (on
        the line).
        """
        # What type of token is it?
        if match.group()[0] in "'\"":
            tag = 'terminal'
        elif match.group() in ('->', self.ARROW):
            tag = 'arrow'
        else:
            # If it's a nonterminal, then set up new bindings, so we
            # can highlight all instances of that nonterminal when we
            # put the mouse over it.
            tag = 'nonterminal_' + match.group()
            if tag not in self._textwidget.tag_names():
                self._init_nonterminal_tag(tag)

        start = '%d.%d' % (linenum, match.start())
        end = '%d.%d' % (linenum, match.end())
        self._textwidget.tag_add(tag, start, end)

    def _init_nonterminal_tag(self, tag, foreground='blue'):
        self._textwidget.tag_config(tag, foreground=foreground, font=CFGEditor._BOLD)
        if not self._highlight_matching_nonterminals:
            return

        def enter(e, textwidget=self._textwidget, tag=tag):
            textwidget.tag_config(tag, background='#80ff80')

        def leave(e, textwidget=self._textwidget, tag=tag):
            textwidget.tag_config(tag, background='')

        self._textwidget.tag_bind(tag, '<Enter>', enter)
        self._textwidget.tag_bind(tag, '<Leave>', leave)

    def _analyze_line(self, linenum):
        """
        Colorize a given line.
        """
        # Get rid of any tags that were previously on the line.
        self._clear_tags(linenum)

        # Get the line line's text string.
        line = self._textwidget.get(repr(linenum) + '.0', repr(linenum) + '.end')

        # If it's a valid production, then colorize each token.
        if CFGEditor._PRODUCTION_RE.match(line):
            # It's valid; Use _TOKEN_RE to tokenize the production,
            # and call analyze_token on each token.
            def analyze_token(match, self=self, linenum=linenum):
                self._analyze_token(match, linenum)
                return ''

            CFGEditor._TOKEN_RE.sub(analyze_token, line)
        elif line.strip() != '':
            # It's invalid; show the user where the error is.
            self._mark_error(linenum, line)

    def _mark_error(self, linenum, line):
        """
        Mark the location of an error in a line.
        """
        arrowmatch = CFGEditor._ARROW_RE.search(line)
        if not arrowmatch:
            # If there's no arrow at all, highlight the whole line.
            start = '%d.0' % linenum
            end = '%d.end' % linenum
        elif not CFGEditor._LHS_RE.match(line):
            # Otherwise, if the LHS is bad, highlight it.
            start = '%d.0' % linenum
            end = '%d.%d' % (linenum, arrowmatch.start())
        else:
            # Otherwise, highlight the RHS.
            start = '%d.%d' % (linenum, arrowmatch.end())
            end = '%d.end' % linenum

        # If we're highlighting 0 chars, highlight the whole line.
        if self._textwidget.compare(start, '==', end):
            start = '%d.0' % linenum
            end = '%d.end' % linenum
        self._textwidget.tag_add('error', start, end)

    def _analyze(self, *e):
        """
        Replace ``->`` with arrows, and colorize the entire buffer.
        """
        self._replace_arrows()
        numlines = int(self._textwidget.index('end').split('.')[0])
        for linenum in range(1, numlines + 1):  # line numbers start at 1.
            self._analyze_line(linenum)

    def _parse_productions(self):
        """
        Parse the current contents of the textwidget buffer, to create
        a list of productions.
        """
        productions = []

        # Get the text, normalize it, and split it into lines.
        text = self._textwidget.get('1.0', 'end')
        text = re.sub(self.ARROW, '->', text)
        text = re.sub('\t', ' ', text)
        lines = text.split('\n')

        # Convert each line to a CFG production
        for line in lines:
            line = line.strip()
            if line == '':
                continue
            productions += _read_cfg_production(line)
            # if line.strip() == '': continue
            # if not CFGEditor._PRODUCTION_RE.match(line):
            #    raise ValueError('Bad production string %r' % line)
            #
            # (lhs_str, rhs_str) = line.split('->')
            # lhs = Nonterminal(lhs_str.strip())
            # rhs = []
            # def parse_token(match, rhs=rhs):
            #    token = match.group()
            #    if token[0] in "'\"": rhs.append(token[1:-1])
            #    else: rhs.append(Nonterminal(token))
            #    return ''
            # CFGEditor._TOKEN_RE.sub(parse_token, rhs_str)
            #
            # productions.append(Production(lhs, *rhs))

        return productions

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

    def _ok(self, *e):
        self._apply()
        self._destroy()

    def _apply(self, *e):
        productions = self._parse_productions()
        start = Nonterminal(self._start.get())
        cfg = CFG(start, productions)
        if self._set_cfg_callback is not None:
            self._set_cfg_callback(cfg)

    def _reset(self, *e):
        self._textwidget.delete('1.0', 'end')
        for production in self._cfg.productions():
            self._textwidget.insert('end', '%s\n' % production)
        self._analyze()
        if self._set_cfg_callback is not None:
            self._set_cfg_callback(self._cfg)

    def _cancel(self, *e):
        try:
            self._reset()
        except:
            pass
        self._destroy()

    def _help(self, *e):
        # The default font's not very legible; try using 'fixed' instead.
        try:
            ShowText(
                self._parent,
                'Help: Chart Parser Demo',
                (_CFGEditor_HELP).strip(),
                width=75,
                font='fixed',
            )
        except:
            ShowText(
                self._parent,
                'Help: Chart Parser Demo',
                (_CFGEditor_HELP).strip(),
                width=75,
            )
Esempio n. 17
0
 def __init__(self, *args, **kwargs):
     super(TkWindowNode, self).__init__(*args, **kwargs)
     self.__tk_object = Toplevel()
     self.__tk_object.title(eval_format('{self.window_name} id={id(self)}'))        
     self.__tk_object.protocol('WM_DELETE_WINDOW', self.on_close)
Esempio n. 18
0
class Task(Frame):
    def __init__(self,
                 master=None,
                 work=WORK_TM,
                 rest=REST_TM,
                 server=HOST,
                 port=PORT,
                 mode='fascist'):
        """create the task widget and get things started"""

        self.lid_state = "open"
        self.lid_time = time.time()
        self.interrupt_count = 0
        self.then = 0.0
        self.old_work = 0.0
        self.state = "working"
        self.cancel_rest = 0

        self.log = logging.getLogger(__name__)

        Frame.__init__(*(self, master))

        self.mode = StringVar()
        self.mode.set(mode)  # "fascist" or "friendly"

        # create main interactor window
        self.workmeter = Meter(self, background="grey50")
        self.workmeter.pack()

        self.work_frame = Frame(self)
        self.work_frame.pack()
        self.work_label = Label(self.work_frame, text="Work time:")
        self.work_label.pack(side=LEFT)
        self.work_scl = Scale(self.work_frame,
                              orient=HORIZONTAL,
                              from_=1,
                              to=max(45, work),
                              command=self.reset_duration)
        self.work_scl.set(work)
        self.work_scl.pack(side=LEFT)

        self.rest_frame = Frame(self)
        self.rest_frame.pack()
        self.rest_label = Label(self.rest_frame, text="Rest time:")
        self.rest_label.pack(side=LEFT)
        self.rest_scl = Scale(self.rest_frame,
                              orient=HORIZONTAL,
                              from_=1,
                              to=max(15, rest),
                              command=self.reset_duration)
        self.rest_scl.set(rest)
        self.rest_scl.pack(side=LEFT)

        self.radio_frame = Frame(self)
        self.radio_frame.pack()
        self.dictator = Radiobutton(self.radio_frame,
                                    text="Fascist",
                                    variable=self.mode,
                                    value="fascist")
        self.friend = Radiobutton(self.radio_frame,
                                  text="Friendly",
                                  variable=self.mode,
                                  value="friendly")
        self.dictator.pack(side=LEFT)
        self.friend.pack(side=LEFT)

        self.button_frame = Frame(self)
        self.button_frame.pack()
        self.restb = Button(self.button_frame, text="Rest", command=self.rest)
        self.restb.pack(side=LEFT)
        self.stopb = Button(self.button_frame, text="Quit", command=self.quit)
        self.stopb.pack(side=LEFT)
        self.helpb = Button(self.button_frame, text="Help", command=self.help)
        self.helpb.pack(side=LEFT)

        # create the cover window
        self.cover = Toplevel(background="black")
        self.cover.withdraw()
        # user can't resize it
        self.cover.resizable(0, 0)
        # when displayed, it should cover all displays
        (w, h) = (self.winfo_vrootwidth(), self.winfo_vrootheight())
        if self.log.getEffectiveLevel() <= logging.DEBUG:
            # but we reduce it while debugging
            w, h = (w / 5, h / 5)
        self.cover.geometry("%dx%d+0+0" % (w, h))

        # and it's undecorated
        self.cover.overrideredirect(1)

        # cover contains a frame with rest message and meter
        f = Frame(self.cover, background="black")
        self.restnote = Label(f, background="black", foreground="white")
        self.restmeter = Meter(f, background="grey50", height=10, width=200)
        self.restnote.pack(pady=2)
        self.restmeter.pack(fill="x", expand=1, pady=2)
        self.cancel_button = Button(f, text="Cancel Rest", command=self.cancel)
        f.pack()

        # initialize interrupt information
        self.linux_interrupts = 0
        # used by the default activity checker
        self.mouse = None

        self.setup_server(server, port)

        # self.last_int is the last time the server was alerted to activity
        # self.now is the server's notion of the current time
        # idle time is therefore max(0, self.now-self.last_int)
        (self.last_int, _w_time, _r_time, self.now) = self.server.get()
        self.idle = max(0, self.now - self.last_int)

        self.bgcolor = self["background"]

        # start the ball rolling
        self.after(CHK_INT, self.tick)
        self.work()

    def setup_server(self, server, port):
        if server is None:
            self.server = collector.Collector()
            self.log.debug("using private Collector()")
            return

        self.server = xmlrpc_client.ServerProxy("http://%s:%d" %
                                                (server, port))
        try:
            self.server.get()
            self.log.debug("found existing server")
        except socket.error:
            if server in ["", "localhost", "127.0.0.1"]:
                cmd = "watch-server.py"
                args = ["-p", "%d" % port]
                pid = os.spawnvp(os.P_NOWAIT, cmd, args)
                # wait briefly for server to start
                time.sleep(0.2)
                self.server = xmlrpc_client.ServerProxy("http://%s:%d" %
                                                        (server, port),
                                                        allow_none=True)
                # try connecting
                for _i in range(10):
                    try:
                        self.server.get()
                        atexit.register(os.kill, pid, signal.SIGHUP)
                        self.log.debug("spawned server")
                        return
                    except socket.error:
                        time.sleep(0.1)
            # nothing else worked, so fall back to an embedded collector
            self.server = collector.Collector()
            self.log.debug("using private Collector()")

    def reset_duration(self, _dummy=None):
        """reset work/rest interval lengths to current scale values"""
        wtime = self.work_scl.get()
        self.workmeter.set_range(self.workmeter.min_val,
                                 self.workmeter.min_val + wtime * 60)
        self.restmeter.set_range(
            self.restmeter.min_val,
            self.restmeter.min_val + self.rest_scl.get() * 60)
        # only time the user can fiddle the work/rest meters is during
        # the work phase, so the only scale change that matters for extending
        # or contracting the end of the interval is the work scale
        try:
            delta = wtime - self.old_work
        except AttributeError:
            delta = 0
        self.log.debug(__("then: {} delta: {}m", hhmm(self.then), delta))
        self.then = self.then + delta * 60
        self.old_work = wtime

        self.server.put(self.work_scl.get(), self.rest_scl.get())

    def work(self):
        """start the work period"""
        self.reset_warning()
        self.restmeter.reset()
        self.state = "working"
        self.then = self.now + self.work_scl.get() * 60
        self.log.debug(__("work: then: {}", hhmm(self.then)))
        self.workmeter.set_range(self.now, self.then)
        self.workmeter.reset()
        self.cover.withdraw()

    def warn_work_end(self):
        """alert user that work period is almost up"""
        self.set_background("yellow")

    def reset_warning(self):
        """back to plain old grey bg"""
        self.set_background(self.bgcolor)

    def set_background(self, color):
        for w in (self, self.work_scl, self.rest_scl, self.dictator,
                  self.friend, self.button_frame, self.stopb, self.restb,
                  self.helpb, self.work_frame, self.rest_frame,
                  self.radio_frame, self.work_label, self.rest_label):
            w["background"] = color

    def rest(self):
        """overlay the screen with a window, preventing typing"""
        self.cancel_rest = 0
        self.workmeter.reset()
        self.state = "resting"
        # the user may not have been typing or mousing right up to the
        # work/rest threshold - give credit for whatever rest time has
        # already been accumulated
        resttime = self.rest_scl.get() * 60 - (self.now - self.last_int)
        if resttime < 0:
            self.work()
            return
        mins, secs = divmod(resttime, 60)
        self.then = self.now + resttime
        self.cover.deiconify()
        self.cover.tkraise()
        resttext = ("Rest for %dm%02ds please..." % (mins, secs))
        self.restnote.configure(text=resttext)
        self.restmeter.set_range(self.now, self.then)
        self.restmeter.reset()
        if self.mode.get() == "friendly":
            self.cancel_button.pack(pady=2)
        else:
            self.cancel_button.pack_forget()

        self.log.debug(
            __("rest: state: {} now: {} then: {} active? {}", self.state,
               hhmm(self.now), hhmm(self.then), self.check_activity()))

    def help(self):
        Dialog(self.master, title="Help", content=usageText())

    ### ---- define activity checkers here ---- ###
    # keyed by sys.platform or "default" to return a method that checks
    # for mouse/keyboard activity
    _dispatch = {}

    def check_activity(self):
        """check mouse/keyboard activity info

        where possible, call platform-dependent routine to get mouse and
        keyboard info, otherwise, just return mouse info

        in all cases, the value returned should evaluate to False if no
        activity was detected.
        """
        active = False
        if self.lid_state == "open":
            dflt = self._dispatch["default"]
            checker = self._dispatch.get(sys.platform, dflt)
            active = checker(self)
            if active:
                self.server.tick()
        return active

    def check_mouse(self):
        """default checker, just compares current w/ saved mouse pos"""
        mouse = self.winfo_pointerxy()
        try:
            return mouse != self.mouse
        finally:
            self.mouse = mouse

    _dispatch["default"] = check_mouse

    def get_linux_interrupts(self):
        count = 0
        # Can't seem to find mouse interrupts, so for now, just watch
        # keyboard and mix add get_mouseinfo() output as a substitute for
        # mouse interrupts.
        last_count = self.interrupt_count
        for line in open("/proc/interrupts"):
            fields = line.split()
            if fields[0] == "1:":
                count = sum(int(fields[n]) for n in range(1, 8))
                self.interrupt_count = count
                break
        return self.check_mouse() or self.interrupt_count > last_count

    _dispatch["linux"] = get_linux_interrupts

    def check_lid_state(self):
        if os.path.exists(LID_STATE):
            for line in open(LID_STATE):
                fields = line.strip().split()
                if fields[0] == "state:":
                    return self.maybe_change_lid_state(fields[1])
        else:
            self.lid_state = "open"
        return 0

    def maybe_change_lid_state(self, state):
        """Take necessary action when lid state changes.

        Return True if lid state changed.
        """
        idle = 0
        if state != self.lid_state:
            self.log.info(__("lid state changed: {}", state))
            lid_time = time.time()
            if state == "open":
                idle = lid_time - self.lid_time
                self.log.info(__("idle for {}s", idle))
            self.lid_state = state
            self.lid_time = lid_time
        return idle

    def tick(self):
        """perform periodic checks for activity or state switch"""
        try:
            self._tick()
        finally:
            self.after(CHK_INT, self.tick)

    def _tick(self):
        (self.last_int, work_time, rest_time, self.now) = self.server.get()
        # check for mouse or keyboard activity
        idle_time = self.check_lid_state()
        if idle_time > rest_time * 60:
            self.log.info(
                __("The lid is up! Back to work: {}", hhmm(idle_time)))
            self.work()
            return

        active = self.check_activity()
        idle = max(0, self.now - self.last_int)

        # check to see if the work/rest scales got adjusted by another
        # watch instance
        if (self.work_scl.get() != work_time
                or self.rest_scl.get() != rest_time):
            self.work_scl.set(work_time)
            self.rest_scl.set(rest_time)

        self.log.debug(
            __("work: state: {} now: {} then: {} active? {}", self.state,
               hhmm(self.now), hhmm(self.then), active))
        if self.state == "resting":
            # user explicitly cancelled the rest or the idle period
            # exceeded the desired rest time
            if self.cancel_rest or idle > rest_time * 60:
                self.work()
                return

            # make sure the rest window is as far up the window stack as
            # possible
            self.cover.tkraise()

            if idle <= self.idle:
                # user moved something - extend rest by a second
                self.then += 1
                self.restmeter.set_range(self.restmeter.min_val, self.then)
                self.restmeter.set(self.now)
                self.idle = idle

            # update message to reflect rest time remaining
            timeleft = int(round(self.then - self.now))
            minleft, secleft = divmod(timeleft, 60)
            resttext = ("Rest for %dm%02ds please..." % (minleft, secleft))
            self.restnote.configure(text=resttext)

        else:
            # if it's been at least the length of the rest interval
            # since last interrupt, reset the work interval
            if idle >= rest_time * 60:
                self.work()
                return

            self.idle = idle

            if self.now > self.then:
                # work period expired
                self.rest()
                return

            if self.now + 60 > self.then:
                # work period nearly expired - warn user
                self.warn_work_end()
            else:
                self.reset_warning()

        self.restmeter.set(self.now)
        self.workmeter.set(self.now)

    def cancel(self):
        self.cancel_rest = 1
Esempio n. 19
0
    def __init__(self,
                 master=None,
                 work=WORK_TM,
                 rest=REST_TM,
                 server=HOST,
                 port=PORT,
                 mode='fascist'):
        """create the task widget and get things started"""

        self.lid_state = "open"
        self.lid_time = time.time()
        self.interrupt_count = 0
        self.then = 0.0
        self.old_work = 0.0
        self.state = "working"
        self.cancel_rest = 0

        self.log = logging.getLogger(__name__)

        Frame.__init__(*(self, master))

        self.mode = StringVar()
        self.mode.set(mode)  # "fascist" or "friendly"

        # create main interactor window
        self.workmeter = Meter(self, background="grey50")
        self.workmeter.pack()

        self.work_frame = Frame(self)
        self.work_frame.pack()
        self.work_label = Label(self.work_frame, text="Work time:")
        self.work_label.pack(side=LEFT)
        self.work_scl = Scale(self.work_frame,
                              orient=HORIZONTAL,
                              from_=1,
                              to=max(45, work),
                              command=self.reset_duration)
        self.work_scl.set(work)
        self.work_scl.pack(side=LEFT)

        self.rest_frame = Frame(self)
        self.rest_frame.pack()
        self.rest_label = Label(self.rest_frame, text="Rest time:")
        self.rest_label.pack(side=LEFT)
        self.rest_scl = Scale(self.rest_frame,
                              orient=HORIZONTAL,
                              from_=1,
                              to=max(15, rest),
                              command=self.reset_duration)
        self.rest_scl.set(rest)
        self.rest_scl.pack(side=LEFT)

        self.radio_frame = Frame(self)
        self.radio_frame.pack()
        self.dictator = Radiobutton(self.radio_frame,
                                    text="Fascist",
                                    variable=self.mode,
                                    value="fascist")
        self.friend = Radiobutton(self.radio_frame,
                                  text="Friendly",
                                  variable=self.mode,
                                  value="friendly")
        self.dictator.pack(side=LEFT)
        self.friend.pack(side=LEFT)

        self.button_frame = Frame(self)
        self.button_frame.pack()
        self.restb = Button(self.button_frame, text="Rest", command=self.rest)
        self.restb.pack(side=LEFT)
        self.stopb = Button(self.button_frame, text="Quit", command=self.quit)
        self.stopb.pack(side=LEFT)
        self.helpb = Button(self.button_frame, text="Help", command=self.help)
        self.helpb.pack(side=LEFT)

        # create the cover window
        self.cover = Toplevel(background="black")
        self.cover.withdraw()
        # user can't resize it
        self.cover.resizable(0, 0)
        # when displayed, it should cover all displays
        (w, h) = (self.winfo_vrootwidth(), self.winfo_vrootheight())
        if self.log.getEffectiveLevel() <= logging.DEBUG:
            # but we reduce it while debugging
            w, h = (w / 5, h / 5)
        self.cover.geometry("%dx%d+0+0" % (w, h))

        # and it's undecorated
        self.cover.overrideredirect(1)

        # cover contains a frame with rest message and meter
        f = Frame(self.cover, background="black")
        self.restnote = Label(f, background="black", foreground="white")
        self.restmeter = Meter(f, background="grey50", height=10, width=200)
        self.restnote.pack(pady=2)
        self.restmeter.pack(fill="x", expand=1, pady=2)
        self.cancel_button = Button(f, text="Cancel Rest", command=self.cancel)
        f.pack()

        # initialize interrupt information
        self.linux_interrupts = 0
        # used by the default activity checker
        self.mouse = None

        self.setup_server(server, port)

        # self.last_int is the last time the server was alerted to activity
        # self.now is the server's notion of the current time
        # idle time is therefore max(0, self.now-self.last_int)
        (self.last_int, _w_time, _r_time, self.now) = self.server.get()
        self.idle = max(0, self.now - self.last_int)

        self.bgcolor = self["background"]

        # start the ball rolling
        self.after(CHK_INT, self.tick)
        self.work()