def __init__(self, parent, hosts): """Prepare the host dialog""" self.hosts = hosts # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('host.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_host.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position(self.ui.dialog_host, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels if widget.get_label(): widget.set_label(text(widget.get_label())) else: widget.set_label(text(widget.get_short_label())) # Initialize labels for widget in self.ui.get_objects_by_type(Gtk.Label): widget.set_label(text(widget.get_label())) widget.set_tooltip_text(widget.get_label().replace('_', '')) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) self.selected_iter = None self.model_devices = ModelDevices(self.ui.store_devices) # Connect signals from the glade file to the module functions self.ui.connect_signals(self)
def __init__(self, parent, groups): """Prepare the group detail dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('group_detail.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_edit_group.set_transient_for(parent) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize labels for widget in self.ui.get_objects_by_type(Gtk.Label): widget.set_label(text(widget.get_label())) widget.set_tooltip_text(widget.get_label().replace('_', '')) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) self.model = groups self.name = '' # Connect signals from the glade file to the module functions self.ui.connect_signals(self)
def __init__(self, parent): """Prepare the devices dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('devices.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_devices.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position(self.ui.dialog_devices, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Load the devices self.model = ModelDevices(self.ui.store_devices) self.selected_iter = None # Sort the data in the models self.model.model.set_sort_column_id( self.ui.column_name.get_sort_column_id(), Gtk.SortType.ASCENDING) # Connect signals from the glade file to the module functions self.ui.connect_signals(self)
def __init__(self, parent, services): """Prepare the services detail dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('service_detail.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_edit_service.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position( self.ui.dialog_edit_service, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize labels for widget in self.ui.get_objects_by_type(Gtk.Label): widget.set_label(text(widget.get_label())) widget.set_tooltip_text(widget.get_label().replace('_', '')) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) self.model = services self.selected_iter = None self.name = '' self.description = '' # Connect signals from the glade file to the module functions self.ui.connect_signals(self)
def __init__(self, parent): """Prepare the devices dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('devices.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_devices.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position( self.ui.dialog_devices, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Load the devices self.model = ModelDevices(self.ui.store_devices) self.selected_iter = None # Sort the data in the models self.model.model.set_sort_column_id( self.ui.column_name.get_sort_column_id(), Gtk.SortType.ASCENDING) # Connect signals from the glade file to the module functions self.ui.connect_signals(self)
def __init__(self, parent, hosts): """Prepare the host dialog""" self.hosts = hosts # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('host.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_host.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position( self.ui.dialog_host, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels if widget.get_label(): widget.set_label(text(widget.get_label())) else: widget.set_label(text(widget.get_short_label())) # Initialize labels for widget in self.ui.get_objects_by_type(Gtk.Label): widget.set_label(text(widget.get_label())) widget.set_tooltip_text(widget.get_label().replace('_', '')) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) self.selected_iter = None self.model_devices = ModelDevices(self.ui.store_devices) # Connect signals from the glade file to the module functions self.ui.connect_signals(self)
def __init__(self, parent, host): """Prepare the snmp values dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('snmp_values.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.window_snmp.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position(self.ui.window_snmp, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels if widget.get_label(): widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Initialize services self.model = SNMPValues(self.ui.store_values) self.services = {} for service in model_devices.devices[host.device].services: oid = model_services.services[service].numeric_oid self.services[service] = oid value = SNMPValueInfo(name=service, value='', timestamp=0) self.model.add_data(value) # Sort the data in the models self.model.model.set_sort_column_id( self.ui.column_name.get_sort_column_id(), Gtk.SortType.ASCENDING) self.host = host self.ui.window_snmp.set_title(_('SNMP values for %s') % host.name) self.semaphore = None self.completed_threads = 0 # Connect signals from the glade file to the module functions self.ui.connect_signals(self)
def loadUI(self): """Load the interface UI""" self.ui = GtkBuilderLoader(get_ui_file('main.glade')) self.ui.win_main.set_application(self.application) self.ui.win_main.set_title(APP_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.ToolButton): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Set list items row height icon_size = preferences.ICON_SIZE self.ui.cell_name.props.height = preferences.get(icon_size) self.ui.cell_group_name.props.height = preferences.get(icon_size) # Set groups visibility self.ui.scroll_groups.set_visible( preferences.get(preferences.GROUPS_SHOW)) # Add a Gtk.Headerbar, only for GTK+ 3.10.0 and higher if (not Gtk.check_version(3, 10, 0) and not preferences.get(preferences.HEADERBARS_DISABLE)): self.load_ui_headerbar() if preferences.get(preferences.HEADERBARS_REMOVE_TOOLBAR): # This is only for development, it should always be True # Remove the redundant toolbar self.ui.toolbar_main.destroy() # Flatten the Gtk.ScrolledWindows self.ui.scroll_groups.set_shadow_type(Gtk.ShadowType.NONE) self.ui.scroll_connections.set_shadow_type(Gtk.ShadowType.NONE) # Connect signals from the glade file to the module functions self.ui.connect_signals(self)
def startup(self, application): """Configure the application during the startup""" self.ui = UIMain(self) # Add the about action to the app menu action = Gio.SimpleAction(name="settings_folder") action.connect("activate", self.on_app_settings_folder_activate) self.add_action(action) # Add the about action to the app menu action = Gio.SimpleAction(name="about") action.connect("activate", self.on_app_about_activate) self.add_action(action) # Add the quit action to the app menu action = Gio.SimpleAction(name="quit") action.connect("activate", self.on_app_quit_activate) self.add_action(action) # Add the app menu builder_appmenu = GtkBuilderLoader(get_ui_file('appmenu.ui')) self.set_app_menu(builder_appmenu.app_menu)
def __init__(self, parent, host): """Prepare the snmp values dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('snmp_values.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.window_snmp.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position( self.ui.window_snmp, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels if widget.get_label(): widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Initialize services self.model = SNMPValues(self.ui.store_values) self.services = {} for service in model_devices.devices[host.device].services: oid = model_services.services[service].numeric_oid self.services[service] = oid value = SNMPValueInfo(name=service, value='', timestamp=0) self.model.add_data(value) # Sort the data in the models self.model.model.set_sort_column_id( self.ui.column_name.get_sort_column_id(), Gtk.SortType.ASCENDING) self.host = host self.ui.window_snmp.set_title(_('SNMP values for %s') % host.name) self.semaphore = None self.completed_threads = 0 # Connect signals from the glade file to the module functions self.ui.connect_signals(self)
def __init__(self, parent): """Prepare the about dialog""" # Retrieve the translators list translators = [] for line in readlines(FILE_TRANSLATORS, False): if ':' in line: line = line.split(':', 1)[1] line = line.replace('(at)', '@').strip() if line not in translators: translators.append(line) # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('about.glade')) # Set various properties self.ui.dialog_about.set_program_name(APP_NAME) self.ui.dialog_about.set_version('Version %s' % APP_VERSION) self.ui.dialog_about.set_comments(APP_DESCRIPTION) self.ui.dialog_about.set_website(APP_URL) self.ui.dialog_about.set_copyright(APP_COPYRIGHT) # Prepare lists for authors and contributors authors = ['%s <%s>' % (APP_AUTHOR, APP_AUTHOR_EMAIL)] contributors = [] for line in readlines(FILE_CONTRIBUTORS, False): contributors.append(line) if len(contributors) > 0: contributors.insert(0, _('Contributors:')) authors.extend(contributors) self.ui.dialog_about.set_authors(authors) self.ui.dialog_about.set_license('\n'.join( readlines(FILE_LICENSE, True))) self.ui.dialog_about.set_translator_credits('\n'.join(translators)) # Retrieve the external resources links # only for GTK+ 3.6.0 and higher if not Gtk.check_version(3, 6, 0): for line in readlines(FILE_RESOURCES, False): resource_type, resource_url = line.split(':', 1) self.ui.dialog_about.add_credit_section( resource_type, (resource_url, )) icon_logo = Pixbuf.new_from_file(FILE_ICON) self.ui.dialog_about.set_logo(icon_logo) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_about.set_transient_for(parent)
class UISNMPValues(object): def __init__(self, parent, host): """Prepare the snmp values dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('snmp_values.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.window_snmp.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position(self.ui.window_snmp, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels if widget.get_label(): widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Initialize services self.model = SNMPValues(self.ui.store_values) self.services = {} for service in model_devices.devices[host.device].services: oid = model_services.services[service].numeric_oid self.services[service] = oid value = SNMPValueInfo(name=service, value='', timestamp=0) self.model.add_data(value) # Sort the data in the models self.model.model.set_sort_column_id( self.ui.column_name.get_sort_column_id(), Gtk.SortType.ASCENDING) self.host = host self.ui.window_snmp.set_title(_('SNMP values for %s') % host.name) self.semaphore = None self.completed_threads = 0 # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def show(self): """Show the Groups dialog""" self.ui.window_snmp.show() def destroy(self): """Destroy the Groups dialog""" settings.positions.save_window_position(self.ui.window_snmp, SECTION_WINDOW_NAME) self.ui.window_snmp.hide() self.ui.window_snmp.destroy() self.ui.window_snmp = None def on_window_snmp_delete_event(self, widget, event): """Window closing event""" # Disable timer and scan when the window is closed self.ui.action_timer.set_active(False) self.ui.action_refresh.set_active(False) self.destroy() def on_action_refresh_activate(self, action): """Update values""" def update_ui(values): """Update the UI in a thread-safe way using GLib""" for service in self.services.keys(): treeiter = self.model.rows[service] self.model.set_value( treeiter, values.get(self.services[service], _('<SNMP Error>'))) if values.has_key('error'): print values # Start scan again if the timer is enabled if self.ui.action_timer.get_active(): GLib.timeout_add(self.ui.adjustment_timer.get_value(), self.on_action_refresh_activate, action) else: # Stop the scan self.ui.action_refresh.set_active(False) def worker(host, oids): """Get a reply from SNMP and update the model accordingly""" try: values = snmp.snmp.get_from_host(host, oids) except SNMPException as error: print 'Exception: %s' % error.value values = {'error': 'Exception: %s' % error.value} GLib.idle_add(update_ui, values) if self.ui.action_refresh.get_active(): # Scan for new data self.completed_threads = 0 self.ui.action_refresh.set_icon_name('media-playback-stop') # Set the number of maximum running threads self.semaphore = threading.BoundedSemaphore(1) self.semaphore.cancel = False oids = [] for service in self.services.keys(): treeiter = self.model.rows[service] self.model.set_value(treeiter, '') oids.append(self.services[service]) # Create a new thread and launch it thread = SemaphoredThread(semaphore=self.semaphore, callback=worker, arguments=(self.host, oids), name=self.services[service], target=worker) thread.start() else: # Stop a previous scan self.semaphore.cancel = True self.ui.action_refresh.set_icon_name('media-playback-start') # Disable the timer when the scan is stopped self.ui.action_timer.set_active(False) # Returning False the timer automatically ends # It will be fired again after the scan is completed return False def on_action_timer_toggled(self, action): """Enable the timer for the autoscan""" if self.ui.action_timer.get_active(): # Start scan when the timer is active self.ui.action_refresh.set_active(True)
class UIHost(object): def __init__(self, parent, hosts): """Prepare the host dialog""" self.hosts = hosts # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('host.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_host.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position( self.ui.dialog_host, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels if widget.get_label(): widget.set_label(text(widget.get_label())) else: widget.set_label(text(widget.get_short_label())) # Initialize labels for widget in self.ui.get_objects_by_type(Gtk.Label): widget.set_label(text(widget.get_label())) widget.set_tooltip_text(widget.get_label().replace('_', '')) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) self.selected_iter = None self.model_devices = ModelDevices(self.ui.store_devices) # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def show(self, name, description, protocol, address, port_number, version, community, device, title, treeiter): """Show the destinations dialog""" self.ui.txt_name.set_text(name) self.ui.txt_description.set_text(description) self.ui.combo_protocol.set_active_id(protocol) self.ui.txt_address.set_text(address) self.ui.spin_port_number.set_value(port_number) self.ui.action_snmp_v1.set_current_value(version) self.ui.txt_community.set_text(community) self.ui.txt_name.grab_focus() self.ui.dialog_host.set_title(title) self.selected_iter = treeiter # Load the list of the devices for device_info in model_devices.devices.values(): self.model_devices.add_data(device_info) if device: self.ui.combo_device.set_active_id(device) if (self.ui.combo_device.get_active_id() < 0 and self.model_devices.count()): self.ui.combo_device.set_active(0) # Show the dialog response = self.ui.dialog_host.run() self.ui.dialog_host.hide() self.name = self.ui.txt_name.get_text().strip() self.description = self.ui.txt_description.get_text().strip() self.protocol = self.ui.combo_protocol.get_active_id() self.address = self.ui.txt_address.get_text().strip() self.port_number = self.ui.spin_port_number.get_value_as_int() self.version = 2 if self.ui.action_snmp_v2c.get_active() else 1 self.community = self.ui.txt_community.get_text().strip() self.device = self.ui.combo_device.get_active_id() return response def destroy(self): """Destroy the host dialog""" settings.positions.save_window_position( self.ui.dialog_host, SECTION_WINDOW_NAME) self.ui.dialog_host.destroy() self.ui.dialog_host = None def on_action_confirm_activate(self, action): """Check che host configuration before confirm""" def show_error_message_on_infobar(widget, error_msg): """Show the error message on the GtkInfoBar""" set_error_message_on_infobar( widget=widget, widgets=(self.ui.txt_name, self.ui.txt_description, self.ui.txt_address, self.ui.txt_community), label=self.ui.lbl_error_message, infobar=self.ui.infobar_error_message, error_msg=error_msg) name = self.ui.txt_name.get_text().strip() description = self.ui.txt_description.get_text().strip() address = self.ui.txt_address.get_text().strip() community = self.ui.txt_community.get_text().strip() if len(name) == 0: # Show error for missing host name show_error_message_on_infobar( self.ui.txt_name, _('The host name is missing')) elif '\'' in name or '\\' in name or '/' in name: # Show error for invalid host name show_error_message_on_infobar( self.ui.txt_name, _('The host name is invalid')) elif self.hosts.get_iter(name) not in (None, self.selected_iter): # Show error for existing host name show_error_message_on_infobar( self.ui.txt_name, _('A host with that name already exists')) elif len(description) == 0: # Show error for missing host description show_error_message_on_infobar( self.ui.txt_description, _('The host description is missing')) elif len(address) == 0: # Show error for missing address show_error_message_on_infobar( self.ui.txt_address, _('The host address is missing')) elif '\'' in address or '\\' in address or '/' in address: # Show error for invalid address show_error_message_on_infobar( self.ui.txt_address, _('The host address is invalid')) elif len(community) == 0: # Show error for missing community string show_error_message_on_infobar( self.ui.txt_community, _('The community string is missing')) else: self.ui.dialog_host.response(Gtk.ResponseType.OK) def on_infobar_error_message_response(self, widget, response_id): """Close the infobar""" if response_id == Gtk.ResponseType.CLOSE: self.ui.infobar_error_message.set_visible(False) def on_txt_name_changed(self, widget): """Check the host name field""" check_invalid_input(widget, False, False, False) def on_txt_description_changed(self, widget): """Check the host description field""" check_invalid_input(widget, False, True, True) def on_txt_address_changed(self, widget): """Check the host address field""" check_invalid_input(widget, False, False, False) def on_txt_community_changed(self, widget): """Check the community string field""" check_invalid_input(widget, False, True, True)
class UISNMPValues(object): def __init__(self, parent, host): """Prepare the snmp values dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('snmp_values.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.window_snmp.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position(self.ui.window_snmp, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels if widget.get_label(): widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Initialize services self.model = SNMPValues(self.ui.store_values) self.services = {} for service in model_devices.devices[host.device].services: oid = model_services.services[service].description self.services[service] = oid value = SNMPValueInfo(name=service, value='', timestamp=0) self.model.add_data(value) # Sort the data in the models self.model.model.set_sort_column_id( self.ui.column_name.get_sort_column_id(), Gtk.SortType.ASCENDING) self.host = host self.ui.window_snmp.set_title(_('SNMP values for %s') % host.name) # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def show(self): """Show the Groups dialog""" self.ui.window_snmp.show() def destroy(self): """Destroy the Groups dialog""" settings.positions.save_window_position(self.ui.window_snmp, SECTION_WINDOW_NAME) self.ui.window_snmp.hide() self.ui.window_snmp.destroy() self.ui.window_snmp = None def on_window_snmp_delete_event(self, widget, event): self.destroy() def on_action_refresh_activate(self, action): fixed_arguments = [ 'snmpget', ] fixed_arguments.append('-v1' if self.host.version == 1 else '-v2c') fixed_arguments.append('-c') fixed_arguments.append(self.host.community) fixed_arguments.append('-OvQn') fixed_arguments.append('-t') fixed_arguments.append('0.3') fixed_arguments.append('%s:%s:%d' % (self.host.protocol.lower(), self.host.address, self.host.port_number)) services = self.services.keys() if self.host.requests == REQUESTS_MULTIPLE: # Process multiple requests at once arguments = fixed_arguments[:] arguments.extend([self.services[value] for value in services]) process = subprocess.Popen(args=arguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = process.communicate()[0].split('\n') for counter in xrange(len(services)): treeiter = self.model.rows[services[counter]] self.model.set_value(treeiter, stdout[counter]) else: # Process a single request for service in services: arguments = fixed_arguments[:] arguments.append(self.services[service]) treeiter = self.model.rows[service] process = subprocess.Popen(args=arguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = process.communicate()[0].split('\n') self.model.set_value(treeiter, stdout[0])
class UIGroups(object): def __init__(self, parent): """Prepare the groups dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('groups.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_groups.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position( self.ui.dialog_groups, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Load the groups self.model = ModelGroups(self.ui.store_groups) self.selected_iter = None # Sort the data in the models self.model.model.set_sort_column_id( self.ui.column_name.get_sort_column_id(), Gtk.SortType.ASCENDING) # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def show(self): """Show the Groups dialog""" self.ui.dialog_groups.run() self.ui.dialog_groups.hide() def destroy(self): """Destroy the Groups dialog""" settings.positions.save_window_position( self.ui.dialog_groups, SECTION_WINDOW_NAME) self.ui.dialog_groups.destroy() self.ui.dialog_groups = None def on_action_add_activate(self, action): """Add a new group""" dialog = UIGroupDetail(self.ui.dialog_groups, self.model) if dialog.show(name='', title=_('Add new group'), treeiter=None) == Gtk.ResponseType.OK: os.mkdir(os.path.join(DIR_HOSTS, dialog.name)) self.model.add_data(GroupInfo(name=dialog.name, description=dialog.name)) dialog.destroy() def on_action_remove_activate(self, action): """Remove the selected group""" selected_row = get_treeview_selected_row(self.ui.tvw_groups) group_name = self.model.get_key(selected_row) if selected_row else '' if selected_row and group_name and show_message_dialog( class_=UIMessageDialogNoYes, parent=self.ui.dialog_groups, message_type=Gtk.MessageType.WARNING, title=None, msg1=_('Remove the group'), msg2=_('Remove the group «%s»?') % group_name, is_response_id=Gtk.ResponseType.YES): group_path = os.path.join(DIR_HOSTS, group_name) # Check for directory not empty if len(os.listdir(group_path)) and not show_message_dialog( class_=UIMessageDialogNoYes, parent=self.ui.dialog_groups, message_type=Gtk.MessageType.WARNING, title=None, msg1=_('The group is not empty'), msg2='%s\n%s\n\n%s' % ( text('If you delete an item, it will ' 'be permanently lost.'), _('All the hosts defined for the group will be lost.'), _('Are you sure you want to delete the ' 'group «%s»?') % group_name, ), is_response_id=Gtk.ResponseType.YES): # Exit immediately without deleting the group return # Delete all the contained files and the directory for the group for filename in os.listdir(group_path): os.remove(os.path.join(group_path, filename)) os.rmdir(group_path) self.model.remove(selected_row)
class UIDevices(object): def __init__(self, parent): """Prepare the devices dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('devices.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_devices.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position(self.ui.dialog_devices, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Load the devices self.model = ModelDevices(self.ui.store_devices) self.selected_iter = None # Sort the data in the models self.model.model.set_sort_column_id( self.ui.column_name.get_sort_column_id(), Gtk.SortType.ASCENDING) # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def show(self): """Show the devices dialog""" self.ui.dialog_devices.run() self.ui.dialog_devices.hide() def destroy(self): """Destroy the devices dialog""" settings.positions.save_window_position(self.ui.dialog_devices, SECTION_WINDOW_NAME) self.ui.dialog_devices.destroy() self.ui.dialog_devices = None def on_action_add_activate(self, action): """Add a new device""" dialog = UIDeviceDetail(self.ui.dialog_devices, self.model) if dialog.show(name='', description='', services=[], title=_('Add new device type'), treeiter=None) == Gtk.ResponseType.OK: self.model.add_data( DeviceInfo(name=dialog.name, description=dialog.description, services=dialog.services)) dialog.destroy() def on_action_edit_activate(self, action): """Edit the selected device""" selected_row = get_treeview_selected_row(self.ui.tvw_devices) if selected_row: name = self.model.get_key(selected_row) description = self.model.get_description(selected_row) services = self.model.get_services(selected_row) selected_iter = self.model.get_iter(name) dialog = UIDeviceDetail(self.ui.dialog_devices, self.model) if dialog.show(name=name, description=description, services=services, title=_('Edit device type'), treeiter=selected_iter) == Gtk.ResponseType.OK: # Update values self.model.set_data( selected_iter, DeviceInfo(name=dialog.name, description=dialog.description, services=dialog.services)) dialog.destroy() def on_action_remove_activate(self, action): """Remove the selected devices""" selected_row = get_treeview_selected_row(self.ui.tvw_devices) if selected_row and show_message_dialog( class_=UIMessageDialogNoYes, parent=self.ui.dialog_devices, message_type=Gtk.MessageType.WARNING, title=None, msg1=_("Remove device"), msg2=_("Remove the selected device?"), is_response_id=Gtk.ResponseType.YES): self.model.remove(selected_row) def on_tvw_devices_row_activated(self, widget, treepath, column): """Edit the selected row on activation""" self.ui.action_edit.activate()
class UIDevices(object): def __init__(self, parent): """Prepare the devices dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('devices.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_devices.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position( self.ui.dialog_devices, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Load the devices self.model = ModelDevices(self.ui.store_devices) self.selected_iter = None # Sort the data in the models self.model.model.set_sort_column_id( self.ui.column_name.get_sort_column_id(), Gtk.SortType.ASCENDING) # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def show(self): """Show the devices dialog""" self.ui.dialog_devices.run() self.ui.dialog_devices.hide() def destroy(self): """Destroy the devices dialog""" settings.positions.save_window_position( self.ui.dialog_devices, SECTION_WINDOW_NAME) self.ui.dialog_devices.destroy() self.ui.dialog_devices = None def on_action_add_activate(self, action): """Add a new device""" dialog = UIDeviceDetail(self.ui.dialog_devices, self.model) if dialog.show(name='', description='', services=[], title=_('Add new device type'), treeiter=None) == Gtk.ResponseType.OK: self.model.add_data(DeviceInfo(name=dialog.name, description=dialog.description, services=dialog.services)) dialog.destroy() def on_action_edit_activate(self, action): """Edit the selected device""" selected_row = get_treeview_selected_row(self.ui.tvw_devices) if selected_row: name = self.model.get_key(selected_row) description = self.model.get_description(selected_row) services = self.model.get_services(selected_row) selected_iter = self.model.get_iter(name) dialog = UIDeviceDetail(self.ui.dialog_devices, self.model) if dialog.show(name=name, description=description, services=services, title=_('Edit device type'), treeiter=selected_iter ) == Gtk.ResponseType.OK: # Update values self.model.set_data(selected_iter, DeviceInfo( name=dialog.name, description=dialog.description, services=dialog.services)) dialog.destroy() def on_action_remove_activate(self, action): """Remove the selected devices""" selected_row = get_treeview_selected_row(self.ui.tvw_devices) if selected_row and show_message_dialog( class_=UIMessageDialogNoYes, parent=self.ui.dialog_devices, message_type=Gtk.MessageType.WARNING, title=None, msg1=_("Remove device"), msg2=_("Remove the selected device?"), is_response_id=Gtk.ResponseType.YES): self.model.remove(selected_row) def on_tvw_devices_row_activated(self, widget, treepath, column): """Edit the selected row on activation""" self.ui.action_edit.activate()
class UISNMPValues(object): def __init__(self, parent, host): """Prepare the snmp values dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('snmp_values.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.window_snmp.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position( self.ui.window_snmp, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels if widget.get_label(): widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Initialize services self.model = SNMPValues(self.ui.store_values) self.services = {} for service in model_devices.devices[host.device].services: oid = model_services.services[service].numeric_oid self.services[service] = oid value = SNMPValueInfo(name=service, value='', timestamp=0) self.model.add_data(value) # Sort the data in the models self.model.model.set_sort_column_id( self.ui.column_name.get_sort_column_id(), Gtk.SortType.ASCENDING) self.host = host self.ui.window_snmp.set_title(_('SNMP values for %s') % host.name) self.semaphore = None self.completed_threads = 0 # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def show(self): """Show the Groups dialog""" self.ui.window_snmp.show() def destroy(self): """Destroy the Groups dialog""" settings.positions.save_window_position( self.ui.window_snmp, SECTION_WINDOW_NAME) self.ui.window_snmp.hide() self.ui.window_snmp.destroy() self.ui.window_snmp = None def on_window_snmp_delete_event(self, widget, event): """Window closing event""" # Disable timer and scan when the window is closed self.ui.action_timer.set_active(False) self.ui.action_refresh.set_active(False) self.destroy() def on_action_refresh_activate(self, action): """Update values""" def update_ui(values): """Update the UI in a thread-safe way using GLib""" for service in self.services.keys(): treeiter = self.model.rows[service] self.model.set_value(treeiter, values.get(self.services[service], _('<SNMP Error>'))) if values.has_key('error'): print values # Start scan again if the timer is enabled if self.ui.action_timer.get_active(): GLib.timeout_add(self.ui.adjustment_timer.get_value(), self.on_action_refresh_activate, action) else: # Stop the scan self.ui.action_refresh.set_active(False) def worker(host, oids): """Get a reply from SNMP and update the model accordingly""" try: values = snmp.snmp.get_from_host(host, oids) except SNMPException as error: print 'Exception: %s' % error.value values = {'error': 'Exception: %s' % error.value} GLib.idle_add(update_ui, values) if self.ui.action_refresh.get_active(): # Scan for new data self.completed_threads = 0 self.ui.action_refresh.set_icon_name('media-playback-stop') # Set the number of maximum running threads self.semaphore = threading.BoundedSemaphore(1) self.semaphore.cancel = False oids = [] for service in self.services.keys(): treeiter = self.model.rows[service] self.model.set_value(treeiter, '') oids.append(self.services[service]) # Create a new thread and launch it thread = SemaphoredThread(semaphore=self.semaphore, callback=worker, arguments=(self.host, oids), name=self.services[service], target=worker) thread.start() else: # Stop a previous scan self.semaphore.cancel = True self.ui.action_refresh.set_icon_name('media-playback-start') # Disable the timer when the scan is stopped self.ui.action_timer.set_active(False) # Returning False the timer automatically ends # It will be fired again after the scan is completed return False def on_action_timer_toggled(self, action): """Enable the timer for the autoscan""" if self.ui.action_timer.get_active(): # Start scan when the timer is active self.ui.action_refresh.set_active(True)
class UIMain(object): def __init__(self, application): self.application = application snmp.snmp = snmp.SNMP() # Load settings settings.settings = settings.Settings(FILE_SETTINGS, False) settings.positions = settings.Settings(FILE_WINDOWS_POSITION, False) settings.services = settings.Settings(FILE_SERVICES, False) settings.devices = settings.Settings(FILE_DEVICES, False) preferences.preferences = preferences.Preferences() # Load services for key in settings.services.get_sections(): model_services.services[key] = ServiceInfo( name=key, description=settings.services.get(key, OPTION_SERVICE_DESCRIPTION), numeric_oid=snmp.snmp.translate( settings.services.get(key, OPTION_SERVICE_DESCRIPTION))) # Load devices for key in settings.devices.get_sections(): model_devices.devices[key] = DeviceInfo( name=key, description=settings.devices.get(key, OPTION_DEVICE_DESCRIPTION), services=settings.devices.get_list(key, OPTION_DEVICE_SERVICES)) self.loadUI() self.model_hosts = ModelHosts(self.ui.store_hosts) self.model_groups = ModelGroups(self.ui.store_groups) # Load the groups and hosts list self.hosts = {} self.reload_groups() # Sort the data in the models self.model_groups.model.set_sort_column_id( self.ui.column_group.get_sort_column_id(), Gtk.SortType.ASCENDING) self.model_hosts.model.set_sort_column_id( self.ui.column_name.get_sort_column_id(), Gtk.SortType.ASCENDING) # Automatically select the first host if any self.ui.tvw_groups.set_cursor(0) if self.model_hosts.count() > 0: self.ui.tvw_connections.set_cursor(0) # Restore the saved size and position settings.positions.restore_window_position(self.ui.win_main, SECTION_WINDOW_NAME) def loadUI(self): """Load the interface UI""" self.ui = GtkBuilderLoader(get_ui_file('main.glade')) self.ui.win_main.set_application(self.application) self.ui.win_main.set_title(APP_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.ToolButton): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Set list items row height icon_size = preferences.ICON_SIZE self.ui.cell_name.props.height = preferences.get(icon_size) self.ui.cell_group_name.props.height = preferences.get(icon_size) # Set groups visibility self.ui.scroll_groups.set_visible( preferences.get(preferences.GROUPS_SHOW)) # Add a Gtk.Headerbar, only for GTK+ 3.10.0 and higher if (not Gtk.check_version(3, 10, 0) and not preferences.get(preferences.HEADERBARS_DISABLE)): self.load_ui_headerbar() if preferences.get(preferences.HEADERBARS_REMOVE_TOOLBAR): # This is only for development, it should always be True # Remove the redundant toolbar self.ui.toolbar_main.destroy() # Flatten the Gtk.ScrolledWindows self.ui.scroll_groups.set_shadow_type(Gtk.ShadowType.NONE) self.ui.scroll_connections.set_shadow_type(Gtk.ShadowType.NONE) # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def load_ui_headerbar(self): """Add a Gtk.HeaderBar to the window with buttons""" def create_button_from_action(action): """Create a new Gtk.Button from a Gtk.Action""" if isinstance(action, Gtk.ToggleAction): new_button = Gtk.ToggleButton() else: new_button = Gtk.Button() new_button.set_use_action_appearance(False) new_button.set_related_action(action) # Use icon from the action icon_name = action.get_icon_name() if preferences.get(preferences.HEADERBARS_SYMBOLIC_ICONS): icon_name += '-symbolic' # Get desired icon size icon_size = (Gtk.IconSize.BUTTON if preferences.get(preferences.HEADERBARS_SMALL_ICONS) else Gtk.IconSize.LARGE_TOOLBAR) new_button.set_image( Gtk.Image.new_from_icon_name(icon_name, icon_size)) # Set the tooltip from the action label new_button.set_tooltip_text(action.get_label().replace('_', '')) return new_button # Add the Gtk.HeaderBar header_bar = Gtk.HeaderBar() header_bar.props.title = self.ui.win_main.get_title() header_bar.set_show_close_button(True) self.ui.win_main.set_titlebar(header_bar) # Add buttons to the left side for action in (self.ui.action_new, self.ui.action_edit, self.ui.action_connect, self.ui.action_delete): header_bar.pack_start(create_button_from_action(action)) # Add buttons to the right side (in reverse order) for action in reversed( (self.ui.action_services, self.ui.action_devices, self.ui.action_groups, self.ui.action_about)): header_bar.pack_end(create_button_from_action(action)) def run(self): """Show the UI""" self.ui.win_main.show_all() def on_win_main_delete_event(self, widget, event): """Save the settings and close the application""" settings.positions.save_window_position(self.ui.win_main, SECTION_WINDOW_NAME) settings.positions.save() settings.services.save() settings.devices.save() settings.settings.save() self.application.quit() def on_action_about_activate(self, action): """Show the about dialog""" dialog = UIAbout(self.ui.win_main) dialog.show() dialog.destroy() def on_action_quit_activate(self, action): """Close the application by closing the main window""" event = Gdk.Event() event.key.type = Gdk.EventType.DELETE self.ui.win_main.event(event) def on_action_services_activate(self, action): """Edit services""" selected_row = get_treeview_selected_row(self.ui.tvw_connections) if selected_row: iter_parent = self.ui.store_hosts.iter_parent(selected_row) selected_path = self.model_hosts.model[selected_row].path # Get the path of the host if iter_parent is None: tree_path = self.model_hosts.model[selected_row].path else: tree_path = self.model_hosts.model[iter_parent].path dialog_services = UIServices(parent=self.ui.win_main) # Load services list dialog_services.model.load(model_services.services) dialog_services.show() # Get the new services list, clear and store the list again model_services.services = dialog_services.model.dump() dialog_services.destroy() settings.services.clear() for key in model_services.services.iterkeys(): settings.services.set( section=key, option=OPTION_SERVICE_DESCRIPTION, value=model_services.services[key].description) self.reload_hosts() if selected_row: # Automatically select again the previously selected row self.ui.tvw_connections.set_cursor(path=selected_path, column=None, start_editing=False) def on_action_devices_activate(self, action): """Edit devices""" selected_row = get_treeview_selected_row(self.ui.tvw_connections) if selected_row: iter_parent = self.ui.store_hosts.iter_parent(selected_row) selected_path = self.model_hosts.model[selected_row].path # Get the path of the host if iter_parent is None: tree_path = self.model_hosts.model[selected_row].path else: tree_path = self.model_hosts.model[iter_parent].path dialog_devices = UIDevices(parent=self.ui.win_main) # Load devices list dialog_devices.model.load(model_devices.devices) dialog_devices.show() # Get the new devices list, clear and store the list again model_devices.devices = dialog_devices.model.dump() dialog_devices.destroy() settings.devices.clear() for key in model_devices.devices.iterkeys(): settings.devices.set(section=key, option=OPTION_DEVICE_DESCRIPTION, value=model_devices.devices[key].description) settings.devices.set(section=key, option=OPTION_DEVICE_SERVICES, value=','.join( model_devices.devices[key].services)) self.reload_hosts() if selected_row: # Automatically select again the previously selected row self.ui.tvw_connections.set_cursor(path=selected_path, column=None, start_editing=False) def reload_hosts(self): """Load hosts from the settings files""" self.model_hosts.clear() self.hosts.clear() hosts_path = self.get_current_group_path() # Fix bug where the groups model isn't yet emptied, resulting in # being still used after a clear, then an invalid path if not os.path.isdir(hosts_path): return for filename in os.listdir(hosts_path): # Skip folders, used for groups if os.path.isdir(os.path.join(hosts_path, filename)): continue settings_host = settings.Settings(filename=os.path.join( hosts_path, filename), case_sensitive=True) host = HostInfo( name=settings_host.get(SECTION_HOST, OPTION_HOST_NAME), description=settings_host.get(SECTION_HOST, OPTION_HOST_DESCRIPTION), protocol=settings_host.get(SECTION_HOST, OPTION_HOST_PROTOCOL), address=settings_host.get(SECTION_HOST, OPTION_HOST_ADDRESS), port_number=settings_host.get_int(SECTION_HOST, OPTION_HOST_PORT), version=settings_host.get_int(SECTION_HOST, OPTION_HOST_VERSION), community=settings_host.get(SECTION_HOST, OPTION_HOST_COMMUNITY), device=settings_host.get(SECTION_HOST, OPTION_HOST_DEVICE)) self.add_host(host, False) def add_host(self, host, update_settings): """Add a new host along as with its destinations""" # Add the host to the data and to the model self.hosts[host.name] = host treeiter = self.model_hosts.add_data(host) # Update settings file if requested if update_settings: hosts_path = self.get_current_group_path() settings_host = settings.Settings(filename=os.path.join( hosts_path, '%s.conf' % host.name), case_sensitive=True) # Add host information settings_host.set(SECTION_HOST, OPTION_HOST_NAME, host.name) settings_host.set(SECTION_HOST, OPTION_HOST_DESCRIPTION, host.description) settings_host.set(SECTION_HOST, OPTION_HOST_PROTOCOL, host.protocol) settings_host.set(SECTION_HOST, OPTION_HOST_ADDRESS, host.address) settings_host.set_int(SECTION_HOST, OPTION_HOST_PORT, host.port_number) settings_host.set_int(SECTION_HOST, OPTION_HOST_VERSION, host.version) settings_host.set(SECTION_HOST, OPTION_HOST_COMMUNITY, host.community) settings_host.set(SECTION_HOST, OPTION_HOST_DEVICE, host.device) # Save the settings to the file settings_host.save() def remove_host(self, name): """Remove a host by its name""" hosts_path = self.get_current_group_path() filename = os.path.join(hosts_path, '%s.conf' % name) if os.path.isfile(filename): os.unlink(filename) self.hosts.pop(name) self.model_hosts.remove(self.model_hosts.get_iter(name)) def reload_groups(self): """Load groups from hosts folder""" self.model_groups.clear() # Always add a default group self.model_groups.add_data(GroupInfo('', _('Default group'))) for filename in os.listdir(DIR_HOSTS): if os.path.isdir(os.path.join(DIR_HOSTS, filename)): # For each folder add a new group self.model_groups.add_data(GroupInfo(filename, filename)) def on_action_new_activate(self, action): """Define a new host""" dialog = UIHost(parent=self.ui.win_main, hosts=self.model_hosts) response = dialog.show(name='', description='', protocol='UDP', address='', port_number=161, version=1, community='public', device='', title=_('Add a new host'), treeiter=None) if response == Gtk.ResponseType.OK: host = HostInfo(dialog.name, dialog.description, dialog.protocol, dialog.address, dialog.port_number, dialog.version, dialog.community, dialog.device) self.add_host(host=host, update_settings=True) # Automatically select the newly added host self.ui.tvw_connections.set_cursor( path=self.model_hosts.get_path_by_name(dialog.name), column=None, start_editing=False) dialog.destroy() def on_action_edit_activate(self, action): """Define a new host""" selected_row = get_treeview_selected_row(self.ui.tvw_connections) if selected_row: dialog = UIHost(parent=self.ui.win_main, hosts=self.model_hosts) # Show the edit host dialog model = self.model_hosts name = model.get_key(selected_row) selected_iter = model.get_iter(name) response = dialog.show( name=name, description=model.get_description(selected_row), protocol=model.get_protocol(selected_row), address=model.get_address(selected_row), port_number=model.get_port_number(selected_row), version=model.get_version(selected_row), community=model.get_community(selected_row), device=model.get_device(selected_row), title=_('Edit host'), treeiter=selected_iter) if response == Gtk.ResponseType.OK: # Remove older host and add the newer host = HostInfo(dialog.name, dialog.description, dialog.protocol, dialog.address, dialog.port_number, dialog.version, dialog.community, dialog.device) self.remove_host(name) self.add_host(host=host, update_settings=True) # Get the path of the host tree_path = self.model_hosts.get_path_by_name(dialog.name) # Automatically select again the previously selected host self.ui.tvw_connections.set_cursor(path=tree_path, column=None, start_editing=False) dialog.destroy() def on_tvw_connections_row_activated(self, widget, treepath, column): """Edit the selected row on activation""" selected_row = get_treeview_selected_row(self.ui.tvw_connections) if selected_row: # Start host connection self.ui.action_connect.activate() def on_action_delete_activate(self, action): """Remove the selected host""" selected_row = get_treeview_selected_row(self.ui.tvw_connections) if selected_row and show_message_dialog( class_=UIMessageDialogNoYes, parent=self.ui.win_main, message_type=Gtk.MessageType.QUESTION, title=None, msg1=_("Remove host"), msg2=_("Remove the selected host?"), is_response_id=Gtk.ResponseType.YES): self.remove_host(self.model_hosts.get_key(selected_row)) def on_action_copy_activate(self, action): """Copy the selected host to another""" row = get_treeview_selected_row(self.ui.tvw_connections) if row: model = self.model_hosts name = self.model_hosts.get_key(row) description = self.model_hosts.get_description(row) selected_iter = self.model_hosts.get_iter(name) dialog = UIHost(parent=self.ui.win_main, hosts=self.model_hosts) # Show the edit host dialog response = dialog.show(name=_('Copy of %s') % name, description=description, title=_('Copy host'), protocol=model.get_protocol(row), address=model.get_address(row), port_number=model.get_port_number(row), version=model.get_version(row), community=model.get_community(row), device=model.get_device(row), treeiter=None) if response == Gtk.ResponseType.OK: host = HostInfo(dialog.name, dialog.description, dialog.protocol, dialog.address, dialog.port_number, dialog.version, dialog.community, dialog.device) self.add_host(host=host, update_settings=True) # Get the path of the host tree_path = self.model_hosts.get_path_by_name(dialog.name) # Automatically select again the previously selected host self.ui.tvw_connections.set_cursor(path=tree_path, column=None, start_editing=False) dialog.destroy() def on_tvw_connections_cursor_changed(self, widget): """Set actions sensitiveness for host and connection""" if get_treeview_selected_row(self.ui.tvw_connections): self.ui.actions_connection.set_sensitive(True) self.ui.actions_host.set_sensitive(True) def on_action_connect_activate(self, action): """Establish the connection for the destination""" selected_row = get_treeview_selected_row(self.ui.tvw_connections) if selected_row: model = self.model_hosts dialog = UISNMPValues( parent=self.ui.win_main, host=HostInfo(name=model.get_key(selected_row), description=model.get_description(selected_row), protocol=model.get_protocol(selected_row), address=model.get_address(selected_row), port_number=model.get_port_number(selected_row), version=model.get_version(selected_row), community=model.get_community(selected_row), device=model.get_device(selected_row))) dialog.show() def get_current_group_path(self): """Return the path of the currently selected group""" selected_row = get_treeview_selected_row(self.ui.tvw_groups) group_name = self.model_groups.get_key(selected_row) if selected_row \ else '' return os.path.join(DIR_HOSTS, group_name) if group_name else DIR_HOSTS def on_tvw_groups_cursor_changed(self, widget): """Set actions sensitiveness for host and connection""" if get_treeview_selected_row(self.ui.tvw_groups): self.reload_hosts() # Automatically select the first host for the group self.ui.tvw_connections.set_cursor(0) def on_action_groups_activate(self, widget): """Edit groups""" dialog_groups = UIGroups(parent=self.ui.win_main) dialog_groups.model = self.model_groups dialog_groups.ui.tvw_groups.set_model(self.model_groups.model) dialog_groups.show() dialog_groups.destroy() def on_tvw_groups_button_release_event(self, widget, event): """Show groups popup menu on right click""" if event.button == Gdk.BUTTON_SECONDARY: show_popup_menu(self.ui.menu_groups, event.button) def on_tvw_connections_button_release_event(self, widget, event): """Show connections popup menu on right click""" if event.button == Gdk.BUTTON_SECONDARY: show_popup_menu(self.ui.menu_connections, event.button) def on_action_group_previous_activate(self, action): """Move to the previous group""" selected_row = get_treeview_selected_row(self.ui.tvw_groups) new_iter = self.model_groups.model.iter_previous(selected_row) if new_iter: # Select the newly selected row in the groups list new_path = self.model_groups.get_path(new_iter) self.ui.tvw_groups.set_cursor(new_path) def on_action_group_next_activate(self, action): """Move to the next group""" selected_row = get_treeview_selected_row(self.ui.tvw_groups) new_iter = self.model_groups.model.iter_next(selected_row) if new_iter: # Select the newly selected row in the groups list new_path = self.model_groups.get_path(new_iter) self.ui.tvw_groups.set_cursor(new_path)
class UIGroupDetail(object): def __init__(self, parent, groups): """Prepare the group detail dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('group_detail.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_edit_group.set_transient_for(parent) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize labels for widget in self.ui.get_objects_by_type(Gtk.Label): widget.set_label(text(widget.get_label())) widget.set_tooltip_text(widget.get_label().replace('_', '')) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) self.model = groups self.name = '' # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def show(self, name, title, treeiter): """Show the Group detail dialog""" self.ui.txt_name.set_text(name) self.ui.txt_name.grab_focus() self.ui.dialog_edit_group.set_title(title) response = self.ui.dialog_edit_group.run() self.ui.dialog_edit_group.hide() self.name = self.ui.txt_name.get_text().strip() return response def destroy(self): """Destroy the Group detail dialog""" self.ui.dialog_edit_group.destroy() self.ui.dialog_edit_group = None def on_action_confirm_activate(self, action): """Check che group configuration before confirm""" def show_error_message_on_infobar(widget, error_msg): """Show the error message on the GtkInfoBar""" set_error_message_on_infobar( widget=widget, widgets=(self.ui.txt_name, ), label=self.ui.lbl_error_message, infobar=self.ui.infobar_error_message, error_msg=error_msg) name = self.ui.txt_name.get_text().strip() if len(name) == 0: # Show error for missing group name show_error_message_on_infobar( self.ui.txt_name, _('The group name is missing')) elif '\'' in name or '\\' in name or '/' in name or ',' in name: # Show error for invalid group name show_error_message_on_infobar( self.ui.txt_name, _('The Group name is invalid')) elif self.model.get_iter(name): # Show error for existing group name show_error_message_on_infobar( self.ui.txt_name, _('A group with that name already exists')) else: self.ui.dialog_edit_group.response(Gtk.ResponseType.OK) def on_infobar_error_message_response(self, widget, response_id): """Close the infobar""" if response_id == Gtk.ResponseType.CLOSE: self.ui.infobar_error_message.set_visible(False) def on_txt_name_changed(self, widget): """Check the group name field""" check_invalid_input(widget, False, False, False)
class UIServiceDetail(object): def __init__(self, parent, services): """Prepare the services detail dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('service_detail.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_edit_service.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position( self.ui.dialog_edit_service, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize labels for widget in self.ui.get_objects_by_type(Gtk.Label): widget.set_label(text(widget.get_label())) widget.set_tooltip_text(widget.get_label().replace('_', '')) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) self.model = services self.selected_iter = None self.name = '' self.description = '' # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def show(self, name, description, title, treeiter): """Show the Services detail dialog""" self.ui.txt_name.set_text(name) self.ui.txt_description.set_text(description) self.ui.txt_name.grab_focus() self.ui.dialog_edit_service.set_title(title) self.selected_iter = treeiter response = self.ui.dialog_edit_service.run() self.ui.dialog_edit_service.hide() self.name = self.ui.txt_name.get_text().strip() self.description = self.ui.txt_description.get_text().strip() return response def destroy(self): """Destroy the Service detail dialog""" settings.positions.save_window_position( self.ui.dialog_edit_service, SECTION_WINDOW_NAME) self.ui.dialog_edit_service.destroy() self.ui.dialog_edit_service = None def on_action_confirm_activate(self, action): """Check che service configuration before confirm""" def show_error_message_on_infobar(widget, error_msg): """Show the error message on the GtkInfoBar""" set_error_message_on_infobar( widget=widget, widgets=(self.ui.txt_name, self.ui.txt_description), label=self.ui.lbl_error_message, infobar=self.ui.infobar_error_message, error_msg=error_msg) name = self.ui.txt_name.get_text().strip() description = self.ui.txt_description.get_text().strip() if len(name) == 0: # Show error for missing service name show_error_message_on_infobar( self.ui.txt_name, _('The service name is missing')) elif '\'' in name or '\\' in name or '/' in name or ',' in name: # Show error for invalid service name show_error_message_on_infobar( self.ui.txt_name, _('The service name is invalid')) elif self.model.get_iter(name) not in (None, self.selected_iter): # Show error for existing service name show_error_message_on_infobar( self.ui.txt_name, _('A service with that name already exists')) elif len(description) == 0: # Show error for missing service description show_error_message_on_infobar( self.ui.txt_description, _('The service description is missing')) elif '\'' in description or '\\' in description: # Show error for invalid service description show_error_message_on_infobar( self.ui.txt_description, _('The service description is invalid')) else: self.ui.dialog_edit_service.response(Gtk.ResponseType.OK) def on_infobar_error_message_response(self, widget, response_id): """Close the infobar""" if response_id == Gtk.ResponseType.CLOSE: self.ui.infobar_error_message.set_visible(False) def on_txt_name_changed(self, widget): """Check the service name field""" check_invalid_input(widget, False, False, False) def on_txt_description_changed(self, widget): """Check the service description field""" check_invalid_input(widget, False, True, False)
class UIHost(object): def __init__(self, parent, hosts): """Prepare the host dialog""" self.hosts = hosts # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('host.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_host.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position(self.ui.dialog_host, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels if widget.get_label(): widget.set_label(text(widget.get_label())) else: widget.set_label(text(widget.get_short_label())) # Initialize labels for widget in self.ui.get_objects_by_type(Gtk.Label): widget.set_label(text(widget.get_label())) widget.set_tooltip_text(widget.get_label().replace('_', '')) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) self.selected_iter = None self.model_devices = ModelDevices(self.ui.store_devices) # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def show(self, name, description, protocol, address, port_number, version, community, device, title, treeiter): """Show the destinations dialog""" self.ui.txt_name.set_text(name) self.ui.txt_description.set_text(description) self.ui.combo_protocol.set_active_id(protocol) self.ui.txt_address.set_text(address) self.ui.spin_port_number.set_value(port_number) self.ui.action_snmp_v1.set_current_value(version) self.ui.txt_community.set_text(community) self.ui.txt_name.grab_focus() self.ui.dialog_host.set_title(title) self.selected_iter = treeiter # Load the list of the devices for device_info in model_devices.devices.values(): self.model_devices.add_data(device_info) if device: self.ui.combo_device.set_active_id(device) if (self.ui.combo_device.get_active_id() < 0 and self.model_devices.count()): self.ui.combo_device.set_active(0) # Show the dialog response = self.ui.dialog_host.run() self.ui.dialog_host.hide() self.name = self.ui.txt_name.get_text().strip() self.description = self.ui.txt_description.get_text().strip() self.protocol = self.ui.combo_protocol.get_active_id() self.address = self.ui.txt_address.get_text().strip() self.port_number = self.ui.spin_port_number.get_value_as_int() self.version = 2 if self.ui.action_snmp_v2c.get_active() else 1 self.community = self.ui.txt_community.get_text().strip() self.device = self.ui.combo_device.get_active_id() return response def destroy(self): """Destroy the host dialog""" settings.positions.save_window_position(self.ui.dialog_host, SECTION_WINDOW_NAME) self.ui.dialog_host.destroy() self.ui.dialog_host = None def on_action_confirm_activate(self, action): """Check che host configuration before confirm""" def show_error_message_on_infobar(widget, error_msg): """Show the error message on the GtkInfoBar""" set_error_message_on_infobar( widget=widget, widgets=(self.ui.txt_name, self.ui.txt_description, self.ui.txt_address, self.ui.txt_community), label=self.ui.lbl_error_message, infobar=self.ui.infobar_error_message, error_msg=error_msg) name = self.ui.txt_name.get_text().strip() description = self.ui.txt_description.get_text().strip() address = self.ui.txt_address.get_text().strip() community = self.ui.txt_community.get_text().strip() if len(name) == 0: # Show error for missing host name show_error_message_on_infobar(self.ui.txt_name, _('The host name is missing')) elif '\'' in name or '\\' in name or '/' in name: # Show error for invalid host name show_error_message_on_infobar(self.ui.txt_name, _('The host name is invalid')) elif self.hosts.get_iter(name) not in (None, self.selected_iter): # Show error for existing host name show_error_message_on_infobar( self.ui.txt_name, _('A host with that name already exists')) elif len(description) == 0: # Show error for missing host description show_error_message_on_infobar(self.ui.txt_description, _('The host description is missing')) elif len(address) == 0: # Show error for missing address show_error_message_on_infobar(self.ui.txt_address, _('The host address is missing')) elif '\'' in address or '\\' in address or '/' in address: # Show error for invalid address show_error_message_on_infobar(self.ui.txt_address, _('The host address is invalid')) elif len(community) == 0: # Show error for missing community string show_error_message_on_infobar(self.ui.txt_community, _('The community string is missing')) else: self.ui.dialog_host.response(Gtk.ResponseType.OK) def on_infobar_error_message_response(self, widget, response_id): """Close the infobar""" if response_id == Gtk.ResponseType.CLOSE: self.ui.infobar_error_message.set_visible(False) def on_txt_name_changed(self, widget): """Check the host name field""" check_invalid_input(widget, False, False, False) def on_txt_description_changed(self, widget): """Check the host description field""" check_invalid_input(widget, False, True, True) def on_txt_address_changed(self, widget): """Check the host address field""" check_invalid_input(widget, False, False, False) def on_txt_community_changed(self, widget): """Check the community string field""" check_invalid_input(widget, False, True, True)
class UIServiceDetail(object): def __init__(self, parent, services): """Prepare the services detail dialog""" # Load the user interface self.ui = GtkBuilderLoader(get_ui_file('service_detail.glade')) if not preferences.get(preferences.DETACHED_WINDOWS): self.ui.dialog_edit_service.set_transient_for(parent) # Restore the saved size and position settings.positions.restore_window_position( self.ui.dialog_edit_service, SECTION_WINDOW_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize labels for widget in self.ui.get_objects_by_type(Gtk.Label): widget.set_label(text(widget.get_label())) widget.set_tooltip_text(widget.get_label().replace('_', '')) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.Button): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) self.model = services self.selected_iter = None self.name = '' self.description = '' # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def show(self, name, description, numeric_oid, title, treeiter): """Show the Services detail dialog""" self.ui.txt_name.set_text(name) self.ui.txt_description.set_text(description) self.ui.txt_numeric_oid.set_text(numeric_oid) self.ui.txt_name.grab_focus() self.ui.dialog_edit_service.set_title(title) self.selected_iter = treeiter response = self.ui.dialog_edit_service.run() self.ui.dialog_edit_service.hide() self.name = self.ui.txt_name.get_text().strip() self.description = self.ui.txt_description.get_text().strip() self.numeric_oid = self.ui.txt_numeric_oid.get_text().strip() return response def destroy(self): """Destroy the Service detail dialog""" settings.positions.save_window_position( self.ui.dialog_edit_service, SECTION_WINDOW_NAME) self.ui.dialog_edit_service.destroy() self.ui.dialog_edit_service = None def on_action_confirm_activate(self, action): """Check che service configuration before confirm""" def show_error_message_on_infobar(widget, error_msg): """Show the error message on the GtkInfoBar""" set_error_message_on_infobar( widget=widget, widgets=(self.ui.txt_name, self.ui.txt_description), label=self.ui.lbl_error_message, infobar=self.ui.infobar_error_message, error_msg=error_msg) name = self.ui.txt_name.get_text().strip() description = self.ui.txt_description.get_text().strip() if len(name) == 0: # Show error for missing service name show_error_message_on_infobar( self.ui.txt_name, _('The service name is missing')) elif '\'' in name or '\\' in name or '/' in name or ',' in name: # Show error for invalid service name show_error_message_on_infobar( self.ui.txt_name, _('The service name is invalid')) elif self.model.get_iter(name) not in (None, self.selected_iter): # Show error for existing service name show_error_message_on_infobar( self.ui.txt_name, _('A service with that name already exists')) elif len(description) == 0: # Show error for missing service description show_error_message_on_infobar( self.ui.txt_description, _('The service description is missing')) elif '\'' in description or '\\' in description: # Show error for invalid service description show_error_message_on_infobar( self.ui.txt_description, _('The service description is invalid')) else: self.ui.dialog_edit_service.response(Gtk.ResponseType.OK) def on_infobar_error_message_response(self, widget, response_id): """Close the infobar""" if response_id == Gtk.ResponseType.CLOSE: self.ui.infobar_error_message.set_visible(False) def on_txt_name_changed(self, widget): """Check the service name field""" check_invalid_input(widget, False, False, False) def on_txt_description_changed(self, widget): """Check the service description field""" check_invalid_input(widget, False, True, False) self.ui.txt_numeric_oid.set_text( snmp.snmp.translate(widget.get_text().strip()) or _('Unkown OID'))
class UIMain(object): def __init__(self, application): self.application = application snmp.snmp = snmp.SNMP() # Load settings settings.settings = settings.Settings(FILE_SETTINGS, False) settings.positions = settings.Settings(FILE_WINDOWS_POSITION, False) settings.services = settings.Settings(FILE_SERVICES, False) settings.devices = settings.Settings(FILE_DEVICES, False) preferences.preferences = preferences.Preferences() # Load services for key in settings.services.get_sections(): model_services.services[key] = ServiceInfo( name=key, description=settings.services.get( key, OPTION_SERVICE_DESCRIPTION), numeric_oid=snmp.snmp.translate(settings.services.get( key, OPTION_SERVICE_DESCRIPTION))) # Load devices for key in settings.devices.get_sections(): model_devices.devices[key] = DeviceInfo( name=key, description=settings.devices.get( key, OPTION_DEVICE_DESCRIPTION), services=settings.devices.get_list( key, OPTION_DEVICE_SERVICES)) self.loadUI() self.model_hosts = ModelHosts(self.ui.store_hosts) self.model_groups = ModelGroups(self.ui.store_groups) # Load the groups and hosts list self.hosts = {} self.reload_groups() # Sort the data in the models self.model_groups.model.set_sort_column_id( self.ui.column_group.get_sort_column_id(), Gtk.SortType.ASCENDING) self.model_hosts.model.set_sort_column_id( self.ui.column_name.get_sort_column_id(), Gtk.SortType.ASCENDING) # Automatically select the first host if any self.ui.tvw_groups.set_cursor(0) if self.model_hosts.count() > 0: self.ui.tvw_connections.set_cursor(0) # Restore the saved size and position settings.positions.restore_window_position( self.ui.win_main, SECTION_WINDOW_NAME) def loadUI(self): """Load the interface UI""" self.ui = GtkBuilderLoader(get_ui_file('main.glade')) self.ui.win_main.set_application(self.application) self.ui.win_main.set_title(APP_NAME) # Initialize actions for widget in self.ui.get_objects_by_type(Gtk.Action): # Connect the actions accelerators widget.connect_accelerator() # Set labels widget.set_label(text(widget.get_label())) # Initialize tooltips for widget in self.ui.get_objects_by_type(Gtk.ToolButton): action = widget.get_related_action() if action: widget.set_tooltip_text(action.get_label().replace('_', '')) # Initialize column headers for widget in self.ui.get_objects_by_type(Gtk.TreeViewColumn): widget.set_title(text(widget.get_title())) # Set list items row height icon_size = preferences.ICON_SIZE self.ui.cell_name.props.height = preferences.get(icon_size) self.ui.cell_group_name.props.height = preferences.get(icon_size) # Set groups visibility self.ui.scroll_groups.set_visible( preferences.get(preferences.GROUPS_SHOW)) # Add a Gtk.Headerbar, only for GTK+ 3.10.0 and higher if (not Gtk.check_version(3, 10, 0) and not preferences.get(preferences.HEADERBARS_DISABLE)): self.load_ui_headerbar() if preferences.get(preferences.HEADERBARS_REMOVE_TOOLBAR): # This is only for development, it should always be True # Remove the redundant toolbar self.ui.toolbar_main.destroy() # Flatten the Gtk.ScrolledWindows self.ui.scroll_groups.set_shadow_type(Gtk.ShadowType.NONE) self.ui.scroll_connections.set_shadow_type(Gtk.ShadowType.NONE) # Connect signals from the glade file to the module functions self.ui.connect_signals(self) def load_ui_headerbar(self): """Add a Gtk.HeaderBar to the window with buttons""" def create_button_from_action(action): """Create a new Gtk.Button from a Gtk.Action""" if isinstance(action, Gtk.ToggleAction): new_button = Gtk.ToggleButton() else: new_button = Gtk.Button() new_button.set_use_action_appearance(False) new_button.set_related_action(action) # Use icon from the action icon_name = action.get_icon_name() if preferences.get(preferences.HEADERBARS_SYMBOLIC_ICONS): icon_name += '-symbolic' # Get desired icon size icon_size = (Gtk.IconSize.BUTTON if preferences.get(preferences.HEADERBARS_SMALL_ICONS) else Gtk.IconSize.LARGE_TOOLBAR) new_button.set_image(Gtk.Image.new_from_icon_name(icon_name, icon_size)) # Set the tooltip from the action label new_button.set_tooltip_text(action.get_label().replace('_', '')) return new_button # Add the Gtk.HeaderBar header_bar = Gtk.HeaderBar() header_bar.props.title = self.ui.win_main.get_title() header_bar.set_show_close_button(True) self.ui.win_main.set_titlebar(header_bar) # Add buttons to the left side for action in (self.ui.action_new, self.ui.action_edit, self.ui.action_connect, self.ui.action_delete): header_bar.pack_start(create_button_from_action(action)) # Add buttons to the right side (in reverse order) for action in reversed((self.ui.action_services, self.ui.action_devices, self.ui.action_groups, self.ui.action_about)): header_bar.pack_end(create_button_from_action(action)) def run(self): """Show the UI""" self.ui.win_main.show_all() def on_win_main_delete_event(self, widget, event): """Save the settings and close the application""" settings.positions.save_window_position( self.ui.win_main, SECTION_WINDOW_NAME) settings.positions.save() settings.services.save() settings.devices.save() settings.settings.save() self.application.quit() def on_action_about_activate(self, action): """Show the about dialog""" dialog = UIAbout(self.ui.win_main) dialog.show() dialog.destroy() def on_action_quit_activate(self, action): """Close the application by closing the main window""" event = Gdk.Event() event.key.type = Gdk.EventType.DELETE self.ui.win_main.event(event) def on_action_services_activate(self, action): """Edit services""" selected_row = get_treeview_selected_row(self.ui.tvw_connections) if selected_row: iter_parent = self.ui.store_hosts.iter_parent(selected_row) selected_path = self.model_hosts.model[selected_row].path # Get the path of the host if iter_parent is None: tree_path = self.model_hosts.model[selected_row].path else: tree_path = self.model_hosts.model[iter_parent].path dialog_services = UIServices(parent=self.ui.win_main) # Load services list dialog_services.model.load(model_services.services) dialog_services.show() # Get the new services list, clear and store the list again model_services.services = dialog_services.model.dump() dialog_services.destroy() settings.services.clear() for key in model_services.services.iterkeys(): settings.services.set( section=key, option=OPTION_SERVICE_DESCRIPTION, value=model_services.services[key].description) self.reload_hosts() if selected_row: # Automatically select again the previously selected row self.ui.tvw_connections.set_cursor(path=selected_path, column=None, start_editing=False) def on_action_devices_activate(self, action): """Edit devices""" selected_row = get_treeview_selected_row(self.ui.tvw_connections) if selected_row: iter_parent = self.ui.store_hosts.iter_parent(selected_row) selected_path = self.model_hosts.model[selected_row].path # Get the path of the host if iter_parent is None: tree_path = self.model_hosts.model[selected_row].path else: tree_path = self.model_hosts.model[iter_parent].path dialog_devices = UIDevices(parent=self.ui.win_main) # Load devices list dialog_devices.model.load(model_devices.devices) dialog_devices.show() # Get the new devices list, clear and store the list again model_devices.devices = dialog_devices.model.dump() dialog_devices.destroy() settings.devices.clear() for key in model_devices.devices.iterkeys(): settings.devices.set( section=key, option=OPTION_DEVICE_DESCRIPTION, value=model_devices.devices[key].description) settings.devices.set( section=key, option=OPTION_DEVICE_SERVICES, value=','.join(model_devices.devices[key].services)) self.reload_hosts() if selected_row: # Automatically select again the previously selected row self.ui.tvw_connections.set_cursor(path=selected_path, column=None, start_editing=False) def reload_hosts(self): """Load hosts from the settings files""" self.model_hosts.clear() self.hosts.clear() hosts_path = self.get_current_group_path() # Fix bug where the groups model isn't yet emptied, resulting in # being still used after a clear, then an invalid path if not os.path.isdir(hosts_path): return for filename in os.listdir(hosts_path): # Skip folders, used for groups if os.path.isdir(os.path.join(hosts_path, filename)): continue settings_host = settings.Settings( filename=os.path.join(hosts_path, filename), case_sensitive=True) host = HostInfo( name=settings_host.get(SECTION_HOST, OPTION_HOST_NAME), description=settings_host.get(SECTION_HOST, OPTION_HOST_DESCRIPTION), protocol=settings_host.get(SECTION_HOST, OPTION_HOST_PROTOCOL), address=settings_host.get(SECTION_HOST, OPTION_HOST_ADDRESS), port_number=settings_host.get_int(SECTION_HOST, OPTION_HOST_PORT), version=settings_host.get_int(SECTION_HOST, OPTION_HOST_VERSION), community=settings_host.get(SECTION_HOST, OPTION_HOST_COMMUNITY), device=settings_host.get(SECTION_HOST, OPTION_HOST_DEVICE)) self.add_host(host, False) def add_host(self, host, update_settings): """Add a new host along as with its destinations""" # Add the host to the data and to the model self.hosts[host.name] = host treeiter = self.model_hosts.add_data(host) # Update settings file if requested if update_settings: hosts_path = self.get_current_group_path() settings_host = settings.Settings( filename=os.path.join(hosts_path, '%s.conf' % host.name), case_sensitive=True) # Add host information settings_host.set(SECTION_HOST, OPTION_HOST_NAME, host.name) settings_host.set(SECTION_HOST, OPTION_HOST_DESCRIPTION, host.description) settings_host.set(SECTION_HOST, OPTION_HOST_PROTOCOL, host.protocol) settings_host.set(SECTION_HOST, OPTION_HOST_ADDRESS, host.address) settings_host.set_int(SECTION_HOST, OPTION_HOST_PORT, host.port_number) settings_host.set_int(SECTION_HOST, OPTION_HOST_VERSION, host.version) settings_host.set(SECTION_HOST, OPTION_HOST_COMMUNITY, host.community) settings_host.set(SECTION_HOST, OPTION_HOST_DEVICE, host.device) # Save the settings to the file settings_host.save() def remove_host(self, name): """Remove a host by its name""" hosts_path = self.get_current_group_path() filename = os.path.join(hosts_path, '%s.conf' % name) if os.path.isfile(filename): os.unlink(filename) self.hosts.pop(name) self.model_hosts.remove(self.model_hosts.get_iter(name)) def reload_groups(self): """Load groups from hosts folder""" self.model_groups.clear() # Always add a default group self.model_groups.add_data(GroupInfo('', _('Default group'))) for filename in os.listdir(DIR_HOSTS): if os.path.isdir(os.path.join(DIR_HOSTS, filename)): # For each folder add a new group self.model_groups.add_data(GroupInfo(filename, filename)) def on_action_new_activate(self, action): """Define a new host""" dialog = UIHost(parent=self.ui.win_main, hosts=self.model_hosts) response = dialog.show(name='', description='', protocol='UDP', address='', port_number=161, version=1, community='public', device='', title=_('Add a new host'), treeiter=None) if response == Gtk.ResponseType.OK: host = HostInfo(dialog.name, dialog.description, dialog.protocol, dialog.address, dialog.port_number, dialog.version, dialog.community, dialog.device) self.add_host(host=host, update_settings=True) # Automatically select the newly added host self.ui.tvw_connections.set_cursor( path=self.model_hosts.get_path_by_name(dialog.name), column=None, start_editing=False) dialog.destroy() def on_action_edit_activate(self, action): """Define a new host""" selected_row = get_treeview_selected_row(self.ui.tvw_connections) if selected_row: dialog = UIHost(parent=self.ui.win_main, hosts=self.model_hosts) # Show the edit host dialog model = self.model_hosts name = model.get_key(selected_row) selected_iter = model.get_iter(name) response = dialog.show( name=name, description=model.get_description(selected_row), protocol=model.get_protocol(selected_row), address=model.get_address(selected_row), port_number=model.get_port_number(selected_row), version=model.get_version(selected_row), community=model.get_community(selected_row), device=model.get_device(selected_row), title=_('Edit host'), treeiter=selected_iter) if response == Gtk.ResponseType.OK: # Remove older host and add the newer host = HostInfo(dialog.name, dialog.description, dialog.protocol, dialog.address, dialog.port_number, dialog.version, dialog.community, dialog.device) self.remove_host(name) self.add_host(host=host, update_settings=True) # Get the path of the host tree_path = self.model_hosts.get_path_by_name(dialog.name) # Automatically select again the previously selected host self.ui.tvw_connections.set_cursor(path=tree_path, column=None, start_editing=False) dialog.destroy() def on_tvw_connections_row_activated(self, widget, treepath, column): """Edit the selected row on activation""" selected_row = get_treeview_selected_row(self.ui.tvw_connections) if selected_row: # Start host connection self.ui.action_connect.activate() def on_action_delete_activate(self, action): """Remove the selected host""" selected_row = get_treeview_selected_row(self.ui.tvw_connections) if selected_row and show_message_dialog( class_=UIMessageDialogNoYes, parent=self.ui.win_main, message_type=Gtk.MessageType.QUESTION, title=None, msg1=_("Remove host"), msg2=_("Remove the selected host?"), is_response_id=Gtk.ResponseType.YES): self.remove_host(self.model_hosts.get_key(selected_row)) def on_action_copy_activate(self, action): """Copy the selected host to another""" row = get_treeview_selected_row(self.ui.tvw_connections) if row: model = self.model_hosts name = self.model_hosts.get_key(row) description = self.model_hosts.get_description(row) selected_iter = self.model_hosts.get_iter(name) dialog = UIHost(parent=self.ui.win_main, hosts=self.model_hosts) # Show the edit host dialog response = dialog.show(name=_('Copy of %s') % name, description=description, title=_('Copy host'), protocol=model.get_protocol(row), address=model.get_address(row), port_number=model.get_port_number(row), version=model.get_version(row), community=model.get_community(row), device=model.get_device(row), treeiter=None) if response == Gtk.ResponseType.OK: host = HostInfo(dialog.name, dialog.description, dialog.protocol, dialog.address, dialog.port_number, dialog.version, dialog.community, dialog.device) self.add_host(host=host, update_settings=True) # Get the path of the host tree_path = self.model_hosts.get_path_by_name(dialog.name) # Automatically select again the previously selected host self.ui.tvw_connections.set_cursor(path=tree_path, column=None, start_editing=False) dialog.destroy() def on_tvw_connections_cursor_changed(self, widget): """Set actions sensitiveness for host and connection""" if get_treeview_selected_row(self.ui.tvw_connections): self.ui.actions_connection.set_sensitive(True) self.ui.actions_host.set_sensitive(True) def on_action_connect_activate(self, action): """Establish the connection for the destination""" selected_row = get_treeview_selected_row(self.ui.tvw_connections) if selected_row: model = self.model_hosts dialog = UISNMPValues( parent=self.ui.win_main, host=HostInfo(name=model.get_key(selected_row), description=model.get_description(selected_row), protocol=model.get_protocol(selected_row), address=model.get_address(selected_row), port_number=model.get_port_number(selected_row), version=model.get_version(selected_row), community=model.get_community(selected_row), device=model.get_device(selected_row)) ) dialog.show() def get_current_group_path(self): """Return the path of the currently selected group""" selected_row = get_treeview_selected_row(self.ui.tvw_groups) group_name = self.model_groups.get_key(selected_row) if selected_row \ else '' return os.path.join(DIR_HOSTS, group_name) if group_name else DIR_HOSTS def on_tvw_groups_cursor_changed(self, widget): """Set actions sensitiveness for host and connection""" if get_treeview_selected_row(self.ui.tvw_groups): self.reload_hosts() # Automatically select the first host for the group self.ui.tvw_connections.set_cursor(0) def on_action_groups_activate(self, widget): """Edit groups""" dialog_groups = UIGroups(parent=self.ui.win_main) dialog_groups.model = self.model_groups dialog_groups.ui.tvw_groups.set_model(self.model_groups.model) dialog_groups.show() dialog_groups.destroy() def on_tvw_groups_button_release_event(self, widget, event): """Show groups popup menu on right click""" if event.button == Gdk.BUTTON_SECONDARY: show_popup_menu(self.ui.menu_groups, event.button) def on_tvw_connections_button_release_event(self, widget, event): """Show connections popup menu on right click""" if event.button == Gdk.BUTTON_SECONDARY: show_popup_menu(self.ui.menu_connections, event.button) def on_action_group_previous_activate(self, action): """Move to the previous group""" selected_row = get_treeview_selected_row(self.ui.tvw_groups) new_iter = self.model_groups.model.iter_previous(selected_row) if new_iter: # Select the newly selected row in the groups list new_path = self.model_groups.get_path(new_iter) self.ui.tvw_groups.set_cursor(new_path) def on_action_group_next_activate(self, action): """Move to the next group""" selected_row = get_treeview_selected_row(self.ui.tvw_groups) new_iter = self.model_groups.model.iter_next(selected_row) if new_iter: # Select the newly selected row in the groups list new_path = self.model_groups.get_path(new_iter) self.ui.tvw_groups.set_cursor(new_path)