Esempio n. 1
0
class Tasks(QObject):
    def __init__(self, ar, process_result):
        super(Tasks, self).__init__()
        self.ar = ar
        self.process_result = process_result
        self.pool = QThreadPool()
        self.pool.setMaxThreadCount(10)

    # def process_result(self, rev):
    #     # print 'Receiving', rev
    #     self.ref.setText(rev)

    def start(self):
        self.factory = GenerWork(self.ar)

        self.factory.generateWorkers()
        workers = self.factory.get_workers()

        # print workers
        for worker in workers:
            worker.signals.result.connect(self.process_result)

            self.pool.start(worker)

        self.pool.waitForDone()
        return data

    def get_shell_data(self):
        return self.factory.get_shell_data()
Esempio n. 2
0
class AsyncPoolController(AsyncAbstractController):
    def __init__(self,
      # A number *n* to create a pool of *n* simple threads, where each thread
      # lacks an event loop, so that it can emit but not receive signals.
      # This means that ``g`` may **not** be run in a thread of this pool,
      # without manually adding a event loop. If *n* < 1, the global thread pool
      # is used.
      maxThreadCount,

      # |parent|
      parent=None):

        super(AsyncPoolController, self).__init__(parent)
        if maxThreadCount < 1:
            self.threadPool = QThreadPool.globalInstance()
        else:
            self.threadPool = QThreadPool()
            self.threadPool.setMaxThreadCount(maxThreadCount)

    # |_start|
    def _start(self, future):
        # Asynchronously invoke ``f``.
        apw = _AsyncPoolWorker(future)
        self.threadPool.start(apw)

    # |terminate|
    def _terminate(self):
        self.threadPool.waitForDone()
        del self.threadPool
Esempio n. 3
0
class PROCESS(QObject):
    queue_finished = pyqtSignal(int)
    prog_finished = pyqtSignal(tuple)
    stoped = pyqtSignal(int, int)  # 1: start, 0: finished, 2: error | queue
    state = pyqtSignal(int, str)

    def __init__(self, parent=None):
        QObject.__init__(self, parent)
        self.process = QProcess()
        self.process.setProcessChannelMode(QProcess.MergedChannels)
        self.process.finished.connect(self.emit_finished)
        self.process.stateChanged.connect(self.emit_state)
        self.process_type = 0  # 0 process, 1 runnable
        self.threadpool = QThreadPool()
        self.worker = Worker()
        self.worker.signals.state.connect(self.emit_state)
        self.queue = None

    def emit_state(self, state):
        self.state.emit(state, self.prog_name)

    def emit_finished(self, exitcode, exitstatus):
        self.prog_finished.emit((self.prog_name, exitcode, exitstatus))

    def set_queue(self, queue):
        self.queue = queue

    def start_process(self):
        try:
            obj = self.queue.get(False)
            self.prog_name = obj.keys()[0]
            if callable(obj.values()[0][0]):
                self.process_type = 1
                funct = obj.values()[0][0]
                args = obj.values()[0][1]
                self.worker.insert_function(funct, args, self.prog_name)
                self.threadpool.start(self.worker)
            else:
                self.process_type = 0
                self.process.start(obj.values()[0][0], obj.values()[0][1])
        except Queue.Empty:
            self.queue_finished.emit(self.queue.name)

    def force_finished(self):
        # for process (programs)
        self.stoped.emit(1, self.queue.name)
        if self.process_type == 0:
            self.process.terminate()
            if not self.process.waitForFinished(1000):
                self.process.kill()
        else:
            if self.threadpool.activeThreadCount():
                self.threadpool.clear()
                self.threadpool.waitForDone()
        with self.queue.mutex:
            self.queue.queue.clear()
        self.stoped.emit(0, self.queue.name)
Esempio n. 4
0
def omap(fkt, par):
    """
    :type fkt: ()->
    :type par: list
    :rtype: list
    """
    # Die Anzahl der Prozesse ist ohne Aufwand auf einen idealen Wert beschränkt
    pool = QThreadPool()
    erg = [None] * len(par)
    for p in par:
        pool.start(QRunnable(fkt, p))
Esempio n. 5
0
class QWorker(QObject):

    """
    Starts the QRunnable in a QThreadPool,  inherits QObject because
    we need to connect signals from the objects we are creating to
    the functions that update the UI
    """

    def __init__(self):

        """
        This class creates new instances of QRunner, which is the class
        that directly interfaces with the external executable

        We need to create the QRunner/QWorker routine because a QRunnable
        does not inherit from QObject and therefore does not have access
        to the signal/slot mechanisms that we need in order to receive when
        things get done.

        QWorker inherits from QObject, so we need to directly call QObjects
        constructor to initialize the underlying C++ object, super() does not
        allow for this (seemingly) so we need to call it directly.
        """

        # init QObject
        QObject.__init__(self)
        # Our own threadpool, for adding QRunners
        self.threadpool = QThreadPool()
        self.jobs = []

    def create_job(self, ifname, ofname, cls):

        """
        This method takes three arguments:

        ifname is the input file name of the file to be converted
        ofname is a string which is to be the output of the filename
        cls is a reference to the calling class, so that we can connect
        a signal to a slot.
        """

        # Create the QRunner object and pass it filenames
        runner = QRunner(ifname, ofname, cls)

        # using our own connect method inherited from QObject
        # connect the QRunner created before and use it's QObject
        # to connect a signal to the slot
        self.connect(runner.q_object, SIGNAL(
                                         "finished()"), cls.update_progress_bar)

        # ask our threadpool to run the task
        self.threadpool.start(runner)
Esempio n. 6
0
    def start(self):
        self.idmap = {}
        self.entries = []

        pool = QThreadPool()
        pool.setMaxThreadCount(1)

        for label in LABELS:
            feed = Feed(label, self)
            pool.start(feed)
            imap = Imap(label, self)
            pool.start(imap)

        pool.waitForDone()
        self.done.emit()
Esempio n. 7
0
    def start(self):
        self.idmap = {}
        self.entries = []

        pool = QThreadPool()
        pool.setMaxThreadCount(1)

        for label in LABELS:
            feed = Feed(label, self)
            pool.start(feed)
            imap = Imap(label, self)
            pool.start(imap)

        pool.waitForDone()
        self.done.emit()
Esempio n. 8
0
class QFileWorker(object):

    def __init__(self, deletions, cls):
        """
        This class handles deletion of temporary file objects once processing
        has completed.

        It takes a reference to the class because we re-enable it's button
        because we disabled it during processing
        """

        self.deletions = deletions
        self.threadpool = QThreadPool()
        self.cls = cls
        self._start()

    def _start(self):
        deleter = QFileCleaner(self.deletions, self.cls)
        self.threadpool.start(deleter)
        self.threadpool.waitForDone()
class GridZoneGeneratorDialog(QtGui.QDialog, FORM_CLASS):
    def __init__(self, iface, parent=None):
        """Constructor."""
        super(GridZoneGeneratorDialog, self).__init__(parent)
        # Set up the user interface from Designer.
        # After setupUI you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)
        self.iface = iface

        self.crsLineEdit.setReadOnly(True)
        
        self.utmgrid = UtmGrid()

        self.setValidCharacters()

        self.setMask()

        self.threadpool = QThreadPool()

    def setValidCharacters(self):
        self.chars = []

        chars = 'NS'
        self.chars.append(chars)
        chars = 'ABCDEFGHIJKLMNOPQRSTUVZ'
        self.chars.append(chars)
        chars = ['01','02','03','04','05','06','07','08','09','10',
                   '11','12','13','14','15','16','17','18','19','20',
                   '21','22','23','24','25','26','27','28','29','30',
                   '31','32','33','34','35','36','37','38','39','40',
                   '41','42','43','44','45','46','47','48','49','50',
                   '51','52','53','54','55','56','57','58','59','60']
        self.chars.append(chars)
        chars = 'VXYZ'
        self.chars.append(chars)
        chars = 'ABCD'
        self.chars.append(chars)
        chars = ['I','II','III','IV','V','VI']
        self.chars.append(chars)
        chars = '1234'
        self.chars.append(chars)
        chars = ['NO','NE','SO','SE']
        self.chars.append(chars)
        chars = 'ABCDEF'
        self.chars.append(chars)
        chars = ['I','II','III','IV']
        self.chars.append(chars)
        chars = '123456'
        self.chars.append(chars)
        chars = 'ABCD'
        self.chars.append(chars)
        
    def setMask(self):
        if self.scaleCombo.currentText() == '1000k':
            self.indexLineEdit.setInputMask('NN-NN')
        elif self.scaleCombo.currentText() == '500k':
            self.indexLineEdit.setInputMask('NN-NN-N')
        elif self.scaleCombo.currentText() == '250k':
            self.indexLineEdit.setInputMask('NN-NN-N-N')
        elif self.scaleCombo.currentText() == '100k':
            self.indexLineEdit.setInputMask('NN-NN-N-N-Nnn')
        elif self.scaleCombo.currentText() == '50k':
            self.indexLineEdit.setInputMask('NN-NN-N-N-Nnn-0')
        elif self.scaleCombo.currentText() == '25k':
            self.indexLineEdit.setInputMask('NN-NN-N-N-Nnn-0-NN')
        elif self.scaleCombo.currentText() == '10k':
            self.indexLineEdit.setInputMask('NN-NN-N-N-Nnn-0-NN-N')
        elif self.scaleCombo.currentText() == '5k':
            self.indexLineEdit.setInputMask('NN-NN-N-N-Nnn-0-NN-N-Nnn')
        elif self.scaleCombo.currentText() == '2k':
            self.indexLineEdit.setInputMask('NN-NN-N-N-Nnn-0-NN-N-Nnn-0')
        elif self.scaleCombo.currentText() == '1k':
            self.indexLineEdit.setInputMask('NN-NN-N-N-Nnn-0-NN-N-Nnn-0-N')
            
    def validateMI(self):
        mi = self.indexLineEdit.text()
        split = mi.split('-')
        for i in range(len(split)):
            word = str(split[i])
            if len(word) == 0:
                return False
            if i == 0:
                if word[0] not in self.chars[0]:
                    print word
                    return False
                if word[1] not in self.chars[1]:
                    print word
                    return False
            elif i == 1:
                if word not in self.chars[2]:
                    print word
                    return False
            elif i == 2:
                if word not in self.chars[3]:
                    print word
                    return False
            elif i == 3:
                if word not in self.chars[4]:
                    print word
                    return False
            elif i == 4:
                if word not in self.chars[5]:
                    print word
                    return False
            elif i == 5:
                if word not in self.chars[6]:
                    print word
                    return False
            elif i == 6:
                if word not in self.chars[7]:
                    print word
                    return False
            elif i == 7:
                if word not in self.chars[8]:
                    print word
                    return False
            elif i == 8:
                if word not in self.chars[9]:
                    print word
                    return False
            elif i == 9:
                if word not in self.chars[10]:
                    print word
                    return False
            elif i == 10:
                if word not in self.chars[11]:
                    print word
                    return False
        return True
    
    def disableAll(self):
        self.mirLineEdit.setEnabled(False)
        self.miLineEdit.setEnabled(False)
        self.indexLineEdit.setEnabled(False)

    @pyqtSlot(bool)
    def on_crsButton_clicked(self):
        projSelector = QgsGenericProjectionSelector()
        message = 'Select the Spatial Reference System!'
        projSelector.setMessage(theMessage=message)
        projSelector.exec_()
        try:
            epsg = int(projSelector.selectedAuthId().split(':')[-1])
            self.crs = QgsCoordinateReferenceSystem(epsg, QgsCoordinateReferenceSystem.EpsgCrsId)
            if self.crs:
                self.crsLineEdit.setText(self.crs.description())
        except:
            QMessageBox.warning(self, self.tr("Warning!"), self.tr(message))

    @pyqtSlot(str)
    def on_indexLineEdit_textEdited(self,s):
        if (s!=''):
            mi = self.utmgrid.getMIFromINomen(str(s))
            self.miLineEdit.setText(mi)

    @pyqtSlot(str)
    def on_miLineEdit_textEdited(self,s):
        if (s!=''):
            self.index = self.utmgrid.getINomenFromMI(str(s))
            self.indexLineEdit.setText(self.index)

    @pyqtSlot(str)
    def on_mirLineEdit_textEdited(self,s):
        if (s!=''):
            self.index = self.utmgrid.getINomenFromMIR(str(s))
            self.indexLineEdit.setText(self.index)

    @pyqtSlot(int)
    def on_scaleCombo_currentIndexChanged(self):
        self.setMask()

    @pyqtSlot(bool)
    def on_mirRadioButton_toggled(self, toggled):
        if toggled:
            self.mirLineEdit.setEnabled(True)
        else:
            self.mirLineEdit.setEnabled(False)

    @pyqtSlot(bool)
    def on_miRadioButton_toggled(self, toggled):
        if toggled:
            self.miLineEdit.setEnabled(True)
        else:
            self.miLineEdit.setEnabled(False)

    @pyqtSlot(bool)
    def on_indexRadioButton_toggled(self, toggled):
        if toggled:
            self.indexLineEdit.setEnabled(True)
        else:
            self.indexLineEdit.setEnabled(False)

    @pyqtSlot(bool)
    def on_saveButton_clicked(self):
        fileName = QFileDialog.getSaveFileName(parent=self, caption=self.tr('Save Output File'), filter='Shapefile (*.shp)')
        self.saveEdit.setText(fileName)
      
    @pyqtSlot()        
    def on_button_box_accepted(self):
        stopScale = int(self.stopScaleCombo.currentText().replace('k','')) 
        scale = int(self.scaleCombo.currentText().replace('k',''))
    
        if stopScale > scale:
            QMessageBox.warning(self, self.tr('Warning!'), self.tr('The stop scale denominator should not be bigger than \
                                                                    the scale denominator!'))
            return
        if self.createShapeBox.isChecked() and not self.saveEdit.text():
            QMessageBox.warning(self, self.tr('Warning!'), self.tr('A output file must be specified!'))
            return
        if not self.crsLineEdit.text():
            QMessageBox.warning(self, self.tr('Warning!'), self.tr('A CRS must be specified!'))
            return
        if not self.validateMI():
            QMessageBox.warning(self, self.tr('Warning!'), self.tr('Invalid Map Index!'))            
            return
        
        # Initiating processing
        gridThread = UtmGrid()
        
        if self.createShapeBox.isChecked():
            self.layer = None
        else:
            self.layer = gridThread.createGridLayer(self.tr('Grid Zones'), 'Multipolygon', self.crs.authid())
            
        gridThread.setParameters(self.indexLineEdit.text(), stopScale, self.miLineEdit.text(), self.crs, self.saveEdit.text(), self.layer)
        # Connecting end signal
        gridThread.aux.processFinished.connect(self.finishProcess)
        gridThread.aux.rangeCalculated.connect(self.setRange)
        gridThread.aux.errorOccurred.connect(self.showError)
        gridThread.aux.stepProcessed.connect(self.updateProgress)
        # Setting the progress bar
        self.progressMessageBar = self.iface.messageBar().createMessage(self.tr('Generating grid, please wait...'))
        self.progressBar = QtGui.QProgressBar()
        self.progressBar.setAlignment(Qt.AlignLeft|Qt.AlignVCenter)
        self.progressMessageBar.layout().addWidget(self.progressBar)
        self.iface.messageBar().pushWidget(self.progressMessageBar, self.iface.messageBar().INFO)
        self.progressBar.setRange(0, 0)
        self.progressMessageBar.destroyed.connect(gridThread.aux.cancel)
        # Starting process
        self.threadpool.start(gridThread)
        
    def setRange(self, maximum):
        self.progressBar.setRange(0, maximum)
        
    def showError(self, msg):
        QMessageBox.warning(self, self.tr('Warning!'), msg)
        
    def updateProgress(self):
        self.progressBar.setValue(self.progressBar.value() + 1)
        
    def finishProcess(self):
        self.progressBar.setValue(self.progressBar.maximum())
        
        if self.createShapeBox.isChecked():
            layer = self.iface.addVectorLayer(self.saveEdit.text(), self.tr('Grid Zones'), 'ogr')
            self.updateMapCanvas(layer)
        else:
            QgsMapLayerRegistry.instance().addMapLayer(self.layer)
            self.updateMapCanvas(self.layer)
            
        QMessageBox.information(self, self.tr('Success!'), self.tr('Grid Created successfully!'))
        
    def updateMapCanvas(self, layer):
        if layer:
            self.iface.setActiveLayer(layer)
            
        layer.updateExtents() 
        
        bbox = self.iface.mapCanvas().mapSettings().layerToMapCoordinates(layer, layer.extent())
        self.iface.mapCanvas().setExtent(bbox)
        self.iface.mapCanvas().refresh()
        
