def __init__(self, db_query):
        
        # Init.
        gtk.VBox.__init__(self)
        SignalContainer.__init__(self)
        
        self.__db_query = db_query
        self.update_interval = 3000 # 3000 millisecond.
        self.reload_flag = False
        self.search_flag = False
        self.cache_search_list = []
        self.cache_search_view = []
        self.__selected_tag = {"album": [], "artist": [], "genre": []}
        Dispatcher.connect("reload-browser", self.on_dispatcher_reload_browser)
        gobject.timeout_add(self.update_interval, self.on_interval_loaded_view)
        
        # The saving song Classification presented to the user.
        self.artists_view, self.artists_sw  = self.get_icon_view(14)
        self.albums_view,  self.albums_sw   = self.get_icon_view(14)
        self.genres_view,  self.genres_sw   = self.get_icon_view(14)
        self.folders_view, self.folders_sw  = self.get_icon_view(20)
        self.folders_view.connect("motion-notify-item", self.on_folders_view_motion_notify)
        
        # Song list for temporarily storing
        # self.songs_view, self.songs_view_sw = self.get_song_view()
        self.songs_view = self.get_song_view()
        
        # Classification navigation bar.
        self.filterbar = OptionBar(
            [(app_theme.get_pixbuf("filter/artist_normal.png"), app_theme.get_pixbuf("filter/artist_press.png"),
              _("Artist"), lambda : self.switch_filter_view("artist")),
             (app_theme.get_pixbuf("filter/album_normal.png"), app_theme.get_pixbuf("filter/album_press.png"),
              _("Album"), lambda : self.switch_filter_view("album")),
             (app_theme.get_pixbuf("filter/genre_normal.png"), app_theme.get_pixbuf("filter/genre_press.png"),
              _("Genre"), lambda : self.switch_filter_view("genre")),
             (app_theme.get_pixbuf("filter/local_normal.png"), app_theme.get_pixbuf("filter/local_press.png"),
              _("Folder"), lambda : self.switch_filter_view("folder"))
             ])
        
        # Manage the media library (import, refresh)
        self.importbar = SongImportBar()
        self.importbar.reload_items(
            [
             (_("Quick Scan"), lambda : ImportFolderJob([os.path.expanduser("~")])),                
             (_("Scan"), lambda : ImportFolderJob()),
             (_("Refresh"), lambda : ReloadDBJob())
             ])
        
        # Left box
        invailed_box = gtk.VBox()
        invailed_box.set_size_request(-1, 10)
        left_vbox = gtk.VBox(spacing=10)
        left_vbox.set_size_request(121, -1)
        # left_vbox.pack_start(invailed_box, False, True)
        left_vbox.pack_start(self.filterbar, False, False)
        left_vbox.pack_start(create_separator_box(), False, False)
        left_vbox.pack_start(self.importbar, False, False)
        
        # Used to switch songs category view, in the right side of the layout.
        self.switch_view_box = gtk.VBox()
        self.switch_view_box.add(self.artists_sw)
        # self.switch_view_box.add(TaskView())

        
        # Control back on a view.
        self.back_hbox = gtk.HBox()
        self.back_hbox.set_size_request(-1, 26)
        self.back_hbox.set_no_show_all(True)
        self.back_button = BackButton()
        self.back_button.connect("clicked", self.on_back_button_clicked)
        self.prompt_button = PromptButton()
        self.back_hbox.pack_start(self.back_button, False, False, 5)
        self.back_hbox.pack_start(self.prompt_button, False, False)
        
        # searchbar 
        self.search_entry, search_align = self.get_search_entry()
        search_hbox = gtk.HBox()
        search_hbox.pack_start(self.back_hbox, False, False)
        search_hbox.pack_start(create_right_align(), True, True)
        # search_hbox.pack_start(search_align, False, False)
        search_hbox_align = gtk.Alignment()
        search_hbox_align.set_padding(5, 0, 0, 0)
        search_hbox_align.set(0, 0, 1, 1)
        search_hbox_align.add(search_hbox)
        
        # Layout on the right.
        content_box = gtk.VBox(spacing=5)
        content_box.pack_start(search_hbox_align, False, False)
        content_box.pack_start(self.switch_view_box, True, True)
        
        body_paned = HPaned(handle_color=app_theme.get_color("panedHandler"), enable_drag=True)
        body_paned.add1(left_vbox)
        body_paned.add2(content_box)
        
        self.pack_start(body_paned, True, True)
