class UninstallPage(gtk.VBox):
    '''
    class docs
    '''
	
    def __init__(self, bus_interface, data_manager):
        '''
        init docs
        '''
        # Init.
        gtk.VBox.__init__(self)
        self.bus_interface = bus_interface        
        self.data_manager = data_manager

        self.search_flag = False
        self.uninstall_change_items = {"add": [], "delete": []}
        
        self.message_bar = MessageBar(32)
        self.message_bar.search_entry.entry.connect("changed", self.search_cb)
        self.message_bar.search_button.connect("clicked", self.search_cb)
        self.treeview = TreeView(enable_drag_drop=False)
        self.treeview.set_expand_column(0)

        top_hbox = gtk.HBox()
        top_hbox.pack_start(self.message_bar)

        self.pack_start(top_hbox, False, False)
        self.pack_start(self.treeview, True, True)
        
        self.treeview.connect("items-change", self.update_message_bar)
        
        self.fetch_uninstall_info()
        
        self.treeview.draw_mask = self.draw_mask

    def search_cb(self, widget, event=None):
        if not self.search_flag:
            self.cache_items = [item for item in self.treeview.visible_items]
        results = []
        keywords = self.message_bar.search_entry.get_text().strip()

        if keywords != "":
            self.search_flag = True
            # TODO: comment this search_query api, there are many problems for this api
            '''
            pkg_names = self.data_manager.search_query(map(lambda word: word.encode("utf8"), keywords.split(" ")))
            for item in self.cache_items:
                if item.pkg_name in pkg_names:
                    results.append(item)
            '''
            for item in self.cache_items:
                if keywords in item.pkg_name:
                    results.append(item)
            self.treeview.clear()
            self.treeview.add_items(results)
        else:
            self.treeview.clear()
            self.search_flag = False

            # for add items
            if self.uninstall_change_items["add"] != []:
                for item in self.uninstall_change_items["add"]:
                    self.cache_items.append(item)
                self.uninstall_change_items["add"] = []

            # for delete items
            if self.uninstall_change_items["delete"] != []:
                for item in self.uninstall_change_items["delete"]:
                    if item in self.cache_items:
                        self.cache_items.remove(item)
                self.uninstall_change_items["delete"] = []

            self.treeview.add_items(self.cache_items)

    def normal_search_cb(self, keywords):
        pass
        
    def update_message_bar(self, treeview):    
        self.message_bar.set_message(_("%s applications can be uninstalled") % len(treeview.visible_items))
        
    def draw_mask(self, cr, x, y, w, h):
        '''
        Draw mask interface.
        
        @param cr: Cairo context.
        @param x: X coordiante of draw area.
        @param y: Y coordiante of draw area.
        @param w: Width of draw area.
        @param h: Height of draw area.
        '''
        draw_vlinear(cr, x, y, w, h,
                     [(0, ("#FFFFFF", 0.9)),
                      (1, ("#FFFFFF", 0.9)),]
                     )
        
    def update_action_status(self, pkg_infos):
        pkg_items = []
        for (pkg_name, action_status) in pkg_infos:
            pkg_item = None
            for item in self.treeview.visible_items:
                if item.pkg_name == pkg_name:
                    pkg_item = item
                    break

            if pkg_item == None:
                pkg_item = UninstallItem(pkg_name, self.bus_interface.request_pkgs_uninstall_version([pkg_name])[0], self.data_manager)
                
            if action_status == "wait":
                pkg_item.action_wait()
            elif action_status == "start":
                pkg_item.action_start()
            elif action_status == "update":
                pkg_item.action_update(0)
            pkg_items.append(pkg_item)
                
        pkg_items = filter(lambda item: item not in self.treeview.visible_items, pkg_items)
        self.treeview.add_items(pkg_items)        
        
    def fetch_uninstall_info(self):
        self.bus_interface.request_uninstall_pkgs(
                        reply_handler=self.render_uninstall_info,
                        error_handler=lambda e:handle_dbus_error("request_uninstall_pkgs", e))
    
    def render_uninstall_info(self, pkg_infos):
        self.add_uninstall_items(pkg_infos)
        
    def add_uninstall_items(self, pkg_infos):
        items = []
        for pkg_info in pkg_infos:
            (pkg_name, pkg_version) = eval(pkg_info)
            if self.data_manager.is_pkg_have_desktop_file(pkg_name) != None \
                and self.data_manager.is_pkg_display_in_uninstall_page(pkg_name)[0] == '1':
                items.append(UninstallItem(pkg_name, pkg_version, self.data_manager))
            
        if self.search_flag:
            self.uninstall_change_items["add"] += items
        else:
            self.treeview.add_items(items)

    def delete_uninstall_items(self, items):
        if self.search_flag:
            self.uninstall_change_items["delete"] += items
            for item in items:
                if item in self.treeview.visible_items:
                    self.treeview.delete_items([item])
        else:
            self.treeview.delete_items(items)
        
    def action_start(self, pkg_name):
        for item in self.treeview.visible_items:
            if item.pkg_name == pkg_name:
                item.action_start()
                break
    
    def action_update(self, pkg_name, percent):
        for item in self.treeview.visible_items:
            if item.pkg_name == pkg_name:
                item.action_update(percent)
                break
    
    def action_finish(self, pkg_name, pkg_info_list):
        for item in self.treeview.visible_items:
            if item.pkg_name == pkg_name:
                item.action_finish()
                break
