class CollectionFieldsBase(QObject):
    def __init__(self, parent=None):
        from OpenNumismat.Collection.CollectionFields import FieldTypes as Type
        super().__init__(parent)

        fields = [
                ('id', QApplication.translate('CollectionFieldsBase', "ID"), Type.BigInt),

                ('title', QApplication.translate('CollectionFieldsBase', "Name"), Type.String),
                ('value', QApplication.translate('CollectionFieldsBase', "Value"), Type.Denomination),
                ('unit', QApplication.translate('CollectionFieldsBase', "Unit"), Type.String),
                ('country', QApplication.translate('CollectionFieldsBase', "Country"), Type.String),
                ('year', QApplication.translate('CollectionFieldsBase', "Year"), Type.Number),
                ('period', QApplication.translate('CollectionFieldsBase', "Period"), Type.String),
                ('mint', QApplication.translate('CollectionFieldsBase', "Mint"), Type.String),
                ('mintmark', QApplication.translate('CollectionFieldsBase', "Mint mark"), Type.ShortString),
                ('issuedate', QApplication.translate('CollectionFieldsBase', "Date of issue"), Type.Date),
                ('type', QApplication.translate('CollectionFieldsBase', "Type"), Type.String),
                ('series', QApplication.translate('CollectionFieldsBase', "Series"), Type.String),
                ('subjectshort', QApplication.translate('CollectionFieldsBase', "Subject"), Type.String),
                ('status', QApplication.translate('CollectionFieldsBase', "Status"), Type.Status),
                ('material', QApplication.translate('CollectionFieldsBase', "Material"), Type.String),
                ('fineness', QApplication.translate('CollectionFieldsBase', "Fineness"), Type.Number),  # 4 digits for Canadian Gold Maple Leaf
                ('shape', QApplication.translate('CollectionFieldsBase', "Shape"), Type.String),
                ('diameter', QApplication.translate('CollectionFieldsBase', "Diameter"), Type.Value),
                ('thickness', QApplication.translate('CollectionFieldsBase', "Thickness"), Type.Value),
                ('weight', QApplication.translate('CollectionFieldsBase', "Weight"), Type.Value),
                ('grade', QApplication.translate('CollectionFieldsBase', "Grade"), Type.String),
                ('edge', QApplication.translate('CollectionFieldsBase', "Type"), Type.String),
                ('edgelabel', QApplication.translate('CollectionFieldsBase', "Label"), Type.String),
                ('obvrev', QApplication.translate('CollectionFieldsBase', "ObvRev"), Type.String),
                ('quality', QApplication.translate('CollectionFieldsBase', "Quality"), Type.String),
                ('mintage', QApplication.translate('CollectionFieldsBase', "Mintage"), Type.BigInt),
                ('dateemis', QApplication.translate('CollectionFieldsBase', "Emission period"), Type.String),
                ('catalognum1', QApplication.translate('CollectionFieldsBase', "1#"), Type.String),
                ('catalognum2', QApplication.translate('CollectionFieldsBase', "2#"), Type.String),
                ('catalognum3', QApplication.translate('CollectionFieldsBase', "3#"), Type.String),
                ('catalognum4', QApplication.translate('CollectionFieldsBase', "4#"), Type.String),
                ('rarity', QApplication.translate('CollectionFieldsBase', "Rarity"), Type.String),
                ('price1', QApplication.translate('CollectionFieldsBase', "Fine"), Type.Money),
                ('price2', QApplication.translate('CollectionFieldsBase', "VF"), Type.Money),
                ('price3', QApplication.translate('CollectionFieldsBase', "XF"), Type.Money),
                ('price4', QApplication.translate('CollectionFieldsBase', "Unc"), Type.Money),
                ('variety', QApplication.translate('CollectionFieldsBase', "Variety"), Type.String),
                ('obversevar', QApplication.translate('CollectionFieldsBase', "Obverse"), Type.String),
                ('reversevar', QApplication.translate('CollectionFieldsBase', "Reverse"), Type.String),
                ('edgevar', QApplication.translate('CollectionFieldsBase', "Edge"), Type.String),
                ('paydate', QApplication.translate('CollectionFieldsBase', "Date"), Type.Date),
                ('payprice', QApplication.translate('CollectionFieldsBase', "Price"), Type.Money),
                ('totalpayprice', QApplication.translate('CollectionFieldsBase', "Paid"), Type.Money),
                ('saller', QApplication.translate('CollectionFieldsBase', "Seller"), Type.String),
                ('payplace', QApplication.translate('CollectionFieldsBase', "Place"), Type.String),
                ('payinfo', QApplication.translate('CollectionFieldsBase', "Info"), Type.Text),
                ('saledate', QApplication.translate('CollectionFieldsBase', "Date"), Type.Date),
                ('saleprice', QApplication.translate('CollectionFieldsBase', "Price"), Type.Money),
                ('totalsaleprice', QApplication.translate('CollectionFieldsBase', "Bailed"), Type.Money),
                ('buyer', QApplication.translate('CollectionFieldsBase', "Buyer"), Type.String),
                ('saleplace', QApplication.translate('CollectionFieldsBase', "Place"), Type.String),
                ('saleinfo', QApplication.translate('CollectionFieldsBase', "Info"), Type.Text),
                ('note', QApplication.translate('CollectionFieldsBase', "Note"), Type.Text),
                ('image', QApplication.translate('CollectionFieldsBase', "Image"), Type.PreviewImage),
                ('obverseimg', QApplication.translate('CollectionFieldsBase', "Obverse"), Type.Image),
                ('obversedesign', QApplication.translate('CollectionFieldsBase', "Design"), Type.Text),
                ('obversedesigner', QApplication.translate('CollectionFieldsBase', "Designer"), Type.String),
                ('reverseimg', QApplication.translate('CollectionFieldsBase', "Reverse"), Type.Image),
                ('reversedesign', QApplication.translate('CollectionFieldsBase', "Design"), Type.Text),
                ('reversedesigner', QApplication.translate('CollectionFieldsBase', "Designer"), Type.String),
                ('edgeimg', QApplication.translate('CollectionFieldsBase', "Edge"), Type.Image),
                ('subject', QApplication.translate('CollectionFieldsBase', "Subject"), Type.Text),
                ('photo1', QApplication.translate('CollectionFieldsBase', "Photo 1"), Type.Image),
                ('photo2', QApplication.translate('CollectionFieldsBase', "Photo 2"), Type.Image),
                ('photo3', QApplication.translate('CollectionFieldsBase', "Photo 3"), Type.Image),
                ('photo4', QApplication.translate('CollectionFieldsBase', "Photo 4"), Type.Image),
                ('defect', QApplication.translate('CollectionFieldsBase', "Defect"), Type.String),
                ('storage', QApplication.translate('CollectionFieldsBase', "Storage"), Type.String),
                ('features', QApplication.translate('CollectionFieldsBase', "Features"), Type.Text),
                ('createdat', QApplication.translate('CollectionFieldsBase', "Created at"), Type.DateTime),
                ('updatedat', QApplication.translate('CollectionFieldsBase', "Updated at"), Type.DateTime),
                ('quantity', QApplication.translate('CollectionFieldsBase', "Quantity"), Type.BigInt),
                ('url', QApplication.translate('CollectionFieldsBase', "URL"), Type.String),
                ('barcode', QApplication.translate('CollectionFieldsBase', "Barcode"), Type.String),
                ('ruler', QApplication.translate('CollectionFieldsBase', "Ruler"), Type.String),
                ('region', QApplication.translate('CollectionFieldsBase', "Region"), Type.String),
                ('obverseengraver', QApplication.translate('CollectionFieldsBase', "Engraver"), Type.String),
                ('reverseengraver', QApplication.translate('CollectionFieldsBase', "Engraver"), Type.String),
                ('obversecolor', QApplication.translate('CollectionFieldsBase', "Color"), Type.String),
                ('reversecolor', QApplication.translate('CollectionFieldsBase', "Color"), Type.String),
                ('varietydesc', QApplication.translate('CollectionFieldsBase', "Description"), Type.Text),
                ('varietyimg', QApplication.translate('CollectionFieldsBase', "Variety"), Type.Image),
                ('format', QApplication.translate('CollectionFieldsBase', "Format"), Type.String),
                ('condition', QApplication.translate('CollectionFieldsBase', "Condition"), Type.String),
                ('category', QApplication.translate('CollectionFieldsBase', "Category"), Type.String),
                ('sort_id', QApplication.translate('CollectionFieldsBase', "Position"), Type.BigInt),
                ('emitent', QApplication.translate('CollectionFieldsBase', "Emitent"), Type.String),
                ('signaturetype', QApplication.translate('CollectionFieldsBase', "Type"), Type.String),
                ('signature', QApplication.translate('CollectionFieldsBase', "Signature"), Type.String),
                ('signatureimg', QApplication.translate('CollectionFieldsBase', "Signature"), Type.Image),
                ('address', QApplication.translate('CollectionFieldsBase', "Address"), Type.String),
                ('latitude', QApplication.translate('CollectionFieldsBase', "Latitude"), Type.Value),
                ('longitude', QApplication.translate('CollectionFieldsBase', "Longitude"), Type.Value),
                ('photo5', QApplication.translate('CollectionFieldsBase', "Photo 5"), Type.Image),
                ('photo6', QApplication.translate('CollectionFieldsBase', "Photo 6"), Type.Image),
                ('grader', QApplication.translate('CollectionFieldsBase', "Grader"), Type.String),
                ('seat', QApplication.translate('CollectionFieldsBase', "Seat"), Type.String),
                ('native_year', QApplication.translate('CollectionFieldsBase', "Year on coin"), Type.String),
            ]

        self.fields = []
        for id_, field in enumerate(fields):
            self.fields.append(
                            CollectionField(id_, field[0], field[1], field[2]))
            setattr(self, self.fields[id_].name, self.fields[id_])

        self.systemFields = (self.id, self.createdat, self.updatedat,
                             self.image, self.sort_id)
        self.userFields = list(self.fields)
        for item in (self.id, self.createdat, self.updatedat, self.sort_id):
            self.userFields.remove(item)

    def field(self, id_):
        return self.fields[id_]

    def __iter__(self):
        self.index = 0
        return self

    def __next__(self):
        if self.index == len(self.fields):
            raise StopIteration
        self.index = self.index + 1
        return self.fields[self.index - 1] class FieldTypes():
    String = 1
    ShortString = 2
    Number = 3
    Text = 4
    Money = 5
    Date = 6
    BigInt = 7
    Image = 8
    Value = 9
    Status = 10
    DateTime = 11
    PreviewImage = 13
    Denomination = 14

    Mask = 0xFF
    Checkable = 0x100
    Disabled = 0x200

    ImageTypes = (Image, PreviewImage)

    @staticmethod
    def toSql(type_):
        if type_ == FieldTypes.String:
            sql_type = 'TEXT'
        elif type_ == FieldTypes.ShortString:
            sql_type = 'TEXT'
        elif type_ == FieldTypes.Number:
            sql_type = 'INTEGER'
        elif type_ == FieldTypes.Text:
            sql_type = 'TEXT'
        elif type_ == FieldTypes.Money:
            sql_type = 'NUMERIC'
        elif type_ == FieldTypes.Denomination:
            sql_type = 'NUMERIC'
        elif type_ == FieldTypes.Date:
            sql_type = 'TEXT'
        elif type_ == FieldTypes.BigInt:
            sql_type = 'INTEGER'
        elif type_ == FieldTypes.PreviewImage:
            sql_type = 'INTEGER'
        elif type_ == FieldTypes.Image:
            sql_type = 'INTEGER'
        elif type_ == FieldTypes.Value:
            sql_type = 'NUMERIC'
        elif type_ == FieldTypes.Status:
            sql_type = 'TEXT'
        elif type_ == FieldTypes.DateTime:
            sql_type = 'TEXT'
        else:
            raise TypeError

        return sql_type class CollectionFields(CollectionFieldsBase):
    def __init__(self, db, parent=None):
        super().__init__(parent)
        self.db = db

        if 'fields' not in self.db.tables():
            self.create(self.db)

        query = QSqlQuery(self.db)
        query.prepare("SELECT * FROM fields")
        query.exec_()
        self.userFields = []
        self.disabledFields = []
        while query.next():
            record = query.record()
            fieldId = record.value('id')
            field = self.field(fieldId)
            field.title = record.value('title')
            field.enabled = bool(record.value('enabled'))
            if field.enabled:
                self.userFields.append(field)
            else:
                self.disabledFields.append(field)

    def getCustomTitle(self, name):
        return self.__getattribute__(name).title

    def save(self):
        self.db.transaction()

        for field in self.fields:
            query = QSqlQuery(self.db)
            query.prepare("UPDATE fields SET title=?, enabled=? WHERE id=?")
            query.addBindValue(field.title)
            query.addBindValue(int(field.enabled))
            query.addBindValue(field.id)
            query.exec_()

        self.db.commit()

    @staticmethod
    def create(db=QSqlDatabase()):
        db.transaction()

        sql = """CREATE TABLE fields (
            id INTEGER NOT NULL PRIMARY KEY,
            title TEXT,
            enabled INTEGER)"""
        QSqlQuery(sql, db)

        fields = CollectionFieldsBase()

        for field in fields:
            query = QSqlQuery(db)
            query.prepare("""INSERT INTO fields (id, title, enabled)
                VALUES (?, ?, ?)""")
            query.addBindValue(field.id)
            query.addBindValue(field.title)
            enabled = field in fields.userFields
            query.addBindValue(int(enabled))
            query.exec_()

        db.commit() class FieldTypes():
