Beispiel #1
0
    def __init__(self, application):
        """ Create a summary page containing various statistics such as the number of logs in the logbook, the logbook's modification date, etc.

        :arg application: The PyQSO application containing the main Gtk window, etc.
        """

        self.application = application
        self.logbook = self.application.logbook
        self.builder = self.application.builder
        glade_file_path = join(realpath(dirname(__file__)), "res", "pyqso.glade")
        self.builder.add_objects_from_file(glade_file_path, ("summary_page",))
        self.summary_page = self.builder.get_object("summary_page")

        self.items = {}

        # Database name in large font at the top of the summary page
        self.builder.get_object("database_name").set_markup("<span size=\"x-large\">%s</span>" % basename(self.logbook.path))
        self.items["LOG_COUNT"] = self.builder.get_object("log_count")
        self.items["QSO_COUNT"] = self.builder.get_object("qso_count")
        self.items["DATE_MODIFIED"] = self.builder.get_object("date_modified")

        # Yearly statistics
        config = configparser.ConfigParser()
        have_config = (config.read(expanduser('~/.config/pyqso/preferences.ini')) != [])
        (section, option) = ("general", "show_yearly_statistics")
        if(have_config and config.has_option(section, option)):
            if(config.getboolean("general", "show_yearly_statistics") and have_matplotlib):
                hbox = Gtk.HBox()
                label = Gtk.Label(label="Display statistics for year: ", halign=Gtk.Align.START)
                hbox.pack_start(label, False, False, 6)
                year_select = Gtk.ComboBoxText()
                min_year, max_year = self.get_year_bounds()
                if min_year and max_year:
                    for year in range(max_year, min_year-1, -1):
                        year_select.append_text(str(year))
                year_select.append_text("")
                year_select.connect("changed", self.on_year_changed)
                hbox.pack_start(year_select, False, False, 6)
                self.summary_page.pack_start(hbox, False, False, 4)

                self.items["YEARLY_STATISTICS"] = Figure()
                canvas = FigureCanvas(self.items["YEARLY_STATISTICS"])
                canvas.set_size_request(800, 175)
                canvas.show()
                self.summary_page.pack_start(canvas, True, True, 0)

        # Summary tab label and icon.
        tab = Gtk.HBox(homogeneous=False, spacing=0)
        label = Gtk.Label(label="Summary  ")
        icon = Gtk.Image.new_from_icon_name(Gtk.STOCK_INDEX, Gtk.IconSize.MENU)
        tab.pack_start(label, False, False, 0)
        tab.pack_start(icon, False, False, 0)
        tab.show_all()

        self.logbook.notebook.insert_page(self.summary_page, tab, 0)  # Append as a new tab
        self.logbook.notebook.show_all()

        return
Beispiel #2
0
 def run_inner(self, endog, exog, **kwargs ):
     
     signs = ['x', '+']
     colours = ['r', 'b']
             
     f = plt.figure()
     
     var_index = 0
     for var in exog.columns:
         sign = signs[var_index % len( signs )]
         colour = colours[var_index % len( colours )]
         plt.plot( endog, exog[var], colour+sign )
         var_index += 1
     
     canvas = FigureCanvas( f )
     
     self.ui.output_vbox.pack_start( canvas, True, True, 0 )
     canvas.show()
     self.ui.output_dialog.run()
     self.ui.output_dialog.hide()
Beispiel #3
0
class Pie(ChartBase):

    def setup(self):
        fig = Figure(figsize=(10, 10), dpi=100, facecolor="white", edgecolor="white")
        self.ax = fig.add_subplot(111)
        fig.subplots_adjust(left=0.1, right=0.90, top=0.95, bottom=0.05)
        # ensure the pie is round
        self.ax.set_aspect('equal')

        matplotlib.rc('font', family="sans", weight="normal", size=9)

        self.plot = FigureCanvas(fig)
        self.pack_start(self.plot, True, True, 0)

    def draw_plot(self):
        self.ax.clear()
        self.ax.pie(self.controller.values.values(),
                    labels=self.controller.values.keys(),
                    autopct='%1.1f%%',
                    colors=self.colors
                    )
        # show pie
        self.spinner.hide()
        self.plot.show()
Beispiel #4
0
class CampaignGraph(object):
	"""
	A basic graph provider for using :py:mod:`matplotlib` to create graph
	representations of campaign data. This class is meant to be subclassed
	by real providers.
	"""
	name = 'Unknown'
	"""The name of the graph provider."""
	name_human = 'Unknown'
	"""The human readable name of the graph provider used for UI identification."""
	graph_title = 'Unknown'
	"""The title that will be given to the graph."""
	table_subscriptions = []
	"""A list of tables from which information is needed to produce the graph."""
	is_available = True
	def __init__(self, application, size_request=None, style_context=None):
		"""
		:param tuple size_request: The size to set for the canvas.
		"""
		self.application = application
		self.style_context = style_context
		self.config = application.config
		"""A reference to the King Phisher client configuration."""
		self.figure, _ = pyplot.subplots()
		self.figure.set_facecolor(self.get_color('bg', ColorHexCode.WHITE))
		self.axes = self.figure.get_axes()
		self.canvas = FigureCanvas(self.figure)
		self.manager = None
		if size_request:
			self.canvas.set_size_request(*size_request)
		self.canvas.mpl_connect('button_press_event', self.mpl_signal_canvas_button_pressed)
		self.canvas.show()
		self.navigation_toolbar = NavigationToolbar(self.canvas, self.application.get_active_window())
		self.popup_menu = Gtk.Menu.new()

		menu_item = Gtk.MenuItem.new_with_label('Export')
		menu_item.connect('activate', self.signal_activate_popup_menu_export)
		self.popup_menu.append(menu_item)

		menu_item = Gtk.MenuItem.new_with_label('Refresh')
		menu_item.connect('activate', lambda action: self.refresh())
		self.popup_menu.append(menu_item)

		menu_item = Gtk.CheckMenuItem.new_with_label('Show Toolbar')
		menu_item.connect('toggled', self.signal_toggled_popup_menu_show_toolbar)
		self._menu_item_show_toolbar = menu_item
		self.popup_menu.append(menu_item)
		self.popup_menu.show_all()
		self.navigation_toolbar.hide()
		self._legend = None

	@property
	def rpc(self):
		return self.application.rpc

	@staticmethod
	def _ax_hide_ticks(ax):
		for tick in ax.yaxis.get_major_ticks():
			tick.tick1On = False
			tick.tick2On = False

	@staticmethod
	def _ax_set_spine_color(ax, spine_color):
		for pos in ('top', 'right', 'bottom', 'left'):
			ax.spines[pos].set_color(spine_color)

	def _load_graph(self, info_cache):
		raise NotImplementedError()

	def add_legend_patch(self, legend_rows, fontsize=None):
		if self._legend is not None:
			self._legend.remove()
			self._legend = None
		if fontsize is None:
			scale = self.markersize_scale
			if scale < 5:
				fontsize = 'xx-small'
			elif scale < 7:
				fontsize = 'x-small'
			elif scale < 9:
				fontsize = 'small'
			else:
				fontsize = 'medium'
		legend_bbox = self.figure.legend(
			tuple(patches.Patch(color=patch_color) for patch_color, _ in legend_rows),
			tuple(label for _, label in legend_rows),
			borderaxespad=1.25,
			fontsize=fontsize,
			frameon=True,
			handlelength=1.5,
			handletextpad=0.75,
			labelspacing=0.3,
			loc='lower right'
		)
		legend_bbox.legendPatch.set_linewidth(0)
		self._legend = legend_bbox

	def get_color(self, color_name, default):
		"""
		Get a color by its style name such as 'fg' for foreground. If the
		specified color does not exist, default will be returned. The underlying
		logic for this function is provided by
		:py:func:`~.gui_utilities.gtk_style_context_get_color`.

		:param str color_name: The style name of the color.
		:param default: The default color to return if the specified one was not found.
		:return: The desired color if it was found.
		:rtype: tuple
		"""
		color_name = 'theme_color_graph_' + color_name
		sc_color = gui_utilities.gtk_style_context_get_color(self.style_context, color_name, default)
		return (sc_color.red, sc_color.green, sc_color.blue)

	def make_window(self):
		"""
		Create a window from the figure manager.

		:return: The graph in a new, dedicated window.
		:rtype: :py:class:`Gtk.Window`
		"""
		if self.manager is None:
			self.manager = FigureManager(self.canvas, 0)
		self.navigation_toolbar.destroy()
		self.navigation_toolbar = self.manager.toolbar
		self._menu_item_show_toolbar.set_active(True)
		window = self.manager.window
		window.set_transient_for(self.application.get_active_window())
		window.set_title(self.graph_title)
		return window

	@property
	def markersize_scale(self):
		bbox = self.axes[0].get_window_extent().transformed(self.figure.dpi_scale_trans.inverted())
		return bbox.width * self.figure.dpi * 0.01

	def mpl_signal_canvas_button_pressed(self, event):
		if event.button != 3:
			return
		self.popup_menu.popup(None, None, None, None, event.button, Gtk.get_current_event_time())
		return True

	def signal_activate_popup_menu_export(self, action):
		dialog = gui_utilities.FileChooser('Export Graph', self.application.get_active_window())
		file_name = self.config['campaign_name'] + '.png'
		response = dialog.run_quick_save(file_name)
		dialog.destroy()
		if not response:
			return
		destination_file = response['target_path']
		self.figure.savefig(destination_file, format='png')

	def signal_toggled_popup_menu_show_toolbar(self, widget):
		if widget.get_property('active'):
			self.navigation_toolbar.show()
		else:
			self.navigation_toolbar.hide()

	def load_graph(self):
		"""Load the graph information via :py:meth:`.refresh`."""
		self.refresh()

	def refresh(self, info_cache=None, stop_event=None):
		"""
		Refresh the graph data by retrieving the information from the
		remote server.

		:param dict info_cache: An optional cache of data tables.
		:param stop_event: An optional object indicating that the operation should stop.
		:type stop_event: :py:class:`threading.Event`
		:return: A dictionary of cached tables from the server.
		:rtype: dict
		"""
		info_cache = (info_cache or {})
		if not self.rpc:
			return info_cache
		for table in self.table_subscriptions:
			if stop_event and stop_event.is_set():
				return info_cache
			if not table in info_cache:
				info_cache[table] = tuple(self.rpc.remote_table(table, query_filter={'campaign_id': self.config['campaign_id']}))
		for ax in self.axes:
			ax.clear()
		if self._legend is not None:
			self._legend.remove()
			self._legend = None
		self._load_graph(info_cache)
		self.figure.suptitle(
			self.graph_title,
			color=self.get_color('fg', ColorHexCode.BLACK),
			size=14,
			weight='bold',
			y=0.97
		)
		self.canvas.draw()
		return info_cache
Beispiel #5
0
class GraphBase(object):
    """
	A basic graph provider for using :py:mod:`matplotlib` to create graph
	representations of campaign data. This class is meant to be subclassed
	by real providers.
	"""
    name = 'Unknown'
    """The name of the graph provider."""
    name_human = 'Unknown'
    """The human readable name of the graph provider used for UI identification."""
    graph_title = 'Unknown'
    """The title that will be given to the graph."""
    table_subscriptions = []
    """A list of tables from which information is needed to produce the graph."""
    is_available = True

    def __init__(self, application, size_request=None, style_context=None):
        """
		:param tuple size_request: The size to set for the canvas.
		"""
        self.application = application
        self.style_context = style_context
        self.config = application.config
        """A reference to the King Phisher client configuration."""
        self.figure, _ = pyplot.subplots()
        self.figure.set_facecolor(self.get_color('bg', ColorHexCode.WHITE))
        self.axes = self.figure.get_axes()
        self.canvas = FigureCanvas(self.figure)
        self.manager = None
        self.minimum_size = (380, 200)
        """An absolute minimum size for the canvas."""
        if size_request is not None:
            self.resize(*size_request)
        self.canvas.mpl_connect('button_press_event',
                                self.mpl_signal_canvas_button_pressed)
        self.canvas.show()
        self.navigation_toolbar = NavigationToolbar(
            self.canvas, self.application.get_active_window())
        self.popup_menu = Gtk.Menu.new()

        menu_item = Gtk.MenuItem.new_with_label('Export')
        menu_item.connect('activate', self.signal_activate_popup_menu_export)
        self.popup_menu.append(menu_item)

        menu_item = Gtk.MenuItem.new_with_label('Refresh')
        menu_item.connect('activate', self.signal_activate_popup_refresh)
        self.popup_menu.append(menu_item)

        menu_item = Gtk.CheckMenuItem.new_with_label('Show Toolbar')
        menu_item.connect('toggled',
                          self.signal_toggled_popup_menu_show_toolbar)
        self._menu_item_show_toolbar = menu_item
        self.popup_menu.append(menu_item)
        self.popup_menu.show_all()
        self.navigation_toolbar.hide()
        self._legend = None

    @property
    def rpc(self):
        return self.application.rpc

    @staticmethod
    def _ax_hide_ticks(ax):
        for tick in ax.yaxis.get_major_ticks():
            tick.tick1On = False
            tick.tick2On = False

    @staticmethod
    def _ax_set_spine_color(ax, spine_color):
        for pos in ('top', 'right', 'bottom', 'left'):
            ax.spines[pos].set_color(spine_color)

    def add_legend_patch(self, legend_rows, fontsize=None):
        if self._legend is not None:
            self._legend.remove()
            self._legend = None
        fontsize = fontsize or self.fontsize_scale
        legend_bbox = self.figure.legend(tuple(
            patches.Patch(color=patch_color)
            for patch_color, _ in legend_rows),
                                         tuple(label
                                               for _, label in legend_rows),
                                         borderaxespad=1.25,
                                         fontsize=fontsize,
                                         frameon=True,
                                         handlelength=1.5,
                                         handletextpad=0.75,
                                         labelspacing=0.3,
                                         loc='lower right')
        legend_bbox.legendPatch.set_linewidth(0)
        self._legend = legend_bbox

    def get_color(self, color_name, default):
        """
		Get a color by its style name such as 'fg' for foreground. If the
		specified color does not exist, default will be returned. The underlying
		logic for this function is provided by
		:py:func:`~.gui_utilities.gtk_style_context_get_color`.

		:param str color_name: The style name of the color.
		:param default: The default color to return if the specified one was not found.
		:return: The desired color if it was found.
		:rtype: tuple
		"""
        color_name = 'theme_color_graph_' + color_name
        sc_color = gui_utilities.gtk_style_context_get_color(
            self.style_context, color_name, default)
        return (sc_color.red, sc_color.green, sc_color.blue)

    def make_window(self):
        """
		Create a window from the figure manager.

		:return: The graph in a new, dedicated window.
		:rtype: :py:class:`Gtk.Window`
		"""
        if self.manager is None:
            self.manager = FigureManager(self.canvas, 0)
        self.navigation_toolbar.destroy()
        self.navigation_toolbar = self.manager.toolbar
        self._menu_item_show_toolbar.set_active(True)
        window = self.manager.window
        window.set_transient_for(self.application.get_active_window())
        window.set_title(self.graph_title)
        return window

    @property
    def fontsize_scale(self):
        scale = self.markersize_scale
        if scale < 5:
            fontsize = 'xx-small'
        elif scale < 7:
            fontsize = 'x-small'
        elif scale < 9:
            fontsize = 'small'
        else:
            fontsize = 'medium'
        return fontsize

    @property
    def markersize_scale(self):
        bbox = self.axes[0].get_window_extent().transformed(
            self.figure.dpi_scale_trans.inverted())
        return bbox.width * self.figure.dpi * 0.01

    def mpl_signal_canvas_button_pressed(self, event):
        if event.button != 3:
            return
        self.popup_menu.popup(None, None, None, None, event.button,
                              Gtk.get_current_event_time())
        return True

    def signal_activate_popup_menu_export(self, action):
        dialog = extras.FileChooserDialog('Export Graph',
                                          self.application.get_active_window())
        file_name = self.config['campaign_name'] + '.png'
        response = dialog.run_quick_save(file_name)
        dialog.destroy()
        if not response:
            return
        destination_file = response['target_path']
        self.figure.savefig(destination_file, format='png')

    def signal_activate_popup_refresh(self, event):
        self.refresh()

    def signal_toggled_popup_menu_show_toolbar(self, widget):
        if widget.get_property('active'):
            self.navigation_toolbar.show()
        else:
            self.navigation_toolbar.hide()

    def resize(self, width=0, height=0):
        """
		Attempt to resize the canvas. Regardless of the parameters the canvas
		will never be resized to be smaller than :py:attr:`.minimum_size`.

		:param int width: The desired width of the canvas.
		:param int height: The desired height of the canvas.
		"""
        min_width, min_height = self.minimum_size
        width = max(width, min_width)
        height = max(height, min_height)
        self.canvas.set_size_request(width, height)