class Browser(gtk.VBox, SignalContainer):        
    
    def __init__(self, db_query):
        
        # Init.
        gtk.VBox.__init__(self)
        SignalContainer.__init__(self)
        
        self.__db_query = db_query
        self.update_interval = 3000 # 3000 millisecond.
        self.reload_flag = False
        self.search_flag = False
        self.cache_search_list = []
        self.cache_search_view = []
        self.__selected_tag = {"album": [], "artist": [], "genre": []}
        Dispatcher.connect("reload-browser", self.on_dispatcher_reload_browser)
        gobject.timeout_add(self.update_interval, self.on_interval_loaded_view)
        
        # The saving song Classification presented to the user.
        self.artists_view, self.artists_sw  = self.get_icon_view(14)
        self.albums_view,  self.albums_sw   = self.get_icon_view(14)
        self.genres_view,  self.genres_sw   = self.get_icon_view(14)
        self.folders_view, self.folders_sw  = self.get_icon_view(20)
        self.folders_view.connect("motion-notify-item", self.on_folders_view_motion_notify)
        
        # Song list for temporarily storing
        # self.songs_view, self.songs_view_sw = self.get_song_view()
        self.songs_view = self.get_song_view()
        
        # Classification navigation bar.
        self.filterbar = OptionBar(
            [(app_theme.get_pixbuf("filter/artist_normal.png"), app_theme.get_pixbuf("filter/artist_press.png"),
              _("Artist"), lambda : self.switch_filter_view("artist")),
             (app_theme.get_pixbuf("filter/album_normal.png"), app_theme.get_pixbuf("filter/album_press.png"),
              _("Album"), lambda : self.switch_filter_view("album")),
             (app_theme.get_pixbuf("filter/genre_normal.png"), app_theme.get_pixbuf("filter/genre_press.png"),
              _("Genre"), lambda : self.switch_filter_view("genre")),
             (app_theme.get_pixbuf("filter/local_normal.png"), app_theme.get_pixbuf("filter/local_press.png"),
              _("Folder"), lambda : self.switch_filter_view("folder"))
             ])
        
        # Manage the media library (import, refresh)
        self.importbar = SongImportBar()
        self.importbar.reload_items(
            [
             (_("Quick Scan"), lambda : ImportFolderJob([os.path.expanduser("~")])),                
             (_("Scan"), lambda : ImportFolderJob()),
             (_("Refresh"), lambda : ReloadDBJob())
             ])
        
        # Left box
        invailed_box = gtk.VBox()
        invailed_box.set_size_request(-1, 10)
        left_vbox = gtk.VBox(spacing=10)
        left_vbox.set_size_request(121, -1)
        # left_vbox.pack_start(invailed_box, False, True)
        left_vbox.pack_start(self.filterbar, False, False)
        left_vbox.pack_start(create_separator_box(), False, False)
        left_vbox.pack_start(self.importbar, False, False)
        
        # Used to switch songs category view, in the right side of the layout.
        self.switch_view_box = gtk.VBox()
        self.switch_view_box.add(self.artists_sw)
        # self.switch_view_box.add(TaskView())

        
        # Control back on a view.
        self.back_hbox = gtk.HBox()
        self.back_hbox.set_size_request(-1, 26)
        self.back_hbox.set_no_show_all(True)
        self.back_button = BackButton()
        self.back_button.connect("clicked", self.on_back_button_clicked)
        self.prompt_button = PromptButton()
        self.back_hbox.pack_start(self.back_button, False, False, 5)
        self.back_hbox.pack_start(self.prompt_button, False, False)
        
        # searchbar 
        self.search_entry, search_align = self.get_search_entry()
        search_hbox = gtk.HBox()
        search_hbox.pack_start(self.back_hbox, False, False)
        search_hbox.pack_start(create_right_align(), True, True)
        # search_hbox.pack_start(search_align, False, False)
        search_hbox_align = gtk.Alignment()
        search_hbox_align.set_padding(5, 0, 0, 0)
        search_hbox_align.set(0, 0, 1, 1)
        search_hbox_align.add(search_hbox)
        
        # Layout on the right.
        content_box = gtk.VBox(spacing=5)
        content_box.pack_start(search_hbox_align, False, False)
        content_box.pack_start(self.switch_view_box, True, True)
        
        body_paned = HPaned(handle_color=app_theme.get_color("panedHandler"), enable_drag=True)
        body_paned.add1(left_vbox)
        body_paned.add2(content_box)
        
        self.pack_start(body_paned, True, True)
        
        
    def get_search_entry(self):    
        search_entry = SearchEntry("")
        search_entry.set_size(155, 22)
        
        align = gtk.Alignment()
        # align.set(0.5, 0.5, 0, 0)
        align.set_padding(2, 0, 0, 10)
        align.add(search_entry)
        search_entry.entry.connect("changed", self.on_search_entry_changed)
        return search_entry, align
        
    def get_icon_view(self, padding_x=0, padding_y=10):    
        ''' Draggable IconView '''
        icon_view = IconView(padding_x, padding_y)
        targets = [("text/deepin-songs", gtk.TARGET_SAME_APP, 1), ("text/uri-list", 0, 2)]
        icon_view.drag_source_set(gtk.gdk.BUTTON1_MASK, targets, gtk.gdk.ACTION_COPY)
        icon_view.connect("drag-data-get", self.__on_drag_data_get) 
        icon_view.connect("double-click-item", self.__on_double_click_item)
        icon_view.connect("single-click-item", self.__on_single_click_item)
        icon_view.connect("right-click-item", self.__on_right_click_item)
        
        icon_view.draw_mask  = self.on_iconview_draw_mask
        scrolled_window = ScrolledWindow()
        scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        scrolled_window.add_child(icon_view)
        return icon_view, scrolled_window
        
    def get_song_view(self):
        song_view = MultiDragSongView(has_title=True)
        song_view.keymap.update({"BackSpace" : self.on_songview_backspace_press})        
        # song_view.add_titles([_("Title"), _("Artist"), _("Album"), _("Added time")])
        # scrolled_window = song_view.get_scrolled_window()
        return song_view
        # return song_view, scrolled_window
    
    def connect_to_db(self):
        self.autoconnect(self.__db_query, "added", self.__on_added_songs)
        self.autoconnect(self.__db_query, "removed", self.__on_removed_songs)
        self.autoconnect(self.__db_query, "update-tag", self.__on_update_tags)
        self.autoconnect(self.__db_query, "full-update", self.__on_full_update)
        self.autoconnect(self.__db_query, "quick-update", self.__on_quick_update)
        self.__db_query.set_query("")
        
    def __on_added_songs(self, db_query, songs):    
        self.reload_flag = True
    
    def __on_removed_songs(self, db_query, songs):
        self.reload_flag = True
    
    def __on_update_tags(self, db_query, infos, songs):
        self.reload_flag = True
    
    def __on_full_update(self, db_query):
        for tag in ["artist", "album", "genre", "folder"]:
            self.load_view(tag)
    
    def __on_quick_update(self, db_query, songs):
        pass
    
    def on_interval_loaded_view(self):
        if self.reload_flag and not self.search_flag:
            for tag in ["artist", "album", "genre", "folder"]:
                self.load_view(tag)
            self.reload_flag = False    
        return True    
    
    def on_dispatcher_reload_browser(self, obj, infos):
        if infos: self.reload_flag = True
    
    def on_folders_view_motion_notify(self, widget, item, x, y):
        Tooltip.text(widget, item.value_name)
        
    def on_songview_backspace_press(self):    
        self.on_back_button_clicked(None)
        
    def on_search_entry_changed(self, widget, text):    
        songs_view_mode = self.back_hbox.get_visible()
        if songs_view_mode:
            if not self.search_flag:
                self.cache_search_list = self.songs_view.items[:]
            # Clear songs view select status.    
            self.songs_view.select_rows = []
            if text != "":
                self.search_flag = True
                results = filter(lambda item: text.lower().replace(" ", "") in item.get_song().get("search", ""), 
                                 self.cache_search_list)
                self.songs_view.items = results
                self.songs_view.update_item_index()
                self.songs_view.update_vadjustment()
            else:    
                self.search_flag = False
                self.songs_view.items = self.cache_search_list
                self.songs_view.update_item_index()
                self.songs_view.update_vadjustment()
            self.songs_view.queue_draw()    
        else:    
            view_widget = self.get_current_view()
            if not view_widget: return 
            if not self.search_flag:
                self.cache_search_view = view_widget.items[:]
            if text != "":    
                self.search_flag = True
                results = filter(lambda item: text.lower().replace(" ", "") in item.retrieve, self.cache_search_view)
                view_widget.items = results
            else:    
                self.search_flag = False
                view_widget.items = self.cache_search_view
            view_widget.queue_draw()    
    
    def __on_drag_data_get(self, widget, context, selection, info, timestamp):
        item = widget.highlight_item
        if not item: return
        
        songs = self.get_item_songs(item)
        songs = list(songs)
        songs.sort()
        song_uris = [song.get("uri") for song in songs ]
        selection.set("text/deepin-songs", 8, "\n".join(song_uris))
        selection.set_uris(song_uris)
    
    def __on_double_click_item(self, widget, item, x, y):
        self.search_entry.entry.set_text("")        
        
        songs = self.get_item_songs(item)
        self.songs_view.clear()        
        self.songs_view.add_songs(songs)
        
        # todo: switch view mode fixed the back.
        switch_tab(self.switch_view_box, self.songs_view)
        
        # show back button.
        self.prompt_button.set_infos((item.pixbuf, item.name_label))
        self.back_hbox.set_no_show_all(False)
        self.back_hbox.show_all()
        
    def get_current_view(self):    
        index = self.filterbar.get_index()
        widget = None
        if index   == 0: widget = self.artists_view
        elif index == 1: widget = self.albums_view   
        elif index == 2: widget = self.genres_view
        elif index == 3: widget = self.folders_view
        return widget
    
    def get_current_view_sw(self):
        index = self.filterbar.get_index()
        widget = None
        if index   == 0: widget = self.artists_sw
        elif index == 1: widget = self.albums_sw
        elif index == 2: widget = self.genres_sw
        elif index == 3: widget = self.folders_sw
        return widget
    
    def on_back_button_clicked(self, obj):    
        # clear entry text.
        self.search_entry.entry.set_text("")
        
        widget = self.get_current_view_sw()
        if widget: switch_tab(self.switch_view_box, widget)
        
        # hide backhbox.
        self.back_hbox.hide_all()
        self.back_hbox.set_no_show_all(True)
        
    def __on_single_click_item(self, widget, item, x, y):    
        if item.pointer_in_play_rect(x, y):
            self.play_item(item)
            
    def play_item(self, item):        
        songs = self.get_item_songs(item)
        songs = list(songs)
        songs.sort()
        Dispatcher.play_and_add_song(songs)
        
    def emit_to_list(self, item):    
        songs = self.get_item_songs(item)
        Dispatcher.add_songs(songs)
        
    def real_remove_item(self, item, fully=False):    
        songs = self.get_item_songs(item)
        MediaDB.remove(songs)
        
        if fully:
            try:
                [ utils.move_to_trash(song.get("uri")) for song in songs if song.get_type() != "cue" ]
            except: pass    
           
    def try_move_trash(self, item):        
        ConfirmDialog(_("Prompt"), _("Are you sure you want to delete them?"), 
                      confirm_callback=lambda : self.real_remove_item(item, True)).show_all()
        
    def change_item_cover(self, item):    
        new_cover_path = WinFile(False, _("Select image")).run()
        if new_cover_path:
            item.change_cover_pixbuf(new_cover_path)
            
    def __on_right_click_item(self, widget, item, x, y):
        if not item: return
        menu_items = [
            (None, _("Play All"), lambda : self.play_item(item)),
            (None, _("Add to List"), lambda : self.emit_to_list(item)),
            None,
            (None, _("Remove from Library"), lambda : self.real_remove_item(item)),
            (None, _("Move to Trash"), lambda : self.try_move_trash(item)),
            None,
            ]
        
        if item.tag == "folder":
            menu_items.append((None, _("Open Directory"), lambda : utils.open_directory(item.value_name)))
        elif item.tag in ["artist", "album"] and item.key_name != "deepin-all-songs":    
            menu_items.append((None, _("Change Cover"), lambda : self.change_item_cover(item)))
        else:    
            menu_items.pop()
            
        Menu(menu_items, True).show((int(x), int(y)))    
        
    def get_item_songs(self, item):    
        if item.tag == "folder":
            songs = self.__db_query.get_attr_songs(item.value_name)
        else:    
            if item.key_name == "deepin-all-songs":
                songs = self.__db_query.get_all_songs()
            else:    
                self.__selected_tag[item.tag] = [item.key_name]
                songs = self.__get_selected_songs(item.tag)
        return songs        

                
    def __get_selected_songs(self, tag="artist"):
        artists = []
        albums = []
        genres = []
        if   tag == "artist": artists = self.__selected_tag["artist"]
        elif tag == "album": albums = self.__selected_tag["album"]
        elif tag == "genre": genres = self.__selected_tag["genre"]
        return self.__db_query.get_songs(genres, artists, albums)    
    
    def get_infos_from_db(self, tag, values=None):
        genres = []
        artists = []
        extened = False
        
        return self.__db_query.get_info(tag, genres, artists, values, extened)
    
    def load_view(self, tag="artist", switch=False):
        items = self.get_info_items(tag)
        
        if  tag == "artist": 
            self.artists_view.clear()
            self.artists_view.add_items(items)    
        elif tag == "album" :
            self.albums_view.clear()
            self.albums_view.add_items(items)
        elif tag == "genre" :
            self.genres_view.clear()
            self.genres_view.add_items(items)
        elif tag == "folder":
            self.folders_view.clear()
            self.folders_view.add_items(items)
        
    def get_info_items(self, tag):    
        if tag == "folder":
            infos = self.__db_query.get_attr_infos()
            return [ LocalItem(info) for info in infos ]
        
        _dict = self.get_infos_from_db(tag)
        keys = _dict.keys()
        keys.sort()
        items = []
        all_nb = len(self.__db_query.get_all_songs())
        items.append(LocalItem(("deepin-all-songs", "deepin-all-songs", all_nb, tag)))
        
        for key in keys:
            value, nb = _dict[key]
            items.append(LocalItem((key, value, nb, tag)))
        return items    
    
    def switch_filter_view(self, tag):    
        
        # clear search entry
        self.search_entry.entry.set_text("")
        
        widget = None
        if tag == "artist" : widget = self.artists_sw
        elif tag == "album": widget = self.albums_sw
        elif tag == "genre": widget = self.genres_sw
        elif tag == "folder" : widget = self.folders_sw
            
        if widget:    
            self.back_hbox.hide_all()
            self.back_hbox.set_no_show_all(True)
            switch_tab(self.switch_view_box, widget)
    
    def on_iconview_draw_mask(self, cr, x, y, width, height):
        draw_alpha_mask(cr, x, y, width, height, "layoutLast")
