示例#1
0
    def treeview_widgets(self):
        # Treeview of current suite state, with filtering and sorting.
        # sorting is handled somewhat manually because the simple method
        # of interposing a TreeModelSort at the top:
        #   treestore = gtk.TreeStore(str, ...)
        #   tms = gtk.TreeModelSort( treestore )   #\
        #   tmf = tms.filter_new()                 #-- or other way round?
        #   tv = gtk.TreeView()
        #   tv.set_model(tms)
        # failed to produce correct results (the data displayed was not
        # consistently what should have been displayed given the
        # filtering in use) although the exact same code worked for a
        # liststore.

        self.sort_col_num = 0

        self.ttreestore = gtk.TreeStore(str, str, str, str, str, str, str, str,
                                        str, str, gtk.gdk.Pixbuf)
        self.tmodelfilter = self.ttreestore.filter_new()
        self.tmodelfilter.set_visible_func(self.visible_cb)
        self.tmodelsort = gtk.TreeModelSort(self.tmodelfilter)
        self.ttreeview = gtk.TreeView()
        self.ttreeview.set_rules_hint(True)
        self.ttreeview.set_model(self.tmodelsort)

        ts = self.ttreeview.get_selection()
        ts.set_mode(gtk.SELECTION_SINGLE)

        self.ttreeview.connect('button_press_event',
                               self.on_treeview_button_pressed)
        headings = [
            None, 'task', 'state', 'host', 'Job ID', 'T-submit', 'T-start',
            'T-finish', 'dT-mean', 'latest message'
        ]

        for n in range(1, len(headings)):
            # Skip first column (cycle point)
            tvc = gtk.TreeViewColumn(headings[n])
            if n == 1:
                crp = gtk.CellRendererPixbuf()
                tvc.pack_start(crp, False)
                tvc.set_attributes(crp, pixbuf=10)
            cr = gtk.CellRendererText()
            tvc.pack_start(cr, True)
            if n == 7:
                tvc.set_attributes(cr, markup=n)
            else:
                tvc.set_attributes(cr, text=n)
            tvc.set_resizable(True)
            tvc.set_clickable(True)
            self.ttreeview.append_column(tvc)
            tvc.set_sort_column_id(n - 1)
            self.tmodelsort.set_sort_func(n - 1, self.sort_column, n - 1)
        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.add(self.ttreeview)

        self.tfilterbox = gtk.VBox()
        subbox1 = gtk.HBox(homogeneous=True)
        subbox2 = gtk.HBox(homogeneous=True)
        self.tfilterbox.pack_start(subbox1)
        self.tfilterbox.pack_start(subbox2)

        self.tfilter_states = []

        dotm = DotMaker(self.theme, size='small')
        cnt = 0
        for st in task_state.legal:
            box = gtk.HBox()
            icon = dotm.get_image(st)
            cb = gtk.CheckButton(task_state.labels[st])
            tooltip = gtk.Tooltips()
            tooltip.enable()
            tooltip.set_tip(cb, "Filter by task state = %s" % st)

            box.pack_start(icon, expand=False)
            box.pack_start(cb, expand=False)
            cnt += 1
            if cnt > (len(task_state.legal) + 1) // 2:
                subbox2.pack_start(box, expand=False, fill=True)
            else:
                subbox1.pack_start(box, expand=False, fill=True)
            if st in self.tfilter_states:
                cb.set_active(False)
            else:
                cb.set_active(True)
            cb.connect('toggled', self.check_tfilter_buttons)

        self.filter_entry = EntryTempText()
        self.filter_entry.set_width_chars(7)
        self.filter_entry.connect("activate", self.check_filter_entry)
        self.filter_entry.set_temp_text("filter")
        tooltip = gtk.Tooltips()
        tooltip.enable()
        tooltip.set_tip(
            self.filter_entry, "Filter by task name.\n"
            "Enter a sub-string or regex and hit Enter\n"
            "(to reset, clear the entry and hit Enter)")
        subbox2.pack_start(self.filter_entry)
        cnt += 1

        if cnt % 2 != 0:
            # subbox2 needs another entry to line things up.
            subbox2.pack_start(gtk.HBox(), expand=False, fill=True)

        filter_hbox = gtk.HBox()
        filter_hbox.pack_start(self.tfilterbox, True, True, 10)
        vbox = gtk.VBox()
        vbox.pack_start(sw, True)
        vbox.pack_end(filter_hbox, False)

        return vbox
