Esempio n. 1
0
class DBRestore(QDialog):

    update_signal = pyqtSignal(object, object)

    def __init__(self, parent, library_path, wait_time=2):
        QDialog.__init__(self, parent)
        self.l = QVBoxLayout()
        self.setLayout(self.l)
        self.l1 = QLabel('<b>'+_('Restoring database from backups, do not'
            ' interrupt, this will happen in three stages')+'...')
        self.setWindowTitle(_('Restoring database'))
        self.l.addWidget(self.l1)
        self.pb = QProgressBar(self)
        self.l.addWidget(self.pb)
        self.pb.setMaximum(0)
        self.pb.setMinimum(0)
        self.msg = QLabel('')
        self.l.addWidget(self.msg)
        self.msg.setWordWrap(True)
        self.bb = QDialogButtonBox(QDialogButtonBox.Cancel)
        self.l.addWidget(self.bb)
        self.bb.rejected.connect(self.reject)
        self.resize(self.sizeHint() + QSize(100, 50))
        self.error = None
        self.rejected = False
        self.library_path = library_path
        self.update_signal.connect(self.do_update, type=Qt.QueuedConnection)

        from calibre.db.restore import Restore
        self.restorer = Restore(library_path, self)
        self.restorer.daemon = True

        # Give the metadata backup thread time to stop
        QTimer.singleShot(wait_time * 1000, self.start)

    def start(self):
        self.restorer.start()
        QTimer.singleShot(10, self.update)

    def reject(self):
        self.rejected = True
        self.restorer.progress_callback = lambda x, y: x
        QDialog.reject(self)

    def update(self):
        if self.restorer.is_alive():
            QTimer.singleShot(10, self.update)
        else:
            self.restorer.progress_callback = lambda x, y: x
            self.accept()

    def __call__(self, msg, step):
        self.update_signal.emit(msg, step)

    def do_update(self, msg, step):
        if msg is None:
            self.pb.setMaximum(step)
        else:
            self.msg.setText(msg)
            self.pb.setValue(step)
Esempio n. 2
0
class DBRestore(QDialog):

    update_signal = pyqtSignal(object, object)

    def __init__(self, parent, library_path, wait_time=2):
        QDialog.__init__(self, parent)
        self.l = QVBoxLayout()
        self.setLayout(self.l)
        self.l1 = QLabel('<b>'+_('Restoring database from backups, do not'
            ' interrupt, this will happen in three stages')+'...')
        self.setWindowTitle(_('Restoring database'))
        self.l.addWidget(self.l1)
        self.pb = QProgressBar(self)
        self.l.addWidget(self.pb)
        self.pb.setMaximum(0)
        self.pb.setMinimum(0)
        self.msg = QLabel('')
        self.l.addWidget(self.msg)
        self.msg.setWordWrap(True)
        self.bb = QDialogButtonBox(QDialogButtonBox.Cancel)
        self.l.addWidget(self.bb)
        self.bb.rejected.connect(self.reject)
        self.resize(self.sizeHint() + QSize(100, 50))
        self.error = None
        self.rejected = False
        self.library_path = library_path
        self.update_signal.connect(self.do_update, type=Qt.QueuedConnection)

        from calibre.db.restore import Restore
        self.restorer = Restore(library_path, self)
        self.restorer.daemon = True

        # Give the metadata backup thread time to stop
        QTimer.singleShot(wait_time * 1000, self.start)

    def start(self):
        self.restorer.start()
        QTimer.singleShot(10, self.update)

    def reject(self):
        self.rejected = True
        self.restorer.progress_callback = lambda x, y: x
        QDialog.reject(self)

    def update(self):
        if self.restorer.is_alive():
            QTimer.singleShot(10, self.update)
        else:
            self.restorer.progress_callback = lambda x, y: x
            self.accept()

    def __call__(self, msg, step):
        self.update_signal.emit(msg, step)

    def do_update(self, msg, step):
        if msg is None:
            self.pb.setMaximum(step)
        else:
            self.msg.setText(msg)
            self.pb.setValue(step)
Esempio n. 3
0
class FluterDownloaderDialog(QDialog):
    def __init__(self, gui, icon, do_user_config):
        QDialog.__init__(self, gui)
        self.gui = gui
        self.do_user_config = do_user_config

        self.db = gui.current_db

        self.l = QVBoxLayout()
        self.setLayout(self.l)

        self.label = QLabel(
            "This plugin helps download last issues from fluter.de")
        self.l.addWidget(self.label)

        self.setWindowTitle("Unofficial fluter. Downloader")
        self.setWindowIcon(icon)

        self.progress_bar = QProgressBar(self)
        self.l.addWidget(self.progress_bar)

        self.progress_label = QLabel("Waiting to start")
        self.l.addWidget(self.progress_label)

        self.add_button = QPushButton("Download new fluter. issues", self)
        self.add_button.clicked.connect(self.add_fluter)
        self.l.addWidget(self.add_button)

        self.conf_button = QPushButton("Configure", self)
        self.conf_button.clicked.connect(self.config)
        self.l.addWidget(self.conf_button)

        self.about_button = QPushButton("About", self)
        self.about_button.clicked.connect(self.about)
        self.l.addWidget(self.about_button)

        self.resize(self.sizeHint())

    def about(self):
        text = get_resources("about.txt")
        QMessageBox.about(self, "About the fluter. Downloader",
                          text.decode("utf-8"))

    def config(self):
        self.do_user_config(parent=self)

    def add_fluter(self):
        self.progress_bar.reset()
        self.progress_label.setText("")

        downloader = FluterDownloader(prefs["max_numbers"],
                                      self.db.new_api,
                                      reporter=self._report_progress)
        downloader.download()
        self.gui.refresh_all()

    def _report_progress(self, value: float, text: str):
        self.progress_label.setText(text)
        self.progress_bar.setValue(100.0 * value)
Esempio n. 4
0
class EvalWizardStep2Window(QMainWindow):

    def __init__(self, wav_files, output_directory, network_location):
        QMainWindow.__init__(self)

        self.wav_files = wav_files
        self.output_directory = output_directory
        self.network_location = network_location

        self.setMinimumSize(QSize(900, 500))
        self.setWindowTitle("Diarization - Diarize Files (Step 2 of 2)")

        centralWidget = QWidget(self)
        self.setCentralWidget(centralWidget)

        gridLayout = QGridLayout(self)
        centralWidget.setLayout(gridLayout)

        title = QLabel("Please Wait While The .wav Files Are Annotated", self)
        title.setAlignment(QtCore.Qt.AlignCenter)

        self._all_files_progress = QProgressBar(self)
        self._all_files_progress.setMinimum(1)
        self._all_files_progress.setMaximum(len(wav_files))

        self._file_name_lbl = QLabel("File: ", self)
        self._file_name_lbl.setAlignment(QtCore.Qt.AlignCenter)

        self._file_progress_lbl = QLabel("0%", self)
        self._file_progress_lbl.setAlignment(QtCore.Qt.AlignCenter)

        gridLayout.setRowStretch(0, 0)
        gridLayout.addWidget(title, 1, 0)
        gridLayout.setRowStretch(2, 0)
        gridLayout.addWidget(self._all_files_progress, 3, 0)
        gridLayout.addWidget(self._file_name_lbl, 4, 0)
        gridLayout.addWidget(self._file_progress_lbl, 5, 0)
        gridLayout.setRowStretch(49, 0)
        gridLayout.setRowStretch(50, 0)

        thread = Thread(target=self.exe_controler, args=())
        thread.start()

    def exe_controler(self):
        # net = network.open(self.network_location)
        i = 0
        for file_name in self.wav_files:
            self._file_name_lbl.setText("File: " + file_name)
            # net.annotate_wav_file(file_name, self.output_directory)

            time.sleep(0.1)  # Delete This Line Shortly
            self._all_files_progress.setValue(i)
            self._file_progress_lbl.setText(str(i * 100 / len(self.wav_files)) + "%")
            i += 1
        self._all_files_progress.setValue(len(self.wav_files))
        self._file_progress_lbl.setText("100%; Your files have now been annotated. Please close this window.")
Esempio n. 5
0
    def create_state_labels(self, state_name):
        """
        Generate 4 QLabel and 1 QProgressBar and store them in "state_data"
        QLabels are: state_icon | state_text | state_number | state_diff
        QProgressBar get value of percent.
        All are added on one row define by "row" value

        :param state_name: name of the state to be stored
        :type state_name: str
        """

        # Icon
        icon = QPixmap(get_image_path(state_name))
        state_icon = QLabel()
        state_icon.setFixedSize(16, 16)
        state_icon.setScaledContents(True)
        state_icon.setPixmap(icon)

        # Initialize Labels
        state_text = QLabel(self.define_label(state_name))
        state_number = QLabel()
        state_diff = QLabel()

        # QProgressBar
        progress_bar = QProgressBar()
        progress_bar.setValue(0)
        progress_bar.setFixedHeight(20)
        progress_bar.setObjectName(state_name)

        # Layout
        self.main_layout.addWidget(state_icon, self.row, 0)
        self.main_layout.addWidget(state_text, self.row, 1)
        self.main_layout.addWidget(state_number, self.row, 2)
        self.main_layout.setAlignment(state_number, Qt.AlignCenter)
        self.main_layout.addWidget(state_diff, self.row, 3)
        self.main_layout.addWidget(progress_bar, self.row, 4)

        # Store state
        self.state_data[state_name] = {
            'icon': state_icon,
            'state_number': state_number,
            'diff': state_diff,
            'progress_bar': progress_bar
        }

        # Increment vertically position for next widget
        self.row += 1