class Status(dict):
class CollectionField():
class CollectionFieldsBase(QObject):
class CollectionFields(CollectionFieldsBase):
    def toSql(type_):
    def __init__(self):
    def keys(self):
    def items(self):
    def values(self):
    def __getitem__(self, key):
    def __init__(self, id_, name, title, type_):
    def __init__(self, parent=None):
    def field(self, id_):
    def __iter__(self):
    def __next__(self):
    def __init__(self, db, parent=None):
    def getCustomTitle(self, name):
    def save(self):
    def create(db=QSqlDatabase()): class CollectionPages(QtCore.QObject):
    def __init__(self, db, parent=None):
        super().__init__(parent)

        self.db = db
        sql = "CREATE TABLE IF NOT EXISTS pages (\
            id INTEGER PRIMARY KEY,\
            title TEXT,\
            isopen INTEGER,\
            position INTEGER,\
            type INTEGER)"
        QSqlQuery(sql, self.db)

        self.fields = CollectionFields(self.db)
        self.params = None

    def pagesParam(self):
        if self.params is None:
            query = QSqlQuery("SELECT * FROM pages ORDER BY position")
            self.params = self.__queryToParam(query)
        return self.params

    def addPage(self, title):
        query = QSqlQuery(self.db)
        query.prepare("INSERT INTO pages (title, isopen, type, position) "
                      "VALUES (?, ?, ?, (SELECT COUNT(*) FROM pages))")
        query.addBindValue(title)
        query.addBindValue(int(True))
        query.addBindValue(CollectionPageTypes.Default)
        query.exec_()

        query = QSqlQuery("SELECT * FROM pages WHERE id=last_insert_rowid()",
                          self.db)
        return self.__queryToParam(query)[0]  # get only one item

    def renamePage(self, page, title):
        query = QSqlQuery(self.db)
        query.prepare("UPDATE pages SET title=? WHERE id=?")
        query.addBindValue(title)
        query.addBindValue(page.id)
        query.exec_()

    def closePage(self, page):
        query = QSqlQuery(self.db)
        query.prepare("UPDATE pages SET isopen=? WHERE id=?")
        query.addBindValue(int(False))
        query.addBindValue(page.id)
        query.exec_()

    def openPage(self, page):
        query = QSqlQuery(self.db)
        query.prepare("UPDATE pages SET isopen=? WHERE id=?")
        query.addBindValue(int(True))
        query.addBindValue(page.id)
        query.exec_()

    def removePage(self, page):
        page.listParam.remove()
        page.treeParam.remove()
        page.statisticsParam.remove()

        query = QSqlQuery(self.db)
        query.prepare("DELETE FROM pages WHERE id=?")
        query.addBindValue(page.id)
        query.exec_()

    def savePositions(self, pages):
        for position, page in enumerate(pages):
            query = QSqlQuery(self.db)
            query.prepare("UPDATE pages SET position=? WHERE id=?")
            query.addBindValue(position)
            query.addBindValue(page.id)
            query.exec_()

    def closedPages(self):
        query = QSqlQuery(self.db)
        query.prepare("SELECT * FROM pages WHERE isopen=? ORDER BY title")
        query.addBindValue(int(False))
        query.exec_()
        return self.__queryToParam(query)

    def changeView(self, page, type_):
        query = QSqlQuery(self.db)
        query.prepare("UPDATE pages SET type=? WHERE id=?")
        query.addBindValue(type_ | page.info_type)
        query.addBindValue(page.id)
        query.exec_()

    def changeInfoType(self, page, info_type):
        query = QSqlQuery(self.db)
        query.prepare("UPDATE pages SET type=? WHERE id=?")
        query.addBindValue(info_type | page.type)
        query.addBindValue(page.id)
        query.exec_()

    def __queryToParam(self, query):
        pagesParam = []
        while query.next():
            param = CollectionPageParam(query.record())
            param.fields = self.fields
            param.db = self.db
            # TODO: Improve code
            if param.type == CollectionPageTypes.List:
                param.listParam = ListPageParam(param)
            elif param.type == CollectionPageTypes.Card:
                param.listParam = ListPageParam(param)
            elif param.type == CollectionPageTypes.Icon:
                param.listParam = ListPageParam(param)
            param.treeParam = TreeParam(param)
            param.statisticsParam = StatisticsParam(param)
            pagesParam.append(param)

        return pagesParam def cryptPassword(password=''):
    return hashlib.md5(password.encode('utf-8')).hexdigest()
 class PasswordDialog(QDialog):

    def __init__(self, crypted_password, collection_name='', parent=None):
        super().__init__(parent,
                         Qt.WindowCloseButtonHint | Qt.WindowSystemMenuHint)
        self.crypted_password = crypted_password

        self.setWindowTitle(collection_name)

        mainLayout = QFormLayout()

        self.passwordWidget = QLineEdit(self)
        self.passwordWidget.setEchoMode(QLineEdit.Password)
        mainLayout.addRow(self.tr("Password"), self.passwordWidget)

        buttonBox = QDialogButtonBox(Qt.Horizontal)
        buttonBox.addButton(QDialogButtonBox.Ok)
        buttonBox.addButton(QDialogButtonBox.Cancel)
        buttonBox.accepted.connect(self.apply)
        buttonBox.rejected.connect(self.reject)

        layout = QVBoxLayout()
        layout.addLayout(mainLayout)
        layout.addWidget(buttonBox)

        self.setLayout(layout)

    def apply(self):
        text = self.passwordWidget.text()
        if checkPassword(self.crypted_password, text):
            self.accept()
        else:
            QMessageBox.critical(self, self.tr("Open collection"),
                                       self.tr("Incorrect password"))
            self.reject()
 class CollectionDescription(QObject):
    def __init__(self, collection):
        super().__init__(collection)
        self.db = collection.db

        if 'description' not in self.db.tables():
            self.create(collection)

        query = QSqlQuery("SELECT * FROM description", self.db)
        query.first()
        record = query.record()

        self.title = record.value('title')
        self.description = record.value('description')
        self.author = record.value('author')

    def save(self):
        self.db.transaction()

        query = QSqlQuery(self.db)
        query.prepare("UPDATE description SET title=?, description=?,"
                      " author=? WHERE id=1")
        query.addBindValue(self.title)
        query.addBindValue(self.description)
        query.addBindValue(self.author)
        query.exec_()

        self.db.commit()

    def create(self, collection):
        self.db.transaction()

        sql = """CREATE TABLE description (
            id INTEGER PRIMARY KEY,
            title TEXT,
            description TEXT,
            author TEXT)"""
        QSqlQuery(sql, self.db)

        query = QSqlQuery(self.db)
        query.prepare("""INSERT INTO description (title, description, author)
                VALUES (?, ?, ?)""")
        query.addBindValue(collection.getCollectionName())
        query.addBindValue('')
        query.addBindValue('')
        query.exec_()

        self.db.commit()
 class Reference(QtCore.QObject):
    def __init__(self, fields, parent=None, db=None):
        super().__init__(parent)

        if db:
            self.db = db
        else:
            self.db = QSqlDatabase.addDatabase('QSQLITE', "reference")

        self.fileName = None
        self.userFields = [field.name for field in fields.userFields]
        self.sections = []

        ref_region = self.__createReferenceSection(None, fields.region)
        ref_country = self.__createReferenceSection(ref_region, fields.country,
                                                    self.tr("C"), True)
        self.__createReferenceSection(ref_country, fields.period,
                                      self.tr("P"), True)
        self.__createReferenceSection(ref_country, fields.emitent)
        self.__createReferenceSection(ref_country, fields.ruler)
        self.__createReferenceSection(ref_country, fields.unit, self.tr("U"))
        self.__createReferenceSection(ref_country, fields.mint)
        self.__createReferenceSection(ref_country, fields.series,
                                      self.tr("S"), True)
        self.__createReferenceSection(None, fields.grade, self.tr("G"))
        self.__createReferenceSection(None, fields.material, self.tr("M"))
        self.__createReferenceSection(None, fields.shape, self.tr("F"))
        self.__createReferenceSection(None, fields.quality, self.tr("Q"))
        self.__createReferenceSection(None, fields.rarity, self.tr("R"))
        self.__createReferenceSection(None, fields.obvrev)
        self.__createReferenceSection(None, fields.type, self.tr("T"))
        self.__createReferenceSection(None, fields.defect, self.tr("D"))
        self.__createReferenceSection(None, fields.format)
        self.__createReferenceSection(None, fields.condition)
        self.__createReferenceSection(None, fields.grader)
        self.__createReferenceSection(None, fields.storage)

        if 'payplace' in self.userFields or 'saleplace' in self.userFields:
            ref_place = ReferenceSection('place', self.tr("Place"))
            self.sections.append(ref_place)
        if 'obversecolor' in self.userFields or 'reversecolor' in self.userFields:
            ref_color = ReferenceSection('color', self.tr("Color"))
            self.sections.append(ref_color)
        if 'edge' in self.userFields or 'signaturetype' in self.userFields:
            ref_edge = ReferenceSection('edge', self.tr("Edge"))
            self.sections.append(ref_edge)

    def __createReferenceSection(self, parentRef, field,
                                 letter='…', sort=False):
        if field.name in self.userFields:
            if parentRef:
                ref = CrossReferenceSection(field.name, parentRef, field.title,
                                            letter, sort)
            else:
                ref = ReferenceSection(field.name, field.title, letter, sort)
            self.sections.append(ref)

            return ref
        return None

    def create(self):
        sql = "CREATE TABLE IF NOT EXISTS sections (\
            id INTEGER PRIMARY KEY,\
            name TEXT,\
            icon BLOB,\
            letter TEXT,\
            parent TEXT,\
            sort INTEGER)"
        QSqlQuery(sql, self.db)

        sql = """CREATE TABLE ref (
            title CHAR NOT NULL UNIQUE,
            value CHAR)"""
        QSqlQuery(sql, self.db)

        sql = """INSERT INTO ref (title, value)
            VALUES ('version', 1)"""
        QSqlQuery(sql, self.db)

        for section in self.sections:
            section.create(self.db)

    def open(self, fileName, interactive=True):
        file = QtCore.QFileInfo(fileName)
        if file.isFile():
            self.db.setDatabaseName(fileName)
            if not self.db.open():
                print(self.db.lastError().text())
                QMessageBox.critical(self.parent(),
                            self.tr("Open reference"),
                            self.tr("Can't open reference:\n%s") % fileName)
                return False
            else:
                # Update reference DB for version 1.4.3
                if self.db.record('sections').indexOf('sort') < 0:
                    sql = "ALTER TABLE sections ADD COLUMN sort INTEGER"
                    QSqlQuery(sql, self.db)
                    sql = "UPDATE sections SET name = 'material' WHERE name = 'metal'"
                    QSqlQuery(sql, self.db)
                # Update reference DB for version 1.4.9
                if 'period' in self.db.tables() and \
                        self.db.record('period').indexOf('icon') < 0:
                    for table in ('period', 'unit', 'mint', 'series'):
                        sql = "ALTER TABLE %s ADD COLUMN icon BLOB" % table
                        QSqlQuery(sql, self.db)
                # Update reference DB for version 1.6
                if 'country' in self.db.tables() and \
                        self.db.record('country').indexOf('parentid') < 0:
                    sql = "ALTER TABLE country ADD COLUMN parentid INTEGER"
                    QSqlQuery(sql, self.db)
                    sql = "UPDATE sections SET parent = 'region' WHERE name = 'country'"
                    QSqlQuery(sql, self.db)

                    tables = ('region', 'country', 'period', 'ruler', 'unit',
                              'mint', 'series', 'grade', 'material', 'shape',
                              'quality', 'edge', 'rarity', 'obvrev', 'type',
                              'defect', 'place')
                    for table in tables:
                        sql = "ALTER TABLE %s RENAME TO ref_%s" % (table, table)
                        QSqlQuery(sql, self.db)
        else:
            if interactive:
                QMessageBox.warning(self.parent(),
                            self.tr("Open reference"),
                            self.tr("Can't open reference:\n%s\nCreated new one") % fileName)

            self.db.setDatabaseName(fileName)
            if not self.db.open():
                print(self.db.lastError().text())
                QMessageBox.critical(self.parent(),
                            self.tr("Create reference"),
                            self.tr("Can't create reference:\n%s") % fileName)
                return False
            self.create()

        self.fileName = fileName

        return True

    def load(self):
        # Update reference DB for version 1.6.2
        if 'ref' not in self.db.tables():
            self.__updateTo1()

        for section in self.sections:
            section.load(self.db)

        self.sections_with_icons = []
        for section in self.sections:
            name = section.table_name
            sql = "SELECT 1 FROM %s WHERE icon IS NOT NULL LIMIT 1" % name
            query = QtSql.QSqlQuery(sql, self.db)
            query.exec_()
            if query.first():
                self.sections_with_icons.append(name)

    def section(self, name):
        # NOTE: payplace and saleplace fields has one reference section =>
        # editing one of it should change another
        if name in ('payplace', 'saleplace'):
            name = 'place'
        elif name in ('obversecolor', 'reversecolor'):
            name = 'color'
        elif name in ('edge', 'signaturetype'):
            name = 'edge'

        for section in self.sections:
            if section.name == name:
                return section

        return None

    def allSections(self):
        sectionNames = []
        for section in self.sections:
            if section.name == 'place':
                sectionNames.extend(['payplace', 'saleplace'])
            elif section.name == 'color':
                sectionNames.extend(['obversecolor', 'reversecolor'])
            elif section.name == 'edge':
                sectionNames.extend(['edge', 'signaturetype'])
            else:
                sectionNames.append(section.name)

        return sectionNames

    def getIcon(self, section, value):
        if section in ('payplace', 'saleplace'):
            section = 'place'
        elif section in ('obversecolor', 'reversecolor'):
            section = 'color'
        elif section in ('edge', 'signaturetype'):
            section = 'edge'

        table_name = "ref_%s" % section
        if table_name in self.sections_with_icons:
            sql = "SELECT icon FROM %s WHERE value=?" % table_name
            query = QtSql.QSqlQuery(sql, self.db)
            query.addBindValue(value)
            query.exec_()
            if query.first():
                data = query.record().value(0)
                if data:
                    pixmap = QPixmap()
                    if pixmap.loadFromData(data):
                        icon = QIcon(pixmap)
                        return icon
        return None

    def backup(self):
        if self.fileName:
            file = QtCore.QFileInfo(self.fileName)
            backupDir = file.dir()
            backupFileName = backupDir.filePath("%s_%s.ref" % (file.baseName(),
                                                               QtCore.QDateTime.currentDateTime().toString('yyMMddhhmmss')))
            srcFile = QtCore.QFile(self.fileName)
            srcFile.copy(backupFileName)

    def __updateTo1(self):
        self.backup()

        self.db.transaction()

        for cross_ref in ('country', 'period', 'ruler',
                          'unit', 'mint', 'series'):
            sql = "ALTER TABLE ref_%s RENAME TO old_ref_%s" % (cross_ref, cross_ref)
            QSqlQuery(sql, self.db)

            sql = "CREATE TABLE ref_%s (\
                id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\
                parentid INTEGER,\
                value TEXT, icon BLOB)" % cross_ref
            QSqlQuery(sql, self.db)

            sql = "INSERT INTO ref_%s\
                SELECT id, parentid, value, icon\
                FROM old_ref_%s" % (cross_ref, cross_ref)
            QSqlQuery(sql, self.db)

            sql = "DROP TABLE old_ref_%s" % cross_ref
            QSqlQuery(sql, self.db)

        sql = """CREATE TABLE ref (
            title CHAR NOT NULL UNIQUE,
            value CHAR)"""
        QSqlQuery(sql, self.db)

        sql = """INSERT INTO ref (title, value)
            VALUES ('version', 1)"""
        QSqlQuery(sql, self.db)

        self.db.commit() class CrossReferenceSection(BaseReferenceSection):
    def __init__(self, name, parentRef, title, letter='…', sort=False, parent=None):
        super().__init__(name, title, letter, sort, parent)

        self.parentIndex = None
        self.parentRef = parentRef
        self.parent_name = parentRef.name
        self.parent_table_name = parentRef.table_name

    def load(self, db):
        self.db = db
        if self.table_name not in self.db.tables():
            self.create(self.db)

        self.model = SqlRelationalTableModel(self.parentRef.model, None, db)
        self.model.setJoinMode(QtSql.QSqlRelationalTableModel.LeftJoin)
        self.model.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)
        self.model.setTable(self.table_name)
        parentidIndex = self.model.fieldIndex('parentid')
        self.model.parentidIndex = parentidIndex
        self.model.setRelation(
            parentidIndex, QtSql.QSqlRelation(self.parent_table_name, 'id', 'value'))

        self.reload()

    def _getDialog(self):
        copy = CrossReferenceSection(self.name, self.parentRef, self.title,
                                     self.letter, self.sort, self.parent)
        copy.load(self.db)

        return CrossReferenceDialog(copy, self.parentIndex,
                                    self.parent.text(), self.parent)

    def fillFromQuery(self, parentId, query):
        while query.next():
            value = query.record().value(0)
            fillQuery = QSqlQuery(self.db)
            fillQuery.prepare("INSERT INTO %s (value, parentid) "
                        "SELECT ?, ? "
                        "WHERE NOT EXISTS "
                        "(SELECT 1 FROM %s WHERE value=? AND parentid=?)" %
                                            (self.table_name, self.table_name))
            fillQuery.addBindValue(value)
            fillQuery.addBindValue(parentId)
            fillQuery.addBindValue(value)
            fillQuery.addBindValue(parentId)
            fillQuery.exec_() class AllReferenceDialog(QDialog):
    def __init__(self, reference, parent=None):
        super().__init__(parent,
                         Qt.WindowCloseButtonHint | Qt.WindowSystemMenuHint)

        self.db = reference.db
        self.db.transaction()

        self.setWindowTitle(self.tr("Reference"))

        self.sections = reference.sections

        tab = QTabWidget(self)
        self.widgets = {}
        for section in self.sections:
            if section.parent_name:
                widget = CrossReferenceWidget(section, None, '', self)
            else:
                widget = ReferenceWidget(section, '', self)

            self.widgets[section.name] = widget
            tab.addTab(widget, section.title)

        buttonBox = QDialogButtonBox(Qt.Horizontal)
        buttonBox.addButton(QDialogButtonBox.Ok)
        buttonBox.addButton(QDialogButtonBox.Cancel)
        buttonBox.accepted.connect(self.accept)
        buttonBox.rejected.connect(self.reject)

        layout = QVBoxLayout()
        layout.addWidget(tab)
        layout.addWidget(buttonBox)

        self.setLayout(layout)

    def accept(self):
        for section in self.sections:
            widget = self.widgets[section.name]
            section.saveSort(widget.sortButton.isChecked())
        if not self.db.commit():
            QMessageBox.critical(self.parent(),
                            self.tr("Save reference"),
                            self.tr("Something went wrong when saving. Please restart"))
            self.db.rollback()

        super().accept()

    def reject(self):
        # Make select for close all SQL request
        for section in self.sections:
            section.model.select()

        if not self.db.rollback():
            QMessageBox.critical(self.parent(),
                            self.tr("Save reference"),
                            self.tr("Something went wrong when canceling. Please restart"))

        for section in self.sections:
            section.setSort()
            section.model.select()

        super().reject() class EditCoinDialog(QDialog):
    def __init__(self, model, record, parent=None, usedFields=None):
        super().__init__(parent,
                         Qt.WindowCloseButtonHint | Qt.WindowSystemMenuHint)

        self.clickedButton = QDialogButtonBox.Abort

        self.usedFields = usedFields
        self.record = record
        self.model = model

        self.tab = FormDetailsTabWidget(model, self, usedFields)
        self.items = self.tab.items

        self.textChangedTitle()
        self.tab.items['title'].widget().textChanged.connect(
                                                        self.textChangedTitle)
        self.tab.fillItems(record)

        self.buttonBox = QDialogButtonBox(Qt.Horizontal)
        self.buttonBox.addButton(QDialogButtonBox.Save)
        self.buttonBox.addButton(QDialogButtonBox.Cancel)
        self.buttonBox.accepted.connect(self.save)
        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.clicked.connect(self.clicked)

        layout = QVBoxLayout()
        layout.addWidget(self.tab)
        layout.addWidget(self.buttonBox)

        self.setLayout(layout)

    def clicked(self, button):
        buttons = (QDialogButtonBox.Save, QDialogButtonBox.SaveAll,
                   QDialogButtonBox.Cancel, QDialogButtonBox.Abort)
        for btn in buttons:
            if self.buttonBox.button(btn) == button:
                self.clickedButton = btn

    # Enable 'Save all' button
    def setManyCoins(self, many=True):
        if many:
            self.buttonBox.addButton(QDialogButtonBox.SaveAll)
            self.buttonBox.addButton(QDialogButtonBox.Abort)

    def textChangedTitle(self, text=''):
        if self.usedFields:
            title = [self.tr("Multi edit"), ]
        elif self.record.isNull('id'):
            title = [self.tr("New"), ]
        else:
            title = [self.tr("Edit"), ]

        if text:
            title.insert(0, text)
        self.setWindowTitle(' - '.join(title))

    def save(self):
        # Clear unused fields
        status = self.items['status'].widget().data()
        if status in ('demo', 'wish'):
            for key in ('paydate', 'payprice', 'totalpayprice', 'saller',
                        'payplace', 'payinfo'):
                self.items[key].clear()
        if status in ('demo', 'wish', 'owned', 'sale', 'ordered', 'missing',
                      'bidding', 'duplicate'):
            for key in ('saledate', 'saleprice', 'totalsaleprice', 'buyer',
                        'saleplace', 'saleinfo'):
                self.items[key].clear()

        settings = Settings()

        if settings['check_coin_title']:
            if not self.usedFields:
                if not self.items['title'].value():
                    result = QMessageBox.warning(
                        self, self.tr("Save"),
                        self.tr("Coin title not set. Save without title?"),
                        QMessageBox.Save | QMessageBox.No, QMessageBox.No)
                    if result != QMessageBox.Save:
                        return

        # Checking that TotalPrice not less than Price
        payprice_str = self.items['payprice'].value()
        totalpayprice_str = self.items['totalpayprice'].value()
        if totalpayprice_str:
            totalpayprice = stringToMoney(totalpayprice_str)
            if totalpayprice < 0:
                result = QMessageBox.warning(self, self.tr("Save"),
                                self.tr("Total paid price is negative. Save?"),
                                QMessageBox.Save | QMessageBox.No,
                                QMessageBox.No)
                if result != QMessageBox.Save:
                    return
        if payprice_str and totalpayprice_str:
            payprice = stringToMoney(payprice_str)
            if totalpayprice < payprice:
                result = QMessageBox.warning(self, self.tr("Save"),
                            self.tr("Pay price is great than total "
                                    "paid price. Save?"),
                            QMessageBox.Save | QMessageBox.No,
                            QMessageBox.No)
                if result != QMessageBox.Save:
                    return
        saleprice_str = self.items['saleprice'].value()
        totalsaleprice_str = self.items['totalsaleprice'].value()
        if totalsaleprice_str:
            totalsaleprice = stringToMoney(totalsaleprice_str)
            if totalsaleprice < 0:
                result = QMessageBox.warning(self, self.tr("Save"),
                                self.tr("Total bailed price is negative. Save?"),
                                QMessageBox.Save | QMessageBox.No,
                                QMessageBox.No)
                if result != QMessageBox.Save:
                    return
        if saleprice_str and totalsaleprice_str:
            saleprice = stringToMoney(saleprice_str)
            if saleprice < totalsaleprice:
                result = QMessageBox.warning(self, self.tr("Save"),
                            self.tr("Sale price is less than total "
                                    "bailed price. Save?"),
                            QMessageBox.Save | QMessageBox.No,
                            QMessageBox.No)
                if result != QMessageBox.Save:
                    return

        for item in self.items.values():
            value = item.value()
            if isinstance(value, str):
                value = value.strip()
            self.record.setValue(item.field(), value)

        for image_field in ImageFields:
            item = self.items[image_field]
            value = item.widget().title
            if isinstance(value, str):
                value = value.strip()
            self.record.setValue(image_field + '_title', value)

        if settings['check_coin_duplicate']:
            if not self.usedFields:
                if self.model.isExist(self.record):
                    result = QMessageBox.warning(
                        self, self.tr("Save"),
                        self.tr("Similar coin already exists. Save?"),
                        QMessageBox.Save | QMessageBox.No, QMessageBox.No)
                    if result != QMessageBox.Save:
                        return

        self.accept()

    def getUsedFields(self):
        for item in self.items.values():
            index = self.record.indexOf(item.field())
            self.usedFields[index] = item.label().checkState()
        return self.usedFields
 class FieldTypes():