Beispiel #6
0
class SenSysDemo2():
    def __init__(self, lc, ylim_correct=[-42,20], ylim_wrong=[-42,2], cmds=[]):

        self.lc = lc

        self.commands = cmds;

        self.create_queues()

        self.window = Gtk.Window(title="SenSys'17 - Packetized-LTE PHY")
        self.window.set_default_size(1200, 900)

        self.superbox = Gtk.Box()
        self.window.add(self.superbox)

        self.boxplot = Gtk.Box()
        self.superbox.pack_start(self.boxplot, True, True, 0)

        self.grid = Gtk.Grid()
        self.superbox.pack_start(self.grid, False, False, 0)

        self.boxbuttons = Gtk.Box()
        self.grid.add(self.boxbuttons)

        self.boxstats = Gtk.Box()
        self.grid.attach_next_to(self.boxstats, self.boxbuttons, Gtk.PositionType.BOTTOM, 1, 2)

        button = Gtk.Button.new_with_label("Single Link")
        button.connect("clicked", self.on_single_radio)
        self.boxbuttons.pack_start(button, True, True, 0)

        button = Gtk.Button.new_with_label("LBT Disabled")
        button.connect("clicked", self.on_lbt_disabled)
        self.boxbuttons.pack_start(button, True, True, 0)

        button = Gtk.Button.new_with_label("LBT Enabled")
        button.connect("clicked", self.on_lbt_enabled)
        self.boxbuttons.pack_start(button, True, True, 0)

        self.box = Gtk.Box()
        self.boxplot.pack_start(self.box, True, True, 0)

        scale = 10
        self.fig = Figure(figsize=(4*scale,3*scale))
        self.ax1 = self.fig.add_subplot(2, 1, 1)
        plt.grid(True)
        self.ax2 = self.fig.add_subplot(2, 1, 2)
        plt.grid(True)
        # draw and show it
        self.ax1.set_title("Successful Statistics")
        self.line1_correct, = self.ax1.plot(np.zeros(measure_lbt_performance.CORRECT_ARRAY_SIZE),'b',visible=True,label='RSSI [dBm]')
        self.line2_correct, = self.ax1.plot(np.zeros(measure_lbt_performance.CORRECT_ARRAY_SIZE),'k',visible=True,label='CQI')
        self.line3_correct, = self.ax1.plot(np.zeros(measure_lbt_performance.CORRECT_ARRAY_SIZE),'g',visible=True,label='Noise [dBm]')
        self.ax1.legend()
        self.ax1.grid(True)
        self.ax1.set_ylim(ylim_correct)
        self.ax2.set_title("Unsuccessful Statistics")
        self.line1_wrong, = self.ax2.plot(np.zeros(measure_lbt_performance.ERROR_ARRAY_SIZE),'b',visible=True,label='RSSI [dBm]')
        self.line2_wrong, = self.ax2.plot(np.zeros(measure_lbt_performance.ERROR_ARRAY_SIZE),'g',visible=True,label='Noise [dBm]')
        self.ax2.legend()
        self.ax2.grid(True)
        self.ax2.set_ylim(ylim_wrong)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.show()
        self.box.pack_start(self.canvas, True, True, 0)
        plt.ion()

        self.liststore_correct_rx = Gtk.ListStore(str, float)
        self.liststore_correct_rx.append(["In sequence %", 0.0])
        self.liststore_correct_rx.append(["Out of sequence  %", 0.0])
        self.liststore_correct_rx.append(["Correct %", 0.0])
        self.liststore_correct_rx.append(["Error %", 0.0])
        self.liststore_correct_rx.append(["Channel free %", 0.0])
        self.liststore_correct_rx.append(["Channel busy %", 0.0])
        self.liststore_correct_rx.append(["Channel free pwr", 0.0])
        self.liststore_correct_rx.append(["Channel busy pwr", 0.0])
        self.liststore_correct_rx.append(["Avg. coding time", 0.0])
        self.liststore_correct_rx.append(["Avg. # TX slots", 0.0])
        treeview = Gtk.TreeView(model=self.liststore_correct_rx)
        renderer_text = Gtk.CellRendererText()
        column_text = Gtk.TreeViewColumn("Statistics", renderer_text, text=0)
        treeview.append_column(column_text)
        renderer_spin = Gtk.CellRendererSpin()
        renderer_spin.set_property("editable", False)
        column_spin = Gtk.TreeViewColumn("Value", renderer_spin, text=1)
        treeview.append_column(column_spin)
        self.boxstats.pack_start(treeview, True, True, 0)

        gobject.idle_add(self.update_graph)

    def create_queues(self):
        self.rx_success_error_queue = queue.Queue()
        self.rx_success_plot_queue = queue.Queue()
        self.rx_error_plot_queue = queue.Queue()
        self.tx_stats_queue = queue.Queue()
        self.decoded_stats_queue = queue.Queue()

    def clear_queues(self):
        while(self.rx_success_error_queue.qsize() > 0): dumb = self.rx_success_error_queue.get()
        while(self.rx_success_plot_queue.qsize() > 0): dumb = self.rx_success_plot_queue.get()
        while(self.rx_error_plot_queue.qsize() > 0): dumb = self.rx_error_plot_queue.get()
        while(self.tx_stats_queue.qsize() > 0): dumb = self.tx_stats_queue.get()
        while(self.decoded_stats_queue.qsize() > 0): dumb = self.decoded_stats_queue.get()

    def close_all(self, widget=None, *data):
        # Do some other clean up before killing the loop.
        radio.stop_radio()
        Gtk.main_quit()
        os.system("sudo killall -9 python3")

    def init(self):
        self.window.connect("delete-event", self.close_all)
        self.window.show_all()

    def set_commands(self, cmds):
        self.commands = cmds

    def on_single_radio(self, button):
        print("Single Link")
        radio.stop_radio()
        print(self.commands[0])
        self.clear_queues()
        radio.start_radio(self.commands[0],self.lc,self)

    def on_lbt_disabled(self, button):
        print("Two Links: LBT disabled")
        radio.stop_radio()
        print(self.commands[1])
        self.clear_queues()
        radio.start_radio(self.commands[1],self.lc,self)

    def on_lbt_enabled(self, button):
        print("Two Links: LBT enabled")
        radio.stop_radio()
        print(self.commands[2])
        self.clear_queues()
        radio.start_radio(self.commands[2],self.lc,self)

    def update_graph(self):

        if(self.decoded_stats_queue.empty() == False):
            try:
                decoded = self.decoded_stats_queue.get_nowait()
                self.liststore_correct_rx[0][1] = decoded.in_sequence_percentage # In sequence
                self.liststore_correct_rx[1][1] = decoded.out_of_sequence_percentage # Out of sequence
            except queue.Empty:
                pass

        if(self.rx_success_error_queue.empty() == False):
            try:
                internal = self.rx_success_error_queue.get_nowait()
                self.liststore_correct_rx[2][1] = internal.correct # Correct
                self.liststore_correct_rx[3][1] = internal.error # Error
            except queue.Empty:
                pass

        if(self.tx_stats_queue.empty() == False):
            try:
                internal = self.tx_stats_queue.get_nowait()
                self.liststore_correct_rx[8][1] = internal.average_coding_time # average coding Time
                self.liststore_correct_rx[9][1] = internal.average_num_of_tx_slots # average number of tx slots
                self.liststore_correct_rx[4][1] = internal.channel_free_percentage # LBT Free
                self.liststore_correct_rx[5][1] = internal.channel_busy_percentage # LBT Busy
                self.liststore_correct_rx[6][1] = internal.channel_free_avg_power # Channle Free Power
                self.liststore_correct_rx[7][1] = internal.channel_busy_avg_power # Channle Busy Power
            except queue.Empty:
                pass

        if(self.rx_success_plot_queue.empty() == False):
            try:
                internal = self.rx_success_plot_queue.get_nowait()
                self.plot_correct_rx_stats(internal)
            except queue.Empty:
                pass

        if(self.rx_error_plot_queue.empty() == False):
            try:
                internal = self.rx_error_plot_queue.get_nowait()
                self.plot_wrong_rx_stats(internal)
            except queue.Empty:
                pass

        return True

    # Plot figure with correct decoding statistics.
    def plot_correct_rx_stats(self, internal):
        # set the new data.
        self.line1_correct.set_ydata(internal.correct_rssi_vector)
        self.line2_correct.set_ydata(internal.correct_cqi_vector)
        self.line3_correct.set_ydata(internal.correct_noise_vector)
        # Draw stats.
        self.fig.canvas.draw()

    # Plot figure with wrong decoding/dectection statistics.
    def plot_wrong_rx_stats(self, internal):
        # set the new data.
        self.line1_wrong.set_ydata(internal.error_rssi_vector)
        self.line2_wrong.set_ydata(internal.error_noise_vector)
        # Draw stats.
        self.fig.canvas.draw()
Beispiel #7
0
class MainWindow(Gtk.ApplicationWindow):
    def __init__(self, file_path=None):
        Gtk.Window.__init__(self)
        self.set_default_size(900, 600)
        self.set_icon_name(config.PROGRAM_NAME_LOWER)

        self.settings = Gio.Settings.new(config.GSETTINGS_BASE_KEY)

        self.circuit = None
        self.netlist_file_path = None
        self.file_monitor = None
        self.raw_data_window = console_gui.ConsoleOutputWindow(
            _("Simulation output"))
        self.execution_log_window = console_gui.ConsoleOutputWindow(
            _("Execution log"))
        self._create_menu_models()

        ##########
        #headerbar
        self.hb = Gtk.HeaderBar()
        self.hb.props.show_close_button = True

        if config.csd_are_supported() == True:
            self.set_titlebar(self.hb)
        else:  #disable headerbar as titlebar if not supported
            self.no_csd_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
            self.no_csd_box.pack_start(self.hb, False, False, 0)
            self.hb.props.show_close_button = False
            self.add(self.no_csd_box)

        ## Right side of headerbar
        self.hb_rbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                               spacing=6)

        self._add_insert_button()
        self._add_simulate_button()
        self._add_gear_button()

        self.hb.pack_end(self.hb_rbox)

        ## Left side of headerbar
        self._add_arrow_buttons()
        self._add_load_button()

        ########
        #Content
        self.stack = Gtk.Stack()
        self.stack.set_transition_type(
            Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
        self.stack.set_transition_duration(500)

        ## Overview stack
        self.overview_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.source_view = None
        self._open_state("new")

        self.infobar = None
        self.stack.add_titled(self.overview_box, "overview", _("Circuit"))

        ## Simulation stack
        self.simulation_box = Gtk.Box()
        self.canvas = Gtk.DrawingArea()
        self.simulation_box.pack_start(self.canvas, True, True, 0)
        self.stack.add_titled(self.simulation_box, "simulation",
                              _("Simulation"))

        if config.csd_are_supported() == True:
            self.add(self.stack)
        else:  #disable headerbar as titlebar if not supported
            self.no_csd_box.pack_end(self.stack, True, True, 0)

        self.overview_view()
        self.forward_button.props.sensitive = False  # HACK: self._open_state("new") sets it to
        # False but self.overview_view() sets it to
        # True. This line fixes the incongruence.

        self.connect_after('destroy', self._on_destroy)

        if file_path is not None:
            self.load_file(file_path)

    def _open_state(self, state="opened"):
        """
        show sourceview state="opened" or suggest opening a file state="new"
        """
        if state == "opened":
            self.overview_view()
            self.forward_button.props.sensitive = False  # Don go forward until having some simulations
            for child in self.overview_box.get_children():
                self.overview_box.remove(child)
            self.source_scrolled = Gtk.ScrolledWindow(None, None)
            self.source_scrolled.set_hexpand(True)
            self.source_scrolled.set_vexpand(True)

            self.source_buffer = GtkSource.Buffer()
            self.source_buffer.connect("modified-changed",
                                       self.on_source_buffer_modified_changed)
            self.source_buffer.set_highlight_syntax(True)
            self.source_buffer.set_language(
                GtkSource.LanguageManager.get_default().get_language(
                    "spice-netlist"))
            self.sourceview = GtkSource.View()
            self.settings.bind('show-line-numbers', self.sourceview,
                               'show-line-numbers',
                               Gio.SettingsBindFlags.DEFAULT)
            self.settings.bind('highlight-current-line', self.sourceview,
                               'highlight-current-line',
                               Gio.SettingsBindFlags.DEFAULT)
            font_desc = Pango.FontDescription('monospace')
            if font_desc:
                self.sourceview.modify_font(font_desc)
            self.sourceview.set_buffer(self.source_buffer)
            self.sourceview.set_show_line_numbers(True)
            self.source_scrolled.add(self.sourceview)
            self.overview_box.pack_end(self.source_scrolled, True, True, 0)
            self.overview_box.show_all()
            self.insert_button.props.sensitive = True
            self.simulate_button.props.sensitive = True
            self.lookup_action("save").props.enabled = True
        elif state == "new":
            if self.source_view is not None:
                self.overview_box.remove(self.source_scrolled)
                self.source_view = None
            else:
                self.emptyGrid = Gtk.Grid(
                    orientation=Gtk.Orientation.HORIZONTAL,
                    hexpand=True,
                    vexpand=True,
                    halign=Gtk.Align.CENTER,
                    valign=Gtk.Align.CENTER,
                    column_spacing=12,
                    margin=30)
                self.overview_box.add(self.emptyGrid)
                emptyPageImage = Gtk.Image(icon_name='document-open-symbolic',
                                           icon_size=Gtk.IconSize.DIALOG)
                emptyPageImage.get_style_context().add_class('dim-label')
                self.emptyGrid.add(emptyPageImage)
                emptyPageDirections = Gtk.Label(
                    label=_("Use the <b>Open</b> button to load a circuit"),
                    use_markup=True,
                    max_width_chars=30,
                    halign=Gtk.Align.CENTER,
                    valign=Gtk.Align.CENTER)
                emptyPageDirections.get_style_context().add_class('dim-label')
                self.emptyGrid.add(emptyPageDirections)
                self.emptyGrid.show_all()
                self.overview_box.pack_end(self.emptyGrid, True, True, 0)
                self.insert_button.props.sensitive = False
                self.simulate_button.props.sensitive = False
                self.forward_button.props.sensitive = False  # TODO: let see why this is not effective...
                self.lookup_action("save").props.enabled = False

    def _create_menu_models(self):
        # gear_menu overview xml #
        ## Create menu model
        builder = Gtk.Builder()
        builder.set_translation_domain(config.DOMAIN)
        builder.add_from_file(
            os.path.join(os.path.dirname(__file__), "data", "menu.ui"))
        self.gearmenu_overview = builder.get_object('gearmenu-overview')

        ## Bind actions
        save_action = Gio.SimpleAction.new("save", None)
        save_action.connect("activate", self.save_cb)
        self.add_action(save_action)

        close_action = Gio.SimpleAction.new("close", None)
        close_action.connect("activate", self.close_cb)
        self.add_action(close_action)

        # gear_menu simulation xml #
        ## Create menu model
        self.gearmenu_simulation = builder.get_object('gearmenu-simulation')

        ## Bind actions
        save_plot_action = Gio.SimpleAction.new("save-plot", None)
        save_plot_action.connect("activate", self.save_plot_cb)
        self.add_action(save_plot_action)

        save_data_action = Gio.SimpleAction.new("save-data", None)
        save_data_action.connect("activate", self.save_data_cb)
        self.add_action(save_data_action)

        simulation_log_action = Gio.SimpleAction.new("simulation-output", None)
        simulation_log_action.connect("activate",
                                      self.simulation_output_action_cb)
        self.add_action(simulation_log_action)

        # insert_menu_xml #
        ## Create menu model
        self.insertmenu = builder.get_object('insertmenu')

        ## Bind actions
        insert_simulation_action = Gio.SimpleAction.new(
            "insert-simulation", None)
        insert_simulation_action.connect("activate",
                                         self.insert_simulation_action)
        self.add_action(insert_simulation_action)

        insert_print_action = Gio.SimpleAction.new("insert-print", None)
        insert_print_action.connect("activate", self.insert_print_cb)
        self.add_action(insert_print_action)

        insert_model_action = Gio.SimpleAction.new("insert-model", None)
        insert_model_action.connect("activate", self.insert_model_cb)
        self.add_action(insert_model_action)

        insert_lib_action = Gio.SimpleAction.new("insert-lib", None)
        insert_lib_action.connect("activate", self.insert_lib_cb)
        self.add_action(insert_lib_action)

        insert_include_action = Gio.SimpleAction.new("insert-include", None)
        insert_include_action.connect("activate", self.insert_include_cb)
        self.add_action(insert_include_action)

    def save_cb(self, action, parameters):
        self.save_netlist_file()

    def save_plot_cb(self, action, parameters):
        dialog = Gtk.FileChooserDialog(
            _("Save plot"), self, Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE,
             Gtk.ResponseType.OK))

        png_filter = Gtk.FileFilter()
        png_filter.set_name(_("Portable Network Graphics"))
        png_filter.add_mime_type("image/png")
        dialog.add_filter(png_filter)

        svg_filter = Gtk.FileFilter()
        svg_filter.set_name(_("Scalable Vector Graphics"))
        svg_filter.add_mime_type("image/svg+xml")
        dialog.add_filter(svg_filter)

        dialog.set_current_name(self.circuit_title + " - " +
                                self.simulation_output.analysis)

        response = dialog.run()
        dialog.set_filter(png_filter)
        if response == Gtk.ResponseType.OK:
            file_name = dialog.get_filename()
            dialog.destroy()
            if file_name.split(".")[-1] == "png":
                self.figure.savefig(file_name,
                                    transparent=True,
                                    dpi=None,
                                    format="png")
            elif file_name.split(".")[-1] == "svg":
                self.figure.savefig(file_name,
                                    transparent=True,
                                    dpi=None,
                                    format="svg")
            else:
                self.figure.savefig(file_name + ".png",
                                    transparent=True,
                                    dpi=None,
                                    format="png")
                #TODO: Fix this!