class InstallPage(gtk.VBox):
    '''
    class docs
    '''

    def __init__(self, bus_interface, data_manager):
        '''
        init docs
        '''
        # Init.
        gtk.VBox.__init__(self)
        self.bus_interface = bus_interface
        self.data_manager = data_manager

        self.message_bar = MessageBar(32)
        self.message_box = gtk.HBox()

        self.treeview = TreeView(enable_drag_drop=False)
        self.treeview.set_expand_column(0)
        self.cute_message_image = gtk.VBox()
        self.content_box = gtk.VBox()

        self.pack_start(self.message_box, False, False)
        self.pack_start(self.content_box, True, True)

        self.cute_message_pixbuf = utils.get_common_locale_image_pixbuf("info", "no_download.png")
        self.content_box.pack_start(self.cute_message_image, True, True)

        self.treeview.draw_mask = self.draw_mask

        self.cute_message_image.connect("expose-event", self.expose_cute_message_image)
        self.treeview.connect("items-change", self.update_message_bar)
        self.treeview.connect("items-change", lambda treeview: global_event.emit("update-install-notify-number", self.get_installing_pkgs_number()))

        #self.get_action_item("deepin-webapps-baidu-map")
        #self.download_failed("deepin-webapps-baidu-map")

    def expose_cute_message_image(self, widget, event):
        if self.cute_message_pixbuf:
            cr = widget.window.cairo_create()
            rect = widget.allocation

            cr.set_source_rgb(1, 1, 1)
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()

            draw_pixbuf(
                cr,
                self.cute_message_pixbuf,
                rect.x + (rect.width - self.cute_message_pixbuf.get_width()) / 2,
                rect.y + (rect.height - self.cute_message_pixbuf.get_height()) / 2,
                )

    def update_install_status(self):
        global_event.emit("update-install-notify-number", self.get_installing_pkgs_number())
        self.update_message_bar(self.treeview)

    def get_installing_pkgs_number(self):
        items = []
        for item in self.treeview.visible_items:
            if not (item.status == item.STATUS_INSTALL_FINISH or \
                    item.status == item.STATUS_DOWNLOAD_FAILED):
                items.append(item)
        return len(items)

    def get_installed_pkgs_number(self):
        items = []
        for item in self.treeview.visible_items:
            if item.status == item.STATUS_INSTALL_FINISH:
                items.append(item)
        return len(items)

    def delete_item_match_pkgname(self, pkg_name):
        for install_item in self.treeview.visible_items:
            if install_item.pkg_name == pkg_name:
                self.treeview.delete_items([install_item])
                break

    def update_message_bar(self, treeview):
        if self.get_installing_pkgs_number() == 0:
            if self.get_installed_pkgs_number() == 0:
                container_remove_all(self.message_box)

                children = self.content_box.get_children()
                if len(children) == 0 or children[0] == self.treeview:
                    if self.cute_message_pixbuf == None:
                        self.cute_message_pixbuf = utils.get_common_locale_image_pixbuf("info", "no_download.png")

                    container_remove_all(self.content_box)
                    self.content_box.pack_start(self.cute_message_image, True, True)

                    self.show_all()
            else:
                self.message_bar.set_message("")
        else:
            container_remove_all(self.message_box)
            self.message_box.pack_start(self.message_bar, True, True)
            self.message_bar.set_message(_("%s applications are being installed") % self.get_installing_pkgs_number())

            children = self.content_box.get_children()
            if len(children) == 0 or children[0] == self.cute_message_image:
                if self.cute_message_pixbuf:
                    del self.cute_message_pixbuf
                    self.cute_message_pixbuf = None

                container_remove_all(self.content_box)
                self.content_box.pack_start(self.treeview, True, True)

                self.show_all()

    def draw_mask(self, cr, x, y, w, h):
        '''
        Draw mask interface.

        @param cr: Cairo context.
        @param x: X coordiante of draw area.
        @param y: Y coordiante of draw area.
        @param w: Width of draw area.
        @param h: Height of draw area.
        '''
        draw_vlinear(cr, x, y, w, h,
                     [(0, ("#FFFFFF", 0.9)),
                      (1, ("#FFFFFF", 0.9)),]
                     )

    def update_download_status(self, pkg_infos):
        pkg_items = []
        for (pkg_name, download_status) in pkg_infos:
            pkg_item = None
            for item in self.treeview.visible_items:
                if item.pkg_name == pkg_name:
                    pkg_item = item
                    break

            if pkg_item == None:
                pkg_item = InstallItem(pkg_name, self.bus_interface.request_pkgs_install_version([pkg_name])[0], self.data_manager)

            if download_status == "wait":
                pkg_item.download_wait()
            elif download_status == "start":
                pkg_item.download_start()
            elif download_status == "update":
                pkg_item.download_update(0, 0)
            pkg_items.append(pkg_item)

        pkg_items = filter(lambda item: item not in self.treeview.visible_items, pkg_items)
        self.treeview.add_items(pkg_items)

    def update_action_status(self, pkg_infos):
        pkg_items = []
        for (pkg_name, action_status) in pkg_infos:
            pkg_item = None
            for item in self.treeview.visible_items:
                if item.pkg_name == pkg_name:
                    pkg_item = item
                    break

            if pkg_item == None:
                pkg_item = InstallItem(pkg_name, self.bus_interface.request_pkgs_install_version([pkg_name])[0], self.data_manager)

            if action_status == "wait":
                pkg_item.download_finish()
            elif action_status == "start":
                pkg_item.action_start()
            elif action_status == "update":
                pkg_item.action_update(0)
            pkg_items.append(pkg_item)

        pkg_items = filter(lambda item: item not in self.treeview.visible_items, pkg_items)
        self.treeview.add_items(pkg_items)

    def add_install_actions(self, pkg_names):
        for pkg_name in pkg_names:
            self.get_action_item(pkg_name)

    def get_action_item(self, pkg_name):
        action_item = None
        for item in self.treeview.visible_items:
            if item.pkg_name == pkg_name:
                action_item = item
                break

        if action_item == None:
            action_item = InstallItem(pkg_name, self.bus_interface.request_pkgs_install_version([pkg_name])[0], self.data_manager)
            self.treeview.add_items([action_item])

        return action_item

    def download_ready(self, pkg_name):
        self.get_action_item(pkg_name).download_ready()

    def download_wait(self, pkg_name):
        self.get_action_item(pkg_name).download_wait()

    def download_start(self, pkg_name):
        self.get_action_item(pkg_name).download_start()

    def download_update(self, pkg_name, percent, speed):
        self.get_action_item(pkg_name).download_update(percent, speed)

    def download_finish(self, pkg_name):
        self.get_action_item(pkg_name).download_finish()

    def download_stop(self, pkg_name):
        self.get_action_item(pkg_name).download_stop()

    def download_parse_failed(self, pkg_name):
        self.get_action_item(pkg_name).download_parse_failed()

    def download_failed(self, pkg_name):
        self.get_action_item(pkg_name).download_failed()

    def action_start(self, pkg_name):
        self.get_action_item(pkg_name).action_start()

    def action_update(self, pkg_name, percent):
        self.get_action_item(pkg_name).action_update(percent)

    def action_finish(self, pkg_name, pkg_info_list):
        self.get_action_item(pkg_name).action_finish()
