예제 #1
0
    def on_start(self):
        """
        Additional procedures run on application start.
        """
        # Let's initialize even some stuff!
        self.al = None
        self.auth_thread = None
        self.init_backend()

        choose_db(str(self.availableDB.currentText()))
        self.showDB.setText("&Change DB (active: %s)" %
                            self.availableDB.currentText())

        self.stats = StatsUI(self.al, self)
예제 #2
0
파일: ui.py 프로젝트: Xifax/ransukan
    def on_start(self):
        """
        Additional procedures run on application start.
        """
        # Let's initialize even some stuff!
        self.al = None
        self.auth_thread = None
        self.init_backend()

        choose_db(str(self.availableDB.currentText()))
        self.showDB.setText("&Change DB (active: %s)" % self.availableDB.currentText())

        self.stats = StatsUI(self.al, self)
예제 #3
0
파일: ui.py 프로젝트: Xifax/ransukan
class GUI(QWidget):

    def __init__(self, parent=None):
        super(GUI, self).__init__(parent)

        self.create_ui_components()
        self.compose_ui()

        # Initializing: window composition, it's contents and event handlers
        self.init_composition()
        self.init_contents()
        self.init_actions()

        self.on_start()

    def create_ui_components(self):
        """
        Create layouts and qt controls.
        """
        self.layout = QGridLayout()

        self.kanjiGroup = QGroupBox()
        self.kanjiLayout = QGridLayout()

        # Kanji ui group
        self.day, self.week, self.month, self.year = \
        QLabel(KANJI), QLabel(KANJI), QLabel(KANJI), QLabel(KANJI)

        self.dayLabel, self.weekLabel, self.monthLabel, self.yearLabel = \
        QLabel('<b>Day</b>'), QLabel('<b>Week</b>'), \
        QLabel('<b>Month</b>'), QLabel('<b>Year</b>')

        # Main layout
        self.showAbout = QPushButton('A&bout')
        # DB controls (top)
        self.showDB, self.availableDB, self.changeDB = \
        QPushButton('&Change DB (active:)'), QComboBox(), QPushButton('&Remap')
        # General controls (bottom)
        self.getAll, self.showStats, self.quitApp, self.authGen, self.methodCombo = \
        QPushButton('&Get all'), QPushButton('&Stats'), QPushButton('&Quit'), \
        QPushButton('&Auth'), QComboBox()
        # Notifications
        self.progressBar = QProgressBar()
        self.statusMessage = QLabel()
        # About
        self.aboutBox = QMessageBox()

    def compose_ui(self):
        """
        Fill layouts and groups, initialize filters.
        """
        self.kanjiLayout.addWidget(self.day, 0, 0)
        self.kanjiLayout.addWidget(self.week, 0, 1)
        self.kanjiLayout.addWidget(self.dayLabel, 1, 0)
        self.kanjiLayout.addWidget(self.weekLabel, 1, 1)

        self.kanjiLayout.addWidget(self.month, 2, 0)
        self.kanjiLayout.addWidget(self.year, 2, 1)
        self.kanjiLayout.addWidget(self.monthLabel, 3, 0)
        self.kanjiLayout.addWidget(self.yearLabel, 3, 1)

        self.kanjiGroup.setLayout(self.kanjiLayout)

        self.layout.addWidget(self.showDB, 0, 0, 1, 2)
        self.layout.addWidget(self.availableDB, 1, 0)
        self.layout.addWidget(self.changeDB, 1, 1)
        self.layout.addWidget(self.kanjiGroup, 2, 0, 1, 2)
        self.layout.addWidget(self.getAll, 3, 0)
        self.layout.addWidget(self.showStats, 3, 1)
        self.layout.addWidget(self.methodCombo, 4, 0)
        self.layout.addWidget(self.authGen, 4, 1)
        #self.layout.addWidget(self.quitApp, 5, 0, 1, 2)
        self.layout.addWidget(self.quitApp, 5, 0)
        self.layout.addWidget(self.showAbout, 5, 1)
        self.layout.addWidget(self.progressBar, 6, 0, 1, 2)
        self.layout.addWidget(self.statusMessage, 7, 0, 1, 2)

        self.setLayout(self.layout)

        self.eFilter = LabelEventFilter()

    def on_start(self):
        """
        Additional procedures run on application start.
        """
        # Let's initialize even some stuff!
        self.al = None
        self.auth_thread = None
        self.init_backend()

        choose_db(str(self.availableDB.currentText()))
        self.showDB.setText("&Change DB (active: %s)" % self.availableDB.currentText())

        self.stats = StatsUI(self.al, self)

    def init_composition(self):
        """
        Window composition and general params.
        """
        self.setWindowTitle(NAME + ' ' + __version__)
        desktop = QApplication.desktop()
        self.setGeometry((desktop.width() - WIDTH)/2,
                        (desktop.height() - HEIGHT)/2, WIDTH, HEIGHT)

    def init_contents(self):
        """
        Setting up qt controls.
        """
        self.changeDB.hide()
        self.availableDB.hide()
        self.availableDB.addItems(dbs.keys())

        self.kanjiGroup.setAlignment(Qt.AlignCenter)
        self.kanjiGroup.setStyleSheet("QGroupBox { border: 1px solid gray; border-radius: 3px; }")

        self.day.setAlignment(Qt.AlignCenter)
        self.week.setAlignment(Qt.AlignCenter)
        self.month.setAlignment(Qt.AlignCenter)
        self.year.setAlignment(Qt.AlignCenter)
        self.dayLabel.setAlignment(Qt.AlignCenter)
        self.weekLabel.setAlignment(Qt.AlignCenter)
        self.monthLabel.setAlignment(Qt.AlignCenter)
        self.yearLabel.setAlignment(Qt.AlignCenter)

        self.day.setFont(QFont(PRETTY_FONT, KANJI_SIZE))
        self.week.setFont(QFont(PRETTY_FONT, KANJI_SIZE))
        self.month.setFont(QFont(PRETTY_FONT, KANJI_SIZE))
        self.year.setFont(QFont(PRETTY_FONT, KANJI_SIZE))

        self.methodCombo.addItems(RandomMess.algs.keys())
        self.methodCombo.setCurrentIndex(1)

        self.statusMessage.setAlignment(Qt.AlignCenter)
        self.statusMessage.hide()
        self.statusMessage.setMaximumHeight(MESSAGE_HEIGHT)
        self.statusMessage.setStyleSheet(WARNING_STYLE)

        self.progressBar.setMaximum(0)
        self.progressBar.setMaximumHeight(PROGRESS_HEIGHT)
        self.progressBar.hide()

        QToolTip.setFont(QFont(PRETTY_FONT, TOOLTIP_FONT_SIZE))

        self.getAll.setToolTip('Randomly select all 4 kanji')
        self.methodCombo.setToolTip('Choose algorithm for randomness')
        self.authGen.setToolTip('Authorize on remote RNG services')
        self.showStats.setToolTip('Show/hide dialog with comprehensive statistics')
        self.quitApp.setToolTip('Close application')
        self.showDB.setToolTip('Show/hide available databases')
        self.availableDB.setToolTip('Available kanji frequency charts db')
        self.changeDB.setToolTip('Pick new kanji from currently selected db')

        # About dialog
        self.aboutBox.layout().itemAt(1).widget().setAlignment(Qt.AlignLeft)

        self.aboutBox.setTextFormat(Qt.RichText)
        self.aboutBox.setText('Version:\t<b>' + __version__ + '</b><br/>Python:\t<b>' + platform.python_version() + '</b>' +
                                '<br/>Platform:\t<b>' + platform.system() + ' ' + platform.release() + '</b>' +
                                '<br/>Author:\t<b>' + __author__ + '</b>' + app_about)
        self.aboutBox.setWindowTitle('About ' + app_name)
        self.aboutBox.setIconPixmap(QPixmap(paths['icon']))

    def init_actions(self):
        """
        Binding events/handlers.
        """
        self.showDB.clicked.connect(self.show_available_db)
        self.changeDB.clicked.connect(self.change_db)

        self.quitApp.clicked.connect(self.close)
        self.getAll.clicked.connect(self.get_all)
        self.authGen.clicked.connect(self.auth_task)
        self.showStats.clicked.connect(self.show_stats)
        self.methodCombo.currentIndexChanged.connect(self.update_alg)

        self.showAbout.clicked.connect(self.app_help)

        # Mouse events for labels
        self.day.setAttribute(Qt.WA_Hover, True)
        self.week.setAttribute(Qt.WA_Hover, True)
        self.month.setAttribute(Qt.WA_Hover, True)
        self.year.setAttribute(Qt.WA_Hover, True)
        self.day.installEventFilter(self.eFilter)
        self.week.installEventFilter(self.eFilter)
        self.month.installEventFilter(self.eFilter)
        self.year.installEventFilter(self.eFilter)

    ##### actions #####

    def show_stats(self):
        if self.stats.isVisible():
            self.stats.hide()
        else:
            self.stats.show()

    def show_available_db(self):
        if self.availableDB.isVisible():
            self.availableDB.hide()
            self.changeDB.hide()
        else:
            self.availableDB.show()
            self.changeDB.show()

    def change_db(self):
        try:
            choose_db(str(self.availableDB.currentText()))
            self.availableDB.hide()
            self.changeDB.hide()
            self.show_message_then_hide("DB successfully remaped!", False)
            self.showDB.setText("&Change DB (active: %s)" % self.availableDB.currentText())

            self.stats.update_stat_info()
            self.stats.refresh_plot()
        except NoDbException as e:
            self.show_message_then_hide(e.message)

    def get_all(self):
        self.random_kanji_task = RandomKanjiTask(self.al)
        self.random_kanji_task.done.connect(self.update_kanji)
        self.show_progress('Selecting kanji...')
        self.random_kanji_task.start()

    def update_kanji(self, results):
        if results['success']:
            kanji_set = results['kanji_set']
            for_a_day = kanji_set.pop()
            for_a_week = kanji_set.pop()
            for_a_month = kanji_set.pop()
            for_a_year = kanji_set.pop()

            self.day.setText(for_a_day.character)
            self.dayLabel.setText('<b>Day:</b> ' + str(for_a_day.frequency) + ' | '
                                        + str(for_a_day.dominance) + '%')
            self.week.setText(for_a_week.character)
            self.weekLabel.setText('<b>Week:</b> ' + str(for_a_week.frequency) + ' | '
                                        + str(for_a_week.dominance) + '%')
            self.month.setText(for_a_month.character)
            self.monthLabel.setText('<b>Month:</b> ' + str(for_a_month.frequency) + ' | '
                                        + str(for_a_month.dominance) + '%')
            self.year.setText(for_a_year.character)
            self.yearLabel.setText('<b>Year:</b> ' + str(for_a_year.frequency) + ' | '
                                        + str(for_a_year.dominance) + '%')

            self.kanji_tooltip(self.day)
            self.kanji_tooltip(self.week)
            self.kanji_tooltip(self.month)
            self.kanji_tooltip(self.year)

            if self.stats.isVisible():
                self.stats.update_stat_info()
                self.stats.refresh_plot()

            self.hide_message()
        else:
            self.show_message_then_hide(results['message'])

        self.hide_progress()

    def pretty_font(self):
        pass

    def update_alg(self):
        self.al.set_active(str(self.methodCombo.currentText()))

    def init_backend(self):
        self.al = RandomMess()
        self.update_alg()

    def auth_task(self):
        self.auth_thread = AuthorizationTask(self.al)
        self.auth_thread.done.connect(self.auth_complete)
        #self.auth_thread.run()
        # IT DOESN't work on windows as it should!
        self.auth_thread.start()
        self.show_progress('Authorizing on RNG services...')

    def auth_complete(self, success):
        self.hide_message()
        self.hide_progress()
        if success:
            self.show_message_then_hide("Successfully authenticated!", False)
        else:
            self.show_message_then_hide("Sorry, could not authenticate.")

    def show_message_then_hide(self, message, error=True):
        if error:
            self.statusMessage.setStyleSheet(WARNING_STYLE)
        else:
            self.statusMessage.setStyleSheet(NOTE_STYLE)

        self.statusMessage.setText(message)
        self.statusMessage.show()
        QTimer.singleShot(MESSAGE_TIMEOUT, self.hide_message)

    def show_progress(self, message):
        self.statusMessage.setStyleSheet(NOTE_STYLE)
        self.statusMessage.setText(message)
        self.statusMessage.show()
        self.progressBar.show()

    def hide_message(self):
        self.statusMessage.setText('')
        self.statusMessage.hide()

    def hide_progress(self):
        self.progressBar.hide()

    def toggle_kanji_info(self, label, info):
        label.setToolTip(info.info())

    def kanji_tooltip(self, label):
        found = JDIC.search(label.text())
        if found:
            label.setToolTip(found.info())
        else:
            label.setToolTip('No such kanji in kanjidic2!')

    def kanji_info(self, kanji):
        pass

    def app_help(self):
        self.aboutBox.show()

        #### Utility events ####

    def resizeEvent(self, QResizeEvent):
        self.updateStatsPosition()
        self.updateStatsSize()

    def moveEvent(self, QMoveEvent):
        self.updateStatsPosition()
        self.updateStatsSize()

    def updateStatsPosition(self):
        self.stats.move(self.x() + self.width() + 20, self.y())

    def updateStatsSize(self):
        self.stats.resize(QSize(self.stats.width(), self.height()))