#                selected_filter = dialog.get_filter()
#                if selected_filter is png_filter:
#                    self.figure.savefig(file_name+".png", transparent=True, dpi=None, format="png")
#                elif selected_filter is png_filter:
#                    self.figure.savefig(file_name+".png", transparent=True, dpi=None, format="png")
        else:
            dialog.destroy()

    def save_data_cb(self, action, parameters):
        dialog = Gtk.FileChooserDialog(
            _("Save simulation data"), self, Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE,
             Gtk.ResponseType.OK))

        csv_filter = Gtk.FileFilter()
        csv_filter.set_name(_("Comma-separated values"))
        csv_filter.add_mime_type("text/csv")
        dialog.add_filter(csv_filter)

        dialog.set_current_name(self.circuit_title + " - " +
                                self.simulation_output.analysis)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            file_name = dialog.get_filename()
            dialog.destroy()
            if file_name.split(".")[-1] != "csv":
                file_name += ".csv"
            self.simulation_output.save_csv(file_name)
        else:
            dialog.destroy()

    def simulation_output_action_cb(self, action, parameters):
        if self.raw_data_window is None:
            self.raw_data_window = console_gui.ConsoleOutputWindow(
                _("Simulation output"))
        self.raw_data_window.show_all()

    def close_cb(self, action, parameters):
        self.destroy()

    def insert_simulation_action(self, action, parameters):
        dialog = add_simulation_gui.AddSimulation(self, [])

        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            self.source_buffer.insert_at_cursor(dialog.statement)
            dialog.destroy()
        dialog.destroy()

    def insert_print_cb(self, action, parameters):
        self.source_buffer.insert_at_cursor(".print ")

    def insert_model_cb(self, action, parameters):
        self.source_buffer.insert_at_cursor(".model mname type (  )")

    def insert_lib_cb(self, action, parameters):
        self.source_buffer.insert_at_cursor(".lib filename libname")

    def insert_include_cb(self, action, parameters):
        self.source_buffer.insert_at_cursor(".include filename")

    def _add_back_button(self):
        self.back_button = Gtk.Button()
        self.back_button.add(Gtk.Arrow(Gtk.ArrowType.LEFT,
                                       Gtk.ShadowType.NONE))

        self.back_button.connect("clicked", self.on_back_button_clicked)
        self.hb.pack_start(self.back_button)
        self.back_button.props.visible = False

    def _add_gear_button(self):
        self.gear_button = Gtk.MenuButton()

        #Set content
        icon = Gio.ThemedIcon(name="emblem-system-symbolic")
        # Use open-menu-symbolic on Gtk+>=3.14
        if Gtk.check_version(3, 14, 0) is None:
            icon = Gio.ThemedIcon(name="open-menu-symbolic")
        image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.MENU)
        self.gear_button.add(image)

        # Use popover on Gtk+>=3.12
        if Gtk.check_version(3, 12, 0) is None:
            self.gear_button.set_use_popover(True)

        #Pack
        self.hb_rbox.pack_start(self.gear_button, False, False, 0)

    def _add_insert_button(self):
        self.insert_button = Gtk.MenuButton()

        #Set content
        icon = Gio.ThemedIcon(name="insert-text-symbolic")
        image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.MENU)
        self.insert_button.add(image)

        # Set menu model
        self.insert_button.props.menu_model = self.insertmenu

        # Use popover on Gtk+>=3.12
        if Gtk.check_version(3, 12, 0) is None:
            self.insert_button.set_use_popover(True)

        #Pack
        self.hb_rbox.pack_start(self.insert_button, False, False, 0)

    def _add_arrow_buttons(self):
        self.arrow_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        Gtk.StyleContext.add_class(self.arrow_box.get_style_context(),
                                   "linked")

        self.back_button = Gtk.Button()
        self.back_button.add(Gtk.Arrow(Gtk.ArrowType.LEFT,
                                       Gtk.ShadowType.NONE))
        self.arrow_box.add(self.back_button)
        self.back_button.connect("clicked", self.on_back_button_clicked)

        self.forward_button = Gtk.Button()
        self.forward_button.add(
            Gtk.Arrow(Gtk.ArrowType.RIGHT, Gtk.ShadowType.NONE))
        self.arrow_box.add(self.forward_button)
        self.forward_button.connect("clicked", self.on_forward_button_clicked)

        self.hb.pack_start(self.arrow_box)

    def _add_load_button(self):
        self.load_button = Gtk.Button()
        self.load_button.set_label(_("Open"))

        self.load_button.connect("clicked", self.on_button_open_clicked)
        self.hb.pack_start(self.load_button)

    def _add_simulate_button(self):
        self.simulate_button = Gtk.Button()
        icon = Gio.ThemedIcon(name="media-playback-start-symbolic")
        image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.MENU)
        self.simulate_button.add(image)

        self.simulate_button.connect("clicked",
                                     self.on_simulate_button_clicked)

        sim_accel = Gtk.AccelGroup()
        self.add_accel_group(sim_accel)
        self.simulate_button.add_accelerator("clicked", sim_accel, Gdk.KEY_F5,
                                             0, Gtk.AccelFlags.VISIBLE)

        self.simulate_button.props.sensitive = False
        self.hb_rbox.pack_start(self.simulate_button, False, False, 0)

    def _update_canvas(self, figure):
        self.simulation_box.remove(self.canvas)
        self.canvas = FigureCanvas(figure)  # a Gtk.DrawingArea
        self.simulation_box.pack_start(self.canvas, True, True, 0)
        self.canvas.show()

    def set_error(self,
                  title=None,
                  message=None,
                  message_type=Gtk.MessageType.ERROR,
                  actions=None):
        '''set_error(self, title=None, message=None, message_type=Gtk.MessageType.ERROR, actions=None) -> None

        Sets and shows an information bar with actions as an option.

        params:
            actions -> (button_text, response_id, callback_function)
        '''
        if self.infobar is not None:
            self.infobar.close()
        self.infobar = InfoMessageBar()
        self.infobar.set_message_type(message_type)
        self.overview_box.pack_start(self.infobar, False, True, 0)

        if title is not None:
            self.infobar.message_title = title
        else:
            self.infobar.messsage_title = ""

        if message is not None:
            self.infobar.message_subtitle = message
        else:
            self.infobar.message_subtitle = ""

        if actions is not None:
            for action in actions:
                self.infobar.add_button(action[0], action[1])
                self.infobar.user_responses[action[1]] = action[2]

        self.infobar.show_all()

    def dismiss_error(self):
        if self.infobar is not None:
            self.infobar.props.visible = False
            self.infobar = None

    def simulation_view(self):
        self.stack.set_visible_child(self.simulation_box)
        self.back_button.props.sensitive = True
        self.forward_button.props.sensitive = False
        self.load_button.props.visible = False
        self.simulate_button.props.visible = False
        self.insert_button.props.visible = False
        self.gear_button.props.menu_model = self.gearmenu_simulation

    def overview_view(self):
        self.stack.set_visible_child(self.overview_box)
        self.back_button.props.sensitive = False
        self.forward_button.props.sensitive = True
        self.load_button.props.visible = True
        self.simulate_button.props.visible = True
        self.insert_button.props.visible = True
        self.gear_button.props.menu_model = self.gearmenu_overview

    def _on_destroy(self, data):
        self.destroy()

    def on_back_button_clicked(self, button):
        self.overview_view()

    def on_forward_button_clicked(self, button):
        self.simulation_view()

    def on_simulate_button_clicked(self, button):
        # Dismiss infobar messages (if they exists)
        self.dismiss_error()
        simulator = ngspice_simulation.NgspiceAsync()
        dialog = running_dialog.RunningDialog(self, simulator.end_event)
        try:
            # First, save changes on disk
            self.save_netlist_file()
            # Start simulation
            simulator.simulatefile(self.netlist_file_path)
            # Show dialog
            if dialog.run() == 1:  # Not cancelled by the user
                if not simulator.errors:
                    self.simulation_output = ngspice_simulation.NgspiceOutput.parse_file(
                        self.netlist_file_path + ".out")
                    self.figure = self.simulation_output.get_figure()
                    self._update_canvas(self.figure)
                    self.simulation_view()
                else:
                    errors_str = [str(x) for x in simulator.errors]
                    self.set_execution_log(self.netlist_file_path,
                                           "\n".join(errors_str))
                    self.set_error(title=_("Simulation failed."),
                                   actions=[(_("Execution log"), 1000,
                                             self.on_execution_log_clicked)])
            else:
                simulator.terminate()
            self.set_output_file_content(self.netlist_file_path + ".out")
        except Exception as e:
            self.set_error(title=_("Simulation failed."), message=str(e))
        finally:
            dialog.destroy()

    def set_output_file_content(self, output_file):
        self.raw_data_window.clear_buffer()

        with open(output_file, 'r') as f:
            lines = f.readlines()
            for line in lines:
                self.raw_data_window.insert_text(line)

        self.raw_data_window.set_subtitle(output_file)

    def on_execution_log_clicked(self, button, response_id):
        if self.execution_log_window is None:
            self.execution_log_window = console_gui.ConsoleOutputWindow(
                _("Execution log"))
        self.execution_log_window.show_all()

    def set_execution_log(self, file_name, content):
        self.execution_log_window.clear_buffer()
        self.execution_log_window.insert_text(content)

        self.execution_log_window.set_subtitle(file_name)

    def start_file_monitor(self):
        if self.schematic_file_path is not None:
            path = self.schematic_file_path
        elif self.netlist_file_path is not None:
            path = self.netlist_file_path
        else:
            return
        target_file = Gio.File.new_for_path(path)
        self.file_monitor = target_file.monitor_file(Gio.FileMonitorFlags.NONE,
                                                     None)
        self.file_monitor.connect("changed", self.on_file_changed)

    def stop_file_monitor(self):
        if self.file_monitor is not None:
            self.file_monitor.cancel()

    def on_file_changed(self, file_monitor, _file, other_file, event_type):
        ''' on_file_changed(file_monitor,_file, other_file, event_type) -> None

        Callback function for file monitor on netlist file
        '''
        if event_type == Gio.FileMonitorEvent.CHANGED or event_type == Gio.FileMonitorEvent.CREATED:
            self.set_error(title=_("Opened file changed on disk."),
                           message=None,
                           message_type=Gtk.MessageType.WARNING,
                           actions=[(_("Reload"), 1000,
                                     self.on_infobar_reload_clicked)])

    def on_infobar_reload_clicked(self, button, response_id):
        if self.schematic_file_path is not None:
            self.load_file(self.schematic_file_path)
        elif self.netlist_file_path is not None:
            self.load_file(self.netlist_file_path)
        else:
            raise Exception(
                "self.schematic_file_path and self.netlist_file_path are None")

    def on_source_buffer_modified_changed(self, data):
        if self.source_buffer.get_modified():
            self.hb.set_title("* " + self.circuit_title)
        else:
            self.hb.set_title(self.circuit_title)

    def load_file(self, path):
        '''
        load a file, converts it to netlist if needed and updates program state
        '''
        self.netlist_file_path = None
        self.schematic_file_path = None
        file_content = None
        #schematic to netlist conversion

        if os.path.splitext(path)[1] == ".sch":
            # Try convert schematic to netlist
            try:
                ngspice_simulation.Gnetlist.create_netlist_file(
                    path, path + ".net")
                self.netlist_file_path = path + ".net"
                self.schematic_file_path = path
            except Exception as e:
                self.set_error(
                    title=_("Schematic could not be converted to netlist."),
                    message=str(e))
                self.netlist_file_path = None
                self.schematic_file_path = None
                return
        else:
            self.netlist_file_path = path

        # Read netlist file
        if self.netlist_file_path is not None:
            with open(self.netlist_file_path) as f:
                file_content = f.read()

        # Set a file monitor
        self.start_file_monitor()

        if file_content is not None and self.netlist_file_path is not None:
            #Set window title
            netlist = ngspice_simulation.Netlist(file_content)
            self.circuit_title = netlist.get_title()
            if self.circuit_title is not None:
                self.hb.set_title(self.circuit_title)
            else:
                self.hb.set_title("")
            self.hb.set_subtitle(self.netlist_file_path)

            # Dismiss older errors
            self.dismiss_error()

            # Set content on source view
            self._open_state("opened")
            self.source_buffer.props.text = file_content
            self.source_buffer.set_modified(False)
            self.simulate_button.props.sensitive = True
            self.canvas.show()

    def on_button_open_clicked(self, button):
        #Filechooserdialog initialization
        dialog = Gtk.FileChooserDialog(
            _("Please choose a file"), self, Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))

        netlist_filter = Gtk.FileFilter()
        netlist_filter.set_name(_("Netlist"))
        netlist_filter.add_pattern("*.net")
        netlist_filter.add_pattern("*.cir")
        netlist_filter.add_pattern("*.ckt")
        dialog.add_filter(netlist_filter)

        gschem_filter = Gtk.FileFilter()
        gschem_filter.set_name(_("GEDA schematic"))
        gschem_filter.add_mime_type("application/x-geda-schematic")
        dialog.add_filter(gschem_filter)

        all_filter = Gtk.FileFilter()
        all_filter.set_name(_("Supported files"))
        all_filter.add_pattern("*.net")
        all_filter.add_pattern("*.cir")
        all_filter.add_pattern("*.ckt")
        all_filter.add_mime_type("application/x-geda-schematic")
        dialog.add_filter(all_filter)

        dialog.set_filter(all_filter)

        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            try:
                path = dialog.get_filename()
                dialog.destroy()
                self.load_file(path)
            except Exception as e:
                self.set_error(title=_("File could not be loaded."),
                               message=str(e.message))
        else:
            dialog.destroy()

    def save_netlist_file(self):
        """Save file on self.netlist_file_path path."""
        self.stop_file_monitor()
        with open(self.netlist_file_path, "w") as f:
            f.write(self.source_buffer.props.text)
        self.start_file_monitor()
        self.source_buffer.set_modified(False)
Beispiel #8
0
class CampaignGraph(object):
	"""
	A basic graph provider for using :py:mod:`matplotlib` to create graph
	representations of campaign data. This class is meant to be subclassed
	by real providers.
	"""
	name = 'Unknown'
	"""The name of the graph provider."""
	name_human = 'Unknown'
	"""The human readable name of the graph provider used for UI identification."""
	graph_title = 'Unknown'
	"""The title that will be given to the graph."""
	table_subscriptions = []
	"""A list of tables from which information is needed to produce the graph."""
	is_available = True
	def __init__(self, config, parent, size_request=None):
		"""
		:param dict config: The King Phisher client configuration.
		:param parent: The parent window for this object.
		:type parent: :py:class:`Gtk.Window`
		:param tuple size_request: The size to set for the canvas.
		"""
		self.config = config
		"""A reference to the King Phisher client configuration."""
		self.parent = parent
		"""The parent :py:class:`Gtk.Window` instance."""
		self.figure, _ = pyplot.subplots()
		self.axes = self.figure.get_axes()
		self.canvas = FigureCanvas(self.figure)
		self.manager = None
		if size_request:
			self.canvas.set_size_request(*size_request)
		self.canvas.mpl_connect('button_press_event', self.mpl_signal_canvas_button_pressed)
		self.canvas.show()
		self.navigation_toolbar = NavigationToolbar(self.canvas, self.parent)
		self.popup_menu = Gtk.Menu.new()

		menu_item = Gtk.MenuItem.new_with_label('Export')
		menu_item.connect('activate', self.signal_activate_popup_menu_export)
		self.popup_menu.append(menu_item)

		menu_item = Gtk.MenuItem.new_with_label('Refresh')
		menu_item.connect('activate', lambda action: self.refresh())
		self.popup_menu.append(menu_item)

		menu_item = Gtk.CheckMenuItem.new_with_label('Show Toolbar')
		menu_item.connect('toggled', self.signal_toggled_popup_menu_show_toolbar)
		self._menu_item_show_toolbar = menu_item
		self.popup_menu.append(menu_item)
		self.popup_menu.show_all()
		self.navigation_toolbar.hide()

	def _load_graph(self, info_cache):
		raise NotImplementedError()

	def _graph_bar_set_yparams(self, top_lim):
		min_value = top_lim + (top_lim * 0.075)
		if min_value <= 25:
			scale = 5
		else:
			scale = scale = 10 ** (len(str(int(min_value))) - 1)
		inc_scale = scale
		while scale <= min_value:
			scale += inc_scale
		top_lim = scale

		ax = self.axes[0]
		yticks = set((round(top_lim * 0.5), top_lim))
		ax.set_yticks(tuple(yticks))
		ax.set_ylim(top=top_lim)
		return

	def _graph_null_pie(self, title):
		ax = self.axes[0]
		ax.pie((100,), labels=(title,), colors=(MPL_COLOR_NULL,), autopct='%1.0f%%', shadow=True, startangle=90)
		ax.axis('equal')
		return

	def add_legend_patch(self, legend_rows, fontsize=None):
		handles = []
		if not fontsize:
			scale = self.markersize_scale
			if scale < 5:
				fontsize = 'xx-small'
			elif scale < 7:
				fontsize = 'x-small'
			elif scale < 9:
				fontsize = 'small'
			else:
				fontsize = 'medium'
		for row in legend_rows:
			handles.append(patches.Patch(color=row[0], label=row[1]))
		self.axes[0].legend(handles=handles, fontsize=fontsize, loc='lower right')

	def graph_bar(self, bars, color=None, xticklabels=None, ylabel=None):
		"""
		Create a standard bar graph with better defaults for the standard use
		cases.

		:param list bars: The values of the bars to graph.
		:param color: The color of the bars on the graph.
		:type color: list, str
		:param list xticklabels: The labels to use on the x-axis.
		:param str ylabel: The label to give to the y-axis.
		:return: The bars created using :py:mod:`matplotlib`
		:rtype: `matplotlib.container.BarContainer`
		"""
		color = color or MPL_COLOR_NULL
		width = 0.25
		ax = self.axes[0]
		self._graph_bar_set_yparams(max(bars) if bars else 0)
		bars = ax.bar(range(len(bars)), bars, width, color=color)
		ax.set_xticks([float(x) + (width / 2) for x in range(len(bars))])
		if xticklabels:
			ax.set_xticklabels(xticklabels, rotation=30)
			for col in bars:
				height = col.get_height()
				ax.text(col.get_x() + col.get_width() / 2.0, height, "{0:,}".format(height), ha='center', va='bottom')
		if ylabel:
			ax.set_ylabel(ylabel)
		self.figure.subplots_adjust(bottom=0.25)
		return bars

	def make_window(self):
		"""
		Create a window from the figure manager.

		:return: The graph in a new, dedicated window.
		:rtype: :py:class:`Gtk.Window`
		"""
		if self.manager == None:
			self.manager = FigureManager(self.canvas, 0)
		self.navigation_toolbar.destroy()
		self.navigation_toolbar = self.manager.toolbar
		self._menu_item_show_toolbar.set_active(True)
		window = self.manager.window
		window.set_transient_for(self.parent)
		window.set_title(self.graph_title)
		return window

	@property
	def markersize_scale(self):
		bbox = self.axes[0].get_window_extent().transformed(self.figure.dpi_scale_trans.inverted())
		return max(bbox.width, bbox.width) * self.figure.dpi * 0.01

	def mpl_signal_canvas_button_pressed(self, event):
		if event.button != 3:
			return
		self.popup_menu.popup(None, None, None, None, event.button, Gtk.get_current_event_time())
		return True

	def signal_activate_popup_menu_export(self, action):
		dialog = gui_utilities.FileChooser('Export Graph', self.parent)
		file_name = self.config['campaign_name'] + '.png'
		response = dialog.run_quick_save(file_name)
		dialog.destroy()
		if not response:
			return
		destination_file = response['target_path']
		self.figure.savefig(destination_file, format='png')

	def signal_toggled_popup_menu_show_toolbar(self, widget):
		if widget.get_property('active'):
			self.navigation_toolbar.show()
		else:
			self.navigation_toolbar.hide()

	def load_graph(self):
		"""Load the graph information via :py:meth:`.refresh`."""
		self.refresh()

	def refresh(self, info_cache=None, stop_event=None):
		"""
		Refresh the graph data by retrieving the information from the
		remote server.

		:param dict info_cache: An optional cache of data tables.
		:param stop_event: An optional object indicating that the operation should stop.
		:type stop_event: :py:class:`threading.Event`
		:return: A dictionary of cached tables from the server.
		:rtype: dict
		"""
		info_cache = (info_cache or {})
		if not self.parent.rpc:
			return info_cache
		for table in self.table_subscriptions:
			if stop_event and stop_event.is_set():
				return info_cache
			if not table in info_cache:
				info_cache[table] = tuple(self.parent.rpc.remote_table('campaign/' + table, self.config['campaign_id']))
		for ax in self.axes:
			ax.clear()
		self._load_graph(info_cache)
		self.axes[0].set_title(self.graph_title, y=1.03)
		self.canvas.draw()
		return info_cache
