Пример #1
0
    def __init__(self, parent, itemsTableTool):
        super(ItemsTableGui, self).__init__(parent)
        self.ui = Ui_ItemsTableGui()
        self.ui.setupUi(self)

        self._itemsTableView = UnivTableView(self)
        self.ui.tableViewContainer.addWidget(self._itemsTableView)

        self.__itemsTableTool = itemsTableTool

        #Widgets for text queries
        self.ui.lineEdit_query = TextEdit(self, one_line=True)
        tmp = QtGui.QHBoxLayout(self.ui.widget_lineEdit_query)
        tmp.addWidget(self.ui.lineEdit_query)
        self.connect(self.ui.pushButton_query_exec, QtCore.SIGNAL("clicked()"),
                     self.query_exec)
        self.connect(self.ui.lineEdit_query, QtCore.SIGNAL("returnPressed()"),
                     self.ui.pushButton_query_exec.click)
        self.connect(self.ui.pushButton_query_reset,
                     QtCore.SIGNAL("clicked()"), self.query_reset)
        self.connect(self._itemsTableView,
                     QtCore.SIGNAL("doubleClicked(const QModelIndex&)"),
                     self.__onTableDoubleClicked)

        #TODO limit page function sometimes works not correct!!! It sometimes shows less items, than specified in limit spinbox!
        #Initialization of limit and page spinboxes
        self.ui.spinBox_limit.setValue(
            int(UserConfig().get("spinBox_limit.value", 0)))
        self.ui.spinBox_limit.setSingleStep(
            int(UserConfig().get("spinBox_limit.step", 5)))
        self.connect(self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"),
                     self.query_exec)
        self.connect(
            self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"),
            lambda: UserConfig().store("spinBox_limit.value",
                                       self.ui.spinBox_limit.value()))
        self.connect(self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"),
                     lambda val: self.ui.spinBox_page.setEnabled(val > 0))
        self.connect(self.ui.spinBox_page, QtCore.SIGNAL("valueChanged(int)"),
                     self.query_exec)
        self.ui.spinBox_page.setEnabled(self.ui.spinBox_limit.value() > 0)

        self._itemsTableView.setSortingEnabled(True)

        self.__table_model = None

        self.__context_menu = None
        self.__initContextMenu()