Esempio n. 6
0
class Downloader(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        layout = QVBoxLayout()

        self.url = QLineEdit()
        self.url.setPlaceholderText("URL")
        self.save_location = QLineEdit("File save location")
        self.progressbar = QProgressBar()
        download = QPushButton("Download")

        self.progressbar.setValue(0)
        self.progressbar.setAlignment(Qt.AlignHCenter)
        layout.addWidget(self.url)
        layout.addWidget(self.save_location)
        layout.addWidget(self.progressbar)
        layout.addWidget(download)

        self.setLayout(layout)
        self.setWindowTitle("Python Downloader using PyQt5")
        self.setFocus()

        download.clicked.connect(self.download)

    def download(self):
        url = self.url.text()
        save_location = self.save_location.text()
        urllib.request.urlretrieve(url, save_location, self.report)

    def report(self, blocknum, blocksize, totalsize):
        print(blocknum, blocksize, totalsize)
        readsofar = blocknum * blocksize

        if totalsize > 0:
            percent = readsofar * 100 / totalsize
            print(percent)
            self.progressbar.setValue(int(percent))
Esempio n. 7
0
class ProgressBar(QDialog):
    def __init__(self,
                 parent=None,
                 max_items=100,
                 window_title='Progress Bar',
                 label='',
                 on_top=False):
        if on_top:
            QDialog.__init__(self,
                             parent=parent,
                             flags=Qt.WindowStaysOnTopHint)
        else:
            QDialog.__init__(self, parent=parent)
        self.application = Application
        self.setWindowTitle(window_title)
        self.l = QVBoxLayout(self)
        self.setLayout(self.l)

        self.label = QLabel(label)
        self.label.setAlignment(Qt.AlignHCenter)
        self.l.addWidget(self.label)

        self.progressBar = QProgressBar(self)
        self.progressBar.setRange(0, max_items)
        self.progressBar.setValue(0)
        self.l.addWidget(self.progressBar)

    def increment(self):
        self.progressBar.setValue(self.progressBar.value() + 1)
        self.refresh()

    def refresh(self):
        self.application.processEvents()

    def set_label(self, value):
        self.label.setText(value)
        self.refresh()

    def left_align_label(self):
        self.label.setAlignment(Qt.AlignLeft)

    def set_maximum(self, value):
        self.progressBar.setMaximum(value)
        self.refresh()

    def set_value(self, value):
        self.progressBar.setValue(value)
        self.refresh()

    def set_progress_format(self, progress_format=None):
        pass
Esempio n. 8
0
class ProgressBar(QDialog):
    def __init__(self, parent=None, max_items=100, window_title='Progress Bar',
                 label='Label goes here', on_top=False):
        if on_top:
            QDialog.__init__(self, parent=parent, flags=Qt.WindowStaysOnTopHint)
        else:
            QDialog.__init__(self, parent=parent)
        self.application = Application
        self.setWindowTitle(window_title)
        self.l = QVBoxLayout(self)
        self.setLayout(self.l)

        self.label = QLabel(label)
        self.label.setAlignment(Qt.AlignHCenter)
        self.l.addWidget(self.label)

        self.progressBar = QProgressBar(self)
        self.progressBar.setRange(0, max_items)
        self.progressBar.setValue(0)
        self.l.addWidget(self.progressBar)

    def increment(self):
        self.progressBar.setValue(self.progressBar.value() + 1)
        self.refresh()

    def refresh(self):
        self.application.processEvents()

    def set_label(self, value):
        self.label.setText(value)
        self.refresh()

    def set_maximum(self, value):
        self.progressBar.setMaximum(value)
        self.refresh()

    def set_value(self, value):
        self.progressBar.setValue(value)
        self.refresh()
Esempio n. 9
0
class ConvertDialog(QDialog):

    hide_text = _('&Hide styles')
    show_text = _('&Show styles')
    prince_log = ''
    prince_file = ''
    prince_css = ''

    # GUI definition
    def __init__(self, mi, fmt, opf, oeb, icon):
        '''
        :param mi: The book metadata
        :param fmt: The source format used for conversion
        :param opf: The path to the OPF file
        :param oeb: An OEB object for the unpacked book
        :param icon: The window icon
        '''
        self.opf = opf
        self.oeb = oeb
        self.mi = mi
        # The unpacked book needs to be parsed before, to read the contents
        # of the prince-style file, if it exists
        self.parse()

        QDialog.__init__(self)

        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setWindowTitle(_('Convert to PDF with Prince'))
        self.setWindowIcon(icon)

        self.l = QVBoxLayout()
        self.setLayout(self.l)

        self.title_label = QLabel(_('<b>Title:</b> %s') % self.mi.title)
        self.l.addWidget(self.title_label)

        self.format_label = QLabel(_('<b>Source format:</b> %s') % fmt)
        self.l.addWidget(self.format_label)

        self.add_book = QCheckBox(_('&Add PDF to the book record'))
        self.add_book.setToolTip(
            _('<qt>Add the converted PDF to the selected book record</qt>'))
        self.add_book.setChecked(prefs['add_book'])
        self.add_book.stateChanged.connect(self.set_add_book)
        self.l.addWidget(self.add_book)

        self.ll = QHBoxLayout()
        self.ll.setAlignment(Qt.AlignLeft)
        self.l.addLayout(self.ll)

        self.label_css = QLabel(_('&Custom style:'))
        self.ll.addWidget(self.label_css)

        self.css_list = QComboBox()
        self.css_list.setToolTip(
            _('<qt>Select one style to use. Additional styles can be created in the plugin configuration</qt>'
              ))
        for key in sorted(prefs['custom_CSS_list'], key=lambda x: x.lower()):
            self.css_list.addItem(key, key)
        self.css_list.setCurrentIndex(
            self.css_list.findText(prefs['default_CSS']))
        self.css_list.currentIndexChanged.connect(self.set_css)
        self.ll.addWidget(self.css_list)
        self.label_css.setBuddy(self.css_list)

        self.ll_ = QHBoxLayout()
        self.l.addLayout(self.ll_)

        self.label_args = QLabel(_('A&dditional command-line arguments:'))
        self.ll_.addWidget(self.label_args)

        self.args = QLineEdit(self)
        self.args.setText(prefs['custom_args_list'][prefs['default_CSS']])
        self.args.setToolTip(
            _('<qt>Specify additional command-line arguments for the conversion</qt>'
              ))
        self.ll_.addWidget(self.args)
        self.label_args.setBuddy(self.args)

        self.css = QTabWidget()
        self.l.addWidget(self.css)

        self.css1 = TextEditWithTooltip(self, expected_geometry=(80, 20))
        self.css1.setLineWrapMode(TextEditWithTooltip.NoWrap)
        self.css1.load_text(
            self.replace_templates(
                prefs['custom_CSS_list'][prefs['default_CSS']]), 'css')
        self.css1.setToolTip(
            _('<qt>This stylesheet can be modified<br/>The default can be configured</qt>'
              ))
        i = self.css.addTab(self.css1, _('C&ustom CSS'))
        self.css.setTabToolTip(
            i,
            _('<qt>Custom CSS stylesheet to be used for this conversion</qt>'))

        monofont = QFont('')
        monofont.setStyleHint(QFont.TypeWriter)

        if (self.prince_css):
            self.css2 = QPlainTextEdit()
            self.css2.setStyleSheet('* { font-family: monospace }')
            self.css2.setLineWrapMode(QPlainTextEdit.NoWrap)
            self.css2.setPlainText(self.prince_css)
            self.css2.setReadOnly(True)
            self.css2.setToolTip(
                _('<qt>This stylesheet cannot be modified</qt>'))
            i = self.css.addTab(self.css2, _('&Book CSS'))
            self.css.setTabToolTip(
                i,
                _('<qt>Book-specific CSS stylesheet included in the ebook file</qt>'
                  ))

        self.ll = QHBoxLayout()
        self.l.addLayout(self.ll)

        if (prefs['show_CSS']):
            self.toggle = QPushButton(self.hide_text, self)
        else:
            self.toggle = QPushButton(self.show_text, self)
        self.toggle.setToolTip(
            _('<qt>Show/hide the additional styles used for the conversion</qt>'
              ))
        self.toggle.clicked.connect(self.toggle_tabs)

        self.convert = QPushButton(_('Con&vert'), self)
        self.convert.setToolTip(_('<qt>Run the conversion with Prince</qt>'))
        self.convert.setDefault(True)

        self.buttons = QDialogButtonBox(QDialogButtonBox.Cancel)
        self.buttons.addButton(self.toggle, QDialogButtonBox.ResetRole)
        self.buttons.addButton(self.convert, QDialogButtonBox.AcceptRole)
        self.l.addWidget(self.buttons)
        self.buttons.accepted.connect(self.prince_convert)
        self.buttons.rejected.connect(self.reject)

        if (not prefs['show_CSS']):
            self.css.hide()
        self.adjustSize()

    def toggle_tabs(self):
        '''
        Enable/disable the CSS tabs, and store the setting
        '''
        if (self.css.isVisible()):
            self.css.hide()
            self.label_args.hide()
            self.args.hide()
            self.toggle.setText(self.show_text)
            self.adjustSize()
        else:
            self.css.show()
            self.label_args.show()
            self.args.show()
            self.toggle.setText(self.hide_text)
            self.adjustSize()
        prefs['show_CSS'] = self.css.isVisible()

    def set_add_book(self):
        '''
        Save the status of the add_book checkbox
        '''
        prefs['add_book'] = self.add_book.isChecked()

    def set_css(self):
        '''
        Fill the custom CSS text box with the selected stylesheet (and command-line arguments)
        '''
        style = unicode(self.css_list.currentText())
        self.css1.load_text(
            self.replace_templates(prefs['custom_CSS_list'][style]), 'css')
        self.args.setText(prefs['custom_args_list'][style])
        prefs['default_CSS'] = style

    def parse(self):
        '''
        Parse the unpacked OPF file to find and read the prince-style file
        '''
        from calibre.constants import DEBUG
        from os.path import dirname, join
        from lxml import etree
        import codecs

        if DEBUG: print(_('Parsing book...'))
        opf_dir = dirname(self.opf)
        root = etree.parse(self.opf).getroot()
        metadata = root.find('{*}metadata')
        for meta in metadata.findall("{*}meta[@name='prince-style']"):
            prince_id = meta.get('content')
            for item in self.oeb.manifest:
                if (item.id == prince_id):
                    self.prince_file = item.href
                    break
        if (self.prince_file):
            fl = codecs.open(join(opf_dir, self.prince_file), 'rb', 'utf-8')
            self.prince_css = fl.read()
            fl.close()

    def replace_templates(self, text):
        '''
        Replace templates (enclosed by '@{@', '@}@') in the input text
        '''
        import re
        import json
        from calibre.ebooks.metadata.book.formatter import SafeFormat
        from calibre.constants import DEBUG

        matches = list(re.finditer('@{@(.+?)@}@', text, re.DOTALL))
        results = {}
        for match in reversed(matches):
            result = SafeFormat().safe_format(match.group(1), self.mi,
                                              ('EXCEPTION: '), self.mi)
            # Escape quotes, backslashes and newlines
            result = re.sub(r'''['"\\]''', r'\\\g<0>', result)
            result = re.sub('\n', r'\\A ', result)
            results[match.group(1)] = result
            text = text[:match.start(0)] + result + text[match.end(0):]
        if DEBUG:
            print(_('Replacing templates'))
            for match in matches:
                print(
                    _('Found: %s (%d-%d)') %
                    (match.group(1), match.start(0), match.end(0)))
                print(_('Replace with: %s') % results[match.group(1)])
        return text

    def prince_convert(self):
        '''
        Call the actual Prince command to convert to PDF
        '''
        from os import makedirs
        from os.path import dirname, join, exists
        from calibre.ptempfile import PersistentTemporaryFile
        from calibre.constants import DEBUG
        from shlex import split as shsplit

        # All files are relative to the OPF location
        opf_dir = dirname(self.opf)
        base_dir = dirname(self.pdf_file)
        base_dir = join(opf_dir, base_dir)
        try:
            makedirs(base_dir)
        except BaseException:
            if not exists(base_dir): raise

        # Create a temporary CSS file with the box contents
        custom_CSS = PersistentTemporaryFile(mode='w+')
        custom_CSS.write(unicode(self.css1.toPlainText()))
        custom_CSS.close()
        # Create a temporary file with the list of input files
        file_list = PersistentTemporaryFile(mode='w+')
        for item in self.oeb.spine:
            file_list.write(item.href + "\n")
        file_list.close()
        # Build the command line
        command = prefs['prince_exe']
        args = ['-v']
        if self.prince_file:
            args.append('-s')
            args.append(self.prince_file)
        args.append('-s')
        args.append(custom_CSS.name)
        args.append('-l')
        args.append(file_list.name)
        args.append('-o')
        args.append(self.pdf_file)
        # Additional command-line arguments
        args.extend(shsplit(self.args.text()))

        # Hide the convert button and show a busy indicator
        self.convert.setEnabled(False)
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 0)
        self.progress_bar.setValue(0)
        self.l.addWidget(self.progress_bar)

        # Run the command and return the path to the PDF file
        if DEBUG: print(_('Converting book...'))
        process = QProcess(self)
        process.setWorkingDirectory(opf_dir)
        process.setProcessChannelMode(QProcess.MergedChannels)
        process.error.connect(self.error)
        process.finished.connect(self.end)
        self.process = process
        if DEBUG:
            from subprocess import list2cmdline
            line = list2cmdline([command] + args)
            print(_('Command line: %s') % line)
        process.start(command, args)

    def error(self, rc):
        '''
        Show a message when there is an error in the command
        :param rc: The error code
        '''
        from calibre.gui2 import error_dialog

        # Remove the progress bar while the error message is displayed
        self.progress_bar.hide()
        self.progress_bar.deleteLater()
        error_dialog(
            self,
            _('Process error'),
            _('<p>Error code: %s'
              '<p>make sure Prince (<a href="http://www.princexml.com">www.princexml.com</a>) is installed '
              'and the correct command-line-interface executable is set in the configuration of this plugin, '
              'which is usually:'
              '<ul><li>In Windows: <code><i>Prince_folder</i>\\Engine\\bin\\prince.exe</code>'
              '    <li>In Linux: <code>prince</code>'
              '</ul>') % rc,
            show=True)
        self.pdf_file = None
        self.accept()

    def end(self, rc):
        '''
        Close and return the filename when the process ends
        :param rc: The return code (0 if successful)
        '''
        from os.path import join

        self.prince_log = unicode(self.process.readAllStandardOutput().data())
        opf_dir = unicode(self.process.workingDirectory())
        if (rc == 0):
            self.pdf_file = join(opf_dir, self.pdf_file)
        else:
            self.pdf_file = None
        self.accept()