Beispiel #9
0
class MainGUI():
    def __init__(self):
        builder = Gtk.Builder()
        builder.add_from_file("./gui/xradio_viewer.glade")
        self.mainwin = builder.get_object("mainWindow")
        self.plotwin = builder.get_object("plotWindow")
        self.mainwin.connect("delete-event", Gtk.main_quit)

        #connect_switch = builder.get_object("connect_switch")
        #connect_switch.connect("state-set", self.on_connect_switch)
        play_button = builder.get_object("playbtn1")
        play_button.connect("clicked", self.on_play_button)
        pause_button = builder.get_object("pausebtn1")
        pause_button.connect("clicked", self.on_pause_button)
        record_button = builder.get_object("record_btn1")
        record_button.connect("clicked", self.on_record_button)
        screenshot_button = builder.get_object("screenshot_btn1")
        screenshot_button.connect("clicked", self.on_screenshot_button)
        save_as_button = builder.get_object("save_btn1")
        save_as_button.connect("clicked", self.on_save_button)

        #load matrix
        mat = scio.loadmat('./gui/interfaces.mat',
                           verify_compressed_data_integrity=False)
        self.simData = np.array(mat['simulation_data'])
        # Normalize data by factor 1/0.2
        resolution = 5
        # Get data resolution
        x, y, z = self.simData.nonzero()
        # Scale by factor
        self.X, self.Y, self.Z = x / resolution, y / resolution, z / resolution
        self.fig = Figure(figsize=(9, 6), dpi=80, facecolor='w', edgecolor='k')
        self.ax = self.fig.add_subplot(111, projection='3d')
        self.ax.scatter(self.X, self.Y, self.Z, zdir='z', c='red', marker='s')
        self.ax.set_zlim(0, 3)
        self.ax.set_ylim(0, 3)
        self.ax.set_xlim(0, 4)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.show()
        self.plotwin.add(self.canvas)
        self.fig.canvas.draw()

    def update_graph(self):
        t1 = time.time()
        self.ax.cla()
        step = 0.5
        self.X, self.Y, self.Z = self.X, self.Y + step, self.Z
        self.ax.scatter(self.X, self.Y, self.Z, zdir='z', c='blue', marker='s')
        self.ax.set_zlim(0, 3)
        self.ax.set_ylim(0, 20)
        self.ax.set_xlim(0, 4)
        self.canvas.show()
        self.fig.canvas.draw()
        t2 = time.time()
        print(t2 - t1)
        return True

    def startUpdateTimer(self):
        GObject.timeout_add(100, self.update_graph)

    def on_play_button(self, button):
        print("Play Button Pressed")
        return True

    def on_pause_button(self, button):
        print("Pause Button Pressed")
        return True

    def on_screenshot_button(self, button):
        print("Screenshot Button Pressed")
        return True

    def on_save_button(self, button):
        print("Save Button Pressed")
        return True

    def on_record_button(self, button):
        print("Record Button Pressed")
        return True

    def on_connect_switch(self, switch, state):
        print("Connect Switch Pressed")
        return True
Beispiel #10
0
class MainWindow(Gtk.ApplicationWindow):

    def __init__(self, file_path=None):
        Gtk.Window.__init__(self)
        self.set_default_size(900, 600)
        self.set_icon_name(config.PROGRAM_NAME_LOWER)

        self.settings = Gio.Settings.new(config.GSETTINGS_BASE_KEY)

        self.circuit = None
        self.netlist_file_path = None
        self.file_monitor = None
        self.raw_data_window = console_gui.ConsoleOutputWindow(_("Simulation output"))
        self.execution_log_window = console_gui.ConsoleOutputWindow(_("Execution log"))
        self._create_menu_models()

        ##########
        #headerbar
        self.hb = Gtk.HeaderBar()
        self.hb.props.show_close_button = True

        if config.csd_are_supported() == True:
            self.set_titlebar(self.hb)
        else: #disable headerbar as titlebar if not supported
            self.no_csd_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
            self.no_csd_box.pack_start(self.hb, False, False, 0)
            self.hb.props.show_close_button = False
            self.add(self.no_csd_box)

        ## Right side of headerbar
        self.hb_rbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)

        self._add_insert_button()
        self._add_simulate_button()
        self._add_gear_button()

        self.hb.pack_end(self.hb_rbox)

        ## Left side of headerbar
        self._add_arrow_buttons()
        self._add_load_button()

        ########
        #Content
        self.stack = Gtk.Stack()
        self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
        self.stack.set_transition_duration(500)

        ## Overview stack
        self.overview_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.source_view = None
        self._open_state("new")

        self.infobar = None
        self.stack.add_titled(self.overview_box, "overview", _("Circuit"))

        ## Simulation stack
        self.simulation_box = Gtk.Box()
        self.canvas = Gtk.DrawingArea()
        self.simulation_box.pack_start(self.canvas, True, True, 0)
        self.stack.add_titled(self.simulation_box, "simulation", _("Simulation"))

        if config.csd_are_supported() == True:
            self.add(self.stack)
        else: #disable headerbar as titlebar if not supported
            self.no_csd_box.pack_end(self.stack, True, True, 0)

        self.overview_view()
        self.forward_button.props.sensitive = False  # HACK: self._open_state("new") sets it to
                                                     # False but self.overview_view() sets it to
                                                     # True. This line fixes the incongruence.

        self.connect_after('destroy', self._on_destroy)

        if file_path is not None:
            self.load_file(file_path)

    def _open_state(self, state="opened"):
        """
        show sourceview state="opened" or suggest opening a file state="new"
        """
        if state == "opened":
            self.overview_view()
            self.forward_button.props.sensitive = False  # Don go forward until having some simulations
            for child in self.overview_box.get_children():
                self.overview_box.remove(child)
            self.source_scrolled = Gtk.ScrolledWindow(None, None)
            self.source_scrolled.set_hexpand(True)
            self.source_scrolled.set_vexpand(True)

            self.source_buffer = GtkSource.Buffer()
            self.source_buffer.connect("modified-changed", self.on_source_buffer_modified_changed)
            self.source_buffer.set_highlight_syntax(True)
            self.source_buffer.set_language(GtkSource.LanguageManager.get_default().get_language("spice-netlist"))
            self.sourceview = GtkSource.View()
            self.settings.bind('show-line-numbers', self.sourceview, 'show-line-numbers', Gio.SettingsBindFlags.DEFAULT)
            self.settings.bind('highlight-current-line', self.sourceview, 'highlight-current-line', Gio.SettingsBindFlags.DEFAULT)
            font_desc = Pango.FontDescription('monospace')
            if font_desc:
                self.sourceview.modify_font(font_desc)
            self.sourceview.set_buffer(self.source_buffer)
            self.sourceview.set_show_line_numbers(True)
            self.source_scrolled.add(self.sourceview)
            self.overview_box.pack_end(self.source_scrolled, True, True, 0)
            self.overview_box.show_all()
            self.insert_button.props.sensitive = True
            self.simulate_button.props.sensitive = True
            self.lookup_action("save").props.enabled = True
        elif state == "new":
            if self.source_view is not None:
                self.overview_box.remove(self.source_scrolled)
                self.source_view = None
            else:
                self.emptyGrid = Gtk.Grid(orientation=Gtk.Orientation.HORIZONTAL, hexpand=True, vexpand=True, halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, column_spacing=12, margin=30)
                self.overview_box.add(self.emptyGrid);
                emptyPageImage = Gtk.Image(icon_name='document-open-symbolic', icon_size=Gtk.IconSize.DIALOG)
                emptyPageImage.get_style_context().add_class('dim-label')
                self.emptyGrid.add(emptyPageImage)
                emptyPageDirections = Gtk.Label(label=_("Use the <b>Open</b> button to load a circuit"), use_markup=True, max_width_chars=30, halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER )
                emptyPageDirections.get_style_context().add_class('dim-label');
                self.emptyGrid.add(emptyPageDirections);
                self.emptyGrid.show_all();
                self.overview_box.pack_end(self.emptyGrid, True, True, 0)
                self.insert_button.props.sensitive = False
                self.simulate_button.props.sensitive = False
                self.forward_button.props.sensitive = False # TODO: let see why this is not effective...
                self.lookup_action("save").props.enabled = False

    def _create_menu_models(self):
        # gear_menu overview xml #
        ## Create menu model
        builder = Gtk.Builder()
        builder.set_translation_domain(config.DOMAIN)
        builder.add_from_file(os.path.join(os.path.dirname(__file__), "data", "menu.ui"))
        self.gearmenu_overview = builder.get_object('gearmenu-overview')

        ## Bind actions
        save_action = Gio.SimpleAction.new("save", None)
        save_action.connect("activate", self.save_cb)
        self.add_action(save_action)

        close_action = Gio.SimpleAction.new("close", None)
        close_action.connect("activate", self.close_cb)
        self.add_action(close_action)

        # gear_menu simulation xml #
        ## Create menu model
        self.gearmenu_simulation = builder.get_object('gearmenu-simulation')

        ## Bind actions
        save_plot_action = Gio.SimpleAction.new("save-plot", None)
        save_plot_action.connect("activate", self.save_plot_cb)
        self.add_action(save_plot_action)

        save_data_action = Gio.SimpleAction.new("save-data", None)
        save_data_action.connect("activate", self.save_data_cb)
        self.add_action(save_data_action)

        simulation_log_action = Gio.SimpleAction.new("simulation-output", None)
        simulation_log_action.connect("activate", self.simulation_output_action_cb)
        self.add_action(simulation_log_action)

        # insert_menu_xml #
        ## Create menu model
        self.insertmenu = builder.get_object('insertmenu')

        ## Bind actions
        insert_simulation_action = Gio.SimpleAction.new("insert-simulation", None)
        insert_simulation_action.connect("activate", self.insert_simulation_action)
        self.add_action(insert_simulation_action)

        insert_print_action = Gio.SimpleAction.new("insert-print", None)
        insert_print_action.connect("activate", self.insert_print_cb)
        self.add_action(insert_print_action)

        insert_model_action = Gio.SimpleAction.new("insert-model", None)
        insert_model_action.connect("activate", self.insert_model_cb)
        self.add_action(insert_model_action)

        insert_lib_action = Gio.SimpleAction.new("insert-lib", None)
        insert_lib_action.connect("activate", self.insert_lib_cb)
        self.add_action(insert_lib_action)

        insert_include_action = Gio.SimpleAction.new("insert-include", None)
        insert_include_action.connect("activate", self.insert_include_cb)
        self.add_action(insert_include_action)

    def save_cb(self, action, parameters):
        self.save_netlist_file()

    def save_plot_cb(self, action, parameters):
        dialog = Gtk.FileChooserDialog(_("Save plot"), self, Gtk.FileChooserAction.SAVE,
                                       (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK))

        png_filter = Gtk.FileFilter()
        png_filter.set_name(_("Portable Network Graphics"))
        png_filter.add_mime_type("image/png")
        dialog.add_filter(png_filter)

        svg_filter = Gtk.FileFilter()
        svg_filter.set_name(_("Scalable Vector Graphics"))
        svg_filter.add_mime_type("image/svg+xml")
        dialog.add_filter(svg_filter)

        dialog.set_current_name(self.circuit_title + " - " + self.simulation_output.analysis)

        response = dialog.run()
        dialog.set_filter(png_filter)
        if response == Gtk.ResponseType.OK:
            file_name = dialog.get_filename()
            dialog.destroy()
            if file_name.split(".")[-1] == "png":
                self.figure.savefig(file_name, transparent=True, dpi=None, format="png")
            elif file_name.split(".")[-1] == "svg":
                self.figure.savefig(file_name, transparent=True, dpi=None, format="svg")
            else:
                self.figure.savefig(file_name+".png", transparent=True, dpi=None, format="png")
                #TODO: Fix this!
