Example #1
0
class ClientDialog(QDialog):
    """a simple popup dialog for asking the player what he wants to do"""
    def __init__(self, client, parent=None):
        QDialog.__init__(self, parent)
        self.setWindowTitle(m18n('Choose') + ' - Kajongg')
        self.setObjectName('ClientDialog')
        self.client = client
        self.layout = QGridLayout(self)
        self.progressBar = QProgressBar()
        self.timer = QTimer()
        if not client.game.autoPlay:
            self.timer.timeout.connect(self.timeout)
        self.deferred = None
        self.buttons = []
        self.setWindowFlags(Qt.SubWindow | Qt.WindowStaysOnTopHint)
        self.setModal(False)
        self.btnHeight = 0
        self.answered = False

    def keyPressEvent(self, event):
        """ESC selects default answer"""
        if not self.client.game or self.client.game.autoPlay:
            return
        if event.key() in [Qt.Key_Escape, Qt.Key_Space]:
            self.selectButton()
            event.accept()
        else:
            for btn in self.buttons:
                if str(event.text()).upper() == btn.message.shortcut:
                    self.selectButton(btn)
                    event.accept()
                    return
            QDialog.keyPressEvent(self, event)

    def __declareButton(self, message):
        """define a button"""
        maySay = self.client.sayable[message]
        if Preferences.showOnlyPossibleActions and not maySay:
            return
        btn = DlgButton(message, self)
        btn.setAutoDefault(True)
        btn.clicked.connect(self.selectedAnswer)
        self.buttons.append(btn)

    def focusTileChanged(self):
        """update icon and tooltip for the discard button"""
        if not self.client.game:
            return
        for button in self.buttons:
            button.decorate(self.client.game.myself.handBoard.focusTile)
        for tile in self.client.game.myself.handBoard.lowerHalfTiles():
            txt = []
            for button in self.buttons:
                _, _, tileTxt = button.message.toolTip(button, tile)
                if tileTxt:
                    txt.append(tileTxt)
            txt = '<br><br>'.join(txt)
            tile.graphics.setToolTip(txt)
        if self.client.game.activePlayer == self.client.game.myself:
            Internal.field.handSelectorChanged(self.client.game.myself.handBoard)

    def checkTiles(self):
        """does the logical state match the displayed tiles?"""
        for player in self.client.game.players:
            logExposed = list()
            physExposed = list()
            physConcealed = list()
            for tile in player.bonusTiles:
                logExposed.append(tile.element)
            for tile in player.handBoard.tiles:
                if tile.yoffset == 0 or tile.element[0] in 'fy':
                    physExposed.append(tile.element)
                else:
                    physConcealed.append(tile.element)
            for meld in player.exposedMelds:
                logExposed.extend(meld.pairs)
            logConcealed = sorted(player.concealedTileNames)
            logExposed.sort()
            physExposed.sort()
            physConcealed.sort()
            assert logExposed == physExposed, '%s != %s' % (logExposed, physExposed)
            assert logConcealed == physConcealed, '%s != %s' % (logConcealed, physConcealed)

    def messages(self):
        """a list of all messages returned by the declared buttons"""
        return list(x.message for x in self.buttons)

    def proposeAction(self):
        """either intelligently or first button by default. May also
        focus a proposed tile depending on the action."""
        result = self.buttons[0]
        game = self.client.game
        if game.autoPlay or Preferences.propose:
            answer, parameter = self.client.intelligence.selectAnswer(
                self.messages())
            result = [x for x in self.buttons if x.message == answer][0]
            result.setFocus()
            if answer in [Message.Discard, Message.OriginalCall]:
                for tile in game.myself.handBoard.tiles:
                    if tile.element == parameter:
                        game.myself.handBoard.focusTile = tile
        return result

    def askHuman(self, move, answers, deferred):
        """make buttons specified by answers visible. The first answer is default.
        The default button only appears with blue border when this dialog has
        focus but we always want it to be recognizable. Hence setBackgroundRole."""
        self.move = move
        self.deferred = deferred
        for answer in answers:
            self.__declareButton(answer)
        self.focusTileChanged()
        self.show()
        self.checkTiles()
        game = self.client.game
        myTurn = game.activePlayer == game.myself
        prefButton = self.proposeAction()
        if game.autoPlay:
            self.selectButton(prefButton)
            return
        prefButton.setFocus()

        self.progressBar.setVisible(not myTurn)
        if not myTurn:
            msecs = 50
            self.progressBar.setMinimum(0)
            self.progressBar.setMaximum(game.ruleset.claimTimeout * 1000 // msecs)
            self.progressBar.reset()
            self.timer.start(msecs)

    def placeInField(self):
        """place the dialog at bottom or to the right depending on space."""
        field = Internal.field
        cwi = field.centralWidget()
        view = field.centralView
        geometry = self.geometry()
        if not self.btnHeight:
            self.btnHeight = self.buttons[0].height()
        vertical = view.width() > view.height() * 1.2
        if vertical:
            height = (len(self.buttons) + 1) * self.btnHeight * 1.2
            width = (cwi.width() - cwi.height() ) // 2
            geometry.setX(cwi.width() - width)
            geometry.setY(min(cwi.height()//3, cwi.height() - height))
        else:
            handBoard = self.client.game.myself.handBoard
            if not handBoard:
                # we are in the progress of logging out
                return
            hbLeftTop = view.mapFromScene(handBoard.mapToScene(handBoard.rect().topLeft()))
            hbRightBottom = view.mapFromScene(handBoard.mapToScene(handBoard.rect().bottomRight()))
            width = hbRightBottom.x() - hbLeftTop.x()
            height = self.btnHeight
            geometry.setY(cwi.height() - height)
            geometry.setX(hbLeftTop.x())
        for idx, btn in enumerate(self.buttons + [self.progressBar]):
            self.layout.addWidget(btn, idx+1 if vertical else 0, idx+1 if not vertical else 0)
        idx = len(self.buttons) + 2
        spacer = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.layout.addItem(spacer, idx if vertical else 0, idx if not vertical else 0)

        geometry.setWidth(width)
        geometry.setHeight(height)
        self.setGeometry(geometry)

    def showEvent(self, dummyEvent):
        """try to place the dialog such that it does not cover interesting information"""
        self.placeInField()

    def timeout(self):
        """the progressboard wants an update"""
        pBar = self.progressBar
        if isAlive(pBar):
            pBar.setValue(pBar.value()+1)
            pBar.setVisible(True)
            if pBar.value() == pBar.maximum():
                # timeout: we always return the original default answer, not the one with focus
                self.selectButton()
                pBar.setVisible(False)

    def selectButton(self, button=None):
        """select default answer. button may also be of type Message."""
        self.timer.stop()
        self.answered = True
        if button is None:
            button = self.focusWidget()
        if isinstance(button, Message):
            assert any(x.message == button for x in self.buttons)
            answer = button
        else:
            answer = button.message
        if not self.client.sayable[answer]:
            Sorry(m18n('You cannot say %1', answer.i18nName))
            return
        Internal.field.clientDialog = None
        self.deferred.callback(answer)

    def selectedAnswer(self, dummyChecked):
        """the user clicked one of the buttons"""
        game = self.client.game
        if game and not game.autoPlay:
            self.selectButton(self.sender())
Example #2
0
class Ui_Form (QWidget):
    '''
    Ui class. Generated with pyuic4.
    '''
    def __init__ (self, parent=None):
        
        QWidget.__init__(self, parent)
        self.timer = QTimer (self)
        
        self.image    = QImage (720, 450, QImage.Format_RGB888)
        
        self.__engine = REngineThread ()
        self.__model  = Model ()
        self.__fsm    = DebugStateMachine (self)
    
        
    def wireEngineUp (self):
        '''
        this method connects the REngine's signals.
        '''
        self.connect (self.__engine, SIGNAL ("update (float)"), self.updateImage)
        self.connect (self.__engine, SIGNAL ("thread_completed()"), self.__fsm.finaliseRender)
        self.connect (self.__engine, SIGNAL ("inters_created (PyQt_PyObject, PyQt_PyObject)"), self.widget.addIntersection)
        self.connect (self.__engine, SIGNAL ("vector_created (PyQt_PyObject, PyQt_PyObject, QString)"), self.widget.addArrow)
        self.connect (self.__engine, SIGNAL ("line_created   (PyQt_PyObject, PyQt_PyObject, QString)"), self.widget.addLine)
    
    def wireOGLViewerUp (self):
        '''
        this method connects the REngine's signals.
        '''
        self.widget.setModel (self.__model)
        
        QObject.connect (self.widget, SIGNAL ("MatrixChanged (PyQt_PyObject)"), self.displayGLMatrix)

        # call the function run regularly when the focus is on it. (60 FPS if interval = 20)
        QObject.connect (self.timer, SIGNAL ('timeout()'), self.widget.run)
    
    def freezeGLFrameRate (self):
        
        self.timer.stop ()
    
    def speedUpGLFrameRate (self):
        
        self.timer.start ()
        self.timer.setInterval (20)
        
    def setupUi (self, Form):
        
        font = QFont ()
        font.setPointSize (9)
        font.setBold (False)
        font.setWeight (50)
        
        sizePolicy = QSizePolicy (QSizePolicy.Fixed, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch (0)
        sizePolicy.setVerticalStretch (0)
        
        Form.setObjectName (_fromUtf8("Form"))
        Form.resize (971, 930)
        self.plainTextEdit = QPlainTextEdit (Form)
        self.plainTextEdit.setGeometry (QRect (740, 280, 221, 611))
        self.plainTextEdit.setObjectName (_fromUtf8 ("plainTextEdit"))
        self.plainTextEdit.setFont (font)
        
        self.widget = OGLViewer (Form)
        self.widget.setUi_Form (self)
        self.widget.setGeometry (QRect (10, 10, 720, 450))
        sizePolicy.setHeightForWidth (self.widget.sizePolicy().hasHeightForWidth())
        self.widget.setSizePolicy (sizePolicy)
        self.widget.setObjectName (_fromUtf8 ("widget"))
        
        self.wireOGLViewerUp ()
        self.wireEngineUp ()
        
        self.label_view = QLabel (Form)
        self.label_view.setGeometry  (QRect (10, 470, 720, 450))
        sizePolicy.setHeightForWidth (self.label_view.sizePolicy().hasHeightForWidth())
        self.label_view.setSizePolicy (sizePolicy)
        self.label_view.setObjectName (_fromUtf8 ("label_view"))
        self.initLabel ()          
        self.pixmap_item = self.label_view.setPixmap (QPixmap.fromImage (self.image))
        
        # buttons definitions
        
        self.renderBtn    = QPushButton (Form)
        self.pauseBtn     = QPushButton (Form)
        self.stopBtn      = QPushButton (Form)
        self.upBtn        = QPushButton (Form)
        self.downBtn      = QPushButton (Form)
        self.moreDownBtn  = QPushButton (Form)
        self.moreUpBtn    = QPushButton (Form)
        self.rightBtn     = QPushButton (Form)
        self.moreRightBtn = QPushButton (Form)
        self.leftBtn      = QPushButton (Form)
        self.furtherLeft  = QPushButton (Form)
        self.grid_switch  = QPushButton (Form)
        
        buttons_properties_list = [[self.renderBtn,    True,  QRect (740, 140, 61, 21), "render"],
                                   [self.pauseBtn,     False, QRect (740, 120, 61, 21), "pause"],
                                   [self.stopBtn,      False, QRect (740, 100, 61, 21), "stop"],
                                   [self.upBtn,        False, QRect (820, 120, 21, 21), "one_row_up"],
                                   [self.downBtn,      False, QRect (820, 140, 21, 21), "one_row_down"],
                                   [self.moreDownBtn,  False, QRect (820, 160, 21, 21), "ten_rows_down"],
                                   [self.moreUpBtn,    False, QRect (820, 100, 21, 21), "ten_rows_up"],
                                   [self.rightBtn,     False, QRect (780, 180, 21, 21), "one_column_right"],
                                   [self.moreRightBtn, False, QRect (800, 180, 21, 21), "ten_columns_right"],
                                   [self.leftBtn,      False, QRect (760, 180, 21, 21), "one_column_left"],
                                   [self.furtherLeft,  False, QRect (740, 180, 21, 21), "ten_columns_left"],
                                   [self.grid_switch,  False, QRect (870, 230, 91, 31), "grid_switch"]]
        
        for button in buttons_properties_list:
            button[0].setEnabled  (button[1])
            button[0].setGeometry (button[2])
            button[0].setFont (font)
            button[0].setObjectName (_fromUtf8 (button[3]))
        
        # other UI elements
        
        self.progressBar = QProgressBar (Form)
        self.progressBar.setGeometry (QRect (740, 901, 221, 20))
        self.progressBar.setProperty ("value", 0)
        self.progressBar.setObjectName (_fromUtf8("progressBar"))
        self.progressBar.setMinimum (0)
        self.progressBar.setMaximum (100)
        
        self.slider_label = QLabel (Form)
        self.slider_label.setGeometry (QRect(900, 260, 61, 16))
        self.slider_label.setFont(font)
        self.slider_label.setObjectName (_fromUtf8("slider_label"))
        self.slider_label.setEnabled (True)
        
        self.arrowSizeSlider = QSlider (Form)
        self.arrowSizeSlider.setGeometry (QRect (740, 258, 151, 22))
        self.arrowSizeSlider.setMinimum (2)
        self.arrowSizeSlider.setMaximum (40)
        self.arrowSizeSlider.setSingleStep (1)
        self.arrowSizeSlider.setProperty ("value", 4)
        self.arrowSizeSlider.setOrientation (Qt.Horizontal)
        self.arrowSizeSlider.setObjectName  (_fromUtf8("arrowSizeSlider"))

        self.retranslateUi (Form)
        QMetaObject.connectSlotsByName (Form)
    
    def retranslateUi (self, Form):
        
        Form.setWindowTitle       (_translate ("Form", "RayTracing Debugging Tool", None))
        
        self.renderBtn.setText    (_translate ("Form", "Render", None))
        self.pauseBtn.setText     (_translate ("Form", "Pause",  None))
        self.stopBtn.setText      (_translate ("Form", "Stop",   None))
        self.upBtn.setText        (_translate ("Form", "^",      None))
        self.downBtn.setText      (_translate ("Form", "v",      None))
        self.moreDownBtn.setText  (_translate ("Form", "+",      None))
        self.moreUpBtn.setText    (_translate ("Form", "-",      None))
        self.rightBtn.setText     (_translate ("Form", ">",      None))
        self.moreRightBtn.setText (_translate ("Form", "+",      None))
        self.leftBtn.setText      (_translate ("Form", "<",      None))
        self.furtherLeft.setText  (_translate ("Form", "-",      None))
        
        self.grid_switch.setText  (_translate ("Form", "Grid on/off", None))
        self.slider_label.setText (_translate ("Form", "Arrows size", None))
        
        self.connect (self.renderBtn,       SIGNAL ("clicked()"),        self.__fsm.startRendering)
        self.connect (self.pauseBtn,        SIGNAL ("clicked()"),        self.__fsm.pauseRendering)
        self.connect (self.stopBtn,         SIGNAL ("clicked()"),        self.__fsm.stopRendering)
        self.connect (self.arrowSizeSlider, SIGNAL ("sliderMoved(int)"), self.resizeArrows)
    
    def initLabel (self):
        
        color = QColor (250, 250, 250)
        self.image.fill (color)
        
        '''
        # test init
        for i in range (0, 200, 20):
            for x in range (i, i+20):
                for y in range (i, i+20):
                    self.image.setPixel (x,y, qRgb (0, 0, 0))
        '''
    
    def enableUIButtons (self, boolean_dict):
        '''
        method used by the debug state machine to manage the greyed-out state of buttons.
        '''
        b_dict = dict (boolean_dict)
        
        self.renderBtn.setEnabled    (b_dict['renderBtn'])
        self.pauseBtn.setEnabled     (b_dict['pauseBtn'])
        self.stopBtn.setEnabled      (b_dict['stopBtn'])
        self.upBtn.setEnabled        (b_dict['upBtn'])
        self.downBtn.setEnabled      (b_dict['downBtn'])
        self.moreDownBtn.setEnabled  (b_dict['moreDownBtn'])
        self.moreUpBtn.setEnabled    (b_dict['moreUpBtn'])
        self.rightBtn.setEnabled     (b_dict['rightBtn'])
        self.moreRightBtn.setEnabled (b_dict['moreRightBtn'])
        self.leftBtn.setEnabled      (b_dict['leftBtn'])
        self.furtherLeft.setEnabled  (b_dict['furtherLeft'])
        
        if b_dict['progressBar'] == 'completed':
            self.progressBar.setValue (100)
        elif b_dict['progressBar'] == 'reset':
            self.progressBar.reset ()
    
    def addScreenshot (self):
        '''
        it grabs a screenshot of OpenGL viewer and add it into the QImage instance.
        '''
        self.image = self.widget.grabFrameBuffer ()
        self.pixmap_item = self.label_view.setPixmap (QPixmap.fromImage (self.image))
    
    def prepAndStartEngineUp (self):
        '''
        it preps the engine and start it up.
        '''
        self.__engine.setImage (self.image)
        self.__engine.setCameraNormalMatrix (self.widget.getNormalMatrix(), self.widget.getFovy ())
        self.__engine.setModel (self.__model)
        self.__engine.start ()
    
    def addCamera (self): self.widget.addCamera ()
    def setIsStoppedFlag (self, boo):  self.__engine.setIsStoppedFlag (boo)
    def setIsPausedFlag  (self, boo):  self.__engine.setIsPausedFlag  (boo)
    def changeRenderBtnName (self, title):  self.renderBtn.setText (_translate ("Form", title, None))
    
    # listeners  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
    def resizeArrows (self, e):
        self.widget.changeArrowsSize (e*0.5)
    def updateImage (self, e):
        self.pixmap_item = self.label_view.setPixmap (QPixmap.fromImage (self.image))
        self.progressBar.setValue (int(100*e))
    def displayGLMatrix (self, e):
        '''
        this method is registered to the MatrixChanged event fired from the OGLViewer
        component. It prints the model matrix. Only for debugging purposes.
        '''
        pass
Example #3
0
class HomeWidget(BaseWidget):
    def __init__(self, parent=0, *args, **kwargs):
        super(HomeWidget, self).__init__(parent=parent, *args, **kwargs)

        # inputs
        self._json_fpath = None
        self._destination_folder = self.guess_destination()
        self._from_date, self._to_date = self.guess_dates()
        self.nb_instances = 0

        self.setup_ui()

    @property
    def json_fpath(self):
        return self._json_fpath

    @json_fpath.setter
    def json_fpath(self, value):
        self._json_fpath = value
        self.json_select_button.setText(
            value if value else "Sélection fichier JSON ODK Aggregate ...")
        self.update_start_button_state()

    @property
    def destination_folder(self):
        return self._destination_folder

    @destination_folder.setter
    def destination_folder(self, value):
        self._destination_folder = value
        self.destination_select_button.setText(self.destination_folder)
        self.update_start_button_state()

    @property
    def from_date(self):
        return self._from_date

    @from_date.setter
    def from_date(self, value):
        self._from_date = value
        self.from_date_selector.setPythonDate(self.from_date)
        self.update_start_button_state()

    @property
    def to_date(self):
        return self._to_date

    @to_date.setter
    def to_date(self, value):
        self._to_date = value
        self.to_date_selector.setPythonDate(self.to_date)
        self.update_start_button_state()

    def setup_ui(self):
        # json file selector
        self.json_groupbox = QGroupBox("Export ODK Aggregate")
        layout = QGridLayout()
        self.json_select_button = PushButton("", self)
        self.json_select_button.clicked.connect(self.json_selector_clicked)
        layout.addWidget(self.json_select_button, 1, 0)
        self.json_groupbox.setLayout(layout)

        # destination folder selector
        self.destination_groupbox = QGroupBox("Destination")
        layout = QGridLayout()
        self.destination_select_button = PushButton(self.destination_folder,
                                                    self)
        self.destination_select_button.clicked.connect(
            self.destination_selector_clicked)
        layout.addWidget(self.destination_select_button, 1, 0)
        self.destination_groupbox.setLayout(layout)

        # period calendars
        today = datetime.date.today()
        self.period_groupbox = QGroupBox("Période")
        layout = QGridLayout()
        self.from_date_selector = DateTimeEdit(QDate(self.from_date))
        self.from_date_selector.dateChanged.connect(self.from_date_changed)
        self.from_date_selector.setMaximumDate(self.to_date)
        self.to_date_selector = DateTimeEdit(QDate(self.to_date))
        self.to_date_selector.dateChanged.connect(self.to_date_changed)
        self.to_date_selector.setMinimumDate(self.from_date)
        self.to_date_selector.setMaximumDate(today)
        layout.addWidget(Label("Du"), 2, 0)
        layout.addWidget(self.from_date_selector, 3, 0)
        layout.addWidget(Label("Au"), 2, 1)
        layout.addWidget(self.to_date_selector, 3, 1)
        self.period_groupbox.setLayout(layout)

        # start button
        self.start_button = PushButton("Démarrer")
        self.start_button.setEnabled(False)
        self.start_button.setDefault(True)
        self.start_button.clicked.connect(self.export_requested)

        # cancel button
        self.cancel_button = CancelPushButton("Annuler")
        self.cancel_button.setEnabled(False)
        self.cancel_button.clicked.connect(self.cancel_export)

        # grid
        self.gridBox = QGridLayout()
        self.gridBox.addWidget(self.json_groupbox, 0, 0, 1, 2)
        self.gridBox.addWidget(self.destination_groupbox, 1, 0, 1, 2)
        self.gridBox.addWidget(self.period_groupbox, 2, 0, 1, 2)
        self.gridBox.addWidget(self.start_button, 3, 0)
        self.gridBox.addWidget(self.cancel_button, 3, 1)

        vBox = QVBoxLayout()
        vBox.addLayout(self.gridBox)
        self.setLayout(vBox)

        self.json_fpath = None

    def guess_destination(self, root_only=False):
        start_folder = os.path.join(os.path.expanduser("~"), 'Desktop')
        if root_only:
            return start_folder
        return os.path.join(start_folder, Constants.DEFAULT_FOLDER_NAME)

    def guess_dates(self):
        to = datetime.date.today()
        start = to - datetime.timedelta(days=15)
        return start, to

    def update_start_button_state(self):
        self.start_button.setEnabled(
            all([
                self.json_fpath, self.destination_folder, self.from_date,
                self.to_date
            ]))

    def json_selector_clicked(self):
        # self.file_name_field.setText("Aucun fichier")
        self.start_button.setEnabled(False)
        fpath = QFileDialog.getOpenFileName(
            self, "Choisir le fichier d'export JSON", self.json_fpath
            or self.guess_destination(root_only=True),
            "Fichiers JSON (*.json)")
        self.json_fpath = os.path.abspath(fpath) if fpath else self.json_fpath

    def destination_selector_clicked(self):
        path = QFileDialog.getExistingDirectory(self,
                                                "Sélectionner le dossier",
                                                self.destination_folder)
        if path:
            self.destination_folder = os.path.abspath(path)

    def from_date_changed(self, new_date):
        self.from_date = new_date.toPyDate()

    def to_date_changed(self, new_date):
        self.to_date = new_date.toPyDate()

    def export_requested(self):
        logger.debug("export_requested")
        self.parentWidget().exporter.check_aggregate_presence()

    def display_missing_aggregate_confirmation(self):
        if MissingODKConfirmationWidget().exec_() == QDialog.Accepted:
            self.start_export()

    def start_export(self):
        logger.debug("Lancement ...")
        self.add_progressbar()
        self.start_button.setEnabled(False)
        self.cancel_button.setEnabled(True)
        self.parentWidget().exporter.parse(
            destination_folder=self.destination_folder,
            fname=self.json_fpath,
            from_date=self.from_date,
            to_date=self.to_date)

    def cancel_export(self):
        logger.debug("cancel")
        self.parentWidget().exporter.cancel()

    def update_progress_label(self, index):
        progression_label = "Export en cours...    {index}/{total}" \
                            .format(index=index,
                                    total=self.nb_instances)
        self.progression_groupbox.setTitle(progression_label)

    def add_progressbar(self):
        self.progressbar = QProgressBar()
        self.progressbar.setMinimum(0)
        self.progressbar.setMaximum(100)
        self.progressbar.reset()
        self.progressbar.setTextVisible(False)

        self.progression_groupbox = QGroupBox("...")
        progress_layout = QHBoxLayout()
        progress_layout.addWidget(self.progressbar)
        self.progression_groupbox.setLayout(progress_layout)
        self.gridBox.addWidget(self.progression_groupbox, 4, 0, 1, 2)

    def remove_progressbar(self):
        self.progression_groupbox.deleteLater()
        self.progression_groupbox = None

    @pyqtSlot(bool, int, str)
    def parsing_ended(self, succeeded, nb_instances, error_message):
        if succeeded:
            self.nb_instances = nb_instances

    @pyqtSlot(str, int)
    def exporting_instance(self, ident, index):
        logger.debug("exporting_instance")
        self.update_progress_label(index)

    @pyqtSlot(bool, int)
    def instance_completed(self, succeeded, index):
        logger.debug("instance_completed")
        pc = index * 100 // self.nb_instances
        self.progressbar.setValue(pc)

    @pyqtSlot(int, int, int, int)
    def export_ended(self, nb_instances_successful, nb_instances_failed,
                     nb_medias_successful, nb_medias_failed):
        self.cancel_button.setEnabled(False)
        self.start_button.setEnabled(True)

    @pyqtSlot()
    def export_canceled(self):
        self.remove_progressbar()
        self.cancel_button.setEnabled(False)
        self.start_button.setEnabled(True)
        QMessageBox.warning(
            self, "Export annulé !", "L'export en cours a été annulé.\n"
            "Tous les fichiers créés ont été supprimés", QMessageBox.Ok,
            QMessageBox.NoButton)
        if self.parentWidget().is_exiting:
            self.parentWidget().do_close()
Example #4
0
class CompileWidget(QWidget):

    progress = pyqtSignal(int)

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self._options = None
        self._conf = None

        self._go = QPushButton('Go')
        self._go.setMaximumWidth(100)
        font = self._go.font()
        font.setPointSizeF(font.pointSizeF() * 2.0)
        font.setWeight(QFont.Bold)
        self._go.setFont(font)
        self._go.clicked.connect(self.go)

        self._saveLog = QPushButton('Save')
        saveLogLabel = QLabel('Log File:')
        saveLogBrowse = QPushButton('&Browse')
        saveLogBrowse.clicked.connect(self.browseSaveLog)
        self._saveLogEdit = QLineEdit('')

        gLayout = QGridLayout()
        gLayout.addWidget(saveLogLabel, 0, 0, 1, 1, Qt.AlignRight)
        gLayout.addWidget(self._saveLogEdit, 0, 1, 1, 6)
        gLayout.addWidget(saveLogBrowse, 0, 7, 1, 1)

        self._console = QTextEdit()
        self._console.setLineWrapMode(QTextEdit.NoWrap)
        self._console.setMinimumSize(800, 400)
        palette = self._console.palette()
        palette.setColor(QPalette.Base, QColor.fromRgb(255, 255,
                                                       221))  # ffffdd.
        self._console.setPalette(palette)
        font = QFont('Bitstream Vera Sans Mono',
                     self._console.font().pointSize())
        self._console.setFont(font)
        self._highlighter = Highlighter(self._console.document())

        self._progressBar = QProgressBar()
        self._progressBar.setRange(0, 100)
        self._progressBar.setTextVisible(True)

        hLayout = QHBoxLayout()
        hLayout.addStretch()
        hLayout.addWidget(self._go)
        hLayout.addStretch()
        hLayout.addWidget(self._saveLog)
        hLayout.addStretch()

        vLayout = QVBoxLayout()
        vLayout.addLayout(hLayout)
        vLayout.addLayout(gLayout)
        vLayout.addWidget(self._progressBar)
        vLayout.addWidget(self._console)
        self.setLayout(vLayout)

        self.progress.connect(self._progressBar.setValue)
        self._saveLog.clicked.connect(self.saveLog)

        self.readSettings()
        return

    def _setOptions(self, options):
        self._options = options

    def _setConf(self, conf):
        self._conf = conf

    def _getOptions(self):
        return self._options

    def _getConf(self):
        return self._conf

    options = property(_getOptions, _setOptions)
    conf = property(_getConf, _setConf)

    def browseSaveLog(self):
        self._saveLogEdit.setText(
            QFileDialog.getSaveFileName(self, 'Select Log File Report',
                                        self._saveLogEdit.text(),
                                        'Report Files (*.log *.txt)'))
        return

    def saveLog(self):
        if self._saveLogEdit.text():
            fd = open(self._saveLogEdit.text(), 'w+')
            fd.write(self._console.toPlainText())
            fd.close()
        return

    def shellCommand(self):
        command = [self.conf.bootstrapDir + '/ccb.py']
        for project in self.options.projects:
            for tool in project.actives:
                command += ['--tool=' + tool]
        toolsCount = len(command) - 1

        if self.conf.rootDir: command += ['--root=%s' % self.conf.rootDir]

        #if self.options.svnUpdate:   command += [ '--svn-update' ]
        #if self.options.svnStatus:   command += [ '--svn-update' ]
        if self.options.enableDoc: command += ['--doc']
        if self.options.devtoolset2: command += ['--devtoolset-2']
        if self.options.qt5: command += ['--qt5']
        if self.options.noCache: command += ['--no-cache']
        if self.options.rmBuild: command += ['--rm-build']
        if self.options.verbose: command += ['--verbose']
        if self.options.make:
            makeArguments = 'install ' + self.options.threads
            command += ['--make=%s' % makeArguments]

        if self.options.buildMode == 'Debug':
            command += ['--debug']
        return toolsCount, command

    def go(self):
        rePercentage = re.compile(r'^\[\s*(?P<percent>\d+)%\].*')
        reProcessTool = re.compile(r'^Processing tool:\s*"(?P<tool>.+)"')

        if not self.options or not self.conf: return

        toolsCount, command = self.shellCommand()
        if not toolsCount: return

        self._progressBar.reset()
        self._progressBar.setRange(0, toolsCount * 100)

        strCommand = command[0]
        for arg in command[1:]:
            strCommand += ' ' + arg
        strCommand += '\n\n'
        self._console.setFontItalic(True)
        self._console.insertPlainText(strCommand)
        self._console.setFontItalic(False)

        toolsDone = -1
        builderProcess = subprocess.Popen(command,
                                          stdout=subprocess.PIPE,
                                          stderr=subprocess.STDOUT)
        while True:
            line = builderProcess.stdout.readline()
            if line == '': break

            m = rePercentage.match(line)
            if m:
                self.progress.emit(toolsDone * 100 + int(m.group('percent')))
            else:
                m = reProcessTool.match(line)
                if m:
                    toolsDone += 1

            self._console.insertPlainText(line)

            scrollBar = self._console.verticalScrollBar()
            scrollBar.setValue(scrollBar.maximum())
            QApplication.processEvents()
        builderProcess.wait()
        if builderProcess.returncode == None:
            pass
        return

    def readSettings(self):
        settings = QSettings()
        self._saveLogEdit.setText(settings.value('compile/saveLog').toString())
        return

    def saveSettings(self):
        settings = QSettings()
        settings.setValue('compile/saveLog', self._saveLogEdit.text())
        return
Example #5
0
class FileItem(QTreeWidgetItem):

    cols = ['Filepath', 'Renamed Filepath']

    invalid_char_map = {':': ''}

    re_filename_episodes = [
        re.compile(
            r'.*[Ss](?P<season>\d{1,2})[\s\-_]*[Ee](?P<episode>\d{1,2}).*',
            re.I),
        re.compile(
            r'.*season\s*(?P<season>\d{1,2})[\s\-_]*episode\s*[Ee](?P<episode>\d{1,2}).*',
            re.I),
    ]

    re_filepath_episodes = [
        re.compile(
            r'.*season\s*(?P<season>\d{1,2})\\(?:season\s*\d{1,2}[\s\-_]*)?(?:episode|ep\.?|e)\s*(?P<episode>\d{1,2}).*',
            re.I),
    ]

    def __init__(self, parent, filepath, mediaman):
        super(FileItem, self).__init__(parent)
        self._renamed = False
        self.mediaman = mediaman
        self.filepath = filepath
        self.renamed_filepath = None
        self.media_info = None
        self.episode_info = None
        self.thread = None
        self.pbar = None
        self.setText(0, self.filepath)
        self.send_thread()

    def send_thread(self):
        if self.thread is None:
            self.thread = FilepathSearchThread(self.treeWidget())
            self.thread.finished.connect(self.receive_thread)
        thread_ready = self.thread.wait(10000)
        if thread_ready:
            tree = self.treeWidget()
            self.pbar = QProgressBar(tree)
            self.pbar.setRange(0, 0)
            tree.setItemWidget(self, 1, self.pbar)
            self.thread.filepath = self.filepath
            self.thread.start()

    def receive_thread(self):
        self.media_info = self.thread.result
        self.pbar.reset()
        tree = self.treeWidget()
        tree.removeItemWidget(self, 1)
        self.pbar.deleteLater()
        self.refresh()

    def _replace_invalid_chars(self, text):
        for k, v in FileItem.invalid_char_map.items():
            if k in text:
                text = text.replace(k, v)
        return text

    def refresh(self):
        moviedir = self.mediaman.moviedir()
        tvdir = self.mediaman.tvdir()

        if self.media_info:
            title = self.media_info.get('title')
            title = self._replace_invalid_chars(title)
            year = self.media_info.get('year')

            filename, ext = os.path.splitext(os.path.basename(self.filepath))

            if self.episode_info or self.media_info.get('episodes'):
                if not self.episode_info:
                    episodes = self.media_info['episodes']
                    ep_match = None
                    for reg in FileItem.re_filename_episodes:
                        m = reg.search(filename)
                        if m:
                            ep_match = m.groupdict()
                            break
                    if not ep_match:
                        for reg in FileItem.re_filepath_episodes:
                            m = reg.search(self.filepath)
                            if m:
                                ep_match = m.groupdict()

                    if ep_match:
                        season, episode = int(ep_match['season']), int(
                            ep_match['episode'])
                        for episode_info in episodes:
                            if (episode_info['season'],
                                    episode_info['episode']) == (season,
                                                                 episode):
                                self.episode_info = episode_info
                                break

                if self.episode_info:
                    self.renamed_filepath = ur'{tvdir}\{title}\Season{season:02d}\{title}.S{season:02d}E{episode:02d}.{episode_title}{ext}'.format(
                        tvdir=tvdir,
                        title=title,
                        year=year,
                        season=self.episode_info['season'],
                        episode=self.episode_info['episode'],
                        episode_title=self._replace_invalid_chars(
                            self.episode_info['title']),
                        ext=ext,
                    )
                else:
                    self.renamed_filepath = ur'{tvdir}\{title}\Season00\{title}.S00E00.XXX{ext}'.format(
                        tvdir=tvdir,
                        title=title,
                        year=year,
                        ext=ext,
                    )

            else:
                self.renamed_filepath = ur'{moviedir}\{title} ({year})\{title}{ext}'.format(
                    moviedir=moviedir, title=title, year=year, ext=ext)

            self.setText(1, self.renamed_filepath)
            if os.path.exists(self.renamed_filepath):
                self.setBackgroundColor(
                    FileItem.cols.index('Renamed Filepath'),
                    QColor(0, 255, 0, 100))
Example #6
0
class OWDatabasesPack(OWWidget.OWWidget):
    settingsList = ["fileslist", "downloadurl", "downloadmessage"]

    def __init__(self, parent=None, signalManager=None,
                 title="Databases Pack"):

        super(OWDatabasesPack, self).__init__(
            parent, signalManager, title, wantMainArea=False)

        self.fileslist = [("Taxonomy", "ncbi_taxonomy.tar.gz")]
        self.downloadurl = "https://dl.dropboxusercontent.com/u/100248799/sf_pack.tar.gz"
        self.downloadmessage = (
            "Downloading a subset of available databases for a smoother " +
            "ride through the workshop"
        )
        self.loadSettings()
        self._tmpfile = None
        self.reply = None

        # Locks held on server files
        self.locks = []
        self.net_manager = QNetworkAccessManager()
        # Lock all files in files list so any other (in process) atempt to
        # download the files waits)
        box = OWGUI.widgetBox(self.controlArea, "Info")
        self.info = OWGUI.widgetLabel(box, self.downloadmessage)
        self.info.setWordWrap(True)

        box = OWGUI.widgetBox(self.controlArea, "Status")
        self.statusinfo = OWGUI.widgetLabel(box, "Please wait")
        self.statusinfo.setWordWrap(True)
        self.progressbar = QProgressBar()
        box.layout().addWidget(self.progressbar)

        self.setMinimumWidth(250)

        already_available = [(domain, filename)
                             for domain in serverfiles.listdomains()
                             for filename in serverfiles.listfiles(domain)]

        if set(self.fileslist) <= set(already_available):
            # All files are already downloaded
            self.statusinfo.setText("All files already available")
            self.setStatusMessage("Done")
        else:
            for domain, filename in self.fileslist + [("_tmp_cache_", "pack")]:
                manager = serverfiles._lock_file(domain, filename)
                try:
                    manager.__enter__()
                except Exception:
                    warnings.warn("Could not acquire lock for {0} {0}"
                                  .format(domain, filename))
                    self.warning(0, "...")
                else:
                    self.locks.append(manager)

            QTimer.singleShot(0, self.show)
            QTimer.singleShot(0, self.run)

    def run(self):
        self.setStatusMessage("Downloading")
        self.info.setText(self.downloadmessage)

        target_dir = os.path.join(environ.buffer_dir, "serverfiles_pack_cache")

        try:
            os.makedirs(target_dir)
        except OSError:
            pass

        self.progressBarInit()

        req = QNetworkRequest(QUrl(self.downloadurl))
        self.reply = self.net_manager.get(req)
        self.reply.downloadProgress.connect(self._progress)
        self.reply.error.connect(self._error)
        self.reply.finished.connect(self._finished)
        self.reply.readyRead.connect(self._read)
        url = urlparse.urlsplit(self.downloadurl)
        self._tmpfilename = posixpath.basename(url.path)

        self._tmpfile = open(
            os.path.join(target_dir, self._tmpfilename), "wb+"
        )

    def _progress(self, rec, total):
        if rec == 0 and total == 0:
            self.progressbar.setRange(0, 0)
            self.progressBarValue = 1.0
        else:
            self.progressbar.setRange(0, total)
            self.progressbar.setValue(rec)
            self.progressBarValue = 100.0 * rec / (total or 1)

    def _error(self, error):
        self.statusinfo.setText(
            u"Error: {0}".format(error.errorString())
        )
        self.error(0, "Error: {0}".format(error.errorString()))
        self.setStatusMessage("Error")
        self._releaselocks()
        self._removetmp()
        self.progressBarFinshed()

    def _read(self):
        contents = str(self.reply.readAll())
        self._tmpfile.write(contents)

    def _finished(self):
        self.progressbar.reset()
        if self.reply.error() != QNetworkReply.NoError:
            self._releaselocks()
            self._removetmp()
            return

        self.statusinfo.setText("Extracting")
        self.setStatusMessage("Extracting")
        try:
            self._extract()
        except Exception:
            # Permission errors, ... ??
            pass

        self.statusinfo.setText("Done")
        self.setStatusMessage("Done")
        self.progressbar.reset()
        self.progressBarFinished()

        self._releaselocks()
        self._removetmp()

    def _extract(self):
        self._tmpfile.seek(0, 0)
        archive = tarfile.open(fileobj=self._tmpfile)
        target_dir = serverfiles.localpath()
        archive.extractall(target_dir)

    def onDeleteWidget(self):
        super(OWDatabasesPack, self).onDeleteWidget()
        self._releaselocks()

        if self.reply is not None and self.reply.isOpen():
            self.reply.finished.disconnect(self._finished)
            self.reply.error.disconnect(self._error)
            self.reply.close()

        if self._tmpfile is not None:
            self._tmpfile.close()
            self._tmpfile = None

    def _releaselocks(self):
        for lock in self.locks:
            lock.__exit__(None, None, None)
        self.locks = []

    def _removetmp(self):
        if self._tmpfile is not None:
            self._tmpfile.close()
            self._tmpfile = None

        tmp_file = os.path.join(
            environ.buffer_dir, "serverfiles_pack_cache", self._tmpfilename
        )

        os.remove(tmp_file)
class _CancellableProgressEditor(Editor):

    title = Unicode   # synced from factory.title_name 
    message = Unicode # synced from factory.message_name
    min = Int#Float   # synced from factory.min_name
    max = Int#Float   # synced from factory.max_name
    show_time = Bool  # synced from factory.show_time_name

    def _title_changed(self):
        if self._title is not None:
            self._title.setText('<B>%s</B>' % self.title)
            self._title.setVisible(len(self.title) > 0)
    
    def _message_changed(self):
        if self._message is not None:
            self._message.setText(self.message)
            self._message.setVisible(len(self.message) > 0)
        if self.factory.prefix_message:
            self.set_text()

    def _show_time_changed(self):
        if self._time_widget is not None:
            self._time_widget.setVisible(self.show_time)
    
    @on_trait_change('min, max')
    def change_range(self):
        if self._progress_bar is not None:
            self._progress_bar.setRange(self.min, self.max)
            self.update_editor()
    
    def init(self, parent):

        self.title = self.factory.title
        if len(self.factory.title_name) > 0:
            self.sync_value(self.factory.title_name, 'title')#, 'from')
        
        self.message = self.factory.message
        if len(self.factory.message_name) > 0:
            self.sync_value(self.factory.message_name, 'message')#, 'from')

        self.min = self.factory.min
        if len(self.factory.min_name) > 0:
            self.sync_value(self.factory.min_name, 'min')#, 'from')

        self.max = self.factory.max
        if len(self.factory.max_name) > 0:
            self.sync_value(self.factory.max_name, 'max')#, 'from')
        
        self.show_time = self.factory.show_time
        if len(self.factory.show_time_name) > 0:
            self.sync_value(self.factory.show_time_name, 'show_time')#, 'from')
        
        self.control = self._create_control(parent)

        self.can_cancel = self.factory.can_cancel
        if len(self.factory.can_cancel_name) > 0:
            self.sync_value(self.factory.can_cancel_name, 'can_cancel')#, 'from')
                
        self.set_tooltip()
        self.reset()

    can_cancel = Bool(False)
    from traits.api import Any
    buttons = Any
    @on_trait_change('can_cancel')
    def set_buttons_visible(self, value):
        self.buttons.setVisible(value)

    def _create_control(self, parent):
        layout = QVBoxLayout()
        
        if len(self.title) > 0:
            self._title = QLabel('<B>%s</B>' % self.title)
            layout.addWidget(self._title)
    
        if not self.factory.prefix_message and len(self.message) > 0:
            self._message = QLabel(self.message)
#            self._message = QTextEdit(self.message)
#            self._message.setReadOnly(True)
            layout.addWidget(self._message)
    
        self._progress_bar = QProgressBar()
        self._progress_bar.setRange(self.min, self.max)
        if not self.factory.can_cancel:
            layout.addWidget(self._progress_bar)
        else:
            self.buttons = QDialogButtonBox()
            self.buttons.addButton(u'Cancel', QDialogButtonBox.RejectRole)
            self.buttons.connect(self.buttons, SIGNAL('rejected()'), self.factory.cancelled)
            grid_layout = QGridLayout()
            grid_layout.addWidget(self._progress_bar, 0, 0)
            grid_layout.setColumnStretch(0, 1)
            grid_layout.addWidget(self.buttons, 0, 1)
            layout.addLayout(grid_layout)
                
        if self.factory.show_time:
            elapsed_label = QLabel('Elapsed time:')
            estimated_label = QLabel('Estimated time:')
            remaining_label = QLabel('Remaining time:')
            self._elapsed_control = QLabel('unknown')
            self._estimated_control = QLabel('unknown')
            self._remaining_control = QLabel('unknown')
            grid_layout = QGridLayout()
            grid_layout.addWidget(elapsed_label, 0, 0)
            grid_layout.addWidget(self._elapsed_control, 0, 1)
            grid_layout.addWidget(estimated_label, 1, 0)
            grid_layout.addWidget(self._estimated_control, 1, 1)
            grid_layout.addWidget(remaining_label, 2, 0)
            grid_layout.addWidget(self._remaining_control, 2, 1)
            grid_layout.setColumnStretch(1, 1)
            self._time_widget = QWidget()
            self._time_widget.setLayout(grid_layout)
            layout.addWidget(self._time_widget)
        
        if self.factory.show_text:
            self.set_text()
        else:
            self._progress_bar.setTextVisible(False)

        widget = QWidget()
        widget.setLayout(layout)
        return widget

    def set_text(self):
        if self._progress_bar is None:
            return
        if self.factory.prefix_message:
            format = self.message + ' '
        else:
            format = ''
        if self.factory.show_value:
            format += '%v'
        if self.factory.show_max:
            if self.factory.show_value:
                format += '/'
            format += '%m'
        if self.factory.show_value or self.factory.show_max:
            format += ' '
        if self.factory.show_percent:
            if self.factory.show_value or self.factory.show_max:
                format += '(%p%)'
            else:
                format += '%p%'
        self._progress_bar.setFormat(format)

    def _set_time_label(self, value, control):
        hours = value / 3600
        minutes = (value % 3600) / 60
        seconds = value % 60
        label = "%1u:%02u:%02u" % (hours, minutes, seconds)
        control.setText(control.text()[:-7] + label)

    def update_editor(self):
        if self.factory.min <= self.value <= self.factory.max:
            if self.value == self.factory.min:
                self.reset()
            self._progress_bar.setValue(self.value)

        if self.factory.show_time:
            if (self.factory.max != self.factory.min):
                percent = (float(self.value) - self.factory.min) / (self.factory.max - self.factory.min)
                # if float(<undefined>) raises an error here then probably the
                # name of the trait this is editing is mispelled or owned by
                # the handler, e.g. 'handler.progress' instead of 'progress'. 
            else:
                percent = 1.0
            if self.factory.show_time and (percent != 0):
                current_time = time.time()
                elapsed = current_time - self._start_time
                estimated = elapsed / percent
                remaining = estimated - elapsed
                self._set_time_label(elapsed, self._elapsed_control)
                self._set_time_label(estimated, self._estimated_control)
                self._set_time_label(remaining, self._remaining_control)            

    def reset(self):
        self._progress_bar.reset()
        self._start_time = time.time()
Example #8
0
class OWDatabasesPack(OWWidget.OWWidget):
    settingsList = ["fileslist", "downloadurl", "downloadmessage"]

    def __init__(self, parent=None, signalManager=None, title="Databases Pack"):

        super(OWDatabasesPack, self).__init__(parent, signalManager, title, wantMainArea=False)

        self.fileslist = [("Taxonomy", "ncbi_taxonomy.tar.gz")]
        self.downloadurl = "https://dl.dropboxusercontent.com/u/100248799/sf_pack.tar.gz"
        self.downloadmessage = (
            "Downloading a subset of available databases for a smoother " + "ride through the workshop"
        )
        self.loadSettings()
        self._tmpfile = None
        self.reply = None

        # Locks held on server files
        self.locks = []
        self.net_manager = QNetworkAccessManager()
        # Lock all files in files list so any other (in process) atempt to
        # download the files waits)
        box = OWGUI.widgetBox(self.controlArea, "Info")
        self.info = OWGUI.widgetLabel(box, self.downloadmessage)
        self.info.setWordWrap(True)

        box = OWGUI.widgetBox(self.controlArea, "Status")
        self.statusinfo = OWGUI.widgetLabel(box, "Please wait")
        self.statusinfo.setWordWrap(True)
        self.progressbar = QProgressBar()
        box.layout().addWidget(self.progressbar)

        self.setMinimumWidth(250)

        already_available = [
            (domain, filename) for domain in serverfiles.listdomains() for filename in serverfiles.listfiles(domain)
        ]

        if set(self.fileslist) <= set(already_available):
            # All files are already downloaded
            self.statusinfo.setText("All files already available")
            self.setStatusMessage("Done")
        else:
            for domain, filename in self.fileslist + [("_tmp_cache_", "pack")]:
                manager = serverfiles._lock_file(domain, filename)
                try:
                    manager.__enter__()
                except Exception:
                    warnings.warn("Could not acquire lock for {0} {0}".format(domain, filename))
                    self.warning(0, "...")
                else:
                    self.locks.append(manager)

            QTimer.singleShot(0, self.show)
            QTimer.singleShot(0, self.run)

    def run(self):
        self.setStatusMessage("Downloading")
        self.info.setText(self.downloadmessage)

        target_dir = os.path.join(environ.buffer_dir, "serverfiles_pack_cache")

        try:
            os.makedirs(target_dir)
        except OSError:
            pass

        self.progressBarInit()

        req = QNetworkRequest(QUrl(self.downloadurl))
        self.reply = self.net_manager.get(req)
        self.reply.downloadProgress.connect(self._progress)
        self.reply.error.connect(self._error)
        self.reply.finished.connect(self._finished)
        self.reply.readyRead.connect(self._read)
        url = urlparse.urlsplit(self.downloadurl)
        self._tmpfilename = posixpath.basename(url.path)

        self._tmpfile = open(os.path.join(target_dir, self._tmpfilename), "wb+")

    def _progress(self, rec, total):
        if rec == 0 and total == 0:
            self.progressbar.setRange(0, 0)
            self.progressBarValue = 1.0
        else:
            self.progressbar.setRange(0, total)
            self.progressbar.setValue(rec)
            self.progressBarValue = 100.0 * rec / (total or 1)

    def _error(self, error):
        self.statusinfo.setText(u"Error: {0}".format(error.errorString()))
        self.error(0, "Error: {0}".format(error.errorString()))
        self.setStatusMessage("Error")
        self._releaselocks()
        self._removetmp()
        self.progressBarFinshed()

    def _read(self):
        contents = str(self.reply.readAll())
        self._tmpfile.write(contents)

    def _finished(self):
        self.progressbar.reset()
        if self.reply.error() != QNetworkReply.NoError:
            self._releaselocks()
            self._removetmp()
            return

        self.statusinfo.setText("Extracting")
        self.setStatusMessage("Extracting")
        try:
            self._extract()
        except Exception:
            # Permission errors, ... ??
            pass

        self.statusinfo.setText("Done")
        self.setStatusMessage("Done")
        self.progressbar.reset()
        self.progressBarFinished()

        self._releaselocks()
        self._removetmp()

    def _extract(self):
        self._tmpfile.seek(0, 0)
        archive = tarfile.open(fileobj=self._tmpfile)
        target_dir = serverfiles.localpath()
        archive.extractall(target_dir)

    def onDeleteWidget(self):
        super(OWDatabasesPack, self).onDeleteWidget()
        self._releaselocks()

        if self.reply is not None and self.reply.isOpen():
            self.reply.finished.disconnect(self._finished)
            self.reply.error.disconnect(self._error)
            self.reply.close()

        if self._tmpfile is not None:
            self._tmpfile.close()
            self._tmpfile = None

    def _releaselocks(self):
        for lock in self.locks:
            lock.__exit__(None, None, None)
        self.locks = []

    def _removetmp(self):
        if self._tmpfile is not None:
            self._tmpfile.close()
            self._tmpfile = None

        tmp_file = os.path.join(environ.buffer_dir, "serverfiles_pack_cache", self._tmpfilename)

        os.remove(tmp_file)
Example #9
0
class CANMonitor(QMainWindow):
    def __init__(self, app, test, parent):
        QMainWindow.__init__(self, parent)
        self.app = app
        self.lcdDict=dict()
        self.logBuffer=deque("", 1000)
        self.logBuffer2=dict()
        self.logBufferInit=dict()
        self.logEntryCount=1
        self.maxLogEntryCount=65353
        self.tableUpdateCouter=0
        self.logFile=None
        self.test=test
        self.logFileName="/tmp/candash.log"
        self.connectCANEnable=True
        self.connectGPSEnable=True
        self.replayMode=False
        self.canIdList=[0x621, 0x353, 0x351, 0x635, 0x271, 0x371, 0x623, 0x571, 0x3e5, 0x591, 0x5d1]
        self.updateGPSThread=None
        self.config=Config("candash.cfg")
        self.log=Log(False)
        font = self.font()
        font.setPointSize(14)
        self.setFont(font)
        self.ampelGruen=QIcon("images/ampel-gruen.png")
        self.ampelRot=QIcon("images/ampel-rot.png")
        self.ampelGelb=QIcon("images/ampel-gelb.png")
        self.lastCANState=canStoppedState
        self.lastGPSState=gpsStoppedState
        self.canDecoder=CANDecoder(self)

        self.initUI(parent)
    
    def clearAllLCD(self):
        for lcdList in self.lcdDict.values():
            for lcd in lcdList:
                if lcd.mode()==QLCDNumber.Bin:
                    lcd.display("00000000")
                else:
                    lcd.display(0)
                    
        self.rpmGauge.setValue(0)
        self.velGauge.setValue(0)
  
    def createLCD(self, mode):
        lcd = QLCDNumber(self)
        lcd.setMode(mode)
        lcd.setMinimumHeight(50)
        lcd.setMinimumWidth(160)
        lcd.setDigitCount(8)
        if mode==QLCDNumber.Bin:
            lcd.display("00000000")
        else:
            lcd.display(0)
        lcd.setSegmentStyle(QLCDNumber.Flat)
        lcd.setAutoFillBackground(True)
        palette = lcd.palette()
        palette.setColor(QPalette.Normal, QPalette.Foreground, Qt.blue)
        palette.setColor(QPalette.Normal, QPalette.Background, Qt.lightGray)
        lcd.setPalette(palette);
        return lcd
    
    def addLCD(self, lcd, canId, subItem):
        if not hex(canId)+":"+subItem in self.lcdDict.keys():
            lcdItemList=list()
            lcdItemList.append(lcd)
            self.lcdDict[hex(canId)+":"+subItem]=lcdItemList
        else:
            self.lcdDict[hex(canId)+":"+subItem].append(lcd)
                
    def createCANIdValueEntry(self, vbox, canId, subId, mode):        
        lcd = self.createLCD(mode)
        
        self.addLCD(lcd, canId, subId)
        
        vbox.addWidget(lcd)          
        
    def createCANIdEntry(self, form, canId, subId, label, mode):
#        hbox = QHBoxLayout()

        lbl = QLabel(self)
        lbl.setMinimumHeight(50)
        font = lbl.font()
        font.setPointSize(14)
        lbl.setFont(font)
        
        if label!=None:
            lbl.setText(label)
#            hbox.addWidget(lbl)
        
        lcd = self.createLCD(mode)
#        hbox.addWidget(lcd)

        form.addRow(lbl, lcd)
        
        self.addLCD(lcd, canId, subId)
        
#        vbox.addLayout(hbox)
        
    def createCANIdEntrySingleLine(self, form, canId, subIdList, label, mode):
#        hbox = QHBoxLayout()

        lbl = QLabel(self)
        lbl.setMinimumHeight(50)
        font = lbl.font()
        font.setPointSize(14)
        lbl.setFont(font)
        if label!=None:
            lbl.setText(label)
#            hbox.addWidget(lbl)

        hbox2=QHBoxLayout();
        
        for i in range(len(subIdList)):
            subId=subIdList[i]
            lcd = self.createLCD(mode)
            hbox2.addWidget(lcd)
            self.addLCD(lcd, canId, subId)

        form.addRow(lbl, hbox2)
#        hbox.addLayout(hbox2)
                        
#        vbox.addLayout(hbox)
        
    def createLogView(self, vbox):
        self.logView=QTableView(self)
        vbox.addWidget(self.logView)
        
        self.logViewModel=CANLogViewTableModel(self.logBuffer, self.canIdList, self)
        self.logView.setModel(self.logViewModel)
        
        header=QHeaderView(Qt.Horizontal, self.logView)
        header.setStretchLastSection(True)
        header.setResizeMode(NUMBER_COL, QHeaderView.Fixed)
        header.setResizeMode(TIME_COL, QHeaderView.Fixed)
        header.setResizeMode(ID_COL, QHeaderView.Fixed)

        self.logView.setHorizontalHeader(header)
        
        self.logView.setColumnWidth(NUMBER_COL, 80)
        self.logView.setColumnWidth(TIME_COL, 150)
        self.logView.setColumnWidth(ID_COL, 80)
        self.logView.setColumnWidth(SIZE_COL, 50)
        
    def createLogView2(self, vbox):
        self.logView2=QTableView(self)
        vbox.addWidget(self.logView2)
        
        self.logViewModel2=CANLogViewTableModel2(self.canIdList, self)
        self.logView2.setModel(self.logViewModel2)
#        self.logView2.setSortingEnabled(True)
        
        header=QHeaderView(Qt.Horizontal, self.logView2)
#        header.setStretchLastSection(True)
#        header.setClickable(True)
        header.setResizeMode(0, QHeaderView.Fixed)
        header.setResizeMode(1, QHeaderView.Fixed)

        self.logView2.setHorizontalHeader(header)
        
        self.logView2.setColumnWidth(0, 80)
        self.logView2.setColumnWidth(1, 50)
        for i in range(2, 10):
            self.logView2.setColumnWidth(i, 60)
        
    def initUI(self, parent):  
#        exitAction = QAction(QIcon(), 'Exit', self)
#        exitAction.setShortcut('Ctrl+Q')
#        exitAction.setStatusTip('Exit application')
#        exitAction.triggered.connectToCAN(self.close)

        self.statusbar=self.statusBar()
        self.progress=QProgressBar()
        self.statusbar.addPermanentWidget(self.progress)

#        menubar = self.menuBar()
#        fileMenu = menubar.addMenu('&File')
#        fileMenu.addAction(exitAction)

#        toolbar = self.addToolBar('Exit')
##        toolbar.addAction(exitAction)
#                
#        self.connectedIcon=QIcon("images/network-connect.png")
#        self.disconnectIcon=QIcon("images/network-disconnect.png")
#        self.connectAction = QAction(self.disconnectIcon , 'Connect', self)
#        self.connectAction.triggered.connect(self._connect1)
#        self.connectAction.setCheckable(True)
#        
#        toolbar.addAction(self.connectAction)
#        
#        self.gpsIcon=QIcon("images/icon_gps.gif")
#        self.reconnectGPSAction = QAction(self.gpsIcon, 'Reconnect GPS', self)
#        self.reconnectGPSAction.triggered.connect(self._reconnectGPS)
#        toolbar.addAction(self.reconnectGPSAction)
        
        mainWidget=QWidget(self)
#        mainWidget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        mainWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)        

        self.setCentralWidget(mainWidget)
        top=QVBoxLayout(mainWidget)
        
        self.tabs = MyTabWidget(self)
        top.addWidget(self.tabs)
        
        mainTab = QWidget(self)
        miscTab = QWidget(self) 
        misc2Tab=QWidget(self)
        canLogTab=QWidget(self)
        dashTab=QWidget(self)
        gpsTab=QWidget(self)
        osmTab=QWidget(self)
        debugLogTab=QWidget(self)
        
        mainTabLayout = QFormLayout(mainTab)
        miscTabLayout = QFormLayout(miscTab)
        misc2TabLayout = QFormLayout(misc2Tab)
        canLogTabLayout = QVBoxLayout(canLogTab)
        dashTabLayout = QHBoxLayout(dashTab)
        gpsTabLayout=QHBoxLayout(gpsTab)
        osmTabLayout=QVBoxLayout(osmTab)
        debugLogTabLayout=QVBoxLayout(debugLogTab)
        
        self.tabs.addTab(dashTab, "Dash") 
        self.tabs.addTab(mainTab, "Main")
        self.tabs.addTab(miscTab, "Misc 1") 
        self.tabs.addTab(misc2Tab, "Misc 2") 
        self.tabs.addTab(canLogTab, "CAN") 
        self.tabs.addTab(gpsTab, "GPS")
        self.tabs.addTab(osmTab, "OSM")
        self.tabs.addTab(debugLogTab, "Log")

        self.tabs.setCurrentIndex(0)
        
        self.debugLogWidget=DebugLogWidget(self)
        debugLogTabLayout.setAlignment(Qt.AlignLeft|Qt.AlignTop)
        self.debugLogWidget.addToWidget(debugLogTabLayout)

#        self.debugLogWidget.addLine("test")

        self.createCANIdEntry(mainTabLayout, 0x353, "0", "Drehzahl", QLCDNumber.Dec)
#        self.createCANIdEntry(mainTabLayout, 0x353, "1", "Öltemperatur", QLCDNumber.Dec)
        self.createCANIdEntry(mainTabLayout, 0x353, "1", "Kuehlwasser Temperatur", QLCDNumber.Dec)
        self.createCANIdEntry(mainTabLayout, 0x351, "0", "Geschwindigkeit", QLCDNumber.Dec)
        self.createCANIdEntry(mainTabLayout, 0x351, "1", "Außentemperatur", QLCDNumber.Dec)
        self.createCANIdEntry(miscTabLayout, 0x635, "0", "Licht, Klemme 58d", QLCDNumber.Dec)
        self.createCANIdEntry(miscTabLayout, 0x271, "0", "Zuendung", QLCDNumber.Dec)
        self.createCANIdEntrySingleLine(miscTabLayout, 0x371, ["0", "1"], "Tuerstatus", QLCDNumber.Bin)
        self.createCANIdEntry(miscTabLayout, 0x371, "2", "Blinker, Retoursgang", QLCDNumber.Bin)
        self.createCANIdEntrySingleLine(mainTabLayout, 0x623, ["0", "1", "2"], "Uhrzeit (Stunden)", QLCDNumber.Dec)        
        self.createCANIdEntry(mainTabLayout, 0x571, "0", "Batteriespannung", QLCDNumber.Dec)
        
        self.createCANIdEntry(misc2TabLayout, 0x3e5, "0", "Zuheizer 1", QLCDNumber.Bin)
        self.createCANIdEntry(misc2TabLayout, 0x3e5, "1", "Zuheizer 2", QLCDNumber.Bin)
        self.createCANIdEntry(misc2TabLayout, 0x3e5, "2", "Zuheizer 3", QLCDNumber.Bin)
        self.createCANIdEntry(misc2TabLayout, 0x3e5, "3", "Zuheizer 4", QLCDNumber.Bin)
        self.createCANIdEntry(misc2TabLayout, 0x3e5, "4", "Zuheizer 5", QLCDNumber.Bin)
        
        self.createCANIdEntry(miscTabLayout, 0x3e5, "5", "Zuheizer", QLCDNumber.Dec)
        self.createCANIdEntry(miscTabLayout, 0x591, "0", "ZV", QLCDNumber.Dec)
        self.createCANIdEntry(miscTabLayout, 0x5d1, "0", "Scheibenwischer", QLCDNumber.Dec)

        self.createCANIdEntrySingleLine(mainTabLayout, 0x351, ["2", "3"], "Wegstreckenimpuls", QLCDNumber.Dec)
        self.createCANIdEntrySingleLine(misc2TabLayout, 0x621, ["0"], "0x621", QLCDNumber.Bin)
        self.createCANIdEntrySingleLine(misc2TabLayout, 0x621, ["1", "2"], "0x621", QLCDNumber.Dec)
        
        logTabs = MyTabWidget(self)
        canLogTabLayout.addWidget(logTabs)
        
        logTabWidget1=QWidget()
        logTabWidget2=QWidget()

        logTabs.addTab(logTabWidget1, "Time")
        logTabs.addTab(logTabWidget2, "Change") 
        
        logTab1Layout = QVBoxLayout(logTabWidget1)
        self.createLogView(logTab1Layout)
        
        self.logViewFilerBox1=CANFilterBox(False, self)
        self.logViewFilerBox1.addFilterBox(logTab1Layout)
        
        self.logViewTableBox1=CANLogTableBox(self.logViewModel, self.logBuffer, None, self)
        self.logViewTableBox1.addTableBox(logTab1Layout)
        
        logTab2Layout = QVBoxLayout(logTabWidget2)
        self.createLogView2(logTab2Layout)

        self.logViewFilterBox2=CANFilterBox(True, self)
        self.logViewFilterBox2.addFilterBox(logTab2Layout)
        
        self.logViewTableBox2=CANLogTableBox(self.logViewModel2, self.logBuffer2, self.logBufferInit, self)
        self.logViewTableBox2.addTableBox(logTab2Layout)
        
        logButtonBox = QHBoxLayout()
        canLogTabLayout.addLayout(logButtonBox)
        
        self.logFileButton=QCheckBox("Log to File", self)
        self.logFileButton.setToolTip('Enable file logging')
        self.logFileButton.resize(self.logFileButton.sizeHint())
        self.logFileButton.setDisabled(self.replayMode==True)
        self.logFileButton.clicked.connect(self._enableLogFile)
        logButtonBox.addWidget(self.logFileButton)
        
        self.clearLogButton = QPushButton('Clear Log', self)
        self.clearLogButton.resize(self.clearLogButton.sizeHint())
        self.clearLogButton.setDisabled(not self.logFileAvailable() or self.replayMode==True)
        self.clearLogButton.clicked.connect(self._clearLogFile)
        logButtonBox.addWidget(self.clearLogButton)

        self.replayButton = QPushButton('Replay Log', self)
        self.replayButton.resize(self.replayButton.sizeHint())
        self.replayButton.setDisabled(not self.logFileAvailable() or self.connectCANEnable==True)
        self.replayButton.clicked.connect(self._startReplayMode)
        logButtonBox.addWidget(self.replayButton)

        self.stopReplayButton = QPushButton('Stop Replay', self)
        self.stopReplayButton.resize(self.stopReplayButton.sizeHint())
        self.stopReplayButton.setDisabled(self.replayMode==False)
        self.stopReplayButton.clicked.connect(self._stopReplayMode)
        logButtonBox.addWidget(self.stopReplayButton)
                    
                    
        velBox = QVBoxLayout()
        dashTabLayout.addLayout(velBox)
        dashTabLayout.setAlignment(Qt.AlignCenter|Qt.AlignBottom)
             
        self.velGauge=QtPngDialGauge(self, "tacho3", "tacho31.png")
        self.velGauge.setMinimum(20)
        self.velGauge.setMaximum(220)
        self.velGauge.setStartAngle(135)
        self.velGauge.setValue(0)
#        self.velGauge.setMaximumSize(400, 400)
        velBox.addWidget(self.velGauge)

        self.createCANIdValueEntry(velBox, 0x351, "0", QLCDNumber.Dec)
        
        valuesBox = QVBoxLayout()
        valuesBox.setAlignment(Qt.AlignCenter|Qt.AlignBottom)

        dashTabLayout.addLayout(valuesBox)
        self.createCANIdValueEntry(valuesBox, 0x353, "1", QLCDNumber.Dec)
        self.createCANIdValueEntry(valuesBox, 0x351, "1", QLCDNumber.Dec)
        self.createCANIdValueEntry(valuesBox, 0x571, "0", QLCDNumber.Dec)
 
        rpmBox = QVBoxLayout()
        dashTabLayout.addLayout(rpmBox)
#        rpmBox.setAlignment(Qt.AlignCenter|Qt.AlignHCenter)
        self.rpmGauge=QtPngDialGauge(self, "rpm", "rpm1.png")
        self.rpmGauge.setMinimum(0)
        self.rpmGauge.setMaximum(8000)
        self.rpmGauge.setStartAngle(125)
        self.rpmGauge.setValue(2500)
#        self.rpmGauge.setMaximumSize(400, 400)
        rpmBox.addWidget(self.rpmGauge)     
         
        self.createCANIdValueEntry(rpmBox, 0x353, "0", QLCDNumber.Dec)
        
        self.gpsBox=GPSMonitor(self)
        gpsTabLayout.setAlignment(Qt.AlignLeft|Qt.AlignTop)
        self.gpsBox.loadConfig(self.config)

        self.gpsBox.addToWidget(gpsTabLayout)

        self.osmWidget=OSMWidget(self)
        osmTabLayout.setAlignment(Qt.AlignLeft|Qt.AlignTop)

        self.osmWidget.addToWidget(osmTabLayout)
        self.osmWidget.loadConfig(self.config)
        self.osmWidget.initWorkers()
                
        self.connect(self.osmWidget.mapWidgetQt, SIGNAL("updateStatus(QString)"), self.updateStatusBarLabel)
        self.connect(self.osmWidget.downloadThread, SIGNAL("updateStatus(QString)"), self.updateStatusBarLabel)
        self.connect(self.osmWidget, SIGNAL("updateStatus(QString)"), self.updateStatusBarLabel)
        self.connect(self.osmWidget, SIGNAL("startProgress()"), self.startProgress)
        self.connect(self.osmWidget, SIGNAL("stopProgress()"), self.stopProgress)

        self.osmWidget.initHome()
        
        connectBox=QHBoxLayout()
        top.addLayout(connectBox)
        
        section="connect"
        self.connectCANButton = QCheckBox('CAN Connect', self)
        self.connectCANButton.clicked.connect(self._connectCAN)
        self.connectCANEnable=self.config.getSection(section).getboolean("CANconnect", False)
        self.connectCANButton.setChecked(self.connectCANEnable)
        self.connectCANButton.setIcon(self.ampelRot)
        connectBox.addWidget(self.connectCANButton)

        self.connectGPSButton = QCheckBox('GPS Connect', self)
        self.connectGPSButton.clicked.connect(self._connectGPS)
        self.connectGPSEnable=self.config.getSection(section).getboolean("GPSconnect", False)
        self.connectGPSButton.setChecked(self.connectGPSEnable)
        self.connectGPSButton.setIcon(self.ampelRot)
        connectBox.addWidget(self.connectGPSButton)
        
        self.setGeometry(0, 0, 900, 600)
        self.setWindowTitle("candash")
        self.show()
        
        self.updateCANThread = CANSocketWorker(self)        
        self.connect(self.updateCANThread, SIGNAL("updateStatus(QString)"), self.updateStatusBarLabel)
        self.connect(self.updateCANThread, SIGNAL("updateCANThreadState(QString)"), self.updateCANThreadState)
        self.connect(self.updateCANThread, SIGNAL("clearAllLCD()"), self.clearAllLCD)
        self.connect(self.updateCANThread, SIGNAL("connectCANFailed()"), self.connectCANFailed)
        self.connect(self.updateCANThread, SIGNAL("replayModeDone()"), self.replayModeDone)
        self.connect(self.updateCANThread, SIGNAL("processCANData(PyQt_PyObject)"), self.canDecoder.scan_can_frame)
        self._connectCAN()
        
        self.updateGPSThread=getGPSUpdateThread(self)
        if self.updateGPSThread!=None:
            self.connect(self.updateGPSThread, SIGNAL("updateStatus(QString)"), self.updateStatusBarLabel)
            self.connect(self.updateGPSThread, SIGNAL("updateGPSThreadState(QString)"), self.updateGPSThreadState)
            self.connect(self.updateGPSThread, SIGNAL("connectGPSFailed()"), self.connectGPSFailed)
            self.connect(self.updateGPSThread, SIGNAL("updateGPSDisplay(PyQt_PyObject)"), self.updateGPSDisplay)
            self._connectGPS()

    #def mousePressEvent(self, event):
    #    print("CANMonitor mousePressEvent")
    #    self.tabs.mousePressEvent(event)

    def getWidget(self, canId, subId):
        try:
            return self.lcdDict[hex(canId)+":"+subId]
        except KeyError:
            return list()
    
    def setValueDashDisplayRPM(self, value):
        if value!=self.rpmGauge.value():
            self.rpmGauge.setValue(value)

    def setValueDashDisplayVel(self, value):
        if value!=self.velGauge.value():
            self.velGauge.setValue(value)
        
    def displayIntValue(self, canId, subId, value, formatString):
        lcdList=self.getWidget(canId, subId)
        for lcdItem in lcdList:
            if lcdItem.intValue()!=int(value):
                lcdItem.display(formatString % value)
                  
    def displayBinValue(self, canId, subId, value, formatString):
        lcdList=self.getWidget(canId, subId)
        for lcdItem in lcdList:
            if lcdItem.intValue()!=int(value):
                lcdItem.display(formatString % value)
                        
    def displayFloatValue(self, canId, subId, value, formatString):
        lcdList=self.getWidget(canId, subId)
        for lcdItem in lcdList:
            if lcdItem.value()!=value:
                lcdItem.display(formatString % value)
                                 
    def addToLogView(self, line):
        tableEntry=[self.logEntryCount, self.createTimeStamp()]
        tableEntry.extend(line[0:])
        
        if self.logFile!=None:
            self.addToLogFile(tableEntry)
            
        if self.logViewTableBox1.update==True:

            canId=line[0]
            if not self.logViewFilerBox1.matchFilter(canId, line, None):
                return
        
            self.logBuffer.appendleft(tableEntry)
            self.logEntryCount=self.logEntryCount+1
            if self.logEntryCount==self.maxLogEntryCount:
                self.logEntryCount=1
        
            self.tableUpdateCouter=self.tableUpdateCouter+1
            if self.tableUpdateCouter==10:
                self.logViewModel.update(self.logBuffer, None)
                self.tableUpdateCouter=0
                
    def addToLogView2(self, line):  
        if self.logViewTableBox2.update==True:
            canId=line[0]    
            if not canId in self.logBufferInit.keys():
                self.logBufferInit[canId]=line
                
            if not self.logViewFilterBox2.matchFilter(canId, line, self.logBufferInit[canId]):
                try:
                    del self.logBuffer2[canId]
                except KeyError:
                    None
            else:
                self.logBuffer2[canId]=line
        
                self.logViewModel2.update(list(self.logBuffer2.values()), self.logBufferInit)
                     
    def createTimeStamp(self):
        stamp=datetime.fromtimestamp(time.time())
        return "".join(["%02d:%02d:%02d.%06d"%(stamp.hour, stamp.minute, stamp.second, stamp.microsecond)])
    
    def dumpLogLine(self, line):
        logLine="%s %s %s"% (line[1], hex(line[2]), line[3])
        dataLine="".join(["0x%02X " % x for x in line[4]])
        return logLine+" "+dataLine   
         
    def addToLogFile(self, line):
        if self.logFile!=None:
            self.logFile.write(self.dumpLogLine(line)+"\n")
        
    def setupLogFile(self, filePath):
        if self.logFile==None:
            self.logFile=open(filePath,"a")
            self.logFile.write("# Log started: "+time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime())+"\n")
            self.logFile.write("# -------------------------------------------------------\n")

    def closeLogFile(self):
        if self.logFile!=None:
            self.logFile.write("# Log stoped: "+time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime())+"\n")
            self.logFile.write("# -------------------------------------------------------\n")
            self.logFile.close()
            self.logFile=None

    def logFileAvailable(self):
        try:
            open(self.logFileName, "r")
            return True
        except IOError:
            return False
    def readLogFile(self):
        try:
            logFileEntries=list()
            readLogFile=open(self.logFileName, "r")
            while True:
                line=readLogFile.readline()
                if not line:
                    break
                if line[0]=="#":
                    continue
                lineParts=line.split(" ")
                strippedLen=len(lineParts)-1
                neededLineParts=lineParts[1:strippedLen]
                addLen=8-len(neededLineParts[2:])
                for _ in range(addLen):
                    neededLineParts.append("%s" % "0x00")
                logFileEntries.append(struct.pack("IIBBBBBBBB", int(neededLineParts[0], 16), int(neededLineParts[1], 10), int(neededLineParts[2], 16),
                   int(neededLineParts[3], 16),int(neededLineParts[4], 16),int(neededLineParts[5], 16),int(neededLineParts[6], 16), 
                   int(neededLineParts[7], 16), int(neededLineParts[8], 16), int(neededLineParts[9], 16)))              
            return logFileEntries
        except IOError:
            return list()
                        
    @pyqtSlot()
    def _enableFilter(self):
        self.filter=self.filterButton.isChecked()
            
        self.filterEdit.setDisabled(self.filter==False)
        self.applyFilterButton.setDisabled(self.filter==False)
        self.filterAll.setDisabled(self.filter==False)
        self.filterKnown.setDisabled(self.filter==False)
        self.filterUnknown.setDisabled(self.filter==False)
        self.filterRingIdsButton.setDisabled(self.filter==False)

    @pyqtSlot()
    def _applyFilter(self):
        if self.filter==True:
            self.filterValue=self.filterEdit.text()
        else:
            self.filterValue=""

    @pyqtSlot()
    def _cleanup(self):
        self.osmWidget._cleanup()
        self.gpsBox._cleanup()

        if self.updateCANThread.isRunning():
            self.updateCANThread.stop()
        
        if self.updateGPSThread.isRunning():
            self.updateGPSThread.stop()
            
        self.closeLogFile()
        section="connect"
        self.config.removeSection(section)
        self.config.addSection(section)
        self.config.getSection(section)["canConnect"]=str(self.connectCANEnable)
        self.config.getSection(section)["gpsConnect"]=str(self.connectGPSEnable)
        
        self.osmWidget.saveConfig(self.config)
        self.gpsBox.saveConfig(self.config)

        self.config.writeConfig()
        self.log.writeLogtoFile()
        
    @pyqtSlot()
    def _enableLogFile(self):
        if self.logFileButton.isChecked()==True:
            if self.logFile==None:
                self.setupLogFile(self.logFileName)
        else:
            self.closeLogFile()
        self.replayButton.setDisabled(not self.logFileAvailable() or self.connectCANEnable==True)
        self.clearLogButton.setDisabled(not self.logFileAvailable() or self.replayMode==True)
        
    @pyqtSlot()
    def _startReplayMode(self):
        self.closeLogFile()
        self.logFileButton.setChecked(False)
        self.replayButton.setDisabled(True)
        self.replayMode=True
        
        self.stopReplayButton.setDisabled(self.replayMode==False)
        self.logFileButton.setDisabled(self.replayMode==True)
        self.clearLogButton.setDisabled(not self.logFileAvailable() or self.replayMode==True)
        
        replayLines=self.readLogFile()
        self.logViewTableBox1._clearTable()
        self.logViewTableBox2._clearTable()
        self.updateCANThread.setup(self.app, self, self.test, True, replayLines)
            
    @pyqtSlot()
    def _stopReplayMode(self):
        self.updateCANThread.stop()
        self.replayModeDone()

    def replayModeDone(self):
        self.replayMode=False
        self.stopReplayButton.setDisabled(self.replayMode==False)
        self.replayButton.setDisabled(not self.logFileAvailable() or self.connectCANEnable==True)
        self.logFileButton.setDisabled(self.replayMode==True)
        self.clearLogButton.setDisabled(not self.logFileAvailable() or self.replayMode==True)
        
    @pyqtSlot()
    def _clearLogFile(self):
        if self.logFileAvailable():                        
            self.closeLogFile()
            os.remove(self.logFileName)
            self.logFile=None
        self._enableLogFile()
    
    @pyqtSlot()
    def _connectCAN(self):
        self.connectCANEnable=self.connectCANButton.isChecked()
        if self.replayMode==True:
            self._stopReplayMode()
            
        if self.connectCANEnable==True:
#            self.connectCANButton.setDisabled(True)
            self.logViewTableBox1._clearTable()
            self.logViewTableBox2._clearTable()
            self.updateCANThread.setup(self.app, self.connectCANEnable, self.test, False, None)

        else:
            if self.updateCANThread.isRunning():
#                self.connectCANButton.setDisabled(True)
                self.updateCANThread.stop()
            
        self.replayButton.setDisabled(not self.logFileAvailable() or self.connectCANEnable==True)
        self.connectCANButton.setChecked(self.connectCANEnable==True)
                
    @pyqtSlot()
    def _connectGPS(self):
        self.connectGPSEnable=self.connectGPSButton.isChecked()
        if self.connectGPSEnable==True:
#            self.connectGPSButton.setDisabled(True)
            self.updateGPSThread.setup(self.connectGPSEnable)
        else:
            if self.updateGPSThread.isRunning():
#                self.connectGPSButton.setDisabled(True)
                self.updateGPSThread.stop()

        self.connectGPSButton.setChecked(self.connectGPSEnable==True)
        
    @pyqtSlot()
    def _enableFilterRingIds(self):
        self.filterRingIds=self.filterRingIdsButton.isChecked()
    
    def connectCANEnabled(self):
        return self.connectCANEnable
         
    def connectCANFailed(self):
        self.connectCANEnable=False
        self.connectCANButton.setChecked(False)
#        self.connectCANButton.setDisabled(False)
        self.connectCANButton.setIcon(self.ampelRot)

    def updateStatusBarLabel(self, text):
        self.statusbar.showMessage(text)
        logLine=self.log.addLineToLog(text)
        self.debugLogWidget.addLineToLog(logLine)
        
    def stopProgress(self):
        self.progress.setMinimum(0)
        self.progress.setMaximum(1)
        self.progress.reset()
    
    def startProgress(self):
        self.progress.setMinimum(0)
        self.progress.setMaximum(0)

#    def connectCANSuccessful(self):
#        self.connectCANEnable=True
##        self.connectCANButton.setChecked(True)
##        self.connectCANButton.setDisabled(False)
#        self.connectCANButton.setIcon(self.ampelGruen)

#    def stopCANSuccesful(self):
#        self.connectCANButton.setDisabled(False)
#        self.connectCANButton.setIcon(self.ampelRot)

    def canIdIsInKnownList(self, canId):
        return canId in self.canIdList

    def updateGPSDisplay(self, gpsData):
        self.gpsBox.update(gpsData)

    def showError(self, title, text):
        msgBox=QMessageBox(QMessageBox.Warning, title, text, QMessageBox.Ok, self)
        font = self.font()
        font.setPointSize(14)
        msgBox.setFont(font)
        msgBox.exec()
        
    def connectGPSFailed(self):
        self.connectGPSButton.setChecked(False)
        self.connectGPSEnable=False
#        self.connectGPSButton.setDisabled(False)
        self.connectGPSButton.setIcon(self.ampelRot)
        self.showError("GPS Error", "Error connecing to GPS")

#    def connectGPSSuccesful(self):
##        self.connectGPSButton.setChecked(True)
#        self.connectGPSEnable=True
##        self.connectGPSButton.setDisabled(False)
#        self.connectGPSButton.setIcon(self.ampelGruen)
        
    def connectGPSEnabled(self):
        return self.connectGPSEnable
    
#    def stopGPSSuccesful(self):
#        self.connectGPSButton.setDisabled(False)
#        self.connectGPSButton.setIcon(self.ampelRot)

    def updateCANThreadState(self, state):
        if state!=self.lastCANState:
            if state==canIdleState:
                self.connectCANButton.setIcon(self.ampelGelb)
            elif state==canRunState:
                self.connectCANButton.setIcon(self.ampelGruen)
            elif state==canStoppedState:
                self.connectCANButton.setIcon(self.ampelRot)
                self.connectCANEnable=False
            self.lastCANState=state
            
    def updateGPSThreadState(self, state):
        if state!=self.lastGPSState:
            if state==gpsRunState:
                self.connectGPSButton.setIcon(self.ampelGruen)
            elif state==gpsStoppedState:
                self.connectGPSButton.setIcon(self.ampelRot)
                self.connectGPSnable=False
            self.lastGPSState=state

    def hasOSMWidget(self):
        return self.osmWidget!=None
Example #10
0
class HomeWidget(BaseWidget):

    def __init__(self, parent=0, *args, **kwargs):
        super(HomeWidget, self).__init__(parent=parent, *args, **kwargs)

        # inputs
        self._json_fpath = None
        self._destination_folder = self.guess_destination()
        self._from_date, self._to_date = self.guess_dates()
        self.nb_instances = 0

        self.setup_ui()

    @property
    def json_fpath(self):
        return self._json_fpath

    @json_fpath.setter
    def json_fpath(self, value):
        self._json_fpath = value
        self.json_select_button.setText(
            value if value else "Sélection fichier JSON ODK Aggregate ...")
        self.update_start_button_state()

    @property
    def destination_folder(self):
        return self._destination_folder

    @destination_folder.setter
    def destination_folder(self, value):
        self._destination_folder = value
        self.destination_select_button.setText(self.destination_folder)
        self.update_start_button_state()

    @property
    def from_date(self):
        return self._from_date

    @from_date.setter
    def from_date(self, value):
        self._from_date = value
        self.from_date_selector.setPythonDate(self.from_date)
        self.update_start_button_state()

    @property
    def to_date(self):
        return self._to_date

    @to_date.setter
    def to_date(self, value):
        self._to_date = value
        self.to_date_selector.setPythonDate(self.to_date)
        self.update_start_button_state()

    def setup_ui(self):
        # json file selector
        self.json_groupbox = QGroupBox("Export ODK Aggregate")
        layout = QGridLayout()
        self.json_select_button = PushButton("", self)
        self.json_select_button.clicked.connect(self.json_selector_clicked)
        layout.addWidget(self.json_select_button, 1, 0)
        self.json_groupbox.setLayout(layout)

        # destination folder selector
        self.destination_groupbox = QGroupBox("Destination")
        layout = QGridLayout()
        self.destination_select_button = PushButton(
            self.destination_folder, self)
        self.destination_select_button.clicked.connect(
            self.destination_selector_clicked)
        layout.addWidget(self.destination_select_button, 1, 0)
        self.destination_groupbox.setLayout(layout)

        # period calendars
        today = datetime.date.today()
        self.period_groupbox = QGroupBox("Période")
        layout = QGridLayout()
        self.from_date_selector = DateTimeEdit(QDate(self.from_date))
        self.from_date_selector.dateChanged.connect(self.from_date_changed)
        self.from_date_selector.setMaximumDate(self.to_date)
        self.to_date_selector = DateTimeEdit(QDate(self.to_date))
        self.to_date_selector.dateChanged.connect(self.to_date_changed)
        self.to_date_selector.setMinimumDate(self.from_date)
        self.to_date_selector.setMaximumDate(today)
        layout.addWidget(Label("Du"), 2, 0)
        layout.addWidget(self.from_date_selector, 3, 0)
        layout.addWidget(Label("Au"), 2, 1)
        layout.addWidget(self.to_date_selector, 3, 1)
        self.period_groupbox.setLayout(layout)

        # start button
        self.start_button = PushButton("Démarrer")
        self.start_button.setEnabled(False)
        self.start_button.setDefault(True)
        self.start_button.clicked.connect(self.export_requested)

        # cancel button
        self.cancel_button = CancelPushButton("Annuler")
        self.cancel_button.setEnabled(False)
        self.cancel_button.clicked.connect(self.cancel_export)

        # grid
        self.gridBox = QGridLayout()
        self.gridBox.addWidget(self.json_groupbox, 0, 0, 1, 2)
        self.gridBox.addWidget(self.destination_groupbox, 1, 0, 1, 2)
        self.gridBox.addWidget(self.period_groupbox, 2, 0, 1, 2)
        self.gridBox.addWidget(self.start_button, 3, 0)
        self.gridBox.addWidget(self.cancel_button, 3, 1)

        vBox = QVBoxLayout()
        vBox.addLayout(self.gridBox)
        self.setLayout(vBox)

        self.json_fpath = None

    def guess_destination(self, root_only=False):
        start_folder = os.path.join(os.path.expanduser("~"), 'Desktop')
        if root_only:
            return start_folder
        return os.path.join(start_folder, Constants.DEFAULT_FOLDER_NAME)

    def guess_dates(self):
        to = datetime.date.today()
        start = to - datetime.timedelta(days=15)
        return start, to

    def update_start_button_state(self):
        self.start_button.setEnabled(
            all([self.json_fpath, self.destination_folder,
                 self.from_date, self.to_date]))

    def json_selector_clicked(self):
        # self.file_name_field.setText("Aucun fichier")
        self.start_button.setEnabled(False)
        fpath = QFileDialog.getOpenFileName(
            self, "Choisir le fichier d'export JSON",
            self.json_fpath or self.guess_destination(root_only=True),
            "Fichiers JSON (*.json)")
        self.json_fpath = os.path.abspath(fpath) if fpath else self.json_fpath

    def destination_selector_clicked(self):
        path = QFileDialog.getExistingDirectory(
            self, "Sélectionner le dossier", self.destination_folder)
        if path:
            self.destination_folder = os.path.abspath(path)

    def from_date_changed(self, new_date):
        self.from_date = new_date.toPyDate()

    def to_date_changed(self, new_date):
        self.to_date = new_date.toPyDate()

    def export_requested(self):
        logger.debug("export_requested")
        self.parentWidget().exporter.check_aggregate_presence()

    def display_missing_aggregate_confirmation(self):
        if MissingODKConfirmationWidget().exec_() == QDialog.Accepted:
            self.start_export()

    def start_export(self):
        logger.debug("Lancement ...")
        self.add_progressbar()
        self.start_button.setEnabled(False)
        self.cancel_button.setEnabled(True)
        self.parentWidget().exporter.parse(
            destination_folder=self.destination_folder,
            fname=self.json_fpath,
            from_date=self.from_date,
            to_date=self.to_date)

    def cancel_export(self):
        logger.debug("cancel")
        self.parentWidget().exporter.cancel()

    def update_progress_label(self, index):
        progression_label = "Export en cours...    {index}/{total}" \
                            .format(index=index,
                                    total=self.nb_instances)
        self.progression_groupbox.setTitle(progression_label)

    def add_progressbar(self):
        self.progressbar = QProgressBar()
        self.progressbar.setMinimum(0)
        self.progressbar.setMaximum(100)
        self.progressbar.reset()
        self.progressbar.setTextVisible(False)

        self.progression_groupbox = QGroupBox("...")
        progress_layout = QHBoxLayout()
        progress_layout.addWidget(self.progressbar)
        self.progression_groupbox.setLayout(progress_layout)
        self.gridBox.addWidget(self.progression_groupbox, 4, 0, 1, 2)

    def remove_progressbar(self):
        self.progression_groupbox.deleteLater()
        self.progression_groupbox = None

    @pyqtSlot(bool, int, str)
    def parsing_ended(self, succeeded, nb_instances, error_message):
        if succeeded:
            self.nb_instances = nb_instances

    @pyqtSlot(str, int)
    def exporting_instance(self, ident, index):
        logger.debug("exporting_instance")
        self.update_progress_label(index)

    @pyqtSlot(bool, int)
    def instance_completed(self, succeeded, index):
        logger.debug("instance_completed")
        pc = index * 100 // self.nb_instances
        self.progressbar.setValue(pc)

    @pyqtSlot(int, int, int, int)
    def export_ended(self, nb_instances_successful, nb_instances_failed,
                     nb_medias_successful, nb_medias_failed):
        self.cancel_button.setEnabled(False)
        self.start_button.setEnabled(True)

    @pyqtSlot()
    def export_canceled(self):
        self.remove_progressbar()
        self.cancel_button.setEnabled(False)
        self.start_button.setEnabled(True)
        QMessageBox.warning(self,
                            "Export annulé !",
                            "L'export en cours a été annulé.\n"
                            "Tous les fichiers créés ont été supprimés",
                            QMessageBox.Ok,
                            QMessageBox.NoButton)
        if self.parentWidget().is_exiting:
            self.parentWidget().do_close()
Example #11
0
class FileItem(QTreeWidgetItem):

    cols = ['Filepath', 'Renamed Filepath']

    invalid_char_map = {':': ''}

    re_filename_episodes = [
        re.compile(r'.*[Ss](?P<season>\d{1,2})[\s\-_]*[Ee](?P<episode>\d{1,2}).*', re.I),
        re.compile(r'.*season\s*(?P<season>\d{1,2})[\s\-_]*episode\s*[Ee](?P<episode>\d{1,2}).*', re.I),
    ]

    re_filepath_episodes = [
        re.compile(r'.*season\s*(?P<season>\d{1,2})\\(?:season\s*\d{1,2}[\s\-_]*)?(?:episode|ep\.?|e)\s*(?P<episode>\d{1,2}).*', re.I),
    ]

    def __init__(self, parent, filepath, mediaman):
        super(FileItem, self).__init__(parent)
        self._renamed = False
        self.mediaman = mediaman
        self.filepath = filepath
        self.renamed_filepath = None
        self.media_info = None
        self.episode_info = None
        self.thread = None
        self.pbar = None
        self.setText(0, self.filepath)
        self.send_thread()

    def send_thread(self):
        if self.thread is None:
            self.thread = FilepathSearchThread(self.treeWidget())
            self.thread.finished.connect(self.receive_thread)
        thread_ready = self.thread.wait(10000)
        if thread_ready:
            tree = self.treeWidget()
            self.pbar = QProgressBar(tree)
            self.pbar.setRange(0, 0)
            tree.setItemWidget(self, 1, self.pbar)
            self.thread.filepath = self.filepath
            self.thread.start()

    def receive_thread(self):
        self.media_info = self.thread.result
        self.pbar.reset()
        tree = self.treeWidget()
        tree.removeItemWidget(self, 1)
        self.pbar.deleteLater()
        self.refresh()


    def _replace_invalid_chars(self, text):
        for k, v in FileItem.invalid_char_map.items():
            if k in text:
                text = text.replace(k, v)
        return text

    def refresh(self):
        moviedir = self.mediaman.moviedir()
        tvdir = self.mediaman.tvdir()

        if self.media_info:
            title = self.media_info.get('title')
            title = self._replace_invalid_chars(title)
            year = self.media_info.get('year')

            filename, ext = os.path.splitext(os.path.basename(self.filepath))

            if self.episode_info or self.media_info.get('episodes'):
                if not self.episode_info:
                    episodes = self.media_info['episodes']
                    ep_match = None
                    for reg in FileItem.re_filename_episodes:
                        m = reg.search(filename)
                        if m:
                            ep_match = m.groupdict()
                            break
                    if not ep_match:
                        for reg in FileItem.re_filepath_episodes:
                            m = reg.search(self.filepath)
                            if m:
                                ep_match = m.groupdict()

                    if ep_match:
                        season, episode = int(ep_match['season']), int(ep_match['episode'])
                        for episode_info in episodes:
                            if (episode_info['season'], episode_info['episode']) == (season, episode):
                                self.episode_info = episode_info
                                break

                if self.episode_info:
                    self.renamed_filepath = ur'{tvdir}\{title}\Season{season:02d}\{title}.S{season:02d}E{episode:02d}.{episode_title}{ext}'.format(
                        tvdir=tvdir,
                        title=title,
                        year=year,
                        season=self.episode_info['season']  ,
                        episode=self.episode_info['episode'],
                        episode_title=self._replace_invalid_chars(self.episode_info['title']),
                        ext=ext,
                    )
                else:
                    self.renamed_filepath = ur'{tvdir}\{title}\Season00\{title}.S00E00.XXX{ext}'.format(
                        tvdir=tvdir,
                        title=title,
                        year=year,
                        ext=ext,
                    )


            else:
                self.renamed_filepath = ur'{moviedir}\{title} ({year})\{title}{ext}'.format(
                    moviedir=moviedir,
                    title=title,
                    year=year,
                    ext=ext
                )


            self.setText(1, self.renamed_filepath)
            if os.path.exists(self.renamed_filepath):
                self.setBackgroundColor(FileItem.cols.index('Renamed Filepath'), QColor(0, 255, 0, 100))