class PyQtPaint(QtGui.QWidget):
    """
    Canvas based painting ui w/ brush control, layers, undo functionality

    Attributes:
        color_dialog (QColorDialog): Color Picker
        file_dialog (QFileDialog): Filepath picker for saving img externally
        layers_tree (QTreeWidgetItem): Tree widget acting as a layers panel
        paint_scene (QGraphicsScene): graphics scene storing/maintaing stroke
                                      information
    Args:
        width (int): width of PyQtPaint
        height (int): height of PyQtPaint
    """
    def __init__(self, width, height, *args, **kwargs):
        super(PyQtPaint, self).__init__(*args, **kwargs)
        uic.loadUi('../ui/pyqtpaint.ui', self)

        self._paint_view = PaintView()
        self._paint_view.setRenderHints(QtGui.QPainter.HighQualityAntialiasing)

        self.paint_scene = PaintScene(0, 0, width, height, None)
        self._paint_view.setScene(self.paint_scene)

        # Numbers of layers
        self.num_layers = 0
        self.old_layers = -1

        # Timer to save images
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.start()

        # Path to save imgs
        self.tmpFilepath = "../img/tmp/tmp.png"

        # Timer to predict shapes
        self.timer_predict = QTimer()
        self.timer_predict.setInterval(1000)
        self.timer_predict.start()

        # The app is not working on predict shapes
        self.working = False

        # Thread to run in background of paint
        self.threadpool = QThreadPool()

        # Setup all UI, and make the connctions between Signals & Slots
        self._setup_ui()
        self._create_actions()
        self._make_connections()

    def __del__(self):
        self.threadpool.deleteLater()

    def _setup_ui(self):
        self.viewport_widget.layout().addWidget(self._paint_view)
        self.layers_tree = LayerPanel(dragToggleColumns=[0], columns=['', ''])
        self.layers_tree.setItemDelegate(TreeDelegate())
        self.layers_widget.layout().addWidget(self.layers_tree)

        self.file_dialog = QtGui.QFileDialog(self)
        self.color_dialog = QtGui.QColorDialog()

        self._update_brush_ui()

    def _create_actions(self):
        self.undo_action = QtGui.QAction('Undo', self)
        self.undo_action.setShortcut('Ctrl+Z')
        self.addAction(self.undo_action)

        self.redo_action = QtGui.QAction('Redo', self)
        self.redo_action.setShortcut('Shift+Ctrl+Z')
        self.addAction(self.redo_action)

        self.delete_action = QtGui.QAction('Delete', self)
        self.delete_action.setShortcut('Backspace')
        self.addAction(self.delete_action)

        self.group_action = QtGui.QAction('Group', self)
        self.group_action.setShortcut('Ctrl+G')
        self.addAction(self.group_action)

        self.save_action = QtGui.QAction('Save', self)
        self.save_action.setShortcut('Ctrl+S')
        self.addAction(self.save_action)

        self.increase_size_action = QtGui.QAction('Increase Size', self)
        self.increase_size_action.setShortcut(']')
        self.addAction(self.increase_size_action)

        self.decrease_size_action = QtGui.QAction('Decrease Size', self)
        self.decrease_size_action.setShortcut('[')
        self.addAction(self.decrease_size_action)

###        self.brush_softer_action = QtGui.QAction('Brush Softer', self)
###        self.brush_softer_action.setShortcut('{')
###        self.addAction(self.brush_softer_action)

###        self.brush_harder_action = QtGui.QAction('Brush Harder', self)
###        self.brush_harder_action.setShortcut('}')
###        self.addAction(self.brush_harder_action)

    def _make_connections(self):
        self.paint_scene.strokeAdded.connect(self.create_layer_item)
        self.paint_scene.strokeRemoved.connect(self.remove_layer_item)

        self.paint_scene.brushChanged.connect(self._update_brush_ui)
        self.size_SLD.valueChanged.connect(
            lambda: self.set_pen_size(self.size_SLD.value()))
        ###        self.blur_SLD.valueChanged.connect(lambda: self.set_pen_blur(self.blur_SLD.value()))

        self.increase_size_action.triggered.connect(
            lambda: self.paint_scene.increment_pen_size(10))
        self.decrease_size_action.triggered.connect(
            lambda: self.paint_scene.increment_pen_size(-10))
        ###        self.brush_softer_action.triggered.connect(lambda: self.paint_scene.increment_pen_blur(1))
        ###        self.brush_harder_action.triggered.connect(lambda: self.paint_scene.increment_pen_blur(-1))

        self.redo_action.triggered.connect(self.paint_scene.undo_stack.redo)
        self.undo_action.triggered.connect(self.paint_scene.undo_stack.undo)

        self.delete_action.triggered.connect(self.delete_layer)
        self.group_action.triggered.connect(self.group_layers)

        self.save_action.triggered.connect(self.save_img)

        self.layers_tree.itemChanged.connect(self.layer_change)
        self.layers_tree.layerOrderChanged.connect(self.update_layer_index)

        self.color_BTN.clicked.connect(self.update_pen_color)

        self.timer.timeout.connect(self.on_timer)
        self.timer_predict.timeout.connect(self.predict)

        self.connect(self, QtCore.SIGNAL('triggered'), self.closeEvent)

    def _update_brush_ui(self):
        self.size_SLD.setValue(self.paint_scene.pen_size)
        ###        self.blur_SLD.setValue(self.paint_scene.pen_blur)

        style = QString("QPushButton { border-style: none; \
                                              border-radius: 10px; \
                                              min-width: 3em; \
                                              height: 3em; \
                                              background-color: " +
                        self.paint_scene.pen_color.name() + "}")
        self.color_BTN.setStyleSheet(style)

    def create_layer_item(self, stroke_id, layer_name):
        """
        Creates layer item in layer panel using stroke data

        Args:
            stroke_id (int): unique index of stroke
            layer_name (str): name of stroke layer

        """
        stroke_info = ['', layer_name]
        layer = Layer(stroke_info, stroke_index=stroke_id)

        self.num_layers += 1
        highest_group = None
        if self.layers_tree.selectedItems():
            iterator = QtGui.QTreeWidgetItemIterator(self.layers_tree)
            while iterator.value():
                item = iterator.value()
                if isinstance(
                        item,
                        Folder) and item in self.layers_tree.selectedItems():
                    highest_group = item
                    break
                iterator += 1
        if highest_group:
            highest_group.insertChild(0, layer)
        else:
            self.layers_tree.insertTopLevelItem(0, layer)
        self.update_layer_index()

    def remove_layer_item(self, stroke_id):
        """
        deletes layer item in layer panel

        Args:
            stroke_id (int): unique index of stroke to be removed

        """
        iterator = QtGui.QTreeWidgetItemIterator(self.layers_tree)
        self.num_layers -= 1

        while iterator.value():
            item = iterator.value()
            if isinstance(item, Layer):
                layer_data = item.data(1, Qt.UserRole).toPyObject()[0]
                if layer_data['stroke_index'] == stroke_id:
                    parent = item.parent()
                    if parent:
                        idx = parent.indexOfChild(item)
                        parent.takeChild(idx)
                    else:
                        idx = self.layers_tree.indexOfTopLevelItem(item)
                        self.layers_tree.takeTopLevelItem(idx)
            if isinstance(item, Folder):
                layer_data = item.data(1, Qt.UserRole).toPyObject()[0]

                if item.group_index == stroke_id:
                    parent = item.parent()
                    if parent:
                        idx = parent.indexOfChild(item)
                        parent.takeChild(idx)
                    else:
                        idx = self.layers_tree.indexOfTopLevelItem(item)
                        self.layers_tree.takeTopLevelItem(idx)
            iterator += 1

    def layer_change(self, item, column):
        """
        updates stroke information, used when updating visibility or layer name

        Args:
            item (QTreeWidgetItem): item associated with stroke
            column (int): column to change
        """
        if column == 0:
            if isinstance(item, Layer):
                self.paint_scene.toggle_layer_visibility(
                    item.stroke_index, item.visible)

            elif isinstance(item, Folder):
                for i in range(item.childCount()):
                    if item.visible is True:
                        item.child(i).setFlags(Qt.ItemIsSelectable
                                               | Qt.ItemIsEditable
                                               | Qt.ItemIsEnabled
                                               | Qt.ItemIsDragEnabled)
                    else:
                        item.child(i).setFlags(Qt.NoItemFlags)
                    self.paint_scene.toggle_layer_visibility(
                        item.child(i).stroke_index, item.visible)

        elif column == 1:
            if isinstance(item, Layer):
                self.paint_scene.update_layer_name(item.stroke_index,
                                                   item.text(1))

    def delete_layer(self):
        """
        Deletes selected layers
        """
        for item in self.layers_tree.selectedItems():
            # remove item.stroke_index
            if isinstance(item, Layer):
                if item.parent():
                    command = DeleteStroke(self, item, group=item.parent())
                    self.paint_scene.undo_stack.push(command)
                else:
                    command = DeleteStroke(self, item)
                    self.paint_scene.undo_stack.push(command)

            if isinstance(item, Folder):
                command = DeleteGroup(self, item)
                self.paint_scene.undo_stack.push(command)

    def group_layers(self):
        """
        groups seleted layers

        """
        if self.layers_tree.selectedItems():
            grab_items = []
            for item in self.layers_tree.selectedItems():
                if isinstance(item, Layer):
                    grab_items.append(item.stroke_index)

            command = GroupStrokes(self, grab_items)
            self.paint_scene.undo_stack.push(command)

    def update_layer_index(self):
        """
        iterates through layer panel & updates stacking order of strokes

        """
        iterator = QtGui.QTreeWidgetItemIterator(self.layers_tree)
        while iterator.value():
            item = iterator.value()
            target_index = self.layers_tree.indexFromItem(item).row()
            try:
                new_indx = len(self.paint_scene.strokes) - target_index
                self.paint_scene.set_stroke_zindex(item._stroke_index,
                                                   new_indx)
            except AttributeError:
                pass

            if isinstance(item, Layer):
                layer_data = item.data(1, Qt.UserRole).toPyObject()[0]
                parent = item.parent()
                if not parent:
                    layer_data['layerType'] = 0
                else:
                    layer_data['layerType'] = 2

                varient = QVariant((layer_data, ))
                item.setData(1, Qt.UserRole, varient)

            elif isinstance(item, Folder):
                for i in range(item.childCount()):
                    if item.visible is True:
                        item.child(i).setFlags(Qt.ItemIsSelectable
                                               | Qt.ItemIsEditable
                                               | Qt.ItemIsEnabled
                                               | Qt.ItemIsDragEnabled)
                    else:
                        item.child(i).setFlags(Qt.NoItemFlags)
                    self.paint_scene.toggle_layer_visibility(
                        item.child(i).stroke_index, item.visible)
            iterator += 1

    def set_pen_size(self, size):
        """
        Sets pen size from slider input

        Args:
            size (int): diameter of pen
        """
        self.paint_scene.set_pen_size(size)
        self._update_brush_ui()

    def set_pen_blur(self, blur):
        """
        Sets pen blur

        Args:
            blur (int): level of blur
        """
        self.paint_scene.set_pen_blur(blur)
        self._update_brush_ui()

    def set_pen_color(self, color):
        """
        sets pen color

        Args:
            color (QColor): color to set
        """
        self.paint_scene.set_pen_color(color)
        self._update_brush_ui()

    def update_pen_color(self):
        """
        updates pen color from color picker
        """
        color = self.color_dialog.getColor(self.paint_scene.pen_color, self,
                                           QString('Color'),
                                           QtGui.QColorDialog.ShowAlphaChannel)
        self.paint_scene.set_pen_color(color)

        style = QString("QPushButton { border-style: none; \
                                              border-radius: 10px; \
                                              min-width: 3em; \
                                              height: 3em; \
                                              background-color: " +
                        color.name() + "}")
        self.color_BTN.setStyleSheet(style)

    def on_timer(self):
        """
        saves image to temporary file
        
        if self.num_layers != self.old_layers :
            self.old_layers = self.num_layers
            """
        img = self.get_img()
        img.save(self.tmpFilepath)

    def save_img(self):
        """
        saves image to file
        """
        filepath = self.file_dialog.getSaveFileName(self, "Save Canvas",
                                                    "Render",
                                                    "Images (*.png *.jpg)")
        if filepath:
            img = self.get_img()
            img.save(filepath)

    def get_img(self):
        """
        gets image from PyQtPaint

        Returns:
            img: returns QImage data from canvas
        """
        img = QtGui.QImage(self.paint_scene.width, self.paint_scene.height,
                           QtGui.QImage.Format_RGB32)
        paint = QtGui.QPainter(img)
        paint.setRenderHint(QtGui.QPainter.Antialiasing)
        self.paint_scene.render(paint)
        paint.end()
        return img

    """
    HFNet function by Hebb rule
    """

    def predict(self):
        if not self.working:
            self.working = True
            predict = Predict(_predict.predict)
            predict.signals.result.connect(self.print_output)
            predict.signals.finished.connect(self.thread_complete)

            # Execute
            self.threadpool.start(predict)

    def thread_complete(self):
        self.working = False
        print("THREAD COMPLETE!")

    def print_output(self, s):
        ##self.resulted = int(s)
        if s == 0:
            self.results.setText(u"É um retângulo.")
        elif s == 1:
            self.results.setText(u"Catetos, catetos, catetos...")
        elif s == 2:
            self.results.setText(u"Catetos, catetos, catetos...")
        elif s == 3:
            self.results.setText(u"Catetos, catetos, catetos...")
        elif s == 4:
            self.results.setText(u"É círculo")
        else:
            self.results.setText(u"Sei lá")
        ##print(s)

    def progress_fn(self, n):
        print("%d%% done" % n)