#                selected_filter = dialog.get_filter()
#                if selected_filter is png_filter:
#                    self.figure.savefig(file_name+".png", transparent=True, dpi=None, format="png")
#                elif selected_filter is png_filter:
#                    self.figure.savefig(file_name+".png", transparent=True, dpi=None, format="png")
        else:
            dialog.destroy()

    def save_data_cb(self, action, parameters):
        dialog = Gtk.FileChooserDialog(_("Save simulation data"), self, Gtk.FileChooserAction.SAVE,
                                       (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK))

        csv_filter = Gtk.FileFilter()
        csv_filter.set_name(_("Comma-separated values"))
        csv_filter.add_mime_type("text/csv")
        dialog.add_filter(csv_filter)

        dialog.set_current_name(self.circuit_title + " - " + self.simulation_output.analysis)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            file_name = dialog.get_filename()
            dialog.destroy()
            if file_name.split(".")[-1] != "csv":
                file_name += ".csv"
            self.simulation_output.save_csv(file_name)
        else:
            dialog.destroy()

    def simulation_output_action_cb(self, action, parameters):
        if self.raw_data_window is None:
            self.raw_data_window = console_gui.ConsoleOutputWindow(_("Simulation output"))
        self.raw_data_window.show_all()

    def close_cb(self, action, parameters):
        self.destroy()
    
    def insert_simulation_action(self, action, parameters):
        dialog = add_simulation_gui.AddSimulation(self,[])
        
        response = dialog.run()
        
        if response == Gtk.ResponseType.OK:
            self.source_buffer.insert_at_cursor(dialog.statement)
            dialog.destroy()
        dialog.destroy()

    def insert_print_cb(self, action, parameters):
        self.source_buffer.insert_at_cursor(".print ")

    def insert_model_cb(self, action, parameters):
        self.source_buffer.insert_at_cursor(".model mname type (  )")

    def insert_lib_cb(self, action, parameters):
        self.source_buffer.insert_at_cursor(".lib filename libname")

    def insert_include_cb(self, action, parameters):
        self.source_buffer.insert_at_cursor(".include filename")

    def _add_back_button(self):
        self.back_button = Gtk.Button()
        self.back_button.add(Gtk.Arrow(Gtk.ArrowType.LEFT, Gtk.ShadowType.NONE))

        self.back_button.connect("clicked", self.on_back_button_clicked)
        self.hb.pack_start(self.back_button)
        self.back_button.props.visible = False

    def _add_gear_button(self):
        self.gear_button = Gtk.MenuButton()

        #Set content
        icon = Gio.ThemedIcon(name="emblem-system-symbolic")
        # Use open-menu-symbolic on Gtk+>=3.14
        if Gtk.check_version(3, 14, 0) is None:
            icon = Gio.ThemedIcon(name="open-menu-symbolic")
        image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.MENU)
        self.gear_button.add(image)

        # Use popover on Gtk+>=3.12
        if Gtk.check_version(3, 12, 0) is None:
            self.gear_button.set_use_popover(True)

        #Pack
        self.hb_rbox.pack_start(self.gear_button, False, False, 0)

    def _add_insert_button(self):
        self.insert_button = Gtk.MenuButton()

        #Set content
        icon = Gio.ThemedIcon(name="insert-text-symbolic")
        image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.MENU)
        self.insert_button.add(image)

        # Set menu model
        self.insert_button.props.menu_model = self.insertmenu

        # Use popover on Gtk+>=3.12
        if Gtk.check_version(3, 12, 0) is None:
            self.insert_button.set_use_popover(True)

        #Pack
        self.hb_rbox.pack_start(self.insert_button, False, False, 0)

    def _add_arrow_buttons(self):
        self.arrow_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        Gtk.StyleContext.add_class(self.arrow_box.get_style_context(), "linked")

        self.back_button = Gtk.Button()
        self.back_button.add(Gtk.Arrow(Gtk.ArrowType.LEFT, Gtk.ShadowType.NONE))
        self.arrow_box.add(self.back_button)
        self.back_button.connect("clicked", self.on_back_button_clicked)

        self.forward_button = Gtk.Button()
        self.forward_button.add(Gtk.Arrow(Gtk.ArrowType.RIGHT, Gtk.ShadowType.NONE))
        self.arrow_box.add(self.forward_button)
        self.forward_button.connect("clicked", self.on_forward_button_clicked)

        self.hb.pack_start(self.arrow_box)

    def _add_load_button(self):
        self.load_button = Gtk.Button()
        self.load_button.set_label(_("Open"))

        self.load_button.connect("clicked", self.on_button_open_clicked)
        self.hb.pack_start(self.load_button)

    def _add_simulate_button(self):
        self.simulate_button = Gtk.Button()
        icon = Gio.ThemedIcon(name="media-playback-start-symbolic")
        image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.MENU)
        self.simulate_button.add(image)

        self.simulate_button.connect("clicked", self.on_simulate_button_clicked)

        sim_accel = Gtk.AccelGroup()
        self.add_accel_group(sim_accel)
        self.simulate_button.add_accelerator("clicked", sim_accel, Gdk.KEY_F5, 0, Gtk.AccelFlags.VISIBLE);

        self.simulate_button.props.sensitive = False
        self.hb_rbox.pack_start(self.simulate_button, False, False, 0)

    def _update_canvas(self, figure):
        self.simulation_box.remove(self.canvas)
        self.canvas = FigureCanvas(figure)  # a Gtk.DrawingArea
        self.simulation_box.pack_start(self.canvas, True, True, 0)
        self.canvas.show()


    def set_error(self, title=None, message=None, message_type=Gtk.MessageType.ERROR, actions=None):
        '''set_error(self, title=None, message=None, message_type=Gtk.MessageType.ERROR, actions=None) -> None

        Sets and shows an information bar with actions as an option.

        params:
            actions -> (button_text, response_id, callback_function)
        '''
        if self.infobar is not None:
            self.infobar.close()
        self.infobar = InfoMessageBar()
        self.infobar.set_message_type(message_type)
        self.overview_box.pack_start(self.infobar, False, True, 0)

        if title is not None:
            self.infobar.message_title = title
        else:
            self.infobar.messsage_title = ""

        if message is not None:
            self.infobar.message_subtitle = message
        else:
            self.infobar.message_subtitle = ""

        if actions is not None:
            for action in actions:
                self.infobar.add_button(action[0], action[1])
                self.infobar.user_responses[action[1]] = action[2]

        self.infobar.show_all()

    def dismiss_error(self):
        if self.infobar is not None:
            self.infobar.props.visible = False
            self.infobar = None

    def simulation_view(self):
        self.stack.set_visible_child(self.simulation_box)
        self.back_button.props.sensitive = True
        self.forward_button.props.sensitive = False
        self.load_button.props.visible = False
        self.simulate_button.props.visible = False
        self.insert_button.props.visible = False
        self.gear_button.props.menu_model = self.gearmenu_simulation

    def overview_view(self):
        self.stack.set_visible_child(self.overview_box)
        self.back_button.props.sensitive = False
        self.forward_button.props.sensitive = True
        self.load_button.props.visible = True
        self.simulate_button.props.visible = True
        self.insert_button.props.visible = True
        self.gear_button.props.menu_model = self.gearmenu_overview

    def _on_destroy(self, data):
        self.destroy()

    def on_back_button_clicked(self, button):
        self.overview_view()

    def on_forward_button_clicked(self, button):
        self.simulation_view()

    def on_simulate_button_clicked(self, button):
        # Dismiss infobar messages (if they exists)
        self.dismiss_error()
        simulator = ngspice_simulation.NgspiceAsync()
        dialog = running_dialog.RunningDialog(self,simulator.end_event)
        try:
            # First, save changes on disk
            self.save_netlist_file()
            # Start simulation
            simulator.simulatefile(self.netlist_file_path)
            # Show dialog
            if dialog.run() == 1: # Not cancelled by the user
                if not simulator.errors:
                    self.simulation_output = ngspice_simulation.NgspiceOutput.parse_file(self.netlist_file_path + ".out")
                    self.figure = self.simulation_output.get_figure()
                    self._update_canvas(self.figure)
                    self.simulation_view()
                else:
                    errors_str = [str(x) for x in simulator.errors]
                    self.set_execution_log(self.netlist_file_path,"\n".join(errors_str))
                    self.set_error(title=_("Simulation failed."), actions=[(_("Execution log"), 1000, self.on_execution_log_clicked)])
            else:
                simulator.terminate()
            self.set_output_file_content(self.netlist_file_path + ".out")
        except Exception as e:
            self.set_error(title=_("Simulation failed."), message=str(e))
        finally:
            dialog.destroy()

    def set_output_file_content(self, output_file):
        self.raw_data_window.clear_buffer()

        with open(output_file, 'r') as f:
            lines = f.readlines()
            for line in lines:
                self.raw_data_window.insert_text(line)

        self.raw_data_window.set_subtitle(output_file)

    def on_execution_log_clicked(self, button, response_id):
        if self.execution_log_window is None:
            self.execution_log_window = console_gui.ConsoleOutputWindow(_("Execution log"))
        self.execution_log_window.show_all()

    def set_execution_log(self, file_name, content):
        self.execution_log_window.clear_buffer()
        self.execution_log_window.insert_text(content)

        self.execution_log_window.set_subtitle(file_name)


    def start_file_monitor(self):
        if self.schematic_file_path is not None:
            path = self.schematic_file_path
        elif self.netlist_file_path is not None:
            path = self.netlist_file_path
        else:
            return
        target_file = Gio.File.new_for_path(path)
        self.file_monitor = target_file.monitor_file(Gio.FileMonitorFlags.NONE, None)
        self.file_monitor.connect("changed", self.on_file_changed)

    def stop_file_monitor(self):
        if self.file_monitor is not None:
            self.file_monitor.cancel()

    def on_file_changed(self, file_monitor, _file, other_file, event_type):
        ''' on_file_changed(file_monitor,_file, other_file, event_type) -> None

        Callback function for file monitor on netlist file
        '''
        if event_type == Gio.FileMonitorEvent.CHANGED or event_type == Gio.FileMonitorEvent.CREATED:
            self.set_error(title=_("Opened file changed on disk."), message=None, message_type=Gtk.MessageType.WARNING, actions=[(_("Reload"), 1000, self.on_infobar_reload_clicked)])

    def on_infobar_reload_clicked(self, button, response_id):
        if self.schematic_file_path is not None:
            self.load_file(self.schematic_file_path)
        elif self.netlist_file_path is not None:
            self.load_file(self.netlist_file_path)
        else:
            raise Exception("self.schematic_file_path and self.netlist_file_path are None")

    def on_source_buffer_modified_changed(self, data):
        if self.source_buffer.get_modified():
            self.hb.set_title("* " + self.circuit_title)
        else:
            self.hb.set_title(self.circuit_title)

    def load_file(self, path):
        '''
        load a file, converts it to netlist if needed and updates program state
        '''
        self.netlist_file_path = None
        self.schematic_file_path = None
        file_content = None
            #schematic to netlist conversion

        if os.path.splitext(path)[1] == ".sch":
            # Try convert schematic to netlist
            try:
                ngspice_simulation.Gnetlist.create_netlist_file(path, path + ".net")
                self.netlist_file_path = path + ".net"
                self.schematic_file_path = path
            except Exception as e:
                self.set_error(title=_("Schematic could not be converted to netlist."), message=str(e))
                self.netlist_file_path = None
                self.schematic_file_path = None
                return
        else:
            self.netlist_file_path = path

        # Read netlist file
        if self.netlist_file_path is not None:
            with open(self.netlist_file_path) as f:
                file_content = f.read()

        # Set a file monitor
        self.start_file_monitor()

        if file_content is not None and self.netlist_file_path is not None:
            #Set window title
            netlist = ngspice_simulation.Netlist(file_content)
            self.circuit_title = netlist.get_title()
            if self.circuit_title is not None:
                self.hb.set_title(self.circuit_title)
            else:
                self.hb.set_title("")
            self.hb.set_subtitle(self.netlist_file_path)

            # Dismiss older errors
            self.dismiss_error()

            # Set content on source view
            self._open_state("opened")
            self.source_buffer.props.text = file_content
            self.source_buffer.set_modified(False)
            self.simulate_button.props.sensitive = True
            self.canvas.show()

    def on_button_open_clicked(self, button):
        #Filechooserdialog initialization
        dialog = Gtk.FileChooserDialog(_("Please choose a file"), self, Gtk.FileChooserAction.OPEN,
                                       (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK))

        netlist_filter = Gtk.FileFilter()
        netlist_filter.set_name(_("Netlist"))
        netlist_filter.add_pattern("*.net")
        netlist_filter.add_pattern("*.cir")
        netlist_filter.add_pattern("*.ckt")
        dialog.add_filter(netlist_filter)

        gschem_filter = Gtk.FileFilter()
        gschem_filter.set_name(_("GEDA schematic"))
        gschem_filter.add_mime_type("application/x-geda-schematic")
        dialog.add_filter(gschem_filter)

        all_filter = Gtk.FileFilter()
        all_filter.set_name(_("Supported files"))
        all_filter.add_pattern("*.net")
        all_filter.add_pattern("*.cir")
        all_filter.add_pattern("*.ckt")
        all_filter.add_mime_type("application/x-geda-schematic")
        dialog.add_filter(all_filter)

        dialog.set_filter(all_filter)

        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            try:
                path = dialog.get_filename()
                dialog.destroy()
                self.load_file(path)
            except Exception as e:
                self.set_error(title=_("File could not be loaded."), message=str(e.message))
        else:
            dialog.destroy()

    def save_netlist_file(self):
        """Save file on self.netlist_file_path path."""
        self.stop_file_monitor()
        with open(self.netlist_file_path, "w") as f:
            f.write(self.source_buffer.props.text)
        self.start_file_monitor()
        self.source_buffer.set_modified(False)
Beispiel #11
0
class GraphBase(object):
	"""
	A basic graph provider for using :py:mod:`matplotlib` to create graph
	representations of campaign data. This class is meant to be subclassed
	by real providers.
	"""
	name = 'Unknown'
	"""The name of the graph provider."""
	name_human = 'Unknown'
	"""The human readable name of the graph provider used for UI identification."""
	graph_title = 'Unknown'
	"""The title that will be given to the graph."""
	is_available = True
	def __init__(self, application, size_request=None, style_context=None):
		"""
		:param tuple size_request: The size to set for the canvas.
		"""
		self.application = application
		self.style_context = style_context
		self.config = application.config
		"""A reference to the King Phisher client configuration."""
		self.figure, _ = pyplot.subplots()
		self.figure.set_facecolor(self.get_color('bg', ColorHexCode.WHITE))
		self.axes = self.figure.get_axes()
		self.canvas = FigureCanvas(self.figure)
		self.manager = None
		self.minimum_size = (380, 200)
		"""An absolute minimum size for the canvas."""
		if size_request is not None:
			self.resize(*size_request)
		self.canvas.mpl_connect('button_press_event', self.mpl_signal_canvas_button_pressed)
		self.canvas.show()
		self.navigation_toolbar = NavigationToolbar(self.canvas, self.application.get_active_window())

		self.popup_menu = managers.MenuManager()
		self.popup_menu.append('Export', self.signal_activate_popup_menu_export)
		self.popup_menu.append('Refresh', self.signal_activate_popup_refresh)

		menu_item = Gtk.CheckMenuItem.new_with_label('Show Toolbar')
		menu_item.connect('toggled', self.signal_toggled_popup_menu_show_toolbar)
		self._menu_item_show_toolbar = menu_item
		self.popup_menu.append_item(menu_item)

		self.navigation_toolbar.hide()
		self._legend = None

	@property
	def rpc(self):
		return self.application.rpc

	@staticmethod
	def _ax_hide_ticks(ax):
		for tick in ax.yaxis.get_major_ticks():
			tick.tick1On = False
			tick.tick2On = False

	@staticmethod
	def _ax_set_spine_color(ax, spine_color):
		for pos in ('top', 'right', 'bottom', 'left'):
			ax.spines[pos].set_color(spine_color)

	def add_legend_patch(self, legend_rows, fontsize=None):
		if self._legend is not None:
			self._legend.remove()
			self._legend = None
		fontsize = fontsize or self.fontsize_scale
		legend_bbox = self.figure.legend(
			tuple(patches.Patch(color=patch_color) for patch_color, _ in legend_rows),
			tuple(label for _, label in legend_rows),
			borderaxespad=1.25,
			fontsize=fontsize,
			frameon=True,
			handlelength=1.5,
			handletextpad=0.75,
			labelspacing=0.3,
			loc='lower right'
		)
		legend_bbox.legendPatch.set_linewidth(0)
		self._legend = legend_bbox

	def get_color(self, color_name, default):
		"""
		Get a color by its style name such as 'fg' for foreground. If the
		specified color does not exist, default will be returned. The underlying
		logic for this function is provided by
		:py:func:`~.gui_utilities.gtk_style_context_get_color`.

		:param str color_name: The style name of the color.
		:param default: The default color to return if the specified one was not found.
		:return: The desired color if it was found.
		:rtype: tuple
		"""
		color_name = 'theme_color_graph_' + color_name
		sc_color = gui_utilities.gtk_style_context_get_color(self.style_context, color_name, default)
		return (sc_color.red, sc_color.green, sc_color.blue)

	def make_window(self):
		"""
		Create a window from the figure manager.

		:return: The graph in a new, dedicated window.
		:rtype: :py:class:`Gtk.Window`
		"""
		if self.manager is None:
			self.manager = FigureManager(self.canvas, 0)
		self.navigation_toolbar.destroy()
		self.navigation_toolbar = self.manager.toolbar
		self._menu_item_show_toolbar.set_active(True)
		window = self.manager.window
		window.set_transient_for(self.application.get_active_window())
		window.set_title(self.graph_title)
		return window

	@property
	def fontsize_scale(self):
		scale = self.markersize_scale
		if scale < 5:
			fontsize = 'xx-small'
		elif scale < 7:
			fontsize = 'x-small'
		elif scale < 9:
			fontsize = 'small'
		else:
			fontsize = 'medium'
		return fontsize

	@property
	def markersize_scale(self):
		bbox = self.axes[0].get_window_extent().transformed(self.figure.dpi_scale_trans.inverted())
		return bbox.width * self.figure.dpi * 0.01

	def mpl_signal_canvas_button_pressed(self, event):
		if event.button != 3:
			return
		self.popup_menu.menu.popup(None, None, None, None, event.button, Gtk.get_current_event_time())
		return True

	def signal_activate_popup_menu_export(self, action):
		dialog = extras.FileChooserDialog('Export Graph', self.application.get_active_window())
		file_name = self.config['campaign_name'] + '.png'
		response = dialog.run_quick_save(file_name)
		dialog.destroy()
		if not response:
			return
		destination_file = response['target_path']
		self.figure.savefig(destination_file, dpi=200, facecolor=self.figure.get_facecolor(), format='png')

	def signal_activate_popup_refresh(self, event):
		self.refresh()

	def signal_toggled_popup_menu_show_toolbar(self, widget):
		if widget.get_property('active'):
			self.navigation_toolbar.show()
		else:
			self.navigation_toolbar.hide()

	def resize(self, width=0, height=0):
		"""
		Attempt to resize the canvas. Regardless of the parameters the canvas
		will never be resized to be smaller than :py:attr:`.minimum_size`.

		:param int width: The desired width of the canvas.
		:param int height: The desired height of the canvas.
		"""
		min_width, min_height = self.minimum_size
		width = max(width, min_width)
		height = max(height, min_height)
		self.canvas.set_size_request(width, height)
Beispiel #12
0
class SimpleLineChart(ChartBase):

    def setup(self):
        fig = Figure(dpi=100, facecolor="white", edgecolor="white")
        self.ax = ax = fig.add_subplot(111)
        fig.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.1)

        # gridlines
        ax.yaxis.grid(color='gray')
        ax.xaxis.grid(color='gray')

        # background
        # ax.patch.set_alpha(1)

        # font
        matplotlib.rc('font', family="sans", weight="normal", size=9)

        # frame
        ax.set_frame_on(False)

        # formatter
        formatter = FuncFormatter(gui_utils.get_currency_format_from_float)
        ax.yaxis.set_major_formatter(formatter)
        formatter = FuncFormatter(self.x_formatter)
        ax.xaxis.set_major_formatter(formatter)

        self.ax.autoscale(enable=True, axis='both', tight=True)

        # annotation
        self.annotation = ax.annotate("foo",
                xy=(0.0, 0.0), xytext=(-20, 20),
                textcoords='offset points', ha='right', va='bottom',
                color='white',
                bbox=dict(boxstyle='round,pad=0.5', color=self.colors[0]),
                # arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0')
                )
        self.annotation.set_visible(False)

        # pack
        self.plot = FigureCanvas(fig)
        self.pack_start(self.plot, True, True, 0)

        # connect events
        fig.canvas.mpl_connect('motion_notify_event', self.on_move)

    def draw_plot(self):
        # remove lines
        self.ax.lines = []
        # vertical line
        self.line = self.ax.axvline(color='gray')
        self.line.set_visible(False)
        c = 0
        x_values = range(len(self.controller.x_values))
        for key, val in self.controller.y_values:
            while len(val) < len(x_values):
                val.append(0.0)
            self.ax.plot(x_values,
                         val,
                         'o-',
                         label=key,
                         color=self.colors[c])
            c += 1

        # legend
        legend = self.ax.legend(loc="best")
        # legend.draw_frame(False)
        legend.get_frame().set_edgecolor("gray")

        # show figure
        self.spinner.hide()
        self.plot.show()

    def on_move(self, event):
        if not event.inaxes:
            self.line.set_visible(False)
            self.annotation.set_visible(False)
            event.canvas.draw()
            return

        x_val = min(int(round(event.xdata, 0)), len(self.controller.x_values) - 1)
        self.line.set_xdata(x_val)
        self.line.set_visible(True)
        self.annotation.set_visible(True)
        self.annotation.xy = x_val, event.ydata
        text = self.controller.x_values[x_val] + "\n"
        for name, vals in self.controller.y_values:
            text += name + ": " + gui_utils.get_currency_format_from_float(vals[x_val]) + "\n"
        self.annotation.set_text(text)
        event.canvas.draw()