예제 #4
0
class GUI(QWidget):
    def __init__(self, parent=None):
        super(GUI, self).__init__(parent)

        self.create_ui_components()
        self.compose_ui()

        # Initializing: window composition, it's contents and event handlers
        self.init_composition()
        self.init_contents()
        self.init_actions()

        self.on_start()

    def create_ui_components(self):
        """
        Create layouts and qt controls.
        """
        self.layout = QGridLayout()

        self.kanjiGroup = QGroupBox()
        self.kanjiLayout = QGridLayout()

        # Kanji ui group
        self.day, self.week, self.month, self.year = \
        QLabel(KANJI), QLabel(KANJI), QLabel(KANJI), QLabel(KANJI)

        self.dayLabel, self.weekLabel, self.monthLabel, self.yearLabel = \
        QLabel('<b>Day</b>'), QLabel('<b>Week</b>'), \
        QLabel('<b>Month</b>'), QLabel('<b>Year</b>')

        # Main layout
        self.showAbout = QPushButton('A&bout')
        # DB controls (top)
        self.showDB, self.availableDB, self.changeDB = \
        QPushButton('&Change DB (active:)'), QComboBox(), QPushButton('&Remap')
        # General controls (bottom)
        self.getAll, self.showStats, self.quitApp, self.authGen, self.methodCombo = \
        QPushButton('&Get all'), QPushButton('&Stats'), QPushButton('&Quit'), \
        QPushButton('&Auth'), QComboBox()
        # Notifications
        self.progressBar = QProgressBar()
        self.statusMessage = QLabel()
        # About
        self.aboutBox = QMessageBox()

    def compose_ui(self):
        """
        Fill layouts and groups, initialize filters.
        """
        self.kanjiLayout.addWidget(self.day, 0, 0)
        self.kanjiLayout.addWidget(self.week, 0, 1)
        self.kanjiLayout.addWidget(self.dayLabel, 1, 0)
        self.kanjiLayout.addWidget(self.weekLabel, 1, 1)

        self.kanjiLayout.addWidget(self.month, 2, 0)
        self.kanjiLayout.addWidget(self.year, 2, 1)
        self.kanjiLayout.addWidget(self.monthLabel, 3, 0)
        self.kanjiLayout.addWidget(self.yearLabel, 3, 1)

        self.kanjiGroup.setLayout(self.kanjiLayout)

        self.layout.addWidget(self.showDB, 0, 0, 1, 2)
        self.layout.addWidget(self.availableDB, 1, 0)
        self.layout.addWidget(self.changeDB, 1, 1)
        self.layout.addWidget(self.kanjiGroup, 2, 0, 1, 2)
        self.layout.addWidget(self.getAll, 3, 0)
        self.layout.addWidget(self.showStats, 3, 1)
        self.layout.addWidget(self.methodCombo, 4, 0)
        self.layout.addWidget(self.authGen, 4, 1)
        #self.layout.addWidget(self.quitApp, 5, 0, 1, 2)
        self.layout.addWidget(self.quitApp, 5, 0)
        self.layout.addWidget(self.showAbout, 5, 1)
        self.layout.addWidget(self.progressBar, 6, 0, 1, 2)
        self.layout.addWidget(self.statusMessage, 7, 0, 1, 2)

        self.setLayout(self.layout)

        self.eFilter = LabelEventFilter()

    def on_start(self):
        """
        Additional procedures run on application start.
        """
        # Let's initialize even some stuff!
        self.al = None
        self.auth_thread = None
        self.init_backend()

        choose_db(str(self.availableDB.currentText()))
        self.showDB.setText("&Change DB (active: %s)" %
                            self.availableDB.currentText())

        self.stats = StatsUI(self.al, self)

    def init_composition(self):
        """
        Window composition and general params.
        """
        self.setWindowTitle(NAME + ' ' + __version__)
        desktop = QApplication.desktop()
        self.setGeometry((desktop.width() - WIDTH) / 2,
                         (desktop.height() - HEIGHT) / 2, WIDTH, HEIGHT)

    def init_contents(self):
        """
        Setting up qt controls.
        """
        self.changeDB.hide()
        self.availableDB.hide()
        self.availableDB.addItems(dbs.keys())

        self.kanjiGroup.setAlignment(Qt.AlignCenter)
        self.kanjiGroup.setStyleSheet(
            "QGroupBox { border: 1px solid gray; border-radius: 3px; }")

        self.day.setAlignment(Qt.AlignCenter)
        self.week.setAlignment(Qt.AlignCenter)
        self.month.setAlignment(Qt.AlignCenter)
        self.year.setAlignment(Qt.AlignCenter)
        self.dayLabel.setAlignment(Qt.AlignCenter)
        self.weekLabel.setAlignment(Qt.AlignCenter)
        self.monthLabel.setAlignment(Qt.AlignCenter)
        self.yearLabel.setAlignment(Qt.AlignCenter)

        self.day.setFont(QFont(PRETTY_FONT, KANJI_SIZE))
        self.week.setFont(QFont(PRETTY_FONT, KANJI_SIZE))
        self.month.setFont(QFont(PRETTY_FONT, KANJI_SIZE))
        self.year.setFont(QFont(PRETTY_FONT, KANJI_SIZE))

        self.methodCombo.addItems(RandomMess.algs.keys())
        self.methodCombo.setCurrentIndex(1)

        self.statusMessage.setAlignment(Qt.AlignCenter)
        self.statusMessage.hide()
        self.statusMessage.setMaximumHeight(MESSAGE_HEIGHT)
        self.statusMessage.setStyleSheet(WARNING_STYLE)

        self.progressBar.setMaximum(0)
        self.progressBar.setMaximumHeight(PROGRESS_HEIGHT)
        self.progressBar.hide()

        QToolTip.setFont(QFont(PRETTY_FONT, TOOLTIP_FONT_SIZE))

        self.getAll.setToolTip('Randomly select all 4 kanji')
        self.methodCombo.setToolTip('Choose algorithm for randomness')
        self.authGen.setToolTip('Authorize on remote RNG services')
        self.showStats.setToolTip(
            'Show/hide dialog with comprehensive statistics')
        self.quitApp.setToolTip('Close application')
        self.showDB.setToolTip('Show/hide available databases')
        self.availableDB.setToolTip('Available kanji frequency charts db')
        self.changeDB.setToolTip('Pick new kanji from currently selected db')

        # About dialog
        self.aboutBox.layout().itemAt(1).widget().setAlignment(Qt.AlignLeft)

        self.aboutBox.setTextFormat(Qt.RichText)
        self.aboutBox.setText('Version:\t<b>' + __version__ +
                              '</b><br/>Python:\t<b>' +
                              platform.python_version() + '</b>' +
                              '<br/>Platform:\t<b>' + platform.system() + ' ' +
                              platform.release() + '</b>' +
                              '<br/>Author:\t<b>' + __author__ + '</b>' +
                              app_about)
        self.aboutBox.setWindowTitle('About ' + app_name)
        self.aboutBox.setIconPixmap(QPixmap(paths['icon']))

    def init_actions(self):
        """
        Binding events/handlers.
        """
        self.showDB.clicked.connect(self.show_available_db)
        self.changeDB.clicked.connect(self.change_db)

        self.quitApp.clicked.connect(self.close)
        self.getAll.clicked.connect(self.get_all)
        self.authGen.clicked.connect(self.auth_task)
        self.showStats.clicked.connect(self.show_stats)
        self.methodCombo.currentIndexChanged.connect(self.update_alg)

        self.showAbout.clicked.connect(self.app_help)

        # Mouse events for labels
        self.day.setAttribute(Qt.WA_Hover, True)
        self.week.setAttribute(Qt.WA_Hover, True)
        self.month.setAttribute(Qt.WA_Hover, True)
        self.year.setAttribute(Qt.WA_Hover, True)
        self.day.installEventFilter(self.eFilter)
        self.week.installEventFilter(self.eFilter)
        self.month.installEventFilter(self.eFilter)
        self.year.installEventFilter(self.eFilter)

    ##### actions #####

    def show_stats(self):
        if self.stats.isVisible():
            self.stats.hide()
        else:
            self.stats.show()

    def show_available_db(self):
        if self.availableDB.isVisible():
            self.availableDB.hide()
            self.changeDB.hide()
        else:
            self.availableDB.show()
            self.changeDB.show()

    def change_db(self):
        try:
            choose_db(str(self.availableDB.currentText()))
            self.availableDB.hide()
            self.changeDB.hide()
            self.show_message_then_hide("DB successfully remaped!", False)
            self.showDB.setText("&Change DB (active: %s)" %
                                self.availableDB.currentText())

            self.stats.update_stat_info()
            self.stats.refresh_plot()
        except NoDbException as e:
            self.show_message_then_hide(e.message)

    def get_all(self):
        self.random_kanji_task = RandomKanjiTask(self.al)
        self.random_kanji_task.done.connect(self.update_kanji)
        self.show_progress('Selecting kanji...')
        self.random_kanji_task.start()

    def update_kanji(self, results):
        if results['success']:
            kanji_set = results['kanji_set']
            for_a_day = kanji_set.pop()
            for_a_week = kanji_set.pop()
            for_a_month = kanji_set.pop()
            for_a_year = kanji_set.pop()

            self.day.setText(for_a_day.character)
            self.dayLabel.setText('<b>Day:</b> ' + str(for_a_day.frequency) +
                                  ' | ' + str(for_a_day.dominance) + '%')
            self.week.setText(for_a_week.character)
            self.weekLabel.setText('<b>Week:</b> ' +
                                   str(for_a_week.frequency) + ' | ' +
                                   str(for_a_week.dominance) + '%')
            self.month.setText(for_a_month.character)
            self.monthLabel.setText('<b>Month:</b> ' +
                                    str(for_a_month.frequency) + ' | ' +
                                    str(for_a_month.dominance) + '%')
            self.year.setText(for_a_year.character)
            self.yearLabel.setText('<b>Year:</b> ' +
                                   str(for_a_year.frequency) + ' | ' +
                                   str(for_a_year.dominance) + '%')

            self.kanji_tooltip(self.day)
            self.kanji_tooltip(self.week)
            self.kanji_tooltip(self.month)
            self.kanji_tooltip(self.year)

            if self.stats.isVisible():
                self.stats.update_stat_info()
                self.stats.refresh_plot()

            self.hide_message()
        else:
            self.show_message_then_hide(results['message'])

        self.hide_progress()

    def pretty_font(self):
        pass

    def update_alg(self):
        self.al.set_active(str(self.methodCombo.currentText()))

    def init_backend(self):
        self.al = RandomMess()
        self.update_alg()

    def auth_task(self):
        self.auth_thread = AuthorizationTask(self.al)
        self.auth_thread.done.connect(self.auth_complete)
        #self.auth_thread.run()
        # IT DOESN't work on windows as it should!
        self.auth_thread.start()
        self.show_progress('Authorizing on RNG services...')

    def auth_complete(self, success):
        self.hide_message()
        self.hide_progress()
        if success:
            self.show_message_then_hide("Successfully authenticated!", False)
        else:
            self.show_message_then_hide("Sorry, could not authenticate.")

    def show_message_then_hide(self, message, error=True):
        if error:
            self.statusMessage.setStyleSheet(WARNING_STYLE)
        else:
            self.statusMessage.setStyleSheet(NOTE_STYLE)

        self.statusMessage.setText(message)
        self.statusMessage.show()
        QTimer.singleShot(MESSAGE_TIMEOUT, self.hide_message)

    def show_progress(self, message):
        self.statusMessage.setStyleSheet(NOTE_STYLE)
        self.statusMessage.setText(message)
        self.statusMessage.show()
        self.progressBar.show()

    def hide_message(self):
        self.statusMessage.setText('')
        self.statusMessage.hide()

    def hide_progress(self):
        self.progressBar.hide()

    def toggle_kanji_info(self, label, info):
        label.setToolTip(info.info())

    def kanji_tooltip(self, label):
        found = JDIC.search(label.text())
        if found:
            label.setToolTip(found.info())
        else:
            label.setToolTip('No such kanji in kanjidic2!')

    def kanji_info(self, kanji):
        pass

    def app_help(self):
        self.aboutBox.show()

        #### Utility events ####

    def resizeEvent(self, QResizeEvent):
        self.updateStatsPosition()
        self.updateStatsSize()

    def moveEvent(self, QMoveEvent):
        self.updateStatsPosition()
        self.updateStatsSize()

    def updateStatsPosition(self):
        self.stats.move(self.x() + self.width() + 20, self.y())

    def updateStatsSize(self):
        self.stats.resize(QSize(self.stats.width(), self.height()))