Esempio n. 11
0
class WorkHandler(object):
    """
    Class to handle threading of "work" (concretely this is just the evaluation of a function of the
     form func(*args, **kwargs).

     The process ID identifies (uniquely) each instance of a Worker; but the caller also defines
     an ID which is then used to identify the Worker through the API.
    """
    class WorkListener(with_metaclass(ABCMeta, object)):
        """
        This abstract base class defines methods which must be overriden and which
        handle responses to certain worker actions such as raised errors, or completion.
        """
        def __init__(self):
            pass

        @abstractmethod
        def on_processing_finished(self, result):
            pass

        @abstractmethod
        def on_processing_error(self, error):
            pass

    def __init__(self):
        self.thread_pool = None
        self._listener = {}
        self._worker = {}
        self.thread_pool = QThreadPool()

    def _add_listener(self, listener, process_id, id):
        if not isinstance(listener, WorkHandler.WorkListener):
            raise ValueError("The listener is not of type "
                             "WorkListener but rather {}".format(
                                 type(listener)))
        self._listener.update({process_id: {'id': id, 'listener': listener}})

    @pyqtSlot()
    def on_finished(self, process_id):
        if process_id not in self._worker:
            return
        result = self._worker.pop(process_id)['worker'].result
        self._listener.pop(process_id)['listener'].on_processing_finished(
            result)

    @pyqtSlot()
    def on_error(self, process_id, error):
        if process_id not in self._worker:
            return
        self._listener[process_id]['listener'].on_processing_error(error)

    def process(self, caller, func, id, *args, **kwargs):
        """
        Process a function call with arbitrary arguments on a new thread.

        :param caller: ??
        :param func: The function to be evaluated.
        :param id: An identifying integer for the task.
        :param args: args for func.
        :param kwargs: keyword args for func.
        """
        self.remove_already_processing(id)
        process_id = uuid.uuid4()
        # Add the caller
        self._add_listener(caller, process_id, id)

        finished_callback = functools.partial(self.on_finished, process_id)
        error_callback = functools.partial(self.on_error, process_id)

        worker = Worker(func, *args, **kwargs)
        worker.signals.finished.connect(finished_callback)
        worker.signals.error.connect(error_callback)

        self._worker.update({process_id: {'id': id, 'worker': worker}})

        self.thread_pool.start(self._worker[process_id]['worker'])

    def remove_already_processing(self, id):
        """
        Remove workers with ID
        :param id:
        """
        for key, process in list(self._listener.items()):
            if process['id'] == id:
                self._listener.pop(key)
                self._worker.pop(key)

    def wait_for_done(self):
        self.thread_pool.waitForDone()

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        return self.__dict__ != other.__dict__
Esempio n. 12
0
class WorkHandler(object):
    """
    Class to handle threading of "work" (concretely this is just the evaluation of a function of the
     form func(*args, **kwargs).

     The process ID identifies (uniquely) each instance of a Worker; but the caller also defines
     an ID which is then used to identify the Worker through the API.
    """

    class WorkListener(with_metaclass(ABCMeta, object)):
        """
        This abstract base class defines methods which must be overriden and which
        handle responses to certain worker actions such as raised errors, or completion.
        """

        def __init__(self):
            pass

        @abstractmethod
        def on_processing_finished(self, result):
            pass

        @abstractmethod
        def on_processing_error(self, error):
            pass

    def __init__(self):
        self.thread_pool = None
        self._listener = {}
        self._worker = {}
        self.thread_pool = QThreadPool()

    def _add_listener(self, listener, process_id, id):
        if not isinstance(listener, WorkHandler.WorkListener):
            raise ValueError("The listener is not of type "
                             "WorkListener but rather {}".format(type(listener)))
        self._listener.update({process_id: {'id': id, 'listener': listener}})

    @pyqtSlot()
    def on_finished(self, process_id):
        if process_id not in self._worker:
            return
        result = self._worker.pop(process_id)['worker'].result
        self._listener.pop(process_id)['listener'].on_processing_finished(result)

    @pyqtSlot()
    def on_error(self, process_id, error):
        if process_id not in self._worker:
            return
        self._listener[process_id]['listener'].on_processing_error(error)

    def process(self, caller, func, id, *args, **kwargs):
        """
        Process a function call with arbitrary arguments on a new thread.

        :param caller: ??
        :param func: The function to be evaluated.
        :param id: An identifying integer for the task.
        :param args: args for func.
        :param kwargs: keyword args for func.
        """
        self.remove_already_processing(id)
        process_id = uuid.uuid4()
        # Add the caller
        self._add_listener(caller, process_id, id)

        finished_callback = functools.partial(self.on_finished, process_id)
        error_callback = functools.partial(self.on_error, process_id)

        worker = Worker(func, *args, **kwargs)
        worker.signals.finished.connect(finished_callback)
        worker.signals.error.connect(error_callback)

        self._worker.update({process_id: {'id': id, 'worker': worker}})

        self.thread_pool.start(self._worker[process_id]['worker'])

    def remove_already_processing(self, id):
        """
        Remove workers with ID
        :param id:
        """
        for key, process in list(self._listener.items()):
            if process['id'] == id:
                self._listener.pop(key)
                self._worker.pop(key)

    def wait_for_done(self):
        self.thread_pool.waitForDone()

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        return self.__dict__ != other.__dict__
Esempio n. 13
0
class KISS_Thread(QtCore.QThread):
    """
        AX.25 Communication
    """
    packet_received = pyqtSignal("QString", name="packetReceived")

    def __init__(self, control_system):
        """Make a instance of the ReaderAndWriterThread class.
        Args:
            protocol (SerialProtocol): It is a instance of a communication protocol.
        """
        QThread.__init__(self, control_system)
        self.writer_thread = QThreadPool(self)
        self.writer_thread.setMaxThreadCount(1)

    def run(self):
        print "kiss started"
        self.kiss_connect()

    def read_callback(self, data):
        print "received packet, len", len(data)
        kiss_data = kiss.constants.FEND + kiss.util.escape_special_codes(data) + kiss.constants.FEND
        log_the_data("./log_files/telemetry_log_files/BSU_satellite.kss", kiss_data)
        data = data[1:]
        if len(data) < 15:
            print "bad packet"
            return
        dest = "".join([chr(ord(c) >> 1) for c in data[:6]])
        # print "Destination", dest
        src = "".join([chr(ord(c) >> 1) for c in data[7:13]])
        #print "Source", src
        if not dest.startswith(LOCAL_SSID):
            print "packet not for us"
            return
        start = 16
        ssid = ord(data[13]) & 1
        if ssid == 0:
            via = "".join([chr(ord(c) >> 1) for c in data[7:13]])
            start = 23
        size = len(data) - start
        if size == 0:
            print "packet is empty"
            return
        payload = data[start:]
        # self.control_system.on_packet_received(payload)
        self.packet_received.emit(payload)

    def kiss_connect(self):
        try:
            print "connect"
            self.kiss_prot = kiss.KISS(port=config.kiss_serial_name, speed=config.kiss_baudrate)
            self.kiss_prot.start()
            self.kiss_prot.read(self.read_callback)
        except:
            error_mesage = "CANNOT OPEN PORT"
            log_the_error(error_mesage)
            sound.play(error_mesage)

            print sys.exc_info()
            print "ax.25 is failed"


    def send_command(self, name, arg, device, time_of_execution):
        data = {
            "Timestamp": int(time.time()),
            "Schedule": time_of_execution,
            "Cmd": name,
            "Arg": arg,
            "Device": device
        }
        json_data = json.dumps(data)

        print "Formed packet", json_data
        writer = KissWriter(self.kiss_prot, LOCAL_SSID, REMOTE_SSID)
        writer.set_data(json_data)
        self.writer_thread.start(writer)