class Status(dict):
class CollectionField():
class CollectionFieldsBase(QObject):
class CollectionFields(CollectionFieldsBase):
    def toSql(type_):
    def __init__(self):
    def keys(self):
    def items(self):
    def values(self):
    def __getitem__(self, key):
    def __init__(self, id_, name, title, type_):
    def __init__(self, parent=None):
    def field(self, id_):
    def __iter__(self):
    def __next__(self):
    def __init__(self, db, parent=None):
    def getCustomTitle(self, name):
    def save(self):
    def create(db=QSqlDatabase()): def updateCollection(collection):
    updater = Updater(collection, collection.parent())
    if updater.check():
        return updater.update()

    return True
 def waitCursorDecorator(f):
    @wraps(f)
    def wrapper(*args, **kwds):
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        res = f(*args, **kwds)
        QApplication.restoreOverrideCursor()
        return res

    return wrapper class ProgressDialog(QProgressDialog):
    def __init__(self, labelText, cancelButtonText, maximum, parent=None):
    def step(self):
    def setLabelText(self, text):
def statusIcon(status):
def getSaveFileName(parent, name, filename, dir_, filters):
 class Settings(BaseSettings):
    default_template = os.path.join(OpenNumismat.PRJ_PATH, 'templates', 'full')
    Default = {'locale': _getLocale(),
               'backup': OpenNumismat.HOME_PATH + "/backup/",
               'autobackup': True,
               'autobackup_depth': 25,
               'reference': OpenNumismat.HOME_PATH + "/reference.ref",
               'error': True,
               'speedup': 1,
               'updates': False,
               'template': default_template,
               'check_coin_title': True,
               'check_coin_duplicate': True,
               'images_by_default': 2,
               'colnect_enabled': True,
               'colnect_locale': _getLocale(),
               'colnect_autoclose': False,
               'colnect_skip_currency': True,
               'map_type': 0,
               'built_in_viewer': True,
               'font_size': 0}

    def __init__(self, autoSave=False):
        super().__init__(autoSave)

        self.settings = QSettings()

    def keys(self):
        return self.Default.keys()

    def _getValue(self, key):
        if key in ('error', 'updates', 'autobackup',
                   'check_coin_title', 'check_coin_duplicate',
                   'colnect_enabled', 'colnect_autoclose',
                   'colnect_skip_currency', 'built_in_viewer'):
            value = self.settings.value('mainwindow/' + key, self.Default[key],
                                        type=bool)
        elif key in ('images_by_default', 'autobackup_depth',
                     'speedup', 'map_type', 'font_size'):
            value = self.settings.value('mainwindow/' + key, self.Default[key],
                                        type=int)
        else:
            value = self.settings.value('mainwindow/' + key, self.Default[key])

            if key == 'template':
                if not os.path.isdir(value):
                    value = self.default_template

        return value

    def _saveValue(self, key, val):
        self.settings.setValue('mainwindow/' + key, val) class BaseSettings(dict):
    def __init__(self, autoSave=False):
        super().__init__()

        self.autoSave = autoSave

    def keys(self):
        raise NotImplementedError

    def items(self):
        result = []
        for key in self.keys():
            result.append((key, self.__getitem__(key)))
        return result

    def values(self):
        result = []
        for key in self.keys():
            result.append(self.__getitem__(key))
        return result

    def __getitem__(self, key):
        if key in self.__dict__:
            return self.__dict__[key]

        if key in self.keys():
            value = self._getValue(key)
            self.__dict__[key] = value

            return value
        else:
            raise KeyError(key)

    def __setitem__(self, key, val):
        if key in self.keys():
            self.__dict__[key] = val
            if self.autoSave:
                self._saveValue(key, val)
        else:
            raise KeyError(key)

    def save(self):
        for key in self.keys():
            self._saveValue(key, self.__getitem__(key))

    def _getValue(self, key):
        raise NotImplementedError

    def _saveValue(self, key, val):
        raise NotImplementedError class ExportDialog(QDialog):
    IMAGE_OBVERSE = 0
    IMAGE_REVERSE = 1
    IMAGE_BOTH = 2

    latestDir = OpenNumismat.HOME_PATH
    params = {}

    def __init__(self, collection, parent=None):
        super().__init__(parent,
                         Qt.WindowCloseButtonHint | Qt.WindowSystemMenuHint)

        self.collection = collection

        self.setWindowTitle(self.tr("Export to mobile"))

        form = QFormLayout()
        form.setRowWrapPolicy(QFormLayout.WrapLongRows)

        # density
        self.densitySelector = QComboBox(self)
        densities = ('MDPI', 'HDPI', 'XHDPI', 'XXHDPI', 'XXXHDPI')
        self.densitySelector.addItems(densities)
        self.densitySelector.setSizePolicy(QSizePolicy.Fixed,
                                           QSizePolicy.Fixed)
        form.addRow(self.tr("Target density of the display"), self.densitySelector)

        settings = QSettings()
        density = settings.value('density', 'XHDPI')
        self.densitySelector.setCurrentText(density)

        # filtering
        self.filterSelector = QComboBox(self)
        self.filterSelector.addItem(self.tr("Countries"), 'country')
        self.filterSelector.addItem(self.tr("Series"), 'series')
        self.filterSelector.addItem(self.tr("Denomination"), 'denomination')
        self.filterSelector.setSizePolicy(QSizePolicy.Fixed,
                                          QSizePolicy.Fixed)
        form.addRow(self.tr("Default filter by"), self.filterSelector)

        # image
        groupBox = QGroupBox(self.tr("Image"))
        vbox = QFormLayout(self)

        self.obverseRadio = QRadioButton(self.tr("Obverse"), self)
        self.reverseRadio = QRadioButton(self.tr("Reverse"), self)
        self.bothRadio = QRadioButton(self.tr("Both"), self)
        self.bothRadio.setChecked(True)

        vbox.addRow(self.obverseRadio)
        vbox.addRow(self.reverseRadio)
        vbox.addRow(self.bothRadio)

        groupBox.setLayout(vbox)
        form.addRow(groupBox)

        self.fullImage = QCheckBox(self.tr("Export a full-sized image"), self)
        form.addRow(self.fullImage)

        # file
        self.destination = QLineEdit(self)
        style = QApplication.style()
        icon = style.standardIcon(QStyle.SP_DialogOpenButton)
        self.destinationButton = QPushButton(icon, '', self)
        self.destinationButton.clicked.connect(self.destinationButtonClicked)

        hLayout = QHBoxLayout()
        hLayout.addWidget(self.destination)
        hLayout.addWidget(self.destinationButton)
        hLayout.setContentsMargins(QMargins())

        form.addRow(self.tr("Destination"), hLayout)

        buttonBox = QDialogButtonBox(Qt.Horizontal)
        self.acceptButton = buttonBox.addButton(QDialogButtonBox.Ok)
        self.acceptButton.setEnabled(False)
        buttonBox.addButton(QDialogButtonBox.Cancel)
        buttonBox.accepted.connect(self.start)
        buttonBox.rejected.connect(self.reject)

        layout = QVBoxLayout()
        layout.addLayout(form)
        layout.addWidget(buttonBox)

        self.setLayout(layout)

        self.setFixedSize(self.sizeHint())

    def destinationButtonClicked(self):
        destination = self.destination.text()
        if not destination and self.collection:
            destination = self.latestDir + '/' + self.collection.getCollectionName() + '_mobile.db'
        file, _selectedFilter = QFileDialog.getSaveFileName(
            self, self.tr("Select destination"), destination, "*.db")
        if file:
            file_info = QFileInfo(file)
            self.latestDir = file_info.absolutePath()

            self.destination.setText(file)
            self.acceptButton.setEnabled(True)

    def start(self):
        file = self.destination.text().strip()
        if not file:
            QMessageBox.warning(self,
                              self.tr("Create mobile collection"),
                              self.tr("Destination file not specified"))
            return

        density = self.densitySelector.currentText()
        settings = QSettings()
        settings.setValue('density', density)

        self.params['filter'] = self.filterSelector.itemData(self.filterSelector.currentIndex())
        self.params['density'] = density
        self.params['file'] = file
        if self.obverseRadio.isChecked():
            self.params['image'] = self.IMAGE_OBVERSE
        elif self.reverseRadio.isChecked():
            self.params['image'] = self.IMAGE_REVERSE
        else:
            self.params['image'] = self.IMAGE_BOTH
        self.params['fullimage'] = self.fullImage.isChecked()

        self.accept()
 def numberWithFraction(string, enabled=True):
    if enabled:
        try:
            if float(string) == 0.25:
                return '¼', True
            elif float(string) == 0.33:
                return '⅓', True
            elif float(string) == 0.5:
                return '½', True
            elif float(string) == 0.75:
                return '¾', True
            elif float(string) == 1.25:
                return '1¼', True
            elif float(string) == 1.5:
                return '1½', True
            elif float(string) == 2.5:
                return '2½', True
        except (ValueError, TypeError):
            pass

    return string, False
 def htmlToPlainText(text):
    RICH_PREFIX = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" '\
                  '"http://www.w3.org/TR/REC-html40/strict.dtd">'
    if text.startswith(RICH_PREFIX):
        document = QTextDocument()
        document.setHtml(text)
        text = document.toPlainText()

    return text