Esempio n. 10
0
class Game(QWidget):

    parent__show_signal = pyqtSignal()
    aumentar_puntaje__dificultad = pyqtSignal(ScoreEvent)
    trigger_aumento_dificultad = pyqtSignal()
    trigger_dano_enemigo_1 = pyqtSignal()
    trigger_dano_enemigo_2 = pyqtSignal()
    trigger_lugar_enemigo = pyqtSignal(PositionMoveEvent)
    trigger_sumar_enemigo_1 = pyqtSignal()
    trigger_sumar_enemigo_2 = pyqtSignal()
    trigger_sumar_pared_1 = pyqtSignal()
    trigger_sumar_pared_2 = pyqtSignal()
    trigger_pausar = pyqtSignal()
    trigger_recibir_explosion = pyqtSignal(PlaceExplodeEvent)
    trigger_power_one = pyqtSignal(PowerUpEvent)
    trigger_power_two = pyqtSignal(PowerUpEvent)
    trigger_initial_one = pyqtSignal(PositionMoveEvent)
    trigger_initial_two = pyqtSignal(PositionMoveEvent)
    trigger_move_player_one = pyqtSignal(SideMoveEvent)
    trigger_move_player_two = pyqtSignal(SideMoveEvent)
    trigger_bomb_one = pyqtSignal()
    trigger_bomb_two = pyqtSignal()
    trigger_no_explota1 = pyqtSignal()
    trigger_no_explota2 = pyqtSignal()
    trigger_enemy_label_move = pyqtSignal(MoveEnemyEvent)
    trigger_enemy_back = pyqtSignal(MoveEnemyEvent)
    trigger_activar_hostilidad = pyqtSignal(HostilidadEvent)
    trigger_enemy_way = pyqtSignal(SideMoveEvent)
    trigger_kick_bomb = pyqtSignal(KickBombEvent)
    trigger_stop_bomb = pyqtSignal(KickBombEvent)
    trigger_move_label_bomb = pyqtSignal(int)

    def __init__(self, name_one, name_two=None):
        super().__init__()
        self.letras = set()
        self.power_ups = []
        self.enemigos = {}
        self.bombas = []
        self.basurero = []
        self.walls, self.espacios_vacios = back_walls(self)
        self.generador_enemigos = GeneradorDeEnemigos(self)
        self.trigger_lugar_enemigo.connect(
            self.generador_enemigos.cambiar_lugar)
        self.aumentar_puntaje__dificultad.connect(
            self.generador_enemigos.actualizar_puntaje)

        self.setWindowTitle("Coding With Fire")
        self.setGeometry(100, 50, N + 300, N + 50)
        self.label_walls = self.set_walls()
        bomber1_pix = QPixmap("assets/bomberman.png")
        self.up_1_pixs = {1: bomber1_pix.copy(*pix.B1),
                          2: bomber1_pix.copy(*pix.B2),
                          3: bomber1_pix.copy(*pix.B3),
                          4: bomber1_pix.copy(*pix.B4),
                          5: bomber1_pix.copy(*pix.B5)}
        self.left_1_pixs = {1: bomber1_pix.copy(*pix.R1).transformed(
            QTransform().scale(-1, 1)),
            2: bomber1_pix.copy(*pix.R2).transformed(
                QTransform().scale(-1, 1)),
            3: bomber1_pix.copy(*pix.R3).transformed(
                QTransform().scale(-1, 1)),
            4: bomber1_pix.copy(*pix.R4).transformed(
                QTransform().scale(-1, 1)),
            5: bomber1_pix.copy(*pix.R5).transformed(
                QTransform().scale(-1, 1))}
        self.right_1_pixs = {1: bomber1_pix.copy(*pix.R1),
                             2: bomber1_pix.copy(*pix.R2),
                             3: bomber1_pix.copy(*pix.R3),
                             4: bomber1_pix.copy(*pix.R4),
                             5: bomber1_pix.copy(*pix.R5)}
        self.down_1_pixs = {1: bomber1_pix.copy(*pix.F1),
                            2: bomber1_pix.copy(*pix.F2),
                            3: bomber1_pix.copy(*pix.F3),
                            4: bomber1_pix.copy(*pix.F4),
                            5: bomber1_pix.copy(*pix.F5)}
        self.atack_1_pixs = {3: bomber1_pix.copy(*pix.A1),
                             2: bomber1_pix.copy(*pix.A2),
                             1: bomber1_pix.copy(*pix.A3)}

        bomber2_pix = QPixmap("assets/bomberman2.png")
        self.up_2_pixs = {1: bomber2_pix.copy(*pix.B1),
                          2: bomber2_pix.copy(*pix.B2),
                          3: bomber2_pix.copy(*pix.B3),
                          4: bomber2_pix.copy(*pix.B4),
                          5: bomber2_pix.copy(*pix.B5)}
        self.left_2_pixs = {1: bomber2_pix.copy(*pix.R1).transformed(
            QTransform().scale(-1, 1)),
            2: bomber2_pix.copy(*pix.R2).transformed(
                QTransform().scale(-1, 1)),
            3: bomber2_pix.copy(*pix.R3).transformed(
                QTransform().scale(-1, 1)),
            4: bomber2_pix.copy(*pix.R4).transformed(
                QTransform().scale(-1, 1)),
            5: bomber2_pix.copy(*pix.R5).transformed(
                QTransform().scale(-1, 1))}
        self.right_2_pixs = {1: bomber2_pix.copy(*pix.R1),
                             2: bomber2_pix.copy(*pix.R2),
                             3: bomber2_pix.copy(*pix.R3),
                             4: bomber2_pix.copy(*pix.R4),
                             5: bomber2_pix.copy(*pix.R5)}
        self.down_2_pixs = {1: bomber2_pix.copy(*pix.F1),
                            2: bomber2_pix.copy(*pix.F2),
                            3: bomber2_pix.copy(*pix.F3),
                            4: bomber2_pix.copy(*pix.F4),
                            5: bomber2_pix.copy(*pix.F5)}
        self.atack_2_pixs = {3: bomber2_pix.copy(*pix.A1),
                             2: bomber2_pix.copy(*pix.A2),
                             1: bomber2_pix.copy(*pix.A3)}

        self.set_stats_one(name_one)
        self.player_one = PlayerOne(self, name_one, N + 150, 10)
        self.label_player_one = QLabel("", self)
        self.label_player_one.setGeometry(N + 150, 10, 22, 35)
        self.label_player_one.setPixmap(self.down_1_pixs[3])
        self.trigger_initial_one.connect(self.player_one.set_pos)
        self.trigger_move_player_one.connect(self.player_one.move)
        self.trigger_bomb_one.connect(self.player_one.soltar_bomba)
        self.trigger_no_explota1.connect(self.player_one.no_explota)
        self.trigger_power_one.connect(self.player_one.catch_power_up)
        self.trigger_sumar_pared_1.connect(self.player_one.puntos_pared)
        self.trigger_sumar_enemigo_1.connect(
            self.player_one.puntos_enemigo)
        self.trigger_dano_enemigo_1.connect(self.player_one.impacto)
        if name_two:
            self.set_stats_two(name_two)
            self.player_two = PlayerTwo(self, name_two, N + 150, N / 2)
            self.label_player_two = QLabel("", self)
            self.label_player_two.setGeometry(N + 150, N / 2, 22, 35)
            self.label_player_two.setPixmap(self.down_2_pixs[3])
            self.trigger_initial_two.connect(self.player_two.set_pos)
            self.trigger_move_player_two.connect(self.player_two.move)
            self.trigger_bomb_two.connect(self.player_two.soltar_bomba)
            self.trigger_no_explota2.connect(self.player_two.no_explota)
            self.trigger_power_two.connect(self.player_two.catch_power_up)
            self.trigger_sumar_pared_2.connect(self.player_two.puntos_pared)
            self.trigger_sumar_enemigo_2.connect(
                self.player_two.puntos_enemigo)
            self.trigger_dano_enemigo_2.connect(self.player_two.impacto)
        else:
            self.player_two = None

        self.pause_button = QPushButton("Pausa", self)
        self.pause_button.setGeometry(N + 20, N + 10, 130, 40)
        self.pause_button.clicked.connect(self.pausa)
        self.back_botton = QPushButton("Salir", self)
        self.back_botton.setGeometry(N + 150, N + 10, 130, 40)
        self.back_botton.clicked.connect(self.back)
        self.setMouseTracking(True)
        self.moving_one = False
        self.moving_two = False
        self.started = False
        self.current2_pix = 1
        self.current2_way = 1  # -1 o 1
        self.current1_pix = 1
        self.current1_way = 1  # -1 o 1
        self.setFocusPolicy(Qt.StrongFocus)

    def set_walls(self):
        walls = []
        with open("mapa.txt") as file:
            currentx = 0
            currenty = 0
            size = N / MAPA_SIZE
            for line in file:
                new_walls = []
                line = line.replace(" ", "")
                for letter in line.strip():
                    if letter == "X":
                        wall = QLabel('', self)
                        wall.setGeometry(currentx, currenty, size, size)
                        wall.setScaledContents(True)
                        wall.setPixmap(QPixmap(
                            "assets/indestructible_wall.png"))
                        new_walls.append(wall)
                    elif letter == "P":
                        wall = QLabel('', self)
                        wall.setGeometry(currentx, currenty, size, size)
                        wall.setScaledContents(True)
                        wall.setPixmap(QPixmap(
                            "assets/destructible_wall.png"))
                        new_walls.append(wall)
                    else:
                        new_walls.append(None)
                    currentx += size
                currentx = 0
                currenty += size
                walls.append(new_walls)
        return walls

    def set_stats_one(self, nombre):
        self.label_nombre_1 = QLabel(nombre, self)
        self.label_nombre_1.setGeometry(N + 50, 10, 150, 30)
        self.labels_vidas_1 = []
        if CANT_VIDAS > 3:
            self.label_nvidas_1 = QLabel(str(CANT_VIDAS), self)
            self.label_nvidas_1.setGeometry(N + 30, 60, 40, 30)
        pixmap = QPixmap("assets/vida.png")
        currentx = N + 100
        tope = (min(CANT_VIDAS, 10))
        for i in range(tope):
            label = QLabel("", self)
            label.setGeometry(currentx, 60, 30, 30)
            label.setPixmap(pixmap.scaled(
                30, 30, Qt.KeepAspectRatio, Qt.FastTransformation))
            self.labels_vidas_1.append(label)
            currentx += 150 / tope

        self.label_power_bombas_1 = QLabel("", self)
        self.label_power_bombas_1.setGeometry(N + 125, 100, 50, 50)
        self.label_power_bombas_1.setScaledContents(True)
        self.label_power_bombas_1.setPixmap(
            QPixmap("assets/mas_bombas.png"))
        self.label_bombas_1 = QLabel("", self)
        self.label_bombas_1.setGeometry(N + 75, 100, 50, 50)
        self.label_power_bombas_1.hide()
        self.label_power_velocidad_1 = QLabel("", self)
        self.label_power_velocidad_1.setGeometry(N + 50, 180, 50, 50)
        self.label_power_velocidad_1.setScaledContents(True)
        self.label_power_velocidad_1.setPixmap(
            QPixmap("assets/velocidad.png"))
        self.label_power_velocidad_1.hide()
        self.label_power_super_1 = QLabel("", self)
        self.label_power_super_1.setGeometry(N + 125, 180, 50, 50)
        self.label_power_super_1.setScaledContents(True)
        self.label_power_super_1.setPixmap(
            QPixmap("assets/supervelocidad.png"))
        self.label_power_super_1.hide()
        self.label_power_jugger_1 = QLabel("", self)
        self.label_power_jugger_1.setGeometry(N + 200, 180, 50, 50)
        self.label_power_jugger_1.setScaledContents(True)
        self.label_power_jugger_1.setPixmap(
            QPixmap("assets/juggernaut.png"))
        self.label_power_jugger_1.hide()

        self.score_bar_1 = QProgressBar(self)
        self.score_bar_1.setRange(0, AUMENTO_DIFICULTAD)
        self.score_bar_1.setGeometry(100, N + 10, N/2 - 150, 30)
        self.score_bar_1.setValue(0)

        self.label_score_1 = QLabel("Score P1", self)
        self.label_score_1.setGeometry(30, N + 10, 80, 30)


    def show_power(self, e):
        tipo = e.tipo
        if tipo == "velocidad":
            if e.player == 1:
                self.label_power_velocidad_1.show()
            else:
                self.label_power_velocidad_2.show()
        elif tipo == "bombas":
            if e.player == 1:
                self.label_power_bombas_1.show()
                self.label_bombas_1.setText(str(e.cantidad))
            else:
                self.label_power_bombas_2.show()
                self.label_bombas_2.setText(str(e.cantidad))
        elif tipo == "super":
            if e.player == 1:
                self.label_power_super_1.show()
            else:
                self.label_power_super_2.show()
        else:
            if e.player == 1:
                self.label_power_jugger_1.show()
            else:
                self.label_power_jugger_2.show()

    def hide_power(self, e):
        tipo = e.tipo
        if tipo == "super":
            if e.player == 1:
                self.label_power_super_1.hide()
            else:
                self.label_power_super_2.hide()
        else:
            if e.player == 1:
                self.label_power_jugger_1.hide()
            else:
                self.label_power_jugger_2.hide()

    def set_stats_two(self, nombre):
        self.label_nombre_2 = QLabel(nombre, self)
        self.label_nombre_2.setGeometry(N + 50, N / 2, 150, 30)
        self.labels_vidas_2 = []
        if CANT_VIDAS > 3:
            self.label_nvidas_2 = QLabel(str(CANT_VIDAS), self)
            self.label_nvidas_2.setGeometry(N + 30, 50 + N / 2, 40, 30)
        pixmap = QPixmap("assets/vida.png")
        currentx = N + 100
        tope = (min(CANT_VIDAS, 10))
        for i in range(tope):
            label = QLabel("", self)
            label.setGeometry(currentx, 50 + N / 2, 30, 30)
            label.setPixmap(pixmap.scaled(
                30, 30, Qt.KeepAspectRatio, Qt.FastTransformation))
            self.labels_vidas_2.append(label)
            currentx += 150 / tope

        self.label_power_bombas_2 = QLabel("", self)
        self.label_power_bombas_2.setGeometry(N + 125, 100 + N / 2, 50, 50)
        self.label_power_bombas_2.setScaledContents(True)
        self.label_power_bombas_2.setPixmap(
            QPixmap("assets/mas_bombas.png"))
        self.label_bombas_2 = QLabel("", self)
        self.label_bombas_2.setGeometry(N + 75, 100 + N / 2, 50, 50)
        self.label_power_bombas_2.hide()
        self.label_power_velocidad_2 = QLabel("", self)
        self.label_power_velocidad_2.setGeometry(N + 50, 180 + N / 2, 50, 50)
        self.label_power_velocidad_2.setScaledContents(True)
        self.label_power_velocidad_2.setPixmap(
            QPixmap("assets/velocidad.png"))
        self.label_power_velocidad_2.hide()
        self.label_power_super_2 = QLabel("", self)
        self.label_power_super_2.setGeometry(N + 125, 180 + N / 2, 50, 50)
        self.label_power_super_2.setScaledContents(True)
        self.label_power_super_2.setPixmap(
            QPixmap("assets/supervelocidad.png"))
        self.label_power_super_2.hide()
        self.label_power_jugger_2 = QLabel("", self)
        self.label_power_jugger_2.setGeometry(N + 200, 180 + N / 2, 50, 50)
        self.label_power_jugger_2.setScaledContents(True)
        self.label_power_jugger_2.setPixmap(
            QPixmap("assets/juggernaut.png"))
        self.label_power_jugger_2.hide()

        self.score_bar_2 = QProgressBar(self)
        self.score_bar_2.setRange(0, AUMENTO_DIFICULTAD)
        self.score_bar_2.setGeometry(N/2 + 100, N + 10, N/2 - 150, 30)
        self.score_bar_2.setValue(0)
        self.label_score_2 = QLabel("Score P2", self)
        self.label_score_2.setGeometry(N/2 + 30, N + 10, 80, 30)

    def keyPressEvent(self, e):
        letter = e.key()
        self.letras.add(letter)
        if Qt.Key_Control in self.letras:
            if Qt.Key_E in self.letras:
                self.back()
            elif Qt.Key_P in self.letras:
                self.pausa()
        if self.started:
            if self.player_two is not None:
                if Qt.Key_W in self.letras:
                    self.current2_pix += self.current2_way
                    self.label_player_two.setPixmap(self.up_2_pixs[
                                                        self.current2_pix])
                    if self.current2_pix == 5:
                        self.current2_way = -1
                    elif self.current2_pix == 1:
                        self.current2_way = 1
                    self.trigger_move_player_two.emit(SideMoveEvent("up"))
                elif Qt.Key_A in self.letras:
                    self.current2_pix += self.current2_way
                    self.label_player_two.setPixmap(self.left_2_pixs[
                                                        self.current2_pix])
                    if self.current2_pix == 5:
                        self.current2_way = -1
                    elif self.current2_pix == 1:
                        self.current2_way = 1
                    self.trigger_move_player_two.emit(SideMoveEvent("left"))
                elif Qt.Key_S in self.letras:
                    self.current2_pix += self.current2_way
                    self.label_player_two.setPixmap(self.down_2_pixs[
                                                        self.current2_pix])
                    if self.current2_pix == 5:
                        self.current2_way = -1
                    elif self.current2_pix == 1:
                        self.current2_way = 1
                    self.trigger_move_player_two.emit(SideMoveEvent("down"))
                elif Qt.Key_D in self.letras:
                    self.current2_pix += self.current2_way
                    self.label_player_two.setPixmap(self.right_2_pixs[
                                                        self.current2_pix])
                    if self.current2_pix == 5:
                        self.current2_way = -1
                    elif self.current2_pix == 1:
                        self.current2_way = 1
                    self.trigger_move_player_two.emit(SideMoveEvent("right"))
                if Qt.Key_F == letter:
                    self.label_player_two.setPixmap(self.atack_2_pixs[1])
                    self.label_player_two.setPixmap(self.atack_2_pixs[2])
                    self.label_player_two.setPixmap(self.atack_2_pixs[3])
                    self.trigger_bomb_two.emit()
                    self.label_player_two.setPixmap(self.atack_2_pixs[2])
                    self.label_player_two.setPixmap(self.atack_2_pixs[1])
                    self.label_player_two.setPixmap(self.down_2_pixs[3])

            if Qt.Key_Up in self.letras:
                self.current1_pix += self.current1_way
                self.label_player_one.setPixmap(self.up_1_pixs[
                                                    self.current1_pix])
                if self.current1_pix == 5:
                    self.current1_way = -1
                elif self.current1_pix == 1:
                    self.current1_way = 1
                self.trigger_move_player_one.emit(SideMoveEvent("up"))
            elif Qt.Key_Left in self.letras:
                self.current1_pix += self.current1_way
                self.label_player_one.setPixmap(self.left_1_pixs[
                                                    self.current1_pix])
                if self.current1_pix == 5:
                    self.current1_way = -1
                elif self.current1_pix == 1:
                    self.current1_way = 1
                self.trigger_move_player_one.emit(SideMoveEvent("left"))
            elif Qt.Key_Down in self.letras:
                self.current1_pix += self.current1_way
                self.label_player_one.setPixmap(self.down_1_pixs[
                                                    self.current1_pix])
                if self.current1_pix == 5:
                    self.current1_way = -1
                elif self.current1_pix == 1:
                    self.current1_way = 1
                self.trigger_move_player_one.emit(SideMoveEvent("down"))
            elif Qt.Key_Right in self.letras:
                self.current1_pix += self.current1_way
                self.label_player_one.setPixmap(self.right_1_pixs[
                                                    self.current1_pix])
                if self.current1_pix == 5:
                    self.current1_way = -1
                elif self.current1_pix == 1:
                    self.current1_way = 1
                self.trigger_move_player_one.emit(SideMoveEvent("right"))
            if Qt.Key_Space == letter:
                self.label_player_one.setPixmap(self.atack_1_pixs[1])
                self.label_player_one.setPixmap(self.atack_1_pixs[2])
                self.label_player_one.setPixmap(self.atack_1_pixs[3])
                self.trigger_bomb_one.emit()
                self.label_player_one.setPixmap(self.atack_1_pixs[2])
                self.label_player_one.setPixmap(self.atack_1_pixs[1])
                self.label_player_one.setPixmap(self.down_1_pixs[3])

    def keyReleaseEvent(self, e):
        letter = e.key()
        self.letras.discard(letter)
        if self.started:
            if self.player_two is not None:
                if Qt.Key_W == letter:
                    self.trigger_move_player_two.emit(SideMoveEvent(None))
                elif Qt.Key_A == letter:
                    self.trigger_move_player_two.emit(SideMoveEvent(None))
                elif Qt.Key_S == letter:
                    self.trigger_move_player_two.emit(SideMoveEvent(None))
                elif Qt.Key_D == letter:
                    self.trigger_move_player_two.emit(SideMoveEvent(None))
                elif Qt.Key_F == letter:
                    self.trigger_move_player_two.emit(SideMoveEvent(None))
            if Qt.Key_Up == letter:
                self.trigger_move_player_one.emit(SideMoveEvent(None))
            elif Qt.Key_Left == letter:
                self.trigger_move_player_one.emit(SideMoveEvent(None))
            elif Qt.Key_Down == letter:
                self.trigger_move_player_one.emit(SideMoveEvent(None))
            elif Qt.Key_Right == letter:
                self.trigger_move_player_one.emit(SideMoveEvent(None))
            elif Qt.Key_Space == letter:
                self.trigger_move_player_two.emit(SideMoveEvent(None))
        while self.letras:
            self.keyPressEvent(KeyEvent(self.letras.pop()))
            QTest.qWait(100)

    def mousePressEvent(self, e):
        """As seen at: https://stackoverflow.com/questions/43453562/
        interaction-between-mousepressevent-and-paintevent-methods"""
        if not self.started:
            if in_range(e.pos().x(), N + 150, N + 173) and \
                    in_range(e.pos().y(), 10, 51):
                self.moving_one = True
            elif in_range(e.pos().x(), N + 150, N + 173) and \
                    in_range(e.pos().y(), N / 2, N / 2 + 41):
                if self.player_two is not None:
                    self.moving_two = True

    def mouseReleaseEvent(self, e):
        if not self.started:
            x = e.pos().x()
            y = e.pos().y()
            if self.moving_one:
                self.trigger_initial_one.emit(PositionMoveEvent(x, y))
            elif self.moving_two:
                self.trigger_initial_two.emit(PositionMoveEvent(x, y))

    def player_release(self, e):
        if self.moving_one:
            if colisiones(self.player_one, self.walls):
                self.trigger_initial_one.emit(
                    PositionMoveEvent(N + 150, 10, True))
                self.label_player_one.move(N + 150, 10)
                self.moving_one = False
                return
            if e.ready:
                if self.player_two is not None:
                    if self.player_two.ready:
                        self.startgame()
                else:
                    self.startgame()
            else:
                self.label_player_one.move(N + 150, 10)
            self.moving_one = False
        elif self.moving_two:
            if colisiones(self.player_two, self.walls):
                self.trigger_initial_two.emit(
                    PositionMoveEvent(N + 150, N / 2, True))
                self.label_player_two.move(N + 150, N / 2)
                self.moving_two = False
                return
            if e.ready:
                if self.player_one.ready:
                    self.startgame()
            else:
                self.label_player_two.move(N + 150, N / 2)
            self.moving_two = False

    def mouseMoveEvent(self, e):
        if not self.started:
            if self.moving_one:
                self.label_player_one.move(e.pos().x(), e.pos().y())
            elif self.moving_two:
                self.label_player_two.move(e.pos().x(), e.pos().y())

    def move_player_one(self, e):
        if self.started:
            if colisiones(self.player_one, self.walls):
                x = self.label_player_one.x()
                y = self.label_player_one.y()
                self.trigger_initial_one.emit((PositionMoveEvent(x, y)))
                return
            elif colisiones(self.player_one, self.enemigos.values()):
                x = self.label_player_one.x()
                y = self.label_player_one.y()
                self.trigger_initial_one.emit((PositionMoveEvent(x, y)))
                self.trigger_dano_enemigo_1.emit()
                return
            bomba = kick_bomb(self.player_one, self.bombas)
            if bomba:
                way, id_ = move_way(self.player_one, bomba)
                self.trigger_kick_bomb.emit(KickBombEvent(way, id_))
            power = specific_colision(self.player_one, self.power_ups)
            if power:
                self.trigger_power_one.emit(PowerUpEvent(power))
                self.power_ups.remove(power)
                power.catched()
            self.label_player_one.move(e.x, e.y)

    def move_player_two(self, e):
        if self.started:
            if colisiones(self.player_two, self.walls):
                x = self.label_player_two.x()
                y = self.label_player_two.y()
                self.trigger_initial_two.emit((PositionMoveEvent(x, y)))
                return
            elif colisiones(self.player_two, self.enemigos.values()):
                x = self.label_player_two.x()
                y = self.label_player_two.y()
                self.trigger_initial_two.emit((PositionMoveEvent(x, y)))
                self.trigger_dano_enemigo_2.emit()
                return
            bomba = kick_bomb(self.player_two, self.bombas)
            if bomba:
                way, id_ = move_way(self.player_two, bomba)
                self.trigger_kick_bomb.emit(KickBombEvent(way, id_))
            power = specific_colision(self.player_two, self.power_ups)
            if power:
                self.trigger_power_two.emit(PowerUpEvent(power))
                power.catched()
            self.label_player_two.move(e.x, e.y)

    def move_enemy(self, e):
        enemigo = self.enemigos[e.id_]
        if colisiones(enemigo, self.walls) or colisiones(enemigo, self.bombas):
            self.trigger_enemy_back.emit(MoveEnemyEvent(e.x, e.y, e.id_))
        elif colision(enemigo, self.player_one):
            self.trigger_enemy_back.emit(MoveEnemyEvent(e.x, e.y, e.id_))
            self.trigger_dano_enemigo_1.emit()
        elif self.player_two is not None:
            if colision(enemigo, self.player_two):
                self.trigger_enemy_back.emit(MoveEnemyEvent(e.x, e.y, e.id_))
                self.trigger_dano_enemigo_2.emit()
            else:
                self.trigger_enemy_label_move.emit(MoveEnemyEvent(
                    e.x, e.y, e.id_))
        else:
            self.trigger_enemy_label_move.emit(MoveEnemyEvent(
                e.x, e.y, e.id_))

    def move_bomb(self, e):
        bomba_ = filter(lambda b: b.id_ == e.id_, self.bombas)
        bomb = next(bomba_)
        if colisiones(bomb, self.enemigos.values()) or \
                colisiones(bomb, self.walls):
            self.trigger_stop_bomb.emit(KickBombEvent(None, e.id_))
        elif colision(self.player_one, bomb):
            self.trigger_stop_bomb.emit(KickBombEvent(None, e.id_))
        elif self.player_two is not None:
            if colision(self.player_two, bomb):
                self.trigger_stop_bomb.emit(KickBombEvent(None, e.id_))
        self.trigger_move_label_bomb.emit(e.id_)

    def revisar_rango_hostil(self, e):
        player = revisar_hostilidad(e, self.player_one, self.player_two)
        if player:
            self.trigger_activar_hostilidad.emit(HostilidadEvent(e.id_,
                                                                 player))
        else:
            self.trigger_activar_hostilidad.emit(HostilidadEvent(e.id_,
                                                                 player))

    def hostil_movement(self, e):
        if e.player == 1:
            side = hostil_way(e.x, e.y, self.player_one, e.last_side)
        else:
            side = hostil_way(e.x, e.y, self.player_two, e.last_side)
        self.trigger_enemy_way.emit(SideMoveEvent(side, e.id_))

    def recibir_enemigos(self, e):
        if e.tipo == "hostil":
            enemigo = EnemigoHostil(self, e.x, e.y)
        else:
            enemigo = Enemigo(self, e.x, e.y)
        self.enemigos[enemigo.id_] = enemigo

    def muere_enemigo(self, id_):
        if id_ in self.enemigos:
            self.basurero.append(self.enemigos[id_])
            del self.enemigos[id_]

    def bomb_release(self, e):
        bomba = Bomba(self, e.x, e.y, e.player)
        space = bomb_space(bomba, self.espacios_vacios)
        if space:
            bomba.encasillar(*space.pos)
            self.bombas.append(bomba)
        else:
            if e.player == 1:
                self.trigger_no_explota1.emit()
            elif e.player == 2:
                self.trigger_no_explota2.emit()

    def bomb_explode(self, e):
        casillas = casillas_afectadas(e, self.espacios_vacios, self.walls)
        for casilla in casillas:
            if isinstance(casilla, Espacio):
                self.explotar_espacio(casilla, e.player)
            else:
                self.detruir_pared(casilla, e.player)
        self.basurero.append(e.bomba)
        self.bombas.remove(e.bomba)

    def detruir_pared(self, pared, player):
        if player == 1:
            self.trigger_sumar_pared_1.emit()
        else:
            self.trigger_sumar_pared_2.emit()
        espacio = Espacio(self, pared.x, pared.y, pared.sizex, True)
        pared.deleteLater()
        self.walls.remove(pared)
        self.espacios_vacios.append(espacio)
        label = find_label(self.label_walls, pared.sizex, *pared.pos)
        label.deleteLater()

    def explotar_espacio(self, casilla, player):
        casilla.ocupado = False
        explode = Explode(self, casilla.x, casilla.y)
        explode.start()
        self.trigger_recibir_explosion.emit(PlaceExplodeEvent(casilla, player))

    def add_enemy_points(self, player):
        if player == 1:
            self.trigger_sumar_enemigo_1.emit()
        else:
            self.trigger_sumar_enemigo_2.emit()

    def cambiar_vida(self, e):
        if e.player == 1:
            if CANT_VIDAS > 3:
                if e.vidas > 10:
                    self.label_nvidas_1.setText(str(e.vidas))
                elif e.vidas == 10:
                    self.label_nvidas_1.setText("")
                    if e.cambio == -1:
                        label = self.labels_vidas_1[9]
                        label.show()
                        label.setVisible(True)
            else:
                if e.cambio == 1:
                    label = self.labels_vidas_1[e.vidas - 1]
                    label.show()
                    label.setVisible(True)
                elif e.cambio == -1:
                    label = self.labels_vidas_1[e.vidas]
                    label.hide()
                    label.setVisible(False)
        elif e.player == 2:
            if CANT_VIDAS > 3:
                if e.vidas > 10:
                    self.label_nvidas_2.setText(str(e.vidas))
                elif e.vidas == 10:
                    self.label_nvidas_2.setText("")
                    if e.cambio == -1:
                        label = self.labels_vidas_2[9]
                        label.show()
                        label.setVisible(True)
            else:
                if e.cambio == 1:
                    label = self.labels_vidas_2[e.vidas - 1]
                    label.show()
                    label.setVisible(True)
                elif e.cambio == -1:
                    label = self.labels_vidas_2[e.vidas]
                    label.hide()
                    label.setVisible(False)

    def lugar_despliegue(self):
        x, y = pedir_celdas(self.espacios_vacios, self.enemigos.values(),
                            self.player_one, self.player_two)
        self.trigger_lugar_enemigo.emit(PositionMoveEvent(x, y))

    def power_up(self, e):
        self.power_ups.append(e.power_up)

    def remove_power_up(self, power):
        if power in self.power_ups:
            self.power_ups.remove(power)

    def actualizar_puntaje(self, e):
        if e.player == 1:
            label_score = e.score
            while label_score > AUMENTO_DIFICULTAD:
                label_score -= AUMENTO_DIFICULTAD
            self.score_bar_1.setValue(label_score)
            self.aumentar_puntaje__dificultad.emit(e)
        else:
            label_score = e.score
            while label_score > AUMENTO_DIFICULTAD:
                label_score -= AUMENTO_DIFICULTAD
            self.score_bar_2.setValue(label_score)
            self.aumentar_puntaje__dificultad.emit(e)

    def aumentar_dificultad_enemigos(self):
        self.trigger_aumento_dificultad.emit()

    def startgame(self):
        self.started = True
        self.player_one.start()
        if self.player_two is not None:
            self.player_two.start()
        self.generador_enemigos.start()

    def pausa(self):
        if self.started:
            self.trigger_pausar.emit()

    def dead_player(self, player):
        if player == 1:
            if self.player_two is not None:
                if self.player_two.vida > 0:
                    self.label_player_one.hide()
                else:
                    self.show_scores()
            else:
                self.show_scores()
        else:
            if self.player_one.vida > 0:
                self.label_player_two.hide()
            else:
                self.show_scores()

    def show_scores(self):
        self.pausa()
        score_1 = [self.player_one.name, self.player_one.score]
        if self.player_two is None:
            score_2 = None
        else:
            score_2 = [self.player_two.name, self.player_two.score]

        self.scores = Scores(score_1, score_2)
        self.hide()
        self.scores.show()

    def back(self):
        """As seen at: https://stackoverflow.com/questions/45098161/
        back-to-previous-window"""
        self.pausa()
        score_1 = [self.player_one.name, self.player_one.score]
        if self.player_two is None:
            score_2 = None
        else:
            score_2 = [self.player_two.name, self.player_two.score]

        self.scores = Scores(score_1, score_2)
        self.hide()
        self.parent__show_signal.emit()