Beispiel #13
0
class BarChart(ChartBase):

    bar_width = 0.6

    def setup(self):
        fig = Figure(figsize=(5, 5), dpi=100, facecolor="white", edgecolor="white")
        self.ax = fig.add_subplot(111)

        fig.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.2)

        # font
        matplotlib.rc('font', family="sans", weight="normal", size=9)

        # frame
        self.ax.set_frame_on(False)

        # pack fig
        self.plot = FigureCanvas(fig)
        self.pack_start(self.plot, True, True, 0)

        # connect events
        fig.canvas.mpl_connect('motion_notify_event', self.on_move)

    def draw_plot(self):
        self.ax.clear()
        # gridlines
        self.ax.yaxis.grid(color='gray')
        self.ax.xaxis.grid(color='gray')

        # annotation
        self.annotation = self.ax.annotate("",
                xy=(0.0, 0.0), xytext=(-20, 20),
                textcoords='offset points', ha='right', va='bottom',
                color='white',
                bbox=dict(boxstyle='round,pad=0.5', color=self.colors[0]),
                # arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0')
                )
        self.annotation.set_visible(False)

        self.spinner.hide()
        pos = range(len(self.controller.x_values))
        if len(self.controller.y_values) == 0:
            self.plot.show()
            return

        c = 0
        for name, vals in self.controller.y_values:
            self.ax.bar(pos,
                        vals,
                        width=self.bar_width,
                        align="center",
                        facecolor=self.colors[c],
                        linewidth=0,
                        label=name)
            c += 1
        # self.ax.set_xticklabels(self.controller.x_values)

        # formatter
        formatter = FuncFormatter(gui_utils.get_currency_format_from_float)
        self.ax.yaxis.set_major_formatter(formatter)
        formatter = FuncFormatter(self.x_formatter)
        self.ax.xaxis.set_major_formatter(formatter)

        # ensure plots with less than 5 bars look ok
        if len(pos) < 5:
            self.ax.xaxis.set_ticks(pos)

        # legend
        legend = self.ax.legend(loc="best")
        # legend.draw_frame(False)
        legend.get_frame().set_edgecolor("gray")

        # recalc limits
        self.ax.relim()
        self.ax.autoscale_view(True, True, True)

        # vertical line
        # line needs to be drawn after recalc limits
        self.line = self.ax.axvline(color='gray')
        self.line.set_visible(False)

        # show plot
        self.plot.show()

    def on_move(self, event):
        if not event.inaxes:
            self.annotation.set_visible(False)
            self.line.set_visible(False)
            event.canvas.draw()
            return

        x_val = min(int(round(event.xdata, 0)), len(self.controller.x_values) - 1)

        self.annotation.set_visible(True)
        self.line.set_visible(True)
        self.line.set_xdata(x_val)
        self.annotation.xy = x_val, event.ydata
        text = self.controller.x_values[x_val] + "\n"
        for name, vals in self.controller.y_values:
            text += name + ": " + gui_utils.get_currency_format_from_float(vals[x_val]) + "\n"
        self.annotation.set_text(text)
        event.canvas.draw()
Beispiel #14
0
class UI:
    # ====== Variables de la classe UI ========
    xn, yn = 0, 0

    # =========================================
    def __init__(self):
        # ### Initialise les datas###
        self.array_size = 10
        self.nbr_dots = 1
        # ###########################
        self.builder = Gtk.Builder()  # voir commentaires lignes 21-25
        # self.builder = gtk.Builder()
        self.builder.add_from_file(os.path.join(os.getcwd(), 'TBench_GUI_gl3.ui'))
        self.window = self.builder.get_object('dialog1')
        self.aboutdialog = self.builder.get_object('aboutdialog1')
        self.assistant = self.builder.get_object('assistant1')
        self.textview = self.builder.get_object('textview1')
        self.textbuffer = self.builder.get_object('textbuffer1')
        self.bt_exit = self.builder.get_object('bt_exit')
        self.tbt_state0 = self.builder.get_object('tbt_state0')
        self.tbt_state1 = self.builder.get_object('tbt_state1')
        self.tbt_state2 = self.builder.get_object('tbt_state2')
        self.imagemenuitem5 = self.builder.get_object('imagemenuitem5')
        self.imagemenuitem10 = self.builder.get_object('imagemenuitem10')
        self.builder.connect_signals(self)
        self.bufsize = 10  # ajout 20.02
        self.databuffer = collections.deque([0.0] * self.bufsize, self.bufsize)  # ajout 20.02
        self.x = [1 * i for i in range(-self.bufsize + 1, 1)]  # ajout 20.02(-self.bufsize+1,1)
        # Matplotlib trucs
        self.figure = Figure(figsize=(100, 100), dpi=100)
        self.ax = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self.figure)  # une gtk.DrawingArea
        self.line, = self.ax.plot(self.x, self.databuffer)
        # Gtk trucs
        self.canvas.show()
        self.graphview = self.builder.get_object("plot")
        self.graphview.pack_start(self.canvas, True, True, True)
        self.arrow = self.builder.get_object('arrow1')
        self.window.connect('delete-event', self.quit)
        self.tbt_state0.connect('toggled', self.on_button_toggled0)
        self.tbt_state1.connect('toggled', self.on_button_toggled1)
        self.tbt_state2.connect('toggled', self.on_button_toggled2)
        self.bt_exit.connect('clicked', self.quit)
        self.imagemenuitem5.connect('activate', self.quit)
        self.imagemenuitem10.connect('activate', self.show_aboutdialog)
        self.window.show()
        # ================= Recherche du port de l'arduino ====================
        self.sonde = arduino.search()
        if self.sonde == "impossible d'ouvrir un port série":
            info = (self.sonde + "!" + '\n' +
                    "quitter cette session, vérifier la connexion avec le PLC, puis relancer le programme")
            self.ajout_log_term("TB", info)
        else:
            self.ajout_log_term("PLC", self.sonde)
            self.init_arduino()  # initialise l'arduino
        # =====================================================================

    def updateplot(self):
        self.databuffer.append(UI.yn)
        self.line.set_ydata(self.databuffer)
        self.ax.relim()
        self.ax.autoscale_view(False, False, True)
        self.canvas.draw()

    def on_button_toggled0(self, button):
        if button.get_active():
            state = ['1', 'on']
            button.set_label(state[1].upper())
            self.send_command(state[0])
            self.updateplot()  # pour marquer un temps...
            UI.xn = UI.xn + 1
            UI.yn = 0.8
        else:
            state = ['0', 'off']
            button.set_label(state[1].upper())
            self.send_command(state[0])
            self.updateplot()  # pour marquer un temps...
            UI.xn = UI.xn + 1
            UI.yn = 0
        # print(UI.xn, UI.yn)
        self.updateplot()
        # self.updateplot()
        # print 'Button0 was turned: ', state[1]

    def on_button_toggled1(self, button):
        if button.get_active():
            state = ['1', 'on']
            button.set_label(state[1].upper())
            self.send_command(state[0])
        else:
            state = ['0', 'off']
            button.set_label(state[1].upper())
            self.send_command(state[0])

    def on_button_toggled2(self, button):
        if button.get_active():
            state = ['1', 'on']
            button.set_label(state[1].upper())
            self.send_command(state[0])
        else:
            state = ['0', 'off']
            button.set_label(state[1].upper())
            self.send_command(state[0])

    def show_aboutdialog(self, *args):
        self.aboutdialog.run()
        self.aboutdialog.hide()

    def show_assistant(self, *args):
        self.assistant.show()
        self.assistant.hide()

    def quit(self, *args):
        if self.sonde != "impossible d'ouvrir un port série":
            self.quit_arduino()  # réinitialise l'arduino
        # Gtk.main_quit()    # voir commentaires lignes 21-25
        Gtk.main_quit()

    def init_arduino(self):
        arduino.open()
        time.sleep(4)
        arduino.write('0')  # éteint la led si elle était allumée
        arduino.flush()

    def quit_arduino(self):
        arduino.write('0')  # éteint la led si elle était allumée
        arduino.flush()
        arduino.close()

    def send_command(self, val):
        arduino.write(val)
        self.rec = arduino.reading()
        info = ("Bascule l'état de la led PLC à " + val)
        self.ajout_log_term("TB", info)
        info = self.rec.decode('utf-8').rstrip('\n\r')
        self.ajout_log_term("PLC", info)

    def ajout_log_term(self, src, msg):
        #self.textbuffer.insert_at_cursor(src + ": " + msg + '\n')
        # text_buffer is a gtk.TextBuffer
        start_iter = self.textbuffer.get_start_iter()
        self.textbuffer.insert(start_iter, (src + ": " + msg + '\n'))
Beispiel #15
0
class Calculator():

    def __init__(self):
        self.history_ex = ["","","","","","","","","",""]
        self.hisotry_page = [0,0,0,0,0,0,0,0,0,0]
        self.x = []
        self.y = []
        self.init_gui()

    def init_gui(self):
        self.builder = Gtk.Builder()
        self.builder.add_from_file("finally.glade")

        self.builder.connect_signals( 
                                    {
                                      "window_destroy"  : self.window_destroy,
                                      "press_button"    : self.press_button,
                                      "clear_text"      : self.clear_text,
                                      "remove_last_char": self.remove_last_char,
                                      "calculate"       : self.calculate,
                                      "switch_page"     : self.switch_page,
                                      "num_base_change" : self.num_base_change,
                                      "fix_cursor"      : self.fix_cursor,
                                      "enable_textview" : self.enable_textview,
                                      "disable_textview": self.disable_textview,
                                      "prog_calc"       : self.prog_calc,
                                      "back_to_future"  : self.back_to_future,
                                      "plot"            : self.plot
                                    }
                                    )

        self.window = self.builder.get_object("main_window")
        self.window.set_size_request(250,305)
        self.window.set_title("The Calculator")
        self.window.set_icon_from_file("/usr/share/pixmaps/thecalculator-icon.png")
        self.text_buff = self.builder.get_object("class_17").get_buffer()  # Access buffer from TextView
        self.builder.get_object("class_17").grab_focus()
        self.builder.get_object("radiobutton3").set_active(True)
        self.num_base_change(self.builder.get_object("radiobutton3"))

        ############### PLOT FUNCTION ##############

        sw = self.builder.get_object("scrolledwindow1")
        sw2 = self.builder.get_object("scrolledwindow2")

        fig = Figure(figsize=(5,5),dpi=120)
        self.ax = fig.add_subplot(111)

        self.x = arange(-3.1415,3.1415,0.01)
        self.y = sin(self.x)

        self.ax.plot(self.x,self.y,label="sin(x)")
        self.ax.set_xlim(-3.2,3.2)
        self.ax.set_ylim(-1.2,1.2)
        self.ax.grid(True)

        fig.set_size_inches(9.5, 5.5, forward=True)

        fig.tight_layout()

        self.canvas = FigureCanvas(fig)
        sw.add_with_viewport(self.canvas)
        self.canvas.show()

        toolbar = NavigationToolbar(self.canvas, self.window)
        sw2.add_with_viewport(toolbar)

    def plot(self,w,data=None,from_x=-10,to_x=10):
        text = self.builder.get_object("plot_1").get_text()
        y_lim = []
        # ([+-]?\d*\.\d+|[+-]?\d+)
        # ([+-]?\d{1,})\)
        c = search("x_lim=\(([+-]?\d*\.\d+|[+-]?\d+),([+-]?\d*\.\d+|[+-]?\d+)",text)
        if (c):
            num1 = float(c.group(1))
            num2 = float(c.group(2))
            print(num1),print(type(num1))
            print(num2),print(type(num2))
            if ( num1 < num2 ):
                print("fees")
                from_x=num1
                to_x=num2
            else:
                from_x=num2
                to_x=num1

        c = search("y_lim=\(([+-]?\d*\.\d+|[+-]?\d+),([+-]?\d*\.\d+|[+-]?\d+)",text)
        if (c):
            num1 = float(c.group(1))
            num2 = float(c.group(2))
            if ( num1 < num2 ):
                y_lim.append(num1)
                y_lim.append(num2)
            else:
                y_lim.append(num2)
                y_lim.append(num1)
        
        self.x = []
        self.y = []
        self.x = arange(from_x,to_x,0.01)

        for x in self.x:
            try:
                string = text.split(",")[0].replace("x",str("(%f)"%(x)))
                tmp_number = solve_expresion(string)

                if ( type(tmp_number) != str ):
                    self.y.append(tmp_number)
                else:
                    self.y.append(None)
                    continue
            except TypeError:
                self.y.append(None)
            except Exception as e:
                print(e)
                self.builder.get_object("plot_1").set_text("Invalid synatax, use variable x")
        self.y = array(self.y)
        print(len(self.x))
        print(len(self.y))
        self.ax.plot(self.x,self.y)

        self.ax.set_xlim(from_x,to_x)
        if ( len(y_lim) == 2 ):
            print("ase")
            self.ax.set_ylim(y_lim[0],y_lim[1])
        self.ax.grid(True)
        self.canvas.draw_idle()
        # c == None podminka
        # c = re.match("(from=[-+]?(\d{1,}) to=[-+]?(\d{1,}))|(to=[-+]?(\d{1,}) from=[-+]?(\d{1,}))"
        #group(0) = founded string
        #group(1) = fouund first variante
        #group(2) = number from
        #group(3) = number to
        #group(4) = found second variante
        #group(5) = number to
        #group(6) = number from






    def back_to_future(self,w,data=None):
        if ( w.get_label() != "" ):
            self.text_buff.set_text(w.get_label())
            self.builder.get_object("notebook1").set_current_page(self.hisotry_page[self.history_ex.index(w.get_label())])  

    def add_to_history(self,expresion,page):
        if ( expresion in self.history_ex):
            return
        if ( len(self.history_ex) == 10 ):
            del(self.history_ex[0])
            del(self.hisotry_page[0])
            self.history_ex.append(expresion)
            self.hisotry_page.append(page)
        else:
            self.history_ex.append(expresion)
            self.hisotry_page.append(page)

        o = 9
        for i in self.history_ex:
            self.builder.get_object("history_"+str(o)).set_text(i)
            o-=1

    def solve_prog(self,base_string):
        try:
            base_dictionary = {"BIN":2,"OCT":8,"DEC":10,"HEX":16}

            base_string=base_string.replace("xor","^")

            for i in base_string:
                if i not in ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","~","^","&","|","+","-","/","*"," ",]:
                    return "Invalid input syntax"

            insert_base = base_dictionary[self.get_radio_state("in")]
            output_base = base_dictionary[self.get_radio_state("out")]

            base_string = prog_transfer(base_string,insert_base)
        
            output = eval(base_string, {"__builtins__":None})
        
            if output_base == insert_base:
                output = output
            elif output_base == 2:
                output = bin(int(str(output)))[2:]
            elif output_base == 8:
                output = oct(int(str(output)))[2:]
            elif output_base == 10:
                output = int(str(output))
            elif output_base == 16:
                output = hex(int(str(output)))[2:]

            return str(output).upper()

        except SyntaxError:
            return "Invalid input syntax"
        except ValueError:
            return "Invalid base"
        except:
            return "Some Error"

    def prog_calc(self,w,d=None):
        text = self.text_buff.get_text(self.text_buff.get_start_iter(),self.text_buff.get_end_iter(),False)

        if ( text == "" ):
            return

        text = text.splitlines()

        self.text_buff.set_text( text[0] + '\n' + str( self.solve_prog(text[0]) ) )
        self.text_buff.place_cursor( self.text_buff.get_iter_at_line_offset(0,len(text[0])) )

    def enable_textview(self,w,e):
        page = self.builder.get_object("notebook1").get_current_page()
        textview = ("class_17", "science_30", "prog_28")

        if ( page in [0,1,2] ):
            if ( e.keyval == Gdk.KEY_Return or e.keyval == Gdk.KEY_KP_Enter):
                self.builder.get_object( textview[page] ).set_editable(True)
                if ( page == 2 ):
                    self.prog_calc(w)
                else:
                    self.calculate(w)

    def disable_textview(self,w,e):
        # tuple with name of all textview
        page = self.builder.get_object("notebook1").get_current_page()
        textview = ("class_17", "science_30", "prog_28")

        if ( page in [0,1,2] ):
            if ( e.keyval == Gdk.KEY_Return or e.keyval == Gdk.KEY_KP_Enter):
                self.builder.get_object(textview[page]).set_editable(False)

    def fix_cursor(self,widget,data=None):
        text = self.text_buff.get_text(self.text_buff.get_start_iter(),self.text_buff.get_end_iter(),False)

        if ('\n' in text):
            if ( len(text.splitlines()) > 2):
                text = text.replace("\n","",1)
                self.text_buff.set_text(text)
            text = text.splitlines()[0]
        if ( self.text_buff.props.cursor_position > len(text) ):
            self.text_buff.place_cursor( self.text_buff.get_iter_at_line_offset(0,len(text)) )

    def calculate(self,widget,data=None):
        # except for plot
        text = self.text_buff.get_text(self.text_buff.get_start_iter(),self.text_buff.get_end_iter(),False)

        if ( text == "" ):
            return

        text = text.splitlines()

        self.text_buff.set_text( text[0] + '\n' + str( solve_expresion(text[0]) ) )
        self.text_buff.place_cursor( self.text_buff.get_iter_at_line_offset(0,len(text[0])) )
        self.add_to_history(text[0],self.builder.get_object("notebook1").get_current_page())

    def num_base_change(self,widget,data=None):
        if ( widget.get_active() == True):
            if ( widget.get_label() == "BIN" ):
                base=2
            elif ( widget.get_label() == "OCT" ):
                base=8
            elif ( widget.get_label() == "DEC" ):
                base=10
            elif (widget.get_label() == "HEX" ):
                base=16

            for i in range(16):
                if ( i < base ):
                    self.builder.get_object("prog_"+str(i)).set_sensitive(True)
                else:
                    self.builder.get_object("prog_"+str(i)).set_sensitive(False)


    def get_radio_state(self,group):
        if ( group == "in" ):
            g = self.builder.get_object("radiobutton1").get_group()
        elif ( group == "out" ):
            g = self.builder.get_object("radiobutton5").get_group()

        for i in g:
            if ( i.get_active() ):
                return i.get_label()

    def clear_text(self,widget,data=None):
        self.text_buff.set_text("")

    def window_destroy(self,widget,data=None):
        Gtk.main_quit()

    def remove_last_char(self,widget,data=None):
        text = self.text_buff.get_text(self.text_buff.get_start_iter(),self.text_buff.get_end_iter(),False)
        l_text = list(text)
        cursor_pos = self.text_buff.props.cursor_position-1
        del(l_text[cursor_pos])
        s = "".join(l_text)
        self.text_buff.set_text(s)
        self.text_buff.place_cursor(self.text_buff.get_iter_at_line_offset(0,cursor_pos))

    def show_tab(self,name,number_of_item):
        for i in range(number_of_item+1):
            self.builder.get_object(name+"_"+str(i)).show()
    def hide_tab(self,name,number_of_item):
        for i in range(number_of_item+1):
            self.builder.get_object(name+"_"+str(i)).hide()

    # @TODO focus switch textview
    def switch_page(self,widget,p1,p2):
        if ( widget.get_current_page() != 4):
            self.text_buff.set_text("")

        modes = { "class" : 0, "science" : 1, "prog" : 2, "plot" : 3, "history" : 4, "authors" : 5 }
        number_of_item = (19,30,29,2,19,0)
        size = ( (300,330),(450,320),(450,320),(800,600),(480,330),(302,330) )
        for i in modes:
            if ( p2 != modes[i] and  i!="authors"):
                self.hide_tab(i,number_of_item[modes[i]])
            else:
                self.show_tab(i,number_of_item[modes[i]])

        self.window.set_size_request(size[p2][0],size[p2][1])
        self.window.resize(size[p2][0],size[p2][1])

    def press_button(self,widget,data=None):
        char = widget.get_label()
        functions = {"√":"sqrt()","x!":"!","ln":"ln()","abs":"||","sin":"sin()","cos":"cos()","tg":"tan()","cotg":"cotg()"}
        if char in ["0","1","2","3","4","5","6","7","8","9","+","-","/","*",",","e","π","%","^","&","|","xor","~","A","B","C","D","E","F"]:
            self.text_buff.insert_at_cursor(char)
        elif char in functions:
            self.text_buff.insert_at_cursor(functions[char])
            if ( char != "x! "):
                text = self.text_buff.get_text(self.text_buff.get_start_iter(),self.text_buff.get_end_iter(),False)
                text = text.splitlines()
                self.text_buff.place_cursor( self.text_buff.get_iter_at_line_offset(0,len(text[0])-1) )

    def main(self):
        self.window.show()
        Gtk.main()