Example #3
0
    def __init__(self, db_query):

        # Init.
        gtk.VBox.__init__(self)
        SignalContainer.__init__(self)

        self.__db_query = db_query
        self.update_interval = 3000  # 3000 millisecond.
        self.reload_flag = False
        self.search_flag = False
        self.cache_search_list = []
        self.cache_search_view = []
        self.__selected_tag = {"album": [], "artist": [], "genre": []}
        Dispatcher.connect("reload-browser", self.on_dispatcher_reload_browser)
        gobject.timeout_add(self.update_interval, self.on_interval_loaded_view)

        # The saving song Classification presented to the user.
        self.artists_view, self.artists_sw = self.get_icon_view(14)
        self.albums_view, self.albums_sw = self.get_icon_view(14)
        self.genres_view, self.genres_sw = self.get_icon_view(14)
        self.folders_view, self.folders_sw = self.get_icon_view(20)
        self.folders_view.connect("motion-notify-item",
                                  self.on_folders_view_motion_notify)

        # Song list for temporarily storing
        # self.songs_view, self.songs_view_sw = self.get_song_view()
        self.songs_view = self.get_song_view()

        # Classification navigation bar.
        self.filterbar = OptionBar([
            (app_theme.get_pixbuf("filter/artist_normal.png"),
             app_theme.get_pixbuf("filter/artist_press.png"), _("Artist"),
             lambda: self.switch_filter_view("artist")),
            (app_theme.get_pixbuf("filter/album_normal.png"),
             app_theme.get_pixbuf("filter/album_press.png"), _("Album"),
             lambda: self.switch_filter_view("album")),
            (app_theme.get_pixbuf("filter/genre_normal.png"),
             app_theme.get_pixbuf("filter/genre_press.png"), _("Genre"),
             lambda: self.switch_filter_view("genre")),
            (app_theme.get_pixbuf("filter/local_normal.png"),
             app_theme.get_pixbuf("filter/local_press.png"), _("Folder"),
             lambda: self.switch_filter_view("folder"))
        ])

        # Manage the media library (import, refresh)
        self.importbar = SongImportBar()
        self.importbar.reload_items([
            (_("Quick Scan"),
             lambda: ImportFolderJob([os.path.expanduser("~")])),
            (_("Scan"), lambda: ImportFolderJob()),
            (_("Refresh"), lambda: ReloadDBJob())
        ])

        # Left box
        invailed_box = gtk.VBox()
        invailed_box.set_size_request(-1, 10)
        left_vbox = gtk.VBox(spacing=10)
        left_vbox.set_size_request(121, -1)
        # left_vbox.pack_start(invailed_box, False, True)
        left_vbox.pack_start(self.filterbar, False, False)
        left_vbox.pack_start(create_separator_box(), False, False)
        left_vbox.pack_start(self.importbar, False, False)

        # Used to switch songs category view, in the right side of the layout.
        self.switch_view_box = gtk.VBox()
        self.switch_view_box.add(self.artists_sw)
        # self.switch_view_box.add(TaskView())

        # Control back on a view.
        self.back_hbox = gtk.HBox()
        self.back_hbox.set_size_request(-1, 26)
        self.back_hbox.set_no_show_all(True)
        self.back_button = BackButton()
        self.back_button.connect("clicked", self.on_back_button_clicked)
        self.prompt_button = PromptButton()
        self.back_hbox.pack_start(self.back_button, False, False, 5)
        self.back_hbox.pack_start(self.prompt_button, False, False)

        # searchbar
        self.search_entry, search_align = self.get_search_entry()
        search_hbox = gtk.HBox()
        search_hbox.pack_start(self.back_hbox, False, False)
        search_hbox.pack_start(create_right_align(), True, True)
        # search_hbox.pack_start(search_align, False, False)
        search_hbox_align = gtk.Alignment()
        search_hbox_align.set_padding(5, 0, 0, 0)
        search_hbox_align.set(0, 0, 1, 1)
        search_hbox_align.add(search_hbox)

        # Layout on the right.
        content_box = gtk.VBox(spacing=5)
        content_box.pack_start(search_hbox_align, False, False)
        content_box.pack_start(self.switch_view_box, True, True)

        body_paned = HPaned(handle_color=app_theme.get_color("panedHandler"),
                            enable_drag=True)
        body_paned.add1(left_vbox)
        body_paned.add2(content_box)

        self.pack_start(body_paned, True, True)