Esempio n. 11
0
    progressBar.setStyleSheet(barStyle)
    progressBar.setAlignment(Qt.AlignRight)

    label = QLabel(splash)
    label.setStyleSheet(labelstyle)
    label.setGeometry((splash_pix.width() - 500) / 2,
                      splash_pix.height() - 40, 500, 20)
    label.setAlignment(Qt.AlignCenter)

    progressText = "loading..."
    label.setText(progressText)

    splash.show()

    for i in range(0, 100):
        progressBar.setValue(i)
        updateSplash(label, i)
        progressBar.setFormat(str(i) + "%")
        t = time.time()
        while time.time() < t + 0.015:
            app.processEvents()

    ### --------------

    # Read Masternode List
    masternode_list = readMNfile()
    # Create QMainWindow Widget
    ex = App(masternode_list, imgDir)

    # Close Splashscreen
    splash.close()
Esempio n. 12
0
class ProgressDialog(QDialog):
    _default = '''
    QProgressBar {
      min-width: 350px;
    }
    '''

    def __init__(self, parent, title, total_progress):
        super().__init__(parent)
        self.setWindowTitle(title)
        self._total_progress = total_progress

        self._progress_bar = None

        self._setup_ui()
        self._prepare()

    def _setup_ui(self):
        self.setStyleSheet(self._default)
        self.setWindowFlags(
            Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint
        )

        self.setStyleSheet(self._default)
        layout = make_layout(
            horizon=False,
            margin=24,
            spacing=24
        )

        self._progress_bar = QProgressBar()
        self._progress_bar.setRange(0, self._total_progress)
        self._progress_bar.setTextVisible(True)
        self._progress_bar.setFormat(r'%p% (%v/%m)')
        self._progress_bar.setValue(0)

        layout.addWidget(
            self._progress_bar
        )

        self.setLayout(layout)
        move_center(self)

    def _prepare(self):
        return

    def increase(self, step=1):
        self._progress_bar.setValue(self._progress_bar.value() + step)

        if self._progress_bar.value() == self._progress_bar.maximum():
            self.close()

    def _on_show(self):
        return

    def _on_close(self):
        return

    def showEvent(self, event):
        self._on_show()
        event.accept()

    def closeEvent(self, event):
        self._on_close()
        event.accept()
