import weakref import logging logger = logging.getLogger(__name__) from core import cons from core import utils from core.api import api from core.config import conf from core.container import Container from PySide.QtGui import * from PySide.QtCore import * import media import signals from list_model import SimpleListModel from context_menu import Menu from add_links_dlg import AddLinks from generic_dialog import Dialog class AddDownloads(QVBoxLayout): def __init__(self, parent): QVBoxLayout.__init__(self) self.setContentsMargins(0, 0, 0, 0) self.setSpacing(5) self.weak_parent = weakref.ref(parent) self.tree_view = QTreeView() self.tree_view.setContextMenuPolicy(Qt.CustomContextMenu) self.tree_view.customContextMenuRequested.connect(self.context_menu) #listview look self.tree_view.setWordWrap(True) #search textElideMode self.tree_view.setRootIsDecorated(False) self.tree_view.setIndentation(0) self.tree_view.setAlternatingRowColors(True) self.icons_dict = self.get_icons() self.items = [] self.rows_buffer = {} #{id_item: row_obj, } bool_cols = [1, ] image_cols = [2, ] headers = ["hidden_id_item", "", "", _("File Name"), _("Host"), _("Size"), _("Status Message")] self.__model = SimpleListModel(headers, self.items, bool_cols, image_cols) self.tree_view.setModel(self.__model) self.addWidget(self.tree_view) self.tree_view.setColumnHidden(0, True) self.tree_view.setColumnWidth(1, 27) self.tree_view.setColumnWidth(2, 27) self.tree_view.header().setResizeMode(1, QHeaderView.Fixed) hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) hbox.setSpacing(10) self.cb = QComboBox() #self.cb.setFixedWidth(100) self.cb.setEditable(True) self.cb.setFixedHeight(35) self.cb.setMinimumWidth(1) cb_view = self.cb.view() cb_view.setAlternatingRowColors(True) self.paths_list = conf.get_save_dl_paths() if not self.paths_list: self.cb.addItem(cons.DLFOLDER_PATH) else: [self.cb.addItem(path) for path in reversed(self.paths_list)] hbox.addWidget(self.cb) btn_examine = QPushButton('...') btn_examine.clicked.connect(self.on_examine) btn_examine.setFixedHeight(35) btn_examine.setMaximumWidth(80) hbox.addWidget(btn_examine) hbox.addSpacing(40) #index, size btn_download = QPushButton() btn_download.setIcon(media.get_icon(media.DOWN, media.MEDIUM)) btn_download.setIconSize(QSize(24, 24)) btn_download.clicked.connect(self.on_download_selected) btn_download.setFixedHeight(35) btn_download.setMaximumWidth(40) hbox.addWidget(btn_download) btn_add = QPushButton() btn_add.setIcon(media.get_icon(media.ADD, media.MEDIUM)) btn_add.setIconSize(QSize(24, 24)) btn_add.clicked.connect(self.on_add_links) btn_add.setFixedHeight(35) btn_add.setMaximumWidth(40) hbox.addWidget(btn_add) self.menu = QMenu() import_action = self.menu.addAction(_("Import Container"), self.on_import_container) self.menu.addSeparator() recheck_action = self.menu.addAction(_("Re-check"), self.on_recheck) clear_action = self.menu.addAction(_("Clear list"), self.on_clear_list) btn_menu = QPushButton() btn_menu.setMenu(self.menu) btn_menu.setFixedHeight(35) btn_menu.setMaximumWidth(22) btn_menu.setFlat(True) hbox.addWidget(btn_menu) self.addLayout(hbox) #custom signals signals.add_downloads_to_check.connect(self.add_downloads_to_check) #update list self.timer = parent.idle_timeout(1000, self.update_) @property def parent(self): return self.weak_parent() def get_selected_rows(self): """""" selected_rows = [index.row() for index in self.tree_view.selectionModel().selectedRows()] selected_rows.sort() return selected_rows def context_menu(self, position): rows = self.get_selected_rows() is_single_row = True if len(rows) == 1 else False options = [(_('Save as...'), self.on_save_as, is_single_row), None, (_('Download Selected'), self.on_download_selected, True), None, (_('Select all'), self.on_select_all, True), (_('Select none'), self.on_select_none, True), (_('Select inverse'), self.on_select_inverse, True), None, (_('Re-check'), self.on_recheck, True), (_('Clear list'), self.on_clear_list, True)] menu = Menu(options) menu.exec_(self.tree_view.viewport().mapToGlobal(position)) def on_save_as(self): rows = self.get_selected_rows() row = self.items[rows[0]] item_id = row[0] download_item = api.get_checking_download_item(item_id) widget = QLineEdit() # set the line entry file name if we have one. if download_item.save_as: widget.setText(download_item.save_as) elif download_item.name != cons.UNKNOWN: widget.setText(download_item.name) dialog = Dialog(self.parent, "Save as", widget) if dialog.result() == QDialog.Accepted: save_as = widget.text() # change the file name in treeview and DownloadItem if save_as: api.save_download_as(download_item, save_as) api.set_download_name(download_item, save_as) row[3] = save_as def on_clear_list(self): self.__model.clear() self.rows_buffer.clear() api.clear_pending() def on_recheck(self): api.recheck_items() def on_select_all(self): for row in self.items: row[1] = True def on_select_none(self): for row in self.items: row[1] = False def on_select_inverse(self): for row in self.items: row[1] = False if row[1] else True def on_import_container(self): file_name, filter = QFileDialog.getOpenFileName(filter='OCH Files (*.och)') if file_name: container = Container(file_name) container.extract_links() links_list = container.get_linklist() if links_list: self.add_downloads_to_check(links_list, copy_link=False) def on_add_links(self): dialog = AddLinks(self.parent) result_code = dialog.result() links_list = dialog.links_list if result_code == QDialog.Accepted and links_list: self.add_downloads_to_check(links_list) def on_examine(self): folder = QFileDialog.getExistingDirectory() if folder: self.cb.setEditText(folder) def cb_remove(self, text): index = self.cb.findText(text) if index >= 0: self.cb.removeItem(index) def on_download_selected(self): # save the selected path current_path = self.cb.currentText() self.cb_remove(current_path) self.cb.insertItem(0, current_path) if current_path in self.paths_list: self.paths_list.remove(current_path) self.paths_list.append(current_path) if len(self.paths_list) > 5: self.paths_list.pop(0) self.cb.removeItem(5) self.cb.setCurrentIndex(0) conf.set_save_dl_paths(self.paths_list) # move selected items to downloads tab id_items_list = [] iters = [] for row in self.items: if row[1]: iters.append(row) id_item = row[0] id_items_list.append(id_item) del self.rows_buffer[id_item] [self.__model.remove(self.items.index(iter)) for iter in iters] item_list = api.pop_checking_items(id_items_list) for download_item in item_list: download_item.path = current_path signals.add_to_downloader.emit(item_list) def add_downloads_to_check(self, links_list, copy_link=True): for link in links_list: download_item = api.create_download_item(cons.UNKNOWN, link, copy_link=copy_link) api.add_to_checker(download_item) item = [download_item.id, True, self.icons_dict[cons.LINK_CHECKING], cons.UNKNOWN, None, None, None] #self.items.append(item) self.__model.append(item) self.rows_buffer[item[0]] = item api.start_checking() def update_(self): checking_downloads = api.get_checking_downloads() api.update_checking_downloads() for download_item in checking_downloads.itervalues(): row = self.rows_buffer[download_item.id] if download_item.link_status == cons.LINK_DEAD: row[1] = False row[2] = self.icons_dict[download_item.link_status] row[3] = download_item.name if not download_item.host == cons.UNSUPPORTED: row[4] = download_item.host if download_item.size: row[5] = utils.size_format(download_item.size) row[6] = download_item.link_status_msg self.__model.refresh() def get_icons(self): alive = media.get_pixmap(media.ALIVE, media.SMALL) dead = media.get_pixmap(media.DEAD, media.SMALL) error = media.get_pixmap(media.ERROR, media.SMALL) checking = media.get_pixmap(media.CHECKING, media.SMALL) #unavailable = media.get_pixmap(media.ERROR, media.SMALL) return {cons.LINK_ALIVE: alive, cons.LINK_DEAD: dead, cons.LINK_UNAVAILABLE: error, cons.LINK_ERROR: error, cons.LINK_CHECKING: checking}