Beispiel #16
0
    def __init__(self, application):
        """ Create a summary page containing various statistics such as the number of logs in the logbook, the logbook's modification date, etc.

        :arg application: The PyQSO application containing the main Gtk window, etc.
        """

        self.application = application
        self.logbook = self.application.logbook
        self.builder = self.application.builder
        glade_file_path = join(realpath(dirname(__file__)), "res",
                               "pyqso.glade")
        self.builder.add_objects_from_file(glade_file_path, ("summary_page", ))
        self.summary_page = self.builder.get_object("summary_page")

        self.items = {}

        # Database name in large font at the top of the summary page
        self.builder.get_object("database_name").set_markup(
            "<span size=\"x-large\">%s</span>" % basename(self.logbook.path))
        self.items["LOG_COUNT"] = self.builder.get_object("log_count")
        self.items["QSO_COUNT"] = self.builder.get_object("qso_count")
        self.items["DATE_MODIFIED"] = self.builder.get_object("date_modified")

        # Yearly statistics
        config = configparser.ConfigParser()
        have_config = (config.read(
            expanduser('~/.config/pyqso/preferences.ini')) != [])
        (section, option) = ("general", "show_yearly_statistics")
        if (have_config and config.has_option(section, option)):
            if (config.getboolean("general", "show_yearly_statistics")
                    and have_matplotlib):
                hbox = Gtk.HBox()
                label = Gtk.Label(label="Display statistics for year: ",
                                  halign=Gtk.Align.START)
                hbox.pack_start(label, False, False, 6)
                year_select = Gtk.ComboBoxText()
                min_year, max_year = self.get_year_bounds()
                if min_year and max_year:
                    for year in range(max_year, min_year - 1, -1):
                        year_select.append_text(str(year))
                year_select.append_text("")
                year_select.connect("changed", self.on_year_changed)
                hbox.pack_start(year_select, False, False, 6)
                self.summary_page.pack_start(hbox, False, False, 4)

                self.items["YEARLY_STATISTICS"] = Figure()
                canvas = FigureCanvas(self.items["YEARLY_STATISTICS"])
                canvas.set_size_request(800, 175)
                canvas.show()
                self.summary_page.pack_start(canvas, True, True, 0)

        # Summary tab label and icon.
        tab = Gtk.HBox(homogeneous=False, spacing=0)
        label = Gtk.Label(label="Summary  ")
        icon = Gtk.Image.new_from_icon_name(Gtk.STOCK_INDEX, Gtk.IconSize.MENU)
        tab.pack_start(label, False, False, 0)
        tab.pack_start(icon, False, False, 0)
        tab.show_all()

        self.logbook.notebook.insert_page(self.summary_page, tab,
                                          0)  # Append as a new tab
        self.logbook.notebook.show_all()

        return
Beispiel #17
0
class CampaignGraph(object):
	"""
	A basic graph provider for using :py:mod:`matplotlib` to create graph
	representations of campaign data. This class is meant to be subclassed
	by real providers.
	"""
	name = 'Unknown'
	"""The name of the graph provider."""
	name_human = 'Unknown'
	"""The human readable name of the graph provider used for UI identification."""
	graph_title = 'Unknown'
	"""The title that will be given to the graph."""
	table_subscriptions = []
	"""A list of tables from which information is needed to produce the graph."""
	is_available = True
	def __init__(self, config, parent, size_request=None):
		"""
		:param dict config: The King Phisher client configuration.
		:param parent: The parent window for this object.
		:type parent: :py:class:`Gtk.Window`
		:param tuple size_request: The size to set for the canvas.
		"""
		self.config = config
		"""A reference to the King Phisher client configuration."""
		self.parent = parent
		"""The parent :py:class:`Gtk.Window` instance."""
		self.figure, _ = pyplot.subplots()
		self.axes = self.figure.get_axes()
		self.canvas = FigureCanvas(self.figure)
		self.manager = None
		if size_request:
			self.canvas.set_size_request(*size_request)
		self.canvas.mpl_connect('button_press_event', self.mpl_signal_canvas_button_pressed)
		self.canvas.show()
		self.navigation_toolbar = NavigationToolbar(self.canvas, self.parent)
		self.popup_menu = Gtk.Menu.new()

		menu_item = Gtk.MenuItem.new_with_label('Export')
		menu_item.connect('activate', self.signal_activate_popup_menu_export)
		self.popup_menu.append(menu_item)

		menu_item = Gtk.MenuItem.new_with_label('Refresh')
		menu_item.connect('activate', lambda action: self.refresh())
		self.popup_menu.append(menu_item)

		menu_item = Gtk.CheckMenuItem.new_with_label('Show Toolbar')
		menu_item.connect('toggled', self.signal_toggled_popup_menu_show_toolbar)
		self._menu_item_show_toolbar = menu_item
		self.popup_menu.append(menu_item)
		self.popup_menu.show_all()
		self.navigation_toolbar.hide()

	def _load_graph(self, info_cache):
		raise NotImplementedError()

	def _graph_bar_set_yparams(self, top_lim):
		min_value = top_lim + (top_lim * 0.075)
		if min_value <= 25:
			scale = 5
		else:
			scale = scale = 10 ** (len(str(int(min_value))) - 1)
		inc_scale = scale
		while scale <= min_value:
			scale += inc_scale
		top_lim = scale

		ax = self.axes[0]
		yticks = set((round(top_lim * 0.5), top_lim))
		ax.set_yticks(tuple(yticks))
		ax.set_ylim(top=top_lim)
		return

	def _graph_null_pie(self, title):
		ax = self.axes[0]
		ax.pie((100,), labels=(title,), colors=(MPL_COLOR_NULL,), autopct='%1.0f%%', shadow=True, startangle=90)
		ax.axis('equal')
		return

	def add_legend_patch(self, legend_rows, fontsize=None):
		handles = []
		if not fontsize:
			scale = self.markersize_scale
			if scale < 5:
				fontsize = 'xx-small'
			elif scale < 7:
				fontsize = 'x-small'
			elif scale < 9:
				fontsize = 'small'
			else:
				fontsize = 'medium'
		for row in legend_rows:
			handles.append(patches.Patch(color=row[0], label=row[1]))
		self.axes[0].legend(handles=handles, fontsize=fontsize, loc='lower right')

	def graph_bar(self, bars, color=None, xticklabels=None, ylabel=None):
		"""
		Create a standard bar graph with better defaults for the standard use
		cases.

		:param list bars: The values of the bars to graph.
		:param color: The color of the bars on the graph.
		:type color: list, str
		:param list xticklabels: The labels to use on the x-axis.
		:param str ylabel: The label to give to the y-axis.
		:return: The bars created using :py:mod:`matplotlib`
		:rtype: `matplotlib.container.BarContainer`
		"""
		color = color or MPL_COLOR_NULL
		width = 0.25
		ax = self.axes[0]
		self._graph_bar_set_yparams(max(bars) if bars else 0)
		bars = ax.bar(range(len(bars)), bars, width, color=color)
		ax.set_xticks([float(x) + (width / 2) for x in range(len(bars))])
		if xticklabels:
			ax.set_xticklabels(xticklabels, rotation=30)
			for col in bars:
				height = col.get_height()
				ax.text(col.get_x() + col.get_width() / 2.0, height, "{0:,}".format(height), ha='center', va='bottom')
		if ylabel:
			ax.set_ylabel(ylabel)
		self.figure.subplots_adjust(bottom=0.25)
		return bars

	def make_window(self):
		"""
		Create a window from the figure manager.

		:return: The graph in a new, dedicated window.
		:rtype: :py:class:`Gtk.Window`
		"""
		if self.manager == None:
			self.manager = FigureManager(self.canvas, 0)
		self.navigation_toolbar.destroy()
		self.navigation_toolbar = self.manager.toolbar
		self._menu_item_show_toolbar.set_active(True)
		window = self.manager.window
		window.set_transient_for(self.parent)
		window.set_title(self.graph_title)
		return window

	@property
	def markersize_scale(self):
		bbox = self.axes[0].get_window_extent().transformed(self.figure.dpi_scale_trans.inverted())
		return max(bbox.width, bbox.width) * self.figure.dpi * 0.01

	def mpl_signal_canvas_button_pressed(self, event):
		if event.button != 3:
			return
		self.popup_menu.popup(None, None, None, None, event.button, Gtk.get_current_event_time())
		return True

	def signal_activate_popup_menu_export(self, action):
		dialog = gui_utilities.UtilityFileChooser('Export Graph', self.parent)
		file_name = self.config['campaign_name'] + '.png'
		response = dialog.run_quick_save(file_name)
		dialog.destroy()
		if not response:
			return
		destination_file = response['target_path']
		self.figure.savefig(destination_file, format='png')

	def signal_toggled_popup_menu_show_toolbar(self, widget):
		if widget.get_property('active'):
			self.navigation_toolbar.show()
		else:
			self.navigation_toolbar.hide()

	def load_graph(self):
		"""Load the graph information via :py:meth:`.refresh`."""
		self.refresh()

	def refresh(self, info_cache=None, stop_event=None):
		"""
		Refresh the graph data by retrieving the information from the
		remote server.

		:param dict info_cache: An optional cache of data tables.
		:param stop_event: An optional object indicating that the operation should stop.
		:type stop_event: :py:class:`threading.Event`
		:return: A dictionary of cached tables from the server.
		:rtype: dict
		"""
		info_cache = (info_cache or {})
		if not self.parent.rpc:
			return info_cache
		for table in self.table_subscriptions:
			if stop_event and stop_event.is_set():
				return info_cache
			if not table in info_cache:
				info_cache[table] = tuple(self.parent.rpc.remote_table('campaign/' + table, self.config['campaign_id']))
		for ax in self.axes:
			ax.clear()
		self._load_graph(info_cache)
		self.axes[0].set_title(self.graph_title, y=1.03)
		self.canvas.draw()
		return info_cache
Beispiel #18
0
class CampaignGraph(object):
    """
	A basic graph provider for using :py:mod:`matplotlib` to create graph
	representations of campaign data. This class is meant to be subclassed
	by real providers.
	"""
    title = 'Unknown'
    """The title of the graph."""
    _graph_id = None
    table_subscriptions = []
    """A list of tables from which information is needed to produce the graph."""
    def __init__(self, config, parent, size_request=None):
        """
		:param dict config: The King Phisher client configuration.
		:param parent: The parent window for this object.
		:type parent: :py:class:`Gtk.Window`
		:param tuple size_request: The size to set for the canvas.
		"""
        self.config = config
        """A reference to the King Phisher client configuration."""
        self.parent = parent
        """The parent :py:class:`Gtk.Window` instance."""
        self.figure, ax = pyplot.subplots()
        self.axes = self.figure.get_axes()
        self.canvas = FigureCanvas(self.figure)
        self.manager = None
        if size_request:
            self.canvas.set_size_request(*size_request)
        self.canvas.mpl_connect('button_press_event',
                                self.mpl_signal_canvas_button_pressed)
        self.canvas.show()
        self.navigation_toolbar = NavigationToolbar(self.canvas, self.parent)
        self.navigation_toolbar.hide()
        self.popup_menu = Gtk.Menu.new()

        menu_item = Gtk.MenuItem.new_with_label('Export')
        menu_item.connect('activate', self.signal_activate_popup_menu_export)
        self.popup_menu.append(menu_item)

        menu_item = Gtk.MenuItem.new_with_label('Refresh')
        menu_item.connect('activate', lambda action: self.refresh())
        self.popup_menu.append(menu_item)

        menu_item = Gtk.CheckMenuItem.new_with_label('Show Toolbar')
        menu_item.connect('toggled',
                          self.signal_toggled_popup_menu_show_toolbar)
        self.popup_menu.append(menu_item)
        self.popup_menu.show_all()

    @classmethod
    def get_graph_id(klass):
        """
		The graph id of an exported :py:class:`.CampaignGraph`.

		:param klass: The class to return the graph id of.
		:type klass: :py:class:`.CampaignGraph`
		:return: The id of the graph.
		:rtype: int
		"""
        return klass._graph_id

    def make_window(self):
        """
		Create a window from the figure manager.

		:return: The graph in a new, dedicated window.
		:rtype: :py:class:`Gtk.Window`
		"""
        if self.manager == None:
            self.manager = FigureManager(self.canvas, 0)
        window = self.manager.window
        window.set_transient_for(self.parent)
        window.set_title(self.title)
        return window

    def mpl_signal_canvas_button_pressed(self, event):
        if event.button != 3:
            return
        self.popup_menu.popup(None, None, None, None, event.button,
                              Gtk.get_current_event_time())
        return True

    def signal_activate_popup_menu_export(self, action):
        dialog = gui_utilities.UtilityFileChooser('Export Graph', self.parent)
        file_name = self.config['campaign_name'] + '.png'
        response = dialog.run_quick_save(file_name)
        dialog.destroy()
        if not response:
            return
        destination_file = response['target_path']
        self.figure.savefig(destination_file, format='png')

    def signal_toggled_popup_menu_show_toolbar(self, widget):
        if widget.get_property('active'):
            self.navigation_toolbar.show()
        else:
            self.navigation_toolbar.hide()

    def load_graph(self):
        """Load the graph information via :py:meth:`.refresh`."""
        self.refresh()

    def refresh(self, info_cache=None, stop_event=None):
        """
		Refresh the graph data by retrieving the information from the
		remote server.

		:param dict info_cache: An optional cache of data tables.
		:param stop_event: An optional object indicating that the operation should stop.
		:type stop_event: :py:class:`threading.Event`
		:return: A dictionary of cached tables from the server.
		:rtype: dict
		"""
        info_cache = (info_cache or {})
        if not self.parent.rpc:
            return info_cache
        for table in self.table_subscriptions:
            if stop_event and stop_event.is_set():
                return info_cache
            if not table in info_cache:
                info_cache[table] = list(
                    self.parent.rpc.remote_table('campaign/' + table,
                                                 self.config['campaign_id']))
        map(lambda ax: ax.clear(), self.axes)
        self._load_graph(info_cache)
        self.canvas.draw()
        return info_cache