Esempio n. 13
0
class WebTab(QWidget):
    """ The tab contains chrome plus a web view; is hosted on a tab bar """

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

        self.current = {
            'title': "[EMPTY]",
            'address': ""
        }

        # address bar
        self.address_bar = AddressBar(parent=self)

        # webkit (the actual "web engine")
        self.webkit = WebView(parent=self)

        # set_prefix: app defined, carries str
        self.webkit.set_prefix.connect(self.address_bar.set_model)  # CFG02
        # javascript_state: app defined, carries bool
        self.webkit.javascript_state.connect(self.address_bar.set_bgcolor)

        # small label displaying instance ID and pending tab operations

        info_label = QLabel(parent=self)
        info_label.setText('?')  # CFG02

        # webkit_info: app defined, carries str
        self.webkit.attr.webkit_info.connect(info_label.setText)

        def update_address(qurl):
            """ The 'connect' gives a QUrl and setText receives a string;
            can't just connect setText

            Required because a 3XX HTTP redirection will change the address,
            and without updating, the address bar will be left stale

            AB02 AB03

            """
            self.current['address'] = qurl.toString()
            self.address_bar.setText(self.current['address'])

        # urlChanged carries QUrl; loadStarted carries nothing;
        # loadFinished carries bool; titleChanged carries str;
        # loadProgress carries int
        self.webkit.urlChanged.connect(update_address)
        self.webkit.loadStarted.connect(self.load_started)
        self.webkit.loadFinished.connect(self.load_finished)
        self.webkit.titleChanged.connect(self.save_title)
        self.webkit.loadProgress.connect(self.load_progress)

        def fill_notifier(message, request):
            """ sends a message to be displayed by the notifier

            """
            notify(message + " " + request.url().toString())

        # downloadRequested carries QNetworkRequest
        self.webkit.page().downloadRequested.connect(
            partial(fill_notifier, "download"))
        # unsupportedContent carries QNetworkReply
        self.webkit.page().unsupportedContent.connect(
            partial(fill_notifier, "unsupported"))

        # input area for access-key navigation

        self.nav_bar = NavigateInput(parent=self)
        # editingFinished carries nothing
        self.nav_bar.editingFinished.connect(self.webkit.clear_labels)

        # textEdited carries str
        self.nav_bar.textEdited.connect(self.webkit.akeynav)
        # nonvalid_tag (app defined) carries nothing
        self.webkit.nonvalid_tag.connect(self.nav_bar.clear)

        # 'corner' message and notification label, not on timer, smaller

        self.message_label = MessageLabel(self.webkit)

        def handle_hovered(link, title, content):
            """ When hovered, if ALT is pressed, show message label;
            hide otherwise

            """

            if ((QApplication.keyboardModifiers() & Qt.AltModifier) and
                    (link or title or content)):
                # ugly hack to ensure proper resizing; find a better way?
                self.message_label.hide()
                self.message_label.setText(
                    link + " " + title + " " + content)
                self.message_label.show()
            else:
                self.message_label.hide()

        # linkHovered carries str, str, str
        self.webkit.page().linkHovered.connect(handle_hovered)

        def handle_signaled(title):
            """ We received a string through a signal; display it on
            the message label

            """

            # if title:
            self.message_label.hide()
            self.message_label.setText(title)
            self.message_label.show()

        # show_message (app defined) carries str
        self.webkit.show_message.connect(handle_signaled)
        # loadStarted carries nothing
        self.webkit.loadStarted.connect(self.message_label.hide)

        # At the time navigation is requested load_requested is sent, and the
        # requested url is set as text in grey at the address bar. Once the
        # urlChanged signal is received, the actual url is set in black.

        # load_requested (app defined) carries str
        self.webkit.load_requested.connect(
            partial(self.address_bar.set_txt_color,
                    color=QColor(128, 128, 128)))

        def hide_message_label(*_):
            """ WARNING scrollRequested carries int, int, QRect;
            star swallows all

            """
            self.message_label.hide()

        self.webkit.page().scrollRequested.connect(hide_message_label)

        # focus_webkit (app defined) carries nothing
        self.webkit.hide_overlay.connect(self.message_label.hide)
        self.webkit.focus_webkit.connect(self.address_bar.restore)

        # progress bar
        self.pbar = QProgressBar(self)

        self.pbar.setRange(0, 100)
        self.pbar.setTextVisible(False)
        self.pbar.setVisible(False)
        self.pbar.setMaximumHeight(7)

        # search in page
        self.search_frame = SearchFrame(parent=self)  # NAV20
        # textChanged carries str
        self.search_frame.search_line.textChanged.connect(self.do_search)

        # layout
        grid = QGridLayout(self)
        grid.setSpacing(0)
        grid.setVerticalSpacing(0)
        grid.setContentsMargins(0, 0, 0, 0)
        grid.setRowStretch(1, 1)

        grid.addWidget(info_label, 0, 0, 1, 1)
        grid.addWidget(self.address_bar, 0, 1, 1, 1)
        grid.addWidget(self.nav_bar, 0, 2, 1, 1)

        grid.addWidget(self.webkit, 1, 0, 1, 3)

        grid.addWidget(self.search_frame, 2, 0, 1, 3)
        grid.addWidget(self.pbar, 3, 0, 1, 3)

        def show_search():
            """ One-time callback for QShortcut NAV20 """
            self.search_frame.setVisible(True)
            self.search_frame.search_line.setFocus()

        def hide_search():
            """ One-time callback for QShortcut NAV20 """
            self.search_frame.setVisible(False)
            self.webkit.findText("")
            self.webkit.setFocus()

        def navigate_completion(key=Qt.Key_Down):
            """ Sends an "arrow press" to the completion popup to navigate
            results.

            Not the best way to do this. It would be better to find out what
            function is being called by that arrow press.

            AB01

            """
            event = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier)

            self.address_bar.completer().popup().keyPressEvent(event)

        # the star swallows all arguments that aren't named 'store'
        def reset_addressbar(*, store=False):
            """ Restore the address bar to its original address and color (it
            could have changed because of a hover event).

            Optionally, store the original address in the clipboard.

            AB03

            """

            if self.current['address']:
                self.address_bar.set_txt_color(self.current['address'],
                                               color=QColor(0, 0, 0))

            if store:
                clipboard(self.current['address'])

        # urlChanged carries QUrl (ignored)
        self.webkit.urlChanged.connect(reset_addressbar)

        def enter_address_bar(clear=True):
            """ do not try entering the address bar if a load is in
            progress; do an 'stop' first

            AB00

            """

            if 'in_page_load' not in self.webkit.attr:
                if clear:
                    self.address_bar.clear_and_focus()
                else:
                    self.address_bar.setFocus()

        def cancel():
            """ if we're in the middle of loading the document, stop loading.
            Otherwise, hide the message label. The general concept is to reach
            a basic state.

            """

            if 'in_page_load' not in self.webkit.attr:
                self.message_label.hide()
                self.webkit.update()
            else:
                self.webkit.stop()

        set_shortcuts([
            # search NAV20
            ("G", self.webkit, show_search),
            ("Escape", self.search_frame, hide_search),
            ("Return", self.search_frame, self.do_search),
            ("Ctrl+J", self.search_frame, self.do_search),
            # go to page AB00
            ("Ctrl+J", self.address_bar, partial(
                self.webkit.navigate, self.address_bar)),
            ("Return", self.address_bar, partial(
                self.webkit.navigate, self.address_bar)),
            # address bar interaction
            ("A", self.webkit, cancel),
            ("Ctrl+L", self.webkit, enter_address_bar),  # AB00
            ("Ctrl+Shift+L", self.webkit, partial(
                enter_address_bar, clear=False)),
            ("Escape", self.address_bar, self.webkit.setFocus),  # AB00
            ("Ctrl+I", self.address_bar, navigate_completion),  # AB01
            ("Ctrl+P", self.address_bar, partial(
                navigate_completion, Qt.Key_Up)),
            # in-page element navigation
            ("Ñ", self, self.enter_nav),  # NAV11
            (";", self, self.enter_nav),
            # DOM01
            ("Ctrl+Ñ", self, partial(self.enter_nav, target="titles")),
            # toggle
            ("Q", self.webkit, self.toggle_script),  # TOG01
            # clipboard
            ("E", self, partial(reset_addressbar, store=True))  # CB05
            ])

    def enter_nav(self, target="links"):
        """ A request for access-key navigation was received; display
        link labels and go to the input area

        NAV11

        """

        self.webkit.make_labels(target)
        if self.webkit.map_tags:
            self.nav_bar.show()
            self.nav_bar.setFocus()

    def toggle_script(self):
        """ Retrieves the current javascript state for the tab and sets
        the opposite

        Callback for shortcut action

        TOG01

        """

        self.webkit.javascript(not self.webkit.javascript())

    def load_progress(self, val):
        """ Callback for connection """

        self.pbar.setValue(val)
        self.set_title("{}% {}".format(val, self.current['title']))

    # connect (en constructor)
    def load_started(self):
        """ Callback for connection """

        self.address_bar.completer().popup().close()
        self.search_frame.setVisible(False)

        self.pbar.setValue(0)
        self.pbar.setVisible(True)

    # connect (en constructor)
    def load_finished(self, success):
        """ Callback for connection """

        self.webkit.navlist = []

        self.pbar.setVisible(False)
        self.set_title(self.current['title'])

        if self.address_bar.hasFocus():
            self.webkit.setFocus()

        if not success:
            notify("[F]")
            print("loadFinished: failed",
                  self.webkit.page().mainFrame().requestedUrl())

    # connect (en constructor)
    def save_title(self, title):
        """ Store a recently changed title, and display it """
        if title:
            self.current['title'] = title
            self.set_title(title)

    def set_title(self, title):
        """ Go upwards to the main window's tab widget and set this
        tab's title
        """

        if title is None:
            title = "[NO TITLE]"

        mainwin().tab_widget.setTabText(
            mainwin().tab_widget.indexOf(self),
            title[:40])

    # connection in constructor and action
    def do_search(self, search=None):
        """ Find text on the currently loaded web page. If no text
        is provided, it's extracted from the search widget.

        NAV20

        """
        if search is None:
            search = self.search_frame.search_line.text()
        self.webkit.findText(search, QWebPage.FindWrapsAroundDocument)
