예제 #1
0
class VNCClient(QObject):
    started = pyqtSignal()
    finished = pyqtSignal()
    imageSizeChanged = pyqtSignal(QSize)
    imageChanged = pyqtSignal(int, int, int, int)
    passwordRequested = pyqtSignal(bool)
    textCut = pyqtSignal(unicode)

    def __init__(self, host, port, settings, parent=None):
        super(VNCClient, self).__init__(parent)
        self.thread = QThread()
        self.moveToThread(self.thread)
        self.host = host
        self.port = port
        self.settings = settings
        self.username = None
        self.password = None
        self.rfb_client = None
        self.socket_notifier = None
        self.thread.started.connect(self._SH_ThreadStarted)
        self.thread.finished.connect(self._SH_ThreadFinished)

    def _get_settings(self):
        return self.__dict__['settings']

    def _set_settings(self, settings):
        old_settings = self.__dict__.get('settings', None)
        if settings == old_settings:
            return
        self.__dict__['settings'] = settings
        if self.thread.isRunning():
            QApplication.postEvent(self, RFBConfigureClientEvent())

    settings = property(_get_settings, _set_settings)
    del _get_settings, _set_settings

    @property
    def image(self):
        return self.rfb_client.image if self.rfb_client is not None else None

    def start(self):
        self.thread.start()

    def stop(self):
        self.thread.quit()

    def key_event(self, key, down):
        if self.thread.isRunning():
            QApplication.postEvent(self, RFBKeyEvent(key, down))

    def mouse_event(self, x, y, button_mask):
        if self.thread.isRunning():
            QApplication.postEvent(self, RFBMouseEvent(x, y, button_mask))

    def cut_text_event(self, text):
        if text and self.thread.isRunning():
            QApplication.postEvent(self, RFBCutTextEvent(text))

    def _SH_ThreadStarted(self):
        self.started.emit()
        notification_center = NotificationCenter()
        notification_center.post_notification('VNCClientWillStart', sender=self)
        self.rfb_client = RFBClient(parent=self)
        try:
            self.rfb_client.connect()
        except RFBClientError:
            self.thread.quit()
        else:
            self.socket_notifier = QSocketNotifier(self.rfb_client.socket, QSocketNotifier.Read, self)
            self.socket_notifier.activated.connect(self._SH_SocketNotifierActivated)
            notification_center.post_notification('VNCClientDidStart', sender=self)

    def _SH_ThreadFinished(self):
        self.finished.emit()
        notification_center = NotificationCenter()
        notification_center.post_notification('VNCClientWillEnd', sender=self)
        if self.socket_notifier is not None:
            self.socket_notifier.activated.disconnect(self._SH_SocketNotifierActivated)
            self.socket_notifier = None
        self.rfb_client = None
        notification_center.post_notification('VNCClientDidEnd', sender=self)

    def _SH_SocketNotifierActivated(self, sock):
        self.socket_notifier.setEnabled(False)
        try:
            self.rfb_client.handle_server_message()
        except RFBClientError:
            self.thread.quit()
        else:
            self.socket_notifier.setEnabled(True)

    def _SH_ConfigureRFBClient(self):
        if self.rfb_client is not None:
            self.rfb_client.configure()

    def customEvent(self, event):
        handler = getattr(self, '_EH_%s' % event.name, Null)
        handler(event)

    def _EH_RFBConfigureClientEvent(self, event):
        if self.rfb_client is not None:
            self.rfb_client.configure()

    def _EH_RFBKeyEvent(self, event):
        if self.rfb_client is not None:
            self.rfb_client.send_key_event(event.key, event.down)

    def _EH_RFBMouseEvent(self, event):
        if self.rfb_client is not None:
            self.rfb_client.send_pointer_event(event.x, event.y, event.button_mask)

    def _EH_RFBCutTextEvent(self, event):
        if self.rfb_client is not None:
            self.rfb_client.send_client_cut_text(event.text)
예제 #2
0
class MQTTClient(QtCore.QObject):
    """
    Wrapper class for Mosquitto MQTT client
    Provides inherited helper classes for SingleShot and Test requests
    Initial approach was to sub class QThread, but reading revealed that
    running the timers within a thread was the preferred approach.
    
    
    """

    kMaxAttempts = 3
    kMinKeepAlive = 5
    kResetTimer = 60

    mqttOnConnect = pyqtSignal(QObject, QObject, int)
    mqttOnDisConnect = pyqtSignal(QObject, QObject, int)
    mqttOnMessage = pyqtSignal(QObject, QObject, QObject)
    mqttOnPublish = pyqtSignal(QObject, QObject, int)
    mqttOnSubscribe = pyqtSignal(QObject, QObject, int, int)
    mqttOnLog = pyqtSignal(str, int)
    mqttOnTimeout = pyqtSignal(QObject)
    mqttConnectionError = pyqtSignal(QObject, str)

    # Hmmm new style signals cause problems with multiple parameters
    #    mqttConnectionError =  QtCore.pyqtSignal([str])

    # Add username/password
    def __init__(self, creator, clientId, broker, cleanSession=True):

        super(MQTTClient, self).__init__()
        # Load settings
        self._creator = creator

        # create client id
        self._cleanSession = cleanSession
        self._resetTimer = QTimer()
        self._resetTimer.setSingleShot(True)
        self._resetTimer.timeout.connect(self._reset)

        self._killTimer = QTimer()
        self._killTimer.setSingleShot(True)
        self._killTimer.timeout.connect(self._kill)
        self._killing = False

        self._loopTimer = QTimer()
        self._loopTimer.setSingleShot(False)
        self._loopTimer.timeout.connect(self._loop)
        self._clientId = clientId
        self._host = broker.host()
        self._port = int(broker.port())
        self._poll = int(broker.poll())
        self.setKeepAlive(broker.keepAlive())
        self._attempts = 0
        self._attempted = 0
        self._connected = False
        self._thread = QThread(self)
        self._thread.started.connect(lambda: self._loopTimer.start(self._poll))
        self._thread.finished.connect(self._loopTimer.stop)

        self._thread.started.connect(lambda: Log.debug("Thread started"))
        self._thread.finished.connect(lambda: Log.debug("Thread stopped"))
        self._thread.terminated.connect(lambda: Log.debug("Thread terminated"))
        self._restarting = False
        self._subscribed = []

        #        self.mqttc = mqtt.Client(self._clientId, self._cleanSession)
        self.mqttc = mqtt.Mosquitto(self._clientId, self._cleanSession)

        if broker.username():  # Basic Auth!
            self.mqttc.username_pw_set(broker.username(), broker.password())

        self.mqttc.on_connect = self.on_connect
        self.mqttc.on_disconnect = self.on_disconnect
        self.mqttc.on_message = self.onMessage
        self.mqttc.on_publish = self.onPublish
        self.mqttc.on_subscribe = self.onSubscribe
        #        self.mqttc.on_unsubscribe = self.onSubscribe - not implemented - remove element from self._subscribed
        self.mqttc.on_log = self.onLog

    def _canRun(self):
        return True

    def run(self):
        Log.debug("MQTT client run")

        if self.isRunning() or self._killing:
            self.restart()
            return

        if self._restarting:
            self._thread.finished.disconnect(self.run)
            self._restarting = False

        self._thread.start(QThread.LowestPriority)

    def stop(self):
        self._thread.quit()  # emits finished
        Log.debug("Thread quit")

    def isRunning(self):
        return self._thread.isRunning()

    def _loop(self):
        if self._canRun():
            self.loop()

    def setHost(self, host):
        self._host = host

    def host(self):
        return self._host

    def setPort(self, port):
        self._port = int(port)

    def port(self):
        return self._port

    def setPoll(self, poll):
        self._poll = int(poll)

    def setKeepAlive(self, keepAlive):
        self._keepAlive = max(
            int(keepAlive) + int(self._poll), self.kMinKeepAlive)

    def getClientId(self):
        return self._clientId

    def on_connect(self, client, obj, flags, rc):  # paho
        #    def on_connect(self, client, obj, rc): # mosquitto
        Log.debug("Connected " + str(rc))
        if rc != mqtt.MQTT_ERR_SUCCESS:  # paho
            #        if rc != mqtt.MOSQ_ERR_SUCCESS: # mosquitto
            return
        self._connected = True
        self._attempts = 0
        self._subscribed = []

        self.onConnect(client, obj, rc)

    def restart(self):

        Log.debug("Restarting")
        if self.isRunning():
            self._restarting = True
            self._thread.finished.connect(self.run)
            if not self._killing:
                self.kill()
        else:
            self.run()

    def on_disconnect(self, client, obj, rc):
        Log.debug("disconnecting rc: " + str(rc) + " " + str(self._connected))
        if self._killing:
            Log.debug("killing")
            self._kill()
        self.onDisConnect(client, obj, rc)
        self._connected = False

    def onConnect(self, client, obj, rc):
        self.mqttOnConnect.emit(self, obj, rc)
        #        QObject.emit(self, SIGNAL('mqttOnConnect'), self, obj, rc)
        pass

    def onDisConnect(self, client, obj, rc):
        self.mqttOnDisConnect.emit(self, obj, rc)
        #        QObject.emit(self, SIGNAL('mqttOnDisConnect'), self, obj, rc)
        pass

    def onMessage(self, client, obj, msg):
        self.mqttOnMessage.emit(self, obj, msg)
#        QObject.emit(self, SIGNAL('mqttOnMessage'), self, obj, msg)
# Log.debug('super ' + msg.topic+" "+str(msg.qos)+" "+str(msg.payload))

    def onPublish(self, client, obj, mid):
        self.mqttOnPublish.emit(self, obj, mid)
        # QObject.emit(self._creator, SIGNAL('mqttOnPublish'), self, obj, mid)
        Log.debug("onPublish - Message ID: " + str(mid))

    def onSubscribe(self, client, obj, mid, granted_qos):
        self.mqttOnSubscribe.emit(self, obj, mid, granted_qos)
        Log.info("Subscribed: " + str(mid) + " " + str(granted_qos))

    def onLog(self, client, obj, level, msg):
        self.mqttOnLog.emit(msg, level)
        #Log.debug(string,level)

    def isConnected(self):
        return self.mqttc.socket() is not None and self._connected

    def publish(self, topic, payload, qos=0, retain=True):
        self.mqttc.publish(str(topic), payload, int(qos), retain)

    def subscribe(self, topic, qos=0):
        if self.isConnected() and not str(topic) in self._subscribed:
            try:
                self.mqttc.subscribe(str(topic), int(qos))
                self._subscribed.append(str(topic))
                Log.debug('Subscribed to ' + topic + " " + str(qos))
            except Exception as e:
                Log.debug("Error on subscribe " + str(e))
                raise e

    def unsubscribe(self, topic):
        if self.isConnected():
            self.mqttc.unsubscribe(topic)
            Log.debug('Un_subscribed to ' + topic)

    def loop(self, timeout=0.1):
        if not self.isConnected():
            if not self._killing:
                self._connect()
            return
        try:
            connResult = self.mqttc.loop(timeout)
            if connResult == mqtt.MQTT_ERR_SUCCESS:  # paho
                #            if connResult == mqtt.MOSQ_ERR_SUCCESS: # mosquitto
                return

            self._connected = False
            self._attempts += 1

            Log.warn("MQTT: An error occurred while looping")
            self.mqttConnectionError.emit(self, mqtt.error_string(connResult))
        except ValueError as e:
            if e == 'Invalid timeout.':
                self.mqttOnTimeout.emit(self, "Connection Timeout")
            else:
                Log.debug("Paho Client ValueError" + str(e))
        except Exception as e:
            self.mqttConnectionError.emit(self, str(e))
            Log.debug("MQTT Connect: Unknown exception raised " + str(e))
            exc_type, exc_value, exc_traceback = sys.exc_info()
            Log.debug(
                repr(
                    traceback.format_exception(exc_type, exc_value,
                                               exc_traceback)))

    def _kill(self):
        self._loopTimer.stop(
        )  # Stopped in self.stop but lets preempt this to avoid self.loop being called by running thread
        self._killTimer.stop()
        self._killing = False
        self._reset()  # reset timer
        self.stop()

    def kill(self):
        try:
            if self.isConnected():
                self._disconnect()
            self._killing = True
            self._killTimer.start(self._keepAlive)
        except Exception as e:
            Log.warn("Error cleaning up " + str(e))
        pass

    def _connect(self):
        try:
            if not self._connected:
                if not self._attempts < self.kMaxAttempts:
                    if not self._resetTimer.isActive():
                        Log.progress(
                            Settings.getMeta("name") +
                            ": Max connection attempts reached - waiting " +
                            str(self.kResetTimer) + " seconds before retrying")
                        self._resetTimer.start(self.kResetTimer *
                                               1000)  # 1 minute parameterise
                    return
                if self._attempts > 0 and (time.time() - pow(
                        2, self._attempts + 1)) < self._attemped:
                    return
                Log.debug("Trying to connect")
                self._attemped = time.time()
                result = self.mqttc.connect(str(self._host), int(self._port),
                                            int(self._keepAlive), 1)
                self._connected = result == mqtt.MQTT_ERR_SUCCESS  # paho
                #                self._connected = result == mqtt.MOSQ_ERR_SUCCESS # mosquitto
                if not self._connected:
                    self._attempts += 1
                    Log.progress(mqtt.connack_string(connResult))
                    self.mqttConnectionError.emit(
                        self, mqtt.connack_string(connResult))

        except Exception as e:
            msg = 'MQTT: ' + str(e)

            self.mqttConnectionError.emit(self, msg)
            #Log.progress(msg)
            Log.debug(msg)
            #exc_type, exc_value, exc_traceback = sys.exc_info()
            #Log.debug(repr(traceback.format_exception(exc_type, exc_value,
            #                                         exc_traceback)))
            self._attempts += 1
            self._connected = False

    def _disconnect(self):
        try:
            self.mqttc.disconnect()
        except Exception as e:
            Log.warn('MQTT Disconnection Error' + str(e))

    def _reset(self):
        Log.warn("Timer reset ")
        self._attempts = 0
        self._resetTimer.stop()  # not required