Esempio n. 14
0
class CatalogDialogTool(QObject):
    """
    Tool for managing the search and export functionality
    """

    def __init__(self, iface, dialog_ui, bbox_tool):
        """
        Constructor for the dialog tool
        :param iface: The QGIS Interface
        :param dialog_ui: The dialog GUI
        :param bbox_tool The bounding box tool
        :return: dialog tool
        """
        QObject.__init__(self, None)
        self.iface = iface
        self.dialog_ui = dialog_ui
        self.bbox_tool = bbox_tool

        self.progress_bar = None
        self.progress_message_bar = None
        self.progress_message_bar_widget = None
        self.search_thread_pool = QThreadPool()
        self.search_lock = Lock()
        self.export_thread_pool = QThreadPool()
        self.export_lock = Lock()
        self.query = None
        self.previous_credentials = None
        self.export_file = None
        self.footprint_layer = None

        self.filters = CatalogFilters(self.dialog_ui)

        self.dialog_ui.aoi_button.clicked.connect(self.aoi_button_clicked)
        self.dialog_ui.reset_button.clicked.connect(self.reset_button_clicked)
        self.dialog_ui.export_button.clicked.connect(self.export_button_clicked)
        self.bbox_tool.released.connect(self.search)
        self.model = None

    def init_progress_bar(self, progress_max):
        """
        Sets up the progress bar for search functionality
        :return: None
        """
        if not self.progress_message_bar:
            self.progress_message_bar = self.iface.messageBar().createMessage("Querying for data")
            self.progress_bar = QProgressBar()
            self.progress_bar.setMinimum(0)
            self.progress_bar.setMaximum(progress_max)
            self.progress_bar.setAlignment(Qt.AlignLeft | Qt.AlignCenter)
            self.progress_message_bar.layout().addWidget(self.progress_bar)
            self.progress_message_bar_widget = self.iface.messageBar().pushWidget(self.progress_message_bar, self.iface.messageBar().INFO)

    def init_layers(self):
        """
        Sets up the layers for rendering the items
        :return: None
        """
        if self.footprint_layer:
            QgsMapLayerRegistry.instance().removeMapLayer(self.footprint_layer.id())

        self.footprint_layer = QgsVectorLayer("Polygon?crs=EPSG:4326", "Catalog Footprints", "memory")
        self.footprint_layer.setCrs(QgsCoordinateReferenceSystem(4326), True)
        self.footprint_layer.dataProvider().addAttributes(CatalogAcquisitionFeature.get_fields())
        QgsMapLayerRegistry.instance().addMapLayer(self.footprint_layer)

    def clear_widgets(self):
        """
        Clears the progress bar
        :return: None
        """
        self.progress_bar = None
        self.progress_message_bar = None
        if self.progress_message_bar_widget:
            self.iface.messageBar().popWidget(self.progress_message_bar_widget)
        self.progress_message_bar_widget = None

    def is_searching(self):
        """
        Check to see if the system is still searching (checks if there's work in the search thread pool)
        :return: True if searching; False otherwise
        """
        return self.get_search_active_thread_count() > 0

    def is_exporting(self):
        """
        Check to see if the system is still exporting (checks if there's work in the export thread pool)
        :return: True if searching; False otherwise
        """
        return self.get_export_active_thread_count() > 0

    def get_search_active_thread_count(self):
        """
        Gets the number of active threads in the search thread pool
        :return:
        """
        with self.search_lock:
            return self.search_thread_pool.activeThreadCount()

    def get_export_active_thread_count(self):
        """
        Gets the number of active threads in the export thread pool
        :return:
        """
        with self.export_lock:
            return self.export_thread_pool.activeThreadCount()

    def aoi_button_clicked(self):
        """
        Validates and runs the search if validation successful
        :return: None
        """
        # can't run search during export
        if self.is_exporting():
            self.iface.messageBar().pushMessage("Error", "Cannot run search while export is running.", level=QgsMessageBar.CRITICAL)
        # can't run multiple search
        elif self.is_searching():
            self.iface.messageBar().pushMessage("Error", "Cannot run a new search while a search is running.", level=QgsMessageBar.CRITICAL)
        else:
            self.bbox_tool.reset()
            self.iface.mapCanvas().setMapTool(self.bbox_tool)

    def reset_button_clicked(self):
        """
        Resets filters.
        :return: None
        """
        self.reset()

    def export_button_clicked(self):
        """
        Validates and runs the export if validation successful
        :return: None
        """
        # can't run export during search
        if self.is_searching():
            self.iface.messageBar().pushMessage("Error", "Cannot run export while search is running.", level=QgsMessageBar.CRITICAL)
        # can't run multiple exports
        elif self.is_exporting():
            self.iface.messageBar().pushMessage("Error", "Cannot run a new export while a export is running.", level=QgsMessageBar.CRITICAL)
        else:
            self.export()

    def search(self, top, bottom, left, right):
        self.search_thread_pool.waitForDone(0)

        # validate credentials if they changed
        errors = []
        username, password, api_key, max_items_to_return = SettingsOps.get_settings()
        credentials = [username, password, api_key]
        if not self.previous_credentials or self.previous_credentials != credentials:
            SettingsOps.validate_stored_info(username, password, api_key, max_items_to_return, errors)
        self.previous_credentials = credentials

        # validate filters
        if not errors:
            self.filters.validate(errors)

        if errors:
            self.iface.messageBar().pushMessage("Error", "The following errors occurred: " + "<br />".join(errors), level=QgsMessageBar.CRITICAL)
        else:
            self.init_layers()

            self.dialog_ui.tab_widget.setCurrentIndex(RESULTS_TAB_INDEX)
            
            next_x_list = self.drange_list(float(left) + INCREMENTAL_INTERVAL, float(right), INCREMENTAL_INTERVAL)
            next_y_list = self.drange_list(float(bottom) + INCREMENTAL_INTERVAL, float(top), INCREMENTAL_INTERVAL)
            self.init_progress_bar(len(next_x_list) * len(next_y_list))

            self.model = CatalogTableModel(self.dialog_ui.table_view)
            self.dialog_ui.table_view.setModel(self.model)
            self.dialog_ui.table_view.selectionModel().selectionChanged.connect(self.selection_changed)

            if not self.query:
                self.query = GBDQuery(username=username, password=password, api_key=api_key)

            filters = self.filters.get_query_filters()
            time_begin = self.filters.get_datetime_begin()
            time_end = self.filters.get_datetime_end()

            current_x = float(left)
            current_y = float(bottom)
            for next_x in next_x_list:
                for next_y in next_y_list:
                    search_runnable = CatalogSearchRunnable(self.query, self.model, self, top=next_y, left=current_x, right=next_x, bottom=current_y, 
                                                            time_begin=time_begin, time_end=time_end, filters=filters)
                    search_runnable.task_object.task_complete.connect(self.on_search_complete)
                    self.search_thread_pool.start(search_runnable)
                    current_y = next_y
                current_y = bottom
                current_x = next_x

    def reset(self):
        self.filters.remove_all()

    def export(self):
        self.export_thread_pool.waitForDone(0)
        acquisitions = None
        if self.model is not None:
            acquisitions = self.model.data

        if not acquisitions:
            self.iface.messageBar().pushMessage("Error", "No data to export.", level=QgsMessageBar.CRITICAL)
        else:
            # open file ui
            select_file_ui = QFileDialog()
            starting_file = self.export_file or os.path.expanduser("~")
            export_file = select_file_ui.getSaveFileName(None, "Choose output file", starting_file, SELECT_FILTER)

            if export_file:
                self.export_file = export_file
                self.init_progress_bar(0)
                export_runnable = CatalogExportRunnable(acquisitions, self.export_file)
                export_runnable.task_object.task_complete.connect(self.on_export_complete)
                self.export_thread_pool.start(export_runnable)

    @pyqtSlot()
    def on_search_complete(self):
        thread_count = self.get_search_active_thread_count()
        if self.progress_message_bar:
            self.progress_bar.setValue(self.progress_bar.value() + 1)
        if thread_count == 0:
            self.clear_widgets()
            self.dialog_ui.table_view.resizeColumnsToContents()

    @pyqtSlot()
    def on_export_complete(self):
        thread_count = self.get_export_active_thread_count()
        if self.progress_message_bar:
            self.progress_bar.setValue(self.progress_bar.value() + 1)
        if thread_count == 0:
            self.clear_widgets()
            self.iface.messageBar().pushMessage("Info", 'File export has completed to "%s".' % self.export_file)

    def selection_changed(self, selected, deselected):
        self.footprint_layer.startEditing()

        # draw footprints for selected rows
        selected_rows = set()
        for index in selected.indexes():
            selected_rows.add(index.row())
        for row in selected_rows:
            acquisition = self.model.get(row)
            feature_id = self.model.generate_feature_id()
            self.model.set_feature_id(acquisition, feature_id)
            feature = CatalogAcquisitionFeature(feature_id, acquisition)
            self.footprint_layer.dataProvider().addFeatures([feature])

        # remove footprints for deselected rows
        deselected_rows = set()
        for index in deselected.indexes():
            deselected_rows.add(index.row())
        feature_ids_to_remove = []
        for row in deselected_rows:
            acquisition = self.model.get(row)
            feature_id = self.model.get_feature_id(acquisition)
            feature_ids_to_remove.append(feature_id)
            self.model.remove_feature_id(acquisition)
        if feature_ids_to_remove:
            self.footprint_layer.dataProvider().deleteFeatures(feature_ids_to_remove)

        self.footprint_layer.commitChanges()
        self.footprint_layer.updateExtents()
        self.footprint_layer.triggerRepaint()

    def drange_list(self, start, stop, step):
        drange_list = []
        r = start
        while r < stop:
            drange_list.append(r)
            r += step
        if not drange_list:
            drange_list.append(stop)
        return drange_list
Esempio n. 15
0
class CSVGenerator:

    def __init__(self, left, top, right, bottom, csv_filename, username, password, client_id, client_secret, days_to_query=60):
        self.left = left
        self.top = top
        self.right = right
        self.bottom = bottom
        self.csv_filename = csv_filename
        self.days_to_query = days_to_query
        self.begin_date = None
        self.end_date = None

        self.username = username
        self.password = password
        self.client_id = client_id
        self.client_secret = client_secret

        # throw up a progress dialog
        min_progress = 0.0
        max_progress = ((self.right - self.left) / INCREMENTAL_INTERVAL) * \
                       ((self.top - self.bottom) / INCREMENTAL_INTERVAL)
        self.current_progress = min_progress

        self.progress_dialog = QProgressDialog("Building up CSV file", "Abort", int(min_progress), int(max_progress),
                                               None)
        self.progress_dialog.setCancelButton(None)
        self.progress_dialog.setWindowTitle("CSV Output")
        self.progress_dialog.setLabelText("Building up CSV file")
        self.progress_dialog.setMinimumDuration(0)
        self.progress_dialog.setValue(0)
        self.progress_dialog.show()

        self.csv_elements = []

        self.csv_generator_object = CSVGeneratorObject(self)
        
        self.vector_header_dict = {}

        self.pool = QThreadPool()

        self.finished_submissions = False

        self.lock = Lock()

    def generate_csv(self):
        # dates
        now = datetime.now()
        self.end_date = now
        self.begin_date = now - timedelta(days=self.days_to_query)

        current_x = self.left
        current_y = self.bottom

        serial_no = 1
        
        # get header dict
        vector_query = VectorQuery(username=self.username, password=self.password, client_id=self.client_id, client_secret=self.client_secret)
        vector_query.log_in()
        vector_params = InfoCubeVectorParams(top=self.top, bottom=self.bottom, left=self.left, right=self.right, time_begin=self.begin_date, time_end=self.end_date)
        header_result = vector_query.get_vector_result(vector_params)
        self.vector_header_dict = vector_query.get_vector_data(header_result)

        for next_x in drange(self.left + INCREMENTAL_INTERVAL, self.right, INCREMENTAL_INTERVAL):
            for next_y in drange(self.bottom + INCREMENTAL_INTERVAL, self.top, INCREMENTAL_INTERVAL):

                username = self.username
                password = self.password
                client_id = self.client_id
                client_secret = self.client_secret
                
                csv_runnable = CSVRunnable(username, password, client_id, client_secret,
                                           serial_no, next_y, current_x, next_x,
                                           current_y, self.begin_date, self.end_date, self.vector_header_dict)
                csv_runnable.csv_object.new_csv_element.connect(self.csv_generator_object.callback)
                self.pool.start(csv_runnable)

                serial_no += 1
                current_y = next_y

            current_y = self.bottom
            current_x = next_x

        self.finished_submissions = True

    def on_completion(self):
        self.csv_elements.sort(key=lambda element: element.serial_no)
        log.info("Sort complete")
        # write file
        csv_file = open(self.csv_filename, 'w')
        
        # write the header
        header = CSVOutput.get_csv_header()
        if self.vector_header_dict:
            for term in self.vector_header_dict:
                header = header + str(term) + ","
        header = header[:-1]
        csv_file.write(header)
        csv_file.write("\n")

        for csv_element in self.csv_elements:
            csv_file.write(str(csv_element))
            csv_file.write("\n")

        csv_file.close()
        log.info("Write complete")

        if self.progress_dialog:
            self.progress_dialog.close()

        self.csv_generator_object.message_complete.emit(self.csv_filename)