Esempio n. 14
0
class FSMainWindow(QMainWindow, FSBase):
    """
    Main Window
    """
    def __init__(self):
        QMainWindow.__init__(self)
        FSBase.__init__(self)

        self.progressbar = None
        self.tab_widget = None
        self.file_tree_widget = None
        self.file_tree_model = None
        self.file_scanner_thread = None

        self.movie_table_widget = None
        self.movie_table_model = None
        self.movie_scanner_thread = None

        self.build_ui()
        self.build_content()

    def build_ui(self):
        self.setWindowTitle("Filesystem Analyzer")

        settings_action = QAction(QIcon("res/settings.svg"), "Settings", self)
        settings_action.setShortcut("Ctrl+S")
        settings_action.triggered.connect(self.settings_action_handler)

        set_path_action = QAction(QIcon("res/directory-submission-symbol.svg"),
                                  "Set path", self)
        set_path_action.setShortcut("Ctrl+N")
        set_path_action.triggered.connect(self.set_path_action_handler)

        refresh_action = QAction(QIcon("res/reload.svg"), "Refresh", self)
        refresh_action.setShortcut("Ctrl+R")
        refresh_action.triggered.connect(self.refresh_action_handler)

        menu_bar = self.menuBar()
        action_menu = menu_bar.addMenu("&Action")
        action_menu.addAction(settings_action)
        action_menu.addAction(set_path_action)
        action_menu.addAction(refresh_action)
        toolbar = self.addToolBar("Exit")
        toolbar.addAction(settings_action)
        toolbar.addAction(set_path_action)
        toolbar.addAction(refresh_action)

        self.progressbar = QProgressBar(self)
        self.progressbar.hide()
        self.progressbar.setRange(0, 100)

        cancel_button = QPushButton(QIcon("res/cancel-button.svg"), "Cancel",
                                    self)
        cancel_button.clicked.connect(self.set_path_cancel)

        self.statusBar().addPermanentWidget(self.progressbar)
        self.statusBar().addPermanentWidget(cancel_button)

        self.tab_widget = QTabWidget(self)

        self.file_tree_widget = FSFileTreeWidget()
        self.file_tree_model = FSFileTreeModel()
        self.file_tree_widget.setModel(self.file_tree_model)

        self.movie_table_widget = FSMovieTableWidget()
        self.movie_table_widget.setShowGrid(False)
        self.movie_table_widget.setAlternatingRowColors(True)
        self.movie_table_widget.verticalHeader().setVisible(False)
        self.movie_table_widget.setSelectionBehavior(QTableView.SelectRows)
        self.movie_table_model = FSMovieTableModel()
        self.movie_table_widget.setModel(self.movie_table_model)
        self.tab_widget.addTab(self.file_tree_widget, "General")
        self.tab_widget.addTab(self.movie_table_widget, "Movies")
        self.setCentralWidget(self.tab_widget)

        last_tab_index = self.app.load_setting("last_tab_index")
        if last_tab_index:
            self.tab_widget.setCurrentIndex(int(last_tab_index))
        self.tab_widget.currentChanged.connect(self.tab_widget_changed)

        self.show()

    def settings_action_handler(self):
        settings_dialog = FSSettingsDialog(self)
        settings_dialog.show()

    def build_content(self):
        path = self.app.load_setting("path")
        self.set_path(path)

    def set_path_action_handler(self):
        file_dialog = QFileDialog()
        path = file_dialog.getExistingDirectory(
            self, "Select directory", "/home/",
            QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)
        self.logger.info("Path set to %s", path)
        self.set_path(path)
        self.app.save_setting("path", path)

    def set_path(self, path):
        self.progressbar.show()

        if self.tab_widget.currentIndex() == 0:
            self.file_tree_model.reset_root()
            file_scanner_context = FSFileScannerContext(
                path, self.file_tree_model.root)
            self.file_scanner_thread = FSFileScannerTask(
                self, file_scanner_context)
            self.file_scanner_thread.notifyProgress.connect(
                self.update_progress)
            self.file_scanner_thread.notifyFinish.connect(
                self.set_path_action_finish)
            self.file_scanner_thread.notifyError.connect(self.report_error)
            self.file_scanner_thread.start()
        else:
            movie_extensions = self.app.load_setting(
                self.app.ExtensionSettings[FSExtensionType.TYPE_MOVIE])
            movie_extensions_list = [
                movie_extension.strip()
                for movie_extension in movie_extensions.split(",")
            ]
            movie_scanner_context = FSMovieScannerContext(
                path, self.movie_table_model.movies, movie_extensions_list)
            self.movie_scanner_thread = FSMovieScannerTask(
                self, movie_scanner_context)
            self.movie_scanner_thread.notifyProgress.connect(
                self.update_progress)
            self.movie_scanner_thread.notifyFinish.connect(
                self.set_path_action_finish)
            self.movie_scanner_thread.notifyError.connect(self.report_error)
            self.movie_scanner_thread.start()

    def set_path_action_finish(self):
        self.progressbar.hide()
        if self.tab_widget.currentIndex() == 0:
            self.file_tree_model.reset_model()
            self.file_tree_widget.setColumnWidth(0, 250)
        else:
            self.movie_table_model.reset_model()
            self.movie_table_widget.resizeColumnsToContents()

    def set_path_cancel(self):
        self.file_scanner_thread.stop_flag = True

    def refresh_action_handler(self):
        path = self.app.load_setting("path")
        self.set_path(path)

    def update_progress(self, value):
        self.progressbar.setValue(value)

    def report_error(self, error):
        print(error)

    def tab_widget_changed(self, index):
        self.app.save_setting("last_tab_index", index)
Esempio n. 15
0
class SplashScreen(QSplashScreen):
    """ Display a Splashscreen """

    signal_done = QtCore.pyqtSignal()

    def __init__(self):
        QSplashScreen.__init__(self, QtGui.QPixmap(),
                               QtCore.Qt.WindowStaysOnTopHint)

        self.rootDir = Path(__file__).parent

        # default values
        self.image = None
        self.version = "Version: 3.x"

        # pixmap.height - ?
        self.progress_y = 68
        # pixmap.width - ?
        self.vx = 24
        # pixmap.height - ?
        self.vy = 32
        # message font size
        self.msize = 12

        self.cv = OpenCVLib()

        self.progressBar = QProgressBar(self)
        self.progressBar.setMinimum(0)
        self.progressBar.setValue(0)
        self.progressBar.setMaximum(100)
        self.progressBar.setTextVisible(False)
        self.setPositionProgressBar()

        self.message = QLabel(self)
        self.message.setFont(QFont("Arial", self.msize))
        self.message.setStyleSheet("QLabel { color : #000000; }")
        self.message.setAlignment(Qt.AlignCenter)

        # Shadow Effekt
        effect = QGraphicsDropShadowEffect(self)
        effect.setBlurRadius(5)
        effect.setColor(QColor("#ffffff"))
        effect.setOffset(1, 1)
        self.message.setGraphicsEffect(effect)
        self.setPositionMessage()
        # self.message.hide()

        # CSS Styling
        self.setStyleSheet("""
            QProgressBar{
              border: 1px solid #eeeeee;
              text-align: center;
              padding: 0;
              margin-top:  10px;
            }
            QProgressBar::chunk{
              background-color: #3daee9;
              width: 0.34em;
              margin:  0 1px;
            }
            """)

    def show(self, *args, **kwargs):
        if self.image == None:
            raise ValueError('Specify an Image via SplashScreen::setImage()')
        return QSplashScreen.show(self, *args, **kwargs)

    def setMessage(self, msg):
        self.message.setText("%s ..." % (msg))
        self.message.show()

    def setPositionMessage(self):
        """ place Message on screen """
        # where is progress?
        p = self.progressBar.geometry()
        self.message.setGeometry(0,
                                 p.y() - self.msize,
                                 self.pixmap().width(), 2 * self.msize)
        self.message.updateGeometry()

    def setPositionProgressBar(self):
        """ place ProgressBar on screen """
        margin = 10
        # x, y, w, h
        self.progressBar.setGeometry(margin,
                                     self.pixmap().height() - self.progress_y,
                                     self.pixmap().width() - 2 * margin, 20)
        self.progressBar.updateGeometry()

    def scale(self, pix):
        gold = 0.618
        h = pix.size().height()
        w = pix.size().width()

        # max width 68% of screen
        screen = QGuiApplication.screens()[0]
        new_w = screen.geometry().width() * gold
        new_h = h * new_w / w

        # python resize
        # return pix.scaled(new_w, new_h, Qt.KeepAspectRatioByExpanding | Qt.SmoothTransformation)
        # resize with opencv
        Qimg = pix.toImage()
        img = self.cv.QImage2MAT(Qimg)
        resized = self.cv.resizeTo(img, new_w, new_h)
        return self.cv.MAT2QPixmap(resized)

    def setVersion(self, version):
        """ adds a Version Number and updates the image """
        self.version = "Version: %s" % version

    def paintEvent(self, *args, **kwargs):
        """ override, important to work """
        return QSplashScreen.paintEvent(self, *args, **kwargs)

    def setImage(self, img):
        """ sets the image and adds a Version Number """

        self.image = self.rootDir.joinpath(img).as_posix()
        splash_pix = QtGui.QPixmap(self.image, format='jpg')
        if splash_pix.isNull():
            raise ValueError('Error loading Image [self.image]')

        # Add version
        painter = QtGui.QPainter(splash_pix)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setFont(QFont("Arial", 18))
        painter.setPen(QColor("#666666"))
        painter.drawText(0, 0,
                         splash_pix.size().width() - self.vx,
                         splash_pix.size().height() - self.vy,
                         QtCore.Qt.AlignBottom | QtCore.Qt.AlignRight,
                         self.version)
        painter.end()

        self.setPixmap(self.scale(splash_pix))
        # ----------------------------------------------
        # other stuff
        self.setPositionProgressBar()
        self.setPositionMessage()

    def step(self):
        """ a preloading step is done """
        self.progressBar.setValue(self.progressBar.value() + 1)
        self.progressBar.repaint()

        if (self.progressBar.value() >= (self.progressBar.maximum() - 1)):
            self.signal_done.emit()

    def setProgressMax(self, maxval):
        self.progressBar.setMaximum(maxval)