class StatPerspective(Gtk.Box, Ide.Perspective):
    """
    Sets up the stats perspective and handles the signals.

    This class sets up the containers of the perspective
    and the matplotlib figure and canvas. An asynchronous
    method iterates over the project and gathers the data
    for the plot.
    """
    def __init__(self, workdir, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.workdir = workdir

        # main containers
        scr_win = Gtk.ScrolledWindow(visible=True)
        pad_box = Gtk.Box(visible=True)
        pad_box.pack_start(scr_win, True, True, 20)

        main_box = Gtk.Box(visible=True, orientation=Gtk.Orientation.VERTICAL)
        scr_win.add_with_viewport(main_box)

        # content
        lbl_head = '<span font="36.0"><b>Project Stats</b></span>'
        heading = Gtk.Label(label=lbl_head, expand=True, visible=True)
        heading.set_use_markup(True)
        main_box.pack_start(heading, False, False, 0)
        line = Gtk.Separator(visible=True)
        main_box.pack_start(line, False, False, 0)

        self.fig = Figure(facecolor='none')
        self.ax = self.fig.add_subplot(111, axisbg='#ffffff')
        self.canvas = FigCanvas(self.fig)
        self.canvas.set_size_request(800, 600)
        self.canvas.draw()
        self.canvas.show()
        main_box.pack_start(self.canvas, True, True, 0)

        self.add(pad_box)
        self.titlebar = Ide.WorkbenchHeaderBar(visible=True)

        # Gather stats
        thread = threading.Thread(target=self.gather_stats)
        thread.daemon = True
        thread.start()

    def gather_stats(self):
        file_types = {}

        for root, subfolders, files in os.walk(self.workdir):
            for file in files:
                try:
                    with open(root + "/" + file) as fl:
                        line_count = 0
                        for line in fl:
                            line_count += 1

                        splt_str = file.split(".")
                        if len(splt_str) > 1:
                            file_ext = splt_str[-1]
                        else:
                            continue
                        if file_ext in file_types:
                            # key exists, add line count
                            file_types[
                                file_ext] = file_types[file_ext] + line_count
                        else:
                            # key doesn't exist, create new key
                            file_types[file_ext] = line_count
                except:
                    continue

        keys = []
        values = []

        for key, value in file_types.items():
            keys.append(key)
            values.append(value)

        key_ar = np.array(keys)
        val_ar = np.array(values).astype(int)

        ar = np.vstack((key_ar, val_ar)).T
        ar = ar[ar[:, 1].astype(int).argsort()]
        rows = ar.shape[0]
        val_pos = np.arange(1, ar.shape[0] + 1)

        self.ax.barh(val_pos, ar[:, 1].astype(int), 0.8, align="center")
        # facecolor='yellow'
        self.ax.set_yticks(val_pos)
        self.ax.tick_params(axis="both", which="major", pad=15)
        self.ax.set_yticklabels(ar[:, 0], fontsize="16", weight="bold")
        self.ax.tick_params(axis="x", which="major", labelsize="16")

        self.canvas.set_size_request(800, (rows * 20 + 50))
        self.canvas.draw()

    def do_get_id(self):
        return 'hello-world2'

    def do_get_title(self):
        return 'Hello'

    def do_get_priority(self):
        return 10000

    def do_get_icon_name(self):
        return "utilities-system-monitor-symbolic"

    def do_get_titlebar(self):
        return self.titlebar
Beispiel #20
0
class Handler:

    def __init__(self):
        global ppp

        self.window1 = builder.get_object("window1")
        self.window1.set_title("SPCinspector - No file loaded")

        self.vbox1 = builder.get_object("vbox1")
        
        self.label0 = builder.get_object("label0")
        self.label1 = builder.get_object("label1")
        self.label2 = builder.get_object("label2")
        self.label3 = builder.get_object("label3")
        self.label4 = builder.get_object("label4")
        self.label5 = builder.get_object("label5")
        self.label6 = builder.get_object("label6")
        self.label7 = builder.get_object("label7")
        self.label8 = builder.get_object("label8")
#        self.label9 = builder.get_object("label9")
#        self.label10 = builder.get_object("label10")
#        self.label11 = builder.get_object("label11")
        self.label12 = builder.get_object("label12")
        self.label13 = builder.get_object("label13")
        self.label14 = builder.get_object("label14")
        self.label15 = builder.get_object("label15")
        self.label16 = builder.get_object("label16")
        self.label17 = builder.get_object("label17")
        self.label18 = builder.get_object("label18")
        self.label19 = builder.get_object("label19")
        self.label20 = builder.get_object("label20")
        self.label21 = builder.get_object("label21")
        self.label22 = builder.get_object("label22")
        self.label23 = builder.get_object("label23")
        self.label24 = builder.get_object("label24")
        self.label25 = builder.get_object("label25")
        self.label26 = builder.get_object("label26")
        
        self.spin1 = builder.get_object("spin1") # depth
        self.spin2 = builder.get_object("spin2") # species
        self.spin3 = builder.get_object("spin3") # E-bins

        self.spin1.set_sensitive(False)
        self.spin2.set_sensitive(False)
        self.spin3.set_sensitive(False)
        
        self.button1 = builder.get_object("button1")
        self.button2 = builder.get_object("button2")
        self.button1.set_sensitive(False)
        
        self.cur_depth = 0
        self.cur_species = 0
        self.cur_ebin = 0
        
        self.spc = []
        self.path = ""
        
        fig = Figure(figsize=(5,5), dpi=100)
        #ax = fig.add_subplot(111, projection='polar')
        self.ax = fig.add_subplot(111)
        #x = [1, 2, 3, 4, 5]
        #y = [1, 4, 9, 16, 25]
        #self.ax.plot(x,y)
        self.ax.set_xlabel('Energy [MeV/u]')
        self.ax.set_ylabel('Histories')

        
        #sw = Gtk.ScrolledWindow()
        #myfirstwindow.add(sw)

        self.canvas = FigureCanvas(fig)
        self.canvas.set_size_request(600,600)
        self.vbox1.pack_end(self.canvas,True,True,True)

        self.zlut = {
            1:'H',2:'He',
            3:'Li',4:'Be',5:'B',6:'C',7:'N', 8:'O',9:'F',10:'Ne',
            11:'Na',12:'Mg',13:'Al',14:'Si',15:'P',16:'S',17:'Cl',18:'Ar',
            19:'K',20:'Ca'
        }

        print(ppp)
        if os.path.isfile(ppp):
            self.load_spc(ppp)



        
    def update_plot(self):

        d = self.spc.data[self.cur_depth]
        ds = d.species[self.cur_species]

        dse = ds.ebindata
        dsh = ds.histdata
        dsc = ds.rcumdata

        #print("NB:",len(dse),len(dsh),len(dsc))        
        
        self.ax.cla()
        self.ax.set_xlabel('Energy [MeV/u]')
        self.ax.set_ylabel('Histories')

        # plot legent in upper right corner
        text = r'$\mathregular{^{'+str(ds.la)+'}}$'+self.zlut.get(ds.lz,'?')
        self.ax.text(0.90, 0.94, text, fontsize=15,transform=self.ax.transAxes)

        #self.ax.plot(dse[1:],dsc[1:]) # cumulative sum
        self.ax.bar(dse[1:],dsh)
        self.canvas.draw()
        self.canvas.show()
        
    def onDeleteWindow(self, *args):
        Gtk.main_quit(*args)

    def onButtonPressed(self, button1):
        print("Hello World!")
        
    def main_quit(self, *args):
        print("Call Gtk.main_quit")
        Gtk.main_quit(*args)

    def on_spin1_value_changed(self,*args):
        self.cur_depth = self.spin1.get_value_as_int()-1       
        self.set_labels(self.spc)
        self.update_plot()
        
    def on_spin2_value_changed(self,*args):
        self.cur_species = self.spin2.get_value_as_int()-1
        self.set_labels(self.spc)
        self.update_plot()
        
    def on_spin3_value_changed(self,*args):
        self.cur_ebin = self.spin3.get_value_as_int()-1
        self.set_labels(self.spc)
        #self.update_plot() # no need to, as the energy marker is missing.

    def on_menuopen_activate(self,*args):
        dialog = Gtk.FileChooserDialog("Please choose a file", None,
            Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_OPEN, Gtk.ResponseType.OK))

        #self.add_filters(dialog)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            print("Open clicked")
            print("File selected: " + dialog.get_filename())
            path = dialog.get_filename()
            dialog.destroy()
            self.load_spc(path)
        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")
            dialog.destroy()
        
    def load_spc(self,path):
        spc = SPC(path)
        spc.read_spc()

        self.filename = os.path.split(path)[1]
        self.window1.set_title("SPCinspector - "+ self.filename)
        
        self.spin1.set_range(1,spc.ndsteps)
        self.spin2.set_range(1,spc.data[self.cur_depth].nparts)
        self.spin3.set_range(1,spc.data[self.cur_depth].species[self.cur_species].ne)

        self.spin1.set_sensitive(True)
        self.spin2.set_sensitive(True)
        self.spin3.set_sensitive(True)

        self.button1.set_sensitive(False) # Todo: currently disabled
        self.set_labels(spc)
        self.spc = spc

        self.update_plot()
        
    def set_labels(self,spc):
        self.label0.set_text(self.filename)
        self.label1.set_text(spc.filetype)
        self.label2.set_text(spc.fileversion)
        self.label3.set_text(spc.filedate)
        self.label4.set_text(spc.targname)
        self.label5.set_text(spc.projname)
        self.label6.set_text('{:f}'.format(spc.energy))
        self.label7.set_text('{:f}'.format(spc.peakpos))
        self.label8.set_text('{:f}'.format(spc.norm))
        # - depth
        self.label12.set_text('{:d}'.format(spc.ndsteps))

        d = spc.data[self.cur_depth]
        self.label13.set_text('{:f}'.format(d.depth))
        self.label14.set_text('{:f}'.format(d.dsnorm))

        # - species 
        self.label15.set_text('{:d}'.format(d.nparts))
        ds = d.species[self.cur_species]
        self.label16.set_text('{:f} {:f}'.format(ds.z,ds.a))
        self.label17.set_text('{:d} {:d}'.format(ds.lz,ds.la))
        self.label18.set_text('{:f}'.format(ds.dscum)) # running cum.sum over species
        self.label19.set_text('{:d}'.format(ds.nc))
        
        # - energy
        self.label20.set_text('{:d}'.format(ds.ne))
        dse = ds.ebindata[self.cur_ebin]
        if self.cur_ebin == 0:
            dsel = dse
        else:
            dsel = ds.ebindata[self.cur_ebin-1]            
        dsh = ds.histdata[self.cur_ebin]
        dsc = ds.rcumdata[self.cur_ebin]
        self.label21.set_text('{:.4f} {:.4f} {:.4f}'.format(dsel,(dsel+dse)*0.5,dse))
        self.label22.set_text('{:f}'.format(dse - dsel))
        self.label23.set_text('{:f}'.format(dsh))
        self.label24.set_text('{:f}'.format(dsh*(dse-dsel)))
        self.label25.set_text('{:f}'.format(dsc)) #cummulative sum
        self.label26.set_text('{:.2f} {:.2f}'.format(ds.ebindata.min(),ds.ebindata.max()))

    def _do_expose(self, widget, event):
        print("_do_expose")
        self.canvas.draw()
        self.canvas.show()
class StatPerspective(Gtk.Box, Ide.Perspective):

    """
    Sets up the stats perspective and handles the signals.

    This class sets up the containers of the perspective
    and the matplotlib figure and canvas. An asynchronous
    method iterates over the project and gathers the data
    for the plot.
    """

    def __init__(self, workdir, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.workdir = workdir

        # main containers
        scr_win = Gtk.ScrolledWindow(visible=True)
        pad_box = Gtk.Box(visible=True)
        pad_box.pack_start(scr_win, True, True, 20)

        main_box = Gtk.Box(visible=True, orientation=Gtk.Orientation.VERTICAL)
        scr_win.add_with_viewport(main_box)

        # content
        lbl_head = '<span font="36.0"><b>Project Stats</b></span>'
        heading = Gtk.Label(label=lbl_head, expand=True, visible=True)
        heading.set_use_markup(True)
        main_box.pack_start(heading, False, False, 0)
        line = Gtk.Separator(visible=True)
        main_box.pack_start(line, False, False, 0)

        self.fig = Figure(facecolor='none')
        self.ax = self.fig.add_subplot(111, axisbg='#ffffff')
        self.canvas = FigCanvas(self.fig)
        self.canvas.set_size_request(800, 600)
        self.canvas.draw()
        self.canvas.show()
        main_box.pack_start(self.canvas, True, True, 0)

        self.add(pad_box)
        self.titlebar = Ide.WorkbenchHeaderBar(visible=True)

         # Gather stats
        thread = threading.Thread(target=self.gather_stats)
        thread.daemon = True
        thread.start()

    def gather_stats(self):
        file_types = {}

        for root, subfolders, files in os.walk(self.workdir):
            for file in files:
                try:
                    with open(root + "/" + file) as fl:
                        line_count = 0
                        for line in fl:
                            line_count += 1

                        splt_str = file.split(".")
                        if len(splt_str) > 1:
                            file_ext = splt_str[-1]
                        else:
                            continue
                        if file_ext in file_types:
                            # key exists, add line count
                            file_types[file_ext] = file_types[file_ext] + line_count
                        else:
                            # key doesn't exist, create new key
                            file_types[file_ext] = line_count
                except:
                    continue

        keys = []
        values = []

        for key, value in file_types.items():
            keys.append(key)
            values.append(value)

        key_ar = np.array(keys)
        val_ar = np.array(values).astype(int)

        ar = np.vstack((key_ar, val_ar)).T
        ar = ar[ar[:,1].astype(int).argsort()]
        rows = ar.shape[0]
        val_pos = np.arange(1, ar.shape[0]+1)

        self.ax.barh(val_pos, ar[:,1].astype(int), 0.8, align="center")
        # facecolor='yellow'
        self.ax.set_yticks(val_pos)
        self.ax.tick_params(axis="both", which="major", pad=15)
        self.ax.set_yticklabels(ar[:,0], fontsize="16", weight="bold")
        self.ax.tick_params(axis="x", which="major", labelsize="16")

        self.canvas.set_size_request(800, (rows * 20 + 50))
        self.canvas.draw()

    def do_get_id(self):
        return 'hello-world2'

    def do_get_title(self):
        return 'Hello'

    def do_get_priority(self):
        return 10000

    def do_get_icon_name(self):
        return "utilities-system-monitor-symbolic"

    def do_get_titlebar(self):
        return self.titlebar
Beispiel #22
0
class UI:
    # ====== Variables de la classe UI ========
    xn, yn = 0, 0

    # =========================================
    def __init__(self):
        # ### Initialise les datas###
        self.array_size = 10
        self.nbr_dots = 1
        # ###########################
        self.builder = Gtk.Builder()  # voir commentaires lignes 21-25
        # self.builder = gtk.Builder()
        self.builder.add_from_file(
            os.path.join(os.getcwd(), 'TBench_GUI_gl3.ui'))
        self.window = self.builder.get_object('dialog1')
        self.aboutdialog = self.builder.get_object('aboutdialog1')
        self.assistant = self.builder.get_object('assistant1')
        self.textview = self.builder.get_object('textview1')
        self.textbuffer = self.builder.get_object('textbuffer1')
        self.bt_exit = self.builder.get_object('bt_exit')
        self.tbt_state0 = self.builder.get_object('tbt_state0')
        self.tbt_state1 = self.builder.get_object('tbt_state1')
        self.tbt_state2 = self.builder.get_object('tbt_state2')
        self.imagemenuitem5 = self.builder.get_object('imagemenuitem5')
        self.imagemenuitem10 = self.builder.get_object('imagemenuitem10')
        self.builder.connect_signals(self)
        self.bufsize = 10  # ajout 20.02
        self.databuffer = collections.deque([0.0] * self.bufsize,
                                            self.bufsize)  # ajout 20.02
        self.x = [1 * i for i in range(-self.bufsize + 1, 1)
                  ]  # ajout 20.02(-self.bufsize+1,1)
        # Matplotlib trucs
        self.figure = Figure(figsize=(100, 100), dpi=100)
        self.ax = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self.figure)  # une gtk.DrawingArea
        self.line, = self.ax.plot(self.x, self.databuffer)
        # Gtk trucs
        self.canvas.show()
        self.graphview = self.builder.get_object("plot")
        self.graphview.pack_start(self.canvas, True, True, True)
        self.arrow = self.builder.get_object('arrow1')
        self.window.connect('delete-event', self.quit)
        self.tbt_state0.connect('toggled', self.on_button_toggled0)
        self.tbt_state1.connect('toggled', self.on_button_toggled1)
        self.tbt_state2.connect('toggled', self.on_button_toggled2)
        self.bt_exit.connect('clicked', self.quit)
        self.imagemenuitem5.connect('activate', self.quit)
        self.imagemenuitem10.connect('activate', self.show_aboutdialog)
        self.window.show()
        # ================= Recherche du port de l'arduino ====================
        self.sonde = arduino.search()
        if self.sonde == "impossible d'ouvrir un port série":
            info = (
                self.sonde + "!" + '\n' +
                "quitter cette session, vérifier la connexion avec le PLC, puis relancer le programme"
            )
            self.ajout_log_term("TB", info)
        else:
            self.ajout_log_term("PLC", self.sonde)
            self.init_arduino()  # initialise l'arduino
        # =====================================================================

    def updateplot(self):
        self.databuffer.append(UI.yn)
        self.line.set_ydata(self.databuffer)
        self.ax.relim()
        self.ax.autoscale_view(False, False, True)
        self.canvas.draw()

    def on_button_toggled0(self, button):
        if button.get_active():
            state = ['1', 'on']
            button.set_label(state[1].upper())
            self.send_command(state[0])
            self.updateplot()  # pour marquer un temps...
            UI.xn = UI.xn + 1
            UI.yn = 0.8
        else:
            state = ['0', 'off']
            button.set_label(state[1].upper())
            self.send_command(state[0])
            self.updateplot()  # pour marquer un temps...
            UI.xn = UI.xn + 1
            UI.yn = 0
        # print(UI.xn, UI.yn)
        self.updateplot()
        # self.updateplot()
        # print 'Button0 was turned: ', state[1]

    def on_button_toggled1(self, button):
        if button.get_active():
            state = ['1', 'on']
            button.set_label(state[1].upper())
            self.send_command(state[0])
        else:
            state = ['0', 'off']
            button.set_label(state[1].upper())
            self.send_command(state[0])

    def on_button_toggled2(self, button):
        if button.get_active():
            state = ['1', 'on']
            button.set_label(state[1].upper())
            self.send_command(state[0])
        else:
            state = ['0', 'off']
            button.set_label(state[1].upper())
            self.send_command(state[0])

    def show_aboutdialog(self, *args):
        self.aboutdialog.run()
        self.aboutdialog.hide()

    def show_assistant(self, *args):
        self.assistant.show()
        self.assistant.hide()

    def quit(self, *args):
        if self.sonde != "impossible d'ouvrir un port série":
            self.quit_arduino()  # réinitialise l'arduino
        # Gtk.main_quit()    # voir commentaires lignes 21-25
        Gtk.main_quit()

    def init_arduino(self):
        arduino.open()
        time.sleep(4)
        arduino.write('0')  # éteint la led si elle était allumée
        arduino.flush()

    def quit_arduino(self):
        arduino.write('0')  # éteint la led si elle était allumée
        arduino.flush()
        arduino.close()

    def send_command(self, val):
        arduino.write(val)
        self.rec = arduino.reading()
        info = ("Bascule l'état de la led PLC à " + val)
        self.ajout_log_term("TB", info)
        info = self.rec.decode('utf-8').rstrip('\n\r')
        self.ajout_log_term("PLC", info)

    def ajout_log_term(self, src, msg):
        #self.textbuffer.insert_at_cursor(src + ": " + msg + '\n')
        # text_buffer is a gtk.TextBuffer
        start_iter = self.textbuffer.get_start_iter()
        self.textbuffer.insert(start_iter, (src + ": " + msg + '\n'))