예제 #3
0
class DataViewerBase(QMainWindow):
    """
    Base GUI class for viewing data / images.
    This class was made in the purpose of viewing VMI images.
    """

    # _name = DataViewerBase().__class__.__name__

    def __init__(self, filepath=""):
        """
        Initialization.
        """
        super().__init__()
        self.initInnerParameters(filepath)
        self.initGui()
        self.initGetDataProcess()
        self.initUpdateImageProcess()
        self.initCheckWindowProcess()

    @footprint
    def initInnerParameters(self, filepath):
        """
        Initialize the inner parameters.
        """
        self._mutex = QMutex()
        self._windows = []
        self.initData()
        self._isUpdatingImage = False
        self._font_size_button = 16  # [pixel]
        self._font_size_groupbox_title = 12  # [pixel]
        self._font_size_label = 11  # [pixel]
        self._font_bold_label = True
        self._init_window_width = 1600  # [pixel]
        self._init_window_height = 700  # [pixel]
        self._init_button_color = "#EBF5FB"
        self.main_bgcolor = "#FDF2E9"

        self._get_data_interval = 1  # [sec]
        self._get_data_worker_sleep_interval = self._get_data_interval - 0.1  # [sec]
        self._update_image_interval = 2  # [sec]
        self._get_update_delay = 1  # [sec]
        self._check_window_interval = 1  # [sec]

        self._currentDir = os.path.dirname(__file__)
        self._online = False
        self._closing_dialog = True

        if os.path.exists(
                os.path.join(os.path.dirname(__file__), "config.json")):
            self.loadConfig()
        if not os.path.exists(
                os.path.join(os.path.dirname(__file__),
                             "config_getdata.json")):
            raise FileNotFoundError("config_getdata.json")
        self.loadConfigGetData()

    @footprint
    @pyqtSlot()
    def initData(self):
        """
        Initialize inner data.
        """
        self.dataset = {
            "sig_wl": None,
            "sig_wol": None,
            "bg_wl": None,
            "bg_wol": None
        }
        self.nbr_of_sig = 0
        self.nbr_of_bg = 0
        self.sig = None
        self.bg = None
        self.currentRun = -1
        self.startTag = -1
        self.endTag = -1

    @footprint
    def loadConfig(self):
        """
        Load a config file.
        """
        with open(os.path.join(os.path.dirname(__file__), "config.json"),
                  'r') as ff:
            config = json.load(ff)
        if config.get("currentDir") is not None:
            if isinstance(config.get("currentDir"), str):
                if os.path.exists(config.get("currentDir")):
                    self._currentDir = config["currentDir"]
        if config.get("online") is not None:
            if isinstance(config.get("online"), bool):
                self._online = config["online"]
        if config.get("closing_dialog") is not None:
            if isinstance(config.get("closing_dialog"), bool):
                self._closing_dialog = config["closing_dialog"]
        if config.get("emulate") is not None:
            if isinstance(config.get("emulate"), bool):
                self._emulate = config["emulate"]
        if config.get("font_size_button") is not None:
            if isinstance(config.get("font_size_button"), int):
                self._font_size_button = config["font_size_button"]
        if config.get("font_size_groupbox_title") is not None:
            if isinstance(config.get("font_size_groupbox_title"), int):
                self._font_size_groupbox_title = config[
                    "font_size_groupbox_title"]
        if config.get("font_size_label") is not None:
            if isinstance(config.get("font_size_label"), int):
                self._font_size_label = config["font_size_label"]
        if config.get("font_bold_label") is not None:
            if isinstance(config.get("font_bold_label"), bool):
                self._font_bold_label = config["font_bold_label"]
        self._config = config

    def loadConfigGetData(self):
        """
        Load a config file of getDatawithOLPY.
        """
        with open(
                os.path.join(os.path.dirname(__file__), "config_getdata.json"),
                'r') as ff:
            config_get_data = json.load(ff)
        self._get_data_interval = config_get_data["interval"]  # [sec]
        self._get_data_worker_sleep_interval = self._get_data_interval - 0.1  # [sec]
        self._get_data_ports = config_get_data["port"]
        self._get_info_port = config_get_data["port_info"]
        self._config_get_data = config_get_data

    @footprint
    def initGui(self):
        """
        Initialize the GUI.
        """
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.initMainWidget()
        self.setMenuBar()

        self.setWindowTitle("VMI Viewer")
        self.resize(self._init_window_width, self._init_window_height)

        ### RunInfo.
        group_runinfo = QGroupBox(self)
        group_runinfo.setTitle("RunInfo")
        font = group_runinfo.font()
        font.setPointSize(self._font_size_groupbox_title)
        group_runinfo.setFont(font)
        group_runinfo.resize(400, 100)
        grid_runinfo = QGridLayout(group_runinfo)

        # Run No.
        label_run = QLabel(self)
        label_run.setText("Run No. : ")
        label_run.setAlignment(Qt.AlignRight)
        font = label_run.font()
        font.setPointSize(self._font_size_label)
        font.setBold(self._font_bold_label)
        label_run.setFont(font)

        self.label_run_number = QLabel(self)
        self.label_run_number.setText("Unknown")
        pal = QPalette()
        pal.setColor(QPalette.Foreground, QColor("#0B5345"))
        self.label_run_number.setPalette(pal)
        font = self.label_run_number.font()
        font.setBold(True)
        font.setPointSize(self._font_size_label)
        self.label_run_number.setFont(font)

        # Tag No.
        label_tag = QLabel(self)
        label_tag.setText("Tag No. : ")
        label_tag.setAlignment(Qt.AlignRight)
        font = label_tag.font()
        font.setPointSize(self._font_size_label)
        font.setBold(self._font_bold_label)
        label_tag.setFont(font)

        self.label_tag_start = QLabel(self)
        self.label_tag_start.setText("None")
        font = self.label_tag_start.font()
        font.setBold(True)
        font.setPointSize(self._font_size_label)
        self.label_tag_start.setFont(font)

        label_tag_hyphen = QLabel(self)
        label_tag_hyphen.setText(" - ")
        label_tag_hyphen.setFixedWidth(30)
        font = label_tag_hyphen.font()
        font.setPointSize(self._font_size_label)
        font.setBold(self._font_bold_label)
        label_tag_hyphen.setFont(font)

        self.label_tag_end = QLabel(self)
        self.label_tag_end.setText("None")
        font = self.label_tag_end.font()
        font.setBold(True)
        font.setPointSize(self._font_size_label)
        self.label_tag_end.setFont(font)

        # Sig / BG.
        label_sig = QLabel(self)
        label_sig.setText("# of Sig : ")
        label_sig.setAlignment(Qt.AlignRight)
        font = label_sig.font()
        font.setPointSize(self._font_size_label)
        font.setBold(self._font_bold_label)
        label_sig.setFont(font)

        self.label_nbr_of_sig = QLabel(self)
        self.label_nbr_of_sig.setText("None")
        font = self.label_nbr_of_sig.font()
        font.setBold(True)
        font.setPointSize(self._font_size_label)
        self.label_nbr_of_sig.setFont(font)

        label_bg = QLabel(self)
        label_bg.setText("# of BG : ")
        label_bg.setAlignment(Qt.AlignRight)
        font = label_bg.font()
        font.setPointSize(self._font_size_label)
        font.setBold(self._font_bold_label)
        label_bg.setFont(font)

        self.label_nbr_of_bg = QLabel(self)
        self.label_nbr_of_bg.setText("None")
        font = self.label_nbr_of_bg.font()
        font.setBold(True)
        font.setPointSize(self._font_size_label)
        self.label_nbr_of_bg.setFont(font)

        # Construct the layout.
        grid_runinfo.addWidget(label_run, 0, 0)
        grid_runinfo.addWidget(self.label_run_number, 0, 1, 1, 3)

        grid_runinfo.addWidget(label_tag, 1, 0)
        grid_runinfo.addWidget(self.label_tag_start, 1, 1)
        grid_runinfo.addWidget(label_tag_hyphen, 1, 2)
        grid_runinfo.addWidget(self.label_tag_end, 1, 3)

        grid_runinfo.addWidget(label_sig, 2, 0)
        grid_runinfo.addWidget(self.label_nbr_of_sig, 2, 1)
        grid_runinfo.addWidget(label_bg, 2, 2)
        grid_runinfo.addWidget(self.label_nbr_of_bg, 2, 3)

        ### Settings.
        # group_settings = QGroupBox(self)
        # group_settings.setTitle("Settings")
        # font = group_settings.font()
        # font.setPointSize(self._font_size_groupbox_title)
        # group_settings.setFont(font)
        # group_settings.resize(400, 100)
        # grid_settings = QGridLayout(group_settings)

        # # Update interval.
        # label_upd_rate = QLabel(self)
        # label_upd_rate.setText("Upd. image interval: ")
        # font = label_upd_rate.font()
        # font.setPointSize(self._font_size_label)
        # font.setBold(self._font_bold_label)
        # label_upd_rate.setFont(font)

        # self.spinbox_upd_img_interval = QDoubleSpinBox(self)
        # self.spinbox_upd_img_interval.setValue(self._get_data_interval)
        # self.spinbox_upd_img_interval.setFixedWidth(100)
        # self.spinbox_upd_img_interval.setAlignment(Qt.AlignRight)
        # font = self.spinbox_upd_img_interval.font()
        # font.setBold(True)
        # font.setPointSize(self._font_size_label)
        # self.spinbox_upd_img_interval.setFont(font)

        # label_upd_rate_unit = QLabel(self)
        # label_upd_rate_unit.setText("sec")
        # font = label_upd_rate_unit.font()
        # font.setPointSize(self._font_size_label)
        # font.setBold(self._font_bold_label)
        # label_upd_rate_unit.setFont(font)

        # Construct the layout.
        # grid_settings.addWidget(label_upd_rate, 0, 0, 1, 3)
        # grid_settings.addWidget(self.spinbox_upd_img_interval, 0, 3)
        # grid_settings.addWidget(label_upd_rate_unit, 0, 4)

        ### Function buttons.
        group_func = QGroupBox(self)
        group_func.setTitle("Function")
        font = group_func.font()
        font.setPointSize(self._font_size_groupbox_title)
        group_func.setFont(font)
        group_func.resize(400, 100)
        grid_func = QGridLayout(group_func)
        grid_func.setSpacing(10)

        # Start/Stop main process button.
        self.brun = QPushButton(group_func)
        self.brun.setText("Start")
        font = self.brun.font()
        font.setPointSize(self._font_size_button)
        self.brun.setFont(font)
        self.brun.resize(400, 50)
        self.brun.setStyleSheet("background-color:{};".format(
            self._init_button_color))
        self.brun.clicked.connect(self.runMainProcess)

        # Clear data button.
        bclear = QPushButton(group_func)
        bclear.setText("Clear")
        font = bclear.font()
        font.setPointSize(self._font_size_button)
        bclear.setFont(font)
        bclear.resize(400, 50)
        bclear.setStyleSheet("background-color:{};".format(
            self._init_button_color))
        bclear.clicked.connect(self.clearData)

        # Save images button.
        bsave = QPushButton(group_func)
        bsave.setText("Save")
        font = bsave.font()
        font.setPointSize(self._font_size_button)
        bsave.setFont(font)
        bsave.resize(400, 50)
        bsave.setStyleSheet("background-color:{};".format(
            self._init_button_color))
        bsave.clicked.connect(self.saveData)

        # New window button.
        bwindow = QPushButton(group_func)
        bwindow.setText("Window")
        font = bwindow.font()
        font.setPointSize(self._font_size_button)
        bwindow.setFont(font)
        bwindow.resize(400, 50)
        bwindow.setStyleSheet("background-color:{};".format(
            self._init_button_color))
        bwindow.clicked.connect(self.showWindow)

        # Construct the layout of RunInfo groupbox.
        grid_func.addWidget(self.brun, 0, 0)
        grid_func.addWidget(bclear, 0, 1)
        grid_func.addWidget(bsave, 1, 0)
        grid_func.addWidget(bwindow, 1, 1)

        ### Plotting area.
        grp1 = QGroupBox(self)
        # grp1.setTitle("SIG WL")
        grp1.setTitle("SIG")
        font = grp1.font()
        font.setPointSize(self._font_size_groupbox_title)
        grp1.setFont(font)
        gp1 = QGridLayout(grp1)
        gp1.setSpacing(10)

        grp2 = QGroupBox(self)
        # grp2.setTitle("SIG WOL")
        grp2.setTitle("BG")
        font = grp2.font()
        font.setPointSize(self._font_size_groupbox_title)
        grp2.setFont(font)
        gp2 = QGridLayout(grp2)
        gp2.setSpacing(10)

        grp3 = QGroupBox(self)
        # grp3.setTitle("BG WL")
        grp3.setTitle("SIg - BG")
        font = grp3.font()
        font.setPointSize(self._font_size_groupbox_title)
        grp3.setFont(font)
        gp3 = QGridLayout(grp3)
        gp3.setSpacing(10)

        # grp4 = QGroupBox(self)
        # grp4.setTitle("BG WOL")
        # font = grp4.font()
        # font.setPointSize(self._font_size_groupbox_title)
        # grp4.setFont(font)
        # gp4 = QGridLayout(grp4)
        # gp4.setSpacing(10)

        kwargs = dict(px=False, py=False, ph=False, bp=False)
        self.pw1 = PlotWindow(self, **kwargs)
        self.pw2 = PlotWindow(self, **kwargs)
        self.pw3 = PlotWindow(self, **kwargs)
        # self.pw4 = PlotWindow(self, **kwargs)

        gp1.addWidget(self.pw1, 0, 0)
        gp2.addWidget(self.pw2, 0, 0)
        gp3.addWidget(self.pw3, 0, 0)
        # gp4.addWidget(self.pw4, 0, 0)

        ### Construct the layout.
        self.grid.addWidget(group_runinfo, 0, 0)
        # self.grid.addWidget(group_settings, 0, 1)
        self.grid.addWidget(group_func, 0, 1)
        self.grid.addWidget(grp1, 1, 0, 2, 1)
        self.grid.addWidget(grp2, 1, 1, 2, 1)
        self.grid.addWidget(grp3, 1, 2, 2, 1)
        # self.grid.addWidget(grp4, 1, 3, 2, 1)
        self.main_widget.setFocus()
        self.setCentralWidget(self.main_widget)

    @footprint
    def initMainWidget(self):
        """
        Initialize the main widget and the grid.
        """
        self.main_widget = QWidget(self)
        self.setStyleSheet("background-color:{};".format(self.main_bgcolor))
        self.grid = QGridLayout(self.main_widget)
        self.grid.setSpacing(10)
        self.setWindowIcon(
            QIcon(os.path.join(os.path.dirname(__file__), "python.png")))

    @footprint
    def setMenuBar(self):
        """
        Set the contents of the menu bar
        """
        ## File
        file_menu = QMenu('&File', self)

        # Open
        # file_menu.addAction('&Open', self.openFile,
        #         QtCore.Qt.CTRL + QtCore.Qt.Key_O)

        # Config
        file_menu.addAction('&Config', self.setConfig,
                            QtCore.Qt.CTRL + QtCore.Qt.Key_C)
        # Quit
        file_menu.addAction('&Quit', self.quitApp,
                            QtCore.Qt.CTRL + QtCore.Qt.Key_Q)

        self.menuBar().addMenu(file_menu)

        ## Help
        # help_menu = QMenu('&Help', self)
        # help_menu.addAction('Help', self.showHelp)
        # help_menu.addAction('About...', self.showAbout)
        self.menuBar().addSeparator()
        # self.menuBar().addMenu(help_menu)

######################## Menu bar ########################

    @footprint
    def openFile(self):
        """
        Show a file dialog and select a file
        """
        pass

    @footprint
    def setConfig(self):
        """
        Set configuration of this application.
        """
        pass

    @footprint
    def quitApp(self):
        """
        Quit this application.
        """
        self.close()

    @footprint
    def showHelp(self):
        """
        Show a pop-up dialog showing how to use this application.
        """
        pass

    @footprint
    def showAbout(self):
        """
        Show a pop-up dialog describing this application.
        """
        pass

######################## Widgets' functions ########################

    @footprint
    @pyqtSlot()
    def showWindow(self):
        window = PlotWindow(self, "win{0:02d}".format(len(self._windows) + 1))
        window.show()
        window.raise_()
        window.activateWindow()
        self._windows.append(window)

    @footprint
    @pyqtSlot()
    def runMainProcess(self):
        if not self._timer_getData.isActive():
            self.initData()
            for listener in self._worker_getData.listeners.values():
                listener.Connect()
            self._worker_getData.listener_info.Connect()
            # self._update_image_interval = self.spinbox_upd_img_interval.value()
            # self.spinbox_upd_img_interval.setEnabled(False)
            self._timer_getData.start()
            self.brun.setText("Stop")
            if not self._timer_updImage.isActive():
                time.sleep(self._get_update_delay)
                self._timer_updImage.start()
        else:
            self.brun.setEnabled(False)
            self.stopTimer = True

    @footprint
    @pyqtSlot()
    def saveData(self):
        now_save = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        now = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        saveDataDir = os.path.join(os.path.dirname(__file__), "data",
                                   "Run{}".format(str(self.currentRun)))

        # Data.
        if not os.path.exists(saveDataDir):
            os.makedirs(saveDataDir)
        for _types in self._get_data_ports.keys():
            np.save(os.path.join(saveDataDir, "data_{0}_{1}.npy".format(now, _types)), \
                    self.dataset[_types])

        # Image.
        # saveScn = os.path.join(saveDataDir, "{}_screenshot.png".format(now))
        # QPixmap.grabWindow(self.winId()).save(saveScn, 'png')

        # Status.
        status = {
            "save_datetime": now_save,
            "Run": self.label_run_number.text(),
            "StartTag": self.label_tag_start.text(),
            "CurrentTag": self.label_tag_end.text()
        }
        with open(os.path.join(saveDataDir, "{}_status.json".format(now)),
                  "w") as ff:
            json.dump(status, ff)

    @footprint
    @pyqtSlot()
    def clearData(self):
        self.saveData()
        self.initData()