Esempio n. 16
0
class CLinesWindow(QtGui.QMainWindow):
    """The GUI in which the user can paste clines, check if they work and get a hadu text.
    """

    # regular expression used to find clines in user pasted text
    CLINE_REGEX = '^[Cc]{1}[:]{1}[ \t]+([^ \t]+)[ \t]+([0-9]+)[ \t]+([^ \t]+)[ \t]+([^ \t]+)'

    # If you want invalid clines to show in the final hadu list, commented or not, set ON_INVALID_CLINES
    # among the following:
    INVALID_CLINES_EXCLUDE = 'exclude'
    INVALID_CLINES_COMMENT = 'comment'
    INVALID_CLINES_DO_NOTHING = 'no'
    ON_INVALID_CLINES = INVALID_CLINES_EXCLUDE

    def __init__(self):
        QtGui.QMainWindow.__init__(self)

        self.pasted_text = ''
        self.clines = []
        self.invalid_lines = []
        self.hadu_lines = []
        self._clines_textarea = None
        self._c_widget = None
        self._hadu_textarea = None
        self._n_tested = 0
        self.servers_to_test = {}

        # Drawing window stuff
        self.resize(640, 480)

        self.layout = QtGui.QVBoxLayout()

        self.stacked_widget = QtGui.QStackedWidget()

        self.scroll_area = QtGui.QScrollArea(self)
        self.scroll_area.setWidgetResizable(True)

        self.layout.addWidget(self.scroll_area)
        self.scroll_area.setWidget(self.stacked_widget)

        self.widget = QtGui.QWidget()
        self.widget.setLayout(self.layout)
        self.setCentralWidget(self.widget)

        # PROGRESS BAR
        self.progress_bar = QtGui.QProgressBar(self)
        self.progress_bar.setAlignment(QtCore.Qt.AlignCenter)
        self.progress_bar.setMinimum(0)
        self.progress_bar.setMaximum(100)
        self.layout.addWidget(self.progress_bar)
        self.progress_bar.hide()

        # BUTTONS
        self.button_box = QtGui.QDialogButtonBox(self)
        self.button_box.setGeometry(QtCore.QRect(10, 480, 461, 32))
        self.button_box.setOrientation(QtCore.Qt.Horizontal)
        self.button_box.setStandardButtons(
            QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok
        )
        self.button_box.setObjectName(_fromUtf8("OkCancelButtonBox"))
        self.button_ok, self.button_cancel = self.button_box.buttons()
        self.button_cancel.setText('Back')
        self.button_cancel.setDisabled(True)
        self.button_ok.clicked.connect(self.__next_page)
        self.button_cancel.clicked.connect(self.__prev_page)
        self.layout.addWidget(self.button_box)

        # Current page
        self.page_index = 1

        self.page1()

    def page1(self):
        """This page contains a textarea where the user can paste CLines to be tested and converted.
        """

        self.setWindowTitle(u"CCCAM - Paste CLines")
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("icons/icon.png"), QtGui.QIcon.Normal,
                       QtGui.QIcon.Off)
        self.setWindowIcon(icon)

        if self._c_widget:
            self.stacked_widget.removeWidget(self._c_widget)

        # Drawing the textatrea where you paste your CLines
        self._clines_textarea = QtGui.QPlainTextEdit(self)
        self._clines_textarea.setGeometry(QtCore.QRect(10, 20, 661, 451))
        self._clines_textarea.setObjectName(_fromUtf8("CCCAM lines"))

        if self.pasted_text:
            # Filling the textarea with the previously pasted CLines (if
            # we are coming back from page 2)
            self._clines_textarea.insertPlainText(self.pasted_text)

        self.stacked_widget.insertWidget(0, self._clines_textarea)

    def clean_line(self, line):
        """Returns a string containing a CLine, stripped of extra spaces and extra characters.

        I.e. '<server name> <port> <user> <pw>'
        """

        try:
            line = unicode(line).strip()
        except UnicodeEncodeError:
            self.invalid_lines.append(line)
            return None
        match = re.findall(self.CLINE_REGEX, line)
        if match:
            return list(match[0])  # "server_name, port, user, pw"
        # no valid CLine found in this string
        return None

    def generate_checkboxes(self, clines):
        """Generates a list of checkboxes, one for each recognized CLine.

        The label describes the CLine and shows a message telling if testing on that server was successful or not,
        once testing (which is asynchronous) is done.
        """

        # Grouping clines by server name+port: pasted clines might contain mnay entries for the same server+port
        # with different usernames and passwords. We want to keep those entries
        # together.
        clines_grouped = defaultdict(list)
        for server_name, port, user, pw in clines:
            clines_grouped[(server_name, port)].append((user, pw))
        clines_grouped = dict(clines_grouped)

        checkboxes = []

        if clines_grouped:
            i = 1
            for (server_name, port), users_pws in clines_grouped.items():
                # Shuffling each server+port usernames and passwords list. This is intended to add some variability
                # if you copy/paste a list of CLines from websites
                shuffle(users_pws)
                for j, (user, pw) in enumerate(users_pws):

                    checkbox = QtGui.QCheckBox(
                        "%s %s %s %s" % (server_name, port, user, pw),
                        self.stacked_widget
                    )
                    checkboxes.append(checkbox)

                    self.servers_to_test[
                        (server_name, port, user, pw)] = checkbox

                i += 1

        return checkboxes

    def retrieve_clines(self, text):
        """Parses the text pasted in the textarea, looking for valid CLines, stripping whitespaces, comments and
        other garbage.
        """

        clines = []

        for line in text.split('\n'):
            line = self.clean_line(line)

            if line is not None:
                clines.append(line)

        return sorted(
            clines, key=lambda l: ''.join(l)
        )

    def page2(self):
        """List of found CLines, checkboxes to select lines to include.
        """

        self._checkboxes = []
        self.clines = []

        self.setWindowTitle(u"CCCAM - Testing servers")

        if self._clines_textarea:
            self.stacked_widget.removeWidget(self._clines_textarea)
        if self._c_widget:
            self.stacked_widget.removeWidget(self._c_widget)
        if self._hadu_textarea:
            self.stacked_widget.removeWidget(self._hadu_textarea)

        self.pasted_text = self._clines_textarea.toPlainText()

        self._c_widget = QtGui.QWidget(self)

        grid = QtGui.QGridLayout(self._c_widget)

        self.clines = self.retrieve_clines(self.pasted_text)

        self._checkboxes = self.generate_checkboxes(self.clines)

        for i, checkbox in enumerate(self._checkboxes):
            grid.addWidget(checkbox, i, 0)
            # https://stackoverflow.com/questions/11073972/pyqt-set-qlabel-image-from-url
            # grid.addWidget(icon, i, 1)

        self._c_widget.setLayout(grid)

        self.stacked_widget.insertWidget(0, self._c_widget)

        # Showing the progress bar, disabling the OK button until processing is finished
        self.button_ok.setDisabled(True)
        self.progress_bar.setMaximum(len(self.servers_to_test))
        self.progress_bar.show()
        self.progress_bar.setTextVisible(True)
        self._update_progress_bar()

        self.start_testing()

    def start_testing(self):
        """Tests all servers by using various thread workers (QRunnables) in a thread pool.

        This way testing is done asynchronously, since some servers may take some time to answer, so the UI is
        not blocked until the process is done and we can show a progress bar.

        See:
        https://martinfitzpatrick.name/article/multithreading-pyqt-applications-with-qthreadpool/
        https://nikolak.com/pyqt-threading-tutorial/
        """

        # A thread pool is a thread automatically hadling various tasks.
        self.threadpool = QThreadPool()
        self._n_tested = 0

        for data in self.servers_to_test:
            worker = CLineTestWorker(*data)
            # When each worker is done, `end_testing` is called.
            worker.signals.finished.connect(self.end_testing)

            # Executing the thread worker within the pool.
            self.threadpool.start(worker)

    def _update_progress_bar(self, value=0):
        self.progress_bar.setValue(value)

    def end_testing(self, server_data, error_msg=''):
        """Callback method that handles each thread worker finishing testing, with success or not.

        It updated the progress bar and the checkbox text with a success/failure message .
        """
        self._n_tested += 1
        self._update_progress_bar(self._n_tested)

        checkbox = self.servers_to_test[tuple(server_data)]
        t = checkbox.text()

        if error_msg:
            # Server testing has failed
            checkbox.setChecked(False)
            checkbox.setText("%s  [FAILED: %s]" % (t, error_msg))
        else:
            # SUCCESS!
            checkbox.setChecked(True)
            checkbox.setText("%s  [OK]" % t)

        if self._n_tested >= len(self.servers_to_test):
            # All servers have been tested, enabling the ok button.
            self.button_ok.setDisabled(False)

    def cline_to_hadu_string(self, n, cline, invalid=False):
        """Converts a cline tuple into a hadu plugin string.
        e.g.
        """

        comment = ''
        if invalid:
            if self.ON_INVALID_CLINES == self.INVALID_CLINES_EXCLUDE:
                return
            elif self.ON_INVALID_CLINES == self.INVALID_CLINES_COMMENT:
                comment = ';'

        text = "{comment}[Serv_{servname}]\n{comment}Server=CCCam:{server}"\
               ":{port}:0:{user}:{pw}\n"
        server, port, user, pw = cline

        self.hadu_lines.append(text.format(
            servname='%s_%s' % (n, slugify(server)), server=server, port=port,
            user=user, pw=pw, comment=comment
        ))

    def page3(self):
        """Final page, showing valid clines in had format.
        """
        self.setWindowTitle('CCCAM - Hadu lines')

        self.stacked_widget.removeWidget(self._c_widget)

        for i, checkbox in enumerate(self._checkboxes):
            self.cline_to_hadu_string(i, self.clines[i], invalid=not checkbox.isChecked())

        self._hadu_textarea = QtGui.QPlainTextEdit(self)
        self._hadu_textarea.setGeometry(QtCore.QRect(10, 20, 461, 451))
        self._hadu_textarea.setObjectName(_fromUtf8("Hadu lines"))
        self._hadu_textarea.setReadOnly(True)
        self._hadu_textarea.insertPlainText('\n'.join(self.hadu_lines))
        self._hadu_textarea.moveCursor(QtGui.QTextCursor.End)
        self._hadu_textarea.selectAll()

        self.stacked_widget.insertWidget(0, self._hadu_textarea)
        self.stacked_widget.setCurrentIndex(0)

    def __change_page(self):
        self.button_ok.show()
        self.button_ok.setDisabled(False)
        self.button_cancel.show()
        self.button_cancel.setDisabled(False)
        self.progress_bar.hide()

        if self.page_index == 1:
            self.button_cancel.setDisabled(True)

        if self.page_index >= 3:
            self.button_ok.setDisabled(True)

        page = getattr(self, 'page%s' % self.page_index)

        page()

    def __next_page(self):
        self.page_index += 1
        if self.page_index > 3:
            self.destroy()

        self.__change_page()

    def __prev_page(self):
        self.page_index -= 1
        if self.page_index < 1:
            self.page_index = 1

        self.__change_page()
Esempio n. 17
0
class DownloaderWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        self.DownloadPath = os.path.expanduser("~") # get home dir
        self.pool = QThreadPool()
        self.pool.setMaxThreadCount(1)

        self.initVariables()

        self.resize(700, 400)
        self.initUI()

        self.line_downpath.setText(self.down_control.getDownloadPath())

    def initVariables(self):
        self.down_control = DownloadController(self.addInfo)
        self.down_control.setDownloadPath(self.DownloadPath)
        self.chapters = None
        self.chapters_filtered = None
        self.ch_from = None
        self.ch_to = None

    def initUI(self):
        cw = QWidget()
        self.setCentralWidget(cw)
        layout_main = QVBoxLayout()
        layout_main.setSpacing(5)

        ## Info
        self.info = QTextEdit()
        self.info.setReadOnly(True)
        self.info.setLineWrapMode(QTextEdit.NoWrap)

        layout_main.addWidget(self.info, 1)

        ## Line edit
        layout_url = QHBoxLayout()
        layout_url.setSpacing(5)

        self.line_url = QLineEdit()

        layout_url.addWidget(QLabel('<b>Series URL:</b>'))
        layout_url.addWidget(self.line_url, 1)
        layout_main.addLayout(layout_url)

        ## Comboboxes
        layout_combo = QHBoxLayout()
        layout_combo.setSpacing(5)

        self.combo_from = QComboBox()
        self.combo_from.setEnabled(False)
        self.combo_to = QComboBox()
        self.combo_to.setEnabled(False)

        layout_combo.addWidget(QLabel('<b>Download chapters: </b>'))
        layout_combo.addWidget(QLabel(' From:'))
        layout_combo.addWidget(self.combo_from, 1)
        layout_combo.addWidget(QLabel('To:'))
        layout_combo.addWidget(self.combo_to, 1)

        layout_main.addLayout(layout_combo)

        ## Download path
        layout_downpath = QHBoxLayout()
        layout_downpath.setSpacing(5)

        self.line_downpath = QLineEdit()
        self.line_downpath.setEnabled(False)
        self.btn_downpath = QPushButton('Change')
        self.btn_downpath.pressed.connect(self.selectDownloadPath)

        layout_downpath.addWidget(QLabel('<b>Download path:</b>'))
        layout_downpath.addWidget(self.line_downpath, 1)
        layout_downpath.addWidget(self.btn_downpath)
        layout_main.addLayout(layout_downpath)

        ## Buttons
        layout_btn = QHBoxLayout()
        layout_btn.setSpacing(5)

        self.btn_getlist = QPushButton('Get List of Chapters')
        self.btn_getlist.pressed.connect(self.getChaptersList)
        self.btn_download = QPushButton('Download chapters')
        self.btn_download.pressed.connect(self.downloadChapters)
        self.btn_download.setEnabled(False)
        self.btn_exit = QPushButton('Exit')
        self.btn_exit.pressed.connect(self.close)

        layout_btn.addStretch()
        layout_btn.addWidget(self.btn_getlist)
        layout_btn.addWidget(self.btn_download)
        layout_btn.addWidget(self.btn_exit)
        layout_btn.addStretch()
        layout_main.addLayout(layout_btn)

        # status bar
        self.statusBar().showMessage('Ready')

        # add layout to main window
        cw.setLayout(layout_main)
        self.setWindowTitle('OMAD - Online MAnga Downloader')
        self.show()

    def closeEvent(self, event):
        """
        Runs when user tryes to close main window.

        sys.exit(0) - to fix wierd bug, where process is not terminated.
        """
        sys.exit(0)

    def addInfo(self, s='Testing printing...', exception=False, downloadProgress=False, trace=[]):
        logger.info(s+', '+str(exception)+', '+str(downloadProgress)+', '+str(trace))

        if type(s)!=type("") and type(s)!=type(b"") and type(s) != type(QtCore.QString('')):
            s = str(s)

        if exception:
            s = "!!! Exception: "+s

        if downloadProgress:
            s = "Downloading progress: "+s
            self.setStatusBarText(s)

        self.info.append(s)

        if exception:
            for t in trace:
                self.info.append(str(t))

        sb = self.info.verticalScrollBar()
        sb.setValue(sb.maximum())

        QtCore.QCoreApplication.processEvents()

    def setStatusBarText(self, s='Testing...'):
        """
        Changes status bar text
        """
        self.statusBar().showMessage(s)
        QtCore.QCoreApplication.processEvents()

    def getChaptersList(self):
        self.addInfo('Getting list of chapters...')

        # reinit clean variables
        self.initVariables()

        # get series url
        url = str(self.line_url.text()).strip()

        if not self.down_control.setSeriesUrl(url):
            return # bad url

        self.chapters = self.down_control.getChaptersList()

        logger.debug('Setting up comboBoxes...')
        for i in range(0, self.combo_from.count()):
            self.combo_from.removeItem(0)
        for i in range(0, self.combo_to.count()):
            self.combo_to.removeItem(0)

        for c in self.chapters:
            self.combo_from.addItem(c[0])
            self.combo_to.addItem(c[0])

        self.combo_from.setCurrentIndex(0)
        self.combo_to.setCurrentIndex(len(self.chapters)-1)

        self.addInfo('Chapter list loaded')

        self.combo_from.setEnabled(True)
        self.combo_to.setEnabled(True)
        self.btn_download.setEnabled(True)

    def downloadChapters(self):
        self.addInfo('Checking chapter range')

        self.ch_from = self.combo_from.currentIndex()
        self.ch_to = self.combo_to.currentIndex()

        if self.ch_from>self.ch_to:
            self.addInfo('Bad range. Cant download backwards!')
            return
        else:
            self.addInfo('Range OK, starting download of '+str((self.ch_to-self.ch_from)+1)+' chapters...')

        self.gui_disable(True)

        worker = DownloadWorker(self.down_control, self.ch_from, self.ch_to)
        worker.signals.update.connect(self.addInfo)
        worker.signals.finished.connect(self.downloadChapters_finished)
        self.pool.start(worker)

    def downloadChapters_finished(self):
        self.gui_disable(False)
        self.setStatusBarText('Ready - Download Finished!!')

        # Finished
        self.addInfo('Download Finished!!')

        # Print failed downloads
        failed_chs = []
        for i, r in enumerate(self.down_control.results):
            if r is False:
                failed_chs.append(self.chapters[i+self.ch_from])

        if len(failed_chs)==0:
            self.addInfo('\nNo failed downloads')
        else:
            self.addInfo('\nChapters with failed downloads:')
            for c in failed_chs:
                self.addInfo(c[0])
        self.addInfo('')

    def selectDownloadPath(self):
        downdir = self._get_dir(directory=self.DownloadPath)
        self.down_control.setDownloadPath(downdir)
        self.DownloadPath = self.down_control.getDownloadPath()
        self.line_downpath.setText(self.DownloadPath)

    def _get_dir(self, directory=''):
        """
        Draw a dialog for directory selection.
        """

        downdir = QFileDialog.getExistingDirectory(
            caption='Select Folder',
            options=QFileDialog.ShowDirsOnly,
            directory=directory
        )

        if len(downdir) > 0:
            downdir = "%s" % (downdir)
        else:
            downdir = directory

        return downdir

    def gui_disable(self, downloading=True):
        self.line_url.setEnabled(not downloading)
        self.combo_from.setEnabled(not downloading)
        self.combo_to.setEnabled(not downloading)
        self.btn_getlist.setEnabled(not downloading)
        self.btn_download.setEnabled(not downloading)
        self.btn_downpath.setEnabled(not downloading)