Пример #2
0
    def __init__(self, parent, itemsTableTool):
        super(ItemsTableGui, self).__init__(parent)
        self.ui = Ui_ItemsTableGui()
        self.ui.setupUi(self)

        self._itemsTableView = UnivTableView(self)
        self.ui.tableViewContainer.addWidget(self._itemsTableView)

        self.__itemsTableTool = itemsTableTool

        #Widgets for text queries
        self.ui.lineEdit_query = TextEdit(self, one_line=True)
        tmp = QtGui.QHBoxLayout(self.ui.widget_lineEdit_query)
        tmp.addWidget(self.ui.lineEdit_query)
        self.connect(self.ui.pushButton_query_exec, QtCore.SIGNAL("clicked()"), self.query_exec)
        self.connect(self.ui.lineEdit_query, QtCore.SIGNAL("returnPressed()"), self.ui.pushButton_query_exec.click)
        self.connect(self.ui.pushButton_query_reset, QtCore.SIGNAL("clicked()"), self.query_reset)
        self.connect(self._itemsTableView, QtCore.SIGNAL("doubleClicked(const QModelIndex&)"), self.__onTableDoubleClicked)

        #TODO limit page function sometimes works not correct!!! It sometimes shows less items, than specified in limit spinbox!
        #Initialization of limit and page spinboxes
        self.ui.spinBox_limit.setValue(int(UserConfig().get("spinBox_limit.value", 0)))
        self.ui.spinBox_limit.setSingleStep(int(UserConfig().get("spinBox_limit.step", 5)))
        self.connect(self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"), self.query_exec)
        self.connect(self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"), lambda: UserConfig().store("spinBox_limit.value", self.ui.spinBox_limit.value()))
        self.connect(self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"), lambda val: self.ui.spinBox_page.setEnabled(val > 0))
        self.connect(self.ui.spinBox_page, QtCore.SIGNAL("valueChanged(int)"), self.query_exec)
        self.ui.spinBox_page.setEnabled(self.ui.spinBox_limit.value() > 0)

        self._itemsTableView.setSortingEnabled(True)

        self.__table_model = None

        self.__context_menu = None
        self.__initContextMenu()
Пример #3
0
    def __init__(self, parent, fileBrowserTool):
        super(FileBrowserGui, self).__init__(parent)
        self.ui = Ui_FileBrowserGui()
        self.ui.setupUi(self)

        self.__fileBrowserTool = fileBrowserTool
        self.__tableModel = None
        self.__proxyModel = None

        self.ui.filesTableView = UnivTableView(self)
        self.ui.tableViewContainer.addWidget(self.ui.filesTableView)

        self.connect(self.ui.filesTableView,
                     QtCore.SIGNAL("activated(const QModelIndex&)"),
                     self.__onTableCellActivated)

        self.resetTableModel(mutex=None)

        self.__context_menu = None
        self.__initContextMenu()

        self.__prevSelRows = []  # This is a stack of row indices
Пример #4
0
class ItemsTableGui(ToolGui):

    def __init__(self, parent, itemsTableTool):
        super(ItemsTableGui, self).__init__(parent)
        self.ui = Ui_ItemsTableGui()
        self.ui.setupUi(self)

        self._itemsTableView = UnivTableView(self)
        self.ui.tableViewContainer.addWidget(self._itemsTableView)

        self.__itemsTableTool = itemsTableTool

        #Widgets for text queries
        self.ui.lineEdit_query = TextEdit(self, one_line=True)
        tmp = QtGui.QHBoxLayout(self.ui.widget_lineEdit_query)
        tmp.addWidget(self.ui.lineEdit_query)
        self.connect(self.ui.pushButton_query_exec, QtCore.SIGNAL("clicked()"), self.query_exec)
        self.connect(self.ui.lineEdit_query, QtCore.SIGNAL("returnPressed()"), self.ui.pushButton_query_exec.click)
        self.connect(self.ui.pushButton_query_reset, QtCore.SIGNAL("clicked()"), self.query_reset)
        self.connect(self._itemsTableView, QtCore.SIGNAL("doubleClicked(const QModelIndex&)"), self.__onTableDoubleClicked)

        #TODO limit page function sometimes works not correct!!! It sometimes shows less items, than specified in limit spinbox!
        #Initialization of limit and page spinboxes
        self.ui.spinBox_limit.setValue(int(UserConfig().get("spinBox_limit.value", 0)))
        self.ui.spinBox_limit.setSingleStep(int(UserConfig().get("spinBox_limit.step", 5)))
        self.connect(self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"), self.query_exec)
        self.connect(self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"), lambda: UserConfig().store("spinBox_limit.value", self.ui.spinBox_limit.value()))
        self.connect(self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"), lambda val: self.ui.spinBox_page.setEnabled(val > 0))
        self.connect(self.ui.spinBox_page, QtCore.SIGNAL("valueChanged(int)"), self.query_exec)
        self.ui.spinBox_page.setEnabled(self.ui.spinBox_limit.value() > 0)

        self._itemsTableView.setSortingEnabled(True)

        self.__table_model = None

        self.__context_menu = None
        self.__initContextMenu()


    def __getTableModel(self):
        return self.__table_model

    def __setTableModel(self, model):
        self.__table_model = model
        self._itemsTableView.setModel(model)
        if model is not None:
            self.connect(model, QtCore.SIGNAL("modelReset()"), self._itemsTableView.resizeRowsToContents)
            self.connect(model, QtCore.SIGNAL("dataChanged(const QModelIndex&, const QModelIndex&)"), self._resize_row_to_contents)

    itemsTableModel = property(fget=__getTableModel, fset=__setTableModel)


    def update(self):
        self.query_exec()


    def query_exec(self):
        try:
            if self.__table_model is None:
                raise errors.MsgException(self.tr("Items Table Widget has no Model."))

            query_text = self.query_text()
            limit = self.query_limit()
            page = self.query_page()

            self.__table_model.query(query_text, limit, page)

            self.resize_rows_to_contents()

            stats.sendEvent("items_table.query_exec")


        except Exception as ex:
            logger.warning(str(ex))
            helpers.show_exc_info(self, ex)


    def query_reset(self):
        if self.__table_model is not None:
            self.__table_model.query("")
        self.query_text_reset()
        self.emit(QtCore.SIGNAL("queryTextResetted"))
        stats.sendEvent("items_table.query_reset")


    def query_text(self):
        return self.ui.lineEdit_query.text()

    def query_text_reset(self):
        self.ui.lineEdit_query.setText("")

    def set_tag_completer(self, completer):
        self.ui.lineEdit_query.set_completer(completer)

    def query_limit(self):
        return self.ui.spinBox_limit.value()

    def query_page(self):
        return self.ui.spinBox_page.value()

    def selectedRows(self):
        #We use set, because selectedIndexes() may return duplicates
        rows = set()
        for index in self._itemsTableView.selectionModel().selectedIndexes():
            rows.add(index.row())
        return rows

    def selectedItemIds(self):
        #We use set, because selectedIndexes() may return duplicates
        item_ids = set()
        for index in self._itemsTableView.selectionModel().selectedIndexes():
            item_ids.add(self.__table_model.objAtRow(index.row()).id)
        return item_ids


    def itemAtRow(self, row):
        return self.__table_model.objAtRow(row)


    def rowCount(self):
        return self.__table_model.rowCount()

    def resetSingleRow(self, row):
        self.__table_model.resetRowRange(row, row)

    def resetRowRange(self, topRow, bottomRow):
        self.__table_model.resetRowRange(topRow, bottomRow)


    def selectedKeywordAll(self):
        self.ui.lineEdit_query.setText("ALL")
        self.query_exec()


    def selected_tags_changed(self, tags, not_tags):
        text = ""
        for tag in tags:
            text = text + tag + " "
        for tag in not_tags:
            text = text + query_tokens.NOT_OPERATOR + " " + tag + " "
        self.ui.lineEdit_query.setText(text)
        self.query_exec()


    def _resize_row_to_contents(self, top_left, bottom_right):
        if top_left.row() == bottom_right.row():
            self._itemsTableView.resizeRowToContents(top_left.row())

        elif top_left.row() < bottom_right.row():
            for row in range(top_left.row(), bottom_right.row()):
                self._itemsTableView.resizeRowToContents(row)

    def resize_rows_to_contents(self):
        self._itemsTableView.resizeRowsToContents()


    def restoreColumnsWidth(self):
        self._itemsTableView.restoreColumnsWidth("items_table")

    def restoreColumnsVisibility(self):
        self._itemsTableView.restoreColumnsVisibility("items_table")

    def saveColumnsWidth(self):
        self._itemsTableView.saveColumnsWidth("items_table")

    def saveColumnsVisibility(self):
        self._itemsTableView.saveColumnsVisibility("items_table")


    def buildActions(self):
        if len(self.actions) > 0:
            logger.info("Actions already built")
            return

        self.actions['addItems'] = self._createAction(self.tr("Add items"))

        self.actions['editItem'] = self._createAction(self.tr("Edit item"))
        self.actions['rebuildItemsThumbnail'] = self._createAction(self.tr("Rebuild item's thumbnail"))

        self.actions['deleteItem'] = self._createAction(self.tr("Delete item"))

        self.actions['openItem'] = self._createAction(self.tr("Open item"))
        self.actions['openItemWithBuiltinImageViewer'] = self._createAction(self.tr("Open item with built-in Image Viewer"))
        self.actions['createM3uAndOpenIt'] = self._createAction(self.tr("Create m3u playlist and open it"))
        self.actions['openItemWithExternalFileManager'] = self._createAction(self.tr("Open containing directory"))

        self.actions['exportItems'] = self._createAction(self.tr("Export items"))
        self.actions['exportItemsFiles'] = self._createAction(self.tr("Export items' files"))
        self.actions['exportItemsFilePaths'] = self._createAction(self.tr("Export items' file paths"))

        self.actions['checkItemsIntegrity'] = self._createAction(self.tr("Check Item integrity"))
        self.actions['fixFileNotFoundTryFind'] = self._createAction(self.tr("Try find file"))
        self.actions['fixFileNotFoundRemoveDataRef'] = self._createAction(self.tr("Remove Item's reference to file"))
        self.actions['fixHashMismatchTryFind'] = self._createAction(self.tr("Try find file"))
        self.actions['fixHashMismatchUpdateHash'] = self._createAction(self.tr("Update file hash"))

        self.actions['itemsTableSettings'] = self._createAction(self.tr("Settings"))


    def buildMainMenu(self):
        assert len(self.actions) > 0, "Actions should be already built"
        if self._mainMenu is not None:
            logger.info("Main Menu of this Tool already built")
            return

        self._mainMenu = self._createMenu(self.tr("Items Table"), self)
        menu = self._mainMenu

        menu.addAction(self.actions['addItems'])
        menu.addSeparator()
        menu.addAction(self.actions['editItem'])
        menu.addAction(self.actions['rebuildItemsThumbnail'])
        menu.addSeparator()
        menu.addAction(self.actions['deleteItem'])
        menu.addSeparator()
        menu.addAction(self.actions['openItem'])
        menu.addAction(self.actions['openItemWithBuiltinImageViewer'])
        menu.addAction(self.actions['createM3uAndOpenIt'])
        menu.addAction(self.actions['openItemWithExternalFileManager'])
        menu.addSeparator()
        subMenuExport = self._createAndAddSubMenu(self.tr("Export"), self, menu)
        subMenuExport.addAction(self.actions['exportItems'])
        subMenuExport.addAction(self.actions['exportItemsFiles'])
        subMenuExport.addAction(self.actions['exportItemsFilePaths'])
        menu.addSeparator()
        menu.addAction(self.actions['checkItemsIntegrity'])
        subMenuFixFileNotFoundError = self._createAndAddSubMenu(self.tr("Fix File Not Found Error"), self, menu)
        subMenuFixFileNotFoundError.addAction(self.actions['fixFileNotFoundTryFind'])
        subMenuFixFileNotFoundError.addAction(self.actions['fixFileNotFoundRemoveDataRef'])
        subMenuFixHashMismatchError = self._createAndAddSubMenu(self.tr("Fix File Hash Mismatch Error"), self, menu)
        subMenuFixHashMismatchError.addAction(self.actions['fixHashMismatchTryFind'])
        subMenuFixHashMismatchError.addAction(self.actions['fixHashMismatchUpdateHash'])
        menu.addSeparator()
        menu.addAction(self.actions['itemsTableSettings'])


    def __buildContextMenu(self):
        if self.__context_menu is not None:
            logger.info("Context menu of this Tool already built")
            return

        self.__context_menu = self._createMenu(menuTitle=None, menuParent=self)
        menu = self.__context_menu

        menu.addAction(self.actions['openItem'])
        menu.addAction(self.actions['openItemWithBuiltinImageViewer'])
        menu.addAction(self.actions['createM3uAndOpenIt'])
        menu.addAction(self.actions['openItemWithExternalFileManager'])
        menu.addSeparator()
        menu.addAction(self.actions['editItem'])
        menu.addAction(self.actions['rebuildItemsThumbnail'])
        menu.addSeparator()
        menu.addAction(self.actions['deleteItem'])
        menu.addSeparator()
        subMenuExport = self._createAndAddSubMenu(self.tr("Export"), self, menu)
        subMenuExport.addAction(self.actions['exportItems'])
        subMenuExport.addAction(self.actions['exportItemsFiles'])
        subMenuExport.addAction(self.actions['exportItemsFilePaths'])
        menu.addSeparator()
        menu.addAction(self.actions['checkItemsIntegrity'])
        subMenuFixFileNotFoundError = self._createAndAddSubMenu(self.tr("Fix File Not Found Error"), self, menu)
        subMenuFixFileNotFoundError.addAction(self.actions['fixFileNotFoundTryFind'])
        subMenuFixFileNotFoundError.addAction(self.actions['fixFileNotFoundRemoveDataRef'])
        subMenuFixHashMismatchError = self._createAndAddSubMenu(self.tr("Fix File Hash Mismatch Error"), self, menu)
        subMenuFixHashMismatchError.addAction(self.actions['fixHashMismatchTryFind'])
        subMenuFixHashMismatchError.addAction(self.actions['fixHashMismatchUpdateHash'])


    def __initContextMenu(self):
        self.buildActions()
        self.__buildContextMenu()
        self.__addContextMenu()

    def __addContextMenu(self):
        assert self.__context_menu is not None, "Context menu is not built"
        self._itemsTableView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.connect(self._itemsTableView, QtCore.SIGNAL("customContextMenuRequested(const QPoint &)"), self.showContextMenu)

    def showContextMenu(self, pos):
        self.__context_menu.exec_(self._itemsTableView.mapToGlobal(pos))



    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls:
            event.accept()
        else:
            event.ignore()


    def dropEvent(self, event):
        if not event.mimeData().hasUrls:
            event.ignore()
            return

        files = []
        for url in event.mimeData().urls():
            files.append(url.toLocalFile())

        if len(files) <= 0:
            event.ignore()
            return

        event.accept()
        self.__itemsTableTool.acceptDropOfFilesAndDirs(files)


    def __onTableDoubleClicked(self, index):
        if not self.__table_model.isOpenItemActionAllowed(index):
            return
        action = self.actions['openItem']
        action.trigger()
Пример #5
0
class ItemsTableGui(ToolGui):
    def __init__(self, parent, itemsTableTool):
        super(ItemsTableGui, self).__init__(parent)
        self.ui = Ui_ItemsTableGui()
        self.ui.setupUi(self)

        self._itemsTableView = UnivTableView(self)
        self.ui.tableViewContainer.addWidget(self._itemsTableView)

        self.__itemsTableTool = itemsTableTool

        #Widgets for text queries
        self.ui.lineEdit_query = TextEdit(self, one_line=True)
        tmp = QtGui.QHBoxLayout(self.ui.widget_lineEdit_query)
        tmp.addWidget(self.ui.lineEdit_query)
        self.connect(self.ui.pushButton_query_exec, QtCore.SIGNAL("clicked()"),
                     self.query_exec)
        self.connect(self.ui.lineEdit_query, QtCore.SIGNAL("returnPressed()"),
                     self.ui.pushButton_query_exec.click)
        self.connect(self.ui.pushButton_query_reset,
                     QtCore.SIGNAL("clicked()"), self.query_reset)
        self.connect(self._itemsTableView,
                     QtCore.SIGNAL("doubleClicked(const QModelIndex&)"),
                     self.__onTableDoubleClicked)

        #TODO limit page function sometimes works not correct!!! It sometimes shows less items, than specified in limit spinbox!
        #Initialization of limit and page spinboxes
        self.ui.spinBox_limit.setValue(
            int(UserConfig().get("spinBox_limit.value", 0)))
        self.ui.spinBox_limit.setSingleStep(
            int(UserConfig().get("spinBox_limit.step", 5)))
        self.connect(self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"),
                     self.query_exec)
        self.connect(
            self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"),
            lambda: UserConfig().store("spinBox_limit.value",
                                       self.ui.spinBox_limit.value()))
        self.connect(self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"),
                     lambda val: self.ui.spinBox_page.setEnabled(val > 0))
        self.connect(self.ui.spinBox_page, QtCore.SIGNAL("valueChanged(int)"),
                     self.query_exec)
        self.ui.spinBox_page.setEnabled(self.ui.spinBox_limit.value() > 0)

        self._itemsTableView.setSortingEnabled(True)

        self.__table_model = None

        self.__context_menu = None
        self.__initContextMenu()

    def __getTableModel(self):
        return self.__table_model

    def __setTableModel(self, model):
        self.__table_model = model
        self._itemsTableView.setModel(model)
        if model is not None:
            self.connect(model, QtCore.SIGNAL("modelReset()"),
                         self._itemsTableView.resizeRowsToContents)
            self.connect(
                model,
                QtCore.SIGNAL(
                    "dataChanged(const QModelIndex&, const QModelIndex&)"),
                self._resize_row_to_contents)

    itemsTableModel = property(fget=__getTableModel, fset=__setTableModel)

    def update(self):
        self.query_exec()

    def query_exec(self):
        try:
            if self.__table_model is None:
                raise errors.MsgException(
                    self.tr("Items Table Widget has no Model."))

            query_text = self.query_text()
            limit = self.query_limit()
            page = self.query_page()

            self.__table_model.query(query_text, limit, page)

            self.resize_rows_to_contents()

            stats.sendEvent("items_table.query_exec")

        except Exception as ex:
            logger.warning(str(ex))
            helpers.show_exc_info(self, ex)

    def query_reset(self):
        if self.__table_model is not None:
            self.__table_model.query("")
        self.query_text_reset()
        self.emit(QtCore.SIGNAL("queryTextResetted"))
        stats.sendEvent("items_table.query_reset")

    def query_text(self):
        return self.ui.lineEdit_query.text()

    def query_text_reset(self):
        self.ui.lineEdit_query.setText("")

    def set_tag_completer(self, completer):
        self.ui.lineEdit_query.set_completer(completer)

    def query_limit(self):
        return self.ui.spinBox_limit.value()

    def query_page(self):
        return self.ui.spinBox_page.value()

    def selectedRows(self):
        #We use set, because selectedIndexes() may return duplicates
        rows = set()
        for index in self._itemsTableView.selectionModel().selectedIndexes():
            rows.add(index.row())
        return rows

    def selectedItemIds(self):
        #We use set, because selectedIndexes() may return duplicates
        item_ids = set()
        for index in self._itemsTableView.selectionModel().selectedIndexes():
            item_ids.add(self.__table_model.objAtRow(index.row()).id)
        return item_ids

    def itemAtRow(self, row):
        return self.__table_model.objAtRow(row)

    def rowCount(self):
        return self.__table_model.rowCount()

    def resetSingleRow(self, row):
        self.__table_model.resetRowRange(row, row)

    def resetRowRange(self, topRow, bottomRow):
        self.__table_model.resetRowRange(topRow, bottomRow)

    def selectedKeywordAll(self):
        self.ui.lineEdit_query.setText("ALL")
        self.query_exec()

    def selected_tags_changed(self, tags, not_tags):
        text = ""
        for tag in tags:
            text = text + tag + " "
        for tag in not_tags:
            text = text + query_tokens.NOT_OPERATOR + " " + tag + " "
        self.ui.lineEdit_query.setText(text)
        self.query_exec()

    def _resize_row_to_contents(self, top_left, bottom_right):
        if top_left.row() == bottom_right.row():
            self._itemsTableView.resizeRowToContents(top_left.row())

        elif top_left.row() < bottom_right.row():
            for row in range(top_left.row(), bottom_right.row()):
                self._itemsTableView.resizeRowToContents(row)

    def resize_rows_to_contents(self):
        self._itemsTableView.resizeRowsToContents()

    def restoreColumnsWidth(self):
        self._itemsTableView.restoreColumnsWidth("items_table")

    def restoreColumnsVisibility(self):
        self._itemsTableView.restoreColumnsVisibility("items_table")

    def saveColumnsWidth(self):
        self._itemsTableView.saveColumnsWidth("items_table")

    def saveColumnsVisibility(self):
        self._itemsTableView.saveColumnsVisibility("items_table")

    def buildActions(self):
        if len(self.actions) > 0:
            logger.info("Actions already built")
            return

        self.actions['addItems'] = self._createAction(self.tr("Add items"))

        self.actions['editItem'] = self._createAction(self.tr("Edit item"))
        self.actions['rebuildItemsThumbnail'] = self._createAction(
            self.tr("Rebuild item's thumbnail"))

        self.actions['deleteItem'] = self._createAction(self.tr("Delete item"))

        self.actions['openItem'] = self._createAction(self.tr("Open item"))
        self.actions['openItemWithBuiltinImageViewer'] = self._createAction(
            self.tr("Open item with built-in Image Viewer"))
        self.actions['createM3uAndOpenIt'] = self._createAction(
            self.tr("Create m3u playlist and open it"))
        self.actions['openItemWithExternalFileManager'] = self._createAction(
            self.tr("Open containing directory"))

        self.actions['exportItems'] = self._createAction(
            self.tr("Export items"))
        self.actions['exportItemsFiles'] = self._createAction(
            self.tr("Export items' files"))
        self.actions['exportItemsFilePaths'] = self._createAction(
            self.tr("Export items' file paths"))

        self.actions['checkItemsIntegrity'] = self._createAction(
            self.tr("Check Item integrity"))
        self.actions['fixFileNotFoundTryFind'] = self._createAction(
            self.tr("Try find file"))
        self.actions['fixFileNotFoundRemoveDataRef'] = self._createAction(
            self.tr("Remove Item's reference to file"))
        self.actions['fixHashMismatchTryFind'] = self._createAction(
            self.tr("Try find file"))
        self.actions['fixHashMismatchUpdateHash'] = self._createAction(
            self.tr("Update file hash"))

        self.actions['itemsTableSettings'] = self._createAction(
            self.tr("Settings"))

    def buildMainMenu(self):
        assert len(self.actions) > 0, "Actions should be already built"
        if self._mainMenu is not None:
            logger.info("Main Menu of this Tool already built")
            return

        self._mainMenu = self._createMenu(self.tr("Items Table"), self)
        menu = self._mainMenu

        menu.addAction(self.actions['addItems'])
        menu.addSeparator()
        menu.addAction(self.actions['editItem'])
        menu.addAction(self.actions['rebuildItemsThumbnail'])
        menu.addSeparator()
        menu.addAction(self.actions['deleteItem'])
        menu.addSeparator()
        menu.addAction(self.actions['openItem'])
        menu.addAction(self.actions['openItemWithBuiltinImageViewer'])
        menu.addAction(self.actions['createM3uAndOpenIt'])
        menu.addAction(self.actions['openItemWithExternalFileManager'])
        menu.addSeparator()
        subMenuExport = self._createAndAddSubMenu(self.tr("Export"), self,
                                                  menu)
        subMenuExport.addAction(self.actions['exportItems'])
        subMenuExport.addAction(self.actions['exportItemsFiles'])
        subMenuExport.addAction(self.actions['exportItemsFilePaths'])
        menu.addSeparator()
        menu.addAction(self.actions['checkItemsIntegrity'])
        subMenuFixFileNotFoundError = self._createAndAddSubMenu(
            self.tr("Fix File Not Found Error"), self, menu)
        subMenuFixFileNotFoundError.addAction(
            self.actions['fixFileNotFoundTryFind'])
        subMenuFixFileNotFoundError.addAction(
            self.actions['fixFileNotFoundRemoveDataRef'])
        subMenuFixHashMismatchError = self._createAndAddSubMenu(
            self.tr("Fix File Hash Mismatch Error"), self, menu)
        subMenuFixHashMismatchError.addAction(
            self.actions['fixHashMismatchTryFind'])
        subMenuFixHashMismatchError.addAction(
            self.actions['fixHashMismatchUpdateHash'])
        menu.addSeparator()
        menu.addAction(self.actions['itemsTableSettings'])

    def __buildContextMenu(self):
        if self.__context_menu is not None:
            logger.info("Context menu of this Tool already built")
            return

        self.__context_menu = self._createMenu(menuTitle=None, menuParent=self)
        menu = self.__context_menu

        menu.addAction(self.actions['openItem'])
        menu.addAction(self.actions['openItemWithBuiltinImageViewer'])
        menu.addAction(self.actions['createM3uAndOpenIt'])
        menu.addAction(self.actions['openItemWithExternalFileManager'])
        menu.addSeparator()
        menu.addAction(self.actions['editItem'])
        menu.addAction(self.actions['rebuildItemsThumbnail'])
        menu.addSeparator()
        menu.addAction(self.actions['deleteItem'])
        menu.addSeparator()
        subMenuExport = self._createAndAddSubMenu(self.tr("Export"), self,
                                                  menu)
        subMenuExport.addAction(self.actions['exportItems'])
        subMenuExport.addAction(self.actions['exportItemsFiles'])
        subMenuExport.addAction(self.actions['exportItemsFilePaths'])
        menu.addSeparator()
        menu.addAction(self.actions['checkItemsIntegrity'])
        subMenuFixFileNotFoundError = self._createAndAddSubMenu(
            self.tr("Fix File Not Found Error"), self, menu)
        subMenuFixFileNotFoundError.addAction(
            self.actions['fixFileNotFoundTryFind'])
        subMenuFixFileNotFoundError.addAction(
            self.actions['fixFileNotFoundRemoveDataRef'])
        subMenuFixHashMismatchError = self._createAndAddSubMenu(
            self.tr("Fix File Hash Mismatch Error"), self, menu)
        subMenuFixHashMismatchError.addAction(
            self.actions['fixHashMismatchTryFind'])
        subMenuFixHashMismatchError.addAction(
            self.actions['fixHashMismatchUpdateHash'])

    def __initContextMenu(self):
        self.buildActions()
        self.__buildContextMenu()
        self.__addContextMenu()

    def __addContextMenu(self):
        assert self.__context_menu is not None, "Context menu is not built"
        self._itemsTableView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.connect(
            self._itemsTableView,
            QtCore.SIGNAL("customContextMenuRequested(const QPoint &)"),
            self.showContextMenu)

    def showContextMenu(self, pos):
        self.__context_menu.exec_(self._itemsTableView.mapToGlobal(pos))

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls:
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        if not event.mimeData().hasUrls:
            event.ignore()
            return

        files = []
        for url in event.mimeData().urls():
            files.append(url.toLocalFile())

        if len(files) <= 0:
            event.ignore()
            return

        event.accept()
        self.__itemsTableTool.acceptDropOfFilesAndDirs(files)

    def __onTableDoubleClicked(self, index):
        if not self.__table_model.isOpenItemActionAllowed(index):
            return
        action = self.actions['openItem']
        action.trigger()