Esempio n. 16
0
class ProgressBar(QDialog):

    def __init__(self, __images_dir, parent=None):

        QDialog.__init__(self, parent=parent)

        self.__thread      = None       # l'objet QThread qui fera le calcul
        self.__images_dir  = __images_dir # le dossier des images
        self.__images_list = None       # la liste des images *.png à traiter
        self.__vMin        = None       # la valeur min de la barre
        self.__vMax        = None       # la valeur max de la barre

        self.title = QLabel("",self)
        self.pbar  = QProgressBar(self)
        self.pbar.setGeometry(30, 40, 250, 25)

        self.btnOk = QPushButton('OK', self)
        self.btnOk.clicked.connect(self.close)
        self.btnOk.setEnabled(False)

        self.btnCancel = QPushButton('Cancel', self)
        self.btnCancel.clicked.connect(self.Cancel)
        self.btnCancel.setEnabled(True)

        vbox = QVBoxLayout()
        vbox.addWidget(self.title)
        vbox.addWidget(self.pbar)
        hbox = QHBoxLayout()
        hbox.addWidget(self.btnOk)
        hbox.addWidget(self.btnCancel)
        vbox.addLayout(hbox)
        self.setLayout(vbox)

        self.setModal(True)
        self.setWindowModality(Qt.ApplicationModal)
        self.show()

    def configure_for_video_extraction(self, videoCapture, imagesFormat):
        self.__vMin = 1
        self.__vMax = int(videoCapture.get(cv2.CAP_PROP_FRAME_COUNT))
        self.pbar.setRange(self.__vMin, self.__vMax)
        self.pbar.setValue(self.__vMin)

        self.setWindowTitle('Découpage de la vidéo')
        self.title.setText("Extraction images : ")

        self.__thread = SplitVideoInImagesThread(videoCapture,
                                                 self.__images_dir,
                                                 imagesFormat)

        self.__thread.ImageExtractedSig.connect(self.updateProgressBar)
        self.__thread.ImageProblemSig.connect(self.updateProgressBar)
        self.__thread.start()

    def configure_for_target_extraction(self,
                                        target_RGB,
                                        algo,
                                        marge_couleur,
                                        target_pos,
                                        first_last_step):

        self.__images_list = [ f for f in os.listdir(self.__images_dir) if f.endswith(".png")]
        self.__images_list.sort()

        self.__vMin, self.__vMax, _ =  first_last_step
        self.pbar.setRange(self.__vMin, self.__vMax)
        self.pbar.setValue(self.__vMin)

        self.setWindowTitle('Traitement des images du dossier {}'\
                            .format(self.__images_dir))

        # Lancer un __thread pour le travil d'extraction des images de la vidéo :
        self.__thread = ExtractTargetFomImagesThread(self.__images_dir,
                                                     self.__images_list,
                                                     target_RGB,
                                                     algo,
                                                     marge_couleur,
                                                     target_pos,
                                                     first_last_step)
        self.__thread.TargetExtractedSig.connect(self.updateProgressBar)
        self.__thread.TargetProblemSig.connect(self.updateProgressBar)
        self.__thread.start()

    def Cancel(self):
        # Appui sur le bouton Cancel.

        # Arrêter le Thread en cours :
        self.__thread.quit()
        # Fermer la fenêtre QDialog avec un code retour à -1 :
        self.done(-1)

    def updateProgressBar(self, value):
        if value >= 0:
            # l'image N° <value> vient d'être traitée avec succès :
            self.pbar.setValue(value)
            self.btnOk.setEnabled(True)
            if value == 0 or value == self.pbar.maximum():
                self.btnOk.setEnabled(True)
            mess = "{:3d}/{:3d}".format(value,self.__vMax)
        else:
            # l'image N° <value> a provoqué une erreur :
            mess = self.title.text()
            mess += '\n Erreur image {}'.format(-value)

        self.title.setText("Extraction images : " + mess)
Esempio n. 17
0
class ConvertDialog(QDialog):

    hide_text = _('&Hide styles')
    show_text = _('&Show styles')
    prince_log = ''
    prince_file = ''
    prince_css = ''

    # GUI definition
    def __init__(self, mi, fmt, opf, oeb, icon):
        '''
        :param mi: The book metadata
        :param fmt: The source format used for conversion
        :param opf: The path to the OPF file
        :param oeb: An OEB object for the unpacked book
        :param icon: The window icon
        '''
        self.opf = opf
        self.oeb = oeb
        self.mi = mi
        # The unpacked book needs to be parsed before, to read the contents
        # of the prince-style file, if it exists
        self.parse()

        QDialog.__init__(self)

        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setWindowTitle(_('Convert to PDF with Prince'))
        self.setWindowIcon(icon)

        self.l = QVBoxLayout()
        self.setLayout(self.l)

        self.title_label = QLabel(_('<b>Title:</b> %s') % self.mi.title)
        self.l.addWidget(self.title_label)

        self.format_label = QLabel(_('<b>Source format:</b> %s') % fmt)
        self.l.addWidget(self.format_label)

        self.add_book = QCheckBox(_('&Add PDF to the book record'))
        self.add_book.setToolTip(_('<qt>Add the converted PDF to the selected book record</qt>'))
        self.add_book.setChecked(prefs['add_book'])
        self.add_book.stateChanged.connect(self.set_add_book)
        self.l.addWidget(self.add_book)

        self.ll = QHBoxLayout()
        self.ll.setAlignment(Qt.AlignLeft)
        self.l.addLayout(self.ll)

        self.label_css = QLabel(_('&Custom style:'))
        self.ll.addWidget(self.label_css)

        self.css_list = QComboBox()
        self.css_list.setToolTip(_('<qt>Select one style to use. Additional styles can be created in the plugin configuration</qt>'))
        for key in sorted(prefs['custom_CSS_list'], key=lambda x: x.lower()):
            self.css_list.addItem(key, key)
        self.css_list.setCurrentIndex(self.css_list.findText(prefs['default_CSS']))
        self.css_list.currentIndexChanged.connect(self.set_css)
        self.ll.addWidget(self.css_list)
        self.label_css.setBuddy(self.css_list)

        self.ll_ = QHBoxLayout()
        self.l.addLayout(self.ll_)

        self.label_args = QLabel(_('A&dditional command-line arguments:'))
        self.ll_.addWidget(self.label_args)

        self.args = QLineEdit(self)
        self.args.setText(prefs['custom_args_list'][prefs['default_CSS']])
        self.args.setToolTip(_('<qt>Specify additional command-line arguments for the conversion</qt>'))
        self.ll_.addWidget(self.args)
        self.label_args.setBuddy(self.args)

        self.css = QTabWidget()
        self.l.addWidget(self.css)

        self.css1 = TextEditWithTooltip(self, expected_geometry=(80,20))
        self.css1.setLineWrapMode(TextEditWithTooltip.NoWrap)
        self.css1.load_text(self.replace_templates(prefs['custom_CSS_list'][prefs['default_CSS']]),'css')
        self.css1.setToolTip(_('<qt>This stylesheet can be modified<br/>The default can be configured</qt>'))
        i = self.css.addTab(self.css1, _('C&ustom CSS'))
        self.css.setTabToolTip(i, _('<qt>Custom CSS stylesheet to be used for this conversion</qt>'))

        monofont = QFont('')
        monofont.setStyleHint(QFont.TypeWriter)

        if (self.prince_css):
            self.css2 = QPlainTextEdit()
            self.css2.setStyleSheet('* { font-family: monospace }')
            self.css2.setLineWrapMode(QPlainTextEdit.NoWrap)
            self.css2.setPlainText(self.prince_css)
            self.css2.setReadOnly(True)
            self.css2.setToolTip(_('<qt>This stylesheet cannot be modified</qt>'))
            i = self.css.addTab(self.css2, _('&Book CSS'))
            self.css.setTabToolTip(i, _('<qt>Book-specific CSS stylesheet included in the ebook file</qt>'))

        self.ll = QHBoxLayout()
        self.l.addLayout(self.ll)

        if (prefs['show_CSS']):
            self.toggle = QPushButton(self.hide_text, self)
        else:
            self.toggle = QPushButton(self.show_text, self)
        self.toggle.setToolTip(_('<qt>Show/hide the additional styles used for the conversion</qt>'))
        self.toggle.clicked.connect(self.toggle_tabs)

        self.convert = QPushButton(_('Con&vert'), self)
        self.convert.setToolTip(_('<qt>Run the conversion with Prince</qt>'))
        self.convert.setDefault(True)

        self.buttons = QDialogButtonBox(QDialogButtonBox.Cancel)
        self.buttons.addButton(self.toggle, QDialogButtonBox.ResetRole)
        self.buttons.addButton(self.convert, QDialogButtonBox.AcceptRole)
        self.l.addWidget(self.buttons)
        self.buttons.accepted.connect(self.prince_convert)
        self.buttons.rejected.connect(self.reject)

        if (not prefs['show_CSS']):
            self.css.hide()
        self.adjustSize()

    def toggle_tabs(self):
        '''
        Enable/disable the CSS tabs, and store the setting
        '''
        if (self.css.isVisible()):
            self.css.hide()
            self.label_args.hide()
            self.args.hide()
            self.toggle.setText(self.show_text)
            self.adjustSize()
        else:
            self.css.show()
            self.label_args.show()
            self.args.show()
            self.toggle.setText(self.hide_text)
            self.adjustSize()
        prefs['show_CSS'] = self.css.isVisible()

    def set_add_book(self):
        '''
        Save the status of the add_book checkbox
        '''
        prefs['add_book'] = self.add_book.isChecked()

    def set_css(self):
        '''
        Fill the custom CSS text box with the selected stylesheet (and command-line arguments)
        '''
        style = unicode(self.css_list.currentText())
        self.css1.load_text(self.replace_templates(prefs['custom_CSS_list'][style]),'css')
        self.args.setText(prefs['custom_args_list'][style])
        prefs['default_CSS'] = style

    def parse(self):
        '''
        Parse the unpacked OPF file to find and read the prince-style file
        '''
        from calibre.constants import DEBUG
        from os.path import dirname, join
        from lxml import etree
        import codecs

        if DEBUG: print(_('Parsing book...'))
        opf_dir = dirname(self.opf)
        root = etree.parse(self.opf).getroot()
        metadata = root.find('{*}metadata')
        for meta in metadata.findall("{*}meta[@name='prince-style']"):
            prince_id = meta.get('content')
            for item in self.oeb.manifest:
                if (item.id == prince_id):
                    self.prince_file = item.href
                    break
        if (self.prince_file):
            fl = codecs.open(join(opf_dir, self.prince_file), 'rb', 'utf-8')
            self.prince_css = fl.read()
            fl.close()

    def replace_templates(self, text):
        '''
        Replace templates (enclosed by '@{@', '@}@') in the input text
        '''
        import re
        import json
        from calibre.ebooks.metadata.book.formatter import SafeFormat
        from calibre.constants import DEBUG

        matches = list(re.finditer('@{@(.+?)@}@',text,re.DOTALL))
        results = {}
        for match in reversed(matches):
            result = SafeFormat().safe_format(match.group(1), self.mi, ('EXCEPTION: '), self.mi)
            # Escape quotes, backslashes and newlines
            result = re.sub(r'''['"\\]''', r'\\\g<0>', result)
            result = re.sub('\n', r'\A ', result)
            results[match.group(1)] = result
            text = text[:match.start(0)] + result + text[match.end(0):]
        if DEBUG:
            print(_('Replacing templates'))
            for match in matches:
                print(_('Found: %s (%d-%d)') % (match.group(1), match.start(0), match.end(0)))
                print(_('Replace with: %s') % results[match.group(1)])
        return text

    def prince_convert(self):
        '''
        Call the actual Prince command to convert to PDF
        '''
        from os import makedirs
        from os.path import dirname, join, exists
        from calibre.ptempfile import PersistentTemporaryFile
        from calibre.constants import DEBUG
        from shlex import split as shsplit

        # All files are relative to the OPF location
        opf_dir = dirname(self.opf)
        base_dir = dirname(self.pdf_file)
        base_dir = join(opf_dir, base_dir)
        try:
            makedirs(base_dir)
        except BaseException:
            if not exists(base_dir): raise

        # Create a temporary CSS file with the box contents
        custom_CSS = PersistentTemporaryFile()
        custom_CSS.write(unicode(self.css1.toPlainText()))
        custom_CSS.close()
        # Create a temporary file with the list of input files
        file_list = PersistentTemporaryFile()
        for item in self.oeb.spine:
            file_list.write(item.href + "\n")
        file_list.close()
        # Build the command line
        command = prefs['prince_exe']
        args = ['-v']
        if self.prince_file:
            args.append('-s')
            args.append(self.prince_file)
        args.append('-s')
        args.append(custom_CSS.name)
        args.append('-l')
        args.append(file_list.name)
        args.append('-o')
        args.append(self.pdf_file)
        # Additional command-line arguments
        args.extend(shsplit(self.args.text()))

        # Hide the convert button and show a busy indicator
        self.convert.setEnabled(False)
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0,0)
        self.progress_bar.setValue(0)
        self.l.addWidget(self.progress_bar)

        # Run the command and return the path to the PDF file
        if DEBUG: print(_('Converting book...'))
        process = QProcess(self)
        process.setWorkingDirectory(opf_dir)
        process.setProcessChannelMode(QProcess.MergedChannels);
        process.error.connect(self.error)
        process.finished.connect(self.end)
        self.process = process
        if DEBUG:
          from subprocess import list2cmdline
          line = list2cmdline([command] + args)
          print(_('Command line: %s') % line)
        process.start(command, args)

    def error(self, rc):
        '''
        Show a message when there is an error in the command
        :param rc: The error code
        '''
        from calibre.gui2 import error_dialog

        # Remove the progress bar while the error message is displayed
        self.progress_bar.hide()
        self.progress_bar.deleteLater()
        error_dialog(self, _('Process error'), _('<p>Error code: %s'
            '<p>make sure Prince (<a href="http://www.princexml.com">www.princexml.com</a>) is installed '
            'and the correct command-line-interface executable is set in the configuration of this plugin, '
            'which is usually:'
            '<ul><li>In Windows: <code><i>Prince_folder</i>\\Engine\\bin\\prince.exe</code>'
            '    <li>In Linux: <code>prince</code>'
            '</ul>') % rc, show=True)
        self.pdf_file = None
        self.accept()

    def end(self, rc):
        '''
        Close and return the filename when the process ends
        :param rc: The return code (0 if successful)
        '''
        from os.path import join

        self.prince_log = unicode(self.process.readAllStandardOutput().data())
        opf_dir = unicode(self.process.workingDirectory())
        if (rc == 0):
            self.pdf_file = join(opf_dir, self.pdf_file)
        else:
            self.pdf_file = None
        self.accept()