Esempio n. 18
0
class CSVGenerator:
    def __init__(self,
                 left,
                 top,
                 right,
                 bottom,
                 csv_filename,
                 username,
                 password,
                 client_id,
                 client_secret,
                 days_to_query=60):
        self.left = left
        self.top = top
        self.right = right
        self.bottom = bottom
        self.csv_filename = csv_filename
        self.days_to_query = days_to_query
        self.begin_date = None
        self.end_date = None

        self.username = username
        self.password = password
        self.client_id = client_id
        self.client_secret = client_secret

        # throw up a progress dialog
        min_progress = 0.0
        max_progress = ((self.right - self.left) / INCREMENTAL_INTERVAL) * \
                       ((self.top - self.bottom) / INCREMENTAL_INTERVAL)
        self.current_progress = min_progress

        self.progress_dialog = QProgressDialog("Building up CSV file", "Abort",
                                               int(min_progress),
                                               int(max_progress), None)
        self.progress_dialog.setCancelButton(None)
        self.progress_dialog.setWindowTitle("CSV Output")
        self.progress_dialog.setLabelText("Building up CSV file")
        self.progress_dialog.setMinimumDuration(0)
        self.progress_dialog.setValue(0)
        self.progress_dialog.show()

        self.csv_elements = []

        self.csv_generator_object = CSVGeneratorObject(self)

        self.vector_header_dict = {}

        self.pool = QThreadPool()

        self.finished_submissions = False

        self.lock = Lock()

    def generate_csv(self):
        # dates
        now = datetime.now()
        self.end_date = now
        self.begin_date = now - timedelta(days=self.days_to_query)

        current_x = self.left
        current_y = self.bottom

        serial_no = 1

        # get header dict
        vector_query = VectorQuery(username=self.username,
                                   password=self.password,
                                   client_id=self.client_id,
                                   client_secret=self.client_secret)
        vector_query.log_in()
        vector_params = InfoCubeVectorParams(top=self.top,
                                             bottom=self.bottom,
                                             left=self.left,
                                             right=self.right,
                                             time_begin=self.begin_date,
                                             time_end=self.end_date)
        header_result = vector_query.get_vector_result(vector_params)
        self.vector_header_dict = vector_query.get_vector_data(header_result)

        for next_x in drange(self.left + INCREMENTAL_INTERVAL, self.right,
                             INCREMENTAL_INTERVAL):
            for next_y in drange(self.bottom + INCREMENTAL_INTERVAL, self.top,
                                 INCREMENTAL_INTERVAL):

                username = self.username
                password = self.password
                client_id = self.client_id
                client_secret = self.client_secret

                csv_runnable = CSVRunnable(username, password, client_id,
                                           client_secret, serial_no, next_y,
                                           current_x, next_x, current_y,
                                           self.begin_date, self.end_date,
                                           self.vector_header_dict)
                csv_runnable.csv_object.new_csv_element.connect(
                    self.csv_generator_object.callback)
                self.pool.start(csv_runnable)

                serial_no += 1
                current_y = next_y

            current_y = self.bottom
            current_x = next_x

        self.finished_submissions = True

    def on_completion(self):
        self.csv_elements.sort(key=lambda element: element.serial_no)
        log.info("Sort complete")
        # write file
        csv_file = open(self.csv_filename, 'w')

        # write the header
        header = CSVOutput.get_csv_header()
        if self.vector_header_dict:
            for term in self.vector_header_dict:
                header = header + str(term) + ","
        header = header[:-1]
        csv_file.write(header)
        csv_file.write("\n")

        for csv_element in self.csv_elements:
            csv_file.write(str(csv_element))
            csv_file.write("\n")

        csv_file.close()
        log.info("Write complete")

        if self.progress_dialog:
            self.progress_dialog.close()

        self.csv_generator_object.message_complete.emit(self.csv_filename)
Esempio n. 19
0
class CatalogDialogTool(QObject):
    """
    Tool for managing the search and export functionality
    """
    def __init__(self, iface, dialog_ui, bbox_tool):
        """
        Constructor for the dialog tool
        :param iface: The QGIS Interface
        :param dialog_ui: The dialog GUI
        :param bbox_tool The bounding box tool
        :return: dialog tool
        """
        QObject.__init__(self, None)
        self.iface = iface
        self.dialog_ui = dialog_ui
        self.bbox_tool = bbox_tool

        self.progress_bar = None
        self.progress_message_bar = None
        self.progress_message_bar_widget = None
        self.search_thread_pool = QThreadPool()
        self.search_lock = Lock()
        self.export_thread_pool = QThreadPool()
        self.export_lock = Lock()
        self.query = None
        self.previous_credentials = None
        self.export_file = None
        self.footprint_layer = None

        self.filters = CatalogFilters(self.dialog_ui)

        self.dialog_ui.aoi_button.clicked.connect(self.aoi_button_clicked)
        self.dialog_ui.reset_button.clicked.connect(self.reset_button_clicked)
        self.dialog_ui.export_button.clicked.connect(
            self.export_button_clicked)
        self.bbox_tool.released.connect(self.search)
        self.model = None

    def init_progress_bar(self, progress_max):
        """
        Sets up the progress bar for search functionality
        :return: None
        """
        if not self.progress_message_bar:
            self.progress_message_bar = self.iface.messageBar().createMessage(
                "Querying for data")
            self.progress_bar = QProgressBar()
            self.progress_bar.setMinimum(0)
            self.progress_bar.setMaximum(progress_max)
            self.progress_bar.setAlignment(Qt.AlignLeft | Qt.AlignCenter)
            self.progress_message_bar.layout().addWidget(self.progress_bar)
            self.progress_message_bar_widget = self.iface.messageBar(
            ).pushWidget(self.progress_message_bar,
                         self.iface.messageBar().INFO)

    def init_layers(self):
        """
        Sets up the layers for rendering the items
        :return: None
        """
        if self.footprint_layer:
            QgsMapLayerRegistry.instance().removeMapLayer(
                self.footprint_layer.id())

        self.footprint_layer = QgsVectorLayer("Polygon?crs=EPSG:4326",
                                              "Catalog Footprints", "memory")
        self.footprint_layer.setCrs(QgsCoordinateReferenceSystem(4326), True)
        self.footprint_layer.dataProvider().addAttributes(
            CatalogAcquisitionFeature.get_fields())
        QgsMapLayerRegistry.instance().addMapLayer(self.footprint_layer)

    def clear_widgets(self):
        """
        Clears the progress bar
        :return: None
        """
        self.progress_bar = None
        self.progress_message_bar = None
        if self.progress_message_bar_widget:
            self.iface.messageBar().popWidget(self.progress_message_bar_widget)
        self.progress_message_bar_widget = None

    def is_searching(self):
        """
        Check to see if the system is still searching (checks if there's work in the search thread pool)
        :return: True if searching; False otherwise
        """
        return self.get_search_active_thread_count() > 0

    def is_exporting(self):
        """
        Check to see if the system is still exporting (checks if there's work in the export thread pool)
        :return: True if searching; False otherwise
        """
        return self.get_export_active_thread_count() > 0

    def get_search_active_thread_count(self):
        """
        Gets the number of active threads in the search thread pool
        :return:
        """
        with self.search_lock:
            return self.search_thread_pool.activeThreadCount()

    def get_export_active_thread_count(self):
        """
        Gets the number of active threads in the export thread pool
        :return:
        """
        with self.export_lock:
            return self.export_thread_pool.activeThreadCount()

    def aoi_button_clicked(self):
        """
        Validates and runs the search if validation successful
        :return: None
        """
        # can't run search during export
        if self.is_exporting():
            self.iface.messageBar().pushMessage(
                "Error",
                "Cannot run search while export is running.",
                level=QgsMessageBar.CRITICAL)
        # can't run multiple search
        elif self.is_searching():
            self.iface.messageBar().pushMessage(
                "Error",
                "Cannot run a new search while a search is running.",
                level=QgsMessageBar.CRITICAL)
        else:
            self.bbox_tool.reset()
            self.iface.mapCanvas().setMapTool(self.bbox_tool)

    def reset_button_clicked(self):
        """
        Resets filters.
        :return: None
        """
        self.reset()

    def export_button_clicked(self):
        """
        Validates and runs the export if validation successful
        :return: None
        """
        # can't run export during search
        if self.is_searching():
            self.iface.messageBar().pushMessage(
                "Error",
                "Cannot run export while search is running.",
                level=QgsMessageBar.CRITICAL)
        # can't run multiple exports
        elif self.is_exporting():
            self.iface.messageBar().pushMessage(
                "Error",
                "Cannot run a new export while a export is running.",
                level=QgsMessageBar.CRITICAL)
        else:
            self.export()

    def search(self, top, bottom, left, right):
        self.search_thread_pool.waitForDone(0)

        # validate credentials if they changed
        errors = []
        username, password, api_key, max_items_to_return = SettingsOps.get_settings(
        )
        credentials = [username, password, api_key]
        if not self.previous_credentials or self.previous_credentials != credentials:
            SettingsOps.validate_stored_info(username, password, api_key,
                                             max_items_to_return, errors)
        self.previous_credentials = credentials

        # validate filters
        if not errors:
            self.filters.validate(errors)

        if errors:
            self.iface.messageBar().pushMessage(
                "Error",
                "The following errors occurred: " + "<br />".join(errors),
                level=QgsMessageBar.CRITICAL)
        else:
            self.init_layers()

            self.dialog_ui.tab_widget.setCurrentIndex(RESULTS_TAB_INDEX)

            next_x_list = self.drange_list(
                float(left) + INCREMENTAL_INTERVAL, float(right),
                INCREMENTAL_INTERVAL)
            next_y_list = self.drange_list(
                float(bottom) + INCREMENTAL_INTERVAL, float(top),
                INCREMENTAL_INTERVAL)
            self.init_progress_bar(len(next_x_list) * len(next_y_list))

            self.model = CatalogTableModel(self.dialog_ui.table_view)
            self.dialog_ui.table_view.setModel(self.model)
            self.dialog_ui.table_view.selectionModel(
            ).selectionChanged.connect(self.selection_changed)

            if not self.query:
                self.query = GBDQuery(username=username,
                                      password=password,
                                      api_key=api_key)

            filters = self.filters.get_query_filters()
            time_begin = self.filters.get_datetime_begin()
            time_end = self.filters.get_datetime_end()

            current_x = float(left)
            current_y = float(bottom)
            for next_x in next_x_list:
                for next_y in next_y_list:
                    search_runnable = CatalogSearchRunnable(
                        self.query,
                        self.model,
                        self,
                        top=next_y,
                        left=current_x,
                        right=next_x,
                        bottom=current_y,
                        time_begin=time_begin,
                        time_end=time_end,
                        filters=filters)
                    search_runnable.task_object.task_complete.connect(
                        self.on_search_complete)
                    self.search_thread_pool.start(search_runnable)
                    current_y = next_y
                current_y = bottom
                current_x = next_x

    def reset(self):
        self.filters.remove_all()

    def export(self):
        self.export_thread_pool.waitForDone(0)
        acquisitions = None
        if self.model is not None:
            acquisitions = self.model.data

        if not acquisitions:
            self.iface.messageBar().pushMessage("Error",
                                                "No data to export.",
                                                level=QgsMessageBar.CRITICAL)
        else:
            # open file ui
            select_file_ui = QFileDialog()
            starting_file = self.export_file or os.path.expanduser("~")
            export_file = select_file_ui.getSaveFileName(
                None, "Choose output file", starting_file, SELECT_FILTER)

            if export_file:
                self.export_file = export_file
                self.init_progress_bar(0)
                export_runnable = CatalogExportRunnable(
                    acquisitions, self.export_file)
                export_runnable.task_object.task_complete.connect(
                    self.on_export_complete)
                self.export_thread_pool.start(export_runnable)

    @pyqtSlot()
    def on_search_complete(self):
        thread_count = self.get_search_active_thread_count()
        if self.progress_message_bar:
            self.progress_bar.setValue(self.progress_bar.value() + 1)
        if thread_count == 0:
            self.clear_widgets()
            self.dialog_ui.table_view.resizeColumnsToContents()

    @pyqtSlot()
    def on_export_complete(self):
        thread_count = self.get_export_active_thread_count()
        if self.progress_message_bar:
            self.progress_bar.setValue(self.progress_bar.value() + 1)
        if thread_count == 0:
            self.clear_widgets()
            self.iface.messageBar().pushMessage(
                "Info",
                'File export has completed to "%s".' % self.export_file)

    def selection_changed(self, selected, deselected):
        self.footprint_layer.startEditing()

        # draw footprints for selected rows
        selected_rows = set()
        for index in selected.indexes():
            selected_rows.add(index.row())
        for row in selected_rows:
            acquisition = self.model.get(row)
            feature_id = self.model.generate_feature_id()
            self.model.set_feature_id(acquisition, feature_id)
            feature = CatalogAcquisitionFeature(feature_id, acquisition)
            self.footprint_layer.dataProvider().addFeatures([feature])

        # remove footprints for deselected rows
        deselected_rows = set()
        for index in deselected.indexes():
            deselected_rows.add(index.row())
        feature_ids_to_remove = []
        for row in deselected_rows:
            acquisition = self.model.get(row)
            feature_id = self.model.get_feature_id(acquisition)
            feature_ids_to_remove.append(feature_id)
            self.model.remove_feature_id(acquisition)
        if feature_ids_to_remove:
            self.footprint_layer.dataProvider().deleteFeatures(
                feature_ids_to_remove)

        self.footprint_layer.commitChanges()
        self.footprint_layer.updateExtents()
        self.footprint_layer.triggerRepaint()

    def drange_list(self, start, stop, step):
        drange_list = []
        r = start
        while r < stop:
            drange_list.append(r)
            r += step
        if not drange_list:
            drange_list.append(stop)
        return drange_list
