예제 #1
0
class GUIBeeTop(GlassWindow, Observable):
    # messages to the observers
    OBS_WHEEL = 0
    OBS_CLOSE = 1
    OBS_MOVE = 2
    OBS_MENU = 3
    OBS_CLICK = 4

    def __init__(self):
        super(GUIBeeTop, self).__init__()
        # flag indicating whether this window is currently being dragged
        self.__is_dragging = 0
        self.__drag_offset = (0, 0)
        self.set_icon_from_file(_config["icon"])
        self.set_title("Beetop")        
        self.set_size_request(_config["window_w"], _config["window_h"] + _config['window_eh'] * len(_config['tasks']))
        self.set_position(gtk.WIN_POS_MOUSE)  #
        self.set_decorated(False)
        # self.set_resizable(True)
        self.stick()
        self.connect("key-press-event", self.__on_key)
        self.connect("destroy", gtk.main_quit)
        self.connect("scroll-event", self.__on_mouse_wheel)
        # window moving
        self.connect("button-press-event", self.__on_button_press)
        self.connect("button-release-event", self.__on_button_release)
        
        gobject.idle_add(self.set_property, "skip-taskbar-hint", 1)
        gobject.idle_add(self.set_property, "skip-pager-hint", 1)
        # keep window below others
        self.connect("focus-in-event", self.__lower_window)
        self.connect_after("button-press-event", self.__lower_window)
        self.add_events(gtk.gdk.SCROLL_MASK | gtk.gdk.POINTER_MOTION_MASK | 
                        # gtk.gdk.POINTER_MOTION_HINT_MASK |
                        gtk.gdk.BUTTON_PRESS_MASK | 
                        gtk.gdk.BUTTON_RELEASE_MASK)
        self.set_bg_image(_config['bg_img'], _config['bg_img_alpha'])
        self.update_bg()

        vbox_app = gtk.VBox(False, 0)
        self.add(vbox_app)
        vbox_app.show()
        self._show_day = None
        self._calendar = TextCalendar(mycal.firstweekday)
        self._lb_month_year = gtk.Label("")
        self._lb_month_year.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(_config['month_year_color']))
        self._lb_month_year.show()
        self._lb_week = CalLabel(7, 1, True)
        self._lb_week.show()
        self._lb_days = CalLabel(7, 6, True)
        self._lb_days.show()
        self._lb_uptime = gtk.Label("")
        self._lb_uptime.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(_config['uptime_color']))
        self._lb_uptime.show()
        self._lb_tasks = []
        self._task_tooltips = []
        for _ in _config['tasks']:
            tlab = gtk.Label("")
            tlab.show()
            self._lb_tasks.append(tlab)
            ttip = gtk.Tooltips()
            ttip.set_delay(200)
            self._task_tooltips.append(ttip)
        self._task_results = [None] * len(self._lb_tasks)
        
        vbox_app.pack_start(self._lb_month_year, False, False, 3)
        vbox_app.pack_start(self._lb_week, False, False, 2)
        vbox_app.pack_start(self._lb_days, False, False, 1)
        vbox_app.pack_start(self._lb_uptime, False, False, 2)
        for tlab in self._lb_tasks:
            vbox_app.pack_start(tlab, False, False, 1)
        self.task_fonts = []
        self.task_fonts.append(pango.FontDescription(_config["task_error_font"]))
        self.task_fonts.append(pango.FontDescription(_config["task_norm_font"]))
        self.task_fonts.append(pango.FontDescription(_config["task_strong_font"]))
        self.task_colors = []
        self.task_colors.append(_config["task_error_color"])
        self.task_colors.append(_config["task_norm_color"])
        self.task_colors.append(_config["task_strong_color"])
        
        self.__popup_menu = Menu([
            ["_mycal.py", self.edit_file, ["mycal.py"]],
            ["_beetask.py", self.edit_file, ["beetask.py"]],
            ["_config.json", self.edit_file, ["config.json"]],
            ["_README", self.edit_file, ["README"]],
            [],
            ["_Move", self.move_window, []],
            ["_Quit", self.__cmd_quit, []]])

        # desktop.watch_bg(self.__on_bg_change)
        self.add_observer(self.__on_window)

        self.show()
        if _config['position_x'] == 0:
            _config['position_x'] = gtk.gdk.screen_width() - _config["window_w"] - 5
        self.move(_config["position_x"] , _config["position_y"])
        self.after_runs = 0
        self._after_run()
        # self.move_window()
    def _after_run(self):
        today = datetime.date.today()
        if self._show_day != today:
            self._show_day = today
            self._set_cal()
        d2 = os.popen('uptime').read().strip()
        i = d2.rfind(',  ')
        self._lb_uptime.set_label(d2[:i] + "\n" + d2[(i + 3):])
        t = 0
        for task, delay in _config['tasks']:
            if self.after_runs % delay == 0:
                self._run_task(t, task)
            t += 1
        gobject.timeout_add(_config['interval'], self._after_run)
        self.after_runs += 1
        
    def _set_cal(self):
        data = self._calendar.formatmonth(self._show_day.year, self._show_day.month).strip().split('\n')
        self._lb_month_year.set_text("%s %d" % (mycal.monthname[self._show_day.month - 1], self._show_day.year))
        # ws = data[1].split()  #decode error?
        i = 0
        wd = []
        for d in self._calendar.iterweekdays():
            wd.append(d)
            week = self._lb_week.get_label(i)
            week.set_text(mycal.weekname[d])
            week.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(_config['week_color']))
            i += 1
        i = 0
        today = datetime.date.today()
        cday = "%d-%d-%d" % (today.year, today.month, today.day)
        ym = "%d-%d" % (self._show_day.year, self._show_day.month)
        for dat in data[2:]:
            # print dat, i
            ds = dat.strip().split()
            if i == 0 and len(ds) < 7:  # the first
                ds = [" "] * (7 - len(ds)) + ds
            if len(ds) < 7:  # the last
                ds = ds + [" "] * (7 - len(ds))
            for j in range(7):
                lday, ltip = self._lb_days.get_labeltip_at(j, i)
                lday.set_text(ds[j])
                mday = "%s-%s" % (ym, ds[j])
                if (not ds[j].isspace()) and (wd[j] in mycal.weekevent or mday in mycal.dayevent):
                    lday.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(_config['event_day_color']))
                    tips = []
                    if wd[j] in mycal.weekevent: tips.append(mycal.weekevent[wd[j]])
                    if mday in mycal.dayevent: tips.append(mycal.dayevent[mday])    
                    ltip.set_tip(lday, "\n".join(tips), tip_private=None)
                else:
                    lday.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(_config['norm_day_color']))
                    ltip.set_tip(lday, "", tip_private=None)  # clear
                if cday == mday:
                    # lday.modify_font(font_month)
                    lday.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(_config['today_color']))
            i += 1
        if i < 6:  # clean others
            for j in range(7):
                lday, ltip = self._lb_days.get_labeltip_at(j, i)
                lday.set_text("")
                lday.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(_config['norm_day_color']))
                ltip.set_tip(lday, "", tip_private=None)  # clear
            i += 1
                    
    def _run_task(self, t, task=None):
        if not task:
            task, delay = _config['tasks'][t]
        self._task_results[t] = beetask.__dict__[task]()
        status, title, tip, _ = self._task_results[t]
        self._lb_tasks[t].set_label(title)
        if status < 0: 
            status = -1
        elif status > 0:
            status = 1
        self._lb_tasks[t].modify_font(self.task_fonts[status + 1])
        self._lb_tasks[t].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.task_colors[status + 1]))
        self._task_tooltips[t].set_tip(self._lb_tasks[t], tip, tip_private=None)
    def edit_file(self, ifile):
        os.system("%s %s  >/dev/null 2>&1 &" % (_config['editor'], os.path.join(sys.path[0], ifile)))
    #
    # Reacts on key presses.
    #
    def __on_key(self, src, event):
        key = gtk.gdk.keyval_name(event.keyval)

        # SPACE updates the background
        if (key == "space"):
            self.update_bg()

        # F10 opens the menu
        elif (key == "F10"):
            # self.update_observer(self.OBS_MENU, 0, event.time)
            self.move_window()
    #
    # Reacts on closing the window.
    #
    def __on_close(self, src, event):

        self.update_observer(self.OBS_CLOSE)
    #
    # Updates the background.
    #
    def update_bg(self, noscreenshot=0):

        GlassWindow.update_bg(self, noscreenshot)
        self.stick()
    #
    # Reacts on changes to the background image.
    #
    def __on_bg_change(self, src, cmd):

        self.update_bg()

    #
    # Reacts on pressing a mouse button.
    #
    def __on_button_press(self, src, event):

        button = event.button
        modifiers = event.state
        if (button == 1):
            x, y = self.get_pointer()
            self.update_observer(self.OBS_CLICK, x, y)

        if (button == 2):
            x, y = self.get_pointer()
            self.__is_dragging = 1
            self.__drag_offset = (x, y)
            self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
            gobject.timeout_add(20, self.__on_move)

    #
    # Reacts on releasing a mouse button.
    #
    def __on_button_release(self, src, event):
        if (self.__is_dragging):
            self.__is_dragging = 0
            self.window.set_cursor(None)
            self.update_bg()

        elif (event.button == 3):
            self.update_observer(self.OBS_MENU, event.button, event.time)
    #
    # Reacts on mouse wheel.
    #
    def __on_mouse_wheel(self, src, event):

        if (event.direction == gtk.gdk.SCROLL_UP): step = -1
        elif (event.direction == gtk.gdk.SCROLL_DOWN): step = 1
        else: step = 0
        self.update_observer(self.OBS_WHEEL, step)
        
    #
    # Keeps the window below others.
    #
    def __lower_window(self, src, event):

        if (self.window): self.window.lower()
        
        return True
    #
    # Reacts on window events.
    #
    def __on_window(self, src, cmd, *args):

        if (cmd == src.OBS_WHEEL):
            step = args[0]
            m = self._show_day.month + step
            if m > 12:
                self._show_day = datetime.date(self._show_day.year + 1, 1, self._show_day.day)
            elif m < 1:
                self._show_day = datetime.date(self._show_day.year - 1, 12, self._show_day.day)
            else:
                self._show_day = datetime.date(self._show_day.year, m, self._show_day.day)
            self._set_cal()

        elif (cmd == src.OBS_CLICK):
            x, y = args
            _, ly = self._lb_month_year.get_layout_offsets()
            if y > ly and y < ly + 20:
                today = datetime.date.today()
                if self._show_day != today:
                    self._show_day = today
                    self._set_cal()
            else:
                for i in  range(len(self._lb_tasks) - 1, -1, -1):
                    lx, ly = self._lb_tasks[i].get_layout_offsets()
                    if y >= ly:
                    # print _config['tasks'][i]
                        cmd = self._task_results[i]
                        if cmd != None: cmd = self._task_results[i][-1]
                        if  x < 30 and cmd:
                            os.system(cmd)
                        else:
                            self._run_task(i)  # run it now
                        break            
        elif (cmd == src.OBS_CLOSE):
            self.__cmd_quit()

        elif (cmd == src.OBS_MOVE):
            x, y = args[0]
            print x, y
            # self.__config.set([conf.GEOMETRY, conf.WINDOW, conf.X], str(x))
            # self.__config.set([conf.GEOMETRY, conf.WINDOW, conf.Y], str(y))

        elif (cmd == src.OBS_MENU):
            button = args[0]
            etime = args[1]
            self.__popup_menu.popup(button, etime)
    #
    # Reacts on moving the mouse pointer.
    #
    def __on_move(self):
        if (self.__is_dragging):
            offx, offy = self.__drag_offset
            winx, winy = self.get_position()
            # print winx, winy
            x, y = self.get_pointer()
            x += winx; y += winy
            self.move(x - offx, y - offy)
            return True
        else:
            return False

    #
    # Switches to window move mode.
    #
    def move_window(self):
        x, y = self.get_pointer()
        width, height = self.window.get_size()
        x = max(4, min(x, width - 4))
        y = max(4, min(y, height - 4))
        self.__is_dragging = 1
        self.__drag_offset = (x, y)
        gobject.timeout_add(20, self.__on_move)

    def __cmd_quit(self):
        # self.__config.save()
        gtk.main_quit()

    def main(self):
        gtk.main()