class ConfigurationTest(EntertainerTest): '''Test for utils.configuration''' def setUp(self): '''Set up the test''' EntertainerTest.setUp(self) self.configuration = Configuration() def test_create(self): '''Test correct Configuration initialization.''' self.assertTrue(isinstance(self.configuration, Configuration)) self.assertEqual(self.configuration.config_dir, os.path.join(self.test_cfg_dir, 'config')) self.assertEqual(self.configuration.theme_path, os.path.join(self.test_cfg_dir, 'data', 'themes', 'Default')) self.assertFalse(self.configuration.tray_icon_enabled) self.assertEqual(self.configuration.port, 45054) self.assertEqual(self.configuration.media_folders, ['']) self.assertEqual(self.configuration.weather_location, 'Bath,England') self.assertTrue(self.configuration.display_weather_in_client) self.assertTrue(self.configuration.download_metadata) self.assertTrue(self.configuration.download_album_art) self.assertFalse(self.configuration.download_lyrics) self.assertTrue(self.configuration.show_effects) self.assertEqual(self.configuration.transition_effect, 'Slide') self.assertEqual(self.configuration.theme_name, 'Default') self.assertTrue(self.configuration.start_in_fullscreen) self.assertTrue(self.configuration.start_auto_server) self.assertEqual(self.configuration.history_size, 8) self.assertEqual(self.configuration.slideshow_step, 5) def test_create_dir(self): '''Test Configuration object directory creation''' self.assertTrue(os.path.exists(self.test_cfg_dir)) def testBorg(self): '''Test that configuration objects share state''' self.second_config = Configuration() self.assertTrue( self.second_config.__dict__ is self.configuration.__dict__) def test_stage_width(self): '''Test the stage_width property.''' self.assertEqual(self.configuration.stage_width, 1366) self.configuration.stage_width = 1600 self.assertEqual(self.configuration.stage_width, 1600) def test_stage_height(self): '''Test the stage_height property.''' self.assertEqual(self.configuration.stage_height, 768) self.configuration.stage_height = 900 self.assertEqual(self.configuration.stage_height, 900) def test_write_content_value(self): """Test writing a value to the content configuration file""" new_value = "Gaithersburg,Maryland" self.configuration.write_content_value("Weather", "location", new_value) self.configuration.update_configuration() self.assertEqual(self.configuration.weather_location, new_value)
def main(*args, **kwargs): '''Client code main loop.''' # Import statements are inside the function so that they aren't imported # every time something from the client is imported # cluttergtk must be imported before the first import of clutter so it # must be imported even though pylint complains about it not being used. import cluttergtk import clutter import gobject import gtk from entertainerlib.client.translation_setup import TranslationSetup TranslationSetup() from entertainerlib.backend.backend_server import BackendServer from entertainerlib.configuration import Configuration from entertainerlib.client.client import Client gobject.threads_init() gtk.gdk.threads_init() clutter.threads_init() config = Configuration() if config.start_auto_server: print "Entertainer backend starting..." BackendServer() client_client = Client() client_client.start()
def setUp(self): '''Set up the basic file I/O requirements.''' self.test_dir = self.get_temp_file() os.mkdir(self.test_dir) self.test_cfg_dir = self.get_temp_file() self.config = Configuration(self.test_cfg_dir) self.data_dir = os.path.dirname(__file__) + '/data'
def __init__(self): self.config = Configuration() if not os.path.exists(self.config.MUSIC_DB): raise Exception("Music database doesn't exist!") self.db_connection = sqlite.connect(self.config.MUSIC_DB) self.cursor = self.db_connection.cursor()
def __init__(self, artist, title, length, year, album_art_url, tracks): self.config = Configuration() self.artist = artist self.title = title self.length = length self.year = year self.album_art_url = album_art_url self.tracks = tracks
def __init__(self, title): self.config = Configuration() self.number_of_episodes = 0 # Season list of numbers. For example [1,2,3,5] in case that user # doesn't have episodes from season 4. self.seasons = [] self.title = title
def __init__(self): self.config = Configuration() if not os.path.exists(self.config.VIDEO_DB): raise Exception("Video database doesn't exist!") self.connection = sqlite.connect(self.config.VIDEO_DB) self.cursor = self.connection.cursor()
def __init__(self): # XXX: laymansterms - VideoItem should really have a few mandatory # parameters. title, filename, maybe more. Playable.__init__(self) self.config = Configuration() self._title = "" self.filename = "" self.art_hash = ""
def server_main(*args, **kwargs): '''Entertainer Server main function.''' startLogging(sys.stdout) config = Configuration() server = server_registry.get(config.network_options['type']) server = server() reactor.listenTCP(config.network_options['port'], server) reactor.run()
def __init__(self, remove_from_stage_callback): '''Initialize the factory The remove_from_stage_callback is a callback that all transition objects require to remove a "from_screen" from the stage without having direct access to the stage. ''' self.remove_from_stage_callback = remove_from_stage_callback self.config = Configuration()
def __init__(self): """Create a new music database object.""" self.logger = Logger().getLogger( 'backend.components.mediacache.MusicCache') self.config = Configuration() if not os.path.exists(self.config.MUSIC_DB): self.__createMusicCacheDatabase() self.__db_conn = sqlite.connect(self.config.MUSIC_DB) self.__db_cursor = self.__db_conn.cursor()
def __init__(self): """ Create a new MediaCacheManager object """ MessageHandler.__init__(self) self.logger = Logger().getLogger( 'backend.components.mediacache.MediaCacheManager') self.config = Configuration() self.video_folders = self.config.media_folders self._index_videos(self.video_folders) self.music_folders = self.config.media_folders self._index_music(self.music_folders) self.image_folders = self.config.media_folders self._index_images(self.image_folders)
def __init__(self): config = Configuration() music_library = MusicLibrary() image_library = ImageLibrary() video_library = VideoLibrary() self.ui = UserInterface(image_library, music_library, video_library, self.quit_client) if config.tray_icon_enabled: SystemTrayIcon(self.quit_client, self.toggle_interface_visibility) startLogging(sys.stdout) client = EntertainerLocalClientProtocol ClientCreator(reactor, client)
def __init__(self): """ Create a new ImageCache. Creates a new database if not already exists and opens a connection to it. """ self.logger = Logger().getLogger( 'backend.components.mediacache.ImageCache') self.config = Configuration() if not os.path.exists(self.config.IMAGE_DB): self._createImageCacheDatabase() self.db_conn = sqlite.connect(self.config.IMAGE_DB) self.db_cursor = self.db_conn.cursor()
def __init__(self, x, y, width, height, direction): Base.__init__(self) clutter.Group.__init__(self) self.config = Configuration() # Size self.width = self.get_abs_x(width) self.height = self.get_abs_y(height) self.direction = direction self.delimiter = " | " self.current = 1 self.maximum = 1 self.theme = self.config.theme self.fg = self.theme.get_color("arrow_foreground") self.bg = self.theme.get_color("arrow_background") if direction == ListIndicator.VERTICAL: text_x_pos = width / 3 else: text_x_pos = width / 2 self.text = Label( height * 0.8, "text", text_x_pos, height / 2, str(self.maximum) + self.delimiter + str(self.maximum)) self.text.set_anchor_point_from_gravity(clutter.GRAVITY_CENTER) self.add(self.text) # Create arrows and calculate positions on screen if direction == ListIndicator.VERTICAL: self.arrow1 = ArrowTexture(5 * width / 7, height / 2, height / 2, self.fg, self.bg, ArrowTexture.UP) self.arrow2 = ArrowTexture(6 * width / 7, height / 2, height / 2, self.fg, self.bg, ArrowTexture.DOWN) elif direction == ListIndicator.HORIZONTAL: self.arrow1 = ArrowTexture(height / 2, height / 2, height / 2, self.fg, self.bg, ArrowTexture.LEFT) self.arrow2 = ArrowTexture(6 * width / 7, height / 2, height / 2, self.fg, self.bg, ArrowTexture.RIGHT) self.add(self.arrow1) self.add(self.arrow2) self.set_position(self.get_abs_x(x), self.get_abs_y(y))
def __init__(self): '''Create a new Entertainer logger object This logger creates the necessary customization for Entertainer logging and should be followed by a getLogger call. Example call: self.logger = Logger().getLogger('my.source.class') ''' self.config = Configuration() logging.basicConfig( level=logging.DEBUG, format='%(asctime)s %(name)s %(levelname)s %(message)s', filename=self.config.LOG, filemode='a')
def __init__(self, filename, album_path, title, description, date, time, width, height,filesize, thumb_hash): """Initialize image""" self.config = Configuration() # Filename of the image (full absolute path) self.__filename = filename # Album path of the album that contains this image self.__album_path = album_path self.__title = title # Title of the image self.__description = description # Description/Comment of the image self.__date = date # Taken date of image self.__time = time # Taken time of the image self.__width = width # Width in pixels self.__height = height # Height in pixels self.__filesize = filesize # Image filesize in bytes self.__thumb_hash = thumb_hash # Image thumbnail hash value
def __init__(self, filename): """ Initialize metadata search thread. @param filename: Filename as string (find metadata for this file) """ threading.Thread.__init__(self) self.setName("Video metadata search thread") self.logger = Logger().getLogger( 'backend.components.mediacache.VideoMetadataSearch') self.config = Configuration() self.filename = filename self.title, self.season, self.episode = self._parse_filename(filename) try: self.IMDb = imdb.IMDb() except imdb.IMDbError: raise IOError("Couldn't connect to IMDB server!")
def __init__(self, path): """Initialize album""" self.config = Configuration() connection = sqlite.connect(self.config.IMAGE_DB) cursor = connection.cursor() cursor.execute( "SELECT path, title, description, hash FROM album WHERE path='%s'" % path) result = cursor.fetchall() self.__path = result[0][0] # Path of the album self.__title = result[0][1] # Title of the album self.__description = result[0][2] # Description text for the album self.__thumbnail = None # Thumbnail URL of the album if len(result[0][3]) > 0: self.__thumbnail = os.path.join(self.config.IMAGE_THUMB_DIR, result[0][3] + ".jpg") connection.close()
def __init__(self): gobject.threads_init() self.config = Configuration() self.logger = Logger().getLogger('backend.BackendServer') self.message_bus = MessageBus() self._port = self.config.port # Connection server - Thread that listens incoming socket connections self.connection_server = None self.scheduler = None self.media_manager = None # The order of the initialize method calls is significant! Don't change # the order unless you know what you are doing! self.initialize_configuration() self.initialize_media_cache_manager() self.initialize_connection_server() self.initialize_scheduler()
def __init__(self, message_type_dictionary=None, message_handler=None, client_name="Unknown client"): """ Create a new MessageBusProxy object @param message_type_dictionary: Dictionary that contains message types @param message_handler: MessageHandler object @param client_name: Name of the client (as string) """ threading.Thread.__init__(self) if message_type_dictionary is None: self.message_type_dictionary = {} else: self.message_type_dictionary = message_type_dictionary self.message_handler = message_handler self.client_name = client_name self.socket_to_server = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) self.socket_as_file = self.socket_to_server.makefile() self.config = Configuration()
def __init__(self, quit_callback, toggle_interface_visibility_callback): '''Create the system tray icon and pop-up menu for it.''' self.quit_callback = quit_callback self.toggle_interface_visibility_callback = \ toggle_interface_visibility_callback self.config = Configuration() # Path to the tray icon when using a branch self.tray_icon_url = os.path.join(self.FILE_DIR, "..", "..", "icons", "hicolor", "24x24", "apps", "entertainer.png") self.icon_widget = gtk.StatusIcon() self.icon_widget.set_tooltip(_("Entertainer Server")) # Load UI with gtk.Builder uifile = os.path.join(self.UI_DIR, 'system_tray_icon_menu.ui') self.menu_widgets = gtk.Builder() self.menu_widgets.set_translation_domain('entertainer') self.menu_widgets.add_from_file(uifile) # Bind menu signals callback_dic = { "on_menuitem_client_activate": self.on_menuitem_client_activate, "on_menuitem_manager_activate": self.on_menuitem_manager_activate, "on_menuitem_log_viewer_activate": self.on_menuitem_log_viewer_activate, "on_menuitem_quit_activate": self.on_menuitem_quit_activate } self.menu_widgets.connect_signals(callback_dic) self.popup = self.menu_widgets.get_object("SystemTrayIconMenu") # Check if running from a branch to set the tray icon if (os.path.exists(self.tray_icon_url)): self.icon_widget.set_from_file(self.tray_icon_url) else: # Must be running from a package, therefore available by icon name self.icon_widget.set_from_icon_name("entertainer") self.icon_widget.connect('activate', self.systray_icon_activated) self.icon_widget.connect('popup-menu', self.open_popup_menu)
def __init__(self, filename, thumb_type): self.config = Configuration() thumb_dir = os.path.join(self.config.THUMB_DIR, thumb_type) self.filename = filename filehash = hashlib.md5() filehash.update(self.filename) self.filename_hash = filehash.hexdigest() if not os.path.exists(self.filename): raise ThumbnailerException( 'File to thumbnail does not exist : %s' % self.filename) if os.path.exists(thumb_dir): if os.path.isfile(filename): self._thumb_file = os.path.join(thumb_dir, self.filename_hash + '.jpg') else: raise ThumbnailerException( 'Thumbnailer filename is a folder : %s' % self.filename) else: raise ThumbnailerException('Unknown thumbnail type : %s' % (thumb_type))
def __init__(self, location=""): self.location = location self.forecasts = [] self.theme = Configuration().theme self.locale = self._get_locale() self.refresh()
class Weather: """Weather class.""" def __init__(self, location=""): self.location = location self.forecasts = [] self.theme = Configuration().theme self.locale = self._get_locale() self.refresh() def _get_locale(self): """Get locale information from user's machine.""" default = locale.getdefaultlocale()[0] if default: lang = default.split("_")[0] else: lang = 'en' return lang def find_forecast(self, search): """Returns the search results page for the search.""" url = WEATHER_LOOKUP_URL + search + "&hl=" + self.locale url = url.replace(" ", "%20") try: raw_data = urllib2.urlopen(url) except urllib2.URLError: self.location = _( "Couldn't get weather reports from the internet!") self.forecasts_are_NA() return # We get the charset from the content-type of the http answer. conent_type = raw_data.info()["Content-Type"] encoding = conent_type.split("=")[1] # We read data according to the relevant charset and then we # prepare it to be parsed by minidom. data = unicode(raw_data.read(), encoding) data = data.encode("utf8") dom = minidom.parseString(data) in_forecast = 0 day = '' low = '' high = '' condition = '' imagename = '' image = '' self.forecasts = [] for node in dom.getElementsByTagNameNS('*', '*'): # a problem occured so bail out if (node.nodeName == 'problem_cause'): print _('Location not found or network problem') break if (node.nodeName == 'forecast_conditions'): in_forecast = 1 if (in_forecast): if node.nodeName == 'day_of_week': day = node.getAttribute('data') if node.nodeName == 'low': low = node.getAttribute('data') converted_low = int(low) if node.nodeName == 'high': high = node.getAttribute('data') converted_high = int(high) if node.nodeName == 'condition': condition = node.getAttribute('data') if node.nodeName == 'icon': imagename = os.path.split(node.getAttribute('data'))[-1] image = self.set_image(imagename) # Condition is the last element of the forecast we are # interested in so write out the forecast if this is set. if (condition): forecast = { "Day": day, "Low": str(converted_low), "High": str(converted_high), "Condition": condition, "Image": image } self.forecasts.append(forecast) in_forecast = 0 day = '' low = '' high = '' condition = '' imagename = '' image = '' return self.forecasts def set_image(self, condition): """Returns an image for a given weather condition.""" try: image_name = WEATHER_IMAGES[condition] except KeyError: image_name = 'weather-na' image = self.theme.getImage(image_name) return image def forecasts_are_NA(self): """Fills forecast with `NA` data.""" self.forecast = [] forecast = { "Day": _("NA"), "Low": _("NA"), "High": _("NA"), "Condition": _("NA"), "Image": self.theme.getImage('weather-na') } while len(self.forecasts) < 4: self.forecasts.append(forecast) def refresh(self): """Clear current weather and forecasts and then loads new data.""" if self.location: self.find_forecast(self.location) else: self.location = _("No weather location defined!") self.forecasts_are_NA()
def __init__(self, remove_from_stage_callback): Transition.__init__(self, remove_from_stage_callback) self.config = Configuration() self.out_behaviour = None self.in_behaviour = None
def __init__(self): self.configuration = Configuration() self._store = Store(self.configuration.MEDIA_DB)
class ManagerDialog: """ This is a content management tool for Entertainer media center application. """ # Temporary storage for entered URL url = "" UI_DIR = os.path.join(os.path.dirname(__file__), "uis") def __init__(self, stand_alone): """ Initialize content management dialog @param stand_alone: Boolean, Is this dialog running as a stand alone process """ self.stand_alone = stand_alone self.config = Configuration() self.themes = [] self.weather = Weather() # Load UI with gtk.Builder uifile = os.path.join(self.UI_DIR, 'manager.ui') self.builder = gtk.Builder() self.builder.set_translation_domain('entertainer') self.builder.add_from_file(uifile) # Get content management dialog and bind signal callbacks self.dialog = self.builder.get_object("ManagerDialog") if (self.dialog): callback_dic = { # Dialog-wide callbacks "on_close_button_clicked" : self.on_close_button_clicked, "on_ManagerDialog_destroy" : self.on_dialog_closed, # Media tab "on_button_remove_media_clicked" : self.on_button_remove_media_clicked, "on_button_add_media_clicked" : self.on_button_add_media_clicked, "on_button_edit_media_clicked" : self.on_button_edit_media_clicked, "on_checkbutton_video_metadata_toggled" : self.on_checkbutton_video_metadata_toggled, "on_lyrics_checkbox_toggled" : self.on_lyrics_checkbox_toggled, "on_art_checkbox_toggled" : self.on_art_checkbox_toggled, "on_button_media_rebuild_clicked" : self.on_button_media_rebuild_clicked, # Weather tab "on_button_add_weather_clicked" : self.on_button_add_weather_clicked, "on_button_remove_weather_clicked" : self.on_button_remove_weather_clicked, "on_weather_display_checkbox_toggled" : self.on_weather_display_checkbox_toggled, "on_location_find_button_clicked" : self.on_location_find_button_clicked, "on_location_cancel_button_clicked" : self.on_location_cancel_button_clicked, "on_location_add_button_clicked" : self.on_location_add_button_clicked, "on_location_entry_activate" : self.on_location_entry_activate, # User Interface tab "on_theme_list_cursor_changed" : self.on_theme_list_cursor_changed, "on_theme_add_button_clicked" : self.on_theme_add_button_clicked, "on_theme_remove_button_clicked" : self.on_theme_remove_button_clicked, "on_checkbutton_effects_toggled" : self.on_checkbutton_effects_toggled, "on_combobox_effects_changed" : self.on_combobox_effects_changed, # General tab "on_checkbutton_fullscreen_toggled" : self.on_checkbutton_fullscreen_toggled, "on_checkbutton_autostart_toggled" : self.on_checkbutton_autostart_toggled, "on_checkbutton_systray_icon_toggled" : self.on_checkbutton_systray_icon_toggled, "on_spinbutton_slideshow_step_value_changed": self.on_spinbutton_slideshow_step_value_changed } self.builder.connect_signals(callback_dic) # Initialize dialog widgets with correct values and show dialog self.init_dialog_values_from_configure_file() self.dialog.resize(500, 300) self.dialog.show() # Initialize location list in search dialog result_list = self.builder.get_object("location_results_treeview") store = gtk.ListStore(str) result_list.set_model(store) cell_renderer = gtk.CellRendererText() column = gtk.TreeViewColumn(_("Location"), cell_renderer, text=0) result_list.append_column(column) def on_dialog_closed(self, widget): """Callback function for dialog's close button""" try: proxy = MessageBusProxy(client_name = "Manager GUI") proxy.connectToMessageBus() proxy.sendMessage(Message(MessageType.CONTENT_CONF_UPDATED)) proxy.disconnectFromMessageBus() except socket.error: error = gtk.MessageDialog( None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _( "Entertainer backend is not running. " "Cache cannot be rebuilt." )) error.run() error.destroy() if(self.stand_alone): self.dialog.hide() self.dialog.destroy() gtk.main_quit() else: self.dialog.hide() self.dialog.destroy() def on_close_button_clicked(self, widget): """Callback function for dialog's close button""" if(self.stand_alone): self.dialog.hide() self.dialog.destroy() gtk.main_quit() else: self.dialog.hide() self.dialog.destroy() def on_button_add_media_clicked(self, widget): """Opens add URL dialog. """ widget = self.builder.get_object("treeview_media") model = widget.get_model() # Open "Select folder" dialog dialog = gtk.FileChooserDialog(_("Select folder"), None, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, (gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN,gtk.RESPONSE_OK), None) status = dialog.run() # If folder was selected we add it to model and update config file if(status == gtk.RESPONSE_OK): self.add_to_model_and_config(dialog.get_current_folder(), model, self.media_folders, "Media") dialog.destroy() def on_button_remove_media_clicked(self, widget): """Remove currently selected folder from media folders""" widget = self.builder.get_object("treeview_media") model = widget.get_model() selection = widget.get_selection().get_selected() if selection[1] == None: return rm_folder = model.get_value(selection[1], 0) self.media_folders.remove(rm_folder) str_folders = ";".join(self.media_folders) self.config.write_content_value("Media", "folders", str_folders) model.remove(selection[1]) def on_button_edit_media_clicked(self, widget): """Edit currently selected folder""" widget = self.builder.get_object("treeview_media") url_dialog = self.builder.get_object("url_dialog") url_entry = self.builder.get_object("url_entry") model = widget.get_model() selection = widget.get_selection().get_selected() if selection[1] == None: return folder = model.get_value(selection[1], 0) url_entry.set_text(folder) url_dialog.set_title(_("Edit URL")) status = url_dialog.run() if status == gtk.RESPONSE_OK and os.path.exists(self.url): # Update list model model.set_value(selection[1], 0, self.url) # Update configure file pos = self.media_folders.index(folder) self.media_folders.remove(folder) self.media_folders.insert(pos, self.url) str_folders = ";".join(self.media_folders) self.config.write_content_value("Media", "folders", str_folders) def on_checkbutton_autostart_toggled(self, widget): '''Server autostart checkbox toggled.''' self.config.write_content_value("General", "start_server_auto", widget.get_active()) def on_checkbutton_fullscreen_toggled(self, widget): '''Start in fullscreen checkbox toggled.''' self.config.write_content_value("General", "start_in_fullscreen", widget.get_active()) def on_checkbutton_systray_icon_toggled(self, widget): """System Tray Icon checkbox toggled""" self.config.write_content_value("General", "display_icon", widget.get_active()) def on_checkbutton_video_metadata_toggled(self, widget): """ Download video file metadata from internet @param widget: GTK-Widget """ self.config.write_content_value("Media", "download_metadata", widget.get_active()) def on_spinbutton_slideshow_step_value_changed(self, widget): """Activation of slideshow effects""" self.config.write_content_value("Photographs", "slideshow_step", int(widget.get_value())) def on_lyrics_checkbox_toggled(self, widget): self.config.write_content_value("Media", "download_lyrics", widget.get_active()) def on_art_checkbox_toggled(self, widget): self.config.write_content_value("Media", "download_album_art", widget.get_active()) def on_button_add_weather_clicked(self, widget): """ Open location search dialog @param widget: GTK-Widget """ location_dialog = self.builder.get_object("weather_search_dialog") location_dialog.set_title(_("Add location")) # Clear results result_list = self.builder.get_object("location_results_treeview") model = result_list.get_model() model.clear() status = location_dialog.run() if(status == gtk.RESPONSE_OK): print "Added" def on_button_remove_weather_clicked(self, widget): """ Remove currently selected weather location from the location list @param widget: GTK-Widget """ widget = self.builder.get_object("treeview_locations") model = widget.get_model() self.weather_locations = [] str_folders = "" self.config.write_content_value("Weather", "location", str_folders) model.clear() def on_weather_display_checkbox_toggled(self, widget): """ Checkbox that defines should we use weather conditions @param widget: GTK-Widget """ self.config.write_content_value("Weather", "display_in_menu", widget.get_active()) if widget.get_active(): self.builder.get_object("button_add_weather").set_sensitive(True) self.builder.get_object( "button_remove_weather").set_sensitive(True) self.builder.get_object("treeview_locations").set_sensitive(True) else: self.builder.get_object("button_add_weather").set_sensitive(False) self.builder.get_object( "button_remove_weather").set_sensitive(False) self.builder.get_object("treeview_locations").set_sensitive(False) def on_location_find_button_clicked(self, widget): """ Find location by search string @param widget: GTK-Widget """ add_button = self.builder.get_object("location_add_button") search_term = self.builder.get_object("location_entry").get_text() result_list = self.builder.get_object("location_results_treeview") model = result_list.get_model() model.clear() if search_term != "": self.weather.location = search_term self.weather.refresh() results = self.weather.forecasts if len(results) > 0: add_button.set_sensitive(True) model.append([search_term]) result_list.set_cursor(0) else: model.clear() model.append([_("Location Not Found!")]) add_button.set_sensitive(False) def on_location_cancel_button_clicked(self, widget): """ Close location search dialog without taking any actions.0 @param widget: GTK-Widget """ location_dialog = self.builder.get_object("weather_search_dialog") location_entry = self.builder.get_object("location_entry") location_dialog.hide() location_entry.set_text("") location_dialog.response(gtk.RESPONSE_CANCEL) def on_location_add_button_clicked(self, widget): """ Add selected location to location list and close search dialog @param widget: GTK-Widget """ self.weather_locations = [] result_list = self.builder.get_object("location_results_treeview") model = result_list.get_model() selection = result_list.get_selection().get_selected() if selection[1] == None: return location_string = model.get_value(selection[1], 0) location_list = self.builder.get_object("treeview_locations") loc_model = location_list.get_model() loc_model.clear() loc_model.append([location_string]) self.weather_locations.append(location_string) str_locations = ";".join(self.weather_locations) self.config.write_content_value("Weather", "location", str_locations) location_dialog = self.builder.get_object("weather_search_dialog") location_entry = self.builder.get_object("location_entry") location_dialog.hide() location_entry.set_text("") location_dialog.response(gtk.RESPONSE_CANCEL) def on_location_entry_activate(self, widget): """ User hit enter on location entry to start search @param widget: GTK-Widget """ self.on_location_find_button_clicked(widget) def on_button_media_rebuild_clicked(self, widget): '''Rebuild media cache requested.''' try: proxy = MessageBusProxy(client_name = "Manager GUI") proxy.connectToMessageBus() proxy.sendMessage(Message(MessageType.REBUILD_IMAGE_CACHE)) proxy.sendMessage(Message(MessageType.REBUILD_MUSIC_CACHE)) proxy.sendMessage(Message(MessageType.REBUILD_VIDEO_CACHE)) proxy.disconnectFromMessageBus() except socket.error: error = gtk.MessageDialog( None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _( "Entertainer backend is not running. " "Cache cannot be rebuilt." )) error.run() error.destroy() def on_theme_add_button_clicked(self, widget): """Add theme button clicked""" themelist = self.builder.get_object("theme_list") model = themelist.get_model() # Open "Select folder" dialog dialog = gtk.FileChooserDialog(_("Select theme package file"), None, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK), None) file_filter = gtk.FileFilter() file_filter.set_name(_("Theme package (tar.gz)")) file_filter.add_pattern("*.tar.gz") dialog.add_filter(file_filter) status = dialog.run() # If theme was selected with file chooser if(status == gtk.RESPONSE_OK): package = dialog.get_filename() tar = tarfile.open(package, 'r:gz') # Open tar.gz package # Make sure that package contains configuration file (is theme) content = tar.getnames() theme_name = None is_theme = False for element in content: if element[-10:] == "theme.conf": theme_name = element[:-11] is_theme = True # Install them if is_theme: tar.extractall(os.path.join(self.config.data_dir, 'themes')) model.insert(len(model), [theme_name]) else: error = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Invalid theme file!")) error.run() error.destroy() dialog.destroy() def on_theme_list_cursor_changed(self, widget): """Executed when theme is changed in theme list. Update preview.""" # Get currently selected theme themelist = self.builder.get_object("theme_list") model = themelist.get_model() selection = themelist.get_selection().get_selected() name = model.get_value(selection[1], 0) themedir = os.path.join(self.config.data_dir, 'themes', name) theme = Theme(theme_path=themedir) # Update preview image = self.builder.get_object("theme_image") image.set_from_file(os.path.join(themedir, "thumbnail.png")) name = self.builder.get_object("name_label") name.set_text(theme.getName()) author = self.builder.get_object("author_label") author.set_text(theme.getAuthor()) license_label = self.builder.get_object("license_label") license_label.set_text(theme.getLicence()) copyright_label = self.builder.get_object("copyright_label") copyright_label.set_text(theme.getCopyright()) comment = self.builder.get_object("comment_label") comment.set_text(theme.getComment()) self.config.write_content_value("General", "theme", name.get_text()) def on_theme_remove_button_clicked(self, widget): """Remove theme button clicked""" # Get currently selected theme themelist = self.builder.get_object("theme_list") model = themelist.get_model() selection = themelist.get_selection().get_selected() name = model.get_value(selection[1], 0) confirm = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, _("Are you sure you want to delete\ntheme: %(name)s") % \ {'name': name}) status = confirm.run() confirm.destroy() if(status == gtk.RESPONSE_YES): themedir = os.path.join(self.config.data_dir, 'themes', name) shutil.rmtree(themedir) model.remove(selection[1]) themelist.set_cursor(0) self.themes.remove(name) def on_checkbutton_effects_toggled(self, widget): """Effect checkbox toggled""" combobox = self.builder.get_object("combobox_effects") combobox.set_sensitive(widget.get_active()) self.config.write_content_value("General", "show_effects", widget.get_active()) def on_combobox_effects_changed(self, widget): """User changed effect for screen transitions""" text = widget.get_active_text() if text == _("No effect"): english_text = "No effect" if text == _("Crossfade"): english_text = "Crossfade" if text == _("Zoom and fade"): english_text = "Zoom and fade" if text == _("Slide"): english_text = "Slide" self.config.write_content_value("General", "transition_effect", english_text) def init_dialog_values_from_configure_file(self): """Read configuration and set dialog widget values with read values. """ # == Videos == medialist_widget = self.builder.get_object("treeview_media") mediastore = gtk.ListStore(str) cell_renderer = gtk.CellRendererText() column = gtk.TreeViewColumn(_("Folders"), cell_renderer, text=0) medialist_widget.append_column(column) self.media_folders = self.config.media_folders # Fill model with folders read from config file self.init_model(mediastore, self.media_folders) medialist_widget.set_model(mediastore) # Checkboxes metadata_checkbox = self.builder.get_object("video_metadata_checkbox") metadata_checkbox.set_active(self.config.download_metadata) art_checkbox = self.builder.get_object("art_checkbox") art_checkbox.set_active(self.config.download_album_art) lyrics_checkbox = self.builder.get_object("lyrics_checkbox") lyrics_checkbox.set_active(self.config.download_lyrics) # == Weather == locationlist_widget = self.builder.get_object("treeview_locations") location_model = gtk.ListStore(str) loc_cell = gtk.CellRendererText() location_column = gtk.TreeViewColumn(_("Location"), loc_cell, text=0) locationlist_widget.append_column(location_column) self.weather_location = self.config.weather_location # Fill model with location read from config file location_model.insert(0, [self.weather_location]) locationlist_widget.set_model(location_model) weather_display_checkbox = self.builder.get_object( "weather_display_checkbox") display_val = self.config.display_weather_in_client weather_display_checkbox.set_active(display_val) if not display_val: self.builder.get_object("button_add_weather").set_sensitive(False) self.builder.get_object("button_remove_weather").set_sensitive( False) self.builder.get_object("treeview_locations").set_sensitive(False) # == User Interface == self.load_themes() current_theme = self.config.theme_name themelist_widget = self.builder.get_object("theme_list") model = gtk.ListStore(str) cell_renderer = gtk.CellRendererText() column = gtk.TreeViewColumn("Themes", cell_renderer, text=0) themelist_widget.append_column(column) # Fill model with installed themes for i in range(len(self.themes)): model.insert(i, [self.themes[i]]) themelist_widget.set_model(model) # Set current theme selected in theme list index = model.get_iter_first() unselected = True index_counter = 0 while(unselected): name = model.get_value(index, 0) if name == current_theme: unselected = False themelist_widget.set_cursor(index_counter) index = model.iter_next(index) index_counter += 1 effect_checkbox = self.builder.get_object("checkbutton_effects") effect_combobox = self.builder.get_object("combobox_effects") if self.config.show_effects: effect_checkbox.set_active(True) effect_combobox.set_sensitive(True) else: effect_checkbox.set_active(False) effect_combobox.set_sensitive(False) # Set Effect Combobox value (Text values are set in ui file) effect = self.config.transition_effect if effect == "No effect": effect_combobox.set_active(0) if effect == "Crossfade": effect_combobox.set_active(1) if effect == "Zoom and fade": effect_combobox.set_active(2) if effect == "Slide": effect_combobox.set_active(3) # == General == checkbutton_fullscreen = self.builder.get_object( "checkbutton_fullscreen") if self.config.start_in_fullscreen: checkbutton_fullscreen.set_active(True) else: checkbutton_fullscreen.set_active(False) checkbutton_autostart = self.builder.get_object("checkbutton_autostart") if self.config.start_auto_server: checkbutton_autostart.set_active(True) else: checkbutton_autostart.set_active(False) checkbutton_systray_icon = self.builder.get_object( "checkbutton_systray_icon") if self.config.tray_icon_enabled: checkbutton_systray_icon.set_active(True) else: checkbutton_systray_icon.set_active(False) spinbutton_slideshow_step = self.builder.get_object( "spinbutton_slideshow_step") spinbutton_slideshow_step.set_value(self.config.slideshow_step) def add_to_model_and_config(self, selected_folder, model, folders, kind): """ Add selected_folder to the model and the folders list while updating the configuration item section specified by type """ if not selected_folder in folders: model.append([selected_folder]) if(folders == None): folders = [selected_folder] else: folders.append(selected_folder) if "" in folders: folders.remove("") str_folders = ";".join(folders) self.config.write_content_value(kind, "folders", str_folders) def init_model(self, model, items): """Fill model with items from supplied list""" for i in range(len(items)): if not str(items[i]).strip() == "": model.insert(i, [items[i]]) def load_themes(self): """Load themes""" themes = os.listdir(os.path.join(self.config.data_dir, 'themes')) for element in themes: theme = os.path.join(self.config.data_dir, 'themes', element) if os.path.isdir(theme): self.themes.append(element)
def __init__(self, stand_alone): """ Initialize content management dialog @param stand_alone: Boolean, Is this dialog running as a stand alone process """ self.stand_alone = stand_alone self.config = Configuration() self.themes = [] self.weather = Weather() # Load UI with gtk.Builder uifile = os.path.join(self.UI_DIR, 'manager.ui') self.builder = gtk.Builder() self.builder.set_translation_domain('entertainer') self.builder.add_from_file(uifile) # Get content management dialog and bind signal callbacks self.dialog = self.builder.get_object("ManagerDialog") if (self.dialog): callback_dic = { # Dialog-wide callbacks "on_close_button_clicked" : self.on_close_button_clicked, "on_ManagerDialog_destroy" : self.on_dialog_closed, # Media tab "on_button_remove_media_clicked" : self.on_button_remove_media_clicked, "on_button_add_media_clicked" : self.on_button_add_media_clicked, "on_button_edit_media_clicked" : self.on_button_edit_media_clicked, "on_checkbutton_video_metadata_toggled" : self.on_checkbutton_video_metadata_toggled, "on_lyrics_checkbox_toggled" : self.on_lyrics_checkbox_toggled, "on_art_checkbox_toggled" : self.on_art_checkbox_toggled, "on_button_media_rebuild_clicked" : self.on_button_media_rebuild_clicked, # Weather tab "on_button_add_weather_clicked" : self.on_button_add_weather_clicked, "on_button_remove_weather_clicked" : self.on_button_remove_weather_clicked, "on_weather_display_checkbox_toggled" : self.on_weather_display_checkbox_toggled, "on_location_find_button_clicked" : self.on_location_find_button_clicked, "on_location_cancel_button_clicked" : self.on_location_cancel_button_clicked, "on_location_add_button_clicked" : self.on_location_add_button_clicked, "on_location_entry_activate" : self.on_location_entry_activate, # User Interface tab "on_theme_list_cursor_changed" : self.on_theme_list_cursor_changed, "on_theme_add_button_clicked" : self.on_theme_add_button_clicked, "on_theme_remove_button_clicked" : self.on_theme_remove_button_clicked, "on_checkbutton_effects_toggled" : self.on_checkbutton_effects_toggled, "on_combobox_effects_changed" : self.on_combobox_effects_changed, # General tab "on_checkbutton_fullscreen_toggled" : self.on_checkbutton_fullscreen_toggled, "on_checkbutton_autostart_toggled" : self.on_checkbutton_autostart_toggled, "on_checkbutton_systray_icon_toggled" : self.on_checkbutton_systray_icon_toggled, "on_spinbutton_slideshow_step_value_changed": self.on_spinbutton_slideshow_step_value_changed } self.builder.connect_signals(callback_dic) # Initialize dialog widgets with correct values and show dialog self.init_dialog_values_from_configure_file() self.dialog.resize(500, 300) self.dialog.show() # Initialize location list in search dialog result_list = self.builder.get_object("location_results_treeview") store = gtk.ListStore(str) result_list.set_model(store) cell_renderer = gtk.CellRendererText() column = gtk.TreeViewColumn(_("Location"), cell_renderer, text=0) result_list.append_column(column)
class Weather: """Weather class.""" def __init__(self, location=""): self.location = location self.forecasts = [] self.theme = Configuration().theme self.locale = self._get_locale() self.refresh() def _get_locale(self): """Get locale information from user's machine.""" default = locale.getdefaultlocale()[0] if default: lang = default.split("_")[0] else: lang = 'en' return lang def find_forecast(self, search): """Returns the search results page for the search.""" url = WEATHER_LOOKUP_URL + search + "&hl=" + self.locale url = url.replace(" ", "%20") try: raw_data = urllib2.urlopen(url) except urllib2.URLError: self.location = _("Couldn't get weather reports from the internet!") self.forecasts_are_NA() return # We get the charset from the content-type of the http answer. conent_type = raw_data.info()["Content-Type"] encoding = conent_type.split("=")[1] # We read data according to the relevant charset and then we # prepare it to be parsed by minidom. data = unicode(raw_data.read(), encoding) data = data.encode("utf8") dom = minidom.parseString(data) in_forecast = 0 day = '' low = '' high = '' condition = '' imagename = '' image = '' self.forecasts = [] for node in dom.getElementsByTagNameNS('*', '*'): # a problem occured so bail out if (node.nodeName == 'problem_cause'): print _('Location not found or network problem') break if (node.nodeName == 'forecast_conditions'): in_forecast = 1 if (in_forecast): if node.nodeName == 'day_of_week': day = node.getAttribute('data') if node.nodeName == 'low': low = node.getAttribute('data') converted_low = int(low) if node.nodeName == 'high': high = node.getAttribute('data') converted_high = int(high) if node.nodeName == 'condition': condition = node.getAttribute('data') if node.nodeName == 'icon': imagename = os.path.split(node.getAttribute('data'))[-1] image = self.set_image(imagename) # Condition is the last element of the forecast we are # interested in so write out the forecast if this is set. if (condition): forecast = {"Day":day, "Low":str(converted_low), "High":str(converted_high), "Condition":condition, "Image":image} self.forecasts.append(forecast) in_forecast = 0 day = '' low = '' high = '' condition = '' imagename = '' image = '' return self.forecasts def set_image(self, condition): """Returns an image for a given weather condition.""" try: image_name = WEATHER_IMAGES[condition] except KeyError: image_name = 'weather-na' image = self.theme.getImage(image_name) return image def forecasts_are_NA(self): """Fills forecast with `NA` data.""" self.forecast = [] forecast = {"Day": _("NA"), "Low": _("NA"), "High": _("NA"), "Condition": _("NA"), "Image":self.theme.getImage('weather-na')} while len(self.forecasts) < 4: self.forecasts.append(forecast) def refresh(self): """Clear current weather and forecasts and then loads new data.""" if self.location: self.find_forecast(self.location) else: self.location = _("No weather location defined!") self.forecasts_are_NA()
def __init__(self, image_library, music_library, video_library, quit_client_callback): self.quit_client_callback = quit_client_callback self.config = Configuration() # Store the dimensions in case users want to return to window mode self.old_width = self.config.stage_width self.old_height = self.config.stage_height self.logger = Logger().getLogger('client.gui.UserInterface') self.window = gtk.Window() self.window.connect('destroy', self.destroy_callback) self.window.set_title('Entertainer') # Set the window icon icon_theme = gtk.icon_theme_get_default() try: icon = icon_theme.load_icon('entertainer', 48, 0) self.window.set_icon(icon) except gobject.GError: # Must not be installed from a package, get icon from the branch file_dir = os.path.dirname(__file__) icon_path = os.path.join(file_dir, '..', '..', 'icons', 'hicolor', '48x48', 'apps', 'entertainer.png') icon = gtk.gdk.pixbuf_new_from_file(icon_path) self.window.set_icon(icon) # cluttergtk.Embed contains the stage that is the canvas for the GUI embed = cluttergtk.Embed() # Enforce a minimum size to prevent weird widget bugs embed.set_size_request( self.config.stage_width, self.config.stage_height) self.window.add(embed) # The embed widget must be realized before you can get the stage. embed.realize() self.stage = embed.get_stage() self._hide_cursor_timeout_key = None self.stage.connect('key-press-event', self.handle_keyboard_event) self.stage.connect('motion-event', self._handle_motion_event) self.stage.set_color(self.config.theme.get_color("background")) self.stage.set_size(self.config.stage_width, self.config.stage_height) self.stage.set_title("Entertainer") if self.config.start_in_fullscreen: self._fullscreen() self.is_fullscreen = True else: self.is_fullscreen = False # Initialize Screen history (allows user to navigate "back") self.history = ScreenHistory(self._remove_from_stage) self.player = MediaPlayer(self.stage, self.config.stage_width, self.config.stage_height) self.player.connect('volume-changed', self._on_volume_changed) # Initialize menu overlay texture self.is_overlay = False self.menu_overlay = MenuOverlay(self.config.theme) self.menu_overlay.set_opacity(0) self.menu_overlay.set_size( self.config.stage_width, self.config.stage_height) self.stage.add(self.menu_overlay) self.volume_indicator = VolumeIndicator() self.stage.add(self.volume_indicator) self.volume_indicator.connect('hiding', self._on_volume_indicator_hiding) self.fade_screen_timeline = clutter.Timeline(200) alpha = clutter.Alpha(self.fade_screen_timeline, clutter.EASE_IN_OUT_SINE) self.fade_screen_behaviour = clutter.BehaviourOpacity(255, 0, alpha) # Transition object. Handles effects between screen changes. transition_factory = TransitionFactory(self._remove_from_stage) self.transition = transition_factory.generate_transition() # Screen factory to create new screens self.screen_factory = ScreenFactory( image_library, music_library, video_library, self.player, self.move_to_new_screen, self.move_to_previous_screen) def default_key_to_user_event(): '''Return the default user event provided by an unmapped keyboard event.''' return UserEvent.DEFAULT_EVENT # Dictionary for keyboard event handling self.key_to_user_event = defaultdict(default_key_to_user_event, { clutter.keysyms.Return : UserEvent.NAVIGATE_SELECT, clutter.keysyms.Up : UserEvent.NAVIGATE_UP, clutter.keysyms.Down : UserEvent.NAVIGATE_DOWN, clutter.keysyms.Left : UserEvent.NAVIGATE_LEFT, clutter.keysyms.Right : UserEvent.NAVIGATE_RIGHT, clutter.keysyms.BackSpace : UserEvent.NAVIGATE_BACK, clutter.keysyms.h : UserEvent.NAVIGATE_HOME, clutter.keysyms.w : UserEvent.NAVIGATE_FIRST_PAGE, clutter.keysyms.e : UserEvent.NAVIGATE_PREVIOUS_PAGE, clutter.keysyms.r : UserEvent.NAVIGATE_NEXT_PAGE, clutter.keysyms.t : UserEvent.NAVIGATE_LAST_PAGE, clutter.keysyms.f : UserEvent.TOGGLE_FULLSCREEN, clutter.keysyms.p : UserEvent.PLAYER_PLAY_PAUSE, clutter.keysyms.s : UserEvent.PLAYER_STOP, clutter.keysyms._1 : UserEvent.USE_ASPECT_RATIO_1, clutter.keysyms._2 : UserEvent.USE_ASPECT_RATIO_2, clutter.keysyms._3 : UserEvent.USE_ASPECT_RATIO_3, clutter.keysyms._4 : UserEvent.USE_ASPECT_RATIO_4, clutter.keysyms.x : UserEvent.PLAYER_SKIP_BACKWARD, clutter.keysyms.c : UserEvent.PLAYER_SKIP_FORWARD, clutter.keysyms.z : UserEvent.PLAYER_PREVIOUS, clutter.keysyms.v : UserEvent.PLAYER_NEXT, clutter.keysyms.m : UserEvent.PLAYER_VOLUME_UP, clutter.keysyms.l : UserEvent.PLAYER_VOLUME_DOWN, clutter.keysyms.q : UserEvent.QUIT, clutter.keysyms.Escape : UserEvent.QUIT }) self.event_handlers = { UserEvent.DEFAULT_EVENT : self._handle_default, UserEvent.NAVIGATE_SELECT : self._handle_default, UserEvent.NAVIGATE_UP : self._handle_default, UserEvent.NAVIGATE_DOWN : self._handle_default, UserEvent.NAVIGATE_LEFT : self._handle_default, UserEvent.NAVIGATE_RIGHT : self._handle_default, UserEvent.NAVIGATE_BACK : self._handle_navigate_back, UserEvent.NAVIGATE_HOME : self._handle_navigate_home, UserEvent.NAVIGATE_FIRST_PAGE : self._handle_default, UserEvent.NAVIGATE_PREVIOUS_PAGE : self._handle_default, UserEvent.NAVIGATE_NEXT_PAGE : self._handle_default, UserEvent.NAVIGATE_LAST_PAGE : self._handle_default, UserEvent.TOGGLE_FULLSCREEN : self._handle_toggle_fullscreen, UserEvent.PLAYER_PLAY_PAUSE : self._handle_player_play_pause, UserEvent.PLAYER_STOP : self._handle_player_stop, UserEvent.USE_ASPECT_RATIO_1 : self._handle_aspect_ratio, UserEvent.USE_ASPECT_RATIO_2 : self._handle_aspect_ratio, UserEvent.USE_ASPECT_RATIO_3 : self._handle_aspect_ratio, UserEvent.USE_ASPECT_RATIO_4 : self._handle_aspect_ratio, UserEvent.PLAYER_SKIP_BACKWARD : self._handle_player_skip_backward, UserEvent.PLAYER_SKIP_FORWARD : self._handle_player_skip_forward, UserEvent.PLAYER_PREVIOUS : self._handle_player_previous, UserEvent.PLAYER_NEXT : self._handle_player_next, UserEvent.PLAYER_VOLUME_UP : self._handle_player_volume_up, UserEvent.PLAYER_VOLUME_DOWN : self._handle_player_volume_down, UserEvent.QUIT : self._handle_quit_client } self.logger.debug("Frontend GUI initialized succesfully")
def __init__(self): self.configuration = Configuration() self.logger = Logger().getLogger( 'entertainerlib.indexer.indexing.Indexer')
def setUp(self): '''Set up the test''' EntertainerTest.setUp(self) self.configuration = Configuration()
def testBorg(self): '''Test that configuration objects share state''' self.second_config = Configuration() self.assertTrue( self.second_config.__dict__ is self.configuration.__dict__)