Esempio n. 20
0
class Validation:
    def __init__(self, iface, db, validation_dia, plugin_dir, params):
        self.iface = iface
        self.db = db
        self.params = params
        self.validation_dia = validation_dia
        self.app_root = plugin_dir
        self.open_image = QPixmap(os.path.join(self.app_root,
                                               "image",
                                               "folder_open_icon.png"))
        self.validation_dia.ui.openPushButton.setIcon(QIcon(self.open_image))
        self.validation_dia.ui.openPushButton.setToolTip("Select File")
        self.export_globals = None
        self.validation_dk = None
        self.report_to_dialog = None
        self.re = QRegExp("CheckBox")
        self.check_boxes_names = []
        self.long_task = QThreadPool(None).globalInstance()
        self.summary_tables = {}
        self.model_navigation()
        self.form_load()
        self.file_dialog = QFileDialog()
        self.summary_functions = {}
        self.report_file_path = None
        self.home_dir = os.path.expanduser('~')
        self.org_name = database.get_from_gaz_metadata(db, "owner")
        self.report = ExportValidationReport("roadNet Validation Report",
                                             self.org_name,
                                             self.db, self.iface, None)
        self.list_check_boxes = []
        self.progress_win = QProgressDialog("", None, 0, 100, self.validation_dia)
        self.progress_win.setFixedSize(380, 100)
        self.progress_win.setModal(True)
        self.progress_win.setWindowTitle("Export Validation Report")

        self.summary_runnables = {'dupStreetCheckBox': [lambda: DupStreetDesc(), 0],
                                  'notStreetEsuCheckBox': [lambda: StreetsNoEsuDesc(), 1],
                                  'notType3CheckBox': [lambda: Type3Desc(False), 2],
                                  'incFootPathCheckBox': [lambda: Type3Desc(True), 2],
                                  'dupEsuRefCheckBox': [lambda: DupEsuRef(True), 3],
                                  'notEsuStreetCheckBox': [lambda: NoLinkEsuStreets(), 4],
                                  'invCrossRefCheckBox': [lambda: InvalidCrossReferences()],
                                  'startEndCheckBox': [lambda: CheckStartEnd(), 8],
                                  'tinyEsuCheckBox': [lambda: CheckTinyEsus("esu", 1)],
                                  'notMaintReinsCheckBox': [lambda: CheckMaintReins()],
                                  'asdStartEndCheckBox': [lambda: CheckAsdCoords()],
                                  'notMaintPolysCheckBox': [lambda: MaintNoPoly(), 16],
                                  'notPolysMaintCheckBox': [lambda: PolyNoMaint()],
                                  'tinyPolysCheckBox': [lambda: CheckTinyEsus("rd_poly", 1)]}

    def init_functions(self, ref_class, tolerance):
        """
        initialise a dictionary which keys are names of check boxes
        and values are all functions that create the respective table on the screen report
        functions are lambda because they will be called upon report creation and
        int references to a dictionary in the validation_summary
        class to the associated table widget to populate
        :param ref_class: class, the class holding the relative function
        :return: void
        """

        self.summary_functions = {'dupStreetCheckBox': [lambda: ref_class.dup_street_desc(), 0],
                                  'notStreetEsuCheckBox': [lambda: ref_class.street_not_esu_desc(), 1],
                                  'notType3CheckBox': [lambda: ref_class.no_type3_desc(include_footpath=False), 2],
                                  'incFootPathCheckBox': [lambda: ref_class.no_type3_desc(include_footpath=True), 2],
                                  'dupEsuRefCheckBox': [lambda: ref_class.dup_esu_ref(), 3],
                                  'notEsuStreetCheckBox': [lambda: ref_class.no_link_esu_streets(), 4],
                                  'invCrossRefCheckBox': [lambda: ref_class.invalid_cross_references()],
                                  'startEndCheckBox': [lambda: ref_class.check_start_end(tolerance), 8],
                                  'tinyEsuCheckBox': [lambda: ref_class.check_tiny_esus("esu", 1)],
                                  'notMaintReinsCheckBox': [lambda: ref_class.check_maint_reinst()],
                                  'asdStartEndCheckBox': [lambda: ref_class.check_asd_coords()],
                                  'notMaintPolysCheckBox': [lambda: ref_class.maint_no_poly(), 16],
                                  'notPolysMaintCheckBox': [lambda: ref_class.poly_no_maint()],
                                  'tinyPolysCheckBox': [lambda: ref_class.check_tiny_esus("rd_poly", 1)]}

    def model_navigation(self):
        """
        events handler for buttons in the form
        :return: object
        """
        buttons = self.validation_dia.ui.okCancelButtons.buttons()
        buttons[0].clicked.connect(self.get_data)
        buttons[1].clicked.connect(self.close_browser)
        self.validation_dia.ui.openPushButton.clicked.connect(self.select_file)
        self.validation_dia.ui.screenRadioButton.toggled.connect(lambda: self.selection_handler(0))
        self.validation_dia.ui.fileRadioButton.toggled.connect(lambda: self.selection_handler(1))
        self.validation_dia.ui.notType3CheckBox.toggled.connect(self.check_no_type_click)
        self.validation_dia.ui.startEndCheckBox.toggled.connect(self.check_coords_click)
        self.validation_dia.ui.selectAllButton.clicked.connect(self.select_all)
        self.validation_dia.ui.clearAllButton.clicked.connect(self.clear_all)

    def form_load(self):
        # set the initial status of the form
        self.validation_dia.ui.screenRadioButton.setChecked(True)
        self.validation_dia.ui.filePathLineEdit.setEnabled(False)
        self.check_coords_click()
        self.check_no_type_click()
        self.validation_dia.ui.dupStreetCheckBox.setChecked(True)
        self.validation_dia.ui.notStreetEsuCheckBox.setChecked(True)
        self.validation_dia.ui.notType3CheckBox.setChecked(True)
        self.validation_dia.ui.dupEsuRefCheckBox.setChecked(True)
        self.validation_dia.ui.notEsuStreetCheckBox.setChecked(True)
        self.validation_dia.ui.invCrossRefCheckBox.setChecked(True)
        self.validation_dia.ui.startEndCheckBox.setChecked(False)
        self.validation_dia.ui.tinyEsuCheckBox.setChecked(True)
        if self.params['RNsrwr'].lower() == 'true':
            self.validation_dia.ui.notMaintReinsCheckBox.setChecked(True)
            self.validation_dia.ui.asdStartEndCheckBox.setChecked(True)
        if self.params['RNsrwr'].lower() == 'false':
            self.validation_dia.ui.notMaintReinsCheckBox.setChecked(False)
            self.validation_dia.ui.asdStartEndCheckBox.setChecked(False)
            self.validation_dia.ui.notMaintReinsCheckBox.setEnabled(False)
            self.validation_dia.ui.asdStartEndCheckBox.setEnabled(False)
        if self.params['RNPolyEdit'].lower() == 'true':
            self.validation_dia.ui.notMaintPolysCheckBox.setChecked(True)
            self.validation_dia.ui.notPolysMaintCheckBox.setChecked(True)
            self.validation_dia.ui.tinyPolysCheckBox.setChecked(True)
        if self.params['RNPolyEdit'].lower() == 'false':
            self.validation_dia.ui.notMaintPolysCheckBox.setChecked(False)
            self.validation_dia.ui.notPolysMaintCheckBox.setChecked(False)
            self.validation_dia.ui.tinyPolysCheckBox.setChecked(False)
            self.validation_dia.ui.notMaintPolysCheckBox.setEnabled(False)
            self.validation_dia.ui.notPolysMaintCheckBox.setEnabled(False)
            self.validation_dia.ui.tinyPolysCheckBox.setEnabled(False)

    def close_browser(self):
        # close the dialog
        self.validation_dia.close()

    def get_data(self):
        """
        produce the report according to the options specified by the user
        :return: validation report either on screen or as text file
        """
        if self.validation_dia.ui.fileRadioButton.isChecked():
            # alert the user if no path is specified
            if self.validation_dia.ui.filePathLineEdit.text() == "":
                no_path_msg_box = QMessageBox(QMessageBox.Warning, " ",
                                              "You must specify a path and filename for the report",
                                              QMessageBox.Ok, None)
                no_path_msg_box.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint)
                no_path_msg_box.exec_()
                return
            # format the path and runs the export
            val_file_path = self.validation_dia.ui.filePathLineEdit.text()
            # checks if the export directory exists and it is valid
            if not os.path.isdir(os.path.dirname(val_file_path)):
                path_invalid_msg_box = QMessageBox(QMessageBox.Warning, " ", "A valid directory must be selected",
                                                   QMessageBox.Ok, None)
                path_invalid_msg_box.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint)
                path_invalid_msg_box.exec_()
            else:
                self.report_to_file(val_file_path)
            # text file report = false, create a screen report, instantiate the report creator class
        if not self.validation_dia.ui.fileRadioButton.isChecked():
            self.report_to_screen()

    def select_file(self):
        """
        open the dialog window to select the file and print the path on the main line edit
        :return: void
        """
        self.file_dialog.setDirectory(self.home_dir)
        self.file_dialog.setFileMode(QFileDialog.ExistingFiles)
        filters = "Text files (*.txt)"
        self.file_dialog.setNameFilter(filters)
        save_file_name = self.file_dialog.getSaveFileName(self.file_dialog, "Export Validation Report",
                                                          self.home_dir,
                                                          filter="Text files (*.txt)")
        if save_file_name != "":
            self.validation_dia.ui.filePathLineEdit.setText(("{}.txt".format(save_file_name)))
        if save_file_name.endswith(".txt"):
            self.validation_dia.ui.filePathLineEdit.setText(save_file_name)

    def selection_handler(self, button_id):
        """
        change the status of the line edit according to the radio button selection
        :return:
        """
        # if screen report is selected disable line edit for the file path
        if button_id == 0:
            self.validation_dia.ui.filePathLineEdit.setEnabled(False)
            self.validation_dia.ui.openPushButton.setEnabled(False)
            self.check_boxes_names = []

        else:
            self.validation_dia.ui.filePathLineEdit.setEnabled(True)
            self.validation_dia.ui.openPushButton.setEnabled(True)
            self.check_boxes_names = []

    def check_coords_click(self):
        # show/hide tolerance metres spin box
        if self.validation_dia.ui.startEndCheckBox.isChecked():
            self.validation_dia.ui.metresSpinBox.setVisible(True)
            self.validation_dia.ui.toleranceLabel.setVisible(True)
        else:
            self.validation_dia.ui.metresSpinBox.setVisible(False)
            self.validation_dia.ui.toleranceLabel.setVisible(False)

    def check_no_type_click(self):
        # enable/disable footpath check box
        if self.validation_dia.ui.notType3CheckBox.isChecked():
            self.validation_dia.ui.incFootPathCheckBox.setEnabled(True)
        else:
            self.validation_dia.ui.notType3CheckBox.setChecked(False)
            self.validation_dia.ui.incFootPathCheckBox.setEnabled(False)

    def select_all(self):
        # reset the form to default status, select all
        self.form_load()

    def clear_all(self):
        # uncheck all checkboxes
        self.validation_dia.ui.dupStreetCheckBox.setChecked(False)
        self.validation_dia.ui.notStreetEsuCheckBox.setChecked(False)
        self.validation_dia.ui.notType3CheckBox.setChecked(False)
        self.validation_dia.ui.incFootPathCheckBox.setChecked(False)
        self.validation_dia.ui.incFootPathCheckBox.setEnabled(False)
        self.validation_dia.ui.dupEsuRefCheckBox.setChecked(False)
        self.validation_dia.ui.notEsuStreetCheckBox.setChecked(False)
        self.validation_dia.ui.invCrossRefCheckBox.setChecked(False)
        self.validation_dia.ui.startEndCheckBox.setChecked(False)
        self.validation_dia.ui.tinyEsuCheckBox.setChecked(False)
        self.validation_dia.ui.notMaintReinsCheckBox.setChecked(False)
        self.validation_dia.ui.asdStartEndCheckBox.setChecked(False)
        self.validation_dia.ui.notMaintPolysCheckBox.setChecked(False)
        self.validation_dia.ui.notPolysMaintCheckBox.setChecked(False)
        self.validation_dia.ui.tinyPolysCheckBox.setChecked(False)

    def report_to_file(self, val_file_path):
        """
        creates a text file report
        :return: void
        """
        # assign to the report class the file path property
        self.report_file_path = val_file_path
        # start writing
        # get all checked check-boxes
        if len(self.list_check_boxes) > 0:
            self.list_check_boxes = []
        self.list_check_boxes = self.validation_dia.findChildren(QCheckBox, self.re)
        if len(self.check_boxes_names) > 0:
            self.check_boxes_names = []
        for check_box in self.list_check_boxes:
            if check_box.isChecked():
                self.check_boxes_names.append(str(check_box.objectName()))
        if len(self.check_boxes_names) < 1:
            no_val_check_msg_box = QMessageBox(QMessageBox.Warning, " ",
                                               "At least one validation option must be selected", QMessageBox.Ok, None)
            no_val_check_msg_box.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint)
            no_val_check_msg_box.exec_()
            return
        tolerance = self.validation_dia.ui.metresSpinBox.value()
        if self.validation_dia.ui.startEndCheckBox.isChecked() and (tolerance is None or tolerance == 0):
            no_tol_msg_box_file = QMessageBox(QMessageBox.Warning, " ", "You must specify a tolerance",
                                              QMessageBox.Ok, None)
            no_tol_msg_box_file.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint)
            no_tol_msg_box_file.exec_()
            return
        self.progress_win.setWindowTitle("Export Validation Report")
        self.progress_win.show()
        if self.validation_dia.ui.notType3CheckBox.isChecked():
            if 'incFootPathCheckBox' in self.check_boxes_names:
                # locate the include footpath option and run just the appropriate function
                self.check_boxes_names.remove('notType3CheckBox')
        self.export_globals = InitGlobals(self.db, self.params, tolerance)
        self.long_task.setMaxThreadCount(1)
        start_report = StartReport(val_file_path, self.org_name)
        start_report.signals.result.connect(self.log_progress)
        end_report = EndReport()
        end_report.signals.result.connect(self.log_progress)
        end_report.signals.report_finished.connect(self.show_finished)
        self.long_task.start(start_report)
        for check_box_name in self.check_boxes_names:
            run_class = self.summary_runnables[check_box_name]
            runnable = run_class[0]()
            runnable.signals.result.connect(self.log_progress)
            self.long_task.start(runnable)
        self.long_task.start(end_report)

        self.list_check_boxes = []
        self.check_boxes_names = []

    @pyqtSlot()
    def show_finished(self):
        self.long_task.waitForDone()
        show_finished_msg_box = QMessageBox(QMessageBox.Information, " ",
                                            "Report successfully exported at \n {0}"
                                            .format(str(self.report_file_path))
                                            .replace("\\\\", "\\"), QMessageBox.Ok, None)
        show_finished_msg_box.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint)
        show_finished_msg_box.exec_()

    @pyqtSlot(str, int)
    def log_progress(self, task, value):
        self.progress_win.setLabelText(task)
        self.progress_win.setValue(value)

    def report_to_screen(self):
        tolerance = self.validation_dia.ui.metresSpinBox.value()
        if self.validation_dia.ui.startEndCheckBox.isChecked() and (tolerance is None or tolerance == 0):
            no_tol_msg_box_screen = QMessageBox(QMessageBox.Warning, " ", "You must specify a tolerance",
                                                QMessageBox.Ok, None)
            no_tol_msg_box_screen.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint)
            no_tol_msg_box_screen.exec_()
            return
        report_to_screen = self.report
        report_to_screen.validation_dia = self.validation_dia
        # in case the user selects a screen report immediately after the generation of
        # a file report create a new instance of the report class and None the file path
        # instantiate the report window, the parent is the main validation report dialog
        if self.validation_dk is None:
            self.validation_dk = ValidationSummaryDock(self.validation_dia)
            self.validation_dk.setWindowTitle("Validation Report Summary")
            self.validation_dk.setWindowFlags(Qt.WindowMaximizeButtonHint | Qt.WindowMinimizeButtonHint)
            rn_icon = QIcon()
            rn_icon.addPixmap(QPixmap(os.path.join(self.app_root,
                                                         "image",
                                                         "rn_logo_v2.png")))
            self.validation_dk.setWindowIcon(rn_icon)
        # instantiate the class handler (functions to create and format the screen report)
        # include the window in the instantiation
        report_to_dialog = ValidationSummary(self.validation_dk, self.iface, self.db, tolerance)
        # creates a list of the checked checkboxes to create the tables
        self.list_check_boxes = self.validation_dia.findChildren(QCheckBox, self.re)
        for check_box in self.list_check_boxes:
            if check_box.isChecked():
                self.check_boxes_names.append(str(check_box.objectName()))
        # check if at least one checkbox is checked before running the report
        if len(self.check_boxes_names) < 1:
            no_val_check_msg_box = QMessageBox(QMessageBox.Warning, " ",
                                               "At least one validation option must be selected", QMessageBox.Ok, None)
            no_val_check_msg_box.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint)
            no_val_check_msg_box.exec_()
            return
        # initialises the functions
        self.init_functions(report_to_screen, tolerance)
        # runs the functions, each function passes a list and a table reference
        # to the handler class methods that create, populate and finally show the window
        if self.validation_dia.ui.notType3CheckBox.isChecked():
            if 'incFootPathCheckBox' in self.check_boxes_names:
                # locate the include footpath option and run just the appropriate function
                self.check_boxes_names.remove('notType3CheckBox')
                report_to_dialog.include_footpath = True
        self.report.start_report()
        for check_box_name in self.check_boxes_names:
            function = self.summary_functions[check_box_name][0]
            # handles multiple results for a unique check box (cross references)
            if check_box_name == 'invCrossRefCheckBox':
                function_list = function()
                report_to_dialog.set_table(function_list[0], 5)
                report_to_dialog.set_table(function_list[1], 6)
                report_to_dialog.set_table(function_list[2], 7)
            # handles multiple results for a unique check box (tiny/empty ESUs Polys)
            elif check_box_name == 'tinyEsuCheckBox':
                function_list = function()
                report_to_dialog.set_table(function_list[0], 9)
                report_to_dialog.set_table(function_list[1], 10)
            elif check_box_name == 'tinyPolysCheckBox':
                function_list = function()
                report_to_dialog.set_table(function_list[0], 19)
                report_to_dialog.set_table(function_list[1], 20)
            # handles multiple results for a unique check box (maint/reins asd streets)
            elif check_box_name == 'notMaintReinsCheckBox':
                function_list = function()
                report_to_dialog.set_table(function_list[0], 11)
                report_to_dialog.set_table(function_list[1], 12)
            # handles multiple results for a unique check box (maint/reins asd coords)
            elif check_box_name == 'asdStartEndCheckBox':
                function_list = function()
                report_to_dialog.set_table(function_list[0], 13)
                report_to_dialog.set_table(function_list[1], 14)
                report_to_dialog.set_table(function_list[2], 15)
            # handles multiple results for a unique check box (polygons with no link, multi maintenance assignation)
            elif check_box_name == 'notPolysMaintCheckBox':
                function_list = function()
                report_to_dialog.set_table(function_list[0], 17)
                report_to_dialog.set_table(function_list[1], 18)
            # all other normal cases
            else:
                table_id = self.summary_functions[check_box_name][1]
                report_to_dialog.set_table(function(), table_id)
        self.report.end_report(self.validation_dia)
        self.report = ExportValidationReport("roadNet Validation Report",
                                             self.org_name,
                                             self.db, self.iface, None)
        report_to_dialog.show_validation_widget()