Example #4
0
class Browser(gtk.VBox, SignalContainer):
    def __init__(self, db_query):

        # Init.
        gtk.VBox.__init__(self)
        SignalContainer.__init__(self)

        self.__db_query = db_query
        self.update_interval = 3000  # 3000 millisecond.
        self.reload_flag = False
        self.search_flag = False
        self.cache_search_list = []
        self.cache_search_view = []
        self.__selected_tag = {"album": [], "artist": [], "genre": []}
        Dispatcher.connect("reload-browser", self.on_dispatcher_reload_browser)
        gobject.timeout_add(self.update_interval, self.on_interval_loaded_view)

        # The saving song Classification presented to the user.
        self.artists_view, self.artists_sw = self.get_icon_view(14)
        self.albums_view, self.albums_sw = self.get_icon_view(14)
        self.genres_view, self.genres_sw = self.get_icon_view(14)
        self.folders_view, self.folders_sw = self.get_icon_view(20)
        self.folders_view.connect("motion-notify-item",
                                  self.on_folders_view_motion_notify)

        # Song list for temporarily storing
        # self.songs_view, self.songs_view_sw = self.get_song_view()
        self.songs_view = self.get_song_view()

        # Classification navigation bar.
        self.filterbar = OptionBar([
            (app_theme.get_pixbuf("filter/artist_normal.png"),
             app_theme.get_pixbuf("filter/artist_press.png"), _("Artist"),
             lambda: self.switch_filter_view("artist")),
            (app_theme.get_pixbuf("filter/album_normal.png"),
             app_theme.get_pixbuf("filter/album_press.png"), _("Album"),
             lambda: self.switch_filter_view("album")),
            (app_theme.get_pixbuf("filter/genre_normal.png"),
             app_theme.get_pixbuf("filter/genre_press.png"), _("Genre"),
             lambda: self.switch_filter_view("genre")),
            (app_theme.get_pixbuf("filter/local_normal.png"),
             app_theme.get_pixbuf("filter/local_press.png"), _("Folder"),
             lambda: self.switch_filter_view("folder"))
        ])

        # Manage the media library (import, refresh)
        self.importbar = SongImportBar()
        self.importbar.reload_items([
            (_("Quick Scan"),
             lambda: ImportFolderJob([os.path.expanduser("~")])),
            (_("Scan"), lambda: ImportFolderJob()),
            (_("Refresh"), lambda: ReloadDBJob())
        ])

        # Left box
        invailed_box = gtk.VBox()
        invailed_box.set_size_request(-1, 10)
        left_vbox = gtk.VBox(spacing=10)
        left_vbox.set_size_request(121, -1)
        # left_vbox.pack_start(invailed_box, False, True)
        left_vbox.pack_start(self.filterbar, False, False)
        left_vbox.pack_start(create_separator_box(), False, False)
        left_vbox.pack_start(self.importbar, False, False)

        # Used to switch songs category view, in the right side of the layout.
        self.switch_view_box = gtk.VBox()
        self.switch_view_box.add(self.artists_sw)
        # self.switch_view_box.add(TaskView())

        # Control back on a view.
        self.back_hbox = gtk.HBox()
        self.back_hbox.set_size_request(-1, 26)
        self.back_hbox.set_no_show_all(True)
        self.back_button = BackButton()
        self.back_button.connect("clicked", self.on_back_button_clicked)
        self.prompt_button = PromptButton()
        self.back_hbox.pack_start(self.back_button, False, False, 5)
        self.back_hbox.pack_start(self.prompt_button, False, False)

        # searchbar
        self.search_entry, search_align = self.get_search_entry()
        search_hbox = gtk.HBox()
        search_hbox.pack_start(self.back_hbox, False, False)
        search_hbox.pack_start(create_right_align(), True, True)
        # search_hbox.pack_start(search_align, False, False)
        search_hbox_align = gtk.Alignment()
        search_hbox_align.set_padding(5, 0, 0, 0)
        search_hbox_align.set(0, 0, 1, 1)
        search_hbox_align.add(search_hbox)

        # Layout on the right.
        content_box = gtk.VBox(spacing=5)
        content_box.pack_start(search_hbox_align, False, False)
        content_box.pack_start(self.switch_view_box, True, True)

        body_paned = HPaned(handle_color=app_theme.get_color("panedHandler"),
                            enable_drag=True)
        body_paned.add1(left_vbox)
        body_paned.add2(content_box)

        self.pack_start(body_paned, True, True)

    def get_search_entry(self):
        search_entry = SearchEntry("")
        search_entry.set_size(155, 22)

        align = gtk.Alignment()
        # align.set(0.5, 0.5, 0, 0)
        align.set_padding(2, 0, 0, 10)
        align.add(search_entry)
        search_entry.entry.connect("changed", self.on_search_entry_changed)
        return search_entry, align

    def get_icon_view(self, padding_x=0, padding_y=10):
        ''' Draggable IconView '''
        icon_view = IconView(padding_x, padding_y)
        targets = [("text/deepin-songs", gtk.TARGET_SAME_APP, 1),
                   ("text/uri-list", 0, 2)]
        icon_view.drag_source_set(gtk.gdk.BUTTON1_MASK, targets,
                                  gtk.gdk.ACTION_COPY)
        icon_view.connect("drag-data-get", self.__on_drag_data_get)
        icon_view.connect("double-click-item", self.__on_double_click_item)
        icon_view.connect("single-click-item", self.__on_single_click_item)
        icon_view.connect("right-click-item", self.__on_right_click_item)

        icon_view.draw_mask = self.on_iconview_draw_mask
        scrolled_window = ScrolledWindow()
        scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        scrolled_window.add_child(icon_view)
        return icon_view, scrolled_window

    def get_song_view(self):
        song_view = MultiDragSongView(has_title=True)
        song_view.keymap.update(
            {"BackSpace": self.on_songview_backspace_press})
        # song_view.add_titles([_("Title"), _("Artist"), _("Album"), _("Added time")])
        # scrolled_window = song_view.get_scrolled_window()
        return song_view
        # return song_view, scrolled_window

    def connect_to_db(self):
        self.autoconnect(self.__db_query, "added", self.__on_added_songs)
        self.autoconnect(self.__db_query, "removed", self.__on_removed_songs)
        self.autoconnect(self.__db_query, "update-tag", self.__on_update_tags)
        self.autoconnect(self.__db_query, "full-update", self.__on_full_update)
        self.autoconnect(self.__db_query, "quick-update",
                         self.__on_quick_update)
        self.__db_query.set_query("")

    def __on_added_songs(self, db_query, songs):
        self.reload_flag = True

    def __on_removed_songs(self, db_query, songs):
        self.reload_flag = True

    def __on_update_tags(self, db_query, infos, songs):
        self.reload_flag = True

    def __on_full_update(self, db_query):
        for tag in ["artist", "album", "genre", "folder"]:
            self.load_view(tag)

    def __on_quick_update(self, db_query, songs):
        pass

    def on_interval_loaded_view(self):
        if self.reload_flag and not self.search_flag:
            for tag in ["artist", "album", "genre", "folder"]:
                self.load_view(tag)
            self.reload_flag = False
        return True

    def on_dispatcher_reload_browser(self, obj, infos):
        if infos: self.reload_flag = True

    def on_folders_view_motion_notify(self, widget, item, x, y):
        Tooltip.text(widget, item.value_name)

    def on_songview_backspace_press(self):
        self.on_back_button_clicked(None)

    def on_search_entry_changed(self, widget, text):
        songs_view_mode = self.back_hbox.get_visible()
        if songs_view_mode:
            if not self.search_flag:
                self.cache_search_list = self.songs_view.items[:]
            # Clear songs view select status.
            self.songs_view.select_rows = []
            if text != "":
                self.search_flag = True
                results = filter(
                    lambda item: text.lower().replace(" ", "") in item.
                    get_song().get("search", ""), self.cache_search_list)
                self.songs_view.items = results
                self.songs_view.update_item_index()
                self.songs_view.update_vadjustment()
            else:
                self.search_flag = False
                self.songs_view.items = self.cache_search_list
                self.songs_view.update_item_index()
                self.songs_view.update_vadjustment()
            self.songs_view.queue_draw()
        else:
            view_widget = self.get_current_view()
            if not view_widget: return
            if not self.search_flag:
                self.cache_search_view = view_widget.items[:]
            if text != "":
                self.search_flag = True
                results = filter(
                    lambda item: text.lower().replace(" ", "") in item.
                    retrieve, self.cache_search_view)
                view_widget.items = results
            else:
                self.search_flag = False
                view_widget.items = self.cache_search_view
            view_widget.queue_draw()

    def __on_drag_data_get(self, widget, context, selection, info, timestamp):
        item = widget.highlight_item
        if not item: return

        songs = self.get_item_songs(item)
        songs = list(songs)
        songs.sort()
        song_uris = [song.get("uri") for song in songs]
        selection.set("text/deepin-songs", 8, "\n".join(song_uris))
        selection.set_uris(song_uris)

    def __on_double_click_item(self, widget, item, x, y):
        self.search_entry.entry.set_text("")

        songs = self.get_item_songs(item)
        self.songs_view.clear()
        self.songs_view.add_songs(songs)

        # todo: switch view mode fixed the back.
        switch_tab(self.switch_view_box, self.songs_view)

        # show back button.
        self.prompt_button.set_infos((item.pixbuf, item.name_label))
        self.back_hbox.set_no_show_all(False)
        self.back_hbox.show_all()

    def get_current_view(self):
        index = self.filterbar.get_index()
        widget = None
        if index == 0: widget = self.artists_view
        elif index == 1: widget = self.albums_view
        elif index == 2: widget = self.genres_view
        elif index == 3: widget = self.folders_view
        return widget

    def get_current_view_sw(self):
        index = self.filterbar.get_index()
        widget = None
        if index == 0: widget = self.artists_sw
        elif index == 1: widget = self.albums_sw
        elif index == 2: widget = self.genres_sw
        elif index == 3: widget = self.folders_sw
        return widget

    def on_back_button_clicked(self, obj):
        # clear entry text.
        self.search_entry.entry.set_text("")

        widget = self.get_current_view_sw()
        if widget: switch_tab(self.switch_view_box, widget)

        # hide backhbox.
        self.back_hbox.hide_all()
        self.back_hbox.set_no_show_all(True)

    def __on_single_click_item(self, widget, item, x, y):
        if item.pointer_in_play_rect(x, y):
            self.play_item(item)

    def play_item(self, item):
        songs = self.get_item_songs(item)
        songs = list(songs)
        songs.sort()
        Dispatcher.play_and_add_song(songs)

    def emit_to_list(self, item):
        songs = self.get_item_songs(item)
        Dispatcher.add_songs(songs)

    def real_remove_item(self, item, fully=False):
        songs = self.get_item_songs(item)
        MediaDB.remove(songs)

        if fully:
            try:
                [
                    utils.move_to_trash(song.get("uri")) for song in songs
                    if song.get_type() != "cue"
                ]
            except:
                pass

    def try_move_trash(self, item):
        ConfirmDialog(_("Prompt"),
                      _("Are you sure to delete?"),
                      confirm_callback=lambda: self.real_remove_item(
                          item, True)).show_all()

    def change_item_cover(self, item):
        new_cover_path = WinFile(False, _("Select image")).run()
        if new_cover_path:
            item.change_cover_pixbuf(new_cover_path)

    def __on_right_click_item(self, widget, item, x, y):
        if not item: return
        menu_items = [
            (None, _("Play All"), lambda: self.play_item(item)),
            (None, _("Add to List"), lambda: self.emit_to_list(item)),
            None,
            (None, _("Remove from Library"),
             lambda: self.real_remove_item(item)),
            (None, _("Move to Trash"), lambda: self.try_move_trash(item)),
            None,
        ]

        if item.tag == "folder":
            menu_items.append((None, _("Open Directory"),
                               lambda: utils.open_directory(item.value_name)))
        elif item.tag in ["artist", "album"
                          ] and item.key_name != "deepin-all-songs":
            menu_items.append((None, _("Change Cover"),
                               lambda: self.change_item_cover(item)))
        else:
            menu_items.pop()

        Menu(menu_items, True).show((int(x), int(y)))

    def get_item_songs(self, item):
        if item.tag == "folder":
            songs = self.__db_query.get_attr_songs(item.value_name)
        else:
            if item.key_name == "deepin-all-songs":
                songs = self.__db_query.get_all_songs()
            else:
                self.__selected_tag[item.tag] = [item.key_name]
                songs = self.__get_selected_songs(item.tag)
        return songs

    def __get_selected_songs(self, tag="artist"):
        artists = []
        albums = []
        genres = []
        if tag == "artist": artists = self.__selected_tag["artist"]
        elif tag == "album": albums = self.__selected_tag["album"]
        elif tag == "genre": genres = self.__selected_tag["genre"]
        return self.__db_query.get_songs(genres, artists, albums)

    def get_infos_from_db(self, tag, values=None):
        genres = []
        artists = []
        extened = False

        return self.__db_query.get_info(tag, genres, artists, values, extened)

    def load_view(self, tag="artist", switch=False):
        items = self.get_info_items(tag)

        if tag == "artist":
            self.artists_view.clear()
            self.artists_view.add_items(items)
        elif tag == "album":
            self.albums_view.clear()
            self.albums_view.add_items(items)
        elif tag == "genre":
            self.genres_view.clear()
            self.genres_view.add_items(items)
        elif tag == "folder":
            self.folders_view.clear()
            self.folders_view.add_items(items)

    def get_info_items(self, tag):
        if tag == "folder":
            infos = self.__db_query.get_attr_infos()
            return [LocalItem(info) for info in infos]

        _dict = self.get_infos_from_db(tag)
        keys = _dict.keys()
        keys.sort()
        items = []
        all_nb = len(self.__db_query.get_all_songs())
        items.append(
            LocalItem(("deepin-all-songs", "deepin-all-songs", all_nb, tag)))

        for key in keys:
            value, nb = _dict[key]
            items.append(LocalItem((key, value, nb, tag)))
        return items

    def switch_filter_view(self, tag):

        # clear search entry
        self.search_entry.entry.set_text("")

        widget = None
        if tag == "artist": widget = self.artists_sw
        elif tag == "album": widget = self.albums_sw
        elif tag == "genre": widget = self.genres_sw
        elif tag == "folder": widget = self.folders_sw

        if widget:
            self.back_hbox.hide_all()
            self.back_hbox.set_no_show_all(True)
            switch_tab(self.switch_view_box, widget)

    def on_iconview_draw_mask(self, cr, x, y, width, height):
        draw_alpha_mask(cr, x, y, width, height, "layoutLast")
 def __init__(self, db_query):
     
     gtk.VBox.__init__(self)
     SignalContainer.__init__(self)
     
     self.__db_query = db_query
     self._tree = {}
     self.__selected_tag = {"album": [], "artist": [], "genre": []}
     self.view_mode = ICON_VIEW_MODE
     self.__search_flag = False
     self.__song_cache_items = []
     self.__cover_cache_items = []
     
     # init widget.
     self.entry_box = SearchEntry("")
     self.entry_box.set_size(155, 22)
     self.entry_box.entry.connect("changed", self.__search_cb)
     
     # upper box.
     self.back_button = self.__create_simple_button("back", self.__switch_to_filter_view)
     self.back_button.set_no_show_all(True)
     back_align = gtk.Alignment()
     back_align.set(0.5, 0.5, 0, 0)
     back_align.set_padding(0, 0, 0, 10)
     back_align.add(self.back_button)
     
     # path control
     self.path_combo_box = ComboMenuButton()
     self.path_combo_box.connect("list-actived", lambda w: self.update_path_list_view())
     self.path_combo_box.connect("combo-actived", lambda w, k : self.update_path_filter_view(k))
     path_combo_align = gtk.Alignment()
     path_combo_align.set_padding(0, 0, 10, 0)
     path_combo_align.add(self.path_combo_box)
     self.path_combo_box.set_no_show_all(True)
     
     upper_box = gtk.HBox(spacing=5)
     upper_box.pack_start(path_combo_align, False, False)
     upper_box.pack_start(create_right_align(), True, True)
     upper_box.pack_start(back_align, False, False)
     entry_box_align = gtk.Alignment()
     entry_box_align.set(0.5, 0.5, 0, 0)
     entry_box_align.set_padding(1, 0, 0, 0)
     entry_box_align.add(self.entry_box)
     upper_box.pack_start(entry_box_align, False, False)
     
     upper_box_align = gtk.Alignment()
     upper_box_align.set_padding(0, 10, 0, 10)
     upper_box_align.set(0.5, 0.5, 1, 1)
     upper_box_align.connect("expose-event", self.expose_upper_box_mask)
     upper_box_align.add(upper_box)
     
     self.categorybar_status = "artist"
     self.filter_categorybar = OptionBar(
         [(app_theme.get_pixbuf("filter/artist_normal.png"), app_theme.get_pixbuf("filter/artist_press.png"),
           _("By artist"), lambda : self.reload_filter_view("artist", True)),
          (app_theme.get_pixbuf("filter/album_normal.png"), app_theme.get_pixbuf("filter/album_press.png"),
           _("By album"), lambda : self.reload_filter_view("album", True)),
          (app_theme.get_pixbuf("filter/genre_normal.png"), app_theme.get_pixbuf("filter/genre_press.png"),
           _("By genre"), lambda : self.reload_filter_view("genre", True)),]
                                         )
     
     # Song path bar.
     self.__current_path = None
     self.current_icon_item = None
     self.reload_path_flag = True
     self.path_categorybar = SongPathBar(_("Local"))
     self.path_categorybar.set_size_request(-1, 205)
     
     # Song import bar.
     self.import_categorybar = SongImportBar()
     self.import_categorybar.reload_items(
         [
          (_("Scan Home dir"), lambda : ImportFolderJob([os.path.expanduser("~")])),                
          (_("Select dir to scan"), lambda : ImportFolderJob()),
          (_("Refresh library"), lambda : ReloadDBJob())]
         )
     
     # iconview.
     self.filter_view = IconView(10, 10)
     targets = [("text/deepin-songs", gtk.TARGET_SAME_APP, 1), ("text/uri-list", 0, 2)]
     self.filter_view.drag_source_set(gtk.gdk.BUTTON1_MASK, targets, gtk.gdk.ACTION_COPY)
     self.filter_view.connect("drag-data-get", self.__on_drag_data_get) 
     self.filter_view.connect("double-click-item", self.__on_double_click_item)
     self.filter_view.connect("single-click-item", self.__on_single_click_item)
     self.filter_view.draw_mask  = self.draw_filter_view_mask
     self.filter_scrolled_window = ScrolledWindow()
     self.filter_scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
     self.filter_scrolled_window.add_child(self.filter_view)
     
     # songs_view
     self.songs_view = MultiDragSongView()
     self.songs_view.add_titles([_("Title"), _("Artist"), _("Album"), _("Added time")])
     self.songs_scrolled_window = ScrolledWindow(0, 0)
     self.songs_scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
     self.songs_scrolled_window.add_child(self.songs_view)
     
     # left_vbox
     align = gtk.Alignment()
     align.set(0, 1, 0, 0)
     left_box = gtk.VBox(spacing=10)
     left_box.set_size_request(140, -1)
     left_box.pack_start(self.filter_categorybar, False, False)
     left_box.pack_start(self.create_separator_box(), False, False)
     left_box.pack_start(self.path_categorybar, False, False)
     left_box.pack_start(self.create_separator_box(), False, False)
     left_box.pack_start(self.import_categorybar, False, False)
     left_box.pack_start(align, True, True)
     left_box.connect("expose-event", self.expose_left_box_mask)
     
     # right_box.
     self.right_box = gtk.VBox()
     self.right_box.add(self.filter_scrolled_window)
     
     # swith_box
     right_box_align = gtk.Alignment()
     right_box_align.set_padding(0, 0, 0, 2)
     right_box_align.set(1, 1, 1, 1)
     right_box_align.add(self.right_box)
     browser_box = gtk.VBox()
     browser_box.pack_start(upper_box_align,  False, False)
     browser_box.pack_start(right_box_align, True, True)
     
     body_box = gtk.HBox()
     body_box.pack_start(left_box, False, False)
     body_box.pack_start(browser_box, True, True)
     self.pack_start(body_box, True, True)
     
     self.reload_flag = False
     Dispatcher.connect("reload-browser", self.reload_browser)
     gobject.timeout_add(5000, self.interval_reload_browser)
