コード例 #1
0
class LogDialog(QDialog):

    # GUI definition
    def __init__(self, log, icon):
        '''
        :param log: The text to show in the dialog
        :param icon: The window icon
        '''
        QDialog.__init__(self)

        self.setWindowTitle(_('Prince log'))
        self.setWindowIcon(icon)

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

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

        self.box = QPlainTextEdit()
        self.box.setPlainText(log)
        self.box.setStyleSheet('* { font-family: monospace }')
        self.box.setMinimumWidth(500)
        self.box.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.box.setReadOnly(True)
        self.box.setToolTip(
            _('<qt>Console output from the last Prince run</qt>'))
        self.l.addWidget(self.box)

        self.buttons = QDialogButtonBox(QDialogButtonBox.Ok)
        self.l.addWidget(self.buttons)
        self.buttons.accepted.connect(self.accept)

        self.adjustSize()
コード例 #2
0
ファイル: log_box.py プロジェクト: Jellby/PrincePDF
class LogDialog(QDialog):

    # GUI definition
    def __init__(self, log, icon):
        '''
        :param log: The text to show in the dialog
        :param icon: The window icon
        '''
        QDialog.__init__(self)

        self.setWindowTitle(_('Prince log'))
        self.setWindowIcon(icon)

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

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

        self.box = QPlainTextEdit()
        self.box.setPlainText(log)
        self.box.setStyleSheet('* { font-family: monospace }')
        self.box.setMinimumWidth(500)
        self.box.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.box.setReadOnly(True)
        self.box.setToolTip(_('<qt>Console output from the last Prince run</qt>'))
        self.l.addWidget(self.box)
         
        self.buttons = QDialogButtonBox(QDialogButtonBox.Ok)
        self.l.addWidget(self.buttons)
        self.buttons.accepted.connect(self.accept)

        self.adjustSize()
コード例 #3
0
class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName(_fromUtf8("Dialog"))
        Dialog.resize(497, 235)
        self.gridLayout = QGridLayout(Dialog)
        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
        self.icon_label = QLabel(Dialog)
        self.icon_label.setMaximumSize(
            QtCore.QSize(COVER_ICON_SIZE, COVER_ICON_SIZE))
        self.icon_label.setText(_fromUtf8(""))
        self.icon_label.setPixmap(QPixmap(_fromUtf8(I("dialog_warning.png"))))
        self.icon_label.setScaledContents(False)
        self.icon_label.setObjectName(_fromUtf8("icon_label"))
        self.gridLayout.addWidget(self.icon_label, 0, 0, 1, 1)
        self.msg = QLabel(Dialog)
        self.msg.setText(_fromUtf8(""))
        self.msg.setWordWrap(True)
        self.msg.setOpenExternalLinks(True)
        self.msg.setObjectName(_fromUtf8("msg"))
        self.gridLayout.addWidget(self.msg, 0, 1, 1, 1)
        self.det_msg = QPlainTextEdit(Dialog)
        self.det_msg.setReadOnly(True)
        self.det_msg.setObjectName(_fromUtf8("det_msg"))
        self.gridLayout.addWidget(self.det_msg, 1, 0, 1, 2)
        self.bb = QDialogButtonBox(Dialog)
        self.bb.setOrientation(QtCore.Qt.Horizontal)
        self.bb.setStandardButtons(QDialogButtonBox.Ok)
        self.bb.setObjectName(_fromUtf8("bb"))
        self.gridLayout.addWidget(self.bb, 3, 0, 1, 2)
        self.toggle_checkbox = QCheckBox(Dialog)
        self.toggle_checkbox.setText(_fromUtf8(""))
        self.toggle_checkbox.setObjectName(_fromUtf8("toggle_checkbox"))
        self.gridLayout.addWidget(self.toggle_checkbox, 2, 0, 1, 2)

        self.retranslateUi(Dialog)
        self.bb.accepted.connect(Dialog.accept)
        self.bb.rejected.connect(Dialog.reject)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(_("Dialog"))
コード例 #4
0
class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName(_fromUtf8("Dialog"))
        Dialog.resize(497, 235)
        self.gridLayout = QGridLayout(Dialog)
        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
        self.icon_label = QLabel(Dialog)
        self.icon_label.setMaximumSize(QtCore.QSize(COVER_ICON_SIZE, COVER_ICON_SIZE))
        self.icon_label.setText(_fromUtf8(""))
        self.icon_label.setPixmap(QPixmap(_fromUtf8(I("dialog_warning.png"))))
        self.icon_label.setScaledContents(False)
        self.icon_label.setObjectName(_fromUtf8("icon_label"))
        self.gridLayout.addWidget(self.icon_label, 0, 0, 1, 1)
        self.msg = QLabel(Dialog)
        self.msg.setText(_fromUtf8(""))
        self.msg.setWordWrap(True)
        self.msg.setOpenExternalLinks(True)
        self.msg.setObjectName(_fromUtf8("msg"))
        self.gridLayout.addWidget(self.msg, 0, 1, 1, 1)
        self.det_msg = QPlainTextEdit(Dialog)
        self.det_msg.setReadOnly(True)
        self.det_msg.setObjectName(_fromUtf8("det_msg"))
        self.gridLayout.addWidget(self.det_msg, 1, 0, 1, 2)
        self.bb = QDialogButtonBox(Dialog)
        self.bb.setOrientation(QtCore.Qt.Horizontal)
        self.bb.setStandardButtons(QDialogButtonBox.Ok)
        self.bb.setObjectName(_fromUtf8("bb"))
        self.gridLayout.addWidget(self.bb, 3, 0, 1, 2)
        self.toggle_checkbox = QCheckBox(Dialog)
        self.toggle_checkbox.setText(_fromUtf8(""))
        self.toggle_checkbox.setObjectName(_fromUtf8("toggle_checkbox"))
        self.gridLayout.addWidget(self.toggle_checkbox, 2, 0, 1, 2)

        self.retranslateUi(Dialog)
        self.bb.accepted.connect(Dialog.accept)
        self.bb.rejected.connect(Dialog.reject)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(_("Dialog"))