Esempio n. 21
0
class MainWindow(QtGui.QMainWindow):

    """
    Main window for the application

    Takes Ui_MainWindow from mainUI.py, which is automatically generated
    with pyuic4 from the UI file.
    """

    def __init__(self, parent=None):
        """Init Window"""
        QtGui.QMainWindow.__init__(self, parent)
        self.gui = Ui_MainWindow()
        self.gui.setupUi(self)
        self.gscriptpath = '"' +  os.getcwd() + r'\gs\gs9.02\bin'
        self.gui.progressBar.hide()
        self.single_output_dir = ''
        self.deletions = []
        self.work = QThreadPool()
        self.work.setMaxThreadCount(1)
        self.thread_number = 5
        self.setWindowIcon(QtGui.QIcon(":/ico.png"))
        self.resolution = 450
        self.mode = 'tiffg4'


    def quit(self):

        """
        Quit the window, in case we need some specific behaviour
        """

        print self


    def dir_locate(self):
        """
        Will locate a dir to split all pdfs
        """
        pass


    def dir_output(self):
        """
        Will locate an output dir for dir conversion
        """
        pass


    def single_output_file(self):

        """
        Spawns a find file dialog
        """
        # get a local ref to dialog
        dir_dialog = QtGui.QFileDialog(self)
        # set dialog type
        dir_dialog.setFileMode(QtGui.QFileDialog.Directory)

        # if the dialog is 'executed' (hit ok)
        # then we take the string into a class attrib
        if dir_dialog.exec_() == True:
            for item in dir_dialog.selectedFiles():
                self.single_output_dir = item
                self.gui.single_line_out.setText(item)
                break


    def single_locate_file(self):

        """
        creates a dialog to find a single file
        """

        # Create the file lookup dialog using built-in dialogs
        # We set the file type to PDF and only PDF
        self.gui.single_line_in.setText(QtGui.QFileDialog.getOpenFileName(
                                       self, 'Open', '' ,('PDF Files (*.pdf)')))


    def update_progress_bar(self):

        """
        Method to update progress bar whilst running conversion
        """

        # When we get a call it's from a thread finishing
        # we increment the progress bar and check if we're at 100%
        self.gui.progressBar.setValue(self.gui.progressBar.value()+1)

        # This is bad, if a QProcess fails, we don't get a tick
        # and the progressBar will never get to 100%
        # we need to implement something that will catch errors with
        # QProcess
        if self.gui.progressBar.value() == self.gui.progressBar.maximum():
            self.gui.progressBar.hide()

            # create the deleter thread with a reference to the deletions
            # list.
            deleter = QFileWorker(self.deletions, self)

            # wait for the deletions thread to return
            deleter.threadpool.waitForDone()

            # re-init deletions list so we don't try to delete
            # already deleted files next time
            self.deletions = []

            # Re-enable the button
            self.gui.btn_single_convert.setEnabled(True)


    def convert(self):

        """
        Implementation of multithreaded processing
        """

        # if they click convert without looking for files
        if len(self.gui.single_line_in.text()) < 1:
            return
        if len(self.gui.single_line_out.text()) < 1:
            return

        # Open the PDF that we found in the dialog
        try:
            pdf = PdfFileReader(open(self.gui.single_line_in.text(), 'rb'))
        # if the file cannot be properly read raise error
        except AssertionError:
            QtGui.QMessageBox.warning(self, "Error", "This file is corrupt")
            return
        # if the file does not exist
        except IOError:
            QtGui.QMessageBox.warning(self, "Error", "Not a valid file path")
            return

        self.gui.btn_single_convert.setEnabled(False) # disable button
        self.gui.progressBar.setValue(0) # re-init progress bar

        # Show the progress bar
        self.gui.progressBar.show()

        # Set the progress bar's maximum number to the number of pages
        # in the PDF
        self.gui.progressBar.setMaximum(pdf.numPages)

        # Send the PDF object (PdfFileReader) to the ThreadHandler
        # along with a reference to ourself in order to set up signal
        # callbacks

        # most of the magic is in mthreading.py
        # this is the cleanest interface I could come up with
        # just pass it an opened PDF document and processing will begin
        self.work.start(QThreadHandle(pdf, self))


    def convert_dir(self):
        """
        Method to convert a whole directory
        """
        pass


    def spawn_options(self):
        """
        Spawns an options dialog
        """

        options.OptionsDialog(self).exec_()


    def spawn_about(self):
        """
        Spawns an options dialog
        """

        about_dialog  = about.AboutDialog(self)
        about_dialog.gui.label_2.setPixmap(QtGui.QPixmap(":/about.png"))
        about_dialog.exec_()