import codecs
import json
import locale
import os
import shutil
from PyQt5 import QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QImage, QPainter
from PyQt5.QtCore import Qt, pyqtSignal, QCryptographicHash
from PyQt5.QtSql import QSqlTableModel, QSqlDatabase, QSqlQuery, QSqlField
from OpenNumismat.Collection.CollectionFields import CollectionFieldsBase
from OpenNumismat.Collection.CollectionFields import FieldTypes as Type
from OpenNumismat.Collection.CollectionFields import CollectionFields
from OpenNumismat.Collection.CollectionFields import ImageFields
from OpenNumismat.Collection.CollectionPages import CollectionPages
from OpenNumismat.Collection.Password import cryptPassword, PasswordDialog
from OpenNumismat.Collection.Description import CollectionDescription
from OpenNumismat.Reference.Reference import Reference
from OpenNumismat.Reference.Reference import CrossReferenceSection
from OpenNumismat.Reference.ReferenceDialog import AllReferenceDialog
from OpenNumismat.EditCoinDialog.EditCoinDialog import EditCoinDialog
from OpenNumismat.Collection.CollectionFields import Statuses
from OpenNumismat.Collection.VersionUpdater import updateCollection
from OpenNumismat.Tools.CursorDecorators import waitCursorDecorator
from OpenNumismat.Tools import Gui
from OpenNumismat.Settings import Settings, BaseSettings
from OpenNumismat import version
from OpenNumismat.Collection.Export import ExportDialog
from OpenNumismat.Tools.Converters import numberWithFraction, htmlToPlainText
                            self.tr("Can't make a collection backup at %s") %
                                                                backupFileName)
            return False

        return True

    def isNeedBackup(self):
        settings = Settings()
        autobackup_depth = settings['autobackup_depth']
        filter_ = ('%s_????????????.db' % self.getCollectionName(),)
        files = QtCore.QDirIterator(settings['backup'], filter_, QtCore.QDir.Files)
        while files.hasNext():
            file = files.next()
            file_info = QtCore.QFileInfo(file)
            if file_info.completeSuffix() == 'db':
                file_title = file_info.baseName()
                file_date = file_title[-12:-6]

                query = QSqlQuery(self.db)
                query.prepare("SELECT count(*) FROM coins WHERE updatedat > ?")
                date = "20%s-%s-%sT23:59:59" % (file_date[0:2], file_date[2:4], file_date[4:6])
                query.addBindValue(date)
                query.exec_()
                query.first()
                if query.record().value(0) < autobackup_depth:
                    return False

        return True

    @waitCursorDecorator
    def vacuum(self):
        QSqlQuery("VACUUM", self.db)

    @staticmethod
    def fileNameToCollectionName(fileName):
        file = QtCore.QFileInfo(fileName)
        return file.baseName()

    def exportToMobile(self, params):
        IMAGE_FORMAT = 'jpg'
        SKIPPED_FIELDS = ('signatureimg', 'varietyimg', 'edgeimg', 'photo1', 'photo2', 'photo3', 'photo4', 'photo5', 'photo6',
            'obversedesigner', 'reversedesigner', 'catalognum2', 'catalognum3', 'catalognum4',
            'saledate', 'saleprice', 'totalsaleprice', 'buyer', 'saleplace', 'saleinfo',
            'paydate', 'payprice', 'totalpayprice', 'saller', 'payplace', 'payinfo',
            'url', 'obversedesigner', 'reversedesigner')

        if os.path.isfile(params['file']):
            os.remove(params['file'])

        db = QSqlDatabase.addDatabase('QSQLITE', 'mobile')
        db.setDatabaseName(params['file'])
        if not db.open():
            print(db.lastError().text())
            QMessageBox.critical(self.parent(),
                                       self.tr("Create mobile collection"),
                                       self.tr("Can't open collection"))
            return

        mobile_settings = {'Version': 5, 'Type': 'Mobile', 'Filter': params['filter']}

        QSqlQuery("PRAGMA synchronous=OFF", db)
        QSqlQuery("PRAGMA journal_mode=MEMORY", db)

        sql = """CREATE TABLE settings (
            title CHAR NOT NULL UNIQUE,
            value CHAR)"""
        QSqlQuery(sql, db)
        for key, value in mobile_settings.items():
            query = QSqlQuery(db)
            query.prepare("""INSERT INTO settings (title, value)
                    VALUES (?, ?)""")
            query.addBindValue(key)
            query.addBindValue(str(value))
            query.exec_()

        sql = """CREATE TABLE updates (
            title CHAR NOT NULL UNIQUE,
            value CHAR)"""
        QSqlQuery(sql, db)

        sql = """CREATE TABLE photos (
            id INTEGER PRIMARY KEY,
            image BLOB)"""
        QSqlQuery(sql, db)

        sqlFields = []
        fields = CollectionFieldsBase()
        for field in fields:
            if field.name == 'id':
                sqlFields.append('id INTEGER PRIMARY KEY')
            elif field.name == 'image':
                sqlFields.append('image INTEGER')
            elif field.name in SKIPPED_FIELDS:
                continue
            else:
                sqlFields.append("%s %s" % (field.name, Type.toSql(field.type)))

        sql = "CREATE TABLE coins (" + ", ".join(sqlFields) + ")"
        QSqlQuery(sql, db)

        model = self.model()
        while model.canFetchMore():
            model.fetchMore()

        dest_model = QSqlTableModel(self.parent(), db)
        dest_model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        dest_model.setTable('coins')
        dest_model.select()

        height = 64
        if params['density'] == 'HDPI':
            height *= 1.5
        elif params['density'] == 'XHDPI':
            height *= 2
        elif params['density'] == 'XXHDPI':
            height *= 3
        elif params['density'] == 'XXXHDPI':
            height *= 4
        maxHeight = height * 4


        is_obverse_enabled = params['image'] in (ExportDialog.IMAGE_OBVERSE, ExportDialog.IMAGE_BOTH)