class TrayUI(gtk.VBox):
    def __init__(self):
        gtk.VBox.__init__(self, spacing=0)
        self.init_ui()
        self.active_ap_index = []
        self.all_showed = False

    def init_ui(self):
        self.wire = Section(app_theme.get_pixbuf("network/cable.png"),
                            _("Wired"))
        self.wireless = Section(app_theme.get_pixbuf("network/wifi.png"),
                                _("Wireless"))
        self.mobile = Section(app_theme.get_pixbuf("network/3g.png"),
                              _("Mobile Network"))
        # vpn
        self.vpn = Section(app_theme.get_pixbuf("network/vpn.png"),
                           _("VPN Network"))
        self.dsl = Section(app_theme.get_pixbuf("network/dsl.png"), _("DSL"))

        self.ssid_list = []
        self.tree_box = gtk.VBox(spacing=0)
        self.button_more = SelectButton(_("Advanced..."),
                                        font_size=10,
                                        ali_padding=5)
        self.button_more.set_size_request(-1, 25)
        #self.pack_start(self.button_more, False, False)
        self.ap_tree = TreeView(mask_bound_height=0)
        self.ap_tree.set_expand_column(0)

        self.vpn_list = ConList()
        self.dsl_list = DSLConList()

        self.wire_box = self.section_box([self.wire])
        self.wireless_box = self.section_box([self.wireless, self.tree_box])
        self.mobile_box = self.section_box([self.mobile])
        self.vpn_box = self.section_box([self.vpn, self.vpn_list])
        self.dsl_box = self.section_box([self.dsl, self.dsl_list])
        self.wire_state = False
        self.wireless_state = False
        self.mobile_state = False
        self.vpn_state = False
        self.dsl_state = False

        self.device_tree = None

        self.pack_start(self.wire_box, False, False)
        self.pack_start(self.wireless_box, False, False)
        self.pack_start(self.mobile_box, False, False)
        self.pack_start(self.vpn_box, False, False)
        self.pack_start(self.dsl_box, False, False)
        self.pack_start(self.button_more, False, False)

    def get_widget_height(self):
        height = 0
        if self.wire_state:
            height += 35
        if self.wireless_state:
            height += 35
            if self.ap_tree.visible_items and self.wireless.get_active():
                height += self.ap_tree.get_size_request()[1]
            if self.device_tree:
                height += 22

        if self.mobile_state:
            height += 35

        if self.vpn_state:
            height += 35 + len(self.vpn_list.get_children()) * 22

        if self.dsl_state:
            height += 35 + len(self.dsl_list.get_children()) * 22
            height += 5
        height += 25

        return height

    def section_box(self, widgets):
        box = gtk.VBox(spacing=0)
        for w in widgets:
            box.pack_start(w, False, False)
        style.add_separator(box, 10)
        return box

    def remove_net(self, net_type):
        #print net_type
        getattr(self, net_type + "_box").set_no_show_all(True)
        #getattr(self, net_type).set_active((True, False))
        getattr(self, net_type + "_box").hide()
        setattr(self, net_type + "_state", False)

    def show_net(self, net_type):
        getattr(self, net_type + "_box").set_no_show_all(False)
        getattr(self, net_type + "_box").show()
        setattr(self, net_type + "_state", True)

    def set_wired_state(self, widget, new_state, reason):
        if new_state is 20:
            self.wire.set_active(0)
        else:
            tray_log.debug(__name__, new_state, reason)

    def set_visible_aps(self, show_all=False):
        if not self.__ap_list:
            self.visible_aps = []
            return

        tray_log.debug(len(self.__ap_list))

        if show_all:
            if len(self.__ap_list) <= 10:
                self.visible_aps = self.__ap_list[:]
            else:
                self.visible_aps = self.__ap_list[:10]
            self.more_button.set_ap_list([])
            self.show_all = True

        else:
            if len(self.__ap_list) <= 5:
                self.visible_aps = self.__ap_list[:]
                self.show_all = True
            else:
                self.visible_aps = self.__ap_list[:5]
                self.more_button.set_ap_list(self.__ap_list[5:])
                self.show_all = False

    def set_ap(self, ap_list, redraw=True):
        if not ap_list:
            return
        self.__set_ap_list(ap_list)
        #print "DEBUG", len(self.visible_aps), self.show_all
        self.ap_tree.delete_all_items()
        container_remove_all(self.tree_box)

        self.ap_tree.add_items(map(lambda ap: SsidItem(ap), self.__ap_list))
        length = len(self.ap_tree.visible_items)
        if length <= 10:
            self.ap_tree.set_size_request(-1, WIDGET_HEIGHT * length)
        else:
            self.ap_tree.set_size_request(-1, WIDGET_HEIGHT * 10)
            for item in self.ap_tree.visible_items:
                item.set_padding(10)

        self.tree_box.pack_start(self.ap_tree, False, False)
        self.show_all()

        if redraw:
            Dispatcher.request_resize()

    def __set_ap_list(self, ap_list):
        self.__ap_list = ap_list

    def move_active(self, index):
        if index != [] and self.__ap_list:
            for i in index:
                if i < len(self.ap_tree.visible_items):
                    self.ap_tree.delete_item_by_index(i)
                    self.ap_tree.add_items([SsidItem(self.__ap_list[i])],
                                           insert_pos=0)
                else:
                    self.ap_tree.delete_item_by_index(-1)
                    self.ap_tree.add_items([SsidItem(self.__ap_list[i])],
                                           insert_pos=0)
                self.ap_tree.visible_items[0].set_active(True)

    def set_active_ap(self, index, state):
        self.active_ap_index = index
        self.set_ap(self.__ap_list, redraw=False)

        if index:
            self.move_active(index)

    def get_active_ap(self):
        return self.active_ap_index

    def add_switcher(self):
        if not hasattr(self, "device_tree") or not self.device_tree:
            self.device_tree = TreeView([DeviceItem()], mask_bound_height=0)
            self.device_tree.set_expand_column(1)
            self.wireless_box.pack_start(self.device_tree, False, False)
            self.wireless_box.reorder_child(
                self.wireless_box.get_children()[-2],
                len(self.wireless_box.get_children()))
            tray_log.debug(self.wireless_box.get_children())
            net_manager.emit_wifi_switch(0)

    def remove_switcher(self):
        if self.device_tree:
            self.wireless_box.remove(self.device_tree)
            self.device_tree = None

    def get_active_in_ui(self):
        return filter(lambda i: i.get_active() == True,
                      self.ap_tree.visible_items)

    def reset_tree(self):
        if len(self.ap_tree.visible_items) >= 5 and self.all_showed:
            remove_items = self.ap_tree.visible_items[5:]
            self.ap_tree.delete_items(remove_items)
            self.ap_tree.set_size_request(-1, WIDGET_HEIGHT * 5)
            self.tree_box.pack_start(self.more_button, False, False)
            self.all_showed = False
