Esempio n. 1
0
class Main(QtGui.QMainWindow):

    # Initialize mainwindow
    def __init__(self):

        # Declare class variables
        self.encodings = [
            ["Default", None],
            ["ASCII", "ascii"],
            ["ISO-8859-1", "latin_1"],
            ["ISO-8859-2", "iso8859_2"],
            ["ISO-8859-3", "iso8859_3"],
            ["ISO-8859-4", "iso8859_4"],
            ["ISO-8859-5", "iso8859_5"],
            ["ISO-8859-6", "iso8859_6"],
            ["ISO-8859-7", "iso8859_7"],
            ["ISO-8859-8", "iso8859_8"],
            ["ISO-8859-9", "iso8859_9"],
            ["ISO-8859-10", "iso8859_10"],
            ["ISO-8859-13", "iso8859_13"],
            ["ISO-8859-14", "iso8859_14"],
            ["ISO-8859-15", "iso8859_15"],
            ["KOI8-R", "koi8_r"],
            ["KOI8-U", "koi8_u"],
            ["UTF-8 with BOM", "utf_8_sig"],
            ["UTF-8 without BOM", "utf_8"],
            ["UTF-16BE", "utf_16_be"],
            ["UTF-16LE", "utf_16_le"],
            ["UTF-32BE", "utf_32_be"],
            ["UTF-32LE", "utf_32_le"],
            ["Windows-1250", "cp1250"],
            ["Windows-1251", "cp1251"],
            ["Windows-1252", "cp1252"],
            ["Windows-1253", "cp1253"],
            ["Windows-1254", "cp1254"],
            ["Windows-1255", "cp1255"],
            ["Windows-1256", "cp1256"],
            ["Windows-1257", "cp1257"],
            ["Windows-1258", "cp1258"]
        ]
        self.path = "" # Path for fix
        self.filelist = [] # File list for fix
        self.filetypes = ["srt", "txt"] # Accepted file types
        self.typefilter = "All supported files (*.srt *.txt)"
        self.typefilter += ";;SubRip subtitle file (*.srt)"
        self.typefilter += ";;Text file (*.txt)"

        # Create class instances
        self.data = DataHandler()
        self.file = FileHandler(self.filetypes)
        self.string = StringHandler()

        # Initialize top level window widget
        QtGui.QMainWindow.__init__(self)

        # This is always the same
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # Connect signals, menu and toolbar
        self.ui.actionNewDatabase.triggered.connect(self.newDatabase)
        self.ui.actionOpenDatabase.triggered.connect(self.openDatabaseMsgBox)
        self.ui.actionAddFiles.triggered.connect(self.fAddFiles)
        self.ui.actionAddFolder.triggered.connect(self.fAddFolder)
        self.ui.actionRemoveFiles.triggered.connect(self.fRemoveFiles)
        self.ui.actionClearList.triggered.connect(self.fClearList)
        self.ui.actionStart.triggered.connect(self.fStart)
        self.ui.actionQuit.triggered.connect(self.quitApplication)
        self.ui.actionAbout.triggered.connect(self.aboutMessage)

        # Connect signals, buttons
        self.ui.btnFStart.clicked.connect(self.fStart)
        self.ui.btnFAddFiles.clicked.connect(self.fAddFiles)
        self.ui.btnFAddFolder.clicked.connect(self.fAddFolder)
        self.ui.btnFRemoveFiles.clicked.connect(self.fRemoveFiles)
        self.ui.btnFClearList.clicked.connect(self.fClearList)
        self.ui.btnLDeleteRow.clicked.connect(self.lDeleteRow)
        self.ui.btnLInsertRow.clicked.connect(self.lInsertRow)
        self.ui.btnLUpdateRow.clicked.connect(self.lUpdateRow)
        self.ui.txtCSearch.returnPressed.connect(self.refreshCCorrections)
        self.ui.btnCDeleteRow.clicked.connect(self.cDeleteRow)
        self.ui.btnCInsertRow.clicked.connect(self.cInsertRow)
        self.ui.btnCUpdateRow.clicked.connect(self.cUpdateRow)
        self.ui.btnLClearLog.clicked.connect(self.lClearLog)

        # Connect signals, comboboxes
        self.ui.cboCCorrectionMode.activated.connect(self.refreshCCorrections)
        self.ui.cboCList.activated.connect(self.refreshCCorrections)

        # Connect signals, tables
        self.ui.tblCCorrections.currentCellChanged[(int,int,int,int)].connect(\
            self.selectCorrection)

        # Drag-and-drop events for file list
        self.ui.tblFFileList.dragEnterEvent = self.dragEnterEvent
        self.ui.tblFFileList.dragMoveEvent = self.dragEnterEvent
        self.ui.tblFFileList.dropEvent = self.dropEvent

        # Loop and set encodings to settings combobox
        for item in self.encodings:
            self.ui.cboSFileEncoding.addItem(item[0])

        # Select the first tab from the tab widgets
        self.ui.tabMain.setCurrentIndex(0)

        # Icons
        self.setWindowIcon(QtGui.QIcon("icon.png"))

        self.ui.actionNewDatabase.setIcon(QtGui.QIcon("new_database.png"))
        self.ui.actionOpenDatabase.setIcon(QtGui.QIcon("open_database.png"))
        self.ui.actionAddFiles.setIcon(QtGui.QIcon("add_files.png"))
        self.ui.actionAddFolder.setIcon(QtGui.QIcon("add_folder.png"))
        self.ui.actionRemoveFiles.setIcon(QtGui.QIcon("remove.png"))
        self.ui.actionClearList.setIcon(QtGui.QIcon("clear.png"))
        self.ui.actionStart.setIcon(QtGui.QIcon("start.png"))
        self.ui.actionQuit.setIcon(QtGui.QIcon("quit.png"))
        self.ui.actionAbout.setIcon(QtGui.QIcon("about.png"))

        self.ui.tabMain.setTabIcon(0, QtGui.QIcon("fix.png"))
        self.ui.tabMain.setTabIcon(1, QtGui.QIcon("lists.png"))
        self.ui.tabMain.setTabIcon(2, QtGui.QIcon("corrections.png"))
        self.ui.tabMain.setTabIcon(3, QtGui.QIcon("log.png"))
        self.ui.tabMain.setTabIcon(4, QtGui.QIcon("settings.png"))

        self.ui.btnFAddFiles.setIcon(QtGui.QIcon("add_files.png"))
        self.ui.btnFAddFolder.setIcon(QtGui.QIcon("add_folder.png"))
        self.ui.btnFRemoveFiles.setIcon(QtGui.QIcon("remove.png"))
        self.ui.btnFClearList.setIcon(QtGui.QIcon("clear.png"))
        self.ui.btnFStart.setIcon(QtGui.QIcon("start.png"))

        self.ui.btnLDeleteRow.setIcon(QtGui.QIcon("delete_row.png"))
        self.ui.btnLInsertRow.setIcon(QtGui.QIcon("insert_row.png"))
        self.ui.btnLUpdateRow.setIcon(QtGui.QIcon("update_row.png"))
        self.ui.btnCDeleteRow.setIcon(QtGui.QIcon("delete_row.png"))
        self.ui.btnCInsertRow.setIcon(QtGui.QIcon("insert_row.png"))
        self.ui.btnCUpdateRow.setIcon(QtGui.QIcon("update_row.png"))

        self.ui.btnLClearLog.setIcon(QtGui.QIcon("clear.png"))

        # Check if command line arguments has files in it
        if sys.argv[1:]:
            self.loopItems(sys.argv[1:])

        # Load settings
        self.loadSettings()


    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #+ Settings
    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    def loadSettings(self):
        try:
            settings = QtCore.QSettings("bulkware", "bwReplacer")
            if settings.contains("geometry"): # Window geometry
                self.restoreGeometry(settings.value("geometry"))
            if settings.contains("state"): # Window state
                self.restoreState(settings.value("state"))
            if settings.contains("database"): # Database
                dbpath = str(settings.value("database", type=str))
                self.openDatabase(dbpath)
            if settings.contains("logfiles"): # Log files
                logfiles = settings.value("logfiles", type=bool)
                self.ui.chkLLogFiles.setChecked(logfiles)
            if settings.contains("logfixes"): # Log fixes
                logfixes = settings.value("logfixes", type=bool)
                self.ui.chkLLogFixes.setChecked(logfixes)
            if settings.contains("encoding"): # Encoding
                encindex = settings.value("encoding", type=int)
                self.ui.cboSFileEncoding.setCurrentIndex(encindex)
            if settings.contains("path"): # Fix, path
                self.path = settings.value("path", type=str)
        except:
            self.path = ""
            return False
        else:
            return True


    # Save settings when closing the application
    def closeEvent(self, event):
        settings = QtCore.QSettings("bulkware", "bwReplacer")
        settings.setValue("geometry", self.saveGeometry())
        settings.setValue("state", self.saveState())
        settings.setValue("database", str(self.data.database))
        settings.setValue("logfiles", self.ui.chkLLogFiles.isChecked())
        settings.setValue("logfixes", self.ui.chkLLogFixes.isChecked())
        settings.setValue("encoding", \
            int(self.ui.cboSFileEncoding.currentIndex()))
        settings.setValue("path", str(self.path))


    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #+ Actions
    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    # New database
    def newDatabase(self):

        # Dialog for database name
        name, ok = QtGui.QInputDialog.getText(self, "New database", 
            "Enter name for database:")

        if not ok:
            return

        if name == "":
            msg = "Database name cannot be empty."
            self.ui.statusBar.showMessage(msg)
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        try:
            self.data.create_database(name)
            self.refreshLists()
            self.refreshLLists()
            self.refreshCCorrections()
        except:
            msg = "Unable to create database."
            self.ui.statusBar.showMessage(msg)
            QtGui.QMessageBox.critical(self, "Error", msg)
            return False
        else:
            msg = "Database created: " + self.data.database
            self.ui.statusBar.showMessage(msg)

        # Enable/disable widgets
        self.enabledisableWidgets()


    # Menu > File > Open database... (using message box)
    def openDatabaseMsgBox(self):

        # Get the database file using a dialog
        fp = QtGui.QFileDialog.getOpenFileName(self, "Open database",
            os.path.dirname(sys.argv[0]), "SQLite databases (*.db)")

        # If the filename was not provided
        if fp == "":
            return

        self.openDatabase(fp)


    # Open database
    def openDatabase(self, fp):

        # Try to open database
        if not self.data.open(fp):
            self.ui.statusBar.showMessage(self.data.error)
            QtGui.QMessageBox.critical(self, "Error", self.data.error)
            return

        # Refresh main window widgets
        self.refreshLists()
        self.refreshCCorrections()
        self.refreshLLists()

        # Enable/disable widgets
        self.enabledisableWidgets()

        # Show success msg
        msg = "Successfully opened database: " + fp
        self.ui.statusBar.showMessage(msg)
        self.logMessage(msg)


    # Menu > File > Quit
    def quitApplication(self):
        QtGui.QApplication.quit()


    # Menu > Help > About...
    def aboutMessage(self):
        msg = """<strong>bwReplacer</strong><br />
        Version 1.3.0<br />
        <br />
        This is free software.<br />
        Released under the General Public License.<br />
        <br />
        <a href="https://github.com/bulkware/bwreplacer">GitHub</a>"""
        QtGui.QMessageBox.about(self, "About", msg)


    # Add files
    def fAddFiles(self):

        # Get file list using a dialog
        items = QtGui.QFileDialog.getOpenFileNames(self, "Add files",
            self.path)

        # Check list for items
        if len(items) < 1:
            return

        # Loop items to main file list
        self.loopItems(items)


    # Add folder
    def fAddFolder(self):

        # Get folder using a dialog
        path = QtGui.QFileDialog.getExistingDirectory(self, "Add folder",
            self.path)

        # Check path
        if path == "":
            return

        # Check dir
        if not os.path.isdir(path):
            return

        # Create a list with full paths
        items = []
        for item in os.listdir(path):
            items.append(os.path.join(path, item))

        # Loop items to main file list
        self.loopItems(items)


    # Fix, loop items to main file list
    def loopItems(self, items):

        nonexist = 0
        duplicates = 0
        folders = 0
        unallowed = 0
        for item in items:

            # Check if item does not exist
            if not os.path.exists(item):
                nonexist += 1
                continue

            # Check for duplicates
            if item in self.filelist:
                duplicates += 1
                continue

            # Check for folders
            if os.path.isdir(item):
                folders += 1
                continue

            # Check for extension
            ext = os.path.splitext(item)[1][1:].lower()
            if ext not in self.filetypes:
                unallowed += 1
                continue

            # Check if file path is an existing regular file
            if not os.path.isfile(item):
                continue

            # Set the path from first file
            if item == items[0]:
                self.path = os.path.split(item)[0]

            # Add file
            self.filelist.append(item)

        # Check for files and sort them
        if len(self.filelist) > 0:
            self.filelist.sort()

        # Enable/disable widgets
        self.enabledisableWidgets()

        # Refresh file list table
        self.refreshFileList()

        # Count total adds and message user, if necessary
        total = nonexist
        total += duplicates
        total += folders
        total += unallowed
        if total > 0:
            msg = "%s items were skipped:\n" % (total)
            msg += "\n"
            msg += "%s doesn't exist\n" % (nonexist)
            msg += "%s duplicates\n" % (duplicates)
            msg += "%s folders\n" % (folders)
            msg += "%s unallowed extensions\n" % (unallowed)
            QtGui.QMessageBox.information(self, "Info", msg)


    # Fix, clear list
    def fClearList(self):
        self.filelist[:] = []
        self.enabledisableWidgets()
        self.refreshFileList()


    # Fix, remove files
    def fRemoveFiles(self):

        # Check if file list is empty
        if len(self.filelist) < 1:
            msg = "No files in list."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Check table's selected items
        if not self.ui.tblFFileList.selectedIndexes():
            msg = "Please select file."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Get indexes from table
        rows = []
        for item in self.ui.tblFFileList.selectedIndexes():
            index = int(item.row())
            if index not in rows:
                rows.append(index)

        # Remove items in reverse order (so the indexes won't change)
        for index in sorted(rows, reverse=True):
            del self.filelist[index]

        # Check file list for files
        if len(self.filelist) < 1:
            self.enabledisableWidgets()

        # Refresh table
        self.refreshFileList()


    # Fix, start
    def fStart(self):

        # Check for database
        if not self.data.database:
            msg = "Database connection not established."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Create a list of selected lists
        lists = []
        for sel in range(self.ui.lstFLists.count()):
            if self.ui.lstFLists.item(sel).checkState():
                lists.append(self.data.get_list(index=sel)[0])

        # Check for lists
        if not lists:
            msg = "No lists defined."
            self.ui.statusBar.showMessage(msg)
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Get corrections
        corrections = self.data.get_corrections([1,2,3], lists)

        # Check for corrections
        if not corrections:
            msg = "No corrections to apply."
            self.ui.statusBar.showMessage(msg)
            QtGui.QMessageBox.critical(self, "Error", msg)
            return False

        # Enable/disable widgets
        self.enabledisableWidgets(disable=True)

        # Select the log tab
        self.ui.tabMain.setCurrentIndex(3)

        # Loop file list
        self.string.reset()
        for file in self.filelist:
            if self.ui.chkLLogFiles.isChecked():
                msg = "Processing file: " + os.path.basename(file)
                self.logMessage(msg)
            ok, msg = self.fixFile(file, corrections)
            if ok:
                self.ui.statusBar.showMessage(msg)
            else:
                self.ui.statusBar.showMessage(msg)
                QtGui.QMessageBox.critical(self, "Error", msg)
                break
            if self.ui.chkLLogFiles.isChecked():
                msg = "File processed successfully: " + os.path.basename(file)
                self.logMessage(msg)

        # Show statistics if processing went ok
        if ok:
            msg = "Processing finished. %s corrections were applied." % \
                (self.string.count)
            self.ui.statusBar.showMessage(msg)
            self.logMessage(msg)

        # Enable/disable widgets
        self.enabledisableWidgets()


    # Fix file
    def fixFile(self, file, corrections):

        # Get the file encoding setting
        enc = self.encodings[self.ui.cboSFileEncoding.currentIndex()][1]

        # Open file
        if not self.file.open(file, enc):
            return False, self.file.error

        i = 1
        lines = self.file.count()

        # Loop file's editable data
        for key, line in sorted(self.file.get_editdata().items()):

            oldline = line

            # Loop corrections
            for item in corrections:
                ok, line = self.string.replace(line, int(item[1]), \
                    str(item[4]), str(item[5]), int(item[3]))

                if not ok:
                    return False, self.string.error

            # If line has changed...
            if line != oldline:

                # Set corrected line back to file
                self.file.set_line(key, line)

                # Log fix
                if self.ui.chkLLogFixes.isChecked():
                    msg = "Fixed row " + str(key) + ", " + oldline + " --> " + \
                        line
                    self.logMessage(msg)

            # Update statusBar info
            msg = "Processing file: %s (line %s/%s)" \
                % (os.path.basename(file), key, lines)
            self.ui.statusBar.showMessage(msg)

            # Update app
            QtGui.QApplication.processEvents()

            i += 1

        # Check for empty lines at EOF removal option
        if self.ui.chkSRemoveEmpty.isChecked():
            emptylines = True
        else:
            emptylines = False

        # Save file
        if not self.file.save(enc, emptylines):
            return False, self.file.error

        # Close file
        self.file.close()

        # All went well
        return True, "File processed successfully: " + file


    # Clear log
    def lClearLog(self):
        self.ui.lstLLog.clear()


    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #+ Events
    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    # Drag
    def dragEnterEvent(self, event):
        if (event.type() == QtCore.QEvent.DragEnter):
            if event.mimeData().hasUrls():
                event.accept()
            else:
                event.ignore()

    # Drop
    def dropEvent(self, event):
        if (event.type() == QtCore.QEvent.Drop):
            if event.mimeData().hasUrls():

                # Make a list of items from drag-and-drop
                items = []
                for i in event.mimeData().urls():
                    items.append(i.toLocalFile())

                # Loop items to main file list
                self.loopItems(items)


    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #+ Widgets
    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    # Fix, refresh file list table
    def refreshFileList(self):

        # Clear widgets
        self.ui.tblFFileList.setColumnCount(0)
        self.ui.tblFFileList.setRowCount(0)
        self.ui.tblFFileList.clear()

        # Check if file list is empty
        if len(self.filelist) < 1:
            return False

        # Set columns and rows
        self.ui.tblFFileList.setColumnCount(3)
        self.ui.tblFFileList.setRowCount(len(self.filelist))

        # Set header labels
        self.ui.tblFFileList.setHorizontalHeaderLabels(["File", "Size", ""])

        # Populate table
        for i, file in enumerate(self.filelist):

            item = QtGui.QTableWidgetItem(os.path.basename(file))
            item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
            item.setTextAlignment(QtCore.Qt.AlignVCenter | QtCore.Qt.AlignLeft)
            self.ui.tblFFileList.setItem(i, 0, item)

            size = functions.convert_bytes(os.path.getsize(file))
            item = QtGui.QTableWidgetItem(size)
            item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
            item.setTextAlignment(QtCore.Qt.AlignVCenter | QtCore.Qt.AlignRight)
            self.ui.tblFFileList.setItem(i, 1, item)

            item = QtGui.QTableWidgetItem()
            item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
            self.ui.tblFFileList.setItem(i, 2, item)

        # Resize columns to contents
        # setVisible lines are because of QTBUG-9352!
        self.ui.tblFFileList.setVisible(False)
        self.ui.tblFFileList.resizeColumnsToContents()
        self.ui.tblFFileList.setVisible(True)


    # Refresh widgets with lists
    def refreshLists(self):

        # Check for database
        if not self.data.database:
            return

        # Clear widgets
        self.ui.cboCList.clear()
        self.ui.lstFLists.clear()

        # Get lists
        lists = self.data.get_lists()

        # Check for lists
        if not lists:
            return

        # Set lists to widgets
        self.ui.cboCList.addItem("All")
        for list in lists:

            # Corrections
            self.ui.cboCList.addItem(list[2])

            # Batch fix, list
            item = QtGui.QListWidgetItem(list[2])
            item.setFlags(QtCore.Qt.ItemIsEnabled | 
                QtCore.Qt.ItemIsUserCheckable)
            if list[1] == 1:
                item.setCheckState(QtCore.Qt.Checked)
            else:
                item.setCheckState(QtCore.Qt.Unchecked)
            self.ui.lstFLists.addItem(item)


    # Refresh lists table
    def refreshLLists(self):

        # Check for database
        if not self.data.database:
            return

        # Clear lists table
        self.ui.tblLLists.setColumnCount(0)
        self.ui.tblLLists.setRowCount(0)
        self.ui.tblLLists.clear()

        # Get lists
        rows = self.data.get_lists()

        # Check for lists
        if not rows:
            return

        # Set columns and rows for table
        self.ui.tblLLists.setColumnCount(4)
        self.ui.tblLLists.setRowCount(len(rows))

        # Set header labels for table
        self.ui.tblLLists.setHorizontalHeaderLabels(["ID", "Selected", "Name", \
            "Comment"])

        # Populate table
        for i, row in enumerate(rows):
            for column in range(4):

                # Column 1 is the selected column
                if column == 1:
                    item = QtGui.QCheckBox("Y/n")
                    if row[column]:
                        item.setCheckState(QtCore.Qt.Checked)
                    else:
                        item.setCheckState(QtCore.Qt.Unchecked)
                    self.ui.tblLLists.setCellWidget(i, column, item)
                else:
                    text = str(row[column])
                    item = QtGui.QTableWidgetItem(text)

                    # ID column can't have any item flags
                    if column == 0:
                        item.setFlags(QtCore.Qt.NoItemFlags)

                    self.ui.tblLLists.setItem(i, column, item)

        # Set horizontal header visibility to true (QT BUG?)
        self.ui.tblLLists.horizontalHeader().setVisible(True)

        # Resize table columns to contents
        # setVisible lines are because of QTBUG-9352!
        self.ui.tblLLists.setVisible(False)
        self.ui.tblLLists.resizeColumnsToContents()
        self.ui.tblLLists.setVisible(True)


    # Delete list
    def lDeleteRow(self):

        # Check for database
        if not self.data.database:
            msg = "Database connection not established."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Check table's selected items
        if not self.ui.tblLLists.selectedIndexes():
            msg = "Please select item from table."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Get selected row
        row = int(self.ui.tblLLists.currentRow())

        # Get id
        id = int(self.ui.tblLLists.item(row, 0).text())

        # Delete list
        ok = self.data.delete(id, "lists")
        if ok:
            msg = "List deleted."
            self.ui.statusBar.showMessage(msg)
        else:
            self.ui.statusBar.showMessage(self.data.error)
            QtGui.QMessageBox.critical(self, "Error", self.data.error)
            return

        # Remove row from table
        self.ui.tblLLists.removeRow(row)

        # Refresh lists
        self.refreshLists()
        self.refreshLLists()

        # Refresh the corrections table
        self.refreshCCorrections()


    # Insert list
    def lInsertRow(self):

        # Check for database
        if not self.data.database:
            msg = "Database connection not established."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Insert list
        ok = self.data.insert("lists", [0, "", ""])
        if ok:
            msg = "List inserted."
            self.ui.statusBar.showMessage(msg)
        else:
            self.ui.statusBar.showMessage(self.data.error)
            QtGui.QMessageBox.critical(self, "Error", self.data.error)
            return

        # Refresh the lists table
        self.refreshLLists()

        # Get the last row from table and insert new row
        lastrow = self.ui.tblLLists.rowCount() - 1

        # Select the name cell from the last row, which was inserted
        self.ui.tblLLists.setCurrentCell(lastrow, 3)
        self.ui.tblLLists.scrollToItem(
            self.ui.tblLLists.item(lastrow, 3),
            QtGui.QAbstractItemView.EnsureVisible)
        self.ui.tblLLists.setFocus()


    # Update list
    def lUpdateRow(self):

        # Check for database
        if not self.data.database:
            msg = "Database connection not established."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Check table's selected items
        if not self.ui.tblLLists.selectedIndexes():
            msg = "Please select item from table."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Get selected row
        row = int(self.ui.tblLLists.currentRow())

        # Get values
        id = int(self.ui.tblLLists.item(row, 0).text())
        selected = int(self.ui.tblLLists.cellWidget(row, 1).checkState())
        if selected > 1: selected = 1 # Tristate checkbox into 1
        name = str(self.ui.tblLLists.item(row, 2).text())
        comment = str(self.ui.tblLLists.item(row, 3).text())

        # Check if name is empty
        if name == "":
            msg = "Name cannot be the empty."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Update list
        ok = self.data.update("lists", [id, selected, name, comment])
        if ok:
            msg = "List updated."
            self.ui.statusBar.showMessage(msg)
        else:
            self.ui.statusBar.showMessage(self.data.error)
            QtGui.QMessageBox.critical(self, "Error", self.data.error)

        # Refresh lists
        self.refreshLists()
        self.refreshLLists()


    # Refresh corrections table
    def refreshCCorrections(self):

        # Clear corrections table
        self.ui.tblCCorrections.setColumnCount(0)
        self.ui.tblCCorrections.setRowCount(0)
        self.ui.tblCCorrections.clear()

        # Check for database
        if not self.data.database:
            return

        # Get lists
        lists = self.data.get_lists()

        # Check for lists
        if not lists:
            return

        # Mode
        modeindex = int(self.ui.cboCCorrectionMode.currentIndex())
        modeid = []
        if modeindex > 0:
            modeid = [modeindex]

        # List
        listindex = int(self.ui.cboCList.currentIndex())
        listid = []
        if listindex > 0:
            listindex -= 1 # "All" option adds one
            listdata = self.data.get_list(index=listindex)
            listid = [int(listdata[0])]

        # Search
        search = str(self.ui.txtCSearch.text())

        # Get corrections
        rows = self.data.get_corrections(modeid, listid, search)

        # Check for corrections
        if not rows:
            return

        # Set columns and rows for table
        self.ui.tblCCorrections.setColumnCount(7)
        self.ui.tblCCorrections.setRowCount(len(rows))

        # Set header labels for table
        self.ui.tblCCorrections.setHorizontalHeaderLabels(["ID", "Mode", \
            "List", "Variations", "Error", "Correction", "Comment"])

        # Populate corrections table
        for i, row in enumerate(rows):
            for column in range(7):

                if column == 0: # ID
                    text = str(row[0])
                    item = QtGui.QTableWidgetItem(text)
                    item.setFlags(QtCore.Qt.NoItemFlags)
                elif column == 1: # Mode
                    modeid = int(row[1])
                    modetext = str(self.data.correctionmodes[modeid])
                    item = QtGui.QTableWidgetItem(modetext)
                elif column == 2: # List
                    listid = int(row[2])
                    listtext = str(self.data.get_list(id=listid)[2])
                    item = QtGui.QTableWidgetItem(listtext)
                elif column == 3: # Variations
                    if row[column]:
                        text = "Yes"
                    else:
                        text = "No"
                    item = QtGui.QTableWidgetItem(text)
                else:
                    text = str(row[column])
                    item = QtGui.QTableWidgetItem(text)

                self.ui.tblCCorrections.setItem(i, column, item)

        # Set horizontal header visibility to true (QT BUG?)
        self.ui.tblCCorrections.horizontalHeader().setVisible(True)

        # Resize table columns to contents
        # setVisible lines are because of QTBUG-9352!
        self.ui.tblCCorrections.setVisible(False)
        self.ui.tblCCorrections.resizeColumnsToContents()
        self.ui.tblCCorrections.setVisible(True)


    # Select correction
    def selectCorrection(self, row, col, row2, col2):

        # Check if row is selected or row is not row2
        if row < 0 or row == row2:
            return

        # Get lists
        lists = self.data.get_lists()

        # Check for lists
        if not lists:
            return

        # Get ID and row data
        id = int(self.ui.tblCCorrections.item(row, 0).text())
        rowdata = self.data.get_correction(id)

        # Mode
        item = QtGui.QComboBox()
        item.addItems(self.data.correctionmodes[1:])
        item.setCurrentIndex(rowdata[1] - 1)
        self.ui.tblCCorrections.setCellWidget(row, 1, item)

        # List
        item = QtGui.QComboBox()
        for i, list in enumerate(lists):
            item.addItem(list[2])
            if list[0] == rowdata[2]:
                selectedlist = i
        item.setCurrentIndex(selectedlist)
        self.ui.tblCCorrections.setCellWidget(row, 2, item)

        # Variations
        self.ui.tblCCorrections.setItem(row, 3, QtGui.QTableWidgetItem())
        item = QtGui.QCheckBox("Y/n")
        if int(rowdata[3]):
            item.setCheckState(QtCore.Qt.Checked)
        else:
            item.setCheckState(QtCore.Qt.Unchecked) 
        self.ui.tblCCorrections.setCellWidget(row, 3, item)

        # Reset old row
        if row != row2 and row2 > -1:

            # Get ID and row data
            id = int(self.ui.tblCCorrections.item(row2, 0).text())
            rowdata = self.data.get_correction(id)

            # If there is no row data, the row was deleted
            if not rowdata:
                return

            # Mode
            modeid = int(rowdata[1])
            modetext = str(self.data.correctionmodes[modeid])
            self.ui.tblCCorrections.removeCellWidget(row2, 1)
            self.ui.tblCCorrections.setItem(row2, 1,
                QtGui.QTableWidgetItem(modetext))

            # List
            listid = int(rowdata[2])
            listtext = str(self.data.get_list(id=listid)[2])
            self.ui.tblCCorrections.removeCellWidget(row2, 2)
            self.ui.tblCCorrections.setItem(row2, 2,
                QtGui.QTableWidgetItem(listtext))

            # Variations
            self.ui.tblCCorrections.removeCellWidget(row2, 3)
            if int(rowdata[3]):
                text = "Yes"
            else:
                text = "No"
            item = QtGui.QTableWidgetItem(text)
            self.ui.tblCCorrections.setItem(row2, 3, item)


    # Delete correction
    def cDeleteRow(self):

        # Check for database
        if not self.data.database:
            msg = "Database connection not established."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Check table's selected items
        if not self.ui.tblCCorrections.selectedIndexes():
            msg = "Please select item from table."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Get selected row
        row = int(self.ui.tblCCorrections.currentRow())

        # Get ID
        id = int(self.ui.tblCCorrections.item(row, 0).text())

        # Delete correction
        ok = self.data.delete(id, "corrections")
        if ok:
            msg = "Correction deleted, ID: %s" % (id)
            self.ui.statusBar.showMessage(msg)
        else:
            self.ui.statusBar.showMessage(self.data.error)
            QtGui.QMessageBox.critical(self, "Error", self.data.error)
            return

        # Remove row from table
        self.ui.tblCCorrections.removeRow(row)


    # Insert correction
    def cInsertRow(self):

        # Check for database
        if not self.data.database:
            msg = "Database connection not established."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Get lists
        lists = self.data.get_lists()

        # Check for lists
        if not lists:
            msg = "No lists defined."
            self.ui.statusBar.showMessage(msg)
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Mode
        modeid = int(self.ui.cboCCorrectionMode.currentIndex()) + 1
        modetext = str(self.data.correctionmodes[modeid])

        # List
        sel = int(self.ui.cboCList.currentIndex())
        listid = int(self.data.get_list(index=sel)[0])

        # Insert correction
        ok = self.data.insert("corrections", [modeid, listid, 0, "", "", ""])
        if ok:
            msg = "Row inserted."
            self.ui.statusBar.showMessage(msg)
        else:
            self.ui.statusBar.showMessage(self.data.error)
            QtGui.QMessageBox.critical(self, "Error", self.data.error)
            return

        # Refresh the corrections table
        self.refreshCCorrections()


    # Update correction
    def cUpdateRow(self):

        # Check for database
        if not self.data.database:
            msg = "Database connection not established."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Check table's selected items
        if not self.ui.tblCCorrections.selectedIndexes():
            msg = "Please select item from table."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Get lists
        lists = self.data.get_lists()

        # Check for lists
        if not lists:
            return

        # Get selected row
        row = int(self.ui.tblCCorrections.currentRow())

        # Get ID
        id = int(self.ui.tblCCorrections.item(row, 0).text())

        # Mode
        modeid = int(self.ui.tblCCorrections.cellWidget(row, 1).currentIndex())
        modeid += 1
        modetext = str(self.data.correctionmodes[modeid])

        # List
        sel = int(self.ui.tblCCorrections.cellWidget(row, 2).currentIndex())
        listdata = self.data.get_list(index=sel)
        listid = int(listdata[0])

        # Variations
        varia = int(self.ui.tblCCorrections.cellWidget(row, 3).checkState())
        if varia > 1: varia = 1 # Tristate checkbox into 1

        # Error, correction and comment
        error = str(self.ui.tblCCorrections.item(row, 4).text())
        correction = str(self.ui.tblCCorrections.item(row, 5).text())
        comment = str(self.ui.tblCCorrections.item(row, 6).text())

        # Check if error is empty
        if error == "":
            msg = "Error cannot be the empty."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # Check if error and correction are the same
        if error == correction:
            msg = "Error and correction cannot be the same."
            QtGui.QMessageBox.critical(self, "Error", msg)
            return

        # If mode is RegEx, check for validity
        if modeid == 1:
            if not self.string.test(str(error), str(correction)):
                QtGui.QMessageBox.critical(self, "Error", self.string.error)
                return

        # Update correction
        ok = self.data.update("corrections", [id, modeid, listid, varia, error,\
            correction, comment])
        if ok:
            msg = "Correction updated."
            self.ui.statusBar.showMessage(msg)
        else:
            self.ui.statusBar.showMessage(self.data.error)
            QtGui.QMessageBox.critical(self, "Error", self.data.error)


    # Log message
    def logMessage(self, msg):
        self.ui.lstLLog.addItem(time.strftime("%I:%M:%S") + chr(32) + msg)
        self.ui.lstLLog.scrollToBottom()


    # Enable/disable widgets
    def enabledisableWidgets(self, disable=False):

        # If disable is True, we disable everything
        if disable:
            self.ui.actionRemoveFiles.setEnabled(False)
            self.ui.actionClearList.setEnabled(False)
            self.ui.actionStart.setEnabled(False)
            self.ui.btnFRemoveFiles.setEnabled(False)
            self.ui.btnFClearList.setEnabled(False)
            self.ui.btnFStart.setEnabled(False)
            self.ui.btnLDeleteRow.setEnabled(False)
            self.ui.btnLInsertRow.setEnabled(False)
            self.ui.btnLUpdateRow.setEnabled(False)
            self.ui.btnCDeleteRow.setEnabled(False)
            self.ui.btnCInsertRow.setEnabled(False)
            self.ui.btnCUpdateRow.setEnabled(False)
            return

        # Fix buttons
        if len(self.filelist) > 0:
            self.ui.actionRemoveFiles.setEnabled(True)
            self.ui.actionClearList.setEnabled(True)
            self.ui.actionStart.setEnabled(True)
            self.ui.btnFRemoveFiles.setEnabled(True)
            self.ui.btnFClearList.setEnabled(True)
        else:
            self.ui.actionRemoveFiles.setEnabled(False)
            self.ui.actionClearList.setEnabled(False)
            self.ui.actionStart.setEnabled(False)
            self.ui.btnFRemoveFiles.setEnabled(False)
            self.ui.btnFClearList.setEnabled(False)

        # Lists and corrections buttons
        if self.data.database:
            self.ui.btnLDeleteRow.setEnabled(True)
            self.ui.btnLInsertRow.setEnabled(True)
            self.ui.btnLUpdateRow.setEnabled(True)
            self.ui.btnCDeleteRow.setEnabled(True)
            self.ui.btnCInsertRow.setEnabled(True)
            self.ui.btnCUpdateRow.setEnabled(True)
        else:
            self.ui.btnLDeleteRow.setEnabled(False)
            self.ui.btnLInsertRow.setEnabled(False)
            self.ui.btnLUpdateRow.setEnabled(False)
            self.ui.btnCDeleteRow.setEnabled(False)
            self.ui.btnCInsertRow.setEnabled(False)
            self.ui.btnCUpdateRow.setEnabled(False)

        # Start-button
        if self.data.database and len(self.filelist) > 0:
            self.ui.btnFStart.setEnabled(True)
        else:
            self.ui.btnFStart.setEnabled(False)