Esempio n. 18
0
class DownloadDialog(QDialog):  # {{{

    def __init__(self, url, fname, parent):
        QDialog.__init__(self, parent)
        self.setWindowTitle(_('Download %s')%fname)
        self.l = QVBoxLayout(self)
        self.purl = urlparse(url)
        self.msg = QLabel(_('Downloading <b>%(fname)s</b> from %(url)s')%dict(
            fname=fname, url=self.purl.netloc))
        self.msg.setWordWrap(True)
        self.l.addWidget(self.msg)
        self.pb = QProgressBar(self)
        self.pb.setMinimum(0)
        self.pb.setMaximum(0)
        self.l.addWidget(self.pb)
        self.bb = QDialogButtonBox(QDialogButtonBox.Cancel, Qt.Horizontal, self)
        self.l.addWidget(self.bb)
        self.bb.rejected.connect(self.reject)
        sz = self.sizeHint()
        self.resize(max(sz.width(), 400), sz.height())

        fpath = PersistentTemporaryFile(os.path.splitext(fname)[1])
        fpath.close()
        self.fpath = fpath.name

        self.worker = Worker(url, self.fpath, Queue())
        self.rejected = False

    def reject(self):
        self.rejected = True
        QDialog.reject(self)

    def start_download(self):
        self.worker.start()
        QTimer.singleShot(50, self.update)
        self.exec_()
        if self.worker.err is not None:
            error_dialog(self.parent(), _('Download failed'),
                _('Failed to download from %(url)r with error: %(err)s')%dict(
                    url=self.worker.url, err=self.worker.err),
                det_msg=self.worker.tb, show=True)

    def update(self):
        if self.rejected:
            return

        try:
            progress = self.worker.rq.get_nowait()
        except Empty:
            pass
        else:
            self.update_pb(progress)

        if not self.worker.is_alive():
            return self.accept()
        QTimer.singleShot(50, self.update)

    def update_pb(self, progress):
        transferred, block_size, total = progress
        if total == -1:
            self.pb.setMaximum(0)
            self.pb.setMinimum(0)
            self.pb.setValue(0)
        else:
            so_far = transferred * block_size
            self.pb.setMaximum(max(total, so_far))
            self.pb.setValue(so_far)

    @property
    def err(self):
        return self.worker.err
Esempio n. 19
0
class WebTab(QWidget):
    """ The tab contains chrome plus a web view; is hosted on a tab bar """
    def __init__(self, parent=None):
        super(WebTab, self).__init__(parent)

        self.current = {'title': "[EMPTY]", 'address': ""}

        # address bar
        self.address_bar = AddressBar(parent=self)

        # webkit (the actual "web engine")
        self.webkit = WebView(parent=self)

        # set_prefix: app defined, carries str
        self.webkit.set_prefix.connect(self.address_bar.set_model)  # CFG02
        # javascript_state: app defined, carries bool
        self.webkit.javascript_state.connect(self.address_bar.set_bgcolor)

        # small label displaying instance ID and pending tab operations

        info_label = QLabel(parent=self)
        info_label.setText('?')  # CFG02

        # webkit_info: app defined, carries str
        self.webkit.attr.webkit_info.connect(info_label.setText)

        def update_address(qurl):
            """ The 'connect' gives a QUrl and setText receives a string;
            can't just connect setText

            Required because a 3XX HTTP redirection will change the address,
            and without updating, the address bar will be left stale

            AB02 AB03

            """
            self.current['address'] = qurl.toString()
            self.address_bar.setText(self.current['address'])

        # urlChanged carries QUrl; loadStarted carries nothing;
        # loadFinished carries bool; titleChanged carries str;
        # loadProgress carries int
        self.webkit.urlChanged.connect(update_address)
        self.webkit.loadStarted.connect(self.load_started)
        self.webkit.loadFinished.connect(self.load_finished)
        self.webkit.titleChanged.connect(self.save_title)
        self.webkit.loadProgress.connect(self.load_progress)

        def fill_notifier(message, request):
            """ sends a message to be displayed by the notifier

            """
            notify(message + " " + request.url().toString())

        # downloadRequested carries QNetworkRequest
        self.webkit.page().downloadRequested.connect(
            partial(fill_notifier, "download"))
        # unsupportedContent carries QNetworkReply
        self.webkit.page().unsupportedContent.connect(
            partial(fill_notifier, "unsupported"))

        # input area for access-key navigation

        self.nav_bar = NavigateInput(parent=self)
        # editingFinished carries nothing
        self.nav_bar.editingFinished.connect(self.webkit.clear_labels)

        # textEdited carries str
        self.nav_bar.textEdited.connect(self.webkit.akeynav)
        # nonvalid_tag (app defined) carries nothing
        self.webkit.nonvalid_tag.connect(self.nav_bar.clear)

        # 'corner' message and notification label, not on timer, smaller

        self.message_label = MessageLabel(self.webkit)

        def handle_hovered(link, title, content):
            """ When hovered, if ALT is pressed, show message label;
            hide otherwise

            """

            if ((QApplication.keyboardModifiers() & Qt.AltModifier)
                    and (link or title or content)):
                # ugly hack to ensure proper resizing; find a better way?
                self.message_label.hide()
                self.message_label.setText(link + " " + title + " " + content)
                self.message_label.show()
            else:
                self.message_label.hide()

        # linkHovered carries str, str, str
        self.webkit.page().linkHovered.connect(handle_hovered)

        def handle_signaled(title):
            """ We received a string through a signal; display it on
            the message label

            """

            # if title:
            self.message_label.hide()
            self.message_label.setText(title)
            self.message_label.show()

        # show_message (app defined) carries str
        self.webkit.show_message.connect(handle_signaled)
        # loadStarted carries nothing
        self.webkit.loadStarted.connect(self.message_label.hide)

        # At the time navigation is requested load_requested is sent, and the
        # requested url is set as text in grey at the address bar. Once the
        # urlChanged signal is received, the actual url is set in black.

        # load_requested (app defined) carries str
        self.webkit.load_requested.connect(
            partial(self.address_bar.set_txt_color,
                    color=QColor(128, 128, 128)))

        def hide_message_label(*_):
            """ WARNING scrollRequested carries int, int, QRect;
            star swallows all

            """
            self.message_label.hide()

        self.webkit.page().scrollRequested.connect(hide_message_label)

        # focus_webkit (app defined) carries nothing
        self.webkit.hide_overlay.connect(self.message_label.hide)
        self.webkit.focus_webkit.connect(self.address_bar.restore)

        # progress bar
        self.pbar = QProgressBar(self)

        self.pbar.setRange(0, 100)
        self.pbar.setTextVisible(False)
        self.pbar.setVisible(False)
        self.pbar.setMaximumHeight(7)

        # search in page
        self.search_frame = SearchFrame(parent=self)  # NAV20
        # textChanged carries str
        self.search_frame.search_line.textChanged.connect(self.do_search)

        # layout
        grid = QGridLayout(self)
        grid.setSpacing(0)
        grid.setVerticalSpacing(0)
        grid.setContentsMargins(0, 0, 0, 0)
        grid.setRowStretch(1, 1)

        grid.addWidget(info_label, 0, 0, 1, 1)
        grid.addWidget(self.address_bar, 0, 1, 1, 1)
        grid.addWidget(self.nav_bar, 0, 2, 1, 1)

        grid.addWidget(self.webkit, 1, 0, 1, 3)

        grid.addWidget(self.search_frame, 2, 0, 1, 3)
        grid.addWidget(self.pbar, 3, 0, 1, 3)

        def show_search():
            """ One-time callback for QShortcut NAV20 """
            self.search_frame.setVisible(True)
            self.search_frame.search_line.setFocus()

        def hide_search():
            """ One-time callback for QShortcut NAV20 """
            self.search_frame.setVisible(False)
            self.webkit.findText("")
            self.webkit.setFocus()

        def navigate_completion(key=Qt.Key_Down):
            """ Sends an "arrow press" to the completion popup to navigate
            results.

            Not the best way to do this. It would be better to find out what
            function is being called by that arrow press.

            AB01

            """
            event = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier)

            self.address_bar.completer().popup().keyPressEvent(event)

        # the star swallows all arguments that aren't named 'store'
        def reset_addressbar(*, store=False):
            """ Restore the address bar to its original address and color (it
            could have changed because of a hover event).

            Optionally, store the original address in the clipboard.

            AB03

            """

            if self.current['address']:
                self.address_bar.set_txt_color(self.current['address'],
                                               color=QColor(0, 0, 0))

            if store:
                clipboard(self.current['address'])

        # urlChanged carries QUrl (ignored)
        self.webkit.urlChanged.connect(reset_addressbar)

        def enter_address_bar(clear=True):
            """ do not try entering the address bar if a load is in
            progress; do an 'stop' first

            AB00

            """

            if 'in_page_load' not in self.webkit.attr:
                if clear:
                    self.address_bar.clear_and_focus()
                else:
                    self.address_bar.setFocus()

        def cancel():
            """ if we're in the middle of loading the document, stop loading.
            Otherwise, hide the message label. The general concept is to reach
            a basic state.

            """

            if 'in_page_load' not in self.webkit.attr:
                self.message_label.hide()
                self.webkit.update()
            else:
                self.webkit.stop()

        set_shortcuts([
            # search NAV20
            ("G", self.webkit, show_search),
            ("Escape", self.search_frame, hide_search),
            ("Return", self.search_frame, self.do_search),
            ("Ctrl+J", self.search_frame, self.do_search),
            # go to page AB00
            ("Ctrl+J", self.address_bar,
             partial(self.webkit.navigate, self.address_bar)),
            ("Return", self.address_bar,
             partial(self.webkit.navigate, self.address_bar)),
            # address bar interaction
            ("A", self.webkit, cancel),
            ("Ctrl+L", self.webkit, enter_address_bar),  # AB00
            ("Ctrl+Shift+L", self.webkit,
             partial(enter_address_bar, clear=False)),
            ("Escape", self.address_bar, self.webkit.setFocus),  # AB00
            ("Ctrl+I", self.address_bar, navigate_completion),  # AB01
            ("Ctrl+P", self.address_bar, partial(navigate_completion,
                                                 Qt.Key_Up)),
            # in-page element navigation
            ("Ñ", self, self.enter_nav),  # NAV11
            (";", self, self.enter_nav),
            # DOM01
            ("Ctrl+Ñ", self, partial(self.enter_nav, target="titles")),
            # toggle
            ("Q", self.webkit, self.toggle_script),  # TOG01
            # clipboard
            ("E", self, partial(reset_addressbar, store=True))  # CB05
        ])

    def enter_nav(self, target="links"):
        """ A request for access-key navigation was received; display
        link labels and go to the input area

        NAV11

        """

        self.webkit.make_labels(target)
        if self.webkit.map_tags:
            self.nav_bar.show()
            self.nav_bar.setFocus()

    def toggle_script(self):
        """ Retrieves the current javascript state for the tab and sets
        the opposite

        Callback for shortcut action

        TOG01

        """

        self.webkit.javascript(not self.webkit.javascript())

    def load_progress(self, val):
        """ Callback for connection """

        self.pbar.setValue(val)
        self.set_title("{}% {}".format(val, self.current['title']))

    # connect (en constructor)
    def load_started(self):
        """ Callback for connection """

        self.address_bar.completer().popup().close()
        self.search_frame.setVisible(False)

        self.pbar.setValue(0)
        self.pbar.setVisible(True)

    # connect (en constructor)
    def load_finished(self, success):
        """ Callback for connection """

        self.webkit.navlist = []

        self.pbar.setVisible(False)
        self.set_title(self.current['title'])

        if self.address_bar.hasFocus():
            self.webkit.setFocus()

        if not success:
            notify("[F]")
            print("loadFinished: failed",
                  self.webkit.page().mainFrame().requestedUrl())

    # connect (en constructor)
    def save_title(self, title):
        """ Store a recently changed title, and display it """
        if title:
            self.current['title'] = title
            self.set_title(title)

    def set_title(self, title):
        """ Go upwards to the main window's tab widget and set this
        tab's title
        """

        if title is None:
            title = "[NO TITLE]"

        mainwin().tab_widget.setTabText(mainwin().tab_widget.indexOf(self),
                                        title[:40])

    # connection in constructor and action
    def do_search(self, search=None):
        """ Find text on the currently loaded web page. If no text
        is provided, it's extracted from the search widget.

        NAV20

        """
        if search is None:
            search = self.search_frame.search_line.text()
        self.webkit.findText(search, QWebPage.FindWrapsAroundDocument)