コード例 #5
0
ファイル: proceed.py プロジェクト: kba/calibre
class ProceedQuestion(QDialog):

    ask_question = pyqtSignal(object, object, object)

    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setAttribute(Qt.WA_DeleteOnClose, False)
        self.setWindowIcon(QIcon(I('dialog_question.png')))

        self.questions = []

        self._l = l = QGridLayout(self)
        self.setLayout(l)

        self.icon_label = ic = QLabel(self)
        ic.setPixmap(QPixmap(I('dialog_question.png')))
        self.msg_label = msg = QLabel('some random filler text')
        msg.setWordWrap(True)
        ic.setMaximumWidth(110)
        ic.setMaximumHeight(100)
        ic.setScaledContents(True)
        ic.setStyleSheet('QLabel { margin-right: 10px }')
        self.bb = QDialogButtonBox()
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        self.log_button = self.bb.addButton(_('View log'), self.bb.ActionRole)
        self.log_button.setIcon(QIcon(I('debug.png')))
        self.log_button.clicked.connect(self.show_log)
        self.copy_button = self.bb.addButton(_('&Copy to clipboard'),
                                             self.bb.ActionRole)
        self.copy_button.clicked.connect(self.copy_to_clipboard)
        self.action_button = self.bb.addButton('', self.bb.ActionRole)
        self.action_button.clicked.connect(self.action_clicked)
        self.show_det_msg = _('Show &details')
        self.hide_det_msg = _('Hide &details')
        self.det_msg_toggle = self.bb.addButton(self.show_det_msg,
                                                self.bb.ActionRole)
        self.det_msg_toggle.clicked.connect(self.toggle_det_msg)
        self.det_msg_toggle.setToolTip(
            _('Show detailed information about this error'))
        self.det_msg = QPlainTextEdit(self)
        self.det_msg.setReadOnly(True)
        self.bb.setStandardButtons(self.bb.Yes | self.bb.No | self.bb.Ok)
        self.bb.button(self.bb.Yes).setDefault(True)

        self.checkbox = QCheckBox('', self)

        l.addWidget(ic, 0, 0, 1, 1)
        l.addWidget(msg, 0, 1, 1, 1)
        l.addWidget(self.checkbox, 1, 0, 1, 2)
        l.addWidget(self.det_msg, 2, 0, 1, 2)
        l.addWidget(self.bb, 3, 0, 1, 2)

        self.ask_question.connect(self.do_ask_question,
                                  type=Qt.QueuedConnection)

    def copy_to_clipboard(self, *args):
        QApplication.clipboard().setText(
            'calibre, version %s\n%s: %s\n\n%s' %
            (__version__, unicode(self.windowTitle()),
             unicode(self.msg_label.text()), unicode(
                 self.det_msg.toPlainText())))
        self.copy_button.setText(_('Copied'))

    def action_clicked(self):
        if self.questions:
            q = self.questions[0]
            self.questions[0] = q._replace(callback=q.action_callback)
        self.accept()

    def accept(self):
        if self.geom_pref:
            gprefs[self.geom_pref] = bytearray(self.saveGeometry())
        if self.questions:
            payload, callback, cancel_callback = self.questions[0][:3]
            self.questions = self.questions[1:]
            cb = None
            if self.checkbox.isVisible():
                cb = bool(self.checkbox.isChecked())
            self.ask_question.emit(callback, payload, cb)
        self.hide()

    def reject(self):
        if self.geom_pref:
            gprefs[self.geom_pref] = bytearray(self.saveGeometry())
        if self.questions:
            payload, callback, cancel_callback = self.questions[0][:3]
            self.questions = self.questions[1:]
            cb = None
            if self.checkbox.isVisible():
                cb = bool(self.checkbox.isChecked())
            self.ask_question.emit(cancel_callback, payload, cb)
        self.hide()

    def do_ask_question(self, callback, payload, checkbox_checked):
        if callable(callback):
            args = [payload]
            if checkbox_checked is not None:
                args.append(checkbox_checked)
            callback(*args)
        self.show_question()

    def toggle_det_msg(self, *args):
        vis = unicode(self.det_msg_toggle.text()) == self.hide_det_msg
        self.det_msg_toggle.setText(
            self.show_det_msg if vis else self.hide_det_msg)
        self.det_msg.setVisible(not vis)
        self.do_resize()

    def do_resize(self):
        if self.geom_pref:
            geom = gprefs.get(self.geom_pref, None)
            if geom:
                self.restoreGeometry(geom)
                return
        sz = self.sizeHint() + QSize(100, 0)
        sz.setWidth(min(500, sz.width()))
        sz.setHeight(min(500, sz.height()))
        self.resize(sz)

    def show_question(self):
        if self.isVisible():
            return
        if self.questions:
            question = self.questions[0]
            self.msg_label.setText(question.msg)
            self.setWindowTitle(question.title)
            self.log_button.setVisible(bool(question.html_log))
            self.copy_button.setText(_('&Copy to clipboard'))
            self.copy_button.setVisible(bool(question.show_copy_button))
            self.action_button.setVisible(question.action_callback is not None)
            if question.action_callback is not None:
                self.action_button.setText(question.action_label or '')
                self.action_button.setIcon(QIcon(
                ) if question.action_icon is None else question.action_icon)
            self.det_msg.setPlainText(question.det_msg or '')
            self.det_msg.setVisible(False)
            self.det_msg_toggle.setVisible(bool(question.det_msg))
            self.det_msg_toggle.setText(self.show_det_msg)
            self.checkbox.setVisible(question.checkbox_msg is not None)
            if question.checkbox_msg is not None:
                self.checkbox.setText(question.checkbox_msg)
                self.checkbox.setChecked(question.checkbox_checked)
            self.bb.button(self.bb.Ok).setVisible(question.show_ok)
            self.bb.button(self.bb.Yes).setVisible(not question.show_ok)
            self.bb.button(self.bb.No).setVisible(not question.show_ok)
            self.geom_pref = (
                'proceed question dialog:' +
                question.geom_pref) if question.geom_pref else None
            if question.show_det:
                self.toggle_det_msg()
            else:
                self.do_resize()
            self.show()
            button = self.action_button if question.focus_action and question.action_callback is not None else \
                (self.bb.button(self.bb.Ok) if question.show_ok else self.bb.button(self.bb.Yes))
            button.setDefault(True)
            button.setFocus(Qt.OtherFocusReason)

    def __call__(self,
                 callback,
                 payload,
                 html_log,
                 log_viewer_title,
                 title,
                 msg,
                 det_msg='',
                 show_copy_button=False,
                 cancel_callback=None,
                 log_is_file=False,
                 checkbox_msg=None,
                 checkbox_checked=False,
                 action_callback=None,
                 action_label=None,
                 action_icon=None,
                 focus_action=False,
                 show_det=False,
                 show_ok=False,
                 geom_pref=None):
        '''
        A non modal popup that notifies the user that a background task has
        been completed. This class guarantees that only a single popup is
        visible at any one time. Other requests are queued and displayed after
        the user dismisses the current popup.

        :param callback: A callable that is called with payload if the user
        asks to proceed. Note that this is always called in the GUI thread.
        :param cancel_callback: A callable that is called with the payload if
        the users asks not to proceed.
        :param payload: Arbitrary object, passed to callback
        :param html_log: An HTML or plain text log
        :param log_viewer_title: The title for the log viewer window
        :param title: The title for this popup
        :param msg: The msg to display
        :param det_msg: Detailed message
        :param log_is_file: If True the html_log parameter is interpreted as
                            the path to a file on disk containing the log
                            encoded with utf-8
        :param checkbox_msg: If not None, a checkbox is displayed in the
                             dialog, showing this message. The callback is
                             called with both the payload and the state of the
                             checkbox as arguments.
        :param checkbox_checked: If True the checkbox is checked by default.
        :param action_callback: If not None, an extra button is added, which
                                when clicked will cause action_callback to be called
                                instead of callback. action_callback is called in
                                exactly the same way as callback.
        :param action_label: The text on the action button
        :param action_icon: The icon for the action button, must be a QIcon object or None
        :param focus_action: If True, the action button will be focused instead of the Yes button
        :param show_det: If True, the Detailed message will be shown initially
        :param show_ok: If True, OK will be shown instead of YES/NO
        :param geom_pref: String for preference name to preserve dialog box geometry

        '''
        question = Question(payload, callback, cancel_callback, title, msg,
                            html_log, log_viewer_title, log_is_file, det_msg,
                            show_copy_button, checkbox_msg, checkbox_checked,
                            action_callback, action_label, action_icon,
                            focus_action, show_det, show_ok, geom_pref)
        self.questions.append(question)
        self.show_question()

    def show_log(self):
        if self.questions:
            q = self.questions[0]
            log = q.html_log
            if q.log_is_file:
                with open(log, 'rb') as f:
                    log = f.read().decode('utf-8')
            self.log_viewer = ViewLog(q.log_viewer_title, log, parent=self)
