コード例 #1
0
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)
コード例 #2
0
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()
コード例 #3
0
ファイル: __init__.py プロジェクト: tiwilliam/entertainer
 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'
コード例 #4
0
ファイル: music.py プロジェクト: tiwilliam/entertainer
    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()
コード例 #5
0
ファイル: music.py プロジェクト: tiwilliam/entertainer
 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
コード例 #6
0
ファイル: videos.py プロジェクト: tiwilliam/entertainer
    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
コード例 #7
0
ファイル: videos.py プロジェクト: tiwilliam/entertainer
    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()
コード例 #8
0
ファイル: videos.py プロジェクト: tiwilliam/entertainer
    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 = ""
コード例 #9
0
ファイル: __init__.py プロジェクト: tiwilliam/entertainer
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()
コード例 #10
0
ファイル: factory.py プロジェクト: tiwilliam/entertainer
    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()
コード例 #11
0
    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()
コード例 #12
0
 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)
コード例 #13
0
ファイル: client.py プロジェクト: tiwilliam/entertainer
    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)
コード例 #14
0
    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()
コード例 #15
0
    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))
コード例 #16
0
ファイル: logger.py プロジェクト: tiwilliam/entertainer
    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')
コード例 #17
0
    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
コード例 #18
0
    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!")
コード例 #19
0
    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()
コード例 #20
0
    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()
コード例 #21
0
 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()
コード例 #22
0
    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)
コード例 #23
0
    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))
コード例 #24
0
ファイル: weather.py プロジェクト: tiwilliam/entertainer
 def __init__(self, location=""):
     self.location = location
     self.forecasts = []
     self.theme = Configuration().theme
     self.locale = self._get_locale()
     self.refresh()
コード例 #25
0
ファイル: weather.py プロジェクト: tiwilliam/entertainer
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()
コード例 #26
0
ファイル: slide.py プロジェクト: tiwilliam/entertainer
 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
コード例 #27
0
 def __init__(self):
     self.configuration = Configuration()
     self._store = Store(self.configuration.MEDIA_DB)
コード例 #28
0
ファイル: dialog.py プロジェクト: tiwilliam/entertainer
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)
コード例 #29
0
ファイル: dialog.py プロジェクト: tiwilliam/entertainer
    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)
コード例 #30
0
ファイル: weather.py プロジェクト: tiwilliam/entertainer
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()
コード例 #31
0
    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")
コード例 #32
0
ファイル: indexer.py プロジェクト: tiwilliam/entertainer
 def __init__(self):
     self.configuration = Configuration()
     self.logger = Logger().getLogger(
         'entertainerlib.indexer.indexing.Indexer')
コード例 #33
0
ファイル: weather.py プロジェクト: tiwilliam/entertainer
 def __init__(self, location=""):
     self.location = location
     self.forecasts = []
     self.theme = Configuration().theme
     self.locale = self._get_locale()
     self.refresh()
コード例 #34
0
    def setUp(self):
        '''Set up the test'''
        EntertainerTest.setUp(self)

        self.configuration = Configuration()
コード例 #35
0
 def testBorg(self):
     '''Test that configuration objects share state'''
     self.second_config = Configuration()
     self.assertTrue(
         self.second_config.__dict__ is self.configuration.__dict__)