######################## GetDataProcess ########################

    @footprint
    def initGetDataProcess(self):
        self._timer_getData = QTimer()
        self._timer_getData.setInterval(int(self._get_data_interval * 1000))
        self.stopTimer = False
        self._thread_getData = QThread()
        self._worker_getData = GetDataWorker3(port=self._get_data_ports,
                                              port_info=self._get_info_port)
        self._worker_getData.sleepInterval = self._get_data_worker_sleep_interval

        # Start.
        self._timer_getData.timeout.connect(self.startGettingDataThread)
        self._thread_getData.started.connect(self._worker_getData.process)
        self._worker_getData.do_something.connect(self.updateData)

        # Finish.
        self._worker_getData.finished.connect(self._thread_getData.quit)
        self._thread_getData.finished.connect(self.checkIsTimerStopped)

        # Move.
        self._worker_getData.moveToThread(self._thread_getData)

    @footprint
    @pyqtSlot()
    def startGettingDataThread(self):
        if not self._thread_getData.isRunning():
            print("start thread by timer.")
            self._thread_getData.start()
        else:
            print("Thread is running.")

    @footprint
    @pyqtSlot(object)
    def updateData(self, obj):
        if self._isUpdatingImage is False:  # In case.
            if obj is not None:
                for key in self.dataset.keys():
                    if self.dataset.get(key) is None and obj.get(
                            key) is not None:
                        self.dataset[key] = obj.get(key).copy()
                    elif obj.get(key) is not None:
                        self.dataset[key] += obj.get(key).copy()
                currentRun = obj.get("currentRun")
                self.label_run_number.setText(str(currentRun))
                if self.nbr_of_sig == 0:
                    self.label_tag_start.setText(str(obj.get("startTag")))
                self.label_tag_end.setText(str(obj.get("endTag")))

                self.nbr_of_sig += obj.get("nbr_sig_wl") + obj.get(
                    "nbr_sig_wol")
                self.nbr_of_bg += obj.get("nbr_bg_wl") + obj.get("nbr_bg_wol")
                self.label_nbr_of_sig.setText(str(self.nbr_of_sig))
                self.label_nbr_of_bg.setText(str(self.nbr_of_bg))
                if self.currentRun != -1 and currentRun != self.currentRun:
                    self.saveData()
                    self.initData()
                self.currentRun = currentRun

    @footprint
    @pyqtSlot()
    def checkIsTimerStopped(self):
        if self.stopTimer:
            self._timer_getData.stop()
            self._timer_updImage.stop()
            print("timer stopped.")
            for listener in self._worker_getData.listeners.values():
                listener.Close()
            self._worker_getData.listener_info.Close()
            self.stopTimer = False
            self.brun.setEnabled(True)
            self.brun.setText("Start")
            # self.spinbox_upd_img_interval.setEnabled(True)

######################## updateImageProcess ########################

    @footprint
    def initUpdateImageProcess(self):
        self._timer_updImage = QTimer()
        self._timer_updImage.setInterval(
            int(self._update_image_interval * 1000))
        self._timer_updImage.timeout.connect(self.updateImage)

    @footprint
    def updateImage(self):
        self._isUpdatingImage = True
        try:
            with QMutexLocker(self._mutex):
                sig_wl = self.dataset.get("sig_wl", None)
                sig_wol = self.dataset.get("sig_wol", None)
                bg_wl = self.dataset.get("bg_wl", None)
                bg_wol = self.dataset.get("bg_wol", None)
                if self.sig is None or self.bg is None:
                    self.sig = sig_wl + sig_wol
                    self.bg = bg_wl + bg_wol
                else:
                    self.sig += sig_wl + sig_wol
                    self.bg += bg_wl + bg_wol
                # print(self.sig.dtype)
                # buff1 = self.sig / float(self.nbr_of_sig)
                self.pw1.data = self.sig / float(self.nbr_of_sig)
                # buff1 = self.bg / float(self.nbr_of_bg)
                self.pw2.data = self.bg / float(self.nbr_of_bg)
                self.pw3.data = self.pw1.data - self.pw2.data
                # self.pw4.data = bg_wol

                # if sig_wl is not None and sig_wol is not None:
                #     self.pw3.data = sig_wl - sig_wol
                for window in self._windows:
                    if not window.is_closed:
                        window.data = sig_wl
        except Exception as ex:
            print(ex)
        self._isUpdatingImage = False

        if self.sig is not None and self.bg is not None:
            self.pw1.updateImage()
            self.pw2.updateImage()
            self.pw3.updateImage()
        # self.pw4.updateImage()

######################## CheckWindowProcess ########################

    @footprint
    def initCheckWindowProcess(self):
        """
        Initialize checkWindow process.
        """
        self._timer_checkWindow = QTimer()
        self._timer_checkWindow.setInterval(
            int(self._check_window_interval * 1000))
        self._timer_checkWindow.timeout.connect(self.checkWindow)
        self._timer_checkWindow.start()

    # @footprint
    @pyqtSlot()
    def checkWindow(self):
        """
        Check whether windows are active.
        """
        # print(len(self._windows))
        N = len(self._windows) * 1
        for ii in range(N):
            if self._windows[N - ii - 1].is_closed:
                del self._windows[N - ii - 1]

    # @footprint
    # @pyqtSlot()
    # def finishWorker(self):
    #     pass


