Beispiel #1
0
    def __init__(self, controller):
        # constants
        self.left_margin = 0
        self.top_margin = 0

        # main control
        self.controller = controller
        self.main_window_w = []

        # general urwid items
        self.clock_view = urwid.Text(ZERO_TIME, align="center")
        self.refresh_rate_ctrl = urwid.Edit((u'Refresh[s]:'),
                                            self.controller.refresh_rate)
        self.hline = urwid.AttrWrap(urwid.SolidFill(u' '), 'line')

        self.mode_buttons = []

        self.summary_widget_index = None

        # Visible graphs are the graphs currently displayed, this is a
        # subset of the available graphs for display
        self.graph_place_holder = urwid.WidgetPlaceholder(urwid.Pile([]))

        # construct the various menus during init phase
        self.stress_menu = StressMenu(self.on_menu_close,
                                      self.controller.stress_exe)
        self.help_menu = HelpMenu(self.on_menu_close)
        self.about_menu = AboutMenu(self.on_menu_close)
        self.graphs_menu = SensorsMenu(self.on_graphs_menu_close,
                                       self.controller.sources,
                                       self.controller.graphs_default_conf)
        self.summary_menu = SensorsMenu(self.on_summary_menu_close,
                                        self.controller.sources,
                                        self.controller.summary_default_conf)

        # call super
        urwid.WidgetPlaceholder.__init__(self, self.main_window())
        urwid.connect_signal(self.refresh_rate_ctrl, 'change',
                             self.update_refresh_rate)