class Browser(gtk.VBox, SignalContainer):
    
    def __init__(self, db_query):
        
        gtk.VBox.__init__(self)
        SignalContainer.__init__(self)
        
        self.__db_query = db_query
        self._tree = {}
        self.__selected_tag = {"album": [], "artist": [], "genre": []}
        self.view_mode = ICON_VIEW_MODE
        self.__search_flag = False
        self.__song_cache_items = []
        self.__cover_cache_items = []
        
        # init widget.
        self.entry_box = SearchEntry("")
        self.entry_box.set_size(155, 22)
        self.entry_box.entry.connect("changed", self.__search_cb)
        
        # upper box.
        self.back_button = self.__create_simple_button("back", self.__switch_to_filter_view)
        self.back_button.set_no_show_all(True)
        back_align = gtk.Alignment()
        back_align.set(0.5, 0.5, 0, 0)
        back_align.set_padding(0, 0, 0, 10)
        back_align.add(self.back_button)
        
        # path control
        self.path_combo_box = ComboMenuButton()
        self.path_combo_box.connect("list-actived", lambda w: self.update_path_list_view())
        self.path_combo_box.connect("combo-actived", lambda w, k : self.update_path_filter_view(k))
        path_combo_align = gtk.Alignment()
        path_combo_align.set_padding(0, 0, 10, 0)
        path_combo_align.add(self.path_combo_box)
        self.path_combo_box.set_no_show_all(True)
        
        upper_box = gtk.HBox(spacing=5)
        upper_box.pack_start(path_combo_align, False, False)
        upper_box.pack_start(create_right_align(), True, True)
        upper_box.pack_start(back_align, False, False)
        entry_box_align = gtk.Alignment()
        entry_box_align.set(0.5, 0.5, 0, 0)
        entry_box_align.set_padding(1, 0, 0, 0)
        entry_box_align.add(self.entry_box)
        upper_box.pack_start(entry_box_align, False, False)
        
        upper_box_align = gtk.Alignment()
        upper_box_align.set_padding(0, 10, 0, 10)
        upper_box_align.set(0.5, 0.5, 1, 1)
        upper_box_align.connect("expose-event", self.expose_upper_box_mask)
        upper_box_align.add(upper_box)
        
        self.categorybar_status = "artist"
        self.filter_categorybar = OptionBar(
            [(app_theme.get_pixbuf("filter/artist_normal.png"), app_theme.get_pixbuf("filter/artist_press.png"),
              _("By artist"), lambda : self.reload_filter_view("artist", True)),
             (app_theme.get_pixbuf("filter/album_normal.png"), app_theme.get_pixbuf("filter/album_press.png"),
              _("By album"), lambda : self.reload_filter_view("album", True)),
             (app_theme.get_pixbuf("filter/genre_normal.png"), app_theme.get_pixbuf("filter/genre_press.png"),
              _("By genre"), lambda : self.reload_filter_view("genre", True)),]
                                            )
        
        # Song path bar.
        self.__current_path = None
        self.current_icon_item = None
        self.reload_path_flag = True
        self.path_categorybar = SongPathBar(_("Local"))
        self.path_categorybar.set_size_request(-1, 205)
        
        # Song import bar.
        self.import_categorybar = SongImportBar()
        self.import_categorybar.reload_items(
            [
             (_("Scan Home dir"), lambda : ImportFolderJob([os.path.expanduser("~")])),                
             (_("Select dir to scan"), lambda : ImportFolderJob()),
             (_("Refresh library"), lambda : ReloadDBJob())]
            )
        
        # iconview.
        self.filter_view = IconView(10, 10)
        targets = [("text/deepin-songs", gtk.TARGET_SAME_APP, 1), ("text/uri-list", 0, 2)]
        self.filter_view.drag_source_set(gtk.gdk.BUTTON1_MASK, targets, gtk.gdk.ACTION_COPY)
        self.filter_view.connect("drag-data-get", self.__on_drag_data_get) 
        self.filter_view.connect("double-click-item", self.__on_double_click_item)
        self.filter_view.connect("single-click-item", self.__on_single_click_item)
        self.filter_view.draw_mask  = self.draw_filter_view_mask
        self.filter_scrolled_window = ScrolledWindow()
        self.filter_scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        self.filter_scrolled_window.add_child(self.filter_view)
        
        # songs_view
        self.songs_view = MultiDragSongView()
        self.songs_view.add_titles([_("Title"), _("Artist"), _("Album"), _("Added time")])
        self.songs_scrolled_window = ScrolledWindow(0, 0)
        self.songs_scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        self.songs_scrolled_window.add_child(self.songs_view)
        
        # left_vbox
        align = gtk.Alignment()
        align.set(0, 1, 0, 0)
        left_box = gtk.VBox(spacing=10)
        left_box.set_size_request(140, -1)
        left_box.pack_start(self.filter_categorybar, False, False)
        left_box.pack_start(self.create_separator_box(), False, False)
        left_box.pack_start(self.path_categorybar, False, False)
        left_box.pack_start(self.create_separator_box(), False, False)
        left_box.pack_start(self.import_categorybar, False, False)
        left_box.pack_start(align, True, True)
        left_box.connect("expose-event", self.expose_left_box_mask)
        
        # right_box.
        self.right_box = gtk.VBox()
        self.right_box.add(self.filter_scrolled_window)
        
        # swith_box
        right_box_align = gtk.Alignment()
        right_box_align.set_padding(0, 0, 0, 2)
        right_box_align.set(1, 1, 1, 1)
        right_box_align.add(self.right_box)
        browser_box = gtk.VBox()
        browser_box.pack_start(upper_box_align,  False, False)
        browser_box.pack_start(right_box_align, True, True)
        
        body_box = gtk.HBox()
        body_box.pack_start(left_box, False, False)
        body_box.pack_start(browser_box, True, True)
        self.pack_start(body_box, True, True)
        
        self.reload_flag = False
        Dispatcher.connect("reload-browser", self.reload_browser)
        gobject.timeout_add(5000, self.interval_reload_browser)
        
    def __create_simple_button(self, name, callback):    
        button = ImageButton(
            app_theme.get_pixbuf("filter/%s_normal.png" % name),
            app_theme.get_pixbuf("filter/%s_hover.png" % name),
            app_theme.get_pixbuf("filter/%s_press.png" % name),
            )
        if callback:
            button.connect("clicked", callback)
        return button    
    
    def expose_left_box_mask(self, widget, event):
        cr = widget.window.cairo_create()
        rect = widget.allocation
        draw_alpha_mask(cr, rect.x, rect.y, rect.width, rect.height, "layoutRight")
        return False
    
    def expose_upper_box_mask(self, widget, event):
        cr = widget.window.cairo_create()
        rect = widget.allocation
        draw_alpha_mask(cr, rect.x, rect.y, rect.width - 2, rect.height, "layoutLast")
        return False
    
    def draw_filter_view_mask(self, cr, x, y, width, height):
        draw_alpha_mask(cr, x, y, width, height, "layoutLast")
    
    def create_separator_box(self, padding_x=0, padding_y=0):
        separator_box = HSeparator(
            app_theme.get_shadow_color("hSeparator").get_color_info(),
            padding_x, padding_y)
        return separator_box
    
    def __switch_to_filter_view(self, widget):
        self.back_button.set_no_show_all(True)
        self.back_button.hide()
        self.switch_box(self.right_box, self.filter_scrolled_window)
        self.view_mode = ICON_VIEW_MODE
        
    def reload_filter_view(self, tag="artist", switch=False, use_path=False):    
        self.entry_box.entry.set_text("")
        self.back_button.set_no_show_all(True)
        self.back_button.hide()
        self.categorybar_status = tag
        self.filter_view.clear()
            
        if not use_path:    
            self.path_categorybar.set_index(-1)    
        
        _dict = self.get_infos_from_db(tag)
        keys = _dict.keys()
        keys.sort()
        items = []
        all_nb = len(self.__db_query.get_all_songs())
        items.append(IconItem(("deepin-all-songs", "deepin-all-songs", all_nb, tag)))

        for key in keys:
            value, nb = _dict[key] 
            items.append(IconItem((key, value, nb, tag)))
        self.filter_view.add_items(items)    
        
        if switch:
            self.switch_box(self.right_box, self.filter_scrolled_window)
            self.view_mode = ICON_VIEW_MODE
            if not use_path:
                self.change_combo_box_status(True)
            
    def get_infos_from_db(self, tag, values=None):
        genres = []
        artists = []
        extened = False
        return self.__db_query.get_info(tag, genres, artists, values, extened)
    
    def get_attr_infos_from_db(self, info_type="###ALL###", song_dir=None):
        return self.__db_query.get_attr_infos(info_type, song_dir)
    
    def change_combo_box_status(self, hide=False):    
        if not hide:
            self.path_combo_box.set_no_show_all(False)
            self.path_combo_box.show_all()
        else:    
            self.path_combo_box.hide_all()
            self.path_combo_box.set_no_show_all(True)
    
    def update_path_songs(self, key):
        self.back_button.set_no_show_all(True)
        self.back_button.hide()
        self.filter_categorybar.set_index(-1)        
        self.__current_path = key        
        self.change_combo_box_status()        
        
        if self.path_combo_box.get_combo_active():
            self.update_path_filter_view(self.path_combo_box.current_status)
        else:    
            songs = self.__db_query.get_attr_songs(key)
            self.update_songs_view(songs)
            
    def update_path_list_view(self):        
        self.back_button.set_no_show_all(True)
        self.back_button.hide()
        if self.__current_path == "###ALL###":
            songs = self.__db_query.get_all_songs()
        else:    
            songs = self.__db_query.get_attr_songs(self.__current_path)
        self.update_songs_view(songs)    
            
    def update_path_filter_view(self, name):
        self.back_button.set_no_show_all(True)
        self.back_button.hide()
        self.entry_box.entry.set_text("")
        
        self.filter_view.clear()
        if self.__current_path == "###ALL###":
            self.reload_filter_view(name, True, True)
        else:    
            attr_infos = self.get_attr_infos_from_db(name, self.__current_path)
            items = []
            for info in attr_infos:
                key, value, nb, tag = info
                items.append(IconItem((key, value, nb, tag)))
            self.filter_view.add_items(items)    
            
            if self.view_mode != ICON_VIEW_MODE:
                self.switch_box(self.right_box, self.filter_scrolled_window)
                self.view_mode = ICON_VIEW_MODE
                
    def reload_song_path(self):
        path_infos = self.get_attr_infos_from_db()
        if path_infos:
            self.path_categorybar.update_items([(name[0], self.update_path_songs, name[1]) for name in path_infos])
    
    def connect_to_db(self):    
        self.autoconnect(self.__db_query, "added", self.__added_song_cb)
        self.autoconnect(self.__db_query, "removed", self.__removed_song_cb)
        self.autoconnect(self.__db_query, "update-tag", self.__update_tag_view)
        self.autoconnect(self.__db_query, "full-update", self.__full_update)
        self.autoconnect(self.__db_query, "quick-update", self.__quick_update)
        self.__db_query.set_query("")                
        
    def __added_song_cb(self, db_query, songs):
        self.reload_song_path()        
        self.reload_flag = True

    def __removed_song_cb(self, db_query, songs):
        self.reload_song_path()        
        self.reload_flag = True
            
    def reload_browser(self,  obj, infos):
        if infos:
            self.reload_flag = True
            
    def interval_reload_browser(self):        
        if self.reload_flag and not self.__search_flag:
            self.reload_all_items()
            self.reload_flag = False    
        return True    
                    
    def reload_all_items(self):                
        if self.view_mode == ICON_VIEW_MODE:
            if self.path_categorybar.get_index() == -1:
                self.reload_filter_view(self.categorybar_status)
            else:    
                self.update_path_filter_view(self.path_combo_box.current_status)
        else:        
            if self.path_categorybar.get_index() == -1:
                if self.current_icon_item:
                    self.update_category_songs_view(self.current_icon_item)
            else:        
                if self.current_icon_item:
                    self.update_path_songs_view(self.current_icon_item)
    
    def __update_tag_view(self, db_query, tag, values):
        if values:
            self.reload_flag = True
    
    def __quick_update(self, db_query, songs):
        pass
        
    def __full_update(self, db_query):    
        self.reload_filter_view()
        self.reload_song_path()
    
    def __get_selected_songs(self, tag="artist"):
        artists = []
        albums = []
        genres = []
        
        if tag == "artist":
            artists = self.__selected_tag["artist"]
        elif tag == "album":    
            albums = self.__selected_tag["album"]
        elif tag == "genre":    
            genres = self.__selected_tag["genre"]
            
        return self.__db_query.get_songs(genres, artists, albums)    
    
    def __on_drag_data_get(self, widget, context, selection, info, timestamp):
        item = self.filter_view.highlight_item
        if not item:
            return 
        
        if item.key_name == "deepin-all-songs":
            songs = self.__db_query.get_all_songs()
        else:    
            del self.__selected_tag[item.tag]
            self.__selected_tag[item.tag] = [item.key_name]
            songs = self.__get_selected_songs(item.tag)
        if not songs:
            return 
        songs = list(songs)
        songs.sort()
        list_uris = list([ song.get("uri") for song in songs])
        selection.set("text/deepin-songs", 8, "\n".join(list_uris))
        selection.set_uris(list_uris)
    
    def __on_double_click_item(self, widget,  item, x, y):
        self.current_icon_item = item
        self.entry_box.entry.set_text("")
        self.back_button.set_no_show_all(False)
        self.back_button.show()
        if self.path_categorybar.get_index() == -1:
            self.update_category_songs_view(item)
        else:    
            self.update_path_songs_view(item)
        
    def update_category_songs_view(self, item):    
        if item.key_name == "deepin-all-songs":
            songs = self.__db_query.get_all_songs()
        else:    
            self.__selected_tag[item.tag] = [item.key_name]
            songs = self.__get_selected_songs(item.tag)
        self.update_songs_view(songs, item.tag)    
        
    def update_path_songs_view(self, item):    
        songs = self.__db_query.get_attr_songs(self.__current_path, item.tag, item.key_name)
        if songs:
            self.update_songs_view(songs, item.tag)
        
    def update_songs_view(self, items, sort_key="title"):    
        self.songs_view.clear()
        self.entry_box.entry.set_text("")
        self.songs_view.add_songs(items)
        self.songs_view.set_sort_keyword(sort_key)
        if self.view_mode != LIST_VIEW_MODE:
            self.switch_box(self.right_box, self.songs_scrolled_window)
            self.view_mode= LIST_VIEW_MODE
        
    def __on_single_click_item(self, widget, item, x, y):    
        if item.pointer_in_play_rect(x, y):
            if item.key_name == "deepin-all-songs":
                songs = self.__db_query.get_all_songs()
            else:    
                del self.__selected_tag[item.tag]
                self.__selected_tag[item.tag] = [item.key_name]
                songs = self.__get_selected_songs(item.tag)
            if not songs:
                return 
            songs = list(songs)
            songs.sort()
            if not songs:
                return 
            Dispatcher.play_and_add_song(songs)
        
        
    def __search_cb(self, widget, text):    
        if self.view_mode == LIST_VIEW_MODE:
            if not self.__search_flag:
                self.__song_cache_items = self.songs_view.items[:]
                
            # Clear song_view select status    
            self.songs_view.select_rows = []    
            if text != "":
                self.__search_flag = True
                results = filter(lambda item: text.lower().replace(" ", "") in item.get_song().get("search", ""), self.__song_cache_items)
                self.songs_view.items = results
                self.songs_view.update_item_index()
                self.songs_view.update_vadjustment()
            else:    
                self.__search_flag = False
                self.songs_view.items = self.__song_cache_items
                self.songs_view.update_item_index()
                self.songs_view.update_vadjustment()
            self.songs_view.queue_draw()    
        elif self.view_mode == ICON_VIEW_MODE:    
            if not self.__search_flag:
                self.__cover_cache_items = self.filter_view.items[:]
            if text != "":    
                self.__search_flag = True
                results = filter(lambda item: text.lower().replace(" ", "") in item.retrieve, self.__cover_cache_items)
                self.filter_view.items = results
            else:    
                self.__search_flag = False
                self.filter_view.items = self.__cover_cache_items
            self.filter_view.queue_draw()    
        
    def switch_box(self, parent, child):    
        switch_tab(parent, child)