######################## Closing processes ########################

    @footprint
    def closeEvent(self, event):
        if self._thread_getData.isRunning():
            string = "Some threads are still running.\n"
            string += "Please wait for their finishing."
            confirmObject = QMessageBox.warning(self, "Closing is ignored.",
                                                string, QMessageBox.Ok)
            event.ignore()
            return
        if self._closing_dialog:
            confirmObject = QMessageBox.question(
                self, "Closing...", "Are you sure to quit?",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            if confirmObject == QMessageBox.Yes:
                self.makeConfig()
                with open(
                        os.path.join(os.path.dirname(__file__), "config.json"),
                        "w") as ff:
                    json.dump(self.config, ff)
                self.stopAllTimers()
                self.saveData()
                event.accept()
            else:
                event.ignore()
        else:
            self.makeConfig()
            with open(os.path.join(os.path.dirname(__file__), "config.json"),
                      "w") as ff:
                json.dump(self.config, ff, indent=4)
            self.saveData()
            self.stopAllTimers()

    @footprint
    def stopAllTimers(self):
        if self._timer_getData.isActive():
            self._timer_getData.stop()
        if self._timer_updImage.isActive():
            self._timer_updImage.stop()
        if self._timer_checkWindow.isActive():
            self._timer_checkWindow.stop()

    @footprint
    def makeConfig(self):
        """
        Make a config dict object to save the latest configration in.
        """
        self.config = OrderedDict([
            ("online", self._online), ("closing_dialog", self._closing_dialog),
            ("currentDir", self._currentDir), ("emulate", self._emulate),
            ("font_size_button", self._font_size_button),
            ("font_size_label", self._font_size_label),
            ("font_size_groupbox_title", self._font_size_groupbox_title)
        ])
예제 #4
0
class MainWindow(QMainWindow, Ui_MainWindow):
    """
    Class for main application window.
    """

    def __init__(self, parent=None):
        """
        Main application window.
        """
        QMainWindow.__init__(self, parent)

        self.win7_taskbar = Win7Taskbar(self)
        self.app = QApplication.instance()
        self.setupUi(self)

        self.setWindowTitle('ABBYY Automator v{0:s}'.format(self.app.applicationVersion()))
        self.settings = Settings()

        self.get_app_paths()

        self.button_save_errors.setVisible(False)
        self.progress_bar.setVisible(0)
        self.on_tb_refresh_profiles_released()

        self.last_logged_text = ''

        self.file_watcher_threads = []
        self.file_watcher = None
        self.processed_count = 0
        self.skipped_count = 0
        self.file_queue = deque()
        self.current_pathname = None
        self.current_watch_path = None
        self.error_paths = []

        self.acrobat_proxy_listener = AcrobatProxyListener()
        self.acrobat_proxy_listener.new_path.connect(self.path_received)

        self.abbyy_ocr = AbbyyOcr(self.abby_path)
        self.abbyy_ocr.error.connect(self.error_received)

        self.update_processed_status()
        self.statusbar.update_left('Ready to begin')

        self.output_folder = ''

        self.load_settings()

    def save_settings(self):
        self.settings.last_watch_folder = self.le_watch_folder.text()
        self.settings.last_output_folder = self.le_output_folder.text()
        self.settings.last_profile = self.cb_profile.currentText()

    def load_settings(self):
        self.le_watch_folder.setText(self.settings.last_watch_folder)
        self.le_output_folder.setText(self.settings.last_output_folder)
        index = self.cb_profile.findText(self.settings.last_profile)
        if index == -1:
            self.cb_profile.setCurrentIndex(0)
        else:
            self.cb_profile.setCurrentIndex(index)

    def get_app_paths(self):
        # Get ABBYY path.
        self.abby_path = find_app_path('FineReader')
        if not self.abby_path or not os.path.isfile(self.abby_path):
            message_box_error('ABBYY FineReader not found',
                              'Could not find an ABBYY FineReader install on this machine.')
            sys.exit()

        # Check for version 10 of ABBYY.
        abbyy_dir = os.path.dirname(self.abby_path)
        if not abbyy_dir[-2:] == '10':
            ten_path = '{0:s}10\\FineReader.exe'.format(self.abby_path[-2:])
            if os.path.isfile(ten_path):
                self.abby_path = ten_path
            else:
                message_box_error('ABBYY FineReader 10 not found',
                                  'ABBYY FineReader was found on this machine, but a version other than 10.')
                sys.exit()

        # Get Acrobat path.
        self.acrobat_path = find_app_path('Acrobat')
        if not self.acrobat_path or not os.path.isfile(self.acrobat_path):
            message_box_error('Adobe Acrobat not found',
                              'Could not find an Adobe Acrobat install on this machine.')
            sys.exit()

    def install_acrobat_proxy(self):
        acrobat_backup_path = '{0:s}_.exe'.format(self.acrobat_path[:-4])
        acrobat_version = get_exe_version(self.acrobat_path)

        if acrobat_version[0] < 5 and os.path.isfile(acrobat_backup_path):
            # Proxy already installed.
            self.log('Acrobat proxy already installed.', bold=True)
            return True

        self.log('Installing Acrobat proxy over Acrobat v{0:d}.{1:d}...'.format(*acrobat_version), bold=True)
        try:
            # Backup existing Acrobat.exe.
            shutil.move(self.acrobat_path, acrobat_backup_path)
        except(OSError, IOError):
            self.log('Error moving Acrobat.exe - is Acrobat running?', bold=True, colour='red')
            return False

        try:
            # Copy Proxy in place of Acrobat
            shutil.copy('Acrobat Proxy.exe', self.acrobat_path)
        except(OSError, IOError):
            self.log('Error installing proxy - please check folder permissions.', bold=True, colour='red')
            return False

        return True

    def restore_acrobat(self):
        acrobat_backup_path = '{0:s}_.exe'.format(self.acrobat_path[:-4])
        acrobat_version = get_exe_version(acrobat_backup_path)
        proxy_version = get_exe_version(self.acrobat_path)

        if not acrobat_version and proxy_version:
            return False

        if proxy_version[0] > 5 and os.path.isfile(acrobat_backup_path):
            # Proxy not installed.
            self.log('Acrobat proxy not installed.', bold=True, colour='red')
            return True

        self.log('Restoring Acrobat v{0:d}.{1:d}...'.format(*acrobat_version), bold=True)
        try:
            # Backup existing Acrobat.exe.
            shutil.move(acrobat_backup_path, self.acrobat_path)
        except(OSError, IOError):
            self.log('Error moving Acrobat.exe - is Acrobat running?', bold=True, colour='red')
            return False

        return True

    def increment_processed(self):
        self.processed_count += 1
        self.update_processed_status()

    def update_processed_status(self):
        if not self.skipped_count:
            skipped_text = ''
        else:
            if self.skipped_count == 1:
                skipped_text = ' (1 file skipped)'
            else:
                skipped_text = ' ({0:,} files skipped)'.format(self.skipped_count)

        if self.processed_count == 1:
            self.statusbar.update_middle('1 file processed{0:s}'.format(skipped_text))
        else:
            self.statusbar.update_middle('{0:,} files processed{1:s}'.format(self.processed_count, skipped_text))

        queue_size = len(self.file_queue)
        if queue_size == 1:
            self.statusbar.update_right('1 file remaining')
        else:
            self.statusbar.update_right('{0:,} files remaining'.format(queue_size))

        self.app.processEvents()

    def log(self, text='', indent=False, update_existing=False, colour=None, bold=False, status_bar=False):
        """
        Update the QPlainTextEdit based log.
        """
        if colour:
            if colour == 'green':
                text = '<font color="#347235">%s</font>' % text
            elif colour == 'red':
                text = '<font color="#7E2217">%s</font>' % text
        if bold:
            text = '<b>%s</b>' % text
        if indent or update_existing:
            text = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%s' % text
        if update_existing:
            self.pte_log.undo()
            text = '%s%s' % (self.last_logged_text, text)

        self.pte_log.appendHtml(text)
        self.last_logged_text = text
        self.app.processEvents()
        v_scrollbar = self.pte_log.verticalScrollBar()
        v_scrollbar.setValue(v_scrollbar.maximum())

        if status_bar:
            # Remove HTML tags from the text and add to the status bar.
            self.statusbar.showMessage(regex_html_tags.sub('', text))

    def queue_size_changed(self, count=None):
        # If we've items in the queue, we're in process mode and currently are not processing any files then start
        # on the next item in the queue.
        if not count:
            count = len(self.file_queue)
        if count and self.button_start.isChecked() and not self.current_pathname:
            print 'Processing restarted!'
            self.process_next()

    def queue_received(self, queue_list):
        print 'Received new queue'
        length = len(queue_list)
        self.file_queue = deque(queue_list)
        self.log('Found <b>{0:,} files'.format(length))

        self.progress_bar.setRange(0, length)
        self.update_processed_status()

        if self.button_start.isChecked():
            self.log()
            self.log('Processing queue', bold=True)
            self.log()
            self.process_next()

    def adjust_progress_bars(self):
        self.progress_bar.setMaximum(len(self.file_queue))

    def watch_folder_changed(self, event):
        print event
        action, filename = event
        if action == 3:
            # Updated.
            return
        elif action in (1, 4):
            # Created / Renamed from something.
            self.file_queue.append(filename)
        elif action in (2, 5):
            # Deleted / Renamed to something.
            try:
                self.file_queue.remove(filename)
            except ValueError:
                print 'Error removing from queue:', filename
        self.update_processed_status()
        self.queue_size_changed()
        self.adjust_progress_bars()

    def process_next(self):
        """
        Get next item in the queue and send it to ABBYY.
        """
        try:
            while True:
                # Keep pulling from the queue until the output file doesn't already exist.
                path = self.file_queue.popleft()
                out_path = os.path.join(self.output_folder,
                                        '{0:s}.pdf'.format(path[len(self.current_watch_path) + 1:-4]))
                print 'CHECKING', out_path
                if not os.path.isfile(out_path):
                    break
                self.skipped_count += 1
                self.update_processed_status()
        except IndexError:
            # Queue is empty.
            print 'QUEUE IS NOW EMPTY!'
            self.current_pathname = None
            self.progress_bar.setMaximum(0)
            self.progress_bar.setValue(0)
            self.statusbar.update_left('Waiting for files...')
            return

        self.current_pathname = path

        print 'QUEUE PROCESSING:', path
        self.statusbar.update_left(path[len(self.current_watch_path):])
        self.abbyy_ocr.ocr(path)

    def closeEvent(self, event):
        self.save_settings()
        self.file_queue.clear()  # Ensure the queue is clear for a clean exit.
        self.restore_acrobat()

        self.abbyy_ocr.kill()

        super(MainWindow, self).closeEvent(event)

    def path_received(self, path):
        self.abbyy_ocr.kill()
        path = str(path)
        print 'Path received:', path

        # Calculate output path and store it for when the file is done.
        out_path = os.path.join(self.output_folder,
                                '{0:s}.pdf'.format(self.current_pathname[len(self.current_watch_path) + 1:-4]))
        out_folder = os.path.dirname(out_path)
        if not os.path.isdir(out_folder):
            os.makedirs(out_folder)
        try:
            move(path, out_path)
        except(IOError, OSError):
            print 'Error moving', path, 'to', out_path

        self.progress_bar.setValue(self.progress_bar.value() + 1)
        self.increment_processed()
        self.update_processed_status()
        if self.button_start.isChecked():
            self.process_next()
        else:
            self.acrobat_proxy_listener.stop()

    def error_received(self, error_message):
        self.button_save_errors.setVisible(True)
        self.error_paths.append(self.current_pathname)
        self.log('Error processing {0:s}:'.format(self.current_pathname), bold=True, colour='red')
        self.log('Error phrase matched: <b>{0:s}</b>'.format(error_message), indent=True)
        self.progress_bar.setValue(self.progress_bar.value() + 1)
        self.increment_processed()
        self.app.processEvents()  # Keep the GUI responsive during processing.
        self.process_next()

    def file_watcher_error(self, error_message):
        self.log('WATCH FOLDER ERROR:', colour='red', bold=True)
        self.log(error_message, indent=True, bold=True)
        message_box_error('Watch folder error', error_message)

        # Lock down all application controls other than the error log saving button.
        self.button_start.setChecked(False)
        for widget in (self.button_start, self.button_output_browse, self.button_watch_browse, self.cb_profile,
                       self.tb_refresh_profiles, self.rb_jpeg, self.rb_pdf, self.rb_tiff):
            widget.setEnabled(False)
        return

    def set_inputs_enabled(self, enabled=True):
        for item in (self.inputs_layout.itemAt(i).widget() for i in xrange(self.inputs_layout.count())):
            if isinstance(item, QWidget):
                item.setEnabled(enabled)

    def reset(self):
        self.acrobat_proxy_listener.stop()
        self.progress_bar.setVisible(False)
        self.button_start.setChecked(False)

        self.processed_count = 0
        self.skipped_count = 0
        self.file_queue = deque()
        self.update_processed_status()

    @pyqtSignature('')
    def on_button_reset_released(self):
        self.button_start.setChecked(False)

        print 'Stopping file watcher...'
        try:
            self.file_watcher.stopping = True
            self.file_watcher_thread.quit()
            # self.file_watcher_thread.terminate()

            del self.file_watcher
            # del self.file_watcher_thread
        except AttributeError:
            print 'Could not stop file watcher. Was it running?'
        print 'File watcher stopped.'

        self.reset()
        self.set_inputs_enabled(True)
        self.button_reset.setEnabled(False)

    @pyqtSignature('bool')
    def on_button_start_toggled(self, pressed):
        if not pressed:
            print 'Released!', pressed
            self.progress_bar.setVisible(False)
            self.statusbar.update_left('Ready to begin')
            if self.current_pathname is None:
                self.acrobat_proxy_listener.stop()
            return

        self.set_inputs_enabled(False)
        self.button_reset.setEnabled(True)

        self.output_folder = str(self.le_output_folder.text())
        print "Output folder:", self.output_folder

        watch_folder = str(self.le_watch_folder.text())
        print watch_folder
        if not os.path.isdir(watch_folder):
            message_box_error(
                'Invalid watch folder',
                'Please set the watch folder to a valid path and try again.'
            )
            self.button_start.setChecked(False)
            return

        # Set profile.
        if self.cb_profile.currentIndex():
            self.abbyy_ocr.current_profile = str(self.cb_profile.itemData(self.cb_profile.currentIndex()).toString())
        else:
            self.abbyy_ocr.current_profile = None
        print 'Current profile:', self.abbyy_ocr.current_profile

        print self.install_acrobat_proxy()
        # return

        self.current_watch_path = watch_folder
        self.log('Searching for files in <b>{0:s}</b>...'.format(watch_folder), status_bar=True)
        self.progress_bar.setVisible(True)
        self.progress_bar.setRange(0, 0)

        if not self.acrobat_proxy_listener.start():
            message_box_error('Error starting Acrobat Proxy Listener',
                              self.acrobat_proxy_listener.errorString())
            self.log('Error starting Acrobat Proxy Listener', colour='red')
            self.log(str(self.acrobat_proxy_listener.errorString()), indent=True, bold=True)
            self.reset()
            return

        # if not hasattr(self, 'file_watcher_thread'):
            # Get extension from radio buttons.
        if self.rb_tiff.isChecked():
            extension = ('.tiff', '.tif')
        elif self.rb_pdf.isChecked():
            extension = '.pdf'
        elif self.rb_jpeg.isChecked():
            extension = '.jpg'
        else:
            raise Exception('No extension selected')

        self.file_watcher_thread = QThread()
        self.file_watcher_threads.append(self.file_watcher_thread)
        self.file_watcher = FileWatcher(watch_folder, extension)
        self.file_watcher.moveToThread(self.file_watcher_thread)
        self.file_watcher_thread.started.connect(self.file_watcher.start)
        self.file_watcher_thread.finished.connect(self.file_watcher_thread.deleteLater)
        self.file_watcher.finished.connect(self.file_watcher_thread.quit)
        self.file_watcher.count_change.connect(self.queue_size_changed)
        self.file_watcher.first_queue.connect(self.queue_received)
        self.file_watcher.queue_change.connect(self.watch_folder_changed)
        self.file_watcher.error.connect(self.file_watcher_error)

        if not self.file_watcher_thread.isRunning():
            self.file_watcher_thread.start()
        else:
            if self.file_queue:
                self.adjust_progress_bars()
                self.progress_bar.setValue(0)
                self.update_processed_status()
                self.process_next()

    @pyqtSignature('')
    def on_button_watch_browse_released(self):
        output_path = unicode(self.le_output_folder.text())
        if output_path and os.path.isdir(output_path):
            start_path = output_path
        else:
            start_path = ''
        watch_path = QFileDialog.getExistingDirectory(self, 'Select an input folder', start_path)
        if not watch_path:
            return
        self.le_watch_folder.setText(watch_path)

    @pyqtSignature('')
    def on_button_output_browse_released(self):
        watch_path = unicode(self.le_watch_folder.text())
        if watch_path and os.path.isdir(watch_path):
            start_path = watch_path
        else:
            start_path = ''
        output_path = QFileDialog.getExistingDirectory(self, 'Select an output folder', start_path)
        if not output_path:
            return
        self.le_output_folder.setText(output_path)

    @pyqtSignature('')
    def on_tb_refresh_profiles_released(self):
        if hasattr(sys, 'frozen'):
            profiles_dir = os.path.join(os.path.dirname(sys.executable), 'profiles')
        else:
            profiles_dir = os.path.join(os.getcwd(), 'profiles')

        profiles_list = sorted(iglob('{0:s}/*.fbt'.format(profiles_dir)))

        self.cb_profile.clear()
        self.cb_profile.addItem('Last used ABBYY settings')
        for path in profiles_list:
            title = os.path.basename(path)[:-4]
            self.cb_profile.addItem(title, path)

    @pyqtSignature('')
    def on_button_save_errors_released(self):
        error_log_path = QFileDialog.getSaveFileName(self, 'Save error log', filter='Text Files (*.txt)')
        if not error_log_path:
            return

        with open(error_log_path, 'w') as log_file:
            for item in self.error_paths:
                log_file.write('{0:s}\n'.format(item))
예제 #5
0
class GCode(object):
    def __init__(self, filename, controller, done_loading_callback,
                 done_writing_callback):
        self.controller = controller
        self.done_loading_callback = done_loading_callback
        self.writing_done_callback = done_writing_callback
        self.data = defaultdict(list)
        self.all_data = []
        self.data_keys = set()
        self.color_change_data = []
        self.actual_z = '0.0'
        self.speed = 0.0
        self.z_hop = False
        self.last_point = np.array([0.0, 0.0, 0.0])
        self.actual_point = [0.0, 0.0, 0.0]

        self.printing_time = 0.0
        self.filament_length = 0.0
        #print("Filename type: " + str(type(filename)))
        #print("Filename: " + filename)
        #if type(filename)==:
        #self.filename = u'c:\\models\\super mega testovací Jindřich šložka čěýáéůú\\anubis_PLA_OPTIMAL.gcode'
        self.filename = filename

        self.is_loaded = False

        self.gcode_parser = GcodeParserRunner(controller, self.filename)
        self.gcode_parser_thread = QThread()

        self.gcode_copy = GcodeCopyRunner(
            self.filename, "", color_change_lst=self.color_change_data)
        self.gcode_copy_thread = QThread()

    def cancel_parsing_gcode(self):
        print("Cancel presset")
        if self.gcode_parser and self.gcode_parser_thread and self.gcode_parser_thread.isRunning(
        ):
            self.gcode_parser.is_running = False
            self.gcode_parser_thread.quit()
            self.gcode_parser_thread.wait()
            self.is_loaded = False
            self.data = {}
            self.all_data = []
            self.data_keys = []
        self.controller.set_progress_bar(0)

    def cancel_writing_gcode(self):
        print("Cancel writing gcode")
        if self.gcode_copy and self.gcode_copy_thread and self.gcode_copy_thread.isRunning(
        ):
            self.gcode_copy.quit()
            self.gcode_copy_thread.wait()

    def get_first_extruding_line_number_of_gcode_for_layers(
            self, layers_keys_lst):
        lines_number = []
        for i in layers_keys_lst:
            line = self.data[i]
            for o in line:
                _a, _b, type, _speed, _extr, _extruder, line_n = o
                if 'E' in type:
                    lines_number.append(line_n)
                    break

        return lines_number

    def read_in_thread(self, update_progressbar_function, after_done_function):
        print("reading in thread")
        self.gcode_parser.moveToThread(self.gcode_parser_thread)
        self.done_loading_callback = after_done_function

        # connect all signals to thread class
        self.gcode_parser_thread.started.connect(
            self.gcode_parser.load_gcode_file)
        # connect all signals to parser class
        self.gcode_parser.finished.connect(self.set_finished_read)
        self.gcode_parser.update_progressbar = True
        self.gcode_parser.set_update_progress.connect(
            update_progressbar_function)
        self.gcode_parser.set_data_keys.connect(self.set_data_keys)
        self.gcode_parser.set_data.connect(self.set_data)
        self.gcode_parser.set_all_data.connect(self.set_all_data)
        self.gcode_parser.set_printing_time.connect(self.set_printig_time)

        self.gcode_parser_thread.start()

    def read_in_realtime(self):
        print("Read in realtime")
        self.gcode_parser.set_data_keys.connect(self.set_data_keys)
        self.gcode_parser.set_data.connect(self.set_data)
        self.gcode_parser.set_all_data.connect(self.set_all_data)
        self.gcode_parser.set_printing_time.connect(self.set_printig_time)
        self.gcode_parser.update_progressbar = False

        print("start read procedure")
        self.gcode_parser.load_gcode_file()

        self.is_loaded = True

    def set_printig_time(self, time):
        self.printing_time = time

    def set_data_keys(self, data_keys):
        self.data_keys = data_keys

    def set_all_data(self, all_data):
        self.all_data = all_data

    def set_data(self, data):
        self.data = data

    def set_finished_read(self):
        self.gcode_parser_thread.quit()
        self.is_loaded = True
        self.done_loading_callback()
        #self.controller.set_gcode()

    def set_finished_copy(self):
        self.gcode_copy_thread.quit()
        #print(str(self.writing_done_callback))
        self.writing_done_callback()

    def set_color_change_data(self, data):
        self.color_change_data = data

    def write_with_changes_in_thread(self, filename_in, filename_out,
                                     update_function):
        self.gcode_copy.filename_in = filename_in
        self.gcode_copy.filename_out = filename_out
        self.gcode_copy.color_change_lst = self.color_change_data
        self.gcode_copy.moveToThread(self.gcode_copy_thread)

        self.gcode_copy_thread.started.connect(self.gcode_copy.write_file)

        self.gcode_copy.finished.connect(self.set_finished_copy)
        self.gcode_copy.set_update_progress.connect(update_function)

        self.gcode_copy_thread.start()
예제 #6
0
class VNCClient(QObject):
    started = pyqtSignal()
    finished = pyqtSignal()
    imageSizeChanged = pyqtSignal(QSize)
    imageChanged = pyqtSignal(int, int, int, int)
    passwordRequested = pyqtSignal(bool)
    textCut = pyqtSignal(unicode)

    def __init__(self, host, port, settings, parent=None):
        super(VNCClient, self).__init__(parent)
        self.thread = QThread()
        self.moveToThread(self.thread)
        self.host = host
        self.port = port
        self.settings = settings
        self.username = None
        self.password = None
        self.rfb_client = None
        self.socket_notifier = None
        self.thread.started.connect(self._SH_ThreadStarted)
        self.thread.finished.connect(self._SH_ThreadFinished)

    def _get_settings(self):
        return self.__dict__['settings']
    def _set_settings(self, settings):
        old_settings = self.__dict__.get('settings', None)
        if settings == old_settings:
            return
        self.__dict__['settings'] = settings
        if self.thread.isRunning():
            QApplication.postEvent(self, RFBConfigureClientEvent())
    settings = property(_get_settings, _set_settings)
    del _get_settings, _set_settings

    @property
    def image(self):
        return self.rfb_client.image if self.rfb_client is not None else None

    def start(self):
        self.thread.start()

    def stop(self):
        self.thread.quit()

    def key_event(self, key, down):
        if self.thread.isRunning():
            QApplication.postEvent(self, RFBKeyEvent(key, down))

    def mouse_event(self, x, y, button_mask):
        if self.thread.isRunning():
            QApplication.postEvent(self, RFBMouseEvent(x, y, button_mask))

    def cut_text_event(self, text):
        if text and self.thread.isRunning():
            QApplication.postEvent(self, RFBCutTextEvent(text))

    def _SH_ThreadStarted(self):
        self.started.emit()
        notification_center = NotificationCenter()
        notification_center.post_notification('VNCClientWillStart', sender=self)
        self.rfb_client = RFBClient(parent=self)
        try:
            self.rfb_client.connect()
        except RFBClientError:
            self.thread.quit()
        else:
            self.socket_notifier = QSocketNotifier(self.rfb_client.socket, QSocketNotifier.Read, self)
            self.socket_notifier.activated.connect(self._SH_SocketNotifierActivated)
            notification_center.post_notification('VNCClientDidStart', sender=self)

    def _SH_ThreadFinished(self):
        self.finished.emit()
        notification_center = NotificationCenter()
        notification_center.post_notification('VNCClientWillEnd', sender=self)
        if self.socket_notifier is not None:
            self.socket_notifier.activated.disconnect(self._SH_SocketNotifierActivated)
            self.socket_notifier = None
        self.rfb_client = None
        notification_center.post_notification('VNCClientDidEnd', sender=self)

    def _SH_SocketNotifierActivated(self, sock):
        self.socket_notifier.setEnabled(False)
        try:
            self.rfb_client.handle_server_message()
        except RFBClientError:
            self.thread.quit()
        else:
            self.socket_notifier.setEnabled(True)

    def _SH_ConfigureRFBClient(self):
        if self.rfb_client is not None:
            self.rfb_client.configure()

    def customEvent(self, event):
        handler = getattr(self, '_EH_%s' % event.name, Null)
        handler(event)

    def _EH_RFBConfigureClientEvent(self, event):
        if self.rfb_client is not None:
            self.rfb_client.configure()

    def _EH_RFBKeyEvent(self, event):
        if self.rfb_client is not None:
            self.rfb_client.send_key_event(event.key, event.down)

    def _EH_RFBMouseEvent(self, event):
        if self.rfb_client is not None:
            self.rfb_client.send_pointer_event(event.x, event.y, event.button_mask)

    def _EH_RFBCutTextEvent(self, event):
        if self.rfb_client is not None:
            self.rfb_client.send_client_cut_text(event.text)
class SensitiveLegendRaster(QObject):
    def __init__(self):
        super(SensitiveLegendRaster, self).__init__()  # QThread
        self.layer = self.worker = self.thread = None
        self.canvas = iface.mapCanvas()
        self.msgBar = iface.messageBar()
        self.legend = iface.legendInterface()
        self.nameModulus = "Script_Sensitive_Legend"
        #
        self.initThread()
        self._connect()
        #
        self.selectLayer(iface.activeLayer())

    def __del__(self):
        self.finishThread()
        self._connect(False)

    def printMsgBar(self, msg, typeMsg=QgsMessageBar.INFO):
        self.msgBar.popWidget()
        if typeMsg == QgsMessageBar.INFO:
            self.msgBar.pushMessage("SensitiveLegendRaster Script", msg, typeMsg)
        else:
            self.msgBar.pushMessage("SensitiveLegendRaster Script", msg, typeMsg, 5)

    def initThread(self):
        self.thread = QThread(self)
        self.thread.setObjectName(self.nameModulus)
        self.worker = WorkerSensitiveLegendRaster()
        self.worker.moveToThread(self.thread)
        self._connectWorker()

    def finishThread(self):
        self._connectWorker(False)
        self.worker.deleteLater()
        self.thread.wait()
        self.thread.deleteLater()
        self.thread = self.worker = None

    def _connectWorker(self, isConnect=True):
        ss = [
            {"signal": self.thread.started, "slot": self.worker.run},
            {"signal": self.worker.finished, "slot": self.finishedWorker},
            {"signal": self.worker.messageResult, "slot": self.messageResultWorker},
            {"signal": self.worker.messageStatus, "slot": self.messageStatusWorker},
        ]
        if isConnect:
            for item in ss:
                item["signal"].connect(item["slot"])
        else:
            for item in ss:
                item["signal"].disconnect(item["slot"])

    def _connect(self, isConnect=True):
        ss = [
            {"signal": self.legend.currentLayerChanged, "slot": self.selectLayer},
            {"signal": QgsMapLayerRegistry.instance().layerWillBeRemoved, "slot": self.unselectLayer},
            {"signal": self.canvas.extentsChanged, "slot": self.changeSensitiveLegend},
        ]
        if isConnect:
            for item in ss:
                item["signal"].connect(item["slot"])
        else:
            for item in ss:
                item["signal"].disconnect(item["slot"])

    @pyqtSlot()
    def finishedWorker(self):
        self.thread.quit()
        if self.worker.isKilled:  # When PAN/ZOOM/...
            self.thread.wait()
            self.changeSensitiveLegend()

    @pyqtSlot(str)
    def messageResultWorker(self, msg):
        self.printMsgBar(msg)

    @pyqtSlot(str)
    def messageStatusWorker(self, msg):
        self.printMsgBar(msg)

    @pyqtSlot("QgsMapLayer")
    def selectLayer(self, layer):

        if self.thread.isRunning():
            return

        isOk = True
        msg = ""
        typeMsg = QgsMessageBar.WARNING
        if not layer is None and layer.type() == QgsMapLayer.RasterLayer:
            legendColorAll = layer.legendSymbologyItems()
            if len(legendColorAll) > 0:  # Had a classification
                self.layer = layer
                self.worker.setLegendReadBlock(layer)
                msg = "Raster Layer '%s' actived" % layer.name()
                typeMsg = QgsMessageBar.INFO
            else:
                msg = "Raster Layer '%s' need be a classification" % layer.name()
                isOk = False
        else:
            if layer is None:
                msg = "Active a Raster layer"
            else:
                msg = "Layer '%s' need be a Raster" % layer.name()
            isOk = False

        self.printMsgBar(msg, typeMsg)

        return isOk

    @pyqtSlot(str)
    def unselectLayer(self, idLayer):
        if idLayer == self.layer.id():
            if self.thread.isRunning():
                self.worker.isKilled = True
            msg = "Raster Layer '%s' was removed" % self.layer.name()
            self.printMsgBar(msg, QgsMessageBar.WARNING)
            self.layer = None

    @pyqtSlot()
    def changeSensitiveLegend(self):

        if self.layer is None:
            return

        if self.thread.isRunning():
            self.worker.isKilled = True
            return

        mapSettings = self.canvas.mapSettings()
        crsCanvas = mapSettings.destinationCrs()
        extentCanvas = self.canvas.extent()

        extentLayer = self.layer.extent()
        resX = self.layer.rasterUnitsPerPixelX()
        resY = self.layer.rasterUnitsPerPixelY()

        if self.layer.crs() != crsCanvas:
            extentCanvas = mapSettings.mapToLayerCoordinates(self.layer, extentCanvas)

        if not extentCanvas.intersects(extentLayer):
            self.printMsgBar("View not intersects Raster '%s'" % self.layer.name, QgsMessageBar.WARNING)
            return

        keysLegend = range(len(self.worker.legendAll))  # [ idClass1, idClass2, ... ] [ 0..N-1]

        if extentCanvas == extentLayer or extentCanvas.contains(extentLayer):
            legendsView = map(lambda x: "(%s)%s" % (x, self.worker.legendAll[x]), keysLegend)
            msg = "[%d] = %s" % (len(legendsView), " ".join(legendsView))
            self.printMsgBar(msg)
            return

        extent = extentCanvas.intersect(extentLayer)
        widthRead = int(extent.width() / resX) + 1
        heightRead = int(extent.height() / resY) + 1

        self.worker.setProcessImage(extent, widthRead, heightRead)
        self.thread.start()
예제 #8
0
class MQTTClient(QtCore.QObject):
    """
    Wrapper class for Mosquitto MQTT client
    Provides inherited helper classes for SingleShot and Test requests
    Initial approach was to sub class QThread, but reading revealed that
    running the timers within a thread was the preferred approach.
    
    
    """

    kMaxAttempts    = 3
    kMinKeepAlive   = 5
    kResetTimer     = 60

    mqttOnConnect       = pyqtSignal(QObject,QObject,int)
    mqttOnDisConnect    = pyqtSignal(QObject,QObject,int)
    mqttOnMessage       = pyqtSignal(QObject,QObject,QObject)
    mqttOnPublish       = pyqtSignal(QObject,QObject,int)
    mqttOnSubscribe     = pyqtSignal(QObject,QObject,int,int)
    mqttOnLog           = pyqtSignal(str,int)
    mqttOnTimeout       = pyqtSignal(QObject)
    mqttConnectionError = pyqtSignal(QObject,str)

    # Hmmm new style signals cause problems with multiple parameters
    #    mqttConnectionError =  QtCore.pyqtSignal([str])

    # Add username/password
    def __init__(self,
                 creator,
                 clientId,
                 broker,
                 cleanSession=True):

        super(MQTTClient, self).__init__()
        # Load settings
        self._creator = creator

        # create client id
        self._cleanSession = cleanSession
        self._resetTimer = QTimer()
        self._resetTimer.setSingleShot(True)
        self._resetTimer.timeout.connect(self._reset)

        self._killTimer = QTimer()
        self._killTimer.setSingleShot(True)
        self._killTimer.timeout.connect(self._kill)
        self._killing = False

        self._loopTimer = QTimer()
        self._loopTimer.setSingleShot(False)
        self._loopTimer.timeout.connect(self._loop)
        self._clientId = clientId
        self._host = broker.host()
        self._port = int(broker.port())
        self._poll = int(broker.poll())
        self.setKeepAlive(broker.keepAlive())
        self._attempts = 0
        self._attempted = 0
        self._connected = False
        self._thread = QThread(self)
        self._thread.started.connect(lambda: self._loopTimer.start(self._poll))
        self._thread.finished.connect(self._loopTimer.stop)

        self._thread.started.connect(lambda:Log.debug("Thread started"))
        self._thread.finished.connect(lambda:Log.debug("Thread stopped"))
        self._thread.terminated.connect(lambda:Log.debug("Thread terminated"))
        self._restarting = False
        self._subscribed =[]
        
#        self.mqttc = mqtt.Client(self._clientId, self._cleanSession)
        self.mqttc = mqtt.Mosquitto(self._clientId, self._cleanSession)
        
        if broker.username(): # Basic Auth!
                self.mqttc.username_pw_set(broker.username(), broker.password())

        self.mqttc.on_connect = self.on_connect
        self.mqttc.on_disconnect = self.on_disconnect
        self.mqttc.on_message = self.onMessage
        self.mqttc.on_publish = self.onPublish
        self.mqttc.on_subscribe = self.onSubscribe
#        self.mqttc.on_unsubscribe = self.onSubscribe - not implemented - remove element from self._subscribed
        self.mqttc.on_log = self.onLog

    def _canRun(self):
           return True

    def run(self):
        Log.debug("MQTT client run")

        if self.isRunning() or self._killing:
            self.restart()
            return

        if self._restarting:
            self._thread.finished.disconnect(self.run)
            self._restarting = False

        self._thread.start(QThread.LowestPriority)

    def stop(self):
        self._thread.quit()  # emits finished
        Log.debug("Thread quit")

    def isRunning(self):
        return self._thread.isRunning()

    def _loop(self):
        if self._canRun():
            self.loop()

    def setHost(self, host):
        self._host = host

    def host(self):
        return self._host

    def setPort(self, port):
        self._port = int(port)

    def port(self):
        return self._port

    def setPoll(self, poll):
        self._poll = int(poll)

    def setKeepAlive(self, keepAlive):
        self._keepAlive = max(int(keepAlive) + int(self._poll), self.kMinKeepAlive)

    def getClientId(self):
        return self._clientId

    def on_connect(self, client, obj,flags, rc):   # paho
#    def on_connect(self, client, obj, rc): # mosquitto
        Log.debug("Connected " + str(rc))
        if rc != mqtt.MQTT_ERR_SUCCESS: # paho
#        if rc != mqtt.MOSQ_ERR_SUCCESS: # mosquitto
            return
        self._connected = True
        self._attempts = 0
        self._subscribed =[]

        self.onConnect(client, obj, rc)

    def restart(self):
     
        Log.debug("Restarting")
        if self.isRunning():
            self._restarting = True
            self._thread.finished.connect(self.run)
            if not self._killing:
                self.kill()
        else:
            self.run()


    def on_disconnect(self, client, obj, rc):
        Log.debug("disconnecting rc: " + str(rc) + " " + str(self._connected))
        if self._killing:
            Log.debug("killing")
            self._kill()
        self.onDisConnect(client, obj, rc)
        self._connected = False

    def onConnect(self, client, obj, rc):
        self.mqttOnConnect.emit(self, obj, rc)
#        QObject.emit(self, SIGNAL('mqttOnConnect'), self, obj, rc)
        pass

    def onDisConnect(self, client, obj, rc):
        self.mqttOnDisConnect.emit(self,obj,rc)
#        QObject.emit(self, SIGNAL('mqttOnDisConnect'), self, obj, rc)
        pass


    def onMessage(self, client, obj, msg):
        self.mqttOnMessage.emit(self,obj,msg)
#        QObject.emit(self, SIGNAL('mqttOnMessage'), self, obj, msg)
        # Log.debug('super ' + msg.topic+" "+str(msg.qos)+" "+str(msg.payload))

    def onPublish(self, client, obj, mid):
        self.mqttOnPublish.emit(self,obj,mid)
        # QObject.emit(self._creator, SIGNAL('mqttOnPublish'), self, obj, mid)
        Log.debug("onPublish - Message ID: " + str(mid))

    def onSubscribe(self, client, obj, mid, granted_qos):
        self.mqttOnSubscribe.emit(self, obj, mid, granted_qos)
        Log.info("Subscribed: " + str(mid) + " " + str(granted_qos))

    def onLog(self, client, obj, level, msg):
        self.mqttOnLog.emit(msg, level)
        #Log.debug(string,level)

    def isConnected(self):
        return self.mqttc.socket() is not None and self._connected

    def publish(self, topic, payload, qos=0, retain=True):
        self.mqttc.publish(str(topic), payload, int(qos), retain)   

    def subscribe(self, topic, qos =0):
        if self.isConnected() and not str(topic) in self._subscribed:
            try:
                self.mqttc.subscribe(str(topic), int(qos))
                self._subscribed.append(str(topic))
                Log.debug('Subscribed to ' + topic + " " + str(qos))
            except Exception as e:
                Log.debug("Error on subscribe " + str(e))
                raise e

    def unsubscribe(self, topic):
        if self.isConnected():
            self.mqttc.unsubscribe(topic)
            Log.debug('Un_subscribed to ' + topic)

    def loop(self, timeout=0.1):
        if not self.isConnected():
            if not self._killing:
                self._connect()
            return
        try:
            connResult = self.mqttc.loop(timeout)
            if connResult == mqtt.MQTT_ERR_SUCCESS: # paho
#            if connResult == mqtt.MOSQ_ERR_SUCCESS: # mosquitto
                return
            
            self._connected = False
            self._attempts += 1
            
            Log.warn("MQTT: An error occurred while looping")
            self.mqttConnectionError.emit(self, mqtt.error_string(connResult))
        except ValueError as e:
            if e == 'Invalid timeout.':
                self.mqttOnTimeout.emit(self, "Connection Timeout")
            else:
                Log.debug("Paho Client ValueError" + str(e))
        except Exception as e:
            self.mqttConnectionError.emit(self, str(e))
            Log.debug("MQTT Connect: Unknown exception raised "  + str(e))
            exc_type, exc_value, exc_traceback = sys.exc_info()
            Log.debug(repr(traceback.format_exception(exc_type, exc_value,
                                                     exc_traceback)))


    def _kill(self):
        self._loopTimer.stop()  # Stopped in self.stop but lets preempt this to avoid self.loop being called by running thread
        self._killTimer.stop()
        self._killing = False
        self._reset() # reset timer
        self.stop()

    def kill(self):
        try:
            if self.isConnected():
                self._disconnect()
            self._killing = True
            self._killTimer.start(self._keepAlive)
        except Exception as e:
            Log.warn("Error cleaning up " + str(e))
        pass

    def _connect(self):
        try:
            if not self._connected:
                if not self._attempts < self.kMaxAttempts:
                    if not self._resetTimer.isActive():
                        Log.progress(Settings.getMeta("name") + ": Max connection attempts reached - waiting " + str(self.kResetTimer) + " seconds before retrying" )
                        self._resetTimer.start(self.kResetTimer*1000)  # 1 minute parameterise
                    return
                if self._attempts > 0 and (time.time() - pow(2,self._attempts +1)) < self._attemped:
                        return
                Log.debug("Trying to connect")
                self._attemped = time.time()
                result = self.mqttc.connect(str(self._host), int(self._port),int( self._keepAlive), 1)
                self._connected = result == mqtt.MQTT_ERR_SUCCESS # paho
#                self._connected = result == mqtt.MOSQ_ERR_SUCCESS # mosquitto
                if not self._connected:
                    self._attempts += 1
                    Log.progress(mqtt.connack_string(connResult))
                    self.mqttConnectionError.emit(self, mqtt.connack_string(connResult))
 
        except Exception as e:
            msg = 'MQTT: ' + str(e)

            self.mqttConnectionError.emit(self, msg)
            #Log.progress(msg)
            Log.debug(msg)
            #exc_type, exc_value, exc_traceback = sys.exc_info()
            #Log.debug(repr(traceback.format_exception(exc_type, exc_value,
             #                                         exc_traceback)))
            self._attempts += 1
            self._connected = False


    def _disconnect(self):
        try:
            self.mqttc.disconnect()
        except Exception as e:
            Log.warn('MQTT Disconnection Error' + str(e))

    def _reset(self):
        Log.warn("Timer reset ")
        self._attempts = 0
        self._resetTimer.stop() # not required
class v_calculator_main(QObject):
    """QGIS Plugin Implementation."""

    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgisInterface
        """
        super(v_calculator_main, self).__init__()
        self.calculation_thread = QThread(self)
        self.calculation_worker = None

        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n',
            'vegetation_calculator_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        self.menu = self.getTranslation(u'&Vegetation calculator')
        # We are going to let the user set this up in a future iteration
        self.toolbar = self.iface.addToolBar(u'vegetation_calculator')
        self.toolbar.setObjectName(u'vegetation_calculator')

        self.LOGGER = logging.getLogger("calculator_logger")
        if len(self.LOGGER.handlers) == 0:
            format_log = \
                "%(asctime)s - [%(levelname)s] -  %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"
            fh = RotatingFileHandler(filename=os.path.join(self.plugin_dir, "calculator.log"),
                                     maxBytes=5 * 1024 * 1024,
                                     backupCount=5)
            fh.setFormatter(logging.Formatter(format_log))
            self.LOGGER.addHandler(fh)
            self.LOGGER.setLevel(logging.DEBUG)

    # noinspection PyMethodMayBeStatic
    def getTranslation(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('v_calculator_main', message)

    def add_action(
            self,
            icon_path,
            text,
            callback,
            enabled_flag=True,
            add_to_menu=True,
            add_to_toolbar=True,
            status_tip=None,
            whats_this=None,
            parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        # Create the dialog (after translation) and keep reference
        self.dlg = vegetation_calculatorDialog()
        self.initHandlers()

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToRasterMenu(
                self.menu,
                action)

        self.actions.append(action)

        return action

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        icon_path = os.path.join(self.plugin_dir, 'icon.png')
        self.add_action(
            icon_path,
            text=self.getTranslation(u'Open calculator'),
            callback=self.run,
            parent=self.iface.mainWindow())

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginRasterMenu(
                self.getTranslation(u'&Vegetation calculator'),
                action)
            self.iface.removeToolBarIcon(action)
        # remove the toolbar
        del self.toolbar

    def initHandlers(self):
        """
        Initializes handlers for UI element events.
        """

        self.LOGGER.debug("init handlers")

        self.dlg.accepted.connect(self.startCalculation)

        self.dlg.cbx_ndvi_redLayer.currentIndexChanged.connect(self.showLayerBandsForNdviRed)
        self.dlg.cbx_ndvi_infraredLayer.currentIndexChanged.connect(self.showLayerBandsForNdviInfrared)
        self.dlg.cbx_agr_swirLayer.currentIndexChanged.connect(self.showLayerBandsForAgroSwir)
        self.dlg.cbx_agr_nnirLayer.currentIndexChanged.connect(self.showLayerBandsForAgroIr)
        self.dlg.cbx_agr_blueLayer.currentIndexChanged.connect(self.showLayerBandsForAgroBlue)

    def run(self):
        """Run method that performs all the real work"""
        logging.info("start")

        layers = QgsMapLayerRegistry.instance().mapLayers()

        self.showLayersLists(layers)
        self.showColorSchemes()

        # show the dialog
        self.LOGGER.debug("show the dialog")
        self.dlg.show()
        self.LOGGER.debug("run the dialog event loop")
        # Run the dialog event loop
        result = self.dlg.exec_()
        self.LOGGER.info("end")

    def showLayersLists(self, layers):
        """
        Display a list of raster layers on the UI.

        :param layers: layers to displaying.
        :type: [QgsMapLayer, ...]
        """

        self.LOGGER.debug("showing layers lists")

        self.dlg.cbx_ndvi_redLayer.clear()
        self.dlg.cbx_ndvi_infraredLayer.clear()
        self.dlg.cbx_agr_swirLayer.clear()
        self.dlg.cbx_agr_nnirLayer.clear()
        self.dlg.cbx_agr_blueLayer.clear()

        layer_names = []
        for name, layer in layers.iteritems():
            if layer.type() == 1:  # 1 = raster layer
                layer_names.append(layer.name())

        layer_names.sort(cmp=locale.strcoll)

        self.dlg.cbx_ndvi_redLayer.addItems(layer_names)
        self.dlg.cbx_ndvi_infraredLayer.addItems(layer_names)
        self.dlg.cbx_agr_swirLayer.addItems(layer_names)
        self.dlg.cbx_agr_nnirLayer.addItems(layer_names)
        self.dlg.cbx_agr_blueLayer.addItems(layer_names)

    def showLayerBandsForNdviRed(self, index):
        """
        Display bands of selected layer with red band for NDVI.

        :param index: index of an item in the QCombobox.
        :type: int
        """

        self.LOGGER.debug("showing bands of the red layer (NDVI)")

        layer_name = self.dlg.cbx_ndvi_redLayer.itemText(index)
        self.showLayerBands(self.dlg.lstw_ndvi_redBands, layer_name, 3)  # 3 = red

    def showLayerBandsForNdviInfrared(self, index):
        """
        Display bands of selected layer with infrared band for NDVI.

        :param index: index of an item in the QCombobox.
        :type: int
        """

        self.LOGGER.debug("showing bands of the infrared layer (NDVI)")

        layer_name = self.dlg.cbx_ndvi_infraredLayer.itemText(index)
        self.showLayerBands(self.dlg.lstw_ndvi_infraredBands, layer_name, 0)  # 0 = undefined color

    def showLayerBandsForAgroSwir(self, index):
        """
        Display bands of selected layer with SWIR (short wave infrared) band for agriculture or healthy vegetation.

        :param index: index of an item in the QCombobox.
        :type: int
        """

        self.LOGGER.debug("showing bands of the SWIR layer (agriculture and HV)")

        layer_name = self.dlg.cbx_agr_swirLayer.itemText(index)
        self.showLayerBands(self.dlg.lstw_agr_swirBands, layer_name, 0)  # 0 = undefined color

    def showLayerBandsForAgroIr(self, index):
        """
        Display bands of selected layer with infrared band for agriculture or healthy vegetation.

        :param index: index of an item in the QCombobox.
        :type: int
        """

        self.LOGGER.debug("showing bands of the IR layer (agriculture and HV)")

        layer_name = self.dlg.cbx_agr_nnirLayer.itemText(index)
        self.showLayerBands(self.dlg.lstw_agr_nnirBands, layer_name, 0)  # 0 = undefined color

    def showLayerBandsForAgroBlue(self, index):
        """
        Display bands of selected layer with blue band for agriculture or healthy vegetation.

        :param index: index of an item in the QCombobox.
        :type: int
        """

        self.LOGGER.debug("showing bands of the blue layer (agriculture and HV)")

        layer_name = self.dlg.cbx_agr_blueLayer.itemText(index)
        self.showLayerBands(self.dlg.lstw_agr_blueBands, layer_name, 5)  # 5 = blue

    def showLayerBands(self, qListWidget, layer_name, color_interpretation=None):
        """
        Display bands of the layer into the QListWidget.

        :param qListWidget: A QListWidget on the UI.
        :type QListWidget

        :param layer_name: A name of layer with bands to display
        :type: unicode

        :param color_interpretation: Color interpretation for automatic band selection.
        :type: int
        """

        self.LOGGER.debug("showing bands of %s", layer_name)

        try:
            raster_layer = QgsMapLayerRegistry.instance().mapLayersByName(layer_name)[0]
        except IndexError:
            return
        bands_dictionary = self.getBandsFromLayer(raster_layer)
        sorted(bands_dictionary)

        qListWidget.clear()

        index = 0
        band_number = None
        for band_information in bands_dictionary.values():
            qListWidget.addItem(band_information.full_name)
            if band_number is None and band_information.color_interpretation == color_interpretation:
                band_number = index
            index += 1

        if band_number is not None:
            qListWidget.setCurrentRow(band_number)
        else:
            qListWidget.setCurrentRow(0)

    def getBandsFromLayer(self, raster_layer):
        """
        Get bands of the raster layer.

        :param raster_layer: A layer to get channels from.
        :type: QgsRasterLayer

        :return: dictionary of BandInformation.
        :type: {unicode: BandInformation}
        """

        self.LOGGER.debug("getting bands of %s", raster_layer.name())

        layer_data_provider = raster_layer.dataProvider()

        bands = {}
        for band_number in range(1, raster_layer.bandCount() + 1):
            band = BandInformation(layer_data_provider.colorInterpretationName(band_number),
                                   band_number,
                                   layer_data_provider.colorInterpretation(band_number))
            bands[band.full_name] = band

        return OrderedDict(sorted(bands.items()))

    def showColorSchemes(self):
        """
        Display color schemes.
        """
        self.LOGGER.debug("showing color schemes")

        self.dlg.cbx_color_schemes.clear()
        color_schemes = OrderedDict(sorted(ColorsForNdviMap().colorSchemes.items()))

        for color_scheme_name in color_schemes:
            color_scheme = color_schemes[color_scheme_name]
            icon_pixmap = QPixmap(50, 20)
            painter = QPainter(icon_pixmap)

            painter.fillRect(0, 0, 10, 20, color_scheme["ndvi_0"])
            painter.fillRect(10, 0, 20, 20, color_scheme["ndvi_0.25"])
            painter.fillRect(20, 0, 30, 20, color_scheme["ndvi_0.5"])
            painter.fillRect(30, 0, 40, 20, color_scheme["ndvi_0.75"])
            painter.fillRect(40, 0, 50, 20, color_scheme["ndvi_1"])
            painter.end()

            icon = QIcon(icon_pixmap)
            self.dlg.cbx_color_schemes.addItem(icon, color_scheme_name)

    def startCalculation(self):
        """
        Start calculating NDVI, agriculture or healthy vegetation
        """

        self.LOGGER.debug("start calculation")

        if self.calculation_thread.isRunning() is True:
            return

        if self.dlg.tabw_content.currentIndex() == 0:  # NDVI
            if self.dlg.rbtn_calculateNdvi.isChecked():
                self.calculateNdvi()
            elif self.dlg.rbtn_openNdviFile.isChecked():
                try:
                    input_file_name = self.dlg.led_ndvi_inputFile.text()
                    self.validateInputFilePath(input_file_name)
                except CalculatorException as exp:
                    self.LOGGER.info(exp.message)
                    self.dlg.show_error_message(self.getTranslation(exp.title), self.getTranslation(exp.message))
                    return
                self.openNdviFile(input_file_name)
        elif self.dlg.tabw_content.currentIndex() == 1:  # Agriculture and HV
            self.calculateAgricultureOrHv()

    def calculateAgricultureOrHv(self):
        """
        Start calculating agriculture or healthy vegetation
        """

        self.LOGGER.info("start agriculture or hv calculation")
        self.LOGGER.info("Agriculture: %s", self.dlg.rbtn_agr_agriculture.isChecked())
        self.LOGGER.info("HV: %s", self.dlg.rbtn_agr_hv.isChecked())

        if self.dlg.cbx_agr_swirLayer.count() == 0 or \
                self.dlg.cbx_agr_nnirLayer.count() == 0 or \
                self.dlg.cbx_agr_blueLayer.count() == 0:
            self.LOGGER.info("Layers not found")
            self.dlg.show_error_message(self.getTranslation("Error"), self.getTranslation("Layers not found"))
            return

        self.LOGGER.info("SWIR: %s", self.dlg.cbx_agr_swirLayer.currentText())
        self.LOGGER.info("NNIR: %s", self.dlg.cbx_agr_nnirLayer.currentText())
        self.LOGGER.info("blue: %s", self.dlg.cbx_agr_blueLayer.currentText())

        output_file_name = self.dlg.led_agr_outputFile.text()

        try:
            self.validateOutputFilePath(output_file_name)
            swir_layer = self.getLayerByName(self.dlg.cbx_agr_swirLayer.currentText())
            nnir_layer = self.getLayerByName(self.dlg.cbx_agr_nnirLayer.currentText())
            blue_layer = self.getLayerByName(self.dlg.cbx_agr_blueLayer.currentText())

            swir_band = self.getBandsFromLayer(swir_layer)[self.getCurrentBandName(self.dlg.lstw_agr_swirBands)]
            nnir_band = self.getBandsFromLayer(nnir_layer)[self.getCurrentBandName(self.dlg.lstw_agr_nnirBands)]
            blue_band = self.getBandsFromLayer(blue_layer)[self.getCurrentBandName(self.dlg.lstw_agr_blueBands)]
        except CalculatorException as exp:
            self.LOGGER.info(exp.message)
            self.dlg.show_error_message(self.getTranslation(exp.title), self.getTranslation(exp.message))
            return

        if self.dlg.rbtn_agr_agriculture.isChecked():
            layer_list = [(swir_layer, swir_band.serial_number),
                          (nnir_layer, nnir_band.serial_number),
                          (blue_layer, blue_band.serial_number)]
        elif self.dlg.rbtn_agr_hv.isChecked():
            layer_list = [(nnir_layer, nnir_band.serial_number),
                          (swir_layer, swir_band.serial_number),
                          (blue_layer, blue_band.serial_number)]
        else:
            return

        self.dlg.enable_load_mode()

        self.calculation_worker = RasterLayerHandler(output_file_name, layer_list)
        self.calculation_worker.moveToThread(self.calculation_thread)
        self.calculation_thread.started.connect(self.calculation_worker.combine_bands)
        self.calculation_worker.warning.connect(self.showWarning)
        self.calculation_worker.finished.connect(self.finishAgricultureOrHvCalculation)
        self.calculation_thread.start()

    def calculateNdvi(self):
        """
        Start calculating NDVI
        """

        self.LOGGER.info("start NDVI calculation")

        if self.dlg.cbx_ndvi_redLayer.count() == 0 or \
                self.dlg.cbx_ndvi_infraredLayer.count() == 0:
            self.LOGGER.info("Layers not found")
            self.dlg.show_error_message(self.getTranslation("Error"), self.getTranslation("Layers not found"))
            return

        self.LOGGER.info("red: %s", self.dlg.cbx_ndvi_redLayer.currentText())
        self.LOGGER.info("red band number: %s", self.dlg.lstw_ndvi_redBands.currentItem().text())
        self.LOGGER.info("IR: %s", self.dlg.cbx_ndvi_infraredLayer.currentText())
        self.LOGGER.info("IR band number: %s", self.dlg.lstw_ndvi_infraredBands.currentItem().text)

        output_file_name = self.dlg.led_ndvi_outputFile.text()

        try:
            self.validateOutputFilePath(output_file_name)
            red_layer_for_calculation = self.getCurrentLayerWithRedBand()
            infrared_layer_for_calculation = self.getCurrentLayerWithInfraredBand()

            bands = self.getBandsFromLayer(red_layer_for_calculation)
            red_band = bands[self.getCurrentBandName(self.dlg.lstw_ndvi_redBands)]

            bands = self.getBandsFromLayer(infrared_layer_for_calculation)
            infrared_band = bands[self.getCurrentBandName(self.dlg.lstw_ndvi_infraredBands)]
        except CalculatorException as exp:
            self.LOGGER.info(exp.message)
            self.dlg.show_error_message(self.getTranslation(exp.title), self.getTranslation(exp.message))
            return

        self.dlg.enable_load_mode()

        self.calculation_worker = NdviCalculator(red_layer_for_calculation, infrared_layer_for_calculation,
                                                 red_band.serial_number, infrared_band.serial_number, output_file_name)
        self.calculation_worker.moveToThread(self.calculation_thread)
        self.calculation_thread.started.connect(self.calculation_worker.run)
        self.calculation_worker.finished.connect(self.finishCalculationNdvi)
        self.calculation_thread.start()

    def getCurrentLayerWithRedBand(self):
        """
        Get user selected layer with red band.

        :raise CalculatorException: layer with this name not found
        """

        self.LOGGER.debug("getting current a layer with red band")

        layer_name = self.dlg.cbx_ndvi_redLayer.currentText()
        return self.getLayerByName(layer_name)

    def getCurrentLayerWithInfraredBand(self):
        """
        Get user selected layer with infrared band.

        :raise CalculatorException: layer with this name not found
        """

        self.LOGGER.debug("getting current a layer with IR band")

        layer_name = self.dlg.cbx_ndvi_infraredLayer.currentText()
        return self.getLayerByName(layer_name)

    def getLayerByName(self, layer_name):
        """
        Get layer by name.

        :param layer_name: layer name
        :type: unicode

        :return: QGis layer
        :type: QgsMapLayer

        :raise CalculatorException: layer with this name not found
        """

        self.LOGGER.debug("getting a layer by name: %s", layer_name)

        try:
            return QgsMapLayerRegistry.instance().mapLayersByName(layer_name)[0]
        except IndexError:
            raise CalculatorException("Layer not found", "One of the specified layers was not found")

    def getCurrentBandName(self, lstw_ndv):
        """
        Get text from QListView with band name

        :param lstw_ndv: QListView with band name
        :type: QListView

        :return: band name
        :type: unicode
        """

        self.LOGGER.debug("getting current band name from the UI. Band name: %s", lstw_ndv.currentItem().text())

        return lstw_ndv.currentItem().text()

    def validateInputFilePath(self, file_path):
        """
        Checking for the correctness of the path to the file to be opened.

        :param file_path: file path
        :type: unicode

        :raise CalculatorException: the file is not exist
        """

        self.LOGGER.debug("validating input file path: %s", file_path)

        if not os.path.exists(file_path):
            self.LOGGER.info("input file - file do not exist")
            raise CalculatorException("File error", "File does not exist")

    def validateOutputFilePath(self, file_path):
        """
        Checking for the correctness of the path to the file to be created.

        :param file_path: file path
        :type: unicode

        :raise CalculatorException: the path is not correct
        """

        self.LOGGER.debug("validating output file path: %s", file_path)

        if not file_path:
            self.LOGGER.info("output file - file path is None")
            raise CalculatorException("File error", "File path is empty")

        file_path_copy = copy.copy(file_path)
        pattern = re.compile(ur"/(?u)\w+.tif$")

        try:
            file_name = pattern.search(file_path_copy).group(0)
        except AttributeError:
            self.LOGGER.info("output file - incorrect file name")
            raise CalculatorException("File error", "Incorrect file name")

        directory_name = pattern.sub(u"", file_path_copy)
        if not os.path.isdir(directory_name):
            self.LOGGER.info("output file - incorrect directory name")
            raise CalculatorException("File error", "Incorrect directory name")

    def finishCalculationNdvi(self, output_file_name):
        """
        Completion of NDVI calculation.

        Unlocking UI and opening file with NDVI.
        Callback for calculation thread.

        :param output_file_name: path to file with NDVI
        :type: unicode
        """

        self.LOGGER.debug("end of NDVI calculation")

        self.calculation_thread.quit()
        self.dlg.disable_load_mode()
        self.openNdviFile(output_file_name)

    def openNdviFile(self, file_name):
        """
        Open file with NDVI

        :param file_name: path to file with NDVI
        :type: unicode
        """

        self.LOGGER.info("opening NDVI file: %s", file_name)

        try:
            self.validateInputFilePath(file_name)
        except CalculatorException as e:
            self.LOGGER.info(e.message)
            self.dlg.show_error_message(self.getTranslation(e.title), self.getTranslation(e.message))
            return

        ndvi0_raster_layer = QgsRasterLayer(file_name, "NDVI - <0")

        layer_data_type = ndvi0_raster_layer.dataProvider().dataType(1)
        ndvi_thresholds = NdviThreshold().dataTypes.get(layer_data_type)
        if ndvi_thresholds is None:
            self.LOGGER.info("NDVI file - unknown data type")
            self.dlg.show_error_message(self.getTranslation("NDVI file open error"),
                                        self.getTranslation("Unknown data type"))
            ndvi_raster_layer = QgsRasterLayer(file_name, "NDVI")
            map_layer_registry = QgsMapLayerRegistry.instance()
            map_layer_registry.addMapLayer(ndvi_raster_layer)
            return

        ndvi025_raster_layer = QgsRasterLayer(file_name, "NDVI - 0-0.25")
        ndvi05_raster_layer = QgsRasterLayer(file_name, "NDVI - 0.25-0.5")
        ndvi075_raster_layer = QgsRasterLayer(file_name, "NDVI - 0.5-0.75")
        ndvi1_raster_layer = QgsRasterLayer(file_name, "NDVI - 0.75-1")

        algorithm = QgsContrastEnhancement.StretchToMinimumMaximum
        limits = QgsRaster.ContrastEnhancementMinMax
        ndvi0_raster_layer.setContrastEnhancement(algorithm, limits)
        ndvi025_raster_layer.setContrastEnhancement(algorithm, limits)
        ndvi05_raster_layer.setContrastEnhancement(algorithm, limits)
        ndvi075_raster_layer.setContrastEnhancement(algorithm, limits)
        ndvi1_raster_layer.setContrastEnhancement(algorithm, limits)

        colors_scheme = ColorsForNdviMap().getColorScheme(self.dlg.cbx_color_schemes.currentText())
        ndvi0_raster_layer.setRenderer(
            self.getRenderer(ndvi0_raster_layer.dataProvider(),
                             self.getColorMapForNdvi0(colors_scheme, ndvi_thresholds)))
        ndvi025_raster_layer.setRenderer(
            self.getRenderer(ndvi025_raster_layer.dataProvider(),
                             self.getColorMapForNdvi025(colors_scheme, ndvi_thresholds)))
        ndvi05_raster_layer.setRenderer(
            self.getRenderer(ndvi05_raster_layer.dataProvider(),
                             self.getColorMapForNdvi05(colors_scheme, ndvi_thresholds)))
        ndvi075_raster_layer.setRenderer(
            self.getRenderer(ndvi075_raster_layer.dataProvider(),
                             self.getColorMapForNdvi075(colors_scheme, ndvi_thresholds)))
        ndvi1_raster_layer.setRenderer(
            self.getRenderer(ndvi1_raster_layer.dataProvider(),
                             self.getColorMapForNdvi1(colors_scheme, ndvi_thresholds)))

        map_layer_registry = QgsMapLayerRegistry.instance()
        map_layer_registry.addMapLayer(ndvi0_raster_layer)
        map_layer_registry.addMapLayer(ndvi025_raster_layer)
        map_layer_registry.addMapLayer(ndvi05_raster_layer)
        map_layer_registry.addMapLayer(ndvi075_raster_layer)
        map_layer_registry.addMapLayer(ndvi1_raster_layer)

    def getRenderer(self, layer_data_provider, color_map):
        """
        Get QgsSingleBandPseudoColorRenderer for NDVI display.

        :param layer_data_provider: layer data provider
        :type: QgsDataProvider

        :param color_map: color list
        :type: [ColorRampItem...]

        :return: QgsSingleBandPseudoColorRenderer
        """

        self.LOGGER.debug("getting renderer")

        raster_shader = QgsRasterShader()
        color_ramp_shader = QgsColorRampShader()
        color_ramp_shader.setColorRampType(QgsColorRampShader.DISCRETE)

        color_ramp_shader.setColorRampItemList(color_map)
        raster_shader.setRasterShaderFunction(color_ramp_shader)
        return QgsSingleBandPseudoColorRenderer(layer_data_provider, 1, raster_shader)

    def getColorMapForNdvi0(self, color_scheme, ndvi_thresholds):
        """
        Get list of colors for layer with NDVI less than 0

        :param color_scheme: color scheme (described in colors_for_ndvi_map.py)
        :type: {str: QColor}

        :param ndvi_thresholds: NDVI thresholds for the current data type
        :type: NdviThreshold.DataType

        :return: color list
        :type: [ColorRampItem...]
        """

        self.LOGGER.debug("getting color map for NDVI 0")

        color_list = []
        qri = QgsColorRampShader.ColorRampItem
        color_list.append(qri(ndvi_thresholds.ndvi0, color_scheme["ndvi_0"], "<0"))
        color_list.append(qri(ndvi_thresholds.ndvi1, QColor(0, 0, 0, 0), ">0"))
        return color_list

    def getColorMapForNdvi025(self, color_scheme, ndvi_thresholds):
        """
        Get a list of colors for a layer with NDVI from 0 to 0.25.

        :param color_scheme: color scheme (described in colors_for_ndvi_map.py)
        :type: {str: QColor}

        :param ndvi_thresholds: NDVI thresholds for the current data type
        :type: NdviThreshold.DataType

        :return: color list
        :type: [ColorRampItem...]
        """

        self.LOGGER.debug("getting color map for NDVI 0.25")

        color_list = []
        qri = QgsColorRampShader.ColorRampItem
        color_list.append(qri(ndvi_thresholds.ndvi0, QColor(0, 0, 0, 0), "<0"))
        color_list.append(qri(ndvi_thresholds.ndvi025, color_scheme["ndvi_0.25"], "0-0.25"))
        color_list.append(qri(ndvi_thresholds.ndvi1, QColor(0, 0, 0, 0), ">0.25"))
        return color_list

    def getColorMapForNdvi05(self, color_scheme, ndvi_thresholds):
        """
        Get a list of colors for a layer with NDVI from 0.25 to 0.5.

        :param color_scheme: color scheme (described in colors_for_ndvi_map.py)
        :type: {str: QColor}

        :param ndvi_thresholds: NDVI thresholds for the current data type
        :type: NdviThreshold.DataType

        :return: color list
        :type: [ColorRampItem...]
        """

        self.LOGGER.debug("getting color map for NDVI 0.5")

        color_list = []
        qri = QgsColorRampShader.ColorRampItem
        color_list.append(qri(ndvi_thresholds.ndvi025, QColor(0, 0, 0, 0), "<0.25"))
        color_list.append(qri(ndvi_thresholds.ndvi05, color_scheme["ndvi_0.5"], "0.25-0.5"))
        color_list.append(qri(ndvi_thresholds.ndvi1, QColor(0, 0, 0, 0), ">0.5"))
        return color_list

    def getColorMapForNdvi075(self, color_scheme, ndvi_thresholds):
        """
        Get a list of colors for a layer with NDVI from 0.5 to 0.75.

        :param color_scheme: color scheme (described in colors_for_ndvi_map.py)
        :type: {str: QColor}

        :param ndvi_thresholds: NDVI thresholds for the current data type
        :type: NdviThreshold.DataType

        :return: color list
        :type: [ColorRampItem...]
        """

        self.LOGGER.debug("getting color map for NDVI 0.75")

        color_list = []
        qri = QgsColorRampShader.ColorRampItem
        color_list.append(qri(ndvi_thresholds.ndvi05, QColor(0, 0, 0, 0), "<0.5"))
        color_list.append(qri(ndvi_thresholds.ndvi075, color_scheme["ndvi_0.75"], "0.5-0.75"))
        color_list.append(qri(ndvi_thresholds.ndvi1, QColor(0, 0, 0, 0), ">0.75"))
        return color_list

    def getColorMapForNdvi1(self, color_scheme, ndvi_thresholds):
        """
        Get a list of colors for a layer with NDVI from 0.75 to 1.

        :param color_scheme: color scheme (described in colors_for_ndvi_map.py)
        :type: {str: QColor}

        :param ndvi_thresholds: NDVI thresholds for the current data type
        :type: NdviThreshold.DataType

        :return: color list
        :type: [ColorRampItem...]
        """

        self.LOGGER.debug("getting color map for NDVI 1")

        color_list = []
        qri = QgsColorRampShader.ColorRampItem
        color_list.append(qri(ndvi_thresholds.ndvi075, QColor(0, 0, 0, 0), "<0.75"))
        color_list.append(qri(ndvi_thresholds.ndvi1, color_scheme["ndvi_1"], ">0.75"))
        return color_list

    def showWarning(self, message):
        """
        Display warning window.

        :param message: warning text
        :type: unicode
        """

        self.LOGGER.debug("showing warning dialog. message: %s", message)

        self.dlg.show_error_message(self.getTranslation("Warning"), self.getTranslation(message))

    def finishAgricultureOrHvCalculation(self, status, message, output_file_name):
        """
        Completion of agriculture or healthy vegetation calculation.

        Unlocking UI and opening file with result.
        Callback for calculation thread.

        :param output_file_name: path to file with agriculture or HV
        :type: unicode
        """

        self.LOGGER.debug("end of agriculture or HV calculation")

        self.calculation_thread.quit()
        self.dlg.disable_load_mode()

        if status is False:
            self.dlg.show_error_message(self.getTranslation("Calculation error"), self.getTranslation(message))
        else:
            self.openAgricultureOrHvFile(output_file_name)

    def openAgricultureOrHvFile(self, input_file_name):
        """
        Open file with agriculture or healthy vegetation.

        :param input_file_name: path to file with agriculture or healthy vegetation
        :type: unicode
        """

        self.LOGGER.info("opening agriculture or HV file %s", input_file_name)

        if self.dlg.rbtn_agr_agriculture.isChecked():
            layer_name = "Agriculture"
        elif self.dlg.rbtn_agr_hv.isChecked():
            layer_name = "Healthy_Vegetation"
        else:
            return

        raster_layer = QgsRasterLayer(input_file_name, layer_name)
        map_layer_registry = QgsMapLayerRegistry.instance()
        map_layer_registry.addMapLayer(raster_layer)
예제 #10
0
class RasterLegendSensitive(QObject):
    def __init__(self, iface, treeView, ckEnabled):
        super(RasterLegendSensitive, self).__init__()
        self.tree = TreeLegend(treeView)
        self.ckEnabled = ckEnabled
        #
        self.layer = self.worker = self.thread = self.transparencyLayer = None
        self.isExtentLayer = self.valuesFullExtent = None
        self.hasConnect = self.hasConnectTree = None
        self.iface = iface
        self.legend = iface.legendInterface()
        self.canvas = iface.mapCanvas()
        self.msgBar = iface.messageBar()
        self.nameModulus = "RasterLegendSensitive"
        #
        self.initThread()
        self._connect()
        self._connectTree()

    def __del__(self):
        del self.tree
        self.finishThread()
        if not self.hasConnect:
            self._connect(False)
        if not self.layer is None:
            self.setTransparenceLayer([])

    def initThread(self):
        self.thread = QThread(self)
        self.thread.setObjectName(self.nameModulus)
        self.worker = WorkerRasterLegendSensitive()
        self.worker.moveToThread(self.thread)
        self._connectWorker()

    def finishThread(self):
        self._connectWorker(False)
        self.worker.deleteLater()
        self.thread.wait()
        self.thread.deleteLater()
        self.thread = self.worker = None

    def _connectWorker(self, isConnect=True):
        ss = [{
            'signal': self.thread.started,
            'slot': self.worker.run
        }, {
            'signal': self.worker.finished,
            'slot': self.finishedWorker
        }, {
            'signal': self.worker.messageStatus,
            'slot': self.messageStatusWorker
        }]
        if isConnect:
            for item in ss:
                item['signal'].connect(item['slot'])
        else:
            for item in ss:
                item['signal'].disconnect(item['slot'])

    def _connect(self, isConnect=True):
        ss = [{
            'signal': self.legend.currentLayerChanged,
            'slot': self.selectLayer
        }, {
            'signal': QgsMapLayerRegistry.instance().layerWillBeRemoved,
            'slot': self.removeLayer
        }, {
            'signal': self.canvas.extentsChanged,
            'slot': self.changeSensitiveLegend
        }]
        if isConnect:
            self.hasConnect = True
            for item in ss:
                item['signal'].connect(item['slot'])
        else:
            self.hasConnect = False
            for item in ss:
                item['signal'].disconnect(item['slot'])

    def _connectTree(self, isConnect=True):
        ss = [{
            'signal': self.tree.toggledLegend,
            'slot': self.setTransparenceLayer
        }, {
            'signal': self.tree.descriptionLegend,
            'slot': self.sendClipboard
        }]
        if isConnect:
            self.hasConnectTree = True
            for item in ss:
                item['signal'].connect(item['slot'])
        else:
            self.hasConnectTree = False
            for item in ss:
                item['signal'].disconnect(item['slot'])

    def _resetLayer(self):
        if self.thread.isRunning():
            self.worker.isKilled = True
        self.layer = None
        self.tree.setHeader()
        self.tree.layer = None

    def setEnabled(self, isEnabled=True):
        if not isEnabled and self.thread.isRunning():
            self.worker.isKilled = True
        #
        self._connect(isEnabled)
        self._connectTree(isEnabled)
        self.tree.setEnabled(isEnabled)
        #
        if isEnabled:
            activeLayer = self.iface.activeLayer()
            if activeLayer == self.layer:
                if activeLayer is None:
                    return
                self.changeSensitiveLegend()
            else:
                self.selectLayer(activeLayer)

    @pyqtSlot(list)
    def finishedWorker(self, values):
        self.thread.quit()
        self.msgBar.popWidget()
        if not self.worker.isKilled:
            if len(values) > 0:  # Never Happing otherwise...
                self.tree.setLegend(values)
                if self.isExtentLayer:
                    self.valuesFullExtent = values
        else:  # When PAN/ZOOM/...
            self.thread.wait()
            if self.ckEnabled.checkState() == Qt.Checked:
                self.changeSensitiveLegend()

    @pyqtSlot(str)
    def messageStatusWorker(self, msg):
        self.msgBar.popWidget()
        self.msgBar.pushMessage(self.nameModulus, msg, QgsMessageBar.INFO)

    @pyqtSlot(list)
    def setTransparenceLayer(self, visibleItems):
        def refreshLayer():
            if hasattr(self.layer, "setCacheImage"):
                self.layer.setCacheImage(None)  # Refresh
            else:
                self.layer.triggerRepaint()

        def setTransparence(value, visible):
            t = QgsRasterTransparency.TransparentSingleValuePixel()
            t.min = t.max = value
            percent = 100.0 if not visible else 0.0
            t.percentTransparent = percent

            return t

        valuesTransparent = []
        item = 0
        for visible in visibleItems:
            valuesTransparent.append(setTransparence(item, visible))
            item += 1
        self.transparencyLayer.setTransparentSingleValuePixelList(
            valuesTransparent)
        refreshLayer()
        del valuesTransparent[:]

    @pyqtSlot(str)
    def sendClipboard(self, description):

        mapSettings = self.canvas.mapSettings()
        crsCanvas = mapSettings.destinationCrs()
        extentCanvas = self.canvas.extent()
        extentLayer = self.layer.extent()

        if self.layer.crs() != crsCanvas:
            extentCanvas = mapSettings.mapToLayerCoordinates(
                self.layer, extentCanvas)

        if extentCanvas == extentLayer or extentCanvas.contains(extentLayer):
            msg = "Calculate for all extent of layer '%s'\n\n%s" % (
                self.layer.name(), description)
        else:
            msg = "Calculate for subset of layer '%s' (extend: %s)\n\n%s" % (
                self.layer.name(), extentCanvas.toString(), description)
        clip = QApplication.clipboard()
        clip.setText(msg)
        self.msgBar.pushMessage(self.nameModulus, "Copy to Clipboard",
                                QgsMessageBar.INFO, 5)

    @pyqtSlot('QgsMapLayer')
    def selectLayer(self, layer):
        def processLegend():
            self.tree.setLayer(layer)
            if not self.valuesFullExtent is None:  # Save legend with all extent layer
                del self.valuesFullExtent[:]
                self.valuesFullExtent = None
            (self.layer,
             self.transparencyLayer) = (layer,
                                        layer.renderer().rasterTransparency())
            self.worker.setLegendReadBlock(layer)
            self.changeSensitiveLegend()

        if not self.layer is None:
            if not self.layer in self.legend.layers():
                self.removeLayer(self.layer.id())
            else:
                self.setTransparenceLayer([])
                self._resetLayer()

        if not layer is None and layer.type() == QgsMapLayer.RasterLayer:
            legendItems = layer.legendSymbologyItems()
            total = len(legendItems)
            if total > 0:  # Had a classification
                processLegend()

    @pyqtSlot(str)
    def removeLayer(self, idLayer):
        if not self.layer is None and self.layer.id() == idLayer:
            msg = "Layer '%s' was removed" % self.tree.getLayerName()
            self.msgBar.pushMessage(self.nameModulus, msg,
                                    QgsMessageBar.WARNING, 5)
            self._resetLayer()

    @pyqtSlot()
    def changeSensitiveLegend(self):
        if self.layer is None:
            return

        if self.thread.isRunning():
            self.worker.isKilled = True
            return

        mapSettings = self.canvas.mapSettings()
        crsCanvas = mapSettings.destinationCrs()
        extentCanvas = self.canvas.extent()

        extentLayer = self.layer.extent()
        resX = self.layer.rasterUnitsPerPixelX()
        resY = self.layer.rasterUnitsPerPixelY()

        if self.layer.crs() != crsCanvas:
            extentCanvas = mapSettings.mapToLayerCoordinates(
                self.layer, extentCanvas)

        if not extentCanvas.intersects(extentLayer):
            self.msgBar.popWidget()
            self.msgBar.pushMessage(
                self.nameModulus,
                "View not intersects Raster '%s'" % self.layer.name(),
                QgsMessageBar.WARNING, 5)
            self.tree.setLegend([])
            return

        if extentCanvas == extentLayer or extentCanvas.contains(extentLayer):
            self.isExtentLayer = True
            if not self.valuesFullExtent is None:
                self.tree.setLegend(self.valuesFullExtent)
                return
            extent = extentLayer
            delta = 0
        else:
            self.isExtentLayer = False
            extent = extentCanvas.intersect(extentLayer)
            delta = 1

        widthRead = int(extent.width() / resX) + delta
        heightRead = int(extent.height() / resY) + delta

        self.worker.setProcessImage(extent, widthRead, heightRead)
        self.thread.start()
예제 #11
0
class CatalogOTF(QObject):

    # Signals
    settedLayer = pyqtSignal("QgsVectorLayer")
    removedLayer = pyqtSignal(str)
    killed = pyqtSignal(str)
    changedNameLayer = pyqtSignal(str, str)
    changedTotal = pyqtSignal(str, str)
    changedIconRun = pyqtSignal(str, bool)

    def __init__(self, iface, tableCOTF):
        def connecTableCOTF():
            self.settedLayer.connect(tableCOTF.insertRow)
            self.removedLayer.connect(tableCOTF.removeRow)
            self.changedNameLayer.connect(tableCOTF.changedNameLayer)
            self.changedTotal.connect(tableCOTF.changedTotal)
            self.changedIconRun.connect(tableCOTF.changedIconRun)
            self.killed.connect(tableCOTF.killed)

        super(CatalogOTF, self).__init__()
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.ltv = iface.layerTreeView()
        self.model = self.ltv.layerTreeModel()
        self.ltgRoot = QgsProject.instance().layerTreeRoot()
        self.msgBar = iface.messageBar()
        self.legendTMS = LegendTMS('Catalog OTF')
        self.legendRaster = LegendRaster('Catalog OTF')

        self._initThread()

        connecTableCOTF()
        self.model.dataChanged.connect(self.dataChanged)
        QgsMapLayerRegistry.instance().layersWillBeRemoved.connect(
            self.layersWillBeRemoved)  # Catalog layer removed

        self.layer = self.layerName = self.nameFieldSource = self.nameFieldDate = None
        self.ltgCatalog = self.ltgCatalogName = self.visibleSourceLayers = self.hasCanceled = None

    def __del__(self):
        self._finishThread()
        del self.legendTMS
        del self.legendRaster
        QgsMapLayerRegistry.instance().layersWillBeRemoved.disconnect(
            self.layersWillBeRemoved)  # Catalog layer removed

    def _initThread(self):
        self.thread = QThread(self)
        self.thread.setObjectName("QGIS_Plugin_%s" %
                                  NAME_PLUGIN.replace(' ', '_'))
        self.worker = WorkerPopulateGroup(self.addLegendLayerWorker)
        self.worker.moveToThread(self.thread)
        self._connectWorker()

    def _finishThread(self):
        self._connectWorker(False)
        self.worker.deleteLater()
        self.thread.wait()
        self.thread.deleteLater()
        self.thread = self.worker = None

    def _connectWorker(self, isConnect=True):
        ss = [{
            'signal': self.thread.started,
            'slot': self.worker.run
        }, {
            'signal': self.worker.finished,
            'slot': self.finishedPG
        }, {
            'signal': self.worker.messageStatus,
            'slot': self.messageStatusPG
        }, {
            'signal': self.worker.messageError,
            'slot': self.messageErrorPG
        }]
        if isConnect:
            for item in ss:
                item['signal'].connect(item['slot'])
        else:
            for item in ss:
                item['signal'].disconnect(item['slot'])

    def addLegendLayerWorker(self, layer):
        if layer.type() == QgsMapLayer.RasterLayer:
            metadata = layer.metadata()
            if metadata.find("GDAL provider") != -1:
                if metadata.find("OGC Web Map Service") != -1:
                    if self.legendTMS.hasTargetWindows(layer):
                        self.legendTMS.setLayer(layer)
                else:
                    self.legendRaster.setLayer(layer)

    def run(self):
        self.hasCanceled = False  # Check in finishedPG

        if self.thread.isRunning():
            self.worker.kill()
            self.hasCanceled = True
            msgtrans = QCoreApplication.translate(
                "CatalogOTF", "Canceled search for image from layer %s")
            msg = msgtrans % self.layerName
            self.msgBar.pushMessage(NAME_PLUGIN, msg, QgsMessageBar.WARNING, 2)
            self.changedTotal.emit(self.layer.id(), "Canceling processing")
            self.killed.emit(self.layer.id())
            return

        if self.layer is None:
            msgtrans = QCoreApplication.translate("CatalogOTF",
                                                  "Need define layer catalog")
            self.msgBar.pushMessage(NAME_PLUGIN, msgtrans,
                                    QgsMessageBar.WARNING, 2)
            return

        self._setGroupCatalog()
        self.ltgCatalogName = self.ltgCatalog.name()

        renderFlag = self.canvas.renderFlag()
        if renderFlag:
            self.canvas.setRenderFlag(False)
            self.canvas.stopRendering()

        self._populateGroupCatalog()

        if renderFlag:
            self.canvas.setRenderFlag(True)
            self.canvas.refresh()

    def _populateGroupCatalog(self):
        def getSourceVisibleLayers():
            def hasVisibleRaster(ltl):
                return ltl.isVisible() == Qt.Checked and ltl.layer().type(
                ) == QgsMapLayer.RasterLayer

            l_ltlVisible = filter(lambda item: hasVisibleRaster(item),
                                  self.ltgCatalog.findLayers())
            return map(lambda item: item.layer().source(), l_ltlVisible)

        def runWorker():
            data = {}
            data['nameFieldDate'] = self.nameFieldDate
            data['nameFieldSource'] = self.nameFieldSource
            data['layer'] = self.layer
            data['ltgCatalog'] = self.ltgCatalog
            self.worker.setData(data)
            self.thread.start()
            #self.worker.run() # DEBUG

        self.visibleSourceLayers = getSourceVisibleLayers()
        self.ltgCatalog.removeAllChildren()
        runWorker()  # See finishPG

    def _setGroupCatalog(self):
        self.ltgCatalogName = "%s - Catalog" % self.layer.name()
        self.ltgCatalog = self.ltgRoot.findGroup(self.ltgCatalogName)
        if self.ltgCatalog is None:
            self.ltgCatalog = self.ltgRoot.addGroup(self.ltgCatalogName)

    @pyqtSlot(bool)
    def finishedPG(self, isKilled):
        def setSourceVisibleLayers():
            l_ltlVisible = filter(
                lambda item: item.layer().source() in self.visibleSourceLayers,
                self.ltgCatalog.findLayers())
            map(lambda item: item.setVisible(Qt.Checked), l_ltlVisible)

        self.thread.quit()

        if not self.layer is None:
            self.changedIconRun.emit(self.layer.id(),
                                     self.layer.selectedFeatureCount() > 0)
            if self.hasCanceled:
                self.changedTotal.emit(self.layer.id(), '0')
            else:
                setSourceVisibleLayers()

        del self.visibleSourceLayers[:]

    @pyqtSlot(str)
    def messageStatusPG(self, msg):
        self.changedTotal.emit(self.layer.id(), msg)

    @pyqtSlot(str)
    def messageErrorPG(self, msg):
        self.msgBar.pushMessage(NAME_PLUGIN, msg, QgsMessageBar.CRITICAL, 8)

    @pyqtSlot('QModelIndex', 'QModelIndex')
    def dataChanged(self, idTL, idBR):
        if idTL != idBR:
            return

        if not self.ltgCatalog is None and self.ltgCatalog == self.model.index2node(
                idBR):
            name = self.ltgCatalog.name()
            if self.ltgCatalogName != name:
                self.ltgCatalogName = name
                return

        if not self.layer is None and self.ltgRoot.findLayer(
                self.layer.id()) == self.model.index2node(idBR):
            name = self.layer.name()
            if self.layerName != name:
                self.changedNameLayer.emit(self.layer.id(), name)
                self.layerName = name

    @pyqtSlot(list)
    def layersWillBeRemoved(self, layerIds):
        if self.layer is None:
            return
        if self.layer.id() in layerIds:
            self.removedLayer.emit(self.layer.id())
            self.removeLayerCatalog()

    @staticmethod
    def getNameFieldsCatalog(layer):
        def getFirstFeature():
            f = QgsFeature()
            #
            fr = QgsFeatureRequest(
            )  # First FID can be 0 or 1 depend of provider type
            it = layer.getFeatures(fr)
            isOk = it.nextFeature(f)
            it.close()
            #
            if not isOk or not f.isValid():
                del f
                return None
            else:
                return f

        def hasAddress(feature, nameField):
            def asValidUrl(url):
                isOk = True
                try:
                    urllib2.urlopen(url)
                except urllib2.HTTPError, e:
                    isOk = False
                except urllib2.URLError, e:
                    isOk = False
                #
                return isOk

            value = feature.attribute(nameField)
            if value is None or type(value) == QPyNullVariant:
                return False

            isUrl = value.find('http://') == 0 or value.find('https://') == 0
            lenSource = len(value)
            isUrl = isUrl and value.rfind(
                'xml', lenSource - len('xml')) == lenSource - len('xml')
            if isUrl:
                return asValidUrl(value)
            #
            fileInfo = QFileInfo(value)
            return fileInfo.isFile()
예제 #12
0
class GCode(object):

    def __init__(self, filename, controller, done_loading_callback, done_writing_callback):
        self.controller = controller
        self.done_loading_callback = done_loading_callback
        self.writing_done_callback = done_writing_callback
        self.data = defaultdict(list)
        self.all_data = []
        self.data_keys = set()
        self.color_change_data = []
        self.actual_z = '0.0'
        self.speed = 0.0
        self.z_hop = False
        self.last_point = np.array([0.0, 0.0, 0.0])
        self.actual_point = [0.0, 0.0, 0.0]

        self.printing_time = 0.0
        self.filament_length = 0.0
        #print("Filename type: " + str(type(filename)))
        #print("Filename: " + filename)
        #if type(filename)==:
        #self.filename = u'c:\\models\\super mega testovací Jindřich šložka čěýáéůú\\anubis_PLA_OPTIMAL.gcode'
        self.filename = filename

        self.is_loaded = False

        self.gcode_parser = GcodeParserRunner(controller, self.filename)
        self.gcode_parser_thread = QThread()

        self.gcode_copy = GcodeCopyRunner(self.filename, "", color_change_lst=self.color_change_data)
        self.gcode_copy_thread = QThread()


    def cancel_parsing_gcode(self):
        print("Cancel presset")
        if self.gcode_parser and self.gcode_parser_thread and self.gcode_parser_thread.isRunning():
            self.gcode_parser.is_running = False
            self.gcode_parser_thread.quit()
            self.gcode_parser_thread.wait()
            self.is_loaded = False
            self.data = {}
            self.all_data = []
            self.data_keys = []
        self.controller.set_progress_bar(0)

    def cancel_writing_gcode(self):
        print("Cancel writing gcode")
        if self.gcode_copy and self.gcode_copy_thread and self.gcode_copy_thread.isRunning():
            self.gcode_copy.quit()
            self.gcode_copy_thread.wait()

    def get_first_extruding_line_number_of_gcode_for_layers(self, layers_keys_lst):
        lines_number = []
        for i in layers_keys_lst:
            line = self.data[i]
            for o in line:
                _a, _b, type, _speed, _extr, line_n = o
                if 'E' in type:
                    lines_number.append(line_n)
                    break

        return lines_number



    def read_in_thread(self, update_progressbar_function, after_done_function):
        print("reading in thread")
        self.gcode_parser.moveToThread(self.gcode_parser_thread)
        self.done_loading_callback = after_done_function

        # connect all signals to thread class
        self.gcode_parser_thread.started.connect(self.gcode_parser.load_gcode_file)
        # connect all signals to parser class
        self.gcode_parser.finished.connect(self.set_finished_read)
        self.gcode_parser.update_progressbar=True
        self.gcode_parser.set_update_progress.connect(update_progressbar_function)
        self.gcode_parser.set_data_keys.connect(self.set_data_keys)
        self.gcode_parser.set_data.connect(self.set_data)
        self.gcode_parser.set_all_data.connect(self.set_all_data)
        self.gcode_parser.set_printing_time.connect(self.set_printig_time)

        self.gcode_parser_thread.start()


    def read_in_realtime(self):
        print("Read in realtime")
        self.gcode_parser.set_data_keys.connect(self.set_data_keys)
        self.gcode_parser.set_data.connect(self.set_data)
        self.gcode_parser.set_all_data.connect(self.set_all_data)
        self.gcode_parser.set_printing_time.connect(self.set_printig_time)
        self.gcode_parser.update_progressbar=False

        print("start read procedure")
        self.gcode_parser.load_gcode_file()

        self.is_loaded = True


    def set_printig_time(self, time):
        self.printing_time = time

    def set_data_keys(self, data_keys):
        self.data_keys = data_keys

    def set_all_data(self, all_data):
        self.all_data = all_data

    def set_data(self, data):
        self.data = data

    def set_finished_read(self):
        self.gcode_parser_thread.quit()
        self.is_loaded = True
        self.done_loading_callback()
        #self.controller.set_gcode()

    def set_finished_copy(self):
        self.gcode_copy_thread.quit()
        #print(str(self.writing_done_callback))
        self.writing_done_callback()

    def set_color_change_data(self, data):
        self.color_change_data = data


    def write_with_changes_in_thread(self, filename_in, filename_out, update_function):
        self.gcode_copy.filename_in = filename_in
        self.gcode_copy.filename_out = filename_out
        self.gcode_copy.color_change_lst = self.color_change_data
        self.gcode_copy.moveToThread(self.gcode_copy_thread)

        self.gcode_copy_thread.started.connect(self.gcode_copy.write_file)

        self.gcode_copy.finished.connect(self.set_finished_copy)
        self.gcode_copy.set_update_progress.connect(update_function)

        self.gcode_copy_thread.start()