コード例 #6
0
ファイル: play_widget.py プロジェクト: javedr8/Cassino
class PlayWidget(QWidget):
    def __init__(self, parent):
        super(PlayWidget, self).__init__(parent)
        self.setAutoFillBackground(True)
        self.hlayout = QHBoxLayout(self)

        self.table_view = CardView(self)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.table_view.sizePolicy().hasHeightForWidth())
        self.table_view.setSizePolicy(sizePolicy)
        self.table_view.setMinimumHeight(200)
        self.table_view.setBackgroundBrush(Qt.darkGreen)
        self.table_view.setGeometry(0, 0, 1028, 200)

        self.hand_view = HandCardView(self)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.hand_view.sizePolicy().hasHeightForWidth())
        self.hand_view.setSizePolicy(sizePolicy)
        self.hand_view.setMinimumHeight(200)
        self.hand_view.setBackgroundBrush(Qt.darkGreen)
        self.hand_view.setGeometry(0, 0, 1028, 200)

        self.show_button = Button(self, 'Show Hand')
        self.show_button.setText("Show hand")
        self.show_button.clicked.connect(self.hand_view.show_cards)
        self.show_button.hide()

        self.move_button = Button(self, 'Make Move')
        self.move_button.setMinimumSize(300, 100)
        self.move_button.clicked.connect(self.attempt_move)
        self.move_button.hide()

        self.start_button = Button(self, 'Start Round')
        self.start_button.setMinimumHeight(100)
        self.start_button.clicked.connect(self.start_round)

        self.next_button = Button(self, 'Continue')
        self.next_button.setMinimumHeight(100)
        self.next_button.clicked.connect(self.goto_next_round)
        self.next_button.hide()

        self.quit_button = Button(self, 'Quit to menu')

        self.save_button = Button(self, 'Save')

        self.show_button.setMaximumWidth(150)
        self.move_button.setMaximumWidth(150)
        self.quit_button.setMaximumWidth(150)

        self.btnlayout = QHBoxLayout()
        self.btnlayout.addWidget(self.start_button)

        self.btn2layout = QHBoxLayout()
        self.btn2layout.addWidget(self.save_button)
        self.btn2layout.addWidget(self.quit_button)

        self.playlayout = QVBoxLayout()
        self.playlayout.addWidget(self.table_view)
        self.playlayout.addLayout(self.btnlayout)
        self.playlayout.addWidget(self.hand_view)
        self.playlayout.addLayout(self.btn2layout)
        self.hlayout.addLayout(self.playlayout)

        self.sidelayout = QVBoxLayout()
        self.log = QPlainTextEdit()
        self.log.setReadOnly(True)
        self.log.setPalette(QPalette(Qt.white))
        self.log.setMaximumWidth(300)
        self.log.setMaximumHeight(200)
        self.sidelayout.addWidget(self.log)

        self.playerinfolayout = QVBoxLayout()
        self.sidelayout.addLayout(self.playerinfolayout)

        self.sidelayout.addItem(
            QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))

        self.hlayout.addLayout(self.sidelayout)

        self.setup_sound()

        self.move_count = 0
        self.speed = 3
        self.game = None

    def init_game(self, game):
        self.game = game
        self.game.logSignal.connect(self.update_log)
        self.game.sweepSignal.connect(self.sweep_sound.play)

        self.game.new_round()
        self.shuffle_sound.play()
        self.game.initial_deal()

        self.move_count = 0

        for player in self.game.players:
            self.playerinfolayout.addWidget(PlayerInfo(self, player))

    def start_round(self):
        self.btnlayout.removeWidget(self.start_button)
        self.btnlayout.insertWidget(0, self.show_button)
        self.btnlayout.insertWidget(1, self.move_button)
        self.start_button.hide()
        self.show_button.show()
        self.move_button.show()

        self.table_view.update_scene(self.game.table)
        self.hand_view.update_scene(self.game.current_player.hand)

        self.hand_view.hide_cards()

        if type(self.game.current_player
                ) is not AIPlayer and self.game.one_human:
            self.hand_view.show_cards()

        self.playerinfolayout.itemAt(
            self.game.players.index(
                self.game.current_player)).widget().set_active()
        self.update_log('\n----------\n{}\'s turn\n'.format(
            self.game.current_player))

        if type(self.game.current_player) is AIPlayer:
            self.move_button.setDisabled(True)
            self.show_button.setDisabled(True)
            self.save_button.setDisabled(True)
            self.make_ai_move()

    def resume_from_save(self, game, logmsg, movecount):
        self.game = game
        self.game.logSignal.connect(self.update_log)
        self.game.sweepSignal.connect(self.sweep_sound.play)

        self.log.insertPlainText(logmsg)
        self.log.insertPlainText(
            '\n----------------\n    Resuming from save\n----------------\n\n')

        self.move_count = movecount

        for player in self.game.players:
            self.playerinfolayout.addWidget(PlayerInfo(self, player))

        self.playerinfolayout.itemAt(
            self.game.players.index(
                self.game.current_player)).widget().set_active()

    def make_ai_move(self):
        self.game.select_move_for_ai()
        QTimer.singleShot(1500 // self.speed, self.show_ai_move)

    def show_ai_move(self):
        self.hand_view.auto_select()
        self.table_view.auto_select()
        self.card_sound.play()
        self.game.do_action()
        QTimer.singleShot(3000 // self.speed, self.after_ai_move_done)

    def after_ai_move_done(self):
        self.move_sound.play()
        self.playerinfolayout.itemAt(
            self.game.players.index(
                self.game.current_player)).widget().update_info()
        self.game.deal()
        self.table_view.update_scene(self.game.table)
        self.hand_view.update_scene(self.game.current_player.hand)
        self.hand_view.hide_cards()
        QTimer.singleShot(3000 // self.speed, self.end_turn)

    def attempt_move(self):
        if self.game.do_action():
            self.move_sound.play()
            self.playerinfolayout.itemAt(
                self.game.players.index(
                    self.game.current_player)).widget().update_info()
            self.move_button.setDisabled(True)
            self.table_view.update_scene(self.game.table)
            self.hand_view.update_scene(self.game.current_player.hand)
            QTimer.singleShot(1800 // self.speed, self.after_move_done)

        else:
            self.error_sound.play()

    def after_move_done(self):
        self.game.deal()
        self.hand_view.update_scene(self.game.current_player.hand)
        QTimer.singleShot(3000 // self.speed, self.end_turn)

    def end_turn(self):
        self.playerinfolayout.itemAt(
            self.game.players.index(
                self.game.current_player)).widget().set_inactive()
        self.game.next_player()
        self.playerinfolayout.itemAt(
            self.game.players.index(
                self.game.current_player)).widget().set_active()

        self.move_button.setDisabled(False)
        self.show_button.setDisabled(False)
        self.table_view.deselect_all()

        self.move_count += 1
        if self.move_count == 48:
            self.end_round()
            return

        self.update_log('\n----------\n{}\'s turn\n'.format(
            self.game.current_player))
        self.hand_view.update_scene(self.game.current_player.hand)
        self.hand_view.hide_cards()

        #if there is only one human player, his/her cards are shown automatically
        if type(self.game.current_player
                ) is not AIPlayer and self.game.one_human:
            self.hand_view.show_cards()
            self.alert_sound.play()

        if type(self.game.current_player) is AIPlayer:
            self.move_button.setDisabled(True)
            self.show_button.setDisabled(True)
            self.save_button.setDisabled(True)
            self.make_ai_move()
            return

        self.save_button.setDisabled(False)

    def end_round(self):
        self.save_button.setDisabled(True)
        self.playerinfolayout.itemAt(
            self.game.players.index(
                self.game.current_player)).widget().set_inactive()
        self.end_sound.play()
        game_ended = self.game.end_round()
        for i in range(self.playerinfolayout.count()):
            self.playerinfolayout.itemAt(i).widget().update_info()
            self.playerinfolayout.itemAt(i).widget().update_score()

        self.table_view.update_scene(self.game.table)

        self.btnlayout.removeWidget(self.show_button)
        self.btnlayout.removeWidget(self.move_button)
        self.btnlayout.insertWidget(0, self.next_button)
        self.next_button.show()
        self.show_button.hide()
        self.move_button.hide()
        if game_ended:
            self.next_button.setDisabled(True)

    def goto_next_round(self):
        self.save_button.setDisabled(False)
        self.btnlayout.removeWidget(self.next_button)
        self.btnlayout.insertWidget(0, self.start_button)
        self.start_button.show()
        self.next_button.hide()

        #rotate playerinfo
        mov = self.playerinfolayout.itemAt(0).widget()
        self.playerinfolayout.removeWidget(mov)
        self.playerinfolayout.addWidget(mov)

        self.game.new_round()
        self.shuffle_sound.play()

        for i in range(self.playerinfolayout.count()):
            self.playerinfolayout.itemAt(i).widget().update_info()

        self.game.new_round()
        self.game.initial_deal()

        self.move_count = 0

    def setup_sound(self):
        self.shuffle_sound = QSoundEffect()
        self.shuffle_sound.setSource(QUrl.fromLocalFile('sound/shuffle.wav'))

        self.error_sound = QSoundEffect()
        self.error_sound.setSource(QUrl.fromLocalFile('sound/error.wav'))

        self.move_sound = QSoundEffect()
        self.move_sound.setSource(QUrl.fromLocalFile('sound/draw.wav'))

        self.card_sound = QSoundEffect()
        self.card_sound.setSource(QUrl.fromLocalFile('sound/playcard.wav'))

        self.sweep_sound = QSoundEffect()
        self.sweep_sound.setSource(QUrl.fromLocalFile('sound/sweep.wav'))

        self.alert_sound = QSoundEffect()
        self.alert_sound.setSource(QUrl.fromLocalFile('sound/alert.wav'))

        self.end_sound = QSoundEffect()
        self.end_sound.setSource(QUrl.fromLocalFile('sound/endturn.wav'))

    def reset(self):
        self.game = None

    def update_log(self, msg):
        self.log.insertPlainText(msg)
        self.log.ensureCursorVisible()  #auto-scrolls to bottom of log

    def export_log(self):
        return self.log.toPlainText()
コード例 #7
0
ファイル: proceed.py プロジェクト: Cykooz/calibre
class ProceedQuestion(QDialog):

    ask_question = pyqtSignal(object, object, object)

    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setAttribute(Qt.WA_DeleteOnClose, False)
        self.setWindowIcon(QIcon(I('dialog_question.png')))

        self.questions = []

        self._l = l = QGridLayout(self)
        self.setLayout(l)

        self.icon_label = ic = QLabel(self)
        ic.setPixmap(QPixmap(I('dialog_question.png')))
        self.msg_label = msg = QLabel('some random filler text')
        msg.setWordWrap(True)
        ic.setMaximumWidth(110)
        ic.setMaximumHeight(100)
        ic.setScaledContents(True)
        ic.setStyleSheet('QLabel { margin-right: 10px }')
        self.bb = QDialogButtonBox()
        self.bb.accepted.connect(self.accept)
        self.bb.rejected.connect(self.reject)
        self.log_button = self.bb.addButton(_('View log'), self.bb.ActionRole)
        self.log_button.setIcon(QIcon(I('debug.png')))
        self.log_button.clicked.connect(self.show_log)
        self.copy_button = self.bb.addButton(_('&Copy to clipboard'),
                self.bb.ActionRole)
        self.copy_button.clicked.connect(self.copy_to_clipboard)
        self.action_button = self.bb.addButton('', self.bb.ActionRole)
        self.action_button.clicked.connect(self.action_clicked)
        self.show_det_msg = _('Show &details')
        self.hide_det_msg = _('Hide &details')
        self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole)
        self.det_msg_toggle.clicked.connect(self.toggle_det_msg)
        self.det_msg_toggle.setToolTip(
                _('Show detailed information about this error'))
        self.det_msg = QPlainTextEdit(self)
        self.det_msg.setReadOnly(True)
        self.bb.setStandardButtons(self.bb.Yes|self.bb.No|self.bb.Ok)
        self.bb.button(self.bb.Yes).setDefault(True)

        self.checkbox = QCheckBox('', self)

        l.addWidget(ic, 0, 0, 1, 1)
        l.addWidget(msg, 0, 1, 1, 1)
        l.addWidget(self.checkbox, 1, 0, 1, 2)
        l.addWidget(self.det_msg, 2, 0, 1, 2)
        l.addWidget(self.bb, 3, 0, 1, 2)

        self.ask_question.connect(self.do_ask_question,
                type=Qt.QueuedConnection)

    def copy_to_clipboard(self, *args):
        QApplication.clipboard().setText(
                'calibre, version %s\n%s: %s\n\n%s' %
                (__version__, unicode(self.windowTitle()),
                    unicode(self.msg_label.text()),
                    unicode(self.det_msg.toPlainText())))
        self.copy_button.setText(_('Copied'))

    def action_clicked(self):
        if self.questions:
            q = self.questions[0]
            self.questions[0] = q._replace(callback=q.action_callback)
        self.accept()

    def accept(self):
        if self.geom_pref:
            gprefs[self.geom_pref] = bytearray(self.saveGeometry())
        if self.questions:
            payload, callback, cancel_callback = self.questions[0][:3]
            self.questions = self.questions[1:]
            cb = None
            if self.checkbox.isVisible():
                cb = bool(self.checkbox.isChecked())
            self.ask_question.emit(callback, payload, cb)
        self.hide()

    def reject(self):
        if self.geom_pref:
            gprefs[self.geom_pref] = bytearray(self.saveGeometry())
        if self.questions:
            payload, callback, cancel_callback = self.questions[0][:3]
            self.questions = self.questions[1:]
            cb = None
            if self.checkbox.isVisible():
                cb = bool(self.checkbox.isChecked())
            self.ask_question.emit(cancel_callback, payload, cb)
        self.hide()

    def do_ask_question(self, callback, payload, checkbox_checked):
        if callable(callback):
            args = [payload]
            if checkbox_checked is not None:
                args.append(checkbox_checked)
            callback(*args)
        self.show_question()

    def toggle_det_msg(self, *args):
        vis = unicode(self.det_msg_toggle.text()) == self.hide_det_msg
        self.det_msg_toggle.setText(self.show_det_msg if vis else
                self.hide_det_msg)
        self.det_msg.setVisible(not vis)
        self.do_resize()

    def do_resize(self):
        if self.geom_pref:
            geom = gprefs.get(self.geom_pref, None)
            if geom:
                self.restoreGeometry(geom)
                return
        sz = self.sizeHint() + QSize(100, 0)
        sz.setWidth(min(500, sz.width()))
        sz.setHeight(min(500, sz.height()))
        self.resize(sz)

    def show_question(self):
        if self.isVisible():
            return
        if self.questions:
            question = self.questions[0]
            self.msg_label.setText(question.msg)
            self.setWindowTitle(question.title)
            self.log_button.setVisible(bool(question.html_log))
            self.copy_button.setText(_('&Copy to clipboard'))
            self.copy_button.setVisible(bool(question.show_copy_button))
            self.action_button.setVisible(question.action_callback is not None)
            if question.action_callback is not None:
                self.action_button.setText(question.action_label or '')
                self.action_button.setIcon(
                    QIcon() if question.action_icon is None else question.action_icon)
            self.det_msg.setPlainText(question.det_msg or '')
            self.det_msg.setVisible(False)
            self.det_msg_toggle.setVisible(bool(question.det_msg))
            self.det_msg_toggle.setText(self.show_det_msg)
            self.checkbox.setVisible(question.checkbox_msg is not None)
            if question.checkbox_msg is not None:
                self.checkbox.setText(question.checkbox_msg)
                self.checkbox.setChecked(question.checkbox_checked)
            self.bb.button(self.bb.Ok).setVisible(question.show_ok)
            self.bb.button(self.bb.Yes).setVisible(not question.show_ok)
            self.bb.button(self.bb.No).setVisible(not question.show_ok)
            self.geom_pref = ('proceed question dialog:' + question.geom_pref) if question.geom_pref else None
            if question.show_det:
                self.toggle_det_msg()
            else:
                self.do_resize()
            self.show()
            button = self.action_button if question.focus_action and question.action_callback is not None else \
                (self.bb.button(self.bb.Ok) if question.show_ok else self.bb.button(self.bb.Yes))
            button.setDefault(True)
            button.setFocus(Qt.OtherFocusReason)

    def __call__(self, callback, payload, html_log, log_viewer_title, title,
            msg, det_msg='', show_copy_button=False, cancel_callback=None,
            log_is_file=False, checkbox_msg=None, checkbox_checked=False,
            action_callback=None, action_label=None, action_icon=None, focus_action=False,
            show_det=False, show_ok=False, geom_pref=None):
        '''
        A non modal popup that notifies the user that a background task has
        been completed. This class guarantees that only a single popup is
        visible at any one time. Other requests are queued and displayed after
        the user dismisses the current popup.

        :param callback: A callable that is called with payload if the user
        asks to proceed. Note that this is always called in the GUI thread.
        :param cancel_callback: A callable that is called with the payload if
        the users asks not to proceed.
        :param payload: Arbitrary object, passed to callback
        :param html_log: An HTML or plain text log
        :param log_viewer_title: The title for the log viewer window
        :param title: The title for this popup
        :param msg: The msg to display
        :param det_msg: Detailed message
        :param log_is_file: If True the html_log parameter is interpreted as
                            the path to a file on disk containing the log
                            encoded with utf-8
        :param checkbox_msg: If not None, a checkbox is displayed in the
                             dialog, showing this message. The callback is
                             called with both the payload and the state of the
                             checkbox as arguments.
        :param checkbox_checked: If True the checkbox is checked by default.
        :param action_callback: If not None, an extra button is added, which
                                when clicked will cause action_callback to be called
                                instead of callback. action_callback is called in
                                exactly the same way as callback.
        :param action_label: The text on the action button
        :param action_icon: The icon for the action button, must be a QIcon object or None
        :param focus_action: If True, the action button will be focused instead of the Yes button
        :param show_det: If True, the Detailed message will be shown initially
        :param show_ok: If True, OK will be shown instead of YES/NO
        :param geom_pref: String for preference name to preserve dialog box geometry

        '''
        question = Question(
            payload, callback, cancel_callback, title, msg, html_log,
            log_viewer_title, log_is_file, det_msg, show_copy_button,
            checkbox_msg, checkbox_checked, action_callback, action_label,
            action_icon, focus_action, show_det, show_ok, geom_pref)
        self.questions.append(question)
        self.show_question()

    def show_log(self):
        if self.questions:
            q = self.questions[0]
            log = q.html_log
            if q.log_is_file:
                with open(log, 'rb') as f:
                    log = f.read().decode('utf-8')
            self.log_viewer = ViewLog(q.log_viewer_title, log,
                        parent=self)
コード例 #8
0
ファイル: convert.py プロジェクト: Jellby/PrincePDF
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()
コード例 #9
0
ファイル: convert.py プロジェクト: Jellby/PrincePDF
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()
コード例 #10
0
ファイル: gui.py プロジェクト: desolovev/SimplePyScripts
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle(WINDOW_TITLE)

        from pathlib import Path
        file_name = str(Path(__file__).resolve().parent / 'favicon.ico')
        icon = QIcon(file_name)

        self.setWindowIcon(icon)

        self.tray = QSystemTrayIcon(icon)
        self.tray.setToolTip(self.windowTitle())
        self.tray.activated.connect(self._on_tray_activated)
        self.tray.show()

        self.logged_dict = dict()

        self.pb_refresh = QPushButton('REFRESH')
        self.pb_refresh.clicked.connect(self.refresh)

        self.cb_show_log = QCheckBox()
        self.cb_show_log.setChecked(True)

        self.log = QPlainTextEdit()
        self.log.setReadOnly(True)
        self.log.setWordWrapMode(QTextOption.NoWrap)
        log_font = self.log.font()
        log_font.setFamily('Courier New')
        self.log.setFont(log_font)

        self.cb_show_log.clicked.connect(self.log.setVisible)
        self.log.setVisible(self.cb_show_log.isChecked())

        header_labels = ['DATE', 'TOTAL LOGGED TIME']
        self.table_logged = QTableWidget()
        self.table_logged.setEditTriggers(QTableWidget.NoEditTriggers)
        self.table_logged.setSelectionBehavior(QTableWidget.SelectRows)
        self.table_logged.setSelectionMode(QTableWidget.SingleSelection)
        self.table_logged.setColumnCount(len(header_labels))
        self.table_logged.setHorizontalHeaderLabels(header_labels)
        self.table_logged.horizontalHeader().setStretchLastSection(True)
        self.table_logged.itemClicked.connect(
            self._on_table_logged_item_clicked)

        header_labels = ['TIME', 'LOGGED', 'JIRA']
        self.table_logged_info = QTableWidget()
        self.table_logged_info.setEditTriggers(QTableWidget.NoEditTriggers)
        self.table_logged_info.setSelectionBehavior(QTableWidget.SelectRows)
        self.table_logged_info.setSelectionMode(QTableWidget.SingleSelection)
        self.table_logged_info.setColumnCount(len(header_labels))
        self.table_logged_info.setHorizontalHeaderLabels(header_labels)
        self.table_logged_info.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.ResizeToContents)
        self.table_logged_info.horizontalHeader().setStretchLastSection(True)
        self.table_logged_info.itemDoubleClicked.connect(
            self._on_table_logged_info_item_double_clicked)

        main_layout = QVBoxLayout()

        central_widget = QWidget()
        central_widget.setLayout(main_layout)

        self.setCentralWidget(central_widget)

        self.pb_refresh.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred))

        h_layout = QHBoxLayout()
        h_layout.addWidget(self.pb_refresh)
        h_layout.addWidget(self.cb_show_log)

        layout_table_widget = QVBoxLayout()
        layout_table_widget.setContentsMargins(0, 0, 0, 0)
        layout_table_widget.addWidget(self.table_logged)
        layout_table_widget.addWidget(self.table_logged_info)

        table_widget = QWidget()
        table_widget.setLayout(layout_table_widget)

        splitter = QSplitter(Qt.Horizontal)
        splitter.addWidget(table_widget)
        splitter.addWidget(self.log)

        main_layout.addLayout(h_layout)
        main_layout.addWidget(splitter)

    def _fill_tables(self, xml_data: bytes):
        import io
        buffer_io = io.StringIO()

        from contextlib import redirect_stdout

        try:
            with redirect_stdout(buffer_io):
                print(len(xml_data), repr(xml_data[:50]))

                # Структура документа -- xml
                self.logged_dict = parse_logged_dict(xml_data)
                print(self.logged_dict)

                if not self.logged_dict:
                    return

                import json
                print(
                    json.dumps(self.logged_dict, indent=4, ensure_ascii=False))
                print()

                logged_list = get_logged_list_by_now_utc_date(self.logged_dict)

                logged_total_seconds = get_logged_total_seconds(logged_list)
                logged_total_seconds_str = seconds_to_str(logged_total_seconds)
                print('entry_logged_list:', logged_list)
                print('today seconds:', logged_total_seconds)
                print('today time:', logged_total_seconds_str)
                print()

                # Для красоты выводим результат в табличном виде
                lines = []

                # Удаление строк таблицы
                while self.table_logged.rowCount():
                    self.table_logged.removeRow(0)

                for i, (date_str, logged_list) in enumerate(
                        get_sorted_logged(self.logged_dict)):
                    total_seconds = get_logged_total_seconds(logged_list)
                    total_seconds_str = seconds_to_str(total_seconds)
                    row = date_str, total_seconds_str, total_seconds
                    lines.append(row)

                    self.table_logged.setRowCount(
                        self.table_logged.rowCount() + 1)

                    self.table_logged.setItem(i, 0, QTableWidgetItem(date_str))

                    item = QTableWidgetItem(total_seconds_str)
                    item.setToolTip('Total seconds: {}'.format(total_seconds))
                    self.table_logged.setItem(i, 1, item)

                self.table_logged.setCurrentCell(0, 0)
                self.table_logged.setFocus()
                self._on_table_logged_item_clicked(
                    self.table_logged.currentItem())

                # Список строк станет списком столбцов, у каждого столбца подсчитается максимальная длина
                max_len_columns = [
                    max(map(len, map(str, col))) for col in zip(*lines)
                ]

                # Создание строки форматирования: [30, 14, 5] -> "{:<30} | {:<14} | {:<5}"
                my_table_format = ' | '.join('{:<%s}' % max_len
                                             for max_len in max_len_columns)

                for line in lines:
                    print(my_table_format.format(*line))

        finally:
            text = buffer_io.getvalue()
            self.log.setPlainText(text)

            print(text)

    def refresh(self):
        progress_dialog = QProgressDialog(self)

        thread = RunFuncThread(func=get_rss_jira_log)
        thread.run_finished.connect(self._fill_tables)
        thread.run_finished.connect(progress_dialog.close)
        thread.start()

        progress_dialog.setWindowTitle('Please wait...')
        progress_dialog.setLabelText(progress_dialog.windowTitle())
        progress_dialog.setRange(0, 0)
        progress_dialog.exec()

        from datetime import datetime
        self.setWindowTitle(WINDOW_TITLE + ". Last refresh date: " +
                            datetime.now().strftime('%d/%m/%Y %H:%M:%S'))

    def _on_table_logged_item_clicked(self, item: QTableWidgetItem):
        # Удаление строк таблицы
        while self.table_logged_info.rowCount():
            self.table_logged_info.removeRow(0)

        row = item.row()
        date_str = self.table_logged.item(row, 0).text()
        logged_list = self.logged_dict[date_str]
        logged_list = reversed(logged_list)

        for i, logged in enumerate(logged_list):
            self.table_logged_info.setRowCount(
                self.table_logged_info.rowCount() + 1)

            self.table_logged_info.setItem(i, 0,
                                           QTableWidgetItem(logged['time']))
            self.table_logged_info.setItem(
                i, 1, QTableWidgetItem(logged['logged_human_time']))

            item = QTableWidgetItem(logged['jira_id'])
            item.setToolTip(logged['jira_title'])
            self.table_logged_info.setItem(i, 2, item)

    def _on_table_logged_info_item_double_clicked(self,
                                                  item: QTableWidgetItem):
        row = item.row()
        jira_id = self.table_logged_info.item(row, 2).text()

        url = 'https://jira.compassplus.ru/browse/' + jira_id

        import webbrowser
        webbrowser.open(url)

    def _on_tray_activated(self, reason):
        self.setVisible(not self.isVisible())

        if self.isVisible():
            self.showNormal()
            self.activateWindow()

    def changeEvent(self, event: QEvent):
        if event.type() == QEvent.WindowStateChange:
            # Если окно свернули
            if self.isMinimized():
                # Прячем окно с панели задач
                QTimer.singleShot(0, self.hide)
コード例 #11
0
class ConverterWidget(QMainWindow):

    name = 'RWConvert'

    # For easier usage calculate the path relative to here.
    here = os.path.abspath(os.path.dirname(__file__))
    getPath = partial(os.path.join, here)

    # Setup a plugin base for "rwconvert.plugins" and make sure to load
    # all the default built-in plugins from the builtin_plugins folder.
    pluginBase = PluginBase(package='rwconvert.plugins',
                            searchpath=[getPath('./plugins')])

    plugins = {}
    filenames = []
    currentPlugin = None
    filetypes = 'All Files (*.*)'
    config = {}

    def __init__(self):
        '''
        init
        '''

        super().__init__()

        self.comms = CommSignals()
        """
        Read configuration file and return its contents
        """
        self.initConfig()
        cfgDir = self.config[PATHS]['config_path']
        self.cfgFileName = os.path.join(cfgDir,
                                        self.config[FILES]['config_name'])
        if not os.path.isfile(self.cfgFileName):
            os.makedirs(os.path.dirname(self.cfgFileName), exist_ok=True)
            self.exportConfig()
        else:
            with open(self.cfgFileName, 'r') as configFile:
                c = yaml.load(configFile)
                c = {} if c is None else c
                if c != {}:
                    self.config = c

        # and a source which loads the plugins from the "plugins"
        # folder.  We also pass the application name as identifier.  This
        # is optional but by doing this out plugins have consistent
        # internal module names which allows pickle to work.
        self.source = self.pluginBase.make_plugin_source(
            searchpath=[self.getPath('./plugins')], identifier=self.name)

        # Here we list all the plugins the source knows about, load them
        # and the use the "setup" function provided by the plugin to
        # initialize the plugin.
        for pluginName in self.source.list_plugins():
            plugin = self.source.load_plugin(pluginName)
            pluginClass = getattr(plugin, pluginName)
            instance = pluginClass(self.config, self.comms)
            self.plugins[pluginName] = instance

        self.initGui()


#         self.showFullScreen()

    def initConfig(self):
        if PATHS not in self.config: self.config[PATHS] = {}
        if FILES not in self.config: self.config[FILES] = {}
        if FORMS not in self.config: self.config[FORMS] = {}
        if NAMES not in self.config: self.config[NAMES] = {}

        self.config[PATHS]['homepath'] = os.path.expanduser('~')
        self.config[PATHS]['docpath'] = os.path.join(
            self.config[PATHS]['homepath'], 'Documents')
        self.config[PATHS]['download_path'] = os.path.join(
            self.config[PATHS]['homepath'], 'Downloads')
        self.config[PATHS]['save_path'] = os.path.join(
            self.config[PATHS]['docpath'], self.name)
        self.config[PATHS]['config_path'] = appdirs.user_config_dir(self.name)
        self.config[PATHS]['db_path'] = os.path.join(
            self.config[PATHS]['config_path'], 'data')

        self.config[FILES]['config_name'] = 'config.yaml'
        self.config[FILES]['db_name'] = 'rwconvert.sqlite'
        self.config[FILES]['save_file'] = 'roadwarrior'
        self.config[FILES]['save_ext'] = '.xlsx'

        self.config[FORMS]['include_date'] = False
        self.config[FORMS]['prefix_date'] = False
        self.config[FORMS]['include_routes'] = False
        self.config[FORMS]['combine_routes'] = False

        self.config[NAMES]['current_plugin_name'] = ''

        self.destFilename = self.config['Files']['save_file'] + self.config[
            'Files']['save_ext']

        # Create destination file directory if it doesn't already exist'
        #         if not os.path.exists(self.config[PATHS]['config_path']):
        os.makedirs(self.config[PATHS]['config_path'], exist_ok=True)
        #         if not os.path.exists(self.config[PATHS]['db_path']):
        os.makedirs(self.config[PATHS]['db_path'], exist_ok=True)
        #         if not os.path.exists(self.config[PATHS]['save_path']):
        os.makedirs(self.config[PATHS]['save_path'], exist_ok=True)

    def initGui(self):
        self.setGeometry(300, 300, 800, 600)
        self.setWindowTitle('Road warrior Upload File Converter')
        self.center()

        fMain = QFrame()
        mainLayout = QGridLayout()
        fMain.setLayout(mainLayout)
        self.setCentralWidget(fMain)

        tabWidget = QTabWidget()
        mainLayout.addWidget(tabWidget, 0, 0)

        self.closeBtn = QPushButton('Close Application')
        self.closeBtn.clicked.connect(self.handleCloseClicked)
        mainLayout.addWidget(self.closeBtn, 1, 0)

        tabWidget.addTab(self.initConvertPage(), 'Converter')
        tabWidget.addTab(self.initResultPage(), 'Converter')
        tabWidget.addTab(self.initConfigPage(), 'Configuration')

    def initResultPage(self):
        f = QFrame()
        l = QHBoxLayout()
        f.setLayout(l)

        self.convertedTabs = QTabWidget()
        l.addWidget(self.convertedTabs)
        '''
        This just adds a blank page with an empty tab widget.
        Pages are added on the fly when the files are converted as
        this could involve one or many pages depending on combine_route
        flag and number of routes.

        self.convertedTabs is the empty tab widget
        '''

        return f

    def initConvertPage(self):
        f = QFrame()
        l = QGridLayout()
        f.setLayout(l)

        row = 0

        l.addWidget(QLabel('Converter :'), row, 0)
        currentPluginBox = QComboBox()
        currentPluginBox.currentTextChanged.connect(self.selectPlugin)
        l.addWidget(currentPluginBox, row, 1)
        for key in self.plugins.keys():
            currentPluginBox.addItem(key)
        row += 1

        l.addWidget(QLabel('Destination path :'), row, 0)
        self.destPathLbl = QLabel(
            self.joinSavePath(self.config[PATHS]['save_path'],
                              self.config[FILES]['save_file'],
                              self.config[FILES]['save_ext']))
        self.destPathLbl.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Fixed)
        l.addWidget(self.destPathLbl, row, 1)

        row += 1

        f2 = QFrame()
        l2 = QHBoxLayout()
        f2.setLayout(l2)

        f3 = QFrame()
        l3 = QGridLayout()
        f3.setLayout(l3)

        l3.addWidget(QLabel('Destination Files :'), 0, 0)
        self.destFilesList = QListWidget()
        self.destFilesList.setAlternatingRowColors(True)
        l3.addWidget(self.destFilesList, 1, 0)

        l2.addWidget(self.initFileFrame())
        l2.addWidget(f3)
        l.addWidget(f2, row, 0, 1, 3)

        row += 1

        l.addWidget(self.initSrcFiles(), row, 0, 1, 3)

        row += 1

        self.convertBtn = QPushButton('Convert')
        self.convertBtn.clicked.connect(self.handleConvertClicked)
        self.convertBtn.setEnabled(False)
        l.addWidget(self.convertBtn, row, 0, 1, 3)

        return f

    def initSrcFiles(self):

        row = 0

        f = QFrame()
        l = QGridLayout()
        f.setLayout(l)

        l.addWidget(QLabel('Source Files :'), row, 0)
        self.srcFilesList = QListWidget()
        self.srcFilesList.setSelectionMode(QAbstractItemView.MultiSelection)
        self.srcFilesList.setAlternatingRowColors(True)
        self.srcFilesList.model().rowsInserted.connect(
            self.handleSrcFilesChanged)
        self.srcFilesList.model().rowsRemoved.connect(
            self.handleSrcFilesChanged)
        selectionModel = self.srcFilesList.selectionModel()
        selectionModel.selectionChanged.connect(
            self.handleSrcFilesSelectionChanged)
        l.addWidget(self.srcFilesList, row, 1, 3, 1)

        self.srcFilesBtn = QPushButton('Select Files')
        self.srcFilesBtn.clicked.connect(self.handleSelectSrcFiles)
        self.srcFilesBtn.setSizePolicy(QSizePolicy.Preferred,
                                       QSizePolicy.Expanding)
        l.addWidget(self.srcFilesBtn, row, 2)
        row += 1

        self.addFilesBtn = QPushButton('Add Files')
        self.addFilesBtn.clicked.connect(self.handleAddSrcFiles)
        self.addFilesBtn.setSizePolicy(QSizePolicy.Preferred,
                                       QSizePolicy.Expanding)
        l.addWidget(self.addFilesBtn, row, 2)
        row += 1

        self.removeFilesBtn = QPushButton('Remove Files')
        self.removeFilesBtn.setEnabled(False)
        self.removeFilesBtn.clicked.connect(self.handleRemoveSrcFiles)
        self.removeFilesBtn.setSizePolicy(QSizePolicy.Preferred,
                                          QSizePolicy.Expanding)
        l.addWidget(self.removeFilesBtn, row, 2)
        row += 1

        self.errorEdit = QPlainTextEdit()
        self.errorEdit.setReadOnly(True)
        l.addWidget(self.errorEdit, row, 1, 1, 2)
        self.comms.errorSignal.connect(self.errorEdit.appendPlainText)

        return f

    def initFileFrame(self):
        row = 0

        f = QFrame()
        l = QGridLayout()
        f.setLayout(l)
        #         f.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)

        l.addWidget(QLabel('Destination File :'), row, 0)
        self.destFilenameEdit = QLineEdit(self.destFilename)
        self.destFilenameEdit.setEnabled(False)
        self.destFilenameEdit.textChanged.connect(
            self.handleDestFilenameChanged)
        l.addWidget(self.destFilenameEdit, row, 1)
        row += 1

        self.combineRoutesBox = QCheckBox('combine_routes')
        if self.config[FORMS]['combine_routes']:
            self.combineRoutesBox.setChecked(True)
        else:
            self.combineRoutesBox.setChecked(False)
        self.combineRoutesBox.clicked.connect(self.handleCombineRoutesClicked)
        self.combineRoutesBox.setEnabled(False)
        l.addWidget(self.combineRoutesBox, row, 0)
        row += 1

        addDateInNameBox = QCheckBox('Add date to filename')
        addDateInNameBox.clicked.connect(self.handleAddDateClicked)
        l.addWidget(addDateInNameBox, row, 0)
        if self.config[FORMS]['prefix_date']:
            self.prefixDateInNameBox = QPushButton('prefix_date')
            self.prefixDateInNameBox.setEnabled(False)
        else:
            self.prefixDateInNameBox = QPushButton('Suffix date')
            self.prefixDateInNameBox.setEnabled(False)
        self.prefixDateInNameBox.setToolTip('Click to change to prefix date.')
        self.prefixDateInNameBox.clicked.connect(self.handlePrefixDateClicked)

        l.addWidget(self.prefixDateInNameBox, row, 1)
        row += 1

        addRouteInNameBox = QCheckBox('Add route to filename')
        addRouteInNameBox.clicked.connect(self.handleAddRouteClicked)
        l.addWidget(addRouteInNameBox, row, 0)
        #         row += 1

        return f

    def initConfigPage(self):
        row = 0

        f = QFrame()
        l = QGridLayout()
        f.setLayout(l)

        srcLbl = QLabel('Source directory :')
        srcLbl.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        l.addWidget(srcLbl, row, 0)

        self.srcDirBox = QLineEdit()
        self.srcDirBox.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.srcDirBox.setText(self.config[PATHS]['download_path'])
        l.addWidget(self.srcDirBox, row, 1)

        srcDirSelectBtn = QPushButton('Select')
        srcDirSelectBtn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        srcDirSelectBtn.clicked.connect(self.handleSelectSrcDirectory)
        l.addWidget(srcDirSelectBtn, row, 2)

        row += 1

        destLbl = QLabel('Destination directory :')
        destLbl.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        l.addWidget(destLbl, row, 0)

        self.destDirBox = QLineEdit()
        self.destDirBox.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.destDirBox.setText(self.config[PATHS]['save_path'])
        l.addWidget(self.destDirBox, row, 1)

        destDirSelectBtn = QPushButton('Select')
        destDirSelectBtn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        destDirSelectBtn.clicked.connect(self.handleSelectDestDirectory)
        l.addWidget(destDirSelectBtn, row, 2)

        row += 1

        l.addWidget(QFrame(), row, 0, 1, 3)

        return f

    def handleSelectSrcDirectory(self):
        directory = QFileDialog.getExistingDirectory(
            self, 'Select Source Directory',
            self.config[PATHS]['download_path'], QFileDialog.ShowDirsOnly)
        if not directory == '':
            self.config[PATHS]['download_path'] = directory
            self.srcDirBox.setText(directory)

    def handleSelectDestDirectory(self):
        directory = QFileDialog.getExistingDirectory(
            self, 'Select Destination Directory',
            self.config[PATHS]['save_path'], QFileDialog.ShowDirsOnly)
        if not directory == '':
            self.config[PATHS]['save_path'] = directory
            self.destDirBox.setText(directory)

    def joinSavePath(self, path, filename, ext):
        newpath = os.path.join(path, filename)
        newpath += ext
        return newpath

    @pyqtSlot(bool)
    def handleAddDateClicked(self, checked):
        if checked:
            self.config[FORMS]['include_path'] = True
            self.prefixDateInNameBox.setEnabled(True)
        else:
            self.config[FORMS]['include_path'] = False
            self.prefixDateInNameBox.setEnabled(False)

    @pyqtSlot()
    def handlePrefixDateClicked(self):
        if self.config[FORMS]['prefix_date']:
            self.config[FORMS]['prefix_date'] = False
            self.prefixDateInNameBox.setText('Suffix date')
            self.prefixDateInNameBox.setToolTip(
                'Click to change to prefix date.')
        else:
            self.config[FORMS]['prefix_date'] = True
            self.prefixDateInNameBox.setText('Prefix date')
            self.prefixDateInNameBox.setToolTip(
                'Click to change to suffix date.')

    @pyqtSlot()
    def handleAddRouteClicked(self, checked):
        if checked:
            self.config[FORMS]['include_routes'] = True
        else:
            self.config[FORMS]['include_routes'] = False

    @pyqtSlot()
    def handleCombineRoutesClicked(self):
        if self.combineRoutesBox.isChecked():
            self.config[FORMS]['combine_routes'] = True
        else:
            self.config[FORMS]['combine_routes'] = False

        self.enableStuff()

    def enableStuff(self):
        if self.srcFilesList.model().rowCount() == 0:
            self.convertBtn.setEnabled(False)
            self.combineRoutesBox.setEnabled(False)
            self.destFilenameEdit.setEnabled(False)
        elif self.srcFilesList.model().rowCount() == 1:
            self.convertBtn.setEnabled(True)
            self.combineRoutesBox.setEnabled(False)
            self.destFilenameEdit.setEnabled(True)
        else:
            self.convertBtn.setEnabled(True)
            self.combineRoutesBox.setEnabled(True)
            if self.combineRoutesBox.isChecked():
                self.destFilenameEdit.setEnabled(True)
            else:
                self.destFilenameEdit.setEnabled(False)

    @pyqtSlot()
    def handleDestFilenameChanged(self, text):
        if len(text) > 0:
            if self.config[PATHS]['include_path']:
                year = datetime.year
                month = datetime.month
                day = datetime.day
                datestr = str(year)
                if month < 10: datestr += '0'
                datestr += str(month)
                if day < 10: datestr += '0'
                datestr += str(day)
                if self.config[FORMS]['prefix_date']:
                    name = datestr + '_' + text
                else:
                    name = text + '_' + datestr
            else:
                name = text

            self.config[FILES]['save file'] = name
            self.destPathLbl.setText(
                self.joinSavePath(self.savepath, self.savefile, self.saveext))

    def createDestinationFilePath(self):
        return self.joinSavePath(self.savepath, self.savefile, self.saveext)

    @pyqtSlot()
    def handleSrcFilesSelectionChanged(self, selected):
        if len(selected.indexes()) > 0:
            self.removeFilesBtn.setEnabled(True)
        else:
            self.removeFilesBtn.setEnabled(False)

    @pyqtSlot()
    def handleSrcFilesChanged(self):
        self.enableStuff()

    @pyqtSlot()
    def handleConvertClicked(self):
        if len(self.filenames) > 0:
            toexcel = ToExcel()

            self.currentPlugin.convert(self.filenames)
            routedata = self.currentPlugin.data

            if self.config[FORMS]['combine_routes']:
                combined = []
                for route in routedata.keys():
                    singleroute = routedata[route]
                    combined += singleroute
                path = self.joinSavePath(self.config[PATHS]['save_path'],
                                         self.config[FILES]['save_file'],
                                         self.config[FILES]['save_ext'])
                toexcel.create_workbook(combined, path)
                self.destFilesList.addItem(path)

            else:
                i = 1
                for route in routedata.keys():
                    singleroute = routedata[route]
                    if self.config[FORMS]['include_routes'] and len(route) > 0:
                        path = self.joinSavePath(
                            self.config[PATHS]['save_path'],
                            self.config[FILES]['save_file'] + '_' + route,
                            self.config[FILES]['save_ext'])
                    else:
                        path = self.joinSavePath(
                            self.config[PATHS]['save_path'],
                            self.config[FILES]['save_file'] + '(' + str(i) +
                            ')', self.config[FILES]['save_ext'])
                        i += 1

                    toexcel.create_workbook(singleroute, path)
                    self.destFilesList.addItem(path)

    @pyqtSlot()
    def handleConverterChanged(self):
        pluginName = self.currentPluginBox.currentText()
        if pluginName != self.config[NAMES]['current_plugin_name']:
            self.config[NAMES]['current_plugin_name'] = pluginName
            self.currentPlugin = self.plugins[pluginName]
            self.filetypes = self.currentPlugin.filetypes

    @pyqtSlot()
    def handleCloseClicked(self):
        self.close()

    @pyqtSlot()
    def handleSelectSrcFiles(self):
        fileDlg = QFileDialog(self, 'Select Files',
                              self.config[PATHS]['download_path'],
                              self.filetypes)
        fileDlg.setFileMode(QFileDialog.ExistingFiles)

        if fileDlg.exec_():
            self.filenames = fileDlg.selectedFiles()

        self.srcFilesList.clear()
        self.srcFilesList.addItems(self.filenames)

    @pyqtSlot()
    def handleAddSrcFiles(self):
        fileDlg = QFileDialog(self, 'Select Files',
                              self.config[PATHS]['download_path'],
                              self.filetypes)
        fileDlg.setFileMode(QFileDialog.ExistingFiles)

        if fileDlg.exec_():
            for filename in fileDlg.selectedFiles():
                if filename not in self.filenames:
                    self.filenames.append(filename)
                    self.srcFilesList.addItem(filename)

    @pyqtSlot()
    def handleRemoveSrcFiles(self):
        selectedModel = self.srcFilesList.selectionModel()
        selected = selectedModel.selectedIndexes()
        for index in selected:
            name = index.data()
            self.filenames.remove(name)
            self.srcFilesList.takeItem(index.row())
        selectedModel.clear()

    @pyqtSlot(str)
    def selectPlugin(self, name):
        # activate the current plugin
        #             self.pluginManager.activatePluginByName(name)
        self.config[NAMES]['current_plugin_name'] = name
        self.currentPlugin = self.plugins[name]
        self.filetypes = self.currentPlugin.filetypes

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def exportConfig(self):
        with open(self.cfgFileName, 'w') as configFile:
            yaml.dump(self.config, configFile)

    def createUserConfig(self):
        """
        Create the user's config file in OS specific location
        """
        os.makedirs(os.path.dirname(self.cfgFileName), exist_ok=True)
        self.exportConfig()

    def closeEvent(self, event):
        buttonReply = QMessageBox.warning(
            self, 'Close Application',
            'You are about to close the Application,'
            ' Press Yes to continue or Cancel to return to the Application',
            QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel)
        if buttonReply == QMessageBox.Yes:
            self.exportConfig()
            exit()