示例#2
0
class SummaryPanelAppletUpdater(BaseSummaryTimeoutUpdater):
    """Update the summary panel applet - subclass of gsummary equivalent."""

    IDLE_STOPPED_TIME = 3600  # 1 hour.
    MAX_INDIVIDUAL_SUITES = 5

    def __init__(self,
                 hosts,
                 dot_hbox,
                 gcylc_image,
                 is_compact,
                 owner=None,
                 poll_interval=None):
        self.quit = True
        self.dot_hbox = dot_hbox
        self.gcylc_image = gcylc_image
        self.is_compact = is_compact
        self._set_gcylc_image_tooltip()
        self.gcylc_image.set_sensitive(False)
        self.theme_name = gcfg.get(['use theme'])
        self.theme = gcfg.get(['themes', self.theme_name])
        self.dots = DotMaker(self.theme)
        self.statuses = {}
        self.stop_summaries = {}
        self._set_exception_hook()
        super(SummaryPanelAppletUpdater,
              self).__init__(hosts, owner=owner, poll_interval=poll_interval)

    def clear_stopped_suites(self):
        """Clear stopped suite information that may have built up."""
        self.stop_summaries.clear()
        gobject.idle_add(self.update)

    def start(self):
        self.gcylc_image.set_sensitive(True)
        super(SummaryPanelAppletUpdater, self).start()
        self._set_gcylc_image_tooltip()

    def stop(self):
        self.gcylc_image.set_sensitive(False)
        super(SummaryPanelAppletUpdater, self).stop()
        self._set_gcylc_image_tooltip()

    def launch_context_menu(self,
                            event,
                            suite_host_tuples=None,
                            extra_items=None):
        has_stopped_suites = bool(self.stop_summaries)

        if suite_host_tuples is None:
            suite_host_tuples = []

        if extra_items is None:
            extra_items = []

        gsummary_item = gtk.ImageMenuItem("Launch cylc gsummary")
        img = gtk.image_new_from_stock("gcylc", gtk.ICON_SIZE_MENU)
        gsummary_item.set_image(img)
        gsummary_item.show()
        gsummary_item.connect("button-press-event",
                              self._on_button_press_event_gsummary)

        extra_items.append(gsummary_item)

        menu = get_summary_menu(suite_host_tuples,
                                self.theme_name,
                                self._set_theme,
                                has_stopped_suites,
                                self.clear_stopped_suites,
                                self.hosts,
                                self.set_hosts,
                                self.update_now,
                                self.start,
                                program_name="cylc gpanel",
                                extra_items=extra_items,
                                owner=self.owner,
                                is_stopped=self.quit)
        menu.popup(None, None, None, event.button, event.time)
        return False

    def update(self, update_time=None):
        """Update the Applet."""
        suite_host_tuples = []
        statuses = copy.deepcopy(self.statuses)
        stop_summaries = copy.deepcopy(self.stop_summaries)
        for host in self.hosts:
            suites = (statuses.get(host, {}).keys() +
                      stop_summaries.get(host, {}).keys())
            for suite in suites:
                suite_host_tuples.append((suite, host))
        suite_host_tuples.sort()
        for child in self.dot_hbox.get_children():
            self.dot_hbox.remove(child)
        number_mode = (not self.is_compact
                       and len(suite_host_tuples) > self.MAX_INDIVIDUAL_SUITES)
        suite_statuses = {}
        compact_suite_statuses = []
        for suite, host in suite_host_tuples:
            if suite in statuses.get(host, {}):
                status_map = statuses[host][suite]
                is_stopped = False
            else:
                info = stop_summaries[host][suite]
                status_map, suite_time = info
                is_stopped = True
            status = extract_group_state(status_map.keys(),
                                         is_stopped=is_stopped)
            if number_mode:
                suite_statuses.setdefault(is_stopped, {})
                suite_statuses[is_stopped].setdefault(status, [])
                suite_statuses[is_stopped][status].append(
                    (suite, host, status_map.items()))
            elif self.is_compact:
                compact_suite_statuses.append(
                    (suite, host, status, status_map.items(), is_stopped))
            else:
                self._add_image_box([(suite, host, status, status_map.items(),
                                      is_stopped)])
        if number_mode:
            for is_stopped in sorted(suite_statuses.keys()):
                statuses = suite_statuses[is_stopped].items()
                statuses.sort(lambda x, y: cmp(len(y[1]), len(x[1])))
                for status, suite_host_states_tuples in statuses:
                    label = gtk.Label(str(len(suite_host_states_tuples)) + ":")
                    label.show()
                    self.dot_hbox.pack_start(label, expand=False, fill=False)
                    suite_info_tuples = []
                    for suite, host, task_states in suite_host_states_tuples:
                        suite_info_tuples.append(
                            (suite, host, status, task_states, is_stopped))
                    self._add_image_box(suite_info_tuples)
        if self.is_compact:
            if not compact_suite_statuses:
                # No suites running or stopped.
                self.gcylc_image.show()
                return False
            self.gcylc_image.hide()
            self._add_image_box(compact_suite_statuses)
        return False

    def _add_image_box(self, suite_host_info_tuples):
        image_eb = gtk.EventBox()
        image_eb.show()
        is_all_stopped = False
        running_status_list = []
        status_list = []
        suite_host_tuples = []
        for info_tuple in suite_host_info_tuples:
            suite, host, status, task_states, is_stopped = info_tuple
            suite_host_tuples.append((suite, host))
            if not is_stopped:
                running_status_list.append(status)
            status_list.append(status)
        if running_status_list:
            status = extract_group_state(running_status_list, is_stopped=False)
            image = self.dots.get_image(status, is_stopped=False)
        else:
            status = extract_group_state(status_list, is_stopped=True)
            image = self.dots.get_image(status, is_stopped=True)
        image.show()
        image_eb.add(image)
        image_eb._connect_args = suite_host_tuples
        image_eb.connect("button-press-event", self._on_button_press_event)

        text_format = "%s - %s - %s"
        long_text_format = text_format + "\n    Tasks: %s\n"
        text = ""
        tip_vbox = gtk.VBox()  # Only used in PyGTK 2.12+
        tip_vbox.show()
        for info_tuple in suite_host_info_tuples:
            suite, host, status, task_states, is_stopped = info_tuple
            task_states.sort(lambda x, y: cmp(len(y[1]), len(x[1])))
            tip_hbox = gtk.HBox()
            tip_hbox.show()
            state_info = []
            for state_name, tasks in task_states:
                state_info.append(str(len(tasks)) + " " + state_name)
                image = self.dots.get_image(state_name, is_stopped=is_stopped)
                image.show()
                tip_hbox.pack_start(image, expand=False, fill=False)
            states_text = ", ".join(state_info)
            if status is None:
                suite_summary = "?"
            else:
                suite_summary = status
            if is_stopped:
                suite_summary = "stopped with " + suite_summary
            tip_label = gtk.Label(text_format % (suite, suite_summary, host))
            tip_label.show()
            tip_hbox.pack_start(tip_label, expand=False, fill=False, padding=5)
            tip_vbox.pack_start(tip_hbox, expand=False, fill=False)
            text += long_text_format % (suite, suite_summary, host,
                                        states_text)
        text = text.rstrip()
        if hasattr(gtk, "Tooltip"):
            image_eb.set_has_tooltip(True)
            image_eb.connect("query-tooltip", self._on_img_tooltip_query,
                             tip_vbox)
        else:
            self._set_tooltip(image_eb, text)
        self.dot_hbox.pack_start(image_eb, expand=False, fill=False, padding=1)

    def _on_button_press_event(self, widget, event):
        if event.button == 1:
            self.launch_context_menu(event,
                                     suite_host_tuples=widget._connect_args)
        return False

    def _on_button_press_event_gsummary(self, widget, event):
        launch_gsummary(hosts=self.hosts, owner=self.owner)

    def _on_img_tooltip_query(self, widget, x, y, kbd, tooltip, tip_widget):
        tooltip.set_custom(tip_widget)
        return True

    def _set_exception_hook(self):
        # Handle an uncaught exception.
        old_hook = sys.excepthook
        sys.excepthook = (
            lambda *a: self._handle_exception(*a, old_hook=old_hook))

    def _handle_exception(self, e_type, e_value, e_traceback, old_hook=None):
        self.gcylc_image.set_from_stock(gtk.STOCK_DIALOG_ERROR,
                                        gtk.ICON_SIZE_MENU)
        exc_lines = traceback.format_exception(e_type, e_value, e_traceback)
        exc_text = "".join(exc_lines)
        info = "cylc gpanel has a problem.\n\n%s" % exc_text
        self._set_tooltip(self.gcylc_image, info.rstrip())
        if old_hook is not None:
            old_hook(exception_class, exception, trace)

    def _set_gcylc_image_tooltip(self):
        if self.quit:
            self._set_tooltip(self.gcylc_image, "Cylc Applet - Off")
        else:
            self._set_tooltip(self.gcylc_image, "Cylc Applet - Active")

    def _set_theme(self, new_theme_name):
        self.theme_name = new_theme_name
        self.theme = gcfg.get(['themes', self.theme_name])
        self.dots = DotMaker(self.theme)

    def _set_tooltip(self, widget, text):
        tooltip = gtk.Tooltips()
        tooltip.enable()
        tooltip.set_tip(widget, text)
示例#3
0
文件: gpanel.py 项目: dmanubens/cylc
class SummaryPanelAppletUpdater(BaseSummaryTimeoutUpdater):

    """Update the summary panel applet - subclass of gsummary equivalent."""

    IDLE_STOPPED_TIME = 3600  # 1 hour.
    MAX_INDIVIDUAL_SUITES = 5

    def __init__(self, hosts, dot_hbox, gcylc_image, is_compact, owner=None,
                 poll_interval=None):
        self.quit = True
        self.dot_hbox = dot_hbox
        self.gcylc_image = gcylc_image
        self.is_compact = is_compact
        self._set_gcylc_image_tooltip()
        self.gcylc_image.set_sensitive(False)
        self.theme_name = gcfg.get( ['use theme'] )
        self.theme = gcfg.get( ['themes', self.theme_name] )
        self.dots = DotMaker(self.theme)
        self.statuses = {}
        self.stop_summaries = {}
        self._set_exception_hook()
        super(SummaryPanelAppletUpdater, self).__init__(
                              hosts, owner=owner, poll_interval=poll_interval)

    def clear_stopped_suites(self):
        """Clear stopped suite information that may have built up."""
        self.stop_summaries.clear()
        gobject.idle_add(self.update)

    def start(self):
        self.gcylc_image.set_sensitive(True)
        super(SummaryPanelAppletUpdater, self).start()
        self._set_gcylc_image_tooltip()

    def stop(self):
        self.gcylc_image.set_sensitive(False)
        super(SummaryPanelAppletUpdater, self).stop()
        self._set_gcylc_image_tooltip()

    def launch_context_menu(self, event, suite_host_tuples=None,
                            extra_items=None):
        has_stopped_suites = bool(self.stop_summaries)

        if suite_host_tuples is None:
            suite_host_tuples = []

        if extra_items is None:
            extra_items = []

        gsummary_item = gtk.ImageMenuItem("Launch cylc gsummary")
        img = gtk.image_new_from_stock("gcylc", gtk.ICON_SIZE_MENU)
        gsummary_item.set_image(img)
        gsummary_item.show()
        gsummary_item.connect("button-press-event",
                                self._on_button_press_event_gsummary)

        extra_items.append(gsummary_item)

        menu = get_summary_menu(suite_host_tuples, 
                                self.theme_name, self._set_theme,
                                has_stopped_suites,
                                self.clear_stopped_suites,
                                self.hosts,
                                self.set_hosts,
                                self.update_now,
                                self.start,
                                program_name="cylc gpanel",
                                extra_items=extra_items,
                                owner=self.owner,
                                is_stopped=self.quit)
        menu.popup( None, None, None, event.button, event.time )
        return False

    def update(self, update_time=None):
        """Update the Applet."""
        suite_host_tuples = []
        statuses = copy.deepcopy(self.statuses)
        stop_summaries = copy.deepcopy(self.stop_summaries)
        for host in self.hosts:
            suites = (statuses.get(host, {}).keys() +
                      stop_summaries.get(host, {}).keys())
            for suite in suites:
                suite_host_tuples.append((suite, host))
        suite_host_tuples.sort()
        for child in self.dot_hbox.get_children():
            self.dot_hbox.remove(child)
        number_mode = (not self.is_compact and
                       len(suite_host_tuples) > self.MAX_INDIVIDUAL_SUITES)
        suite_statuses = {}
        compact_suite_statuses = []
        for suite, host in suite_host_tuples:
            if suite in statuses.get(host, {}):
                status_map = statuses[host][suite]
                is_stopped = False
            else:
                info = stop_summaries[host][suite]
                status_map, suite_time = info
                is_stopped = True
            status = extract_group_state(status_map.keys(),
                                         is_stopped=is_stopped)
            if number_mode:
                suite_statuses.setdefault(is_stopped, {})
                suite_statuses[is_stopped].setdefault(status, [])
                suite_statuses[is_stopped][status].append(
                                           (suite, host, status_map.items()))
            elif self.is_compact:
                compact_suite_statuses.append((suite, host, status,
                                               status_map.items(), is_stopped))
            else:
                self._add_image_box([(suite, host, status, status_map.items(),
                                      is_stopped)])
        if number_mode:
            for is_stopped in sorted(suite_statuses.keys()):
                statuses = suite_statuses[is_stopped].items()
                statuses.sort(lambda x, y: cmp(len(y[1]), len(x[1])))
                for status, suite_host_states_tuples in statuses:
                    label = gtk.Label(
                                str(len(suite_host_states_tuples)) + ":")
                    label.show()
                    self.dot_hbox.pack_start(label, expand=False, fill=False)
                    suite_info_tuples = []
                    for suite, host, task_states in suite_host_states_tuples:
                        suite_info_tuples.append((suite, host, status,
                                                  task_states, is_stopped))
                    self._add_image_box(suite_info_tuples)
        if self.is_compact:
            if not compact_suite_statuses:
                # No suites running or stopped.
                self.gcylc_image.show()
                return False
            self.gcylc_image.hide()
            self._add_image_box(compact_suite_statuses)
        return False

    def _add_image_box(self, suite_host_info_tuples):
        image_eb = gtk.EventBox()
        image_eb.show()
        is_all_stopped = False
        running_status_list = []
        status_list = []
        suite_host_tuples = []
        for info_tuple in suite_host_info_tuples:
            suite, host, status, task_states, is_stopped = info_tuple
            suite_host_tuples.append((suite, host))
            if not is_stopped:
                running_status_list.append(status)
            status_list.append(status)
        if running_status_list:
            status = extract_group_state(running_status_list,
                                         is_stopped=False)
            image = self.dots.get_image(status, is_stopped=False)
        else:
            status = extract_group_state(status_list, is_stopped=True)
            image = self.dots.get_image(status, is_stopped=True)
        image.show()
        image_eb.add(image)
        image_eb._connect_args = suite_host_tuples
        image_eb.connect("button-press-event",
                         self._on_button_press_event)

        text_format = "%s - %s - %s"
        long_text_format = text_format + "\n    Tasks: %s\n"
        text = ""
        tip_vbox = gtk.VBox()  # Only used in PyGTK 2.12+
        tip_vbox.show()
        for info_tuple in suite_host_info_tuples:
            suite, host, status, task_states, is_stopped = info_tuple
            task_states.sort(lambda x, y: cmp(len(y[1]), len(x[1])))
            tip_hbox = gtk.HBox()
            tip_hbox.show()
            state_info = []
            for state_name, tasks in task_states:
                state_info.append(str(len(tasks)) + " " + state_name)
                image = self.dots.get_image(state_name, is_stopped=is_stopped)
                image.show()
                tip_hbox.pack_start(image, expand=False, fill=False)
            states_text = ", ".join(state_info)
            if status is None:
                suite_summary = "?"
            else:
                suite_summary = status
            if is_stopped:
                suite_summary = "stopped with " + suite_summary
            tip_label = gtk.Label(text_format % (suite, suite_summary, host))
            tip_label.show()
            tip_hbox.pack_start(tip_label, expand=False, fill=False,
                                padding=5)
            tip_vbox.pack_start(tip_hbox, expand=False, fill=False)
            text += long_text_format % (suite, suite_summary, host, states_text)
        text = text.rstrip()
        if hasattr(gtk, "Tooltip"):
            image_eb.set_has_tooltip(True)
            image_eb.connect("query-tooltip", self._on_img_tooltip_query,
                             tip_vbox)
        else:
            self._set_tooltip(image_eb, text)
        self.dot_hbox.pack_start(image_eb, expand=False, fill=False,
                                 padding=1)

    def _on_button_press_event(self, widget, event):
        if event.button == 1:
            self.launch_context_menu(event,
                                     suite_host_tuples=widget._connect_args)
        return False

    def _on_button_press_event_gsummary(self, widget, event):
        launch_gsummary(hosts=self.hosts, owner=self.owner)

    def _on_img_tooltip_query(self, widget, x, y, kbd, tooltip, tip_widget):
        tooltip.set_custom(tip_widget)
        return True

    def _set_exception_hook(self):
        # Handle an uncaught exception.
        old_hook = sys.excepthook
        sys.excepthook = (lambda *a:
                          self._handle_exception(*a, old_hook=old_hook))

    def _handle_exception(self, e_type, e_value, e_traceback,
                          old_hook=None):
        self.gcylc_image.set_from_stock(gtk.STOCK_DIALOG_ERROR,
                                        gtk.ICON_SIZE_MENU)
        exc_lines = traceback.format_exception(e_type, e_value, e_traceback)
        exc_text = "".join(exc_lines)
        info = "cylc gpanel has a problem.\n\n%s" % exc_text
        self._set_tooltip(self.gcylc_image, info.rstrip())
        if old_hook is not None:
            old_hook(exception_class, exception, trace)

    def _set_gcylc_image_tooltip(self):
        if self.quit:
            self._set_tooltip(self.gcylc_image, "Cylc Applet - Off")
        else:
            self._set_tooltip(self.gcylc_image, "Cylc Applet - Active")

    def _set_theme(self, new_theme_name):
        self.theme_name = new_theme_name
        self.theme = gcfg.get( ['themes', self.theme_name] )
        self.dots = DotMaker(self.theme)

    def _set_tooltip(self, widget, text):
        tooltip = gtk.Tooltips()
        tooltip.enable()
        tooltip.set_tip(widget, text)