class InstallPage(gtk.VBox):
    '''
    class docs
    '''
    def __init__(self, bus_interface, data_manager):
        '''
        init docs
        '''
        # Init.
        gtk.VBox.__init__(self)
        self.bus_interface = bus_interface
        self.data_manager = data_manager

        self.message_bar = MessageBar(32)
        self.message_box = gtk.HBox()

        self.treeview = TreeView(enable_drag_drop=False)
        self.treeview.set_expand_column(0)
        self.cute_message_image = gtk.VBox()
        self.content_box = gtk.VBox()

        self.pack_start(self.message_box, False, False)
        self.pack_start(self.content_box, True, True)

        self.cute_message_pixbuf = utils.get_common_locale_image_pixbuf(
            "info", "no_download.png")
        self.content_box.pack_start(self.cute_message_image, True, True)

        self.treeview.draw_mask = self.draw_mask

        self.cute_message_image.connect("expose-event",
                                        self.expose_cute_message_image)
        self.treeview.connect("items-change", self.update_message_bar)
        self.treeview.connect(
            "items-change", lambda treeview: global_event.emit(
                "update-install-notify-number",
                self.get_installing_pkgs_number()))

        #self.get_action_item("deepin-webapps-baidu-map")
        #self.download_failed("deepin-webapps-baidu-map")

    def expose_cute_message_image(self, widget, event):
        if self.cute_message_pixbuf:
            cr = widget.window.cairo_create()
            rect = widget.allocation

            cr.set_source_rgb(1, 1, 1)
            cr.rectangle(rect.x, rect.y, rect.width, rect.height)
            cr.fill()

            draw_pixbuf(
                cr,
                self.cute_message_pixbuf,
                rect.x +
                (rect.width - self.cute_message_pixbuf.get_width()) / 2,
                rect.y +
                (rect.height - self.cute_message_pixbuf.get_height()) / 2,
            )

    def update_install_status(self):
        global_event.emit("update-install-notify-number",
                          self.get_installing_pkgs_number())
        self.update_message_bar(self.treeview)

    def get_installing_pkgs_number(self):
        items = []
        for item in self.treeview.visible_items:
            if not (item.status == item.STATUS_INSTALL_FINISH or \
                    item.status == item.STATUS_DOWNLOAD_FAILED):
                items.append(item)
        return len(items)

    def get_installed_pkgs_number(self):
        items = []
        for item in self.treeview.visible_items:
            if item.status == item.STATUS_INSTALL_FINISH:
                items.append(item)
        return len(items)

    def delete_item_match_pkgname(self, pkg_name):
        for install_item in self.treeview.visible_items:
            if install_item.pkg_name == pkg_name:
                self.treeview.delete_items([install_item])
                break

    def update_message_bar(self, treeview):
        if self.get_installing_pkgs_number() == 0:
            if self.get_installed_pkgs_number() == 0:
                container_remove_all(self.message_box)

                children = self.content_box.get_children()
                if len(children) == 0 or children[0] == self.treeview:
                    if self.cute_message_pixbuf == None:
                        self.cute_message_pixbuf = utils.get_common_locale_image_pixbuf(
                            "info", "no_download.png")

                    container_remove_all(self.content_box)
                    self.content_box.pack_start(self.cute_message_image, True,
                                                True)

                    self.show_all()
            else:
                self.message_bar.set_message("")
        else:
            container_remove_all(self.message_box)
            self.message_box.pack_start(self.message_bar, True, True)
            self.message_bar.set_message(
                _("%s applications are being installed") %
                self.get_installing_pkgs_number())

            children = self.content_box.get_children()
            if len(children) == 0 or children[0] == self.cute_message_image:
                if self.cute_message_pixbuf:
                    del self.cute_message_pixbuf
                    self.cute_message_pixbuf = None

                container_remove_all(self.content_box)
                self.content_box.pack_start(self.treeview, True, True)

                self.show_all()

    def draw_mask(self, cr, x, y, w, h):
        '''
        Draw mask interface.

        @param cr: Cairo context.
        @param x: X coordiante of draw area.
        @param y: Y coordiante of draw area.
        @param w: Width of draw area.
        @param h: Height of draw area.
        '''
        draw_vlinear(cr, x, y, w, h, [
            (0, ("#FFFFFF", 0.9)),
            (1, ("#FFFFFF", 0.9)),
        ])

    def update_download_status(self, pkg_infos):
        pkg_items = []
        for (pkg_name, download_status) in pkg_infos:
            pkg_item = None
            for item in self.treeview.visible_items:
                if item.pkg_name == pkg_name:
                    pkg_item = item
                    break

            if pkg_item == None:
                pkg_item = InstallItem(
                    pkg_name,
                    self.bus_interface.request_pkgs_install_version([pkg_name
                                                                     ])[0],
                    self.data_manager)

            if download_status == "wait":
                pkg_item.download_wait()
            elif download_status == "start":
                pkg_item.download_start()
            elif download_status == "update":
                pkg_item.download_update(0, 0)
            pkg_items.append(pkg_item)

        pkg_items = filter(
            lambda item: item not in self.treeview.visible_items, pkg_items)
        self.treeview.add_items(pkg_items)

    def update_action_status(self, pkg_infos):
        pkg_items = []
        for (pkg_name, action_status) in pkg_infos:
            pkg_item = None
            for item in self.treeview.visible_items:
                if item.pkg_name == pkg_name:
                    pkg_item = item
                    break

            if pkg_item == None:
                pkg_item = InstallItem(
                    pkg_name,
                    self.bus_interface.request_pkgs_install_version([pkg_name
                                                                     ])[0],
                    self.data_manager)

            if action_status == "wait":
                pkg_item.download_finish()
            elif action_status == "start":
                pkg_item.action_start()
            elif action_status == "update":
                pkg_item.action_update(0)
            pkg_items.append(pkg_item)

        pkg_items = filter(
            lambda item: item not in self.treeview.visible_items, pkg_items)
        self.treeview.add_items(pkg_items)

    def add_install_actions(self, pkg_names):
        for pkg_name in pkg_names:
            self.get_action_item(pkg_name)

    def get_action_item(self, pkg_name):
        action_item = None
        for item in self.treeview.visible_items:
            if item.pkg_name == pkg_name:
                action_item = item
                break

        if action_item == None:
            action_item = InstallItem(
                pkg_name,
                self.bus_interface.request_pkgs_install_version([pkg_name])[0],
                self.data_manager)
            self.treeview.add_items([action_item])

        return action_item

    def download_ready(self, pkg_name):
        self.get_action_item(pkg_name).download_ready()

    def download_wait(self, pkg_name):
        self.get_action_item(pkg_name).download_wait()

    def download_start(self, pkg_name):
        self.get_action_item(pkg_name).download_start()

    def download_update(self, pkg_name, percent, speed):
        self.get_action_item(pkg_name).download_update(percent, speed)

    def download_finish(self, pkg_name):
        self.get_action_item(pkg_name).download_finish()

    def download_stop(self, pkg_name):
        self.get_action_item(pkg_name).download_stop()

    def download_parse_failed(self, pkg_name):
        self.get_action_item(pkg_name).download_parse_failed()

    def download_failed(self, pkg_name):
        self.get_action_item(pkg_name).download_failed()

    def action_start(self, pkg_name):
        self.get_action_item(pkg_name).action_start()

    def action_update(self, pkg_name, percent):
        self.get_action_item(pkg_name).action_update(percent)

    def action_finish(self, pkg_name, pkg_info_list):
        self.get_action_item(pkg_name).action_finish()