Beispiel #2
0
class GraphView(urwid.WidgetPlaceholder):
    """
    A class responsible for providing the application's interface and
    graph display.
    The GraphView can change the state of the graph, since it provides the UI
    The change is state should be reflected in the GraphController
    """
    def __init__(self, controller):
        # constants
        self.left_margin = 0
        self.top_margin = 0

        # main control
        self.controller = controller
        self.main_window_w = []

        # general urwid items
        self.clock_view = urwid.Text(ZERO_TIME, align="center")
        self.refresh_rate_ctrl = urwid.Edit((u'Refresh[s]:'),
                                            self.controller.refresh_rate)
        self.hline = urwid.AttrWrap(urwid.SolidFill(u' '), 'line')

        self.mode_buttons = []

        self.summary_widget_index = None

        # Visible graphs are the graphs currently displayed, this is a
        # subset of the available graphs for display
        self.graph_place_holder = urwid.WidgetPlaceholder(urwid.Pile([]))

        # construct the various menus during init phase
        self.stress_menu = StressMenu(self.on_menu_close,
                                      self.controller.stress_exe)
        self.help_menu = HelpMenu(self.on_menu_close)
        self.about_menu = AboutMenu(self.on_menu_close)
        self.graphs_menu = SensorsMenu(self.on_graphs_menu_close,
                                       self.controller.sources,
                                       self.controller.graphs_default_conf)
        self.summary_menu = SensorsMenu(self.on_summary_menu_close,
                                        self.controller.sources,
                                        self.controller.summary_default_conf)

        # call super
        urwid.WidgetPlaceholder.__init__(self, self.main_window())
        urwid.connect_signal(self.refresh_rate_ctrl, 'change',
                             self.update_refresh_rate)

    def update_refresh_rate(self, _, new_refresh_rate):
        # Special case of 'q' in refresh rate
        if 'q' in new_refresh_rate:
            self.on_exit_program()

        try:
            if float(new_refresh_rate) <= 0.001:
                pass
            else:
                self.controller.refresh_rate = new_refresh_rate
        except ValueError:
            self.controller.refresh_rate = '2.0'

    def update_displayed_information(self):
        """ Update all the graphs that are being displayed """

        for source in self.controller.sources:
            source_name = source.get_source_name()
            if (any(self.graphs_menu.active_sensors[source_name])
                    or any(self.summary_menu.active_sensors[source_name])):
                source.update()

        for graph in self.visible_graphs.values():
            try:
                graph.update()
            except IndexError:
                logging.debug("Graph update failed")
                pass

        # update graph summery
        for summary in self.visible_summaries.values():
            try:
                summary.update()
            except IndexError:
                logging.debug("Summary update failed")
                pass

        # Only update clock if not is stress mode
        if self.controller.stress_conroller.get_current_mode() != 'Monitor':
            self.clock_view.set_text(
                seconds_to_text((timeit.default_timer() -
                                 self.controller.stress_start_time)))

    def on_reset_button(self, _):
        """Reset graph data and display empty graph"""
        for graph in self.visible_graphs.values():
            graph.reset()
        for graph in self.graphs.values():
            try:
                graph.source.reset()
            except NotImplementedError:
                pass
        # Reset clock
        self.clock_view.set_text(ZERO_TIME)

        self.update_displayed_information()

    def on_menu_close(self):
        """Return to main screen"""
        self.original_widget = self.main_window_w

    def on_graphs_menu_close(self, update):
        """Return to main screen and update sensor that
        are active in the view"""
        logging.info("closing sensor menu, update=%s", update)
        if update:
            for sensor, visible_sensors in \
                    self.graphs_menu.active_sensors.items():
                self.graphs[sensor].set_visible_graphs(visible_sensors)
                # If not sensor is selected, do not display the graph
                if sensor in self.visible_graphs and not any(visible_sensors):
                    del self.visible_graphs[sensor]
                elif not any(visible_sensors):
                    pass
                # Update visible graphs if a sensor was selected
                else:
                    self.visible_graphs[sensor] = self.graphs[sensor]
            self.show_graphs()

        self.original_widget = self.main_window_w

    def on_summary_menu_close(self, update):
        """Return to main screen and update sensor that
        are active in the view"""
        logging.info("closing summary_menu menu, update=%s", update)
        if update:
            for sensor, visible_sensors in \
                    self.summary_menu.active_sensors.items():
                self.visible_summaries[sensor].update_visibility(
                    visible_sensors)

        self.main_window_w.base_widget[0].body[self.summary_widget_index] =\
            self._generate_summaries()

        self.original_widget = self.main_window_w

    def on_stress_menu_open(self, widget):
        """Open stress options"""
        self.original_widget = urwid.Overlay(self.stress_menu.main_window,
                                             self.original_widget,
                                             ('relative', self.left_margin),
                                             self.stress_menu.get_size()[1],
                                             ('relative', self.top_margin),
                                             self.stress_menu.get_size()[0])

    def on_help_menu_open(self, widget):
        """Open Help menu"""
        self.original_widget = urwid.Overlay(self.help_menu.main_window,
                                             self.original_widget,
                                             ('relative', self.left_margin),
                                             self.help_menu.get_size()[1],
                                             ('relative', self.top_margin),
                                             self.help_menu.get_size()[0])

    def on_about_menu_open(self, widget):
        """Open About menu"""
        self.original_widget = urwid.Overlay(self.about_menu.main_window,
                                             self.original_widget,
                                             ('relative', self.left_margin),
                                             self.about_menu.get_size()[1],
                                             ('relative', self.top_margin),
                                             self.about_menu.get_size()[0])

    def on_graphs_menu_open(self, widget):
        """Open Sensor menu on top of existing frame"""
        self.original_widget = urwid.Overlay(self.graphs_menu.main_window,
                                             self.original_widget,
                                             ('relative', self.left_margin),
                                             self.graphs_menu.get_size()[1],
                                             ('relative', self.top_margin),
                                             self.graphs_menu.get_size()[0])

    def on_summary_menu_open(self, widget):
        """Open Sensor menu on top of existing frame"""
        self.original_widget = urwid.Overlay(self.summary_menu.main_window,
                                             self.original_widget,
                                             ('relative', self.left_margin),
                                             self.summary_menu.get_size()[1],
                                             ('relative', self.top_margin),
                                             self.summary_menu.get_size()[0])

    def on_mode_button(self, my_button, state):
        """Notify the controller of a new mode setting."""
        if state:
            # The new mode is the label of the button
            self.controller.set_mode(my_button.get_label())

    def on_unicode_checkbox(self, w=None, state=False):
        """Enable smooth edges if utf-8 is supported"""
        logging.debug("unicode State is %s", state)

        # Update the controller to the state of the checkbox
        self.controller.smooth_graph_mode = state
        if state:
            self.hline = urwid.AttrWrap(
                urwid.SolidFill(u'\N{LOWER ONE QUARTER BLOCK}'), 'line')
        else:
            self.hline = urwid.AttrWrap(urwid.SolidFill(u' '), 'line')

        for graph in self.graphs.values():
            graph.set_smooth_colors(state)

        self.show_graphs()

    def on_save_settings(self, w=None):
        """ Calls controller save settings method """
        self.controller.save_settings()

    def on_exit_program(self, w=None):
        """ Calls controller exit_program method """
        self.controller.exit_program()

    def _generate_graph_controls(self):
        """ Display sidebar controls. i.e. buttons, and controls"""
        # setup mode radio buttons
        stress_modes = self.controller.stress_conroller.get_modes()
        group = []
        for mode in stress_modes:
            self.mode_buttons.append(
                radio_button(group, mode, self.on_mode_button))

        # Set default radio button to "Monitor" mode
        self.mode_buttons[0].set_state(True, do_callback=False)

        # Create list of buttons
        control_options = list()
        control_options.append(button('Graphs', self.on_graphs_menu_open))
        control_options.append(button('Summaries', self.on_summary_menu_open))
        if self.controller.stress_exe:
            control_options.append(
                button('Stress Options', self.on_stress_menu_open))
        control_options.append(button("Reset", self.on_reset_button))
        control_options.append(button('Help', self.on_help_menu_open))
        control_options.append(button('About', self.on_about_menu_open))
        control_options.append(button("Save Settings", self.on_save_settings))
        control_options.append(button("Quit", self.on_exit_program))

        # Create the menu
        animate_controls = urwid.GridFlow(control_options, 18, 2, 0, 'center')

        # Create smooth graph selection button
        default_smooth = self.controller.smooth_graph_mode
        if urwid.get_encoding_mode() == "utf8":
            unicode_checkbox = urwid.CheckBox(
                "UTF-8",
                state=default_smooth,
                on_state_change=self.on_unicode_checkbox)
            # Init the state of the graph accoding to the selected mode
            self.on_unicode_checkbox(state=default_smooth)
        else:
            unicode_checkbox = urwid.Text("[N/A] UTF-8")

        install_stress_message = urwid.Text("")
        if not self.controller.firestarter and not self.controller.stress_exe:
            install_stress_message = urwid.Text(
                ('button normal', u"(N/A) install stress"))

        clock_widget = []
        # if self.controller.stress_exe or self.controller.firestarter:
        if self.controller.stress_exe or self.controller.firestarter:
            clock_widget = [
                urwid.Text(('bold text', u"Stress Timer"), align="center"),
                self.clock_view
            ]

        controls = [urwid.Text(('bold text', u"Modes"), align="center")]
        controls += self.mode_buttons
        controls += [install_stress_message]
        controls += clock_widget
        controls += [
            urwid.Divider(),
            urwid.Text(('bold text', u"Control Options"), align="center"),
            animate_controls,
            urwid.Divider(),
            urwid.Text(('bold text', u"Visual Options"), align="center"),
            unicode_checkbox,
            self.refresh_rate_ctrl,
            urwid.Divider(),
            urwid.Text(('bold text', u"Summaries"), align="center"),
        ]

        return controls

    @staticmethod
    def _generate_cpu_stats():
        """Read and display processor name """
        cpu_name = urwid.Text("CPU Name N/A", align="center")
        try:
            cpu_name = urwid.Text(get_processor_name().strip(), align="center")
        except OSError:
            logging.info("CPU name not available")
        return [
            urwid.Text(('bold text', "CPU Detected"), align="center"),
            cpu_name,
            urwid.Divider()
        ]

    def _generate_summaries(self):

        fixed_stats = []
        for summary in self.visible_summaries.values():
            fixed_stats += summary.get_text_item_list()
            fixed_stats += [urwid.Text('')]

        # return fixed_stats pile widget
        return urwid.Pile(fixed_stats)

    def show_graphs(self):
        """Show a pile of the graph selected for dislpay"""
        elements = itertools.chain.from_iterable(
            ([graph] for graph in self.visible_graphs.values()))
        self.graph_place_holder.original_widget = urwid.Pile(elements)

    def main_window(self):
        # initiating the graphs
        self.graphs = OrderedDict()
        self.summaries = OrderedDict()

        for source in self.controller.sources:
            source_name = source.get_source_name()
            color_pallet = source.get_pallet()
            alert_pallet = source.get_alert_pallet()
            self.graphs[source_name] = BarGraphVector(
                source,
                color_pallet,
                len(source.get_sensor_list()),
                self.graphs_menu.active_sensors[source_name],
                alert_colors=alert_pallet)
            if self.controller.script_hooks_enabled:
                source.add_edge_hook(
                    self.controller.script_loader.load_script(
                        source.__class__.__name__,
                        HOOK_INTERVAL))  # Invoke threshold script every 30s

            self.summaries[source_name] = SummaryTextList(
                self.graphs[source_name].source,
                self.summary_menu.active_sensors[source_name],
            )

        # Check if source is available and add it to a dict of visible graphs
        # and summaries.
        # All available summaries are always visible
        self.visible_graphs = OrderedDict((key, val)
                                          for key, val in self.graphs.items()
                                          if val.get_is_available())

        # Do not show the graph if there is no selected sensors
        for key in self.graphs.keys():
            if not any(self.graphs_menu.active_sensors[key]):
                del self.visible_graphs[key]

        self.visible_summaries = OrderedDict(
            (key, val) for key, val in self.summaries.items()
            if val.get_is_available())

        cpu_stats = self._generate_cpu_stats()
        graph_controls = self._generate_graph_controls()
        summaries = self._generate_summaries()

        text_col = ViListBox(
            urwid.SimpleListWalker(cpu_stats + graph_controls + [summaries]))

        vline = urwid.AttrWrap(urwid.SolidFill(u'|'), 'line')
        widget = urwid.Columns([('fixed', 20, text_col), ('fixed', 1, vline),
                                ('weight', 2, self.graph_place_holder)],
                               dividechars=0,
                               focus_column=0)

        widget = urwid.Padding(widget, ('fixed left', 1), ('fixed right', 1))
        self.main_window_w = widget

        base = self.main_window_w.base_widget[0].body
        self.summary_widget_index = len(base) - 1
        logging.debug("Pile index: %s", self.summary_widget_index)

        return self.main_window_w