class PlaylistUI(gtk.VBox):
    '''Playlist UI.'''
	
    def __init__(self):
        '''Init.'''
        gtk.VBox.__init__(self)

        # Init catagory list.
        self.category_list = TreeView()
        self.category_list.draw_mask = self.draw_category_list_mask
        self.category_list.connect("single-click-item", self.on_category_single_click)
        self.category_list.connect("right-press-items", self.on_category_right_press)
        self.category_list.set_size_request(CATEGROYLIST_WIDTH, -1)
        
        # Init SearchEntry.
        self.entry_box = SearchEntry("")
        self.entry_box.entry.connect("changed", self.search_cb)
        self.entry_box.set_no_show_all(True)
        entry_align = gtk.Alignment()
        entry_align.set(0, 0, 1, 1)
        entry_align.set_padding(2, 0, 10, 10)
        entry_align.add(self.entry_box)
        entry_align.connect("expose-event", self.expose_entry_mask)
        
        # Init toolbar.
        self.toolbar_box = gtk.HBox(spacing=45)
        self.search_button = self.__create_simple_toggle_button("search", self.show_text_entry, 
                                                                _("Search in Current Playlist"))
        
        self.__create_simple_button("list", self.popup_list_menu, _("Playlist Operations"))
        self.__create_simple_button("add", self.popup_add_menu, _("Add"))
        
        self.playmode_button = PlaymodeButton(config.get("setting", "loop_mode", "list_mode").split("_")[0])
        Tooltip.text(self.playmode_button, _("Playback Order"))
        self.playmode_button.connect("button-press-event", self.popup_sort_menu)
        self.toolbar_box.pack_start(self.playmode_button, False, False)
        self.__create_simple_button("delete", self.popup_delete_menu, _("Delete"))
        toolbar_align = gtk.Alignment()
        toolbar_align.set_padding(6, 6, 28, 0)
        toolbar_align.add(self.toolbar_box)
        toolbar_align.connect("expose-event", self.expose_toolbar_mask)
                
        self.right_box = gtk.VBox()
        self.right_box.connect("size-allocate", self.on_right_box_size_allocate)
        self.list_paned = HPaned(handle_color=app_theme.get_color("panedHandler"), enable_drag=True)
        self.list_paned.pack1(self.category_list, True, True)
        self.list_paned.pack2(self.right_box, True, False)
        bottom_box = gtk.VBox()
        bottom_box.set_size_request(-1, 22)
        self.pack_start(self.list_paned, True, True)            
        self.pack_start(entry_align, False, False)            
        self.pack_start(toolbar_align, False, True)            
        
        # Current
        self.current_playlist = None
        self.search_time_source = 0        
        self.current_item = None
        self.search_flag = False
        self.cache_items = None
        self.delete_source_id = None
        self.drag_source_id = None
        self.menu_source_id = None
        self.song_notify_id = None
        self.detail_menu = None
        
        if MediaDB.isloaded():
            self.__on_db_loaded(MediaDB)
        else:    
            MediaDB.connect("loaded", self.__on_db_loaded)
            
        Player.connect("loaded", self.__on_player_loaded)    
        Dispatcher.connect("play-song", self.__play_and_add)
        Dispatcher.connect("add-songs", self.__add_songs_to_list)
        Dispatcher.connect("new-cd-playlist", self.__new_audiocd_playlist)
        Dispatcher.connect("del-cd-playlist", self.delete_audiocd_list)
        Dispatcher.connect("save-current-list", self.save_current_playlist)
        config.connect("config-changed", self.on_config_changed)
        
    def on_config_changed(self, config, section, option, value):    
        if section == "setting" and option == "loop_mode":
            icon_name = value.split("_")[0]
            self.playmode_button.update_dpixbufs(icon_name, True)
        
    def on_right_box_size_allocate(self, widget, rect):    
        if self.current_item:
            if rect.width > HIDE_PLAYLIST_WIDTH:
                self.current_item.song_view.set_hide_columns(None)
            else:    
                self.current_item.song_view.set_hide_columns([1])
        
    def expose_toolbar_mask(self, widget, event):    
        cr = widget.window.cairo_create()
        rect = widget.allocation
        cr.set_source_rgba(1, 1, 1, 0.95)
        cr.rectangle(rect.x, rect.y, rect.width, rect.height)
        cr.fill()
        
        draw_line(cr, (rect.x, rect.y + 1), 
                  (rect.x + rect.width, rect.y + 1), "#b0b0b0")
        return False
    
    def expose_entry_mask(self, widget, event):
        cr = widget.window.cairo_create()
        rect = widget.allocation
        draw_alpha_mask(cr, rect.x , rect.y, rect.width, rect.height, "toolbarEntry")
        
    def draw_category_list_mask(self, cr, x, y, width, height):
        draw_alpha_mask(cr, x, y, width, height, "layoutLeft")
        
    def draw_item_mask(self, cr, x, y, width, height):    
        draw_vlinear(cr, x, y, width, height,
                     app_theme.get_shadow_color("editlistItemPress").get_color_info())        
        
    def __on_db_loaded(self, db):        
        if not MediaDB.get_playlists():
            MediaDB.create_playlist("local", _("Default List"))            
            
        # From MediaDB loaded playlists.    
        init_items = [ListTreeItem(pl) for pl in MediaDB.get_playlists()]    
        self.category_list.add_items(init_items)
        
        # Init Category_list.
        self.category_list.set_highlight_item(self.get_categroy_item_by_index(self.get_save_item_index()))
        self.current_item = self.category_list.get_highlight_item()
        
        self.delete_source_id = self.current_item.song_view.connect("delete-select-items", self.parser_delete_items)
        self.drag_source_id = self.current_item.song_view.connect("drag-data-received", self.parser_drag_event)
        self.menu_source_id = self.current_item.song_view.connect("right-press-items", self.popup_detail_menu)

        Player.set_source(self.current_item.song_view)
        self.right_box.add(self.current_item.get_list_widget())
        self.list_paned.show_all()
        
    def __on_player_loaded(self, player):   
        if self.current_item:
            self.current_item.song_view.reset_error_items()
            self.current_item.song_view.set_highlight_song(Player.song)
        
    def __play_and_add(self, widget, song):    
        self.current_item.song_view.add_songs(song, play=True)
        
    def __add_songs_to_list(self, widget, songs):
        if songs and self.current_item.song_view:
            self.current_item.song_view.add_songs(songs)
        
    def get_selected_song_view(self):    
        if self.current_item:
            return self.current_item.song_view
            
    def search_cb(self, widget, text):        
        if not self.search_flag:
            self.cache_items = self.current_item.song_view.get_items()
        
        # Clear song_view select status    
        self.current_item.song_view.clear_highlight()
        self.current_item.song_view.select_rows = []
        
        if text != "":
            self.search_flag = True
            results = filter(lambda item: text.lower().replace(" ", "") in item.get_song().get("search", ""), self.cache_items)
            self.current_item.song_view.set_song_items(results)
        else:    
            self.search_flag = False
            self.current_item.song_view.set_song_items(self.cache_items)
            
            if Player.song:
                self.current_item.song_view.set_highlight_song(Player.song)
        
    def parser_delete_items(self, widget, items):    
        if self.search_flag:
            if self.cache_items != None:
                [self.cache_items.remove(item) for item in items if item in self.cache_items]
        
    def parser_drag_event(self, widget, context, x, y, selection, info, timestamp):
        if self.search_flag:
            self.reset_search_entry()
            
    def reset_search_entry(self):        
        self.search_button.set_active(False)
            
    def __create_simple_toggle_button(self, name, callback, tip_msg=""):        
        toggle_button = ToggleButton(
            app_theme.get_pixbuf("toolbar/%s_normal.png" % name),
            app_theme.get_pixbuf("toolbar/%s_press.png" % name),
            )
        toggle_button.connect("toggled", callback)
        
        if tip_msg:
            Tooltip.text(toggle_button, tip_msg)
            
        self.toolbar_box.pack_start(toggle_button, False, False)
        return toggle_button
            
    def __create_simple_button(self, name, callback, tip_msg=""):        
        button = ImageButton(
            app_theme.get_pixbuf("toolbar/%s_normal.png" % name),
            app_theme.get_pixbuf("toolbar/%s_hover.png" % name),
            app_theme.get_pixbuf("toolbar/%s_press.png" % name),
            )
        button.connect("button-press-event", callback)
        if tip_msg:
            Tooltip.text(button, tip_msg)
            
        self.toolbar_box.pack_start(button, False, False)
        return button
                                                        
    def popup_add_menu(self, widget, event):
        self.current_item.song_view.popup_add_menu(int(event.x_root), int(event.y_root))
        
        
    def popup_list_menu(self, widget, event):    
        menu_items = [(None, _("New List"), self.new_list),
                      (None, _("Import List"), self.leading_in_list),
                      (None, _("Open List"), self.add_to_list),
                      (None, _("Export List"), self.leading_out_list),
                      (None, _("Remove List"), self.delete_item_list),
                      None,
                      (None, _("Save all Lists"), self.save_all_list)]
        Menu(menu_items, True).show((int(event.x_root), int(event.y_root)))
        
    def new_list(self, items=[], name=None):    
        index = len(self.category_list.get_items())
        if name is None:
            name = "%s%d" % (_("New List"), index)
        input_dialog = InputDialog(_("New List"), name, 300, 100, lambda name : self.create_new_playlist(name, items))
        input_dialog.show_all()
        
    def create_new_playlist(self, name, items):    
        self.category_list.add_items([ListTreeItem(Playlist("local", name, items))])
        
    def __new_audiocd_playlist(self, obj, name, songs, udi):
        self.category_list.add_items([ListTreeItem(CDPlaylist("audiocd", name, songs), udi=udi)]) 
        
    def get_categroy_other_items(self):    
        other_items = []
        highlight_item = self.category_list.get_highlight_item()
        for item in self.category_list.get_items():
            if highlight_item == item:
                continue
            other_items.append(item)
        return other_items    
    
    def get_categroy_index_by_item(self, item):
        index = -1
        for each_index, each_item in enumerate(self.category_list.get_items()):
            if item == each_item: 
                index = each_index
                break
        return index    
    
    def get_categroy_item_by_index(self, index):
        try:
            return self.category_list.get_items()[index]
        except:
            return None
        
    def get_edit_sub_menu(self, select_items, move=False):    
        sub_menu_items = []
        if len(self.category_list.get_items()) > 1:
            other_category_items = self.get_categroy_other_items()
            sub_menu_items = [(None, category_item.get_title(), 
                               self.edit_list_item, category_item, select_items ,move) for category_item in other_category_items]
        if sub_menu_items:    
            sub_menu_items.extend([None, ((app_theme.get_pixbuf("toolbar/add_normal.png"), None, None),
                                          _("New List"), self.edit_new_list_item, select_items, move)])
        else:    
            sub_menu_items.extend([((app_theme.get_pixbuf("toolbar/add_normal.png"), None, None),
                                    _("New List"), self.edit_new_list_item, select_items, move)])
        return Menu(sub_menu_items)
    
    def edit_list_item(self, category_item, select_items, move):
        try:
            category_item.song_view.add_items(select_items)
            category_item.song_view.update_item_index()
            category_item.song_view.update_vadjustment()        
            if move:
                self.current_item.song_view.remove_select_items()
        except:        
            pass
        else:
            self.current_item.song_view.update_item_index()
            self.current_item.song_view.update_vadjustment()
        
    def edit_new_list_item(self, select_items, move):    
        self.new_list([item.get_song().get("uri") for item in select_items])
        if move:
            self.current_item.song_view.remove_select_items()
        self.current_item.song_view.update_item_index()    
        self.current_item.song_view.update_vadjustment()
        
    def leading_in_list(self):    
        uri = WindowLoadPlaylist().run()
        try:
            p_name = utils.get_filename(uri)
            pl = MediaDB.create_playlist("local", p_name, [])
            new_item = ListTreeItem(pl)
            self.category_list.add_items([new_item])
            new_item.song_view.async_add_uris(uri)
        except:    
            pass
        
    def leading_out_list(self, item):    
        if not item:
            item = self.current_item
        WindowExportPlaylist(item.get_songs()).run()
        
    def add_to_list(self, item=None):    
        uri = WindowLoadPlaylist().run()
        if uri:
            try:
                if not item:
                    item = self.current_item
                item.song_view.async_add_uris(uri)
            except: pass    
            
    def delete_audiocd_list(self, obj, udi):
        reset = False
        for item in self.category_list.get_items():
            if item.udi == udi:
                reset = True
                self.category_list.delete_items([item])
        if reset:        
            self.reset_highlight_item(self.category_list.get_items()[-1])    
            
    def delete_item_list(self, item):
        if len(self.category_list.get_items()) == 1:
            return
        
        index = self.get_categroy_index_by_item(item)
        self.category_list.delete_items([item])
        
        max_index = len(self.category_list.get_items()) - 1
        if index <= max_index: 
            new_index = index
        else:    
            new_index = index- 1
        self.reset_highlight_item(self.category_list.get_items()[new_index])    
        
    def save_all_list(self):    
        uri = WinDir().run()
        if uri:
            try:
                save_name_dict = {}
                dir_name = utils.get_path_from_uri(uri)
                for item in self.category_list.get_items():
                    item_name = item.get_title()
                    save_name_dict[item_name] = save_name_dict.get(item_name, -1) + 1
                    if save_name_dict.get(item_name) > 0:
                        filename = "%s%d.%s" % (os.path.join(dir_name, item_name), save_name_dict.get(item_name), "m3u")
                    else:    
                        filename = "%s.%s" % (os.path.join(dir_name, item_name), "m3u")
                    utils.export_playlist(item.get_songs(), filename, "m3u")
            except:        
                pass
        
    def reset_highlight_item(self, item):    
        self.category_list.set_highlight_item(item)
        self.on_category_single_click(None, item, None, None, None)
        
        
    def get_current_item_index(self):    
        item = self.category_list.get_highlight_item()
        index = self.get_categroy_index_by_item(item)
        if index is None:
            return 0
        else:
            return index
    
    def popup_sort_menu(self, widget, event):
        self.current_item.song_view.get_playmode_menu([int(event.x_root), int(event.y_root)])
    
    def popup_delete_menu(self, widget, event):
        self.current_item.song_view.popup_delete_menu(int(event.x_root), int(event.y_root))
        
    def get_save_item_index(self):    
        index = config.getint("playlist", "current_index")
        if index <= len(self.category_list.get_items()) - 1:
            return index
        return 0
    
    def on_category_right_press(self, widget, x, y, item, column):    
        if not item:
            menu_items = [
                (None, _("New List"), self.new_list),
                (None, _("Import List"), self.leading_in_list),
                None,
                (None, _("Save all Lists"), self.save_all_list)
                ]
        else:    
            menu_items = [
                (None, _("Rename"), lambda : self.rename_item_list(item)),
                (None, _("Remove List"), lambda : self.delete_item_list(item)),
                (None, _("Open List"), lambda : self.add_to_list(item)),
                None,
                (None, _("Save all Lists"), self.save_all_list)
                ]
            
        Menu(menu_items, True).show((x, y))    
            
    def rename_item_list(self, item):        
        input_dialog = InputDialog(_("Rename"), item.get_title(), 300, 100,
                                   lambda name: item.set_title(name))    
        input_dialog.show_all()
        
    def on_category_button_press(self, widget, event):    
        if event.button == 3:
            self.popup_list_menu(widget, event)
        
    def on_category_single_click(self, widget, item, column, x, y):        
        self.reset_search_entry()
        if self.drag_source_id != None or self.delete_source_id != None or self.menu_source_id !=None:
            gobject.source_remove(self.drag_source_id)
            gobject.source_remove(self.delete_source_id)
            gobject.source_remove(self.menu_source_id)

        self.current_item = item
        self.category_list.set_highlight_item(item)
        
        self.delete_source_id = self.current_item.song_view.connect("delete-select-items", self.parser_delete_items)
        self.drag_source_id = self.current_item.song_view.connect("drag-data-received", self.parser_drag_event)
        self.menu_source_id = self.current_item.song_view.connect("right-press-items", self.popup_detail_menu)

        container_remove_all(self.right_box)
        self.right_box.add(item.get_list_widget())
        self.list_paned.show_all()
        
    def show_text_entry(self, widget):        
        if widget.get_active():
            self.entry_box.set_no_show_all(False)
            self.entry_box.show_all()
            self.entry_box.focus_input()
        else:    
            self.entry_box.hide_all()            
            self.entry_box.set_no_show_all(True)                        
            self.entry_box.entry.set_text("")
            
    def popup_detail_menu(self, widget, x, y, item, select_items):        
        if self.detail_menu != None:
            self.detail_menu.destroy()
        play_mode_menu = self.current_item.song_view.get_playmode_menu(align=True)
        sort_dict = OrderedDict()
        sort_dict["file"] = _("By Filename")        
        sort_dict["title"] = _("By Title")
        sort_dict["artist"] = _("By Artist")        
        sort_dict["album"] = _("By Album") 
        sort_dict["genre"] = _("By Genre")
        sort_dict["#track"] = _("By Track")
        sort_dict["#playcount"] = _("By Play Count")
        sort_dict["#added"] = _("By Date Added")

        sort_items = [(None, value, self.current_item.song_view.set_sort_keyword, key) for key, value in sort_dict.iteritems()]
        sort_items.append(None)
        sort_items.append((None, _("Randomize"), self.current_item.song_view.random_reorder))
        sub_sort_menu = Menu(sort_items)
        add_to_list_menu = self.get_edit_sub_menu(select_items)
        move_to_list_menu = self.get_edit_sub_menu(select_items, True)
        self.detail_menu = Menu([(None, _("Play"),  self.current_item.song_view.play_select_item),
                                 (None, _("Add to List"), add_to_list_menu),
                                 (None, _("move to List"), move_to_list_menu),
                                 None,
                                 (None, _("Remove Track"), self.current_item.song_view.remove_select_items),
                                 (None, _("Move to Trash"), self.current_item.song_view.try_move_trash),
                                 (None, _("Clear List"), self.current_item.song_view.erase_items),
                                 None,
                                 (None, _("Playback Order"), play_mode_menu),
                                 (None, _("Sort"), sub_sort_menu),
                                 (None, _("Convert"), self.current_item.song_view.songs_convert),
                                 (None, _("Open directory"), self.current_item.song_view.open_song_dir),
                                 (None, _("Properties"), self.current_item.song_view.open_song_editor),
                                 ], True)
        
        if item and item.song.get_type() == "cue":
            self.detail_menu.set_menu_item_sensitive_by_index(5, False)
            self.detail_menu.set_menu_item_sensitive_by_index(10, False)
        self.detail_menu.show((int(x), int(y)))
        
        
    def save_current_playlist(self, *args):    
        index = self.get_current_item_index()        
        config.set("playlist","current_index", str(index))
        
    def save_to_library(self):    
        if self.search_flag:
            self.reset_search_entry()
                  
        MediaDB.full_erase_playlists()
        for item in self.category_list.get_items():
            if item.udi is not None:
                continue
            songs = item.get_songs()
            name = item.get_title()
            MediaDB.create_playlist("local", name, songs)