def loadFile(self):
     mnFileName = unicode(self.mnFileNameInput.text())
     if not mnFileName:
         QMessageBox.warning(glb.mainWin,
             QCoreApplication.translate('SmileKit', 'No filename specified'),
             QCoreApplication.translate('SmileKit', 'Please enter a filename in the input box!'))
         return
     progressDlg = QProgressDialog(glb.mainWin)
     progressDlg.setRange(0, 100)
     progressDlg.setLabelText('Reading File...')
     progressDlg.show()
     a = glb.application
     def progFunc(p):
         progressDlg.setValue(p)
         if a.hasPendingEvents():
             a.processEvents()
     r = readMnFile(mnFileName, progress=progFunc)
     self.data = r
     progressDlg.close()
     self.locationFrame.setEnabled(1)
     self.statisticsFrame.setEnabled(1)
     if ncOk:
         self.ncFileFrame.setEnabled(1)
     self.statisticsButton.setCheckState(Qt.Unchecked)
     self.locNameInput.setText(r['name'])
     c = unicode(QCoreApplication.translate('SmileKit', "created %s from %s by Meteo2Nc.py (v%d)"))
     self.locCommentInput.setText(c % (time.ctime(), mnFileName, version))
     self.locLatitudeInput.setValue(r['latitude'])
     self.locLongitudeInput.setValue(r['longitude'])
     self.locHeightInput.setValue(r['height'])
     self.locTimeZoneInput.setValue(r['timezone'])
     path, tmp = os.path.split(mnFileName)
     ncFileName = os.path.join(path, makeFileName(r['name'])+'_weather.nc')
     self.ncFileNameInput.setText(ncFileName)
Example #2
0
    def createPortfolioListModel(self):

        portfolios = self.getPortfolios()
        listModel = PortfolioListModel(portfolios)
        numPortfolios = len(portfolios)

        progress = QProgressDialog(
            self.tr("Loading portfolios from Google"), QString(), 0, numPortfolios, self.mainWindow
        )
        progress.setWindowTitle(self.tr("Loading portfolios from Google"))

        if self.updater:
            self.updater.terminate()
            self.disconnect(self.updater, SIGNAL("quotesUpdated"), self.processQuotesUpdated)

        self.updater = Updater(self.quoter)
        QObject.connect(self.updater, SIGNAL("quotesUpdated"), self.processQuotesUpdated)

        for pIndex in range(numPortfolios):

            portfolio = portfolios[pIndex]
            positions = self.gDataClient.GetPositionFeed(portfolio)
            for position in positions.entry:
                tickerTuple = position.symbol.exchange, position.symbol.symbol
                self.updater.addTickers(tickerTuple)

            portfolioName = portfolio.title.text.decode("utf-8")
            labelText = QString("'%s' (%d / %d)" % (portfolioName, pIndex + 1, numPortfolios))
            progress.setLabelText(labelText)
            progress.setValue(pIndex + 1)
            QApplication.processEvents()

        self.updater.start()

        return listModel
Example #3
0
    def stop_experiment(self, msg, stop_storing=False):
        progress = QProgressDialog(None, Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
        progress.setLabelText("Stopping...")
        progress.setRange(0, 5)
        progress.setCancelButton(None)
        progress.show()

        print("STOP EXPERIMENT!!!!")
        uid = str(msg)
        index = self.index_of(uid)
        if index is None:
            print("experiment uuid not found: ", uid)
            return
        exp = self.experiments[index]
        if not exp.launcher_data:
            print("this exp is not running...", uid)
            return
        if stop_storing:
            # stop storing ONLY if the experiment was fired from this very obci gui
            # otherwise the data is lost ....
            # below code was to stop storing every time signal saver is in scenarios`es modules
            # but it sometimes hangs forever eg. when we are using morph extensively ...
            # `
            # or ("signal_saver" in exp.exp_config.peers and\
            #    exp.status.peer_status("signal_saver").status_name \
            #                in [launcher_tools.RUNNING, launcher_tools.LAUNCHING]):
            print("STOP STORING")
            exp.stop_storing(self.client)
            for i in range(4):
                time.sleep(0.6)  # FIXME - without it some problem with below kill...
                progress.setValue(i + 1)
        progress.setValue(5)
        self._process_response(self.client.kill_exp(exp.uuid))
 def dump_script(self):
   to_dump = self.get_checked([self.ui.treeFileList.topLevelItem(i) for i in range(self.ui.treeFileList.topLevelItemCount())])
   
   if not to_dump:
     QtGui.QMessageBox.warning(self, "No Selection", "No folders have beens selected to dump.")
     return
   
   out_file = get_save_file(self, self.last_file, "Text files (*.txt)")
   if out_file == "":
     return
   
   translated    = not self.ui.chkUntranslated.isChecked()
   strip_clt     = self.ui.chkStripClt.isChecked()
   only_voiced   = self.ui.chkOnlyVoiced.isChecked()
   line_numbers  = self.ui.chkLineNumbers.isChecked()
   
   progress = QProgressDialog("Dumping...", QtCore.QString(), 0, len(to_dump), self)
   progress.setWindowTitle("Dumping...")
   progress.setWindowModality(Qt.Qt.WindowModal)
   progress.setValue(0)
   progress.setAutoClose(False)
   progress.setMinimumDuration(0)
   
   # print out_file
   with open(out_file, "wb") as f:
     for dir in to_dump:
       progress.setLabelText("Dumping %s..." % dir)
       f.write(script_to_text(dir, translated, strip_clt, only_voiced, line_numbers).encode("UTF-8"))
       progress.setValue(progress.value() + 1)
   
   progress.close()
   
   self.last_file = out_file
Example #5
0
 def on_action_2_triggered(self):
     """
     Slot documentation goes here.
     """
     # TODO: not implemented yet
     if self.model.rowCount < 1:
         QtGui.QMessageBox.warning(self,'warning', "Nothing could be export")
         return
     fileName = QFileDialog.getSaveFileName(self,self.tr('Save csv'),'',self.tr("*.csv"))
     if platform.system() == 'Windows':
         fileName = str(fileName.toUtf8()).encode('gbk')
     content = ''
     for j in range(self.model.columnCount()):
         content += str(self.model.headerData(j,  QtCore.Qt.Horizontal).toString().toUtf8())+ ','
     for j in range(self.model.columnCount()):
         content += str(self.model2.headerData(j,  QtCore.Qt.Horizontal).toString().toUtf8())+ ','
     content = content[:-1] + '\r\n'
     progressDialog = QProgressDialog(u"正在导出 (%d/%d)" %(0,  self.model.rowCount()), u"取消", 0, self.model.rowCount(), self)
     for i in range(self.model.rowCount()):
         for j in range(self.model.columnCount()):
             content += str(self.model.data(self.model.index(i, j)).toString().toUtf8())+ ','
         for j in range(self.model2.columnCount()):
             content += str(self.model2.data(self.model2.index(i, j)).toString().toUtf8())+ ','
         content = content[:-1] + '\r\n'
         if  progressDialog.wasCanceled():
             return
         progressDialog.setLabelText (u"正在导出 (%d/%d)" %(i+1,  self.model.rowCount()))
         progressDialog.setValue(i+1)
         
     if platform.system() == 'Windows':
         content = content.decode('utf-8').encode('gbk')
     f = open(fileName,  'wb')
     f.write(content)
     f.close()
Example #6
0
    def on_btn_save_udf_param_clicked(self):
        """
        Slot documentation goes here.
        """
        msg = u'保存参数并同时更新UDF中建筑负载文件名,确定吗?'
        reply = self.show_yesno_msgbox(msg)
        if reply == 0:
            return
        fname = self.le_fluent_udf_file.text()
        if fname == '':
            msg = u'UDF文件名为空, 请先设置一个有效的UDF文件'
            self._show_tips(msg, tip_type=1)
            return
        # check if file path exists
        if not os.path.exists(fname):  
            msg = u'UDF文件路径不存在, 请打开一个有效的UDF文件!'
            self._show_tips(msg, tip_type=1)
            return

        # first, get params from widgets
        params = self.get_udf_param_from_widgets()
        # read the load file
        progress_dlg = QProgressDialog(self)
        progress_dlg.setModal(True)
        progress_dlg.setMinimumDuration(1)  
        progress_dlg.setWindowTitle(u"处理数据")  
        progress_dlg.setLabelText(u"正在处理建筑负荷数据...")  
        progress_dlg.setCancelButtonText("Cancel")  
        # we don't know how many lines in the load file
        progress_dlg.setMinimum(1)
        progress_dlg.setMaximum(10000)
        max_q = 0.0
        min_q = 0.0
        line_cnt = 0
        with open(params['load_file'], 'r') as rfh:
            for line in rfh:
                val = float(line)
                if val > max_q:
                    max_q = val
                if val < min_q:
                    min_q = val
                progress_dlg.setValue(line_cnt)  
                if progress_dlg.wasCanceled():
                    return
                line_cnt += 1
        # set the max value to terminate the progress dialog
        if line_cnt < 10000:
            QThread.sleep(1)
            progress_dlg.setValue(10000)  
        params['copc_max_q'] = max_q
        params['coph_max_q'] = min_q
        # modify the udf file
        result = self.udf_model.write_params(params, fname)
        if result == True:
            msg = u'文件%s更新成功' % fname
            self._show_tips(msg)
        else:
            msg = u'文件更新失败, 请确保%s是有效的UDF文件' % fname
            self._show_tips(msg, tip_type=1)
Example #7
0
 def on_actionOpenSession_triggered(self, filename=None):
     if not filename:
         filename = QFileDialog.getOpenFileName(self, 'Open Session')
     if filename:
         if self.session.messages:
             args = argv[:]
             if len(args) > 1:
                 args[1] = filename
             else:
                 args.append(abspath(str(filename)))
             try:
                 pid = spawnvp(P_NOWAIT, args[0], args)
             except (NameError, ):
                 Popen('"%s" "%s" "%s"' % (executable, args[0], args[1]))
             return
         if not self.warningOpenTabs():
             return
         dlg = QProgressDialog(self)
         dlg.setLabelText('Reading session file.')
         dlg.setCancelButtonText('Abort')
         dlg.setWindowModality(Qt.WindowModal)
         dlg.setWindowTitle('Reading...')
         self.show()
         processEvents()
         dlg.show()
         processEvents()
         try:
             loadit = self.session.load(str(filename))
             count = loadit.next()
             last = count - 1
         except (StopIteration, ):
             msg = 'Warning session not loaded from "%s"' % filename
             dlg.close()
         else:
             dlg.setLabelText('Loading session messages.')
             dlg.setWindowTitle('Loading...')
             dlg.setMaximum(last)
             msgid = -1
             for msgid in loadit:
                 processEvents()
                 dlg.setValue(msgid)
                 if dlg.wasCanceled():
                     dlg.close()
                     break
             if msgid == last:
                 msg = 'Loaded all %s messages from file "%s".'
                 msg %= (count, filename)
                 self.setCurrentSession(filename)
             else:
                 msg = 'Load aborted; loaded %s messages of %s.'
                 msg %= (msgid+1, count)
         self.statusBar().showMessage(msg, 5000)
Example #8
0
def showAllChartWindows(sg, maximized=False):
    dlg = QProgressDialog(SimuVis4.Globals.mainWin)
    dlg.setWindowModality(Qt.WindowModal)
    dlg.setMaximum(len(sg.charts))
    dlg.setAutoClose(True)
    dlg.setMinimumDuration(0)
    dlg.setValue(0)
    i = 1
    app = SimuVis4.Globals.application
    for name, chart in sg.charts.items():
        dlg.setLabelText(name)
        app.processEvents()
        showChartWindow(chart, maximized)
        dlg.setValue(i)
        i += 1
        if dlg.wasCanceled():
            break
 def generate_font(self):
   progress = QProgressDialog("", QtCore.QString(), 0, 0, self)
   progress.setWindowModality(Qt.Qt.WindowModal)
   progress.setWindowTitle("Generating font...")
   progress.setLabelText("Generating font...")
   progress.setMinimumDuration(0)
   progress.setAutoClose(False)
   
   # Thread this because it's slow as hell and we don't want to lock up the GUI.
   thread = threading.Thread(target = self.__generate_font__)
   thread.start()
   
   while thread.isAlive():
     thread.join(THREAD_TIMEOUT)
     # It has to change by some amount or it won't update and the UI will lock up.
     progress.setValue(progress.value() - 1)
   
   progress.close()
Example #10
0
def scan_ros_distro():
    global main_widget
    global ROS_PKGS, ROS_MSGS, ROS_SRVS
    # reset current
    ROS_MSGS = []
    ROS_SRVS = []
    # scan with progress shown
    progress_dialog = QProgressDialog('Scanning ROS Distro', 'Cancel', 0, len(ROS_PKGS), parent=main_widget)
    progress_dialog.setWindowModality(Qt.WindowModal)
    count = 0
    total = len(ROS_PKGS)
    for package in ROS_PKGS:
        if progress_dialog.wasCanceled():
            ROS_MSGS = []
            ROS_SRVS = []
            break
        progress_dialog.setValue(count)
        progress_dialog.setLabelText('Scanning ROS Distro\nscanning {0} from {1}: {2}...'.format(
            count+1, total, package))
        if len(rosmsg.list_msgs(package)) > 0:
            ROS_MSGS.append(package)
            progress_dialog.setLabelText('Scanning ROS Distro\nscanning {0} from {1}: {2}...\nfound messages...'.format(
                count+1, total, package))
        if len(rosmsg.list_srvs(package)) > 0:
            progress_dialog.setLabelText('Scanning ROS Distro\nscanning {0} from {1}: {2}...\nfound services...'.format(
                count+1, total, package))
            ROS_SRVS.append(package)
        count += 1
    progress_dialog.setValue(len(ROS_PKGS))
    # store settings
    store_settings()
    print 'stored {0} msgs and {1} srvs...'.format(len(ROS_MSGS), len(ROS_SRVS))
Example #11
0
    def doExport(self,  model):
#        print model.rowCount()
        if model.rowCount() < 1:
            QMessageBox.warning(self,'warning', "导出内容为空")
            return
        fileName = QFileDialog.getSaveFileName(self,self.tr('Save csv'),'',self.tr("*.csv"))
        if not fileName:
            return
        if platform.system() == 'Windows':
            fileName = str(fileName.toUtf8()).encode('gbk')
        content = ''
        for j in range(model.columnCount()):
            try:
                content += str(model.headerData(j,  QtCore.Qt.Horizontal).toString().toUtf8())+ ','
            except:
                content += str(model.headerData(j,  QtCore.Qt.Horizontal).toUtf8())+ ','
#        for j in range(model.columnCount()):
#            content += str(model2.headerData(j,  QtCore.Qt.Horizontal).toString().toUtf8())+ ','
        content = content[:-1] + '\r\n'
        progressDialog = QProgressDialog(u"正在导出 (%d/%d)" %(0,  model.rowCount()), u"取消", 0, model.rowCount(), self)
        for i in range(model.rowCount()):
            for j in range(model.columnCount()):
                try:
                    content += str(model.data(model.index(i, j)).toString().toUtf8())+ ','
                except:
                    content += str(model.data(model.index(i, j)).toUtf8())+ ','
#            for j in range(model2.columnCount()):
#                content += str(model2.data(model2.index(i, j)).toString().toUtf8())+ ','
            content = content[:-1] + '\r\n'
            if  progressDialog.wasCanceled():
                return
            progressDialog.setLabelText (u"正在导出 (%d/%d)" %(i+1,  model.rowCount()))
            progressDialog.setValue(i+1)
            
        if platform.system() == 'Windows':
            content = content.decode('utf-8').encode('gbk')
        f = open(fileName,  'wb')
        f.write(content)
        f.close()
Example #12
0
class Progress:
    def __init__(self, parent):
        self.parent = parent
        self.dialog = None
        self.application = None

    def started(self, title):
        self.dialog = QProgressDialog(title, "Stop", 0, 0, self.parent)
        self.dialog.setCancelButton(None)
        self.dialog.show()
        QCoreApplication.processEvents(QEventLoop.AllEvents)

    def progress(self, msg, percent):
        self.dialog.setLabelText(msg)
        # otherwise KProgressDialog automatically closes itself, sigh
        if percent < 100:
            self.dialog.setValue(percent)
        QCoreApplication.processEvents(QEventLoop.AllEvents)

    def finished(self):
        if self.dialog:
            self.dialog.done(0)
        self.dialog = None
Example #13
0
def saveAllChartImages(sg):
    if SimuVis4.Globals.config.getboolean('matplot', 'set_default_backend'):
        QMessageBox.warning(SimuVis4.Globals.mainWin,
            QCoreApplication.translate('DataStorageBrowser', 'Configuration error'),
            QCoreApplication.translate('DataStorageBrowser',
"""The option "set_default_backend" in section "matplot" is enabled.
The requested action will not work with this setting.
Change this setting and restart the application to make this work!"""))
        return

    f = QFileDialog.getExistingDirectory(SimuVis4.Globals.mainWin,
        QCoreApplication.translate('DataStorageBrowser',
        "Select a folder (existing image files will be overwritten!)"),
        SimuVis4.Globals.defaultFolder)
    if f.isEmpty():
        return
    folder = unicode(f)
    SimuVis4.Globals.defaultFolder = folder
    dlg = QProgressDialog(SimuVis4.Globals.mainWin)
    dlg.setWindowModality(Qt.WindowModal)
    dlg.setMaximum(len(sg.charts))
    dlg.setAutoClose(True)
    dlg.setMinimumDuration(0)
    dlg.setValue(0)
    i = 1
    app = SimuVis4.Globals.application
    for name, chart in sg.charts.items():
        fileName = "%s.png" % name
        dlg.setLabelText(fileName)
        app.processEvents()
        #chart.setTimeslice(1*86400)
        chart(starttime=(sg.stop-chart.standardSlice), filename=os.path.join(folder, fileName))
        dlg.setValue(i)
        i += 1
        if dlg.wasCanceled():
            break
class specread:
    def __init__(self,
                 specfile,
                 startLineNum=0,
                 endScanNum=0,
                 beamline='APS-15IDC',
                 det='CCD',
                 data={},
                 par={}):
        self.Data = data
        self.Par = par
        self.specfile = specfile
        if beamline == 'APS-15IDC':
            self.APS_15IDC(startLineNum=startLineNum,
                           endScanNum=endScanNum,
                           det=det)
        if beamline == 'APS-9IDC':
            self.APS_9IDC(startLineNum=startLineNum,
                          endScanNum=endScanNum,
                          det=det)

    def updateProgress(self):
        self.progressDialog.setValue(self.progressDialog.value() + 1)

    def APS_15IDC(self, startLineNum=0, endScanNum=0, det='CCD'):
        """
        Function to read a complete spec File collected at APS 15IDC 
        """
        self.progressDialog = QProgressDialog('Reading scans form SPEC File:',
                                              'Abort', 0, 100)
        self.progressDialog.setWindowModality(Qt.WindowModal)
        self.progressDialog.setWindowTitle('Wait')
        self.progressDialog.setAutoClose(True)
        self.progressDialog.setAutoReset(True)
        self.progressDialog.setMinimum(1)
        self.Data['YCol'] = 'Apex2'
        self.Data['NCol'] = 'Monc'
        fid = open(self.specfile)
        fdata = fid.readlines()
        self.SpecFileFull = fdata
        fid.close()
        if fdata[0][:2] != '#F':
            self.Data['NumOfScans'] = 0
            self.Data['Message'] = 'The file is not a valid specfile!!'
            print 'Error:: The file is not a valid specfile!!'
        else:
            startScanLineNums = [
                i for i in range(startLineNum, len(fdata))
                if fdata[i][:2] == '#S'
            ]
            self.progressDialog.setMaximum(len(startScanLineNums))
            self.progressDialog.show()
            if startLineNum > 0:
                startScanLineNums = sorted(startScanLineNums)
            numOfScans = len(startScanLineNums)
            scanLines = [fdata[i] for i in startScanLineNums]
            if startLineNum == 0:
                tmp = 0
                self.Data['NumOfScans'] = 0  #numOfScans
                self.Data['ScanNums'] = []
                offset = 0
#                self.Data['ScanLines']=[]#scanLines
#                self.Data['StartScanLineNums']=[]#startScanLineNums
            else:
                tmp = self.Data['NumOfScans']
                self.Data[
                    'NumOfScans'] = self.Data['NumOfScans'] - 1  #+numOfScans
                offset = 1
#                self.Data['ScanLines']=self.Data['ScanLines'][:-1]#+scanLines[1:]
#                self.Data['StartScanLineNums']=self.Data['StartScanLineNums'][:-1]#+startScanLineNums
            if int(scanLines[-1].split()
                   [1]) != len(startScanLineNums) + endScanNum - offset:
                print len(
                    startScanLineNums), scanLines[-1].split()[1], endScanNum
                self.Data['Error'] = True
                self.Data['Message'] = 'There are identical scans in the file'
            else:
                self.Data['Error'] = False
            for i in range(numOfScans):
                start = startScanLineNums[i] + 1
                line = fdata[start]
                num = int(fdata[startScanLineNums[i]].split()[1])
                i = i + tmp
                self.Data[num] = {}
                self.Par[num] = {}
                if fdata[start - 1].split()[2] == 'getandsave_mca':
                    self.Par[num]['Detector'] = 'Vortex'
                    self.Data[num]['ScanVar'] = 'Empty'
                else:
                    self.Par[num]['Detector'] = 'Monitor'
                tmpdata = []
                while line[:2] != '\n' and line[:2] != '#C':
                    if line[:2] == '#P':
                        parName = line[4:].split()
                        start = start + 1
                        parValue = map(eval, fdata[start][1:].split())
                        for j in range(len(parName)):
                            self.Par[num][parName[j]] = parValue[j]
                    if line[:2] == '#W':
                        tmppar = line[2:].split()
                        self.Par[num]['Wavelength'] = eval(tmppar[1])
                    if line[:3] == '#G0':
                        self.Par[num]['g_l1'] = float(line[4:].split()[5])
                        self.Par[num]['g_l2'] = float(line[4:].split()[6])
                        self.Par[num]['g_l3'] = float(line[4:].split()[7])
                    if line[:2] == '#A':
                        tmppar = line[2:].split()
                        self.Par[num]['Absorber'] = eval(tmppar[1])
                    if line[:2] == '#Q':
                        tmppar = line[2:].split()
                        self.Par[num]['Q'] = map(eval, tmppar)
                    if line[:2] == '#V':
                        self.Par[num]['Detector'] = 'Vortex'
                    if line[:3] == '#B0':
                        tmppar = line[3:].split('.')
                        self.Par[num]['ImageNumber'] = len(
                            line[3:].split('_')[-1].split('.')[0])
                        if tmppar[1] == 'tif\n':
                            self.Par[num]['Detector'] = 'Pilatus'
                        elif tmppar[1] == 'sfrm\n':
                            self.Par[num]['Detector'] = 'Bruker'
                    if line[:3] == '#B1':
                        try:
                            tmppar = map(eval, line[3:].split())
                        except:
                            tmppar = map(eval, line[3:].split()[:-1])
                        self.Par[num]['DBPos'] = tmppar[:2]
                        self.Par[num]['S2D_Dist'] = tmppar[2]
                        self.Par[num]['S7D_Dist'] = tmppar[3]
                    if line[:3] == '#B2':
                        tmppar = map(eval, line[3:].split())
                        self.Par[num]['DBPos'] = tmppar[:2]
                        self.Par[num]['S2D_Dist'] = tmppar[2]
                        self.Par[num]['S7D_Dist'] = tmppar[3]
                    if line[:2] == '#L':
                        scanVar = line[3:-1].split()
                        self.Data[num]['ScanVar'] = scanVar
                    if line[0] != '#':
                        try:
                            tmpdata.append(map(eval, line.split()))
                        except:
                            self.Data[num][
                                'Message'] = 'Something wrong with Scan Number %d', num, '.Please check the the scan in the specfile.'
                            print 'Something wrong with Scan Number %d', num
                    start = start + 1
                    try:
                        line = fdata[start]
                    except:
                        break
                if self.Data[num]['ScanVar'] != 'Empty':
                    for j in range(len(scanVar)):
                        try:
                            self.Data[num][scanVar[j]] = np.array(
                                tmpdata, dtype='float')[:, j]
                        except:
                            self.Data[num][scanVar[j]] = None
                if len(self.Par[num]) == 1:
                    self.Par[num]['Message'] = 'No parameters!!'
                self.progressDialog.setLabelText('Reading Scan #' + str(num))
                self.updateProgress()
                self.Data['NumOfScans'] = num
                #                self.Data['ScanLines']=self.Data['ScanLines']+[scanLines[num-tmp]]
                self.Data[num]['ScanLine'] = fdata[startScanLineNums[i - tmp]]
                self.Data[num]['StartScanLineNum'] = startScanLineNums[i - tmp]
                self.endLineNum = startScanLineNums[i - tmp]
                self.Data['ScanNums'].append(num)
                if self.progressDialog.wasCanceled() == True:
                    break
        self.progressDialog.hide()

    def APS_9IDC(self, startLineNum=0, endScanNum=0, det='CCD'):
        """
        Function to read a complete spec File collected at APS 9IDC 
        """
        self.progressDialog = QProgressDialog('Reading scans form SPEC File:',
                                              'Abort', 0, 100)
        self.progressDialog.setWindowModality(Qt.WindowModal)
        self.progressDialog.setWindowTitle('Wait')
        self.progressDialog.setAutoClose(True)
        self.progressDialog.setAutoReset(True)
        self.progressDialog.setMinimum(1)
        self.Data['YCol'] = 'Bicron1'
        self.Data['NCol'] = 'i2'
        fid = open(self.specfile)
        fdata = fid.readlines()
        self.SpecFileFull = fdata
        fid.close()
        if fdata[0][:2] != '#F':
            self.Data['NumOfScans'] = 0
            self.Data['Message'] = 'The file is not a valid specfile!!'
            print 'Error:: The file is not a valid specfile!!'
        else:
            startScanLineNums = [
                i for i in range(startLineNum, len(fdata))
                if fdata[i][:2] == '#S'
            ]
            self.progressDialog.setMaximum(len(startScanLineNums))
            self.progressDialog.show()
            self.endLineNum = startScanLineNums[-1]
            if startLineNum > 0:
                startScanLineNums = sorted(startScanLineNums)
            self.Data['StartScanLineNums'] = startScanLineNums
            numOfScans = len(self.Data['StartScanLineNums'])
            scanLines = [fdata[i] for i in startScanLineNums]
            if startLineNum == 0:
                tmp = 0
                self.Data['NumOfScans'] = 0  #numOfScans
                self.Data['ScanLines'] = []  #scanLines
                self.Data['StartScanLineNums'] = []  #startScanLineNums
                self.Par['ParName'] = []
                for i in range(startScanLineNums[0]):
                    line = fdata[i].split()
                    if fdata[i][:2] == '#O':
                        self.Par['ParName'] = self.Par['ParName'] + line[1:]
            else:
                tmp = self.Data['NumOfScans']
                self.Data[
                    'NumOfScans'] = self.Data['NumOfScans'] - 1  #+numOfScans
                self.Data['ScanLines'] = self.Data[
                    'ScanLines'][:-1]  #+scanLines[1:]
                self.Data['StartScanLineNums'] = self.Data[
                    'StartScanLineNums'][:-1]  #+startScanLineNums
            for i in range(numOfScans):
                start = startScanLineNums[i] + 1
                line = fdata[start]
                i = i + tmp
                self.Data[i] = {}
                self.Par[i] = {}
                if fdata[start - 1].split()[2] == 'getandsave_mca' or fdata[
                        start - 1].split()[2] == 'MCAscanpt':
                    self.Par[i]['Mca'] = 1
                    self.Data[i]['ScanVar'] = 'Empty'
                else:
                    self.Par[i]['Mca'] = 0
                self.Par[i]['CCD'] = 0
                tmpdata = []
                pstart = 0
                while line[:2] != '\n' and line[:2] != '#C':
                    if line[:2] == '#P':
                        parValue = map(eval, fdata[start].split()[1:])
                        for j in range(len(parValue)):
                            self.Par[i][self.Par['ParName']
                                        [pstart]] = parValue[j]
                            pstart = pstart + 1
                    if line[:2] == '#Q':
                        tmppar = line[2:].split()
                        self.Par[i]['Q'] = map(eval, tmppar)
                    if line[:2] == '#L':
                        scanVar = line[3:-1].split()
                        self.Data[i]['ScanVar'] = scanVar
                    if line[0] != '#':
                        tmpdata.append(map(eval, line.split()))
                    start = start + 1
                    line = fdata[start]
                for j in range(len(scanVar)):
                    try:
                        self.Data[i][scanVar[j]] = np.array(tmpdata)[:, j]
                    except:
                        self.Data[i][scanVar[j]] = None
                if len(self.Par[i]) == 1:
                    self.Par[i]['Message'] = 'No parameters!!'
                self.progressDialog.setLabelText(
                    'Reading scans form SPEC File: ' + str(i + 1))
                self.updateProgress()
                self.Data['NumOfScans'] = i
                self.Data['ScanLines'] = self.Data['ScanLines'] + [
                    scanLines[i - tmp]
                ]
                self.Data['StartScanLineNums'] = self.Data[
                    'StartScanLineNums'] + [startScanLineNums[i - tmp]]
                self.endLineNum = startScanLineNums[i - tmp]
                if self.progressDialog.wasCanceled() == True:
                    break
        self.progressDialog.hide()
Example #15
0
class ImportDialog(QDialog, Ui_ImportDialogBase):

    def __init__(self, theParent=None, theIface=None):
        """Constructor for import dialog.

        Args:
           * theParent - Optional widget to use as parent
           * theIface - an instance of QGisInterface
        Returns:
           not applicable
        Raises:
           no exceptions explicitly raised
        """
        QDialog.__init__(self, theParent)
        self.parent = theParent
        self.setupUi(self)

        self.setWindowTitle(self.tr('InaSAFE OpenStreetMap Downloader'))

        self.iface = theIface
        self.url = "http://osm.linfiniti.com/buildings-shp"

        ## region coordinate: (latitude, longtitude, zoom_level)
        self.regionExtent = {
            '0': [18.87685, -71.493, 6],     # haiti
            '1': [-2.5436300, 116.8887, 3],  # indonesia
            '2': [1.22449, 15.40999, 2],     # africa
            '3': [34.05, 56.55, 3],          # middle east
            '4': [12.98855, 121.7166, 4],    # philipine
        }

        # creating progress dialog for download
        self.progressDialog = QProgressDialog(self)
        self.progressDialog.setAutoClose(False)
        myTitle = self.tr("InaSAFE OpenStreetMap Downloader")
        self.progressDialog.setWindowTitle(myTitle)

        ## set map parameter based on placeholder self.map widget
        theMap = InasafeLightMaps(self.gbxMap)
        theMap.setGeometry(self.map.geometry())
        theMap.setSizePolicy(self.map.sizePolicy())
        self.map = theMap

        self.nam = QNetworkAccessManager(self)

        self.setupOptions()

        self.restoreState()

        self.cbxRegion.currentIndexChanged.connect(self.regionChanged)
        self.map.m_normalMap.updated.connect(self.updateExtent)

    def regionChanged(self, theIndex):
        """ Slot that called when region combo box changed.
        Params:
            theIndex - index of combo box
        """
        myRegionIndex = str(self.cbxRegion.itemData(theIndex).toString())
        myCenter = self.regionExtent[myRegionIndex]
        self.map.setCenter(myCenter[0], myCenter[1], myCenter[2])

    # pylint: disable=W0613
    def resizeEvent(self, theEvent):
        """ Function that called when resize event occurred.
        Params:
            theEvent - QEvent instance. Not used.
        """
        self.map.resize(self.gbxMap.width() - 30, self.gbxMap.height() - 30)
    # pylint: disable=W0613

    def setupOptions(self):
        """ Set the content of combo box for region and preset """
        self.cbxRegion.insertItem(0, 'Indonesia', 1)
        self.cbxRegion.insertItem(1, 'Africa', 2)
        self.cbxRegion.insertItem(2, 'Philippines', 4)
        self.cbxRegion.insertItem(3, 'Central Asia/Middle East', 3)
        self.cbxRegion.insertItem(4, 'Haiti', 0)

        self.cbxPreset.insertItem(0, self.tr('Buildings'), 'building')
        self.cbxPreset.insertItem(0, self.tr('Highway'), 'highway')

    def restoreState(self):
        """ Read last state of GUI from configuration file """
        mySetting = QSettings()

        myRegion = mySetting.value('region').toInt()
        if myRegion[1] is True:
            self.cbxRegion.setCurrentIndex(myRegion[0])

        myPreset = mySetting.value('preset').toInt()
        if myPreset[1] is True:
            self.cbxPreset.setCurrentIndex(myPreset[0])

        self.outDir.setText(mySetting.value('directory').toString())

        myZoomLevel = mySetting.value('zoom_level').toInt()
        myLatitude = mySetting.value('latitude').toDouble()
        myLongitude = mySetting.value('longitude').toDouble()

        if myZoomLevel[1] is True:
            self.map.setCenter(myLatitude[0], myLongitude[0], myZoomLevel[0])
        else:
            # just set to indonesia extent
            myCenter = self.regionExtent['1']
            self.map.setCenter(myCenter[0], myCenter[1], myCenter[2])

    def saveState(self):
        """ Store current state of GUI to configuration file """
        mySetting = QSettings()
        mySetting.setValue('region', self.cbxRegion.currentIndex())
        mySetting.setValue('preset', self.cbxPreset.currentIndex())
        mySetting.setValue('directory', self.outDir.text())

        mySetting.setValue('zoom_level', self.map.getZoomLevel())
        myCenter = self.map.getCenter()
        mySetting.setValue('latitude', myCenter[0])
        mySetting.setValue('longitude', myCenter[1])

    def updateExtent(self):
        """ Update extent value in GUI based from value in map widget"""
        myExtent = self.map.getExtent()
        self.minLongitude.setText(str(myExtent[1]))
        self.minLatitude.setText(str(myExtent[0]))
        self.maxLongitude.setText(str(myExtent[3]))
        self.maxLatitude.setText(str(myExtent[2]))

    @pyqtSignature('')  # prevents actions being handled twice
    def on_pBtnDir_clicked(self):
        """ Show a dialog to choose directory """
        self.outDir.setText(QFileDialog.getExistingDirectory(
            self, self.tr("Select Directory")))

    def accept(self):
        """ Do import process """

        try:
            self.saveState()

            self.ensureDirExist()
            self.doImport()
            self.loadShapeFile()
            self.done(QDialog.Accepted)
        except CanceledImportDialogError:
            # don't show anything because this exception raised
            # when user canceling the import process directly
            pass
        except Exception as myEx:
            QMessageBox.warning(
                self,
                self.tr("InaSAFE OpenStreetMap Downloader Error"),
                str(myEx))

            self.progressDialog.cancel()

    def ensureDirExist(self):
        """
        Ensure directory path entered in dialog exist.
        When the path is not exist, this function will
        ask the user if he want to create it or not.

        Raises:
            CanceledImportDialogError - when user choose 'No'
                        in question dialog for creating directory.
        """

        myDir = str(self.outDir.text())

        if os.path.exists(myDir):
            return

        myTitle = self.tr("Directory %1 not exist").arg(myDir)
        myQuestion = self.tr(
            "Directory %1 not exist. Are you want to create it?"
        ).arg(myDir)
        myAnswer = QMessageBox.question(
            self, myTitle,
            myQuestion, QMessageBox.Yes | QMessageBox.No)

        if myAnswer == QMessageBox.Yes:
            os.makedirs(myDir)
        else:
            raise CanceledImportDialogError()

    def doImport(self):
        """
        Import shape files from Linfinti.
        Raises:
            * ImportDialogError - when network error occurred
            * CanceledImportDialogError - when user press cancel button
        """

        ## preparing necessary data
        myMinLng = str(self.minLongitude.text())
        myMinLat = str(self.minLatitude.text())
        myMaxLng = str(self.maxLongitude.text())
        myMaxLat = str(self.maxLatitude.text())

        myCurrentIndex = self.cbxPreset.currentIndex()
        myType = str(self.cbxPreset.itemData(myCurrentIndex).toString())

        myCoordinate = "{myMinLng},{myMinLat},{myMaxLng},{myMaxLat}".format(
            myMinLng=myMinLng,
            myMinLat=myMinLat,
            myMaxLng=myMaxLng,
            myMaxLat=myMaxLat
        )

        myShapeUrl = "{url}?bbox={myCoordinate}&obj={type}".format(
            url=self.url,
            myCoordinate=myCoordinate,
            type=myType
        )

        myFilePath = tempfile.mktemp('.shp.zip')

        # download and extract it
        self.downloadShapeFile(myShapeUrl, myFilePath)
        self.extractZip(myFilePath, str(self.outDir.text()))

        self.progressDialog.done(QDialog.Accepted)

    def downloadShapeFile(self, theUrl, theOutput):
        """
        Download shape file from theUrl and write to theOutput.
        Params:
            * theUrl - URL of shape file
            * theOutput - path of output file
        Raises:
            * ImportDialogError - when network error occurred
        """

        self.progressDialog.show()
        self.progressDialog.setMaximum(100)
        self.progressDialog.setValue(0)

        # myLabelText = "Begin downloading shapefile from " \
        #               + "%1 ..."
        # self.progressDialog.setLabelText(self.tr(myLabelText).arg(theUrl))
        myLabelText = self.tr("Begin downloading shapefile")
        self.progressDialog.setLabelText(myLabelText)

        myResult = httpDownload(self.nam, theUrl, theOutput,
                                self.progressDialog)

        if myResult is not True:
            _, myErrorMessage = myResult
            raise ImportDialogError(myErrorMessage)

    def extractZip(self, thePath, theOutDir):
        """
        Extract all content of zip file from thePath to theOutDir.
        Args:
           * thePath - the path of zip file
           * theOutDir - output directory
        Raises:
            IOError - when cannot open thePath or theOutDir is not exist.
        """

        import zipfile

        ## extract all files...
        myHandle = open(thePath, 'rb')
        myZip = zipfile.ZipFile(myHandle)
        for myName in myZip.namelist():
            myOutPath = os.path.join(theOutDir, myName)
            myOutFile = open(myOutPath, 'wb')
            myOutFile.write(myZip.read(myName))
            myOutFile.close()

        myHandle.close()

    def loadShapeFile(self):
        """
        Load downloaded shape file to QGIS Main Window.

        Raises:
            ImportDialogError - when buildings.shp not exist
        """

        myDir = str(self.outDir.text())
        myPath = os.path.join(myDir, 'buildings.shp')

        if not os.path.exists(myPath):
            myMessage = self.tr(
                "%s don't exist. The server don't have buildings data."
            )
            raise ImportDialogError(myMessage)

        self.iface.addVectorLayer(myPath, 'buildings', 'ogr')
    def setup_workspace(self):
        data0 = os.path.join(self.iso_dir, DATA0_CPK)

        self.generate_directories()

        progress = QProgressDialog("", QtCore.QString(), 0, 11000, self)
        progress.setWindowTitle("Setting up workspace...")
        progress.setWindowModality(Qt.Qt.WindowModal)
        progress.setMinimumDuration(0)
        progress.setValue(0)
        progress.setAutoClose(False)
        progress.setAutoReset(False)

        progress.setLabelText("Creating directories...")

        # Do the easy stuff first.
        if not os.path.isdir(self.changes_dir):
            os.makedirs(self.changes_dir)
        progress.setValue(progress.value() + 1)

        if not os.path.isdir(self.backup_dir):
            os.makedirs(self.backup_dir)
        progress.setValue(progress.value() + 1)

        thread_fns = [{"target": extract_cpk, "kwargs": {"filename": data0, "out_dir": self.data0_dir}}]

        # Going to capture stdout because I don't feel like
        # rewriting the extract functions to play nice with GUI.
        stdout = sys.stdout
        sys.stdout = cStringIO.StringIO()

        for thread_fn in thread_fns:
            thread = threading.Thread(**thread_fn)
            thread.start()

            while thread.isAlive():
                thread.join(THREAD_TIMEOUT)

                output = [line for line in sys.stdout.getvalue().split("\n") if len(line) > 0]
                progress.setValue(progress.value() + len(output))
                if len(output) > 0:
                    progress.setLabelText("Extracting %s..." % output[-1])

                sys.stdout = cStringIO.StringIO()

        sys.stdout = stdout

        # Give us an ISO directory for the editor to place modified files in.
        progress.setLabelText("Copying ISO files...")

        # ISO directory needs to not exist for copytree.
        if os.path.isdir(self.edited_iso_dir):
            shutil.rmtree(self.edited_iso_dir)

        # One more thing we want threaded so it doesn't lock up the GUI.
        thread = threading.Thread(target=shutil.copytree, kwargs={"src": self.iso_dir, "dst": self.edited_iso_dir})
        thread.start()

        while thread.isAlive():
            thread.join(THREAD_TIMEOUT)
            progress.setLabelText("Copying ISO files...")
            # It has to increase by some amount or it won't update and the UI will lock up.
            progress.setValue(progress.value() + 1)

        # shutil.copytree(self.iso_dir, self.edited_iso_dir)
        progress.setValue(progress.value() + 1)

        # Files we want to make blank, because they're unnecessary.
        blank_files = [
            os.path.join(self.edited_iso_dir, "PSP_GAME", "SYSDIR", "UPDATE", "DATA.BIN"),
            os.path.join(self.edited_iso_dir, "PSP_GAME", "SYSDIR", "UPDATE", "EBOOT.BIN"),
            os.path.join(self.edited_iso_dir, "PSP_GAME", "SYSDIR", "UPDATE", "PARAM.SFO"),
        ]

        for blank in blank_files:
            with open(blank, "wb") as f:
                pass

        # Copy the decrypted EBOOT into the ISO folder and apply our hacks to it.
        progress.setLabelText("Hacking EBOOT...")
        progress.setValue(progress.value() + 1)

        hacked_eboot = BitStream(filename=self.eboot_path)
        hacked_eboot = apply_eboot_patches(hacked_eboot)
        with open(os.path.join(self.edited_iso_dir, "PSP_GAME", "SYSDIR", "EBOOT.BIN"), "wb") as f:
            hacked_eboot.tofile(f)
        # shutil.copy(self.eboot_path, os.path.join(self.edited_iso_dir, "PSP_GAME", "SYSDIR", "EBOOT.BIN"))

        progress.setLabelText("Extracting editor data...")
        progress.setValue(progress.value() + 1)

        # Extract the editor data.
        editor_data = zipfile.ZipFile("data/editor_data.zip", "r")
        editor_data.extractall(self.editor_data_dir)
        editor_data.close()

        progress.setValue(progress.maximum())
        progress.close()

        self.ui.grpStep4.setEnabled(False)
        self.ui.grpStep5.setEnabled(True)
    def copy_gfx(self):
        gfx_dir = os.path.join(self.editor_data_dir, "gfx")

        if os.path.isdir(gfx_dir):
            shutil.rmtree(gfx_dir)

        os.makedirs(gfx_dir)

        progress = QProgressDialog("", "Abort", 0, 0, self)
        progress.setWindowTitle("Copying GFX...")
        progress.setWindowModality(Qt.Qt.WindowModal)
        progress.setMinimumDuration(0)
        progress.setValue(0)
        progress.setAutoClose(False)

        progress.setLabelText("Setting up GFX dir.")
        progress.setMaximum(5)
        progress.setValue(0)

        # Extract the images we can't just take directly from the game's data.
        gfx_bin = zipfile.ZipFile("data/gfx_base.zip", "r")
        progress.setValue(1)
        progress.setValue(2)
        gfx_bin.extractall(gfx_dir)
        progress.setValue(5)
        gfx_bin.close()

        # We can mostly loop this.
        gfx_data = [
            ("ammo", "kotodama_icn_???.gim"),
            ("bgd", "bgd_???.gim"),
            ("cutin", "cutin_icn_???.gim"),
            ("events", "gallery_icn_???.gim"),
            ("movies", "bin_movie_gallery_l.pak/0000/000[1789].gim"),
            ("movies", "bin_movie_gallery_l.pak/0000/00[123]?.gim"),
            ("movies", "gallery_ico_m_none.gim"),
            ("movies", "gallery_thumbnail_m_???.gim"),
            ("nametags", "tex_system.pak/00[12]?.gim"),
            ("nametags", "tex_system.pak/003[0123456].gim"),
            ("presents", "present_icn_???.gim"),
            ("sprites", "bustup_??_??.gim"),
            ("sprites", "stand_??_??.gmo"),
        ]

        for (dir, file_glob) in gfx_data:
            out_dir = os.path.join(gfx_dir, dir)
            files = glob.glob(os.path.join(self.data0_dir, file_glob))

            progress.setLabelText("Copying %s." % dir)
            progress.setMaximum(len(files))
            progress.setValue(0)

            if not os.path.isdir(out_dir):
                os.makedirs(out_dir)

            for i, image in enumerate(files):
                if i % 10 == 0:
                    progress.setValue(i)

                if progress.wasCanceled():
                    return

                src = image
                dest = os.path.join(out_dir, os.path.basename(src))
                shutil.copy(src, dest)

            progress.setValue(len(files))

        progress.setLabelText("Copying font.")
        progress.setMaximum(4)
        progress.setValue(0)

        # The font we have to get from umdimage2.
        font_dir = os.path.join(gfx_dir, "font")
        if not os.path.isdir(font_dir):
            os.makedirs(font_dir)

        progress.setValue(1)
        # And convert to PNG with an alpha channel so our editor can use it.
        font1 = font_bmp_to_alpha(os.path.join(self.data01_dir, "jp", "font", "font.pak", "0000.bmp"))
        progress.setValue(2)
        font2 = font_bmp_to_alpha(os.path.join(self.data01_dir, "jp", "font", "font.pak", "0002.bmp"))
        progress.setValue(3)

        font1.save(os.path.join(font_dir, "Font01.png"))
        font2.save(os.path.join(font_dir, "Font02.png"))
        shutil.copy(
            os.path.join(self.data01_dir, "jp", "font", "font.pak", "0001.font"), os.path.join(font_dir, "Font01.font")
        )
        shutil.copy(
            os.path.join(self.data01_dir, "jp", "font", "font.pak", "0003.font"), os.path.join(font_dir, "Font02.font")
        )

        progress.setValue(4)

        # And then the flash files. This'll be fun.
        flash_dir = os.path.join(gfx_dir, "flash")
        if not os.path.isdir(flash_dir):
            os.makedirs(flash_dir)

        # Because there's so many in so many different places, I just stored a list
        # of the flash files we need in the gfx_base archive. So let's load that.
        with open(os.path.join(gfx_dir, "fla.txt"), "rb") as fla:
            fla_list = fla.readlines()

            progress.setLabelText("Copying flash.")
            progress.setMaximum(len(fla_list))
            progress.setValue(0)

            for i, flash in enumerate(fla_list):
                if i % 10 == 0:
                    progress.setValue(i)

                if progress.wasCanceled():
                    return

                flash = flash.strip()
                fla_name = flash[:7]  # fla_###

                src = os.path.join(self.data01_dir, "all", "flash", flash)
                dest = os.path.join(flash_dir, "%s.gim" % fla_name)

                shutil.copy(src, dest)

            progress.setValue(len(fla_list))

        # We have a couple sets of files that aren't named the way we want them to
        # be, just because of how they're stored in umdimage.
        progress.setLabelText("Renaming files.")
        to_rename = [("movies", "movie_%03d.gim", range(32)), ("nametags", "%02d.gim", range(23) + [24, 25, 30, 31])]

        for (folder, pattern, nums) in to_rename:
            folder = os.path.join(gfx_dir, folder)
            files = glob.glob(os.path.join(folder, "*.gim"))

            progress.setMaximum(len(files))
            progress.setValue(0)

            for i, image in enumerate(files):
                if i % 10 == 0:
                    progress.setValue(i)

                if progress.wasCanceled():
                    return

                src = image
                dest = os.path.join(folder, pattern % nums[i])

                if os.path.isfile(dest):
                    os.remove(dest)

                shutil.move(src, dest)

        sprite_dir = os.path.join(gfx_dir, "sprites")
        gmo_files = glob.glob(os.path.join(sprite_dir, "*.gmo"))

        progress.setLabelText("Extracting GMO files.")
        progress.setValue(0)
        progress.setMaximum(len(gmo_files))

        for i, gmo_file in enumerate(gmo_files):
            if i % 10 == 0:
                progress.setValue(i)

            if progress.wasCanceled():
                return

            name, ext = os.path.splitext(os.path.basename(gmo_file))
            gim_file = os.path.join(sprite_dir, name + ".gim")

            gmo = GmoFile(filename=gmo_file)

            # Once we've loaded it, we're all done with it, so make it go away.
            os.remove(gmo_file)

            if gmo.gim_count() == 0:
                continue

            gim = gmo.get_gim(0)

            with open(gim_file, "wb") as f:
                gim.tofile(f)

        if self.ui.chkGimToPng.isChecked():
            gim_files = glob.glob(os.path.join(gfx_dir, "*", "*.gim"))

            progress.setLabelText("Converting GIM to PNG.")
            progress.setValue(0)
            progress.setMaximum(len(gim_files))

            converter = GimConverter()

            for i, gim_file in enumerate(gim_files):
                progress.setValue(i)
                if progress.wasCanceled():
                    return

                converter.gim_to_png(gim_file)
                os.remove(gim_file)

        progress.close()

        self.gfx_dir = gfx_dir

        self.ui.grpStep5.setEnabled(False)
        self.ui.grpStep6.setEnabled(True)
Example #18
0
class OsmDownloader(QDialog, Ui_OsmDownloaderBase):
    """Downloader for OSM data."""

    def __init__(self, parent=None, iface=None):
        """Constructor for import dialog.

        :param parent: Optional widget to use as parent
        :type parent: QWidget

        :param iface: An instance of QGisInterface
        :type iface: QGisInterface
        """
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setupUi(self)

        self.setWindowTitle(self.tr('InaSAFE OpenStreetMap Downloader'))

        self.iface = iface
        self.buildings_url = "http://osm.linfiniti.com/buildings-shp"
        self.roads_url = "http://osm.linfiniti.com/roads-shp"

        self.help_context = 'openstreetmap_downloader'
        # creating progress dialog for download
        self.progress_dialog = QProgressDialog(self)
        self.progress_dialog.setAutoClose(False)
        title = self.tr("InaSAFE OpenStreetMap Downloader")
        self.progress_dialog.setWindowTitle(title)
        # Set up context help
        help_button = self.button_box.button(QtGui.QDialogButtonBox.Help)
        help_button.clicked.connect(self.show_help)

        self.show_info()

        # set up the validator for the file name prefix
        expression = QRegExp('^[A-Za-z0-9-_]*$')
        validator = QRegExpValidator(expression)
        self.filename_prefix.setValidator(validator)

        # Set Proxy in webpage
        proxy = get_proxy()
        self.network_manager = QNetworkAccessManager(self)
        if not proxy is None:
            self.network_manager.setProxy(proxy)
        self.restore_state()
        self.update_extent()

    def show_info(self):
        """Show usage info to the user."""
        # Read the header and footer html snippets
        header = html_header()
        footer = html_footer()

        string = header

        heading = m.Heading(self.tr('OSM Downloader'), **INFO_STYLE)
        body = self.tr(
            'This tool will fetch building (\'structure\') or road ('
            '\'highway\') data from the OpenStreetMap project for you. '
            'The downloaded data will have InaSAFE keywords defined and a '
            'default QGIS style applied. To use this tool effectively:'
        )
        tips = m.BulletedList()
        tips.add(self.tr(
            'Your current extent will be used to determine the area for which '
            'you want data to be retrieved. You can adjust it manually using '
            'the bounding box options below.'))
        tips.add(self.tr(
            'Check the output directory is correct. Note that the saved '
            'dataset will be called either roads.shp or buildings.shp (and '
            'associated files).'
        ))
        tips.add(self.tr(
            'By default simple file names will be used (e.g. roads.shp, '
            'buildings.shp). If you wish you can specify a prefix to '
            'add in front of this default name. For example using a prefix '
            'of \'padang-\' will cause the downloaded files to be saved as '
            '\'padang-roads.shp\' and \'padang-buildings.shp\'. Note that '
            'the only allowed prefix characters are A-Z, a-z, 0-9 and the '
            'characters \'-\' and \'_\'. You can leave this blank if you '
            'prefer.'
        ))
        tips.add(self.tr(
            'If a dataset already exists in the output directory it will be '
            'overwritten.'
        ))
        tips.add(self.tr(
            'This tool requires a working internet connection and fetching '
            'buildings or roads will consume your bandwidth.'))
        tips.add(m.Link(
            'http://www.openstreetmap.org/copyright',
            text=self.tr(
                'Downloaded data is copyright OpenStreetMap contributors'
                ' (click for more info).')
        ))
        message = m.Message()
        message.add(heading)
        message.add(body)
        message.add(tips)
        string += message.to_html()
        string += footer

        self.web_view.setHtml(string)

    def restore_state(self):
        """ Read last state of GUI from configuration file."""
        settings = QSettings()
        try:
            last_path = settings.value('directory', type=str)
        except TypeError:
            last_path = ''
        self.output_directory.setText(last_path)

    def save_state(self):
        """ Store current state of GUI to configuration file """
        settings = QSettings()
        settings.setValue('directory', self.output_directory.text())

    def show_help(self):
        """Load the help text for the dialog."""
        show_context_help(self.help_context)

    def update_extent(self):
        """ Update extent value in GUI based from value in map."""
        # Get the extent as [xmin, ymin, xmax, ymax]
        extent = viewport_geo_array(self.iface.mapCanvas())
        self.min_longitude.setText(str(extent[0]))
        self.min_latitude.setText(str(extent[1]))
        self.max_longitude.setText(str(extent[2]))
        self.max_latitude.setText(str(extent[3]))

    @pyqtSignature('')  # prevents actions being handled twice
    def on_directory_button_clicked(self):
        """ Show a dialog to choose directory """
        # noinspection PyCallByClass,PyTypeChecker
        self.output_directory.setText(QFileDialog.getExistingDirectory(
            self, self.tr("Select download directory")))

    def accept(self):
        """Do osm download and display it in QGIS."""

        index = self.feature_type.currentIndex()
        if index == 0:
            feature_types = ['buildings', 'roads']
        elif index == 1:
            feature_types = ['buildings']
        else:
            feature_types = ['roads']

        try:
            self.save_state()
            self.require_directory()
            for feature_type in feature_types:
                self.download(feature_type)
                self.load_shapefile(feature_type)
            self.done(QDialog.Accepted)
        except CanceledImportDialogError:
            # don't show anything because this exception raised
            # when user canceling the import process directly
            pass
        except Exception as myEx:
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QMessageBox.warning(
                self,
                self.tr("InaSAFE OpenStreetMap downloader error"),
                str(myEx))

            self.progress_dialog.cancel()

    def require_directory(self):
        """Ensure directory path entered in dialog exist.

        When the path does not exist, this function will ask the user if he
        want to create it or not.

        :raises: CanceledImportDialogError - when user choose 'No' in
            the question dialog for creating directory.
        """
        path = str(self.output_directory.text())

        if os.path.exists(path):
            return

        title = self.tr("Directory %s not exist") % path
        question = self.tr(
            "Directory %s not exist. Do you want to create it?"
        ) % path
        # noinspection PyCallByClass,PyTypeChecker
        answer = QMessageBox.question(
            self, title,
            question, QMessageBox.Yes | QMessageBox.No)

        if answer == QMessageBox.Yes:
            if len(path) != 0:
                os.makedirs(path)
            else:
            # noinspection PyCallByClass,PyTypeChecker, PyArgumentList
                QMessageBox.warning(
                    self,
                    self.tr('InaSAFE error'),
                    self.tr('Output directory can not be empty.'))
                raise CanceledImportDialogError()
        else:
            raise CanceledImportDialogError()

    def download(self, feature_type):
        """Download shapefiles from Linfinti server.

        :param feature_type: What kind of features should be downloaded.
            Currently 'buildings' or 'roads' are supported.
        :type feature_type: str

        :raises: ImportDialogError, CanceledImportDialogError
        """

        ## preparing necessary data
        min_longitude = str(self.min_longitude.text())
        min_latitude = str(self.min_latitude.text())
        max_longitude = str(self.max_longitude.text())
        max_latitude = str(self.max_latitude.text())

        box = (
            '{min_longitude},{min_latitude},{max_longitude},'
            '{max_latitude}').format(
                min_longitude=min_longitude,
                min_latitude=min_latitude,
                max_longitude=max_longitude,
                max_latitude=max_latitude
            )
        output_prefix = self.filename_prefix.text()
        if feature_type == 'buildings':
            url = "{url}?bbox={box}&qgis_version=2".format(
                url=self.buildings_url, box=box)
        else:
            url = "{url}?bbox={box}&qgis_version=2".format(
                url=self.roads_url, box=box)

        if output_prefix is not None:
            url += '&output_prefix=%s' % output_prefix

        path = tempfile.mktemp('.shp.zip')

        # download and extract it
        self.fetch_zip(url, path)
        #print path
        #print str(self.output_directory.text())

        self.extract_zip(path, str(self.output_directory.text()))

        self.progress_dialog.done(QDialog.Accepted)

    def fetch_zip(self, url, output_path):
        """Download zip containing shp file and write to output_path.

        :param url: URL of the zip bundle.
        :type url: str

        :param output_path: Path of output file,
        :type output_path: str

        :raises: ImportDialogError - when network error occurred
        """
        LOGGER.debug('Downloading file from URL: %s' % url)
        LOGGER.debug('Downloading to: %s' % output_path)

        self.progress_dialog.show()
        self.progress_dialog.setMaximum(100)
        self.progress_dialog.setValue(0)

        # label_text = "Begin downloading shapefile from " \
        #               + "%s ..."
        # self.progress_dialog.setLabelText(self.tr(label_text) % (url))
        label_text = self.tr("Downloading shapefile")
        self.progress_dialog.setLabelText(label_text)

        result = download_url(
            self.network_manager, url, output_path,
            self.progress_dialog)

        if result[0] is not True:
            _, error_message = result
            raise ImportDialogError(error_message)

    @staticmethod
    def extract_zip(path, output_dir):
        """Extract all content of a .zip file from path to output_dir.

        :param path: The path of the .zip file
        :type path: str

        :param output_dir: Output directory where the shp will be written to.
        :type output_dir: str

        :raises: IOError - when not able to open path or output_dir does not
            exist.
        """

        import zipfile

        # extract all files...
        handle = open(path, 'rb')
        zip_file = zipfile.ZipFile(handle)
        for name in zip_file.namelist():
            output_path = os.path.join(output_dir, name)
            output_file = open(output_path, 'wb')
            output_file.write(zip_file.read(name))
            output_file.close()

        handle.close()

    def load_shapefile(self, feature_type):
        """
        Load downloaded shape file to QGIS Main Window.

        :param feature_type: What kind of features should be downloaded.
            Currently 'buildings' or 'roads' are supported.
        :type feature_type: str

        :raises: ImportDialogError - when buildings.shp not exist
        """
        output_prefix = self.filename_prefix.text()
        path = str(self.output_directory.text())
        path = os.path.join(path, '%s%s.shp' % (output_prefix, feature_type))

        if not os.path.exists(path):
            message = self.tr(
                "%s don't exist. The server doesn't have any data."
            )
            raise ImportDialogError(message)

        self.iface.addVectorLayer(path, feature_type, 'ogr')
Example #19
0
def run(iface,
        lineLayer,
        nodeLayer,
        nodeRadiiExpr="0",
        lineWidthExpr="1",
        iterations=100,
        w_flows=1,
        w_nodes=0.5,
        w_antiTorsion=0.8,
        w_spring=1,
        w_angRes=3.75,
        snapThreshold=0,
        bezierRes=15,
        alpha=4,
        beta=4,
        kShort=0.5,
        kLong=0.05,
        Cp=2.5,
        K=4,
        C=4,
        constraintRectAspect=0.5,
        nodeBuffer=0):
    """
    Runs the algorithm
    :return:
    """
    # Generate a progress bar
    progDialog = QProgressDialog()
    progDialog.setWindowTitle("Progress")
    progDialog.setLabelText("Generating flowmap from layers")
    progBar = QProgressBar(progDialog)
    progBar.setTextVisible(True)
    progBar.setValue(0)
    progDialog.setBar(progBar)
    progDialog.setMinimumWidth(300)
    progBar.setMaximum(iterations)
    progDialog.show()
    # Load the nodes and flows into a data structure
    fm = FlowMap(w_flows=w_flows,
                 w_nodes=w_nodes,
                 w_antiTorsion=w_antiTorsion,
                 w_spring=w_spring,
                 w_angRes=w_angRes,
                 snapThreshold=snapThreshold,
                 bezierRes=bezierRes,
                 alpha=alpha,
                 beta=beta,
                 kShort=kShort,
                 kLong=kLong,
                 Cp=Cp,
                 K=K,
                 C=C,
                 constraintRectAspect=constraintRectAspect,
                 nodeBuffer=nodeBuffer)
    fm.getNodesFromLineLayer(lineLayer)
    if nodeLayer is not None:
        fm.getNodeRadiiFromLayer(nodeLayer, nodeRadiiExpr)
    else:
        fm.nodeRadii = [0 for node in fm.nodes]
    fm.getLineWidthFromLayer(lineLayer, lineWidthExpr)
    fm.calculateMapScale()
    fm.loadFlowLinesFromLayer(lineLayer)
    # Iterate
    j = 0  # used in node collision avoidance algorithm
    progDialog.setLabelText("Iterating")
    for i in range(iterations):
        progBar.setValue(i)
        if progDialog.wasCanceled():
            break
        w = 1 - float(i) / iterations
        # Calculate flowline-against-flowline forces
        flowline_forces, Fs = fm.calculateInterFlowLineForces(
            returnSumOfMagnitudes=True)
        # Calculate node-against-flowline forces
        node_forces = fm.calculateNodeToFlowLineForces()
        # Calculate anti-torsion forces
        antitorsion_forces = fm.calculateAntiTorsionForces()
        # Calculate spring forces
        spring_forces = fm.calculateSpringForces(flowline_forces, Fs)
        # Calculate angular-resolution-of-flowlines-around-nodes forces
        angRes_forces = fm.calculateAngleResForces()
        # Apply forces to arc control points
        resultantForces = []
        for i in range(len(fm.flowlines)):
            rForce = (flowline_forces[i]*fm.w_flows +
                      node_forces[i]*fm.w_nodes +
                      antitorsion_forces[i]*fm.w_antiTorsion +
                      spring_forces[i]*fm.w_spring)*w +\
                     (angRes_forces[i]*fm.w_angRes)*(w - w**2)
            resultantForces.append(rForce)
        fm.applyForces(resultantForces)
        # Apply rectangle constraint
        fm.applyRectangleConstraints()
        # Reduce intersections of flowlines with a common node
        fm.reduceFlowLineIntersections()
        # Move flows off of nodes
        if i > 0.1 * iterations and j <= 0:
            N = fm.getFlowLinesOverlappingNodes()
            j = (iterations - i) / (len(N) + 1) / 2
            n = math.ceil(float(len(N)) / (iterations - i - 1))
            movedFlows = 0  # number of flows which have been moved. Iterate until this equals n
            for flowline in N:
                movedFlows += 1 if fm.moveFlowLineOffNodes(flowline) else 0
                if movedFlows >= n:
                    break
        else:
            j -= 1

    progDialog.setLabelText("Updating Geometry")
    # Update the geometry of the layer
    fm.updateGeometryOnLayer(lineLayer)
    iface.mapCanvas().refresh()
    # close the dialog
    progDialog.close()
Example #20
0
class AddonManagerDialog(QDialog):
    def __init__(self, parent=None, **kwargs):
        super(AddonManagerDialog, self).__init__(parent, **kwargs)
        self.setLayout(QVBoxLayout())

        self.addonwidget = AddonManagerWidget()
        self.addonwidget.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().addWidget(self.addonwidget)
        buttons = QDialogButtonBox(
            orientation=Qt.Horizontal,
            standardButtons=QDialogButtonBox.Ok | QDialogButtonBox.Cancel
        )
        buttons.accepted.connect(self.__accepted)
        buttons.rejected.connect(self.reject)

        self.layout().addWidget(buttons)

        self.__progress = QProgressDialog(
            self, Qt.Sheet,
            minimum=0, maximum=0,
            labelText=self.tr("Retrieving package list"),
            sizeGripEnabled=False,
            windowTitle="Progress"
        )
        self.__progress.canceled.connect(self.reject)

        # The installer thread
        self.__thread = None
        # The installer object
        self.__installer = None

    @Slot(list)
    def setItems(self, items):
        self.addonwidget.setItems(items)

    def progressDialog(self):
        return self.__progress

    def done(self, retcode):
        super(AddonManagerDialog, self).done(retcode)
        if self.__thread is not None:
            self.__thread.quit()
            self.__thread.wait(1000)

    def closeEvent(self, event):
        super(AddonManagerDialog, self).closeEvent(event)
        if self.__thread is not None:
            self.__thread.quit()
            self.__thread.wait(1000)

    def __accepted(self):
        steps = self.addonwidget.itemState()

        if steps:
            # Move all uninstall steps to the front
            steps = sorted(
                steps, key=lambda step: 0 if step[0] == Uninstall else 1
            )
            self.__installer = Installer(steps=steps)
            self.__thread = QThread(self)
            self.__thread.start()

            self.__installer.moveToThread(self.__thread)
            self.__installer.finished.connect(self.__on_installer_finished)
            self.__installer.error.connect(self.__on_installer_error)
            self.__installer.installStatusChanged.connect(
                self.__progress.setLabelText)

            self.__progress.show()
            self.__progress.setLabelText("Installing")

            self.__installer.start()

        else:
            self.accept()

    def __on_installer_error(self, command, pkg, retcode, output):
        message_error(
            "An error occurred while running a subprocess", title="Error",
            informative_text="{} exited with non zero status.".format(command),
            details="".join(output),
            parent=self
        )
        self.reject()

    def __on_installer_finished(self):
        message_information(
            "Please restart the application for changes to take effect.",
            parent=self)
        self.accept()
Example #21
0
class ImportDialog(QDialog, Ui_ImportDialogBase):
    def __init__(self, theParent=None, theIface=None):
        """Constructor for import dialog.

        Args:
           * theParent - Optional widget to use as parent
           * theIface - an instance of QGisInterface
        Returns:
           not applicable
        Raises:
           no exceptions explicitly raised
        """
        QDialog.__init__(self, theParent)
        self.parent = theParent
        self.setupUi(self)

        self.setWindowTitle(self.tr('InaSAFE OpenStreetMap Downloader'))

        self.iface = theIface
        self.url = "http://osm.linfiniti.com/buildings-shp"

        ## region coordinate: (latitude, longtitude, zoom_level)
        self.regionExtent = {
            '0': [18.87685, -71.493, 6],  # haiti
            '1': [-2.5436300, 116.8887, 3],  # indonesia
            '2': [1.22449, 15.40999, 2],  # africa
            '3': [34.05, 56.55, 3],  # middle east
            '4': [12.98855, 121.7166, 4],  # philipine
        }

        # creating progress dialog for download
        self.progressDialog = QProgressDialog(self)
        self.progressDialog.setAutoClose(False)
        myTitle = self.tr("InaSAFE OpenStreetMap Downloader")
        self.progressDialog.setWindowTitle(myTitle)

        ## set map parameter based on placeholder self.map widget
        theMap = InasafeLightMaps(self.gbxMap)
        theMap.setGeometry(self.map.geometry())
        theMap.setSizePolicy(self.map.sizePolicy())
        self.map = theMap

        self.nam = QNetworkAccessManager(self)

        self.setupOptions()

        self.restoreState()

        self.cbxRegion.currentIndexChanged.connect(self.regionChanged)
        self.map.m_normalMap.updated.connect(self.updateExtent)

    def regionChanged(self, theIndex):
        """ Slot that called when region combo box changed.
        Params:
            theIndex - index of combo box
        """
        myRegionIndex = str(self.cbxRegion.itemData(theIndex).toString())
        myCenter = self.regionExtent[myRegionIndex]
        self.map.setCenter(myCenter[0], myCenter[1], myCenter[2])

    # pylint: disable=W0613
    def resizeEvent(self, theEvent):
        """ Function that called when resize event occurred.
        Params:
            theEvent - QEvent instance. Not used.
        """
        self.map.resize(self.gbxMap.width() - 30, self.gbxMap.height() - 30)

    # pylint: disable=W0613

    def setupOptions(self):
        """ Set the content of combo box for region and preset """
        self.cbxRegion.insertItem(0, 'Indonesia', 1)
        self.cbxRegion.insertItem(1, 'Africa', 2)
        self.cbxRegion.insertItem(2, 'Philippines', 4)
        self.cbxRegion.insertItem(3, 'Central Asia/Middle East', 3)
        self.cbxRegion.insertItem(4, 'Haiti', 0)

        self.cbxPreset.insertItem(0, self.tr('Buildings'), 'building')
        self.cbxPreset.insertItem(0, self.tr('Highway'), 'highway')

    def restoreState(self):
        """ Read last state of GUI from configuration file """
        mySetting = QSettings()

        myRegion = mySetting.value('region').toInt()
        if myRegion[1] is True:
            self.cbxRegion.setCurrentIndex(myRegion[0])

        myPreset = mySetting.value('preset').toInt()
        if myPreset[1] is True:
            self.cbxPreset.setCurrentIndex(myPreset[0])

        self.outDir.setText(mySetting.value('directory').toString())

        myZoomLevel = mySetting.value('zoom_level').toInt()
        myLatitude = mySetting.value('latitude').toDouble()
        myLongitude = mySetting.value('longitude').toDouble()

        if myZoomLevel[1] is True:
            self.map.setCenter(myLatitude[0], myLongitude[0], myZoomLevel[0])
        else:
            # just set to indonesia extent
            myCenter = self.regionExtent['1']
            self.map.setCenter(myCenter[0], myCenter[1], myCenter[2])

    def saveState(self):
        """ Store current state of GUI to configuration file """
        mySetting = QSettings()
        mySetting.setValue('region', self.cbxRegion.currentIndex())
        mySetting.setValue('preset', self.cbxPreset.currentIndex())
        mySetting.setValue('directory', self.outDir.text())

        mySetting.setValue('zoom_level', self.map.getZoomLevel())
        myCenter = self.map.getCenter()
        mySetting.setValue('latitude', myCenter[0])
        mySetting.setValue('longitude', myCenter[1])

    def updateExtent(self):
        """ Update extent value in GUI based from value in map widget"""
        myExtent = self.map.getExtent()
        self.minLongitude.setText(str(myExtent[1]))
        self.minLatitude.setText(str(myExtent[0]))
        self.maxLongitude.setText(str(myExtent[3]))
        self.maxLatitude.setText(str(myExtent[2]))

    @pyqtSignature('')  # prevents actions being handled twice
    def on_pBtnDir_clicked(self):
        """ Show a dialog to choose directory """
        self.outDir.setText(
            QFileDialog.getExistingDirectory(self,
                                             self.tr("Select Directory")))

    def accept(self):
        """ Do import process """

        try:
            self.saveState()

            self.ensureDirExist()
            self.doImport()
            self.loadShapeFile()
            self.done(QDialog.Accepted)
        except CanceledImportDialogError:
            # don't show anything because this exception raised
            # when user canceling the import process directly
            pass
        except Exception as myEx:
            QMessageBox.warning(
                self, self.tr("InaSAFE OpenStreetMap Downloader Error"),
                str(myEx))

            self.progressDialog.cancel()

    def ensureDirExist(self):
        """
        Ensure directory path entered in dialog exist.
        When the path is not exist, this function will
        ask the user if he want to create it or not.

        Raises:
            CanceledImportDialogError - when user choose 'No'
                        in question dialog for creating directory.
        """

        myDir = str(self.outDir.text())

        if os.path.exists(myDir):
            return

        myTitle = self.tr("Directory %1 not exist").arg(myDir)
        myQuestion = self.tr(
            "Directory %1 not exist. Are you want to create it?").arg(myDir)
        myAnswer = QMessageBox.question(self, myTitle, myQuestion,
                                        QMessageBox.Yes | QMessageBox.No)

        if myAnswer == QMessageBox.Yes:
            os.makedirs(myDir)
        else:
            raise CanceledImportDialogError()

    def doImport(self):
        """
        Import shape files from Linfinti.
        Raises:
            * ImportDialogError - when network error occurred
            * CanceledImportDialogError - when user press cancel button
        """

        ## preparing necessary data
        myMinLng = str(self.minLongitude.text())
        myMinLat = str(self.minLatitude.text())
        myMaxLng = str(self.maxLongitude.text())
        myMaxLat = str(self.maxLatitude.text())

        myCurrentIndex = self.cbxPreset.currentIndex()
        myType = str(self.cbxPreset.itemData(myCurrentIndex).toString())

        myCoordinate = "{myMinLng},{myMinLat},{myMaxLng},{myMaxLat}".format(
            myMinLng=myMinLng,
            myMinLat=myMinLat,
            myMaxLng=myMaxLng,
            myMaxLat=myMaxLat)

        myShapeUrl = "{url}?bbox={myCoordinate}&obj={type}".format(
            url=self.url, myCoordinate=myCoordinate, type=myType)

        myFilePath = tempfile.mktemp('.shp.zip')

        # download and extract it
        self.downloadShapeFile(myShapeUrl, myFilePath)
        self.extractZip(myFilePath, str(self.outDir.text()))

        self.progressDialog.done(QDialog.Accepted)

    def downloadShapeFile(self, theUrl, theOutput):
        """
        Download shape file from theUrl and write to theOutput.
        Params:
            * theUrl - URL of shape file
            * theOutput - path of output file
        Raises:
            * ImportDialogError - when network error occurred
        """

        self.progressDialog.show()
        self.progressDialog.setMaximum(100)
        self.progressDialog.setValue(0)

        # myLabelText = "Begin downloading shapefile from " \
        #               + "%1 ..."
        # self.progressDialog.setLabelText(self.tr(myLabelText).arg(theUrl))
        myLabelText = self.tr("Begin downloading shapefile")
        self.progressDialog.setLabelText(myLabelText)

        myResult = httpDownload(self.nam, theUrl, theOutput,
                                self.progressDialog)

        if myResult is not True:
            _, myErrorMessage = myResult
            raise ImportDialogError(myErrorMessage)

    def extractZip(self, thePath, theOutDir):
        """
        Extract all content of zip file from thePath to theOutDir.
        Args:
           * thePath - the path of zip file
           * theOutDir - output directory
        Raises:
            IOError - when cannot open thePath or theOutDir is not exist.
        """

        import zipfile

        ## extract all files...
        myHandle = open(thePath, 'rb')
        myZip = zipfile.ZipFile(myHandle)
        for myName in myZip.namelist():
            myOutPath = os.path.join(theOutDir, myName)
            myOutFile = open(myOutPath, 'wb')
            myOutFile.write(myZip.read(myName))
            myOutFile.close()

        myHandle.close()

    def loadShapeFile(self):
        """
        Load downloaded shape file to QGIS Main Window.

        Raises:
            ImportDialogError - when buildings.shp not exist
        """

        myDir = str(self.outDir.text())
        myPath = os.path.join(myDir, 'buildings.shp')

        if not os.path.exists(myPath):
            myMessage = self.tr(
                "%s don't exist. The server don't have buildings data.")
            raise ImportDialogError(myMessage)

        self.iface.addVectorLayer(myPath, 'buildings', 'ogr')
Example #22
0
class LodgementWizard(QWizard, Ui_ldg_wzd, MapperMixin):
    """
    Wizard that incorporates lodgement of all information required for a Land
    Hold Title Scheme
    """
    def __init__(self, parent=None):
        QWizard.__init__(self, parent)

        self.setupUi(self)
        # Equate number of pages in wizard to page IDs
        self._num_pages = len(self.pageIds())
        self._base_win_title = self.windowTitle()

        # Current profile
        self.curr_p = current_profile()

        # Flag for checking if document type has been loaded
        self._supporting_docs_loaded = False

        # Entity names
        self._sch_entity_name = 'Scheme'
        self._rel_auth_entity_name = 'Relevant_authority'
        self._rel_auth_chk_entity_name = 'check_lht_relevant_authority'
        self._rgn_chk_entity_name = 'check_lht_region'
        self._reg_div_chk_entity_name = 'check_lht_reg_division'
        self._scheme_doc_type_lookup = 'cb_check_scheme_document_type'
        self._holders_entity_name = 'Holder'
        self._workflow_chk_entity_name = 'check_lht_workflow'
        self._approval_chk_entity_name = 'check_lht_approval_status'
        self._sch_workflow_entity_name = 'Scheme_workflow'

        # Check if the current profile exists
        if self.curr_p is None:
            QMessageBox.critical(self, self.tr('Missing Profile'),
                                 self.tr("No profile has been specified"))
            self.reject()

        # Scheme entity
        self.sch_entity = self.curr_p.entity(self._sch_entity_name)

        # Entity models
        self.schm_model, self._scheme_doc_model = entity_model(
            self.sch_entity, with_supporting_document=True)

        # Check if scheme entity models exist
        if self.schm_model is None:
            QMessageBox.critical(
                self, self.tr('Scheme Entity Model'),
                self.tr("The scheme entity model could not be generated."))
            self.reject()

        # Entity objects
        self._relv_auth_entity = None
        self._relevant_auth_lookup = None
        self._region_lookup = None
        self._reg_div_lookup = None
        self._holder_entity = None
        self._workflow_lookup = None
        self._approval_lookup = None
        self._sch_workflow_entity = None

        # Entity models
        self._relevant_auth_type_model = None
        self._region_lookup_model = None
        self._relevant_auth_model = None
        self._regdiv_lookup_model = None
        self._workflow_lookup_model = None
        self._approval_lookup_model = None
        self._sch_workflow_model = None

        # Initialize Mappermixin for saving attribute data
        MapperMixin.__init__(self, self.schm_model, self.sch_entity)

        # Configure notification bars
        self.notif_bar = NotificationBar(self.vlNotification)
        self.docs_notif_bar = NotificationBar(self.vlNotification_docs)
        self.holders_notif_bar = NotificationBar(self.vlNotification_holders)

        # CMIS stuff for document management
        self._cmis_mgr = CmisManager()

        # Mapper will be set in 1st page initialization
        self._cmis_doc_mapper = None

        # Last int value used for generating the scheme number
        self._abs_last_scheme_value = None

        # Validator for holders data
        self._holders_validator = None

        # Progress dialog for showing validation status
        self._h_validation_prog_dlg = QProgressDialog(self)

        # Database importer
        self._holder_importer = None

        # Connect signals
        self.btn_brws_hld.clicked.connect(self.browse_holders_file)
        self.btn_upload_dir.clicked.connect(self.on_upload_multiple_files)
        self.currentIdChanged.connect(self.on_page_changed)
        self.cbx_region.currentIndexChanged.connect(
            self.update_relevant_authority)
        self.cbx_relv_auth.currentIndexChanged.connect(
            self.update_relevant_authority)
        self.cbx_relv_auth_name.currentIndexChanged.connect(
            self.on_ra_name_changed)
        self.btn_reload_holders.clicked.connect(self.load_holders_file)
        self.chk_holders_validate.toggled.connect(self.on_validate_holders)
        self.tr_summary.link_clicked.connect(self._on_summary_link_clicked)

        # Block area
        self.radio_sq_meters.setChecked(True)
        self.dbl_spinbx_block_area.setSuffix(" Sq.m")
        self.dbl_spinbx_block_area.setDecimals(0)
        self.radio_hectares.toggled.connect(self._on_hectares_clicked)

        self.radio_sq_meters.toggled.connect(self._on_sq_meters_clicked)

        # Populate lookup combo boxes
        self._populate_lookups()

        # Current date
        self._current_date = QDate.currentDate().getDate()
        self._current_year = self._current_date[0]

        # Set date limits
        self._configure_date_controls()

        # Specify MapperMixin widgets
        self.register_col_widgets()

    def _populate_combo(self, cbo, lookup_name):
        """
        Populates comboboxes with items from the database.
        :param cbo: Combobox object
        :param lookup_name: name of the lookup table.
        """
        res = export_data(lookup_name)
        cbo.clear()
        cbo.addItem('')

        for r in res:
            cbo.addItem(r.value, r.id)

    def _populate_lookups(self):
        """
        Populate combobox dropdowns with values to be displayed when user
        clicks the dropdown.
        """
        # Check if the tables exists
        self._populate_combo(self.cbx_region, 'cb_check_lht_region')
        self._populate_combo(self.cbx_relv_auth,
                             'cb_check_lht_relevant_authority')
        self._populate_combo(self.cbx_lro, 'cb_check_lht_land_rights_office')
        self.cbx_region.model().sort(0)

    def _configure_date_controls(self):
        """
        Set the configuration of the date widget controls.
        """
        self.date_apprv.setMaximumDate(QDate.currentDate())
        self.date_establish.setMaximumDate(QDate.currentDate())
        self.date_establish.setDate(QDate.currentDate())
        self.date_apprv.setDate((QDate.currentDate()))

    def _update_entities_and_models(self):
        """
        Update the entity objects and database models for the relevant authority.
        """
        if not self._relv_auth_entity:
            self._relv_auth_entity = self.curr_p.entity(
                self._rel_auth_entity_name)
        if not self._relevant_auth_lookup:
            self._relevant_auth_lookup = self.curr_p.entity(
                self._rel_auth_chk_entity_name)
        if not self._region_lookup:
            self._region_lookup = self.curr_p.entity(self._rgn_chk_entity_name)
        if not self._reg_div_lookup:
            self._reg_div_lookup = self.curr_p.entity(
                self._reg_div_chk_entity_name)

        # Check if entities exist
        if self._relv_auth_entity is None:
            QMessageBox.critical(
                self, self.tr('Missing Relevant Authority Entity'),
                self.tr("The relevant authority entity is missing in the "
                        "profile."))
            self.reject()
        elif self._relevant_auth_lookup is None:
            QMessageBox.critical(
                self, self.tr('Missing Relevant Authority Entity Lookup'),
                self.tr(
                    "The relevant authority entity lookup is missing in the "
                    "profile."))
            self.reject()
        elif self._region_lookup is None:
            QMessageBox.critical(
                self, self.tr('Missing Relevant Authority Entity Lookup'),
                self.tr(
                    "The relevant authority entity lookup is missing in the "
                    "profile."))
            self.reject()
        elif self._reg_div_lookup is None:
            QMessageBox.critical(
                self, self.tr('Missing Relevant Authority Entity Lookup'),
                self.tr(
                    "The relevant authority entity lookup is missing in the "
                    "profile."))
            self.reject()

        # Entity models
        if not self._relevant_auth_type_model:
            self._relevant_auth_type_model = entity_model(
                self._relevant_auth_lookup)
        if not self._region_lookup_model:
            self._region_lookup_model = entity_model(self._region_lookup)
        if not self._relevant_auth_model:
            self._relevant_auth_model = entity_model(self._relv_auth_entity)
        if not self._regdiv_lookup_model:
            self._regdiv_lookup_model = entity_model(self._reg_div_lookup)

    def update_relevant_authority(self):
        """
        Slot for updating the Relevant Authority combobox based on the
        selections in related combo boxes.
        """
        self._update_entities_and_models()
        # Entity object
        relv_entity_obj = self._relevant_auth_model()
        # Get the region ID
        region_id = self.cbx_region.itemData(self.cbx_region.currentIndex())
        # Get the relevant authority ID
        ra_id_type = self.cbx_relv_auth.itemData(
            self.cbx_relv_auth.currentIndex())
        # Check if region combobox is selected
        if not region_id and not ra_id_type:
            return

        self.cbx_relv_auth_name.clear()
        self.cbx_reg_div.clear()
        self.lnedit_sg_num.clear()
        self.cbx_relv_auth_name.addItem('')
        self.cbx_reg_div.addItem('')
        # Query object for filtering items on name of relevant authority
        res = relv_entity_obj.queryObject().filter(
            self._relevant_auth_model.region == region_id,
            self._relevant_auth_model.type_of_relevant_authority ==
            ra_id_type).all()

        # Looping through the results to get details
        for r in res:
            authority_name = r.name_of_relevant_authority
            authority_id = r.id
            code = r.au_code
            last_val = r.last_val
            reg_divs = []
            for i in r.cb_check_lht_reg_division_collection:
                reg_divs.append((i.id, i.value))
            # Add items to combobox
            # Data will contain tuple(ID, code and registration division)
            self.cbx_relv_auth_name.addItem(
                authority_name, (authority_id, code, last_val, reg_divs))

    def on_ra_name_changed(self):
        """
        Slot for updating the scheme number based on selection of name of
        relevant authority combobox.
        """
        self.lnedit_schm_num.clear()
        self.lnedit_landhold_num.clear()
        self.cbx_reg_div.clear()
        if not self.cbx_relv_auth_name.currentText():
            return

        authority_id, code, last_value, reg_divs = self.cbx_relv_auth_name.itemData(
            self.cbx_relv_auth_name.currentIndex())
        self.cbx_reg_div.addItem('')
        for regdiv in reg_divs:
            self.cbx_reg_div.addItem(regdiv[1], regdiv[0])
        # Select the first item automatically if there is only one division
        if self.cbx_reg_div.count() == 2:
            self.cbx_reg_div.setCurrentIndex(1)
        scheme_code = self._gen_scheme_number(code, last_value)
        self.lnedit_schm_num.setText(scheme_code)

    def _gen_scheme_number(self, code, last_value):
        """
        Generate the scheme number.
        """
        if not last_value:
            last_value = 0
        last_value += 1
        self._abs_last_scheme_value = last_value
        scheme_code = u'{0}. {1} / {2}'.format(code,
                                               str(last_value).zfill(4),
                                               self._current_year)

        return scheme_code

    def _on_hectares_clicked(self):
        """
        Slot raised when the hectares radio button is selected.
        """
        self.dbl_spinbx_block_area.setDecimals(4)
        self.dbl_spinbx_block_area.setSuffix(" Ha")
        initial_value = self.dbl_spinbx_block_area.value()
        value = initial_value / 10000
        self.dbl_spinbx_block_area.setValue(value)

    def _on_sq_meters_clicked(self):
        """
        Slot raised when the area radio button is clicked.
        """
        self.dbl_spinbx_block_area.setDecimals(0)
        self.dbl_spinbx_block_area.setSuffix(" Sq.m")
        initial_value = self.dbl_spinbx_block_area.value()
        value = initial_value * 10000
        self.dbl_spinbx_block_area.setValue(value)

    def validate_block_area(self):
        """
        Validate the block area value input.
        """
        min_value = self.dbl_spinbx_block_area.minimum()

        if self.dbl_spinbx_block_area.value() == min_value:
            self.notif_bar.insertWarningNotification(
                self.tr("Block Area value cannot be zero."))
        else:
            return True

    def on_page_changed(self, idx):
        """
        Slot raised when the page with the given id is loaded.
        """
        page_num = idx + 1
        win_title = u'{0} - Step {1} of {2}'.format(self._base_win_title,
                                                    str(page_num),
                                                    str(self._num_pages))
        self.setWindowTitle(win_title)
        # First page
        # Set entity document mapper if connection to CMIS is successful
        if idx == 0:
            self._init_cmis_doc_mapper()
        # Load scheme supporting documents
        elif idx == 1:
            self._load_scheme_document_types()
            # Disable widget if doc mapper could not be initialized
            if not self._cmis_doc_mapper:
                self.tbw_documents.setEnabled(False)
        # Initialize holders information
        elif idx == 2:
            self._init_holder_helpers()
        # Last page
        elif idx == 3:
            # Populate summary widget
            self.populate_summary()

    def _init_holder_helpers(self):
        """
        Initialize helper classes for holder's data.
        """
        if not self._holder_entity:
            self._holder_entity = self.curr_p.entity(self._holders_entity_name)
            if not self._holder_entity:
                msg = self.tr(
                    'Could not find the Holders entity.\nPlease check to '
                    'confirm that it has been created in the configuration')
                QMessageBox.critical(self, self.tr('Missing Holders Entity'),
                                     msg)

                return

    def _init_cmis_doc_mapper(self):
        """
        Initialize CMIS class methods.
        """
        conn_status = self._cmis_mgr.connect()
        if not conn_status:
            msg = self.tr(
                'Failed to connect to the CMIS Service.\nPlease check the '
                'URL and login credentials for the CMIS service.')
            QMessageBox.critical(self, self.tr('CMIS Server Error'), msg)
        if conn_status:
            if not self._cmis_doc_mapper:
                try:
                    self._cmis_doc_mapper = CmisEntityDocumentMapper(
                        cmis_manager=self._cmis_mgr,
                        doc_model_cls=self._scheme_doc_model,
                        entity_name=self._sch_entity_name)

                    # Set the CMIS document mapper in document widget
                    self.tbw_documents.cmis_entity_doc_mapper = \
                        self._cmis_doc_mapper
                except CmisDocumentMapperException as cm_ex:
                    QMessageBox.critical(self, self.tr('CMIS Server Error'),
                                         str(cm_ex))
                except CmisException as c_ex:
                    QMessageBox.critical(self, self.tr('CMIS Server Error'),
                                         c_ex.status)

    def browse_holders_file(self):
        """
        Browse the holders file in the file directory.
        """
        last_doc_path = last_document_path()
        if not last_doc_path:
            last_doc_path = '~/'

        holders_file = QFileDialog.getOpenFileName(
            self, 'Browse Holders File', last_doc_path,
            'Excel File (*.xls *xlsx);;CSV (Comma Delimited) (*.csv)')

        if holders_file:
            set_last_document_path(holders_file)
            self.lnEdit_hld_path.setText(holders_file)
            self.load_holders_file()

    def load_holders_file(self):
        """
        Load the holders data into the table view based on the file specified
        in the path textbox.
        """
        h_path = self.lnEdit_hld_path.text()
        if not h_path:
            QMessageBox.warning(
                self, self.tr('Empty File Path'),
                self.tr('Please specify the path to the Holders file.'))

            return

        self.tw_hld_prv.load_holders_file(h_path)

        curr_sheet = self.tw_hld_prv.current_sheet_view()

        # Clear validation result label
        self.lbl_validation_description.clear()

        # Check if a signal has been defined in the sheet view and disconnect
        # Use old-style signal to check if signal is connected
        receivers = curr_sheet.receivers(SIGNAL('itemSelectionChanged()'))
        # Disconnect all slots for the itemSelectionChanged signal
        if receivers > 0:
            curr_sheet.itemSelectionChanged.disconnect()

        # Reconnect signal
        curr_sheet.itemSelectionChanged.connect(
            self._on_holders_table_selection_changed)

        # Create validator object
        ds = self.tw_hld_prv.current_sheet_view().vector_layer
        self._holders_validator = EntityVectorLayerValidator(
            self._holder_entity, ds, parent=self)

        # Connect signals
        self._holders_validator.featureValidated.connect(
            self._on_holder_feat_validated)
        self._holders_validator.validationFinished.connect(
            self._on_holder_validation_complete)

        # Create holder importer
        self._holder_importer = HolderPlotNumberDbImporter(
            ds, unique_cols=['holder_identifier'], parent=self)

        # Perform validation immediately after loading the data
        if self.chk_holders_validate.isChecked():
            self._validate_holders()

    def on_validate_holders(self, toggled):
        """
        Slot raised when the checkbox for validating holders data is
        checked/unchecked.
        :param toggled: Toggle status
        :type toggled: bool
        """
        if not toggled:
            msg = 'Validation of the holders data will be performed prior to ' \
                  'loading the summary page upon clicking Next.'
            self.holders_notif_bar.insertInformationNotification(msg)

    def _validate_holders(self):
        """
        Reset and validate loaded holders information.
        """
        self._holders_validator.reset()

        try:
            # Performs some pre-validation checks.
            # Check if mandatory columns have been mapped
            passed_mandatory, cols = self._holders_validator.validate_mandatory(
            )
            if not passed_mandatory:
                cols_str = '\n'.join(cols)
                msg = self.tr('The following mandatory columns have not been '
                              'mapped: {0}'.format(cols_str))
                QMessageBox.critical(self,
                                     self.tr('Missing Mandatory Columns'), msg)

                return

            # Check if at least one data source column has been mapped
            ds_mapped = self._holders_validator.validate_mapped_ds_columns()
            if not ds_mapped:
                msg = 'At least one column in the data source has to be ' \
                      'mapped.'
                QMessageBox.critical(self,
                                     self.tr('Mapped Data Source Columns'),
                                     msg)

                return

            # Check if at least one entity column has been mapped
            entity_mapped = self._holders_validator.validate_entity_columns()
            if not entity_mapped:
                msg = 'At least one entity column has to be mapped.'
                QMessageBox.critical(self, self.tr('Mapped Entity Columns'),
                                     msg)

                return

            # Set progress dialog properties
            self._h_validation_prog_dlg.setMinimum(0)
            self._h_validation_prog_dlg.setMaximum(
                self._holders_validator.count)
            self._h_validation_prog_dlg.setWindowModality(Qt.WindowModal)
            self._h_validation_prog_dlg.setLabelText(
                self.tr('Validating holders records in the data source...'))
            self._h_validation_prog_dlg.setWindowTitle(
                self.tr('Validation Progress'))
            # Connect canceled signal
            self._h_validation_prog_dlg.canceled.connect(
                self._on_validation_canceled)
            self._h_validation_prog_dlg.setValue(0)

            # Start the validation process
            self._holders_validator.start()

        except ValidatorException as ve:
            QMessageBox.critical(self, self.tr('Holders Validation Error'),
                                 unicode(ve))

    def _on_holder_feat_validated(self, results):
        """
        Slot raised when a feature in the data source has been validated.
        """
        for r in results:
            if len(r.warnings) > 0 or len(r.errors) > 0:
                self.tw_hld_prv.current_sheet_view(). \
                    highlight_validation_cell(r)
        # Update progress bar
        curr_val = self._h_validation_prog_dlg.value()
        curr_val += 1
        self._h_validation_prog_dlg.setValue(curr_val)

    def _on_holder_validation_complete(self):
        """
        Slot raised when holder validation is complete.
        """
        num_features = self._holders_validator.count
        num_err_features = len(
            self._holders_validator.row_warnings_errors.keys())
        # Get features that have warnings or errors
        msg = self.tr(
            u'Validation process complete.\nOut of the {0} features in the '
            u'data source, {1} have warnings and/or errors.\nPlease click '
            u'on a cell with an error icon in the preview table to get more '
            u'details.'.format(str(num_features), str(num_err_features)))
        QMessageBox.information(self, self.tr('Validation Summary'), msg)

    def _on_validation_canceled(self):
        """"
        Slot raised when the validation process has been cancelled by the
        user.
        """
        if self._holders_validator:
            self._holders_validator.cancel()

    def _on_holders_table_selection_changed(self):
        """
        Slot raised when selection changes in the holders table widget.
        """
        self.lbl_validation_description.setText('')
        # Check if validator has been initialized
        if not self._holders_validator:
            return

        curr_sheet = self.tw_hld_prv.current_sheet_view()
        sel_items = curr_sheet.selectedItems()
        if len(sel_items) == 0:
            return

        sel_item = sel_items[0]
        if self._holders_validator.status == \
                EntityVectorLayerValidator.NOT_STARTED:
            self.lbl_validation_description.setText(self.tr('Not validated'))
        elif self._holders_validator.status == \
                EntityVectorLayerValidator.NOT_COMPLETED:
            self.lbl_validation_description.setText(
                self.tr('UNKNOWN: Validation process not complete'))
        elif self._holders_validator.status == \
                EntityVectorLayerValidator.FINISHED:
            # Get data stored in the user role
            val_results = sel_item.data(Qt.UserRole)
            if not val_results:
                self.lbl_validation_description.setText(self.tr('SUCCESSFUL'))
            else:
                combined_msgs = val_results.errors + val_results.warnings
                str_msgs = [str(vr) for vr in combined_msgs]
                self.lbl_validation_description.setText('\n- '.join(str_msgs))

    def _load_scheme_document_types(self):
        """
        Handles Uploading and viewing of the scheme supporting documents.
        """
        doc_type_entity = self.curr_p.entity_by_name(
            self._scheme_doc_type_lookup)
        if doc_type_entity is None:
            QMessageBox.critical(
                self, self.tr('Scheme Document Type Lookup'),
                self.tr('The lookup table containing the document types is '
                        'missing.'))
            self.tbw_documents.setEnabled(False)

            return

        # No need of fetching the documents again if already done before
        if self._supporting_docs_loaded:
            return

        # Check Doc mapper
        if not self._cmis_doc_mapper:
            QMessageBox.critical(
                self, self.tr('CMIS Server Error'),
                self.tr(
                    'Document mapper could not be initialized, please check '
                    'the connection to the CMIS server.'))
            self.tbw_documents.setEnabled(False)
            self.btn_upload_dir.setEnabled(False)

            return

        doc_res = export_data(self._scheme_doc_type_lookup)
        # Add the documents types to the view
        for d in doc_res:
            doc_type = d.value
            code = d.code
            type_id = d.id
            self.tbw_documents.add_document_type(doc_type)
            # Also add the types to the CMIS doc mapper
            self._cmis_doc_mapper.add_document_type(doc_type, code, type_id)

        self._supporting_docs_loaded = True

    def on_upload_multiple_files(self):
        """
        Browse and select multiple supporting documents.
        """
        last_doc_path = last_document_path()
        if not last_doc_path:
            last_doc_path = '~/'

        docs_dir = QFileDialog.getExistingDirectory(
            self, 'Browse Supporting Documents Source Directory',
            last_doc_path)
        if not docs_dir:
            return

        # Check if there are files in the selected directory
        dir = QDir(docs_dir)
        els = dir.entryList(QDir.NoDot | QDir.NoDotDot | QDir.Files)
        if len(els) == 0:
            QMessageBox.warning(
                self, 'Supporting Documents',
                self.tr('There are no files in the selected directory.'))
            return

        doc_types = self.tbw_documents.document_types()
        dir_doc_dlg = DirDocumentTypeSelector(docs_dir, doc_types, self)
        res = dir_doc_dlg.exec_()
        if res == QDialog.Accepted:
            # Get document types selected by the user
            selected_doc_types = dir_doc_dlg.selected_document_types
            self.tbw_documents.upload_document(selected_doc_types)

    def register_col_widgets(self):
        """
        Registers the column widgets to the table columns
        """
        # Get the table columns and add mapping
        self.addMapping('region', self.cbx_region, pseudoname='Region')
        self.addMapping('relevant_authority',
                        self.cbx_relv_auth,
                        pseudoname='Relevant Authority Type')
        self.addMapping('relevant_authority_name',
                        self.cbx_relv_auth_name,
                        pseudoname='Relevant Authority Name')
        self.addMapping('registration_division',
                        self.cbx_reg_div,
                        pseudoname='Registration Division')
        self.addMapping('scheme_number',
                        self.lnedit_schm_num,
                        pseudoname='Scheme Number')
        self.addMapping('land_hold_plan_number',
                        self.lnedit_landhold_num,
                        pseudoname='Land Hold Plan Number')
        self.addMapping('sg_number',
                        self.lnedit_sg_num,
                        pseudoname='Surveyor General Number')
        self.addMapping('scheme_name',
                        self.lnedit_schm_nam,
                        pseudoname='Scheme Name')
        self.addMapping('date_of_approval',
                        self.date_apprv,
                        pseudoname='Approval Date')
        self.addMapping('date_of_establishment',
                        self.date_establish,
                        pseudoname='Establishment Date')
        self.addMapping('land_rights_office',
                        self.cbx_lro,
                        pseudoname='Land Rights Office')
        self.addMapping('area', self.dbl_spinbx_block_area, pseudoname='Area')
        self.addMapping('no_of_plots',
                        self.dbl_spinbx_num_plots,
                        pseudoname='Number of Plots')
        self.addMapping('title_deed_number',
                        self.lnedit_title_deed_num,
                        pseudoname='Title Deed Number')
        self.addMapping('constitution_ref_number',
                        self.lnedit_constitution_ref_num,
                        pseudoname='Constitution Reference Number')
        self.addMapping('scheme_description',
                        self.lnedit_scheme_description,
                        pseudoname='Scheme Description')

    def validate_num_plots(self):
        """
        Check whether the number of plots is zero
        """
        # Preset minimum value equals to zero
        min_value_plots = self.dbl_spinbx_num_plots.minimum()

        if self.dbl_spinbx_num_plots.value() == min_value_plots:
            self.notif_bar.insertWarningNotification(
                self.tr("Number of Plots cannot be zero."))
        else:
            return True

    def validateCurrentPage(self):
        """
        Validate each wizard page.
        """
        current_id = self.currentId()
        ret_status = False
        self.notif_bar.clear()

        if current_id == 0:
            # Check if values have been specified for the attribute widgets
            errors = self.validate_all()
            if self.validate_block_area() and len(errors) == 0:
                if self.validate_num_plots():
                    ret_status = True

        # Holders page
        elif current_id == 2:
            if not self.lnEdit_hld_path.text():
                self.holders_notif_bar.clear()
                self.holders_notif_bar.insertWarningNotification(
                    self.tr('Please upload the file containing the Holders '
                            'information.'))
            else:
                status = self._holders_validator.status
                if status == EntityVectorLayerValidator.NOT_STARTED:
                    msg = self.tr(
                        'The holders data has not yet been validated.')
                elif status == EntityVectorLayerValidator.NOT_COMPLETED:
                    msg = self.tr('The validation process was interrupted.')
                elif status == EntityVectorLayerValidator.FINISHED:
                    # Check if there were errors (exclude warnings)
                    num_err_features = len(
                        self._holders_validator.row_errors.keys())
                    if num_err_features > 0:
                        msg = self.tr(
                            'There were errors in the last validation '
                            'process.')
                    else:
                        ret_status = True

                if not ret_status and msg:
                    # Give user the option to (re)run the validation process.
                    action_msg = self.tr(
                        'Do you want to (re)run the validation process?')
                    res = QMessageBox.warning(
                        self, self.tr('Validation Status'),
                        u'{0}\n{1}'.format(msg, action_msg),
                        QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

                    # Run the validation if the user selects Yes
                    if res == QMessageBox.Yes:
                        self._validate_holders()

        # Documents page
        elif current_id == 1:
            ret_status = self._is_documents_page_valid()
            if not ret_status:
                self.docs_notif_bar.clear()
                msg = self.tr('Please upload all the supporting documents. ')
                self.docs_notif_bar.insertWarningNotification(msg)

            # Check if there is an active document upload/removal operation
            active_operation = self.tbw_documents.has_active_operation
            if active_operation:
                ret_status = False
                msg = self.tr(
                    'There is an ongoing operation with the CMIS server. '
                    'Please wait a few moments.')
                self.docs_notif_bar.insertWarningNotification(msg)

        elif current_id == 3:
            # This is the last page
            try:
                self.save_scheme()
                self.populate_workflow()
                ret_status = True

            except Exception as err:
                QMessageBox.critical(self, self.tr('Error in Saving Scheme'),
                                     unicode(err))

        return ret_status

    def _is_documents_page_valid(self):
        # Checks if the documents have been uploaded
        uploaded_docs = self.tbw_documents.uploaded_documents.values()

        return len(uploaded_docs) == self.tbw_documents.rowCount()

    def populate_summary(self):
        """
        Populating the scheme summary widget with values from the user input
        """
        self.tr_summary.scm_num.setText(1, self.lnedit_schm_num.text())
        self.tr_summary.scm_desc.setText(1,
                                         self.lnedit_scheme_description.text())
        self.tr_summary.scm_name.setText(1, self.lnedit_schm_nam.text())
        self.tr_summary.scm_title_deed_num.setText(
            1, self.lnedit_title_deed_num.text())
        self.tr_summary.scm_date_apprv.setText(1, self.date_apprv.text())
        self.tr_summary.scm_date_est.setText(1, self.date_establish.text())
        self.tr_summary.scm_region.setText(1, self.cbx_region.currentText())
        self.tr_summary.scm_ra_type.setText(1,
                                            self.cbx_relv_auth.currentText())
        self.tr_summary.scm_ra_name.setText(
            1, self.cbx_relv_auth_name.currentText())
        self.tr_summary.scm_land_hold_num.setText(
            1, self.lnedit_landhold_num.text())
        self.tr_summary.scm_sg_num.setText(1, self.lnedit_sg_num.text())
        self.tr_summary.scm_lro.setText(1, self.cbx_lro.currentText())
        self.tr_summary.scm_reg_div.setText(1, self.cbx_reg_div.currentText())
        self.tr_summary.scm_numplots.setText(1,
                                             self.dbl_spinbx_num_plots.text())
        self.tr_summary.scm_blk_area.setText(1,
                                             self.dbl_spinbx_block_area.text())

    def _on_summary_link_clicked(self, code):
        """
        Slot raised when the hyperlink in summary widget is clicked
        :param code: Code identifier of the wizard page.
        :type code: str
        """
        ref_id = -1
        if code == 'DOC':
            ref_id = 1
        elif code == 'HLD':
            ref_id = 2

        if ref_id == -1:
            return

        while self.currentId() != ref_id:
            self.back()

    def _save_ra_last_value(self, scheme_number):
        """
        Save the most recent value for the relevant authority.
        """
        if not self._abs_last_scheme_value:
            return

        num_parts = scheme_number.split('.')
        if len(num_parts) > 0:
            code = num_parts[0]
            rel_auth_obj = self._relevant_auth_model()
            res = rel_auth_obj.queryObject().filter(
                self._relevant_auth_model.au_code == code).first()
            if res:
                # Update last value
                res.last_val = self._abs_last_scheme_value
                res.update()

    def save_scheme(self):
        """
        Save scheme information, move supporting documents, save holders
        table and create appropriate notifications.
        """
        sch_number = None
        pg_dlg = QProgressDialog(parent=self)
        pg_dlg.setWindowModality(Qt.WindowModal)
        pg_dlg.setMinimum(0)
        pg_dlg.setMaximum(4)
        pg_dlg.setCancelButton(None)
        pg_dlg.setWindowTitle(self.tr('Saving Scheme Information...'))

        pg_dlg.setLabelText(self.tr('Retrieving scheme attribute data...'))
        pg_dlg.setValue(1)
        # Get scheme db object for manual saving to database.
        self.submit(True)
        scheme_obj = self.model()
        scheme_obj.plot_status = 2
        QgsApplication.processEvents()

        pg_dlg.setLabelText(
            self.tr('Saving supporting documents, please wait...'))
        pg_dlg.setValue(2)

        # Format scheme number for saving in document repository
        if not sch_number:
            sch_number = scheme_obj.scheme_number.replace(" / ", "_")
            sch_number = sch_number.replace(" ", "_")

        # Attach documents
        doc_objs = self._cmis_doc_mapper.persist_documents(sch_number)
        scheme_obj.documents = doc_objs
        QgsApplication.processEvents()

        pg_dlg.setLabelText(self.tr('Saving scheme data...'))
        pg_dlg.setValue(3)
        scheme_obj.save()

        # Update last value for generating scheme number
        self._save_ra_last_value(scheme_obj.scheme_number)
        QgsApplication.processEvents()

        pg_dlg.setLabelText(self.tr('Saving holders data...'))
        pg_dlg.setValue(4)
        QgsApplication.processEvents()
        # Attach the scheme object to the holders
        self._holder_importer.set_extra_attribute_value(
            'cb_scheme_collection', [scheme_obj])
        # Save holders data
        self._holder_importer.start()
        QgsApplication.processEvents()

        msg = self.tr(
            u'A new scheme (No. {0}) has been successfully lodged.'.format(
                scheme_obj.scheme_number))
        QMessageBox.information(self, self.tr('New Scheme'), msg)

    def populate_workflow(self):
        """
        Update the workflow table once lodgement has been done
        """
        # Entities
        self._workflow_lookup = self.curr_p.entity(
            self._workflow_chk_entity_name)
        self._approval_lookup = self.curr_p.entity(
            self._approval_chk_entity_name)
        self._sch_workflow_entity = self.curr_p.entity(
            self._sch_workflow_entity_name)

        # Check if entity exists
        if self._workflow_lookup is None:
            QMessageBox.critical(
                self, self.tr('Missing workflow Entity'),
                self.tr("The workflow entity is missing in the "
                        "profile."))

        if self._approval_lookup is None:
            QMessageBox.critical(
                self, self.tr('Missing approval Entity'),
                self.tr("The approval entity is missing in the "
                        "profile."))

        if self._sch_workflow_entity is None:
            QMessageBox.critical(
                self, self.tr('Missing scheme workflow Entity'),
                self.tr("The scheme workflow entity is missing in the "
                        "profile."))

        # Models
        self._workflow_lookup_model = entity_model(self._workflow_lookup)
        self._approval_lookup_model = entity_model(self._approval_lookup)
        self._sch_workflow_model = entity_model(self._sch_workflow_entity)

        # Check if model exists
        if self._workflow_lookup_model is None:
            QMessageBox.critical(
                self, self.tr('Workflow Entity Model'),
                self.tr("The workflow entity model could not be generated."))

        if self._approval_lookup_model is None:
            QMessageBox.critical(
                self, self.tr('Workflow Entity Model'),
                self.tr("The approval entity model could not be generated."))

        if self._sch_workflow_model is None:
            QMessageBox.critical(
                self, self.tr('Scheme Workflow Entity Model'),
                self.tr("The scheme workflow entity model could not be "
                        "generated."))

        # Entity objects
        scheme_obj = self.schm_model()
        chk_workflow_obj = self._workflow_lookup_model()
        chk_approval_obj = self._approval_lookup_model()
        scheme_workflow_obj = self._sch_workflow_model()

        # Get last lodged scheme ID
        scheme_res = scheme_obj.queryObject().order_by(
            self.schm_model.id.desc()).first()

        # Filter the lookup IDs based on values
        workflow_res = chk_workflow_obj.queryObject().filter(
            self._workflow_lookup_model.value == 'Lodgement').one()

        approval_lodge_res = chk_approval_obj.queryObject().filter(
            self._approval_lookup_model.value == 'Approved').one()

        # Save details
        scheme_workflow_obj.scheme_id = scheme_res.id
        scheme_workflow_obj.workflow_id = workflow_res.id
        scheme_workflow_obj.approval_id = approval_lodge_res.id
        scheme_workflow_obj.save()

        self.populate_establishment_workflow()
        self.populate_plot_workflow()

    def populate_establishment_workflow(self):
        """
        Update the workflow link table with establishment as unapproved.
        :return:
        """
        # Entity objects
        scheme_obj = self.schm_model()
        chk_workflow_obj = self._workflow_lookup_model()
        chk_approval_obj = self._approval_lookup_model()
        scheme_workflow_obj = self._sch_workflow_model()
        # Get last lodged scheme ID

        scheme_res = scheme_obj.queryObject().order_by(
            self.schm_model.id.desc()).first()

        # Filter the lookup IDs based on values
        workflow_res = chk_workflow_obj.queryObject().filter(
            self._workflow_lookup_model.value == 'Establishment').one()

        approval_res = chk_approval_obj.queryObject().filter(
            self._approval_lookup_model.value == 'Pending').one()

        # Save details
        scheme_workflow_obj.scheme_id = scheme_res.id
        scheme_workflow_obj.workflow_id = workflow_res.id
        scheme_workflow_obj.approval_id = approval_res.id
        scheme_workflow_obj.save()

    def populate_plot_workflow(self):
        """
        Update the workflow link table with import plot as unapproved.
        :return: None
        """
        # Entity objects
        scheme_obj = self.schm_model()
        chk_workflow_obj = self._workflow_lookup_model()
        chk_approval_obj = self._approval_lookup_model()
        scheme_workflow_obj = self._sch_workflow_model()
        # Get last lodged scheme ID

        scheme_res = scheme_obj.queryObject().order_by(
            self.schm_model.id.desc()).first()

        # Filter the lookup IDs based on values
        workflow_res = chk_workflow_obj.queryObject().filter(
            self._workflow_lookup_model.value == 'Import Plot').one()

        approval_res = chk_approval_obj.queryObject().filter(
            self._approval_lookup_model.value == 'Pending').one()

        # Save details
        scheme_workflow_obj.scheme_id = scheme_res.id
        scheme_workflow_obj.workflow_id = workflow_res.id
        scheme_workflow_obj.approval_id = approval_res.id
        scheme_workflow_obj.save()

    def populate_third_workflow(self):
        """
        Update the workflow link table with import plot as unapproved.
        """
        # Entity objects
        scheme_obj = self.schm_model()
        chk_workflow_obj = self._workflow_lookup_model()
        chk_approval_obj = self._approval_lookup_model()
        scheme_workflow_obj = self._sch_workflow_model()
        # Get last lodged scheme ID

        scheme_res = scheme_obj.queryObject().order_by(
            self.schm_model.id.desc()).first()

        # Filter the lookup IDs based on values
        workflow_res = chk_workflow_obj.queryObject().filter(
            self._workflow_lookup_model.value == 'Third Assessment').one()

        approval_res = chk_approval_obj.queryObject().filter(
            self._approval_lookup_model.value == 'Pending').one()

        # Save details
        scheme_workflow_obj.scheme_id = scheme_res.id
        scheme_workflow_obj.workflow_id = workflow_res.id
        scheme_workflow_obj.approval_id = approval_res.id
        scheme_workflow_obj.save()
Example #23
0
class AddonManagerDialog(QDialog):
    _packages = None

    def __init__(self, parent=None, **kwargs):
        super().__init__(parent, acceptDrops=True, **kwargs)
        self.setLayout(QVBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.addonwidget = AddonManagerWidget()
        self.layout().addWidget(self.addonwidget)

        info_bar = QWidget()
        info_layout = QHBoxLayout()
        info_bar.setLayout(info_layout)
        self.layout().addWidget(info_bar)

        buttons = QDialogButtonBox(
            orientation=Qt.Horizontal,
            standardButtons=QDialogButtonBox.Ok | QDialogButtonBox.Cancel
        )
        buttons.accepted.connect(self.__accepted)
        buttons.rejected.connect(self.reject)

        self.layout().addWidget(buttons)

        # No system access => install into user site-packages
        self.user_install = not os.access(sysconfig.get_path("purelib"),
                                          os.W_OK)

        self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
        if AddonManagerDialog._packages is None:
            self._f_pypi_addons = self._executor.submit(list_pypi_addons)
        else:
            self._f_pypi_addons = concurrent.futures.Future()
            self._f_pypi_addons.set_result(AddonManagerDialog._packages)

        self._f_pypi_addons.add_done_callback(
            method_queued(self._set_packages, (object,))
        )

        self.__progress = QProgressDialog(
            self, Qt.Sheet,
            minimum=0, maximum=0,
            labelText=self.tr("Retrieving package list"),
            sizeGripEnabled=False,
            windowTitle="Progress"
        )

        self.__progress.rejected.connect(self.reject)
        self.__thread = None
        self.__installer = None

    @Slot(object)
    def _set_packages(self, f):
        if self.__progress.isVisible():
            self.__progress.close()

        try:
            packages = f.result()
        except (IOError, OSError) as err:
            message_warning(
                "Could not retrieve package list",
                title="Error",
                informative_text=str(err),
                parent=self
            )
            packages = []
        except Exception:
            raise
        else:
            AddonManagerDialog._packages = packages

        installed = list_installed_addons()
        dists = {dist.project_name: dist for dist in installed}
        packages = {pkg.name: pkg for pkg in packages}

        # For every pypi available distribution not listed by
        # list_installed_addons, check if it is actually already
        # installed.
        ws = pkg_resources.WorkingSet()
        for pkg_name in set(packages.keys()).difference(set(dists.keys())):
            try:
                d = ws.find(pkg_resources.Requirement.parse(pkg_name))
            except pkg_resources.VersionConflict:
                pass
            except ValueError:
                # Requirements.parse error ?
                pass
            else:
                if d is not None:
                    dists[d.project_name] = d

        project_names = unique(
            itertools.chain(packages.keys(), dists.keys())
        )

        items = []
        for name in project_names:
            if name in dists and name in packages:
                item = Installed(packages[name], dists[name])
            elif name in dists:
                item = Installed(None, dists[name])
            elif name in packages:
                item = Available(packages[name])
            else:
                assert False
            items.append(item)

        self.addonwidget.set_items(items)

    def showEvent(self, event):
        super().showEvent(event)

        if not self._f_pypi_addons.done():
            QTimer.singleShot(0, self.__progress.show)

    def done(self, retcode):
        super().done(retcode)
        self._f_pypi_addons.cancel()
        self._executor.shutdown(wait=False)
        if self.__thread is not None:
            self.__thread.quit()
            self.__thread.wait(1000)

    def closeEvent(self, event):
        super().closeEvent(event)
        self._f_pypi_addons.cancel()
        self._executor.shutdown(wait=False)

        if self.__thread is not None:
            self.__thread.quit()
            self.__thread.wait(1000)

    ADDON_EXTENSIONS = ('.zip', '.whl', '.tar.gz')

    def dragEnterEvent(self, event):
        urls = event.mimeData().urls()
        if any((OSX_NSURL_toLocalFile(url) or url.toLocalFile())
                .endswith(self.ADDON_EXTENSIONS) for url in urls):
            event.acceptProposedAction()

    def dropEvent(self, event):
        """Allow dropping add-ons (zip or wheel archives) on this dialog to
        install them"""
        packages = []
        names = []
        for url in event.mimeData().urls():
            path = OSX_NSURL_toLocalFile(url) or url.toLocalFile()
            if path.endswith(self.ADDON_EXTENSIONS):
                name, vers, summary, descr = (get_meta_from_archive(path) or
                                              (os.path.basename(path), '', '', ''))
                names.append(name)
                packages.append(
                    Installable(name, vers, summary,
                                descr or summary, path, [path]))
        future = concurrent.futures.Future()
        future.set_result((AddonManagerDialog._packages or []) + packages)
        self._set_packages(future)
        self.addonwidget.set_install_projects(names)

    def __accepted(self):
        steps = self.addonwidget.item_state()

        if steps:
            # Move all uninstall steps to the front
            steps = sorted(
                steps, key=lambda step: 0 if step[0] == Uninstall else 1
            )
            self.__installer = Installer(steps=steps,
                                         user_install=self.user_install)
            self.__thread = QThread(self)
            self.__thread.start()

            self.__installer.moveToThread(self.__thread)
            self.__installer.finished.connect(self.__on_installer_finished)
            self.__installer.error.connect(self.__on_installer_error)
            self.__installer.installStatusChanged.connect(
                self.__progress.setLabelText)

            self.__progress.show()
            self.__progress.setLabelText("Installing")

            self.__installer.start()

        else:
            self.accept()

    def __on_installer_error(self, command, pkg, retcode, output):
        message_error(
            "An error occurred while running a subprocess", title="Error",
            informative_text="{} exited with non zero status.".format(command),
            details="".join(output),
            parent=self
        )
        self.reject()

    def __on_installer_finished(self):
        message = (
            ("Changes successfully applied in <i>{}</i>.<br>".format(
                USER_SITE) if self.user_install else '') +
            "Please restart Orange for changes to take effect.")
        message_information(message, parent=self)
        self.accept()
Example #24
0
class AddonManagerDialog(QDialog):
    def __init__(self, parent=None, **kwargs):
        super(AddonManagerDialog, self).__init__(parent, **kwargs)
        self.setLayout(QVBoxLayout())

        self.addonwidget = AddonManagerWidget()
        self.addonwidget.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().addWidget(self.addonwidget)
        buttons = QDialogButtonBox(orientation=Qt.Horizontal,
                                   standardButtons=QDialogButtonBox.Ok
                                   | QDialogButtonBox.Cancel)
        buttons.accepted.connect(self.__accepted)
        buttons.rejected.connect(self.reject)

        self.layout().addWidget(buttons)

        self.__progress = QProgressDialog(
            self,
            Qt.Sheet,
            minimum=0,
            maximum=0,
            labelText=self.tr("Retrieving package list"),
            sizeGripEnabled=False,
            windowTitle="Progress")
        self.__progress.canceled.connect(self.reject)

        # The installer thread
        self.__thread = None
        # The installer object
        self.__installer = None

    @Slot(list)
    def setItems(self, items):
        self.addonwidget.setItems(items)

    def progressDialog(self):
        return self.__progress

    def done(self, retcode):
        super(AddonManagerDialog, self).done(retcode)
        if self.__thread is not None:
            self.__thread.quit()
            self.__thread.wait(1000)

    def closeEvent(self, event):
        super(AddonManagerDialog, self).closeEvent(event)
        if self.__thread is not None:
            self.__thread.quit()
            self.__thread.wait(1000)

    def __accepted(self):
        steps = self.addonwidget.itemState()

        if steps:
            # Move all uninstall steps to the front
            steps = sorted(steps,
                           key=lambda step: 0 if step[0] == Uninstall else 1)
            self.__installer = Installer(steps=steps)
            self.__thread = QThread(self)
            self.__thread.start()

            self.__installer.moveToThread(self.__thread)
            self.__installer.finished.connect(self.__on_installer_finished)
            self.__installer.error.connect(self.__on_installer_error)
            self.__installer.installStatusChanged.connect(
                self.__progress.setLabelText)

            self.__progress.show()
            self.__progress.setLabelText("Installing")

            self.__installer.start()

        else:
            self.accept()

    def __on_installer_error(self, command, pkg, retcode, output):
        message_error(
            "An error occurred while running a subprocess",
            title="Error",
            informative_text="{} exited with non zero status.".format(command),
            details="".join(output),
            parent=self)
        self.reject()

    def __on_installer_finished(self):
        message_information(
            "Please restart the application for changes to take effect.",
            parent=self)
        self.accept()
Example #25
0
class OsmDownloader(QDialog, Ui_OsmDownloaderBase):
    """Downloader for OSM data."""
    def __init__(self, parent=None, iface=None):
        """Constructor for import dialog.

        :param parent: Optional widget to use as parent
        :type parent: QWidget

        :param iface: An instance of QGisInterface
        :type iface: QGisInterface
        """
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setupUi(self)

        self.setWindowTitle(self.tr('InaSAFE OpenStreetMap Downloader'))

        self.iface = iface
        self.url = "http://osm.linfiniti.com/buildings-shp"

        # creating progress dialog for download
        self.progressDialog = QProgressDialog(self)
        self.progressDialog.setAutoClose(False)
        myTitle = self.tr("InaSAFE OpenStreetMap Downloader")
        self.progressDialog.setWindowTitle(myTitle)
        # Set up context help
        helpButton = self.buttonBox.button(QtGui.QDialogButtonBox.Help)
        QtCore.QObject.connect(helpButton, QtCore.SIGNAL('clicked()'),
                               self.show_help)

        self.show_info()

        # Set Proxy in webpage
        proxy = get_proxy()
        self.network_manager = QNetworkAccessManager(self)
        if not proxy is None:
            self.network_manager.setProxy(proxy)
        self.restore_state()
        self.update_extent()

    def show_info(self):
        """Show usage info to the user."""
        # Read the header and footer html snippets
        header = html_header()
        footer = html_footer()

        string = header

        heading = m.Heading(self.tr('OSM Downloader'), **INFO_STYLE)
        body = self.tr(
            'This tool will fetch building (\'structure\') data from the '
            'OpenStreetMap project for you. The downloaded data will have '
            'InaSAFE keywords defined and a default QGIS style applied. To '
            'use this tool effectively:')
        tips = m.BulletedList()
        tips.add(
            self.
            tr('Use QGIS to zoom in to the area for which you want building data '
               'to be retrieved.'))
        tips.add(
            self.
            tr('Check the output directory is correct. Note that the saved '
               'dataset will be called buildings.shp (and its associated files).'
               ))
        tips.add(
            self.
            tr('If a dataset already exists in the output directory it will be '
               'overwritten.'))
        tips.add(
            self.
            tr('This tool requires a working internet connection and fetching '
               'buildings will consume your bandwidth.'))
        tips.add(
            m.Link(
                'http://www.openstreetmap.org/copyright',
                text=self.tr(
                    'Downloaded data is copyright OpenStreetMap contributors'
                    ' (click for more info).')))
        message = m.Message()
        message.add(heading)
        message.add(body)
        message.add(tips)
        string += message.to_html()
        string += footer

        self.webView.setHtml(string)

    def restore_state(self):
        """ Read last state of GUI from configuration file."""
        mySetting = QSettings()
        self.outDir.setText(mySetting.value('directory'))

    def save_state(self):
        """ Store current state of GUI to configuration file """
        mySetting = QSettings()
        mySetting.setValue('directory', self.outDir.text())

    def show_help(self):
        """Load the help text for the dialog."""
        show_context_help('openstreetmap_downloader')

    def update_extent(self):
        """ Update extent value in GUI based from value in map."""
        # Get the extent as [xmin, ymin, xmax, ymax]
        myExtent = viewport_geo_array(self.iface.mapCanvas())
        self.minLongitude.setText(str(myExtent[0]))
        self.minLatitude.setText(str(myExtent[1]))
        self.maxLongitude.setText(str(myExtent[2]))
        self.maxLatitude.setText(str(myExtent[3]))

    @pyqtSignature('')  # prevents actions being handled twice
    def on_pBtnDir_clicked(self):
        """ Show a dialog to choose directory """
        # noinspection PyCallByClass,PyTypeChecker
        self.outDir.setText(
            QFileDialog.getExistingDirectory(
                self, self.tr("Select download directory")))

    def accept(self):
        """Do osm download and display it in QGIS."""

        try:
            self.save_state()

            self.require_directory()
            self.download()
            self.load_shapefile()
            self.done(QDialog.Accepted)
        except CanceledImportDialogError:
            # don't show anything because this exception raised
            # when user canceling the import process directly
            pass
        except Exception as myEx:
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QMessageBox.warning(
                self, self.tr("InaSAFE OpenStreetMap downloader error"),
                str(myEx))

            self.progressDialog.cancel()

    def require_directory(self):
        """Ensure directory path entered in dialog exist.

        When the path does not exist, this function will ask the user if he
        want to create it or not.

        :raises: CanceledImportDialogError - when user choose 'No' in
            the question dialog for creating directory.
        """

        myDir = str(self.outDir.text())

        if os.path.exists(myDir):
            return

        myTitle = self.tr("Directory %s not exist") % myDir
        myQuestion = self.tr(
            "Directory %s not exist. Do you want to create it?") % myDir
        # noinspection PyCallByClass,PyTypeChecker
        myAnswer = QMessageBox.question(self, myTitle, myQuestion,
                                        QMessageBox.Yes | QMessageBox.No)

        if myAnswer == QMessageBox.Yes:
            os.makedirs(myDir)
        else:
            raise CanceledImportDialogError()

    def download(self):
        """Download shapefiles from Linfinti server.

        :raises: ImportDialogError, CanceledImportDialogError
        """

        ## preparing necessary data
        myMinLng = str(self.minLongitude.text())
        myMinLat = str(self.minLatitude.text())
        myMaxLng = str(self.maxLongitude.text())
        myMaxLat = str(self.maxLatitude.text())

        myCoordinate = "{myMinLng},{myMinLat},{myMaxLng},{myMaxLat}".format(
            myMinLng=myMinLng,
            myMinLat=myMinLat,
            myMaxLng=myMaxLng,
            myMaxLat=myMaxLat)

        myShapeUrl = "{url}?bbox={myCoordinate}".format(
            url=self.url, myCoordinate=myCoordinate)

        myFilePath = tempfile.mktemp('.shp.zip')

        # download and extract it
        self.fetch_zip(myShapeUrl, myFilePath)
        print myFilePath
        print str(self.outDir.text())
        self.extract_zip(myFilePath, str(self.outDir.text()))

        self.progressDialog.done(QDialog.Accepted)

    def fetch_zip(self, url, output_path):
        """Download zip containing shp file and write to output_path.

        :param url: URL of the zip bundle.
        :type url: str

        :param output_path: Path of output file,
        :type output_path: str

        :raises: ImportDialogError - when network error occurred
        """

        self.progressDialog.show()
        self.progressDialog.setMaximum(100)
        self.progressDialog.setValue(0)

        # myLabelText = "Begin downloading shapefile from " \
        #               + "%s ..."
        # self.progressDialog.setLabelText(self.tr(myLabelText) % (url))
        myLabelText = self.tr("Downloading shapefile")
        self.progressDialog.setLabelText(myLabelText)

        myResult = download_url(self.network_manager, url, output_path,
                                self.progressDialog)

        if myResult is not True:
            _, myErrorMessage = myResult
            raise ImportDialogError(myErrorMessage)

    def extract_zip(self, path, output_dir):
        """Extract all content of a .zip file from path to output_dir.

        :param path: The path of the .zip file
        :type path: str

        :param output_dir: Output directory where the shp will be written to.
        :type output_dir: str

        :raises: IOError - when not able to open path or output_dir does not
            exist.
        """

        import zipfile

        # extract all files...
        myHandle = open(path, 'rb')
        myZip = zipfile.ZipFile(myHandle)
        for myName in myZip.namelist():
            myOutPath = os.path.join(output_dir, myName)
            myOutFile = open(myOutPath, 'wb')
            myOutFile.write(myZip.read(myName))
            myOutFile.close()

        myHandle.close()

    def load_shapefile(self):
        """
        Load downloaded shape file to QGIS Main Window.

        :raises: ImportDialogError - when buildings.shp not exist
        """

        myDir = str(self.outDir.text())
        myPath = os.path.join(myDir, 'buildings.shp')

        if not os.path.exists(myPath):
            myMessage = self.tr(
                "%s don't exist. The server don't have buildings data.")
            raise ImportDialogError(myMessage)

        self.iface.addVectorLayer(myPath, 'buildings', 'ogr')
Example #26
0
class RebuildIndex(object):
    """
    Tool class to rebuild the indexation
    """
    def __init__(self, iface):
        """
        Constructor
        :param iface: interface
        """
        self.__iface = iface
        self.icon_path = ':/plugins/VDLTools/icons/rebuild_icon.png'
        self.text = QCoreApplication.translate("VDLTools", "Rebuild Index")
        self.killed = False

    def start(self):
        """
        To start the rebuild
        """
        snap_util = self.__iface.mapCanvas().snappingUtils()
        extent = self.__iface.mapCanvas().extent()
        self.__progressDialog = QProgressDialog()
        self.__progressDialog.setWindowTitle(
            QCoreApplication.translate("VDLTools", "Rebuild Index..."))
        self.__progressDialog.setLabelText(
            QCoreApplication.translate("VDLTools",
                                       "Percentage of indexed layers"))
        progressBar = QProgressBar(self.__progressDialog)
        progressBar.setTextVisible(True)
        cancelButton = QPushButton()
        cancelButton.setText(QCoreApplication.translate("VDLTools", "Cancel"))
        cancelButton.clicked.connect(self.kill)
        self.__progressDialog.setBar(progressBar)
        self.__progressDialog.setCancelButton(cancelButton)
        self.__progressDialog.setMinimumWidth(300)
        self.__progressDialog.show()

        lcs_list = snap_util.layers()
        step = 0
        self.killed = False
        for lc in lcs_list:
            if self.killed:
                break
            locator = snap_util.locatorForLayer(lc.layer)
            if locator.extent() is not None:
                txt = locator.extent().toString()
            else:
                txt = "None"
            print("old extent : " + txt)
            print("new extent : " + extent.toString())
            locator.setExtent(extent)
            if not locator.hasIndex():
                locator.init()
            else:
                locator.rebuildIndex()
            locator.setExtent(None)
            progressBar.setValue(100 * step / len(lcs_list))
            step += 1
        self.__progressDialog.close()

    def kill(self):
        """
        To stop the rebuild at the end of the current working layer
        """
        self.killed = True
Example #27
0
  def copy_gfx(self):
    gfx_dir = os.path.join(self.editor_data_dir, "gfx")
    
    if os.path.isdir(gfx_dir):
      shutil.rmtree(gfx_dir)
    
    os.makedirs(gfx_dir)
    
    progress = QProgressDialog("", "Abort", 0, 0, self)
    progress.setWindowTitle("Copying GFX...")
    progress.setWindowModality(Qt.Qt.WindowModal)
    progress.setMinimumDuration(0)
    progress.setValue(0)
    progress.setAutoClose(False)
    
    progress.setLabelText("Setting up GFX dir.")
    progress.setMaximum(5)
    progress.setValue(0)
    
    # Extract the images we can't just take directly from the game's data.
    gfx_bin = zipfile.ZipFile("data/gfx_base.zip", "r")
    progress.setValue(1)
    progress.setValue(2)
    gfx_bin.extractall(gfx_dir)
    progress.setValue(5)
    gfx_bin.close()
    
    # We can mostly loop this.
    gfx_data = [
      ("ammo",      "kotodama_icn_???.gim"),
      ("bgd",       "bgd_???.gim"),
      ("cutin",     "cutin_icn_???.gim"),
      ("events",    "gallery_icn_???.gim"),
      ("movies",    "bin_movie_gallery_l.pak/0000/000[1789].gim"),
      ("movies",    "bin_movie_gallery_l.pak/0000/00[123]?.gim"),
      ("movies",    "gallery_ico_m_none.gim"),
      ("movies",    "gallery_thumbnail_m_???.gim"),
      ("nametags",  "tex_system.pak/00[12]?.gim"),
      ("nametags",  "tex_system.pak/003[0123456].gim"),
      ("presents",  "present_icn_???.gim"),
      ("sprites",   "bustup_??_??.gim"),
      ("sprites",   "stand_??_??.gmo"),
    ]
    
    for (dir, file_glob) in gfx_data:
      out_dir = os.path.join(gfx_dir, dir)
      files   = glob.glob(os.path.join(self.data01_dir, file_glob))
      
      progress.setLabelText("Copying %s." % dir)
      progress.setMaximum(len(files))
      progress.setValue(0)
      
      if not os.path.isdir(out_dir):
        os.makedirs(out_dir)
      
      for i, image in enumerate(files):
        if i % 10 == 0:
          progress.setValue(i)
        
        if progress.wasCanceled():
          return
        
        src  = image
        dest = os.path.join(out_dir, os.path.basename(src))
        shutil.copy(src, dest)
      
      progress.setValue(len(files))
    
    progress.setLabelText("Copying font.")
    progress.setMaximum(4)
    progress.setValue(0)
    
    # The font we have to get from umdimage2.
    font_dir = os.path.join(gfx_dir, "font")
    if not os.path.isdir(font_dir):
      os.makedirs(font_dir)
    
    progress.setValue(1)
    # And convert to PNG with an alpha channel so our editor can use it.
    font1 = font_bmp_to_alpha(os.path.join(self.data01_dir, "jp", "font", "font.pak", "0000.bmp"))
    progress.setValue(2)
    font2 = font_bmp_to_alpha(os.path.join(self.data01_dir, "jp", "font", "font.pak", "0002.bmp"))
    progress.setValue(3)
    
    font1.save(os.path.join(font_dir, "Font01.png"))
    font2.save(os.path.join(font_dir, "Font02.png"))
    shutil.copy(os.path.join(self.data01_dir, "jp", "font", "font.pak", "0001.font"), os.path.join(font_dir, "Font01.font"))
    shutil.copy(os.path.join(self.data01_dir, "jp", "font", "font.pak", "0003.font"), os.path.join(font_dir, "Font02.font"))
    
    progress.setValue(4)
    
    # And then the flash files. This'll be fun.
    flash_dir = os.path.join(gfx_dir, "flash")
    if not os.path.isdir(flash_dir):
      os.makedirs(flash_dir)

    #flash2_dir = os.path.join(gfx_dir, "flash2")
    #if not os.path.isdir(flash2_dir):
      #os.makedirs(flash2_dir)
    
     #Because there's so many in so many different places, I just stored a list
     #of the flash files we need in the gfx_base archive. So let's load that.
    with open(os.path.join(gfx_dir, "fla.txt"), "rb") as fla:
      fla_list = fla.readlines()
      
      progress.setLabelText("Copying flash.")
      progress.setMaximum(len(fla_list))
      progress.setValue(0)
      
      for i, flash in enumerate(fla_list):
        if i % 10 == 0:
          progress.setValue(i)
        
        if progress.wasCanceled():
          return
        
        flash = flash.strip()
        fla_name = flash[:7] # fla_###
        
        src  = os.path.join(self.data01_dir, "all", "flash", flash)
        dest = os.path.join(flash_dir, "%s.gim" % fla_name)

        shutil.copy(src, dest)
        
      progress.setValue(len(fla_list))
    
    # We have a couple sets of files that aren't named the way we want them to
    # be, just because of how they're stored in umdimage.
    progress.setLabelText("Renaming files.")
    to_rename = [
      ("movies",    "movie_%03d.gim", range(32)),
      ("nametags", "%02d.gim", range(23) + [24, 25, 30, 31]),
    ]
    
    for (folder, pattern, nums) in to_rename:
      folder  = os.path.join(gfx_dir, folder)
      files   = glob.glob(os.path.join(folder, "*.gim"))
      
      progress.setMaximum(len(files))
      progress.setValue(0)
      
      for i, image in enumerate(files):
        if i % 10 == 0:
          progress.setValue(i)
        
        if progress.wasCanceled():
          return
        
        src  = image
        dest = os.path.join(folder, pattern % nums[i])
        
        if os.path.isfile(dest):
          os.remove(dest)
        
        shutil.move(src, dest)
    
    sprite_dir = os.path.join(gfx_dir, "sprites")
    gmo_files = glob.glob(os.path.join(sprite_dir, "*.gmo"))
    
    progress.setLabelText("Extracting GMO files.")
    progress.setValue(0)
    progress.setMaximum(len(gmo_files))
    
    for i, gmo_file in enumerate(gmo_files):
      if i % 10 == 0:
        progress.setValue(i)
      
      if progress.wasCanceled():
        return
      
      name, ext = os.path.splitext(os.path.basename(gmo_file))
      gim_file  = os.path.join(sprite_dir, name + ".gim")
      
      gmo = GmoFile(filename = gmo_file)
      
      # Once we've loaded it, we're all done with it, so make it go away.
      os.remove(gmo_file)
      
      if gmo.gim_count() == 0:
        continue
      
      gim = gmo.get_gim(0)
      
      with open(gim_file, "wb") as f:
        gim.tofile(f)
    
    if self.ui.chkGimToPng.isChecked():
      gim_files = glob.glob(os.path.join(gfx_dir, "*", "*.gim"))
      
      progress.setLabelText("Converting GIM to PNG.")
      progress.setValue(0)
      progress.setMaximum(len(gim_files))
      
      converter = GimConverter()
      
      for i, gim_file in enumerate(gim_files):
        progress.setValue(i)
        if progress.wasCanceled():
          return
        
        converter.gim_to_png(gim_file)
        os.remove(gim_file)
    
    progress.close()
    
    self.gfx_dir = gfx_dir
    
    self.ui.grpStep5.setEnabled(False)
    self.ui.grpStep6.setEnabled(True)
Example #28
0
class AddonManagerDialog(QDialog):
    _packages = None

    def __init__(self, parent=None, **kwargs):
        super().__init__(parent, **kwargs)
        self.setLayout(QVBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.addonwidget = AddonManagerWidget()
        self.layout().addWidget(self.addonwidget)

        info_bar = QWidget()
        info_layout = QHBoxLayout()
        info_bar.setLayout(info_layout)
        info_icon = QLabel()
        info_text = QLabel()
        info_layout.addWidget(info_icon)
        info_layout.addWidget(info_text)
        self.layout().addWidget(info_bar)

        buttons = QDialogButtonBox(
            orientation=Qt.Horizontal,
            standardButtons=QDialogButtonBox.Ok | QDialogButtonBox.Cancel
        )
        buttons.accepted.connect(self.__accepted)
        buttons.rejected.connect(self.reject)

        self.layout().addWidget(buttons)

        if not os.access(sysconfig.get_path("purelib"), os.W_OK):
            if sysconfig.get_platform().startswith("macosx"):
                info = "You must install Orange by dragging it into" \
                       " Applications before installing add-ons."
            else:
                info = "You do not have permissions to write into Orange " \
                       "directory.\nYou may need to contact an administrator " \
                       "for assistance."
            info_text.setText(info)
            style = QApplication.instance().style()
            info_icon.setPixmap(style.standardIcon(
                QStyle.SP_MessageBoxCritical).pixmap(14, 14))
            buttons.button(QDialogButtonBox.Ok ).setEnabled(False)

        self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
        if AddonManagerDialog._packages is None:
            self._f_pypi_addons = self._executor.submit(list_pypi_addons)
        else:
            self._f_pypi_addons = concurrent.futures.Future()
            self._f_pypi_addons.set_result(AddonManagerDialog._packages)

        self._f_pypi_addons.add_done_callback(
            method_queued(self._set_packages, (object,))
        )

        self.__progress = QProgressDialog(
            self, Qt.Sheet,
            minimum=0, maximum=0,
            labelText=self.tr("Retrieving package list"),
            sizeGripEnabled=False,
            windowTitle="Progress"
        )

        self.__progress.rejected.connect(self.reject)
        self.__thread = None
        self.__installer = None

    @Slot(object)
    def _set_packages(self, f):
        if self.__progress.isVisible():
            self.__progress.close()

        try:
            packages = f.result()
        except (IOError, OSError) as err:
            message_warning(
                "Could not retrieve package list",
                title="Error",
                informative_text=str(err),
                parent=self
            )
            packages = []
        except Exception:
            raise
        else:
            AddonManagerDialog._packages = packages

        installed = list_installed_addons()
        dists = {dist.project_name: dist for dist in installed}
        packages = {pkg.name: pkg for pkg in packages}

        # For every pypi available distribution not listed by
        # list_installed_addons, check if it is actually already
        # installed.
        ws = pkg_resources.WorkingSet()
        for pkg_name in set(packages.keys()).difference(set(dists.keys())):
            try:
                d = ws.find(pkg_resources.Requirement.parse(pkg_name))
            except pkg_resources.VersionConflict:
                pass
            except ValueError:
                # Requirements.parse error ?
                pass
            else:
                if d is not None:
                    dists[d.project_name] = d

        project_names = unique(
            itertools.chain(packages.keys(), dists.keys())
        )

        items = []
        for name in project_names:
            if name in dists and name in packages:
                item = Installed(packages[name], dists[name])
            elif name in dists:
                item = Installed(None, dists[name])
            elif name in packages:
                item = Available(packages[name])
            else:
                assert False
            items.append(item)

        self.addonwidget.set_items(items)

    def showEvent(self, event):
        super().showEvent(event)

        if not self._f_pypi_addons.done():
            QTimer.singleShot(0, self.__progress.show)

    def done(self, retcode):
        super().done(retcode)
        self._f_pypi_addons.cancel()
        self._executor.shutdown(wait=False)
        if self.__thread is not None:
            self.__thread.quit()
            self.__thread.wait(1000)

    def closeEvent(self, event):
        super().closeEvent(event)
        self._f_pypi_addons.cancel()
        self._executor.shutdown(wait=False)

        if self.__thread is not None:
            self.__thread.quit()
            self.__thread.wait(1000)

    def __accepted(self):
        steps = self.addonwidget.item_state()

        if steps:
            # Move all uninstall steps to the front
            steps = sorted(
                steps, key=lambda step: 0 if step[0] == Uninstall else 1
            )
            self.__installer = Installer(steps=steps)
            self.__thread = QThread(self)
            self.__thread.start()

            self.__installer.moveToThread(self.__thread)
            self.__installer.finished.connect(self.__on_installer_finished)
            self.__installer.error.connect(self.__on_installer_error)
            self.__installer.installStatusChanged.connect(
                self.__progress.setLabelText)

            self.__progress.show()
            self.__progress.setLabelText("Installing")

            self.__installer.start()

        else:
            self.accept()

    def __on_installer_error(self, command, pkg, retcode, output):
        message_error(
            "An error occurred while running a subprocess", title="Error",
            informative_text="{} exited with non zero status.".format(command),
            details="".join(output),
            parent=self
        )
        self.reject()

    def __on_installer_finished(self):
        message_information(
            "Please restart Orange for changes to take effect.",
            parent=self)
        self.accept()
class OsmDownloaderDialog(QDialog, FORM_CLASS):
    """Downloader for OSM data."""

    def __init__(self, parent=None, iface=None):
        """Constructor for import dialog.

        :param parent: Optional widget to use as parent
        :type parent: QWidget

        :param iface: An instance of QGisInterface
        :type iface: QGisInterface
        """
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setupUi(self)

        self.setWindowTitle(self.tr('InaSAFE OpenStreetMap Downloader'))

        self.iface = iface
        self.buildings_url = 'http://osm.linfiniti.com/buildings-shp'
        self.building_points_url = \
            'http://osm.linfiniti.com/building-points-shp'
        self.roads_url = 'http://osm.linfiniti.com/roads-shp'

        self.help_context = 'openstreetmap_downloader'
        # creating progress dialog for download
        self.progress_dialog = QProgressDialog(self)
        self.progress_dialog.setAutoClose(False)
        title = self.tr('InaSAFE OpenStreetMap Downloader')
        self.progress_dialog.setWindowTitle(title)
        # Set up context help
        help_button = self.button_box.button(QtGui.QDialogButtonBox.Help)
        help_button.clicked.connect(self.show_help)

        self.show_info()

        # set up the validator for the file name prefix
        expression = QRegExp('^[A-Za-z0-9-_]*$')
        validator = QRegExpValidator(expression, self.filename_prefix)
        self.filename_prefix.setValidator(validator)

        # Set Proxy in webpage
        proxy = get_proxy()
        self.network_manager = QNetworkAccessManager(self)
        if proxy is not None:
            self.network_manager.setProxy(proxy)
        self.restore_state()

        # Setup the rectangle map tool
        self.canvas = iface.mapCanvas()
        self.rectangle_map_tool = \
            RectangleMapTool(self.canvas)
        self.rectangle_map_tool.rectangle_created.connect(
            self.update_extent_from_rectangle)
        self.button_extent_rectangle.clicked.connect(
            self.drag_rectangle_on_map_canvas)

        # Setup pan tool
        self.pan_tool = QgsMapToolPan(self.canvas)
        self.canvas.setMapTool(self.pan_tool)
        self.update_extent_from_map_canvas()

    def show_info(self):
        """Show usage info to the user."""
        # Read the header and footer html snippets
        header = html_header()
        footer = html_footer()

        string = header

        heading = m.Heading(self.tr('OSM Downloader'), **INFO_STYLE)
        body = self.tr(
            'This tool will fetch building (\'structure\') or road ('
            '\'highway\') data from the OpenStreetMap project for you. '
            'The downloaded data will have InaSAFE keywords defined and a '
            'default QGIS style applied. To use this tool effectively:'
        )
        tips = m.BulletedList()
        tips.add(self.tr(
            'Your current extent, when opening this window, will be used to '
            'determine the area for which you want data to be retrieved.'
            'You can interactively select the area by using the '
            '\'select on map\' button - which will temporarily hide this '
            'window and allow you to drag a rectangle on the map. After you '
            'have finished dragging the rectangle, this window will '
            'reappear.'))
        tips.add(self.tr(
            'Check the output directory is correct. Note that the saved '
            'dataset will be called either roads.shp or buildings.shp (and '
            'associated files).'
        ))
        tips.add(self.tr(
            'By default simple file names will be used (e.g. roads.shp, '
            'buildings.shp). If you wish you can specify a prefix to '
            'add in front of this default name. For example using a prefix '
            'of \'padang-\' will cause the downloaded files to be saved as '
            '\'padang-roads.shp\' and \'padang-buildings.shp\'. Note that '
            'the only allowed prefix characters are A-Z, a-z, 0-9 and the '
            'characters \'-\' and \'_\'. You can leave this blank if you '
            'prefer.'
        ))
        tips.add(self.tr(
            'If a dataset already exists in the output directory it will be '
            'overwritten.'
        ))
        tips.add(self.tr(
            'This tool requires a working internet connection and fetching '
            'buildings or roads will consume your bandwidth.'))
        tips.add(m.Link(
            'http://www.openstreetmap.org/copyright',
            text=self.tr(
                'Downloaded data is copyright OpenStreetMap contributors'
                ' (click for more info).')
        ))
        message = m.Message()
        message.add(heading)
        message.add(body)
        message.add(tips)
        string += message.to_html()
        string += footer

        self.web_view.setHtml(string)

    def restore_state(self):
        """ Read last state of GUI from configuration file."""
        settings = QSettings()
        try:
            last_path = settings.value('directory', type=str)
        except TypeError:
            last_path = ''
        self.output_directory.setText(last_path)

    def save_state(self):
        """ Store current state of GUI to configuration file """
        settings = QSettings()
        settings.setValue('directory', self.output_directory.text())

    def show_help(self):
        """Load the help text for the dialog."""
        show_context_help(self.help_context)

    def update_extent(self, extent):
        """Update extent value in GUI based from an extent.

        :param extent: A list in the form [xmin, ymin, xmax, ymax] where all
            coordinates provided are in Geographic / EPSG:4326.
        :type extent: list
        """
        self.min_longitude.setText(str(extent[0]))
        self.min_latitude.setText(str(extent[1]))
        self.max_longitude.setText(str(extent[2]))
        self.max_latitude.setText(str(extent[3]))

    def update_extent_from_map_canvas(self):
        """Update extent value in GUI based from value in map.

        .. note:: Delegates to update_extent()
        """

        self.groupBox.setTitle(self.tr('Bounding box from the map canvas'))
        # Get the extent as [xmin, ymin, xmax, ymax]
        extent = viewport_geo_array(self.iface.mapCanvas())
        self.update_extent(extent)

    def update_extent_from_rectangle(self):
        """Update extent value in GUI based from the QgsMapTool rectangle.

        .. note:: Delegates to update_extent()
        """

        self.show()
        self.canvas.unsetMapTool(self.rectangle_map_tool)
        self.canvas.setMapTool(self.pan_tool)

        rectangle = self.rectangle_map_tool.rectangle()
        if rectangle:
            self.groupBox.setTitle(self.tr('Bounding box from rectangle'))
            extent = rectangle_geo_array(rectangle, self.iface.mapCanvas())
            self.update_extent(extent)

    def validate_extent(self):
        """Validate the bounding box before user click OK to download.

        :return: True if the bounding box is valid, otherwise False
        :rtype: bool
        """
        min_latitude = float(str(self.min_latitude.text()))
        max_latitude = float(str(self.max_latitude.text()))
        min_longitude = float(str(self.min_longitude.text()))
        max_longitude = float(str(self.max_longitude.text()))

        # min_latitude < max_latitude
        if min_latitude >= max_latitude:
            return False

        # min_longitude < max_longitude
        if min_longitude >= max_longitude:
            return False

        # -90 <= latitude <= 90
        if min_latitude < -90 or min_latitude > 90:
            return False
        if max_latitude < -90 or max_latitude > 90:
            return False

        # -180 <= longitude <= 180
        if min_longitude < -180 or min_longitude > 180:
            return False
        if max_longitude < -180 or max_longitude > 180:
            return False

        return True

    @pyqtSignature('')  # prevents actions being handled twice
    def on_directory_button_clicked(self):
        """Show a dialog to choose directory."""
        # noinspection PyCallByClass,PyTypeChecker
        self.output_directory.setText(QFileDialog.getExistingDirectory(
            self, self.tr('Select download directory')))

    def drag_rectangle_on_map_canvas(self):
        """Hide the dialog and allow the user to draw a rectangle."""

        self.hide()
        self.rectangle_map_tool.reset()
        self.canvas.unsetMapTool(self.pan_tool)
        self.canvas.setMapTool(self.rectangle_map_tool)

    def accept(self):
        """Do osm download and display it in QGIS."""
        error_dialog_title = self.tr('InaSAFE OpenStreetMap Downloader Error')

        # Lock the groupbox
        self.groupBox.setDisabled(True)

        # Validate extent
        valid_flag = self.validate_extent()
        if not valid_flag:
            message = self.tr(
                'The bounding box is not valid. Please make sure it is '
                'valid or check your projection!')
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            display_warning_message_box(self, error_dialog_title, message)
            # Unlock the groupbox
            self.groupBox.setEnabled(True)
            return

        # Get all the feature types
        index = self.feature_type.currentIndex()
        if index == 0:
            feature_types = ['buildings', 'roads', 'building-points']
        elif index == 1:
            feature_types = ['buildings']
        elif index == 2:
            feature_types = ['building-points']
        else:
            feature_types = ['roads']

        try:
            self.save_state()
            self.require_directory()
            for feature_type in feature_types:

                output_directory = self.output_directory.text()
                output_prefix = self.filename_prefix.text()
                overwrite = self.overwrite_checkBox.isChecked()
                output_base_file_path = self.get_output_base_path(
                    output_directory, output_prefix, feature_type, overwrite)

                self.download(feature_type, output_base_file_path)
                try:
                    self.load_shapefile(feature_type, output_base_file_path)
                except FileMissingError as exception:
                    display_warning_message_box(
                        self,
                        error_dialog_title,
                        exception.message)
            self.done(QDialog.Accepted)
            self.rectangle_map_tool.reset()

        except CanceledImportDialogError:
            # don't show anything because this exception raised
            # when user canceling the import process directly
            pass
        except Exception as exception:  # pylint: disable=broad-except
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            display_warning_message_box(
                self, error_dialog_title, exception.message)

            self.progress_dialog.cancel()

        finally:
            # Unlock the groupbox
            self.groupBox.setEnabled(True)

    def get_output_base_path(
            self,
            output_directory,
            output_prefix,
            feature_type,
            overwrite):
        """Get a full base name path to save the shapefile.

        :param output_directory: The directory where to put results.
        :type output_directory: str

        :param output_prefix: The prefix to add for the shapefile.
        :type output_prefix: str

        :param feature_type: What kind of features should be downloaded.
            Currently 'buildings', 'building-points' or 'roads' are supported.
        :type feature_type: str

        :param overwrite: Boolean to know if we can overwrite existing files.
        :type overwrite: bool

        :return: The base path.
        :rtype: str
        """
        path = os.path.join(
            output_directory, '%s%s' % (output_prefix, feature_type))

        if overwrite:

            # If a shapefile exists, we must remove it (only the .shp)
            shp = '%s.shp' % path
            if os.path.isfile(shp):
                os.remove(shp)

        else:
            separator = '-'
            suffix = self.get_unique_file_path_suffix(
                '%s.shp' % path, separator)

            if suffix:
                path = os.path.join(output_directory, '%s%s%s%s' % (
                    output_prefix, feature_type, separator, suffix))

        return path

    @staticmethod
    def get_unique_file_path_suffix(file_path, separator='-', i=0):
        """Return the minimum number to suffix the file to not overwrite one.
        Example : /tmp/a.txt exists.
            - With file_path='/tmp/b.txt' will return 0.
            - With file_path='/tmp/a.txt' will return 1 (/tmp/a-1.txt)

        :param file_path: The file to check.
        :type file_path: str

        :param separator: The separator to add before the prefix.
        :type separator: str

        :param i: The minimum prefix to check.
        :type i: int

        :return: The minimum prefix you should add to not overwrite a file.
        :rtype: int
        """

        basename = os.path.splitext(file_path)
        if i != 0:
            file_path_test = os.path.join(
                '%s%s%s%s' % (basename[0], separator, i, basename[1]))
        else:
            file_path_test = file_path

        if os.path.isfile(file_path_test):
            return OsmDownloaderDialog.get_unique_file_path_suffix(
                file_path, separator, i + 1)
        else:
            return i

    def require_directory(self):
        """Ensure directory path entered in dialog exist.

        When the path does not exist, this function will ask the user if he
        want to create it or not.

        :raises: CanceledImportDialogError - when user choose 'No' in
            the question dialog for creating directory.
        """
        path = self.output_directory.text()

        if os.path.exists(path):
            return

        title = self.tr('Directory %s not exist') % path
        question = self.tr(
            'Directory %s not exist. Do you want to create it?') % path
        # noinspection PyCallByClass,PyTypeChecker
        answer = QMessageBox.question(
            self, title, question, QMessageBox.Yes | QMessageBox.No)

        if answer == QMessageBox.Yes:
            if len(path) != 0:
                os.makedirs(path)
            else:
                # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
                display_warning_message_box(
                    self,
                    self.tr('InaSAFE error'),
                    self.tr('Output directory can not be empty.'))
                raise CanceledImportDialogError()
        else:
            raise CanceledImportDialogError()

    def download(self, feature_type, output_base_path):
        """Download shapefiles from Kartoza server.

        :param feature_type: What kind of features should be downloaded.
            Currently 'buildings', 'building-points' or 'roads' are supported.
        :type feature_type: str

        :param output_base_path: The base path of the shape file.
        :type output_base_path: str

        :raises: ImportDialogError, CanceledImportDialogError
        """

        # preparing necessary data
        min_longitude = str(self.min_longitude.text())
        min_latitude = str(self.min_latitude.text())
        max_longitude = str(self.max_longitude.text())
        max_latitude = str(self.max_latitude.text())

        box = (
            '{min_longitude},{min_latitude},{max_longitude},'
            '{max_latitude}').format(
                min_longitude=min_longitude,
                min_latitude=min_latitude,
                max_longitude=max_longitude,
                max_latitude=max_latitude
            )
        if feature_type == 'buildings':
            url = '{url}?bbox={box}&qgis_version=2'.format(
                url=self.buildings_url, box=box)
        elif feature_type == 'building-points':
            url = '{url}?bbox={box}&qgis_version=2'.format(
                url=self.building_points_url, box=box)
        else:
            url = '{url}?bbox={box}&qgis_version=2'.format(
                url=self.roads_url, box=box)

        if 'LANG' in os.environ:
            env_lang = os.environ['LANG']
            url += '&lang=%s' % env_lang

        path = tempfile.mktemp('.shp.zip')

        # download and extract it
        self.fetch_zip(url, path, feature_type)
        self.extract_zip(path, output_base_path)

        self.progress_dialog.done(QDialog.Accepted)

    def fetch_zip(self, url, output_path, feature_type):
        """Download zip containing shp file and write to output_path.

        :param url: URL of the zip bundle.
        :type url: str

        :param output_path: Path of output file,
        :type output_path: str

        :param feature_type: What kind of features should be downloaded.
            Currently 'buildings', 'building-points' or 'roads' are supported.
        :type feature_type: str

        :raises: ImportDialogError - when network error occurred
        """
        LOGGER.debug('Downloading file from URL: %s' % url)
        LOGGER.debug('Downloading to: %s' % output_path)

        self.progress_dialog.show()

        # Infinite progress bar when the server is fetching data.
        # The progress bar will be updated with the file size later.
        self.progress_dialog.setMaximum(0)
        self.progress_dialog.setMinimum(0)
        self.progress_dialog.setValue(0)

        # Get a pretty label from feature_type, but not translatable
        label_feature_type = feature_type.replace('-', ' ')

        label_text = self.tr('Fetching %s' % label_feature_type)
        self.progress_dialog.setLabelText(label_text)

        # Download Process
        downloader = FileDownloader(
            self.network_manager, url, output_path, self.progress_dialog)
        try:
            result = downloader.download()
        except IOError as ex:
            raise IOError(ex)

        if result[0] is not True:
            _, error_message = result

            if result[0] == QNetworkReply.OperationCanceledError:
                raise CanceledImportDialogError(error_message)
            else:
                raise DownloadError(error_message)

    @staticmethod
    def extract_zip(zip_path, destination_base_path):
        """Extract different extensions to the destination base path.

        Example : test.zip contains a.shp, a.dbf, a.prj
        and destination_base_path = '/tmp/CT-buildings
        Expected result :
            - /tmp/CT-buildings.shp
            - /tmp/CT-buildings.dbf
            - /tmp/CT-buildings.prj

        If two files in the zip with the same extension, only one will be
        copied.

        :param zip_path: The path of the .zip file
        :type zip_path: str

        :param destination_base_path: The destination base path where the shp
            will be written to.
        :type destination_base_path: str

        :raises: IOError - when not able to open path or output_dir does not
            exist.
        """

        import zipfile

        handle = open(zip_path, 'rb')
        zip_file = zipfile.ZipFile(handle)
        for name in zip_file.namelist():
            extension = os.path.splitext(name)[1]
            output_final_path = u'%s%s' % (destination_base_path, extension)
            output_file = open(output_final_path, 'wb')
            output_file.write(zip_file.read(name))
            output_file.close()

        handle.close()

    def load_shapefile(self, feature_type, base_path):
        """Load downloaded shape file to QGIS Main Window.

        :param feature_type: What kind of features should be downloaded.
            Currently 'buildings', 'building-points' or 'roads' are supported.
        :type feature_type: str

        :param base_path: The base path of the shape file (without extension).
        :type base_path: str

        :raises: FileMissingError - when buildings.shp not exist
        """

        path = '%s.shp' % base_path

        if not os.path.exists(path):
            message = self.tr(
                '%s does not exist. The server does not have any data for '
                'this extent.' % path)
            raise FileMissingError(message)

        self.iface.addVectorLayer(path, feature_type, 'ogr')

        canvas_srid = self.canvas.mapRenderer().destinationCrs().srsid()
        on_the_fly_projection = self.canvas.hasCrsTransformEnabled()
        if canvas_srid != 4326 and not on_the_fly_projection:
            if QGis.QGIS_VERSION_INT >= 20400:
                self.canvas.setCrsTransformEnabled(True)
            else:
                display_warning_message_bar(
                    self.tr('Enable \'on the fly\''),
                    self.tr(
                        'Your current projection is different than EPSG:4326. '
                        'You should enable \'on the fly\' to display '
                        'correctly your layers')
                    )

    def reject(self):
        """Redefinition of the reject() method
        to remove the rectangle selection tool.
        It will call the super method.
        """

        self.canvas.unsetMapTool(self.rectangle_map_tool)
        self.rectangle_map_tool.reset()

        super(OsmDownloaderDialog, self).reject()
 def search_bar(self, query):
   matches = []
   
   progress = QProgressDialog("", "Abort", 0, 50000, self)
   progress.setWindowTitle("Searching...")
   progress.setWindowModality(Qt.Qt.WindowModal)
   progress.setValue(0)
   
   width = self.width()
   height = self.height()
   x = self.x()
   y = self.y()
   
   self.re_flags = re.UNICODE | re.MULTILINE
   
   if not self.ui.chkAdvRegex.isChecked():
     query = re.escape(query)
   
   if not self.ui.chkAdvCase.isChecked():
     self.re_flags |= re.IGNORECASE
   
   if self.ui.chkAdvNewline.isChecked():
     self.re_flags |= re.DOTALL
   
   query_re = re.compile(query, self.re_flags)
   
   dir_filter  = common.qt_to_unicode(self.ui.txtFilterRe.text())
   if dir_filter == "":
     filter_re = script_analytics.DEFAULT_FILTER
   else:
     filter_re = re.compile(dir_filter, re.IGNORECASE | re.DOTALL | re.UNICODE)
   
   self.search_flags = 0
   if self.ui.chkAdvTrans.isChecked():
     self.search_flags |= script_analytics.SEARCH_TRANSLATED
   if self.ui.chkAdvOrig.isChecked():
     self.search_flags |= script_analytics.SEARCH_ORIGINAL
   if self.ui.chkAdvComments.isChecked():
     self.search_flags |= script_analytics.SEARCH_COMMENTS
   
   if self.ui.chkAdvNoTags.isChecked():
     self.search_flags |= script_analytics.SEARCH_NOTAGS
   
   matches = []
   for i, total, filename, partial_results in script_analytics.SA.search_gen(query_re, filter_re, self.search_flags):
     
     if progress.wasCanceled():
       break
     
     progress.setValue(i)
     progress.setMaximum(total)
     progress.setLabelText(filename)
     
     # Re-center the dialog.
     progress_w = progress.geometry().width()
     progress_h = progress.geometry().height()
     
     new_x = x + ((width - progress_w) / 2)
     new_y = y + ((height - progress_h) / 2)
     
     progress.move(new_x, new_y)
     
     matches.extend(partial_results)
   
   progress.close()
   
   return matches
Example #31
0
 def setup_workspace(self):
   data00  = os.path.join(self.iso_dir, DATA00_CPK)
   data01  = os.path.join(self.iso_dir, DATA01_CPK)
   voice   = os.path.join(self.workspace_dir, VOICE_AWB)
   
   self.generate_directories()
   
   progress = QProgressDialog("", QtCore.QString(), 0, 11000, self)
   progress.setWindowTitle("Setting up workspace...")
   progress.setWindowModality(Qt.Qt.WindowModal)
   progress.setMinimumDuration(0)
   progress.setValue(0)
   progress.setAutoClose(False)
   progress.setAutoReset(False)
   
   progress.setLabelText("Creating directories...")
   
   # Do the easy stuff first.
   if not os.path.isdir(self.changes_dir):
     os.makedirs(self.changes_dir)
   progress.setValue(progress.value() + 1)
   
   if not os.path.isdir(self.backup_dir):
     os.makedirs(self.backup_dir)
   progress.setValue(progress.value() + 1)
   
   if not os.path.isdir(self.editor_data_dir):
     os.makedirs(self.editor_data_dir)
   progress.setValue(progress.value() + 1)
   
   thread_fns = [
     {"target": extract_cpk, "kwargs": {"filename": data00, "out_dir": self.data00_dir}},
     {"target": extract_cpk, "kwargs": {"filename": data01, "out_dir": self.data01_dir}},
   ]
   
   # Going to capture stdout because I don't feel like
   # rewriting the extract functions to play nice with GUI.
   stdout      = sys.stdout
   sys.stdout  = cStringIO.StringIO()
   
   for thread_fn in thread_fns:
     thread = threading.Thread(**thread_fn)
     thread.start()
     
     while thread.isAlive():
       thread.join(THREAD_TIMEOUT)
       
       output = [line for line in sys.stdout.getvalue().split('\n') if len(line) > 0]
       progress.setValue(progress.value() + len(output))
       if len(output) > 0:
         progress.setLabelText("Extracting %s..." % output[-1])
       
       sys.stdout = cStringIO.StringIO()
   
   sys.stdout = stdout
   
   # Give us an ISO directory for the editor to place modified files in.
   progress.setLabelText("Copying ISO files...")
   
   # ISO directory needs to not exist for copytree.
   if os.path.isdir(self.edited_iso_dir):
     shutil.rmtree(self.edited_iso_dir)
   
   # One more thing we want threaded so it doesn't lock up the GUI.
   thread = threading.Thread(target = shutil.copytree, kwargs = {"src": self.iso_dir, "dst": self.edited_iso_dir})
   thread.start()
   
   while thread.isAlive():
     thread.join(THREAD_TIMEOUT)
     progress.setLabelText("Copying ISO files...")
     # It has to increase by some amount or it won't update and the UI will lock up.
     progress.setValue(progress.value() + 1)
     
   # shutil.copytree(self.iso_dir, self.edited_iso_dir)
   progress.setValue(progress.value() + 1)
   
   # Files we want to make blank, because they're unnecessary.
   blank_files = [
     os.path.join(self.edited_iso_dir, "PSP_GAME", "INSDIR", "UMDIMAGE.DAT"),
     os.path.join(self.edited_iso_dir, "PSP_GAME", "SYSDIR", "UPDATE", "DATA.BIN"),
     os.path.join(self.edited_iso_dir, "PSP_GAME", "SYSDIR", "UPDATE", "EBOOT.BIN"),
     os.path.join(self.edited_iso_dir, "PSP_GAME", "SYSDIR", "UPDATE", "PARAM.SFO"),
   ]
   
   for blank in blank_files:
     with open(blank, "wb") as f:
       pass
   
   # NOTE: To re-enable this, Simply remove the hashtag before the codes.
   # Copy the decrypted EBOOT into the ISO folder and apply our hacks to it.
   # progress.setLabelText("Hacking EBOOT...")
   # progress.setValue(progress.value() + 1)
   
   # hacked_eboot = BitStream(filename = self.eboot_path)
   # hacked_eboot = apply_eboot_patches(hacked_eboot)
   # with open(os.path.join(self.edited_iso_dir, "PSP_GAME", "SYSDIR", "EBOOT.BIN"), "wb") as f:
     #hacked_eboot.tofile(f)
   # shutil.copy(self.eboot_path, os.path.join(self.edited_iso_dir, "PSP_GAME", "SYSDIR", "EBOOT.BIN"))
   
   progress.setLabelText("Extracting editor data...")
   progress.setValue(progress.value() + 1)
   
   # Extract the editor data.
   editor_data = zipfile.ZipFile("data/editor_data.zip", "r")
   editor_data.extractall(self.editor_data_dir)
   editor_data.close()
   
   progress.setValue(progress.maximum())
   progress.close()
   
   self.ui.grpStep4.setEnabled(False)
   self.ui.grpStep5.setEnabled(True)
Example #32
0
def import_labeling_layer(labelLayer, labelingSlots, parent_widget=None):
    """
    Prompt the user for layer import settings, and perform the layer import.
    :param labelLayer: The top label layer source
    :param labelingSlots: An instance of LabelingGui.LabelingSlots
    :param parent_widget: The Qt GUI parent object
    """
    writeSeeds = labelingSlots.labelInput
    assert isinstance(
        writeSeeds,
        lazyflow.graph.Slot), "slot is of type %r" % (type(writeSeeds))
    opLabels = writeSeeds.getRealOperator()
    assert isinstance(opLabels, lazyflow.graph.Operator
                      ), "slot's operator is of type %r" % (type(opLabels))

    recentlyImported = PreferencesManager().get('labeling',
                                                'recently imported')
    mostRecentProjectPath = PreferencesManager().get('shell',
                                                     'recently opened')
    mostRecentImageFile = PreferencesManager().get('DataSelection',
                                                   'recent image')
    if recentlyImported:
        defaultDirectory = os.path.split(recentlyImported)[0]
    elif mostRecentProjectPath:
        defaultDirectory = os.path.split(mostRecentProjectPath)[0]
    elif mostRecentImageFile:
        defaultDirectory = os.path.split(mostRecentImageFile)[0]
    else:
        defaultDirectory = os.path.expanduser('~')

    fileNames = DataSelectionGui.getImageFileNamesToOpen(
        parent_widget, defaultDirectory)
    fileNames = map(str, fileNames)

    if not fileNames:
        return

    PreferencesManager().set('labeling', 'recently imported', fileNames[0])

    try:
        # Initialize operators
        opImport = OpInputDataReader(parent=opLabels.parent)
        opCache = OpArrayCache(parent=opLabels.parent)
        opMetadataInjector = OpMetadataInjector(parent=opLabels.parent)
        opReorderAxes = OpReorderAxes(parent=opLabels.parent)

        # Set up the pipeline as follows:
        #
        #   opImport --> opCache --> opMetadataInjector --------> opReorderAxes --(inject via setInSlot)--> labelInput
        #                           /                            /
        #   User-specified axisorder    labelInput.meta.axistags

        opImport.WorkingDirectory.setValue(defaultDirectory)
        opImport.FilePath.setValue(fileNames[0] if len(fileNames) ==
                                   1 else os.path.pathsep.join(fileNames))
        assert opImport.Output.ready()

        opCache.blockShape.setValue(opImport.Output.meta.shape)
        opCache.Input.connect(opImport.Output)
        assert opCache.Output.ready()

        opMetadataInjector.Input.connect(opCache.Output)
        metadata = opCache.Output.meta.copy()
        opMetadataInjector.Metadata.setValue(metadata)
        opReorderAxes.Input.connect(opImport.Output)

        # Transpose the axes for assignment to the labeling operator.
        opReorderAxes.AxisOrder.setValue(writeSeeds.meta.getAxisKeys())

        # We'll show a little window with a busy indicator while the data is loading
        busy_dlg = QProgressDialog(parent=parent_widget)
        busy_dlg.setLabelText("Importing Label Data...")
        busy_dlg.setCancelButton(None)
        busy_dlg.setMinimum(100)
        busy_dlg.setMaximum(100)

        def close_busy_dlg(*args):
            QApplication.postEvent(busy_dlg, QCloseEvent())

        # Load the data from file into our cache
        # When it's done loading, close the progress dialog.
        req = opCache.Output[:]
        req.notify_finished(close_busy_dlg)
        req.notify_failed(close_busy_dlg)
        req.submit()
        busy_dlg.exec_()

        readData = req.result

        maxLabels = len(labelingSlots.labelNames.value)
        unique_read_labels, readLabelCounts = numpy.unique(readData,
                                                           return_counts=True)
        labelInfo = (maxLabels, (unique_read_labels, readLabelCounts))
        del readData

        # Ask the user how to interpret the data.
        settingsDlg = LabelImportOptionsDlg(parent_widget, fileNames,
                                            opMetadataInjector.Output,
                                            labelingSlots.labelInput,
                                            labelInfo)

        def handle_updated_axes():
            # The user is specifying a new interpretation of the file's axes
            updated_axisorder = str(settingsDlg.axesEdit.text())
            metadata = opMetadataInjector.Metadata.value.copy()
            metadata.axistags = vigra.defaultAxistags(updated_axisorder)
            opMetadataInjector.Metadata.setValue(metadata)

        settingsDlg.axesEdit.editingFinished.connect(handle_updated_axes)

        dlg_result = settingsDlg.exec_()
        if dlg_result != LabelImportOptionsDlg.Accepted:
            return

        # Get user's chosen label mapping from dlg
        labelMapping = settingsDlg.labelMapping

        # Get user's chosen offsets.
        # Offsets in dlg only include the file axes, not the 5D axes expected by the label input,
        # so expand them to full 5D
        axes_5d = opReorderAxes.Output.meta.getAxisKeys()
        tagged_offsets = collections.OrderedDict(
            zip(axes_5d, [0] * len(axes_5d)))
        tagged_offsets.update(
            dict(
                zip(opMetadataInjector.Output.meta.getAxisKeys(),
                    settingsDlg.imageOffsets)))
        imageOffsets = tagged_offsets.values()

        # Optimization if mapping is identity
        if labelMapping.keys() == labelMapping.values():
            labelMapping = None

        # This will be fast (it's already cached)
        label_data = opReorderAxes.Output[:].wait()

        # Map input labels to output labels
        if labelMapping:
            # There are other ways to do a relabeling (e.g skimage.segmentation.relabel_sequential)
            # But this supports potentially huge values of unique_read_labels (in the billions),
            # without needing GB of RAM.
            mapping_indexes = numpy.searchsorted(unique_read_labels,
                                                 label_data)
            new_labels = numpy.array(
                [labelMapping[x] for x in unique_read_labels])
            label_data[:] = new_labels[mapping_indexes]

        label_roi = numpy.array(roiFromShape(opReorderAxes.Output.meta.shape))
        label_roi += imageOffsets
        label_slice = roiToSlice(*label_roi)
        writeSeeds[label_slice] = label_data

    finally:
        opReorderAxes.cleanUp()
        opMetadataInjector.cleanUp()
        opCache.cleanUp()
        opImport.cleanUp()
class CpkPacker():
  def __init__(self, parent = None):
    self.parent   = parent
    self.process  = None
  
  def __pack_cpk(self, csv, cpk):
    
    self.progress.setValue(0)
    self.progress.setMaximum(1000)
    self.progress.setLabelText("Building %s" % cpk)
    
    process = QProcess()
    process.start("tools/cpkmakec", [csv, cpk, "-align=2048", "-mode=FILENAME"])
    
    percent = 0
    
    while not process.waitForFinished(100):
    
      output = QString(process.readAll())
      output = output.split("\n", QString.SkipEmptyParts)
      
      for line in output:
        line = common.qt_to_unicode(line)
        match = OUTPUT_RE.search(line)
        
        if match == None:
          continue
        
        percent = float(match.group(1)) * 1000
      
      self.progress.setValue(percent)
      percent += 1
  
  def __cache_outdated(self, src_dir, cache_file):
    if not os.path.isfile(cache_file):
      return True
    
    cache_updated = os.path.getmtime(cache_file)
    
    for src_file in list_all_files(src_dir):
      if os.path.getmtime(src_file) > cache_updated:
        return True
    
    return False

  def create_archives(self):
    
    try:
      self.width = self.parent.width()
      self.height = self.parent.height()
      self.x = self.parent.x()
      self.y = self.parent.y()
    except:
      self.width = 1920
      self.height = 1080
      self.x = 0
      self.y = 0
    
    self.progress = QProgressDialog("Reading...", QtCore.QString(), 0, 7600, self.parent)
    self.progress.setWindowModality(Qt.Qt.WindowModal)
    self.progress.setValue(0)
    self.progress.setAutoClose(False)
    self.progress.setMinimumDuration(0)
    
    USRDIR     = os.path.join(common.editor_config.iso_dir, "PSP_GAME", "USRDIR")
    eboot_path = os.path.join(common.editor_config.iso_dir, "PSP_GAME", "SYSDIR", "EBOOT.BIN")
    
    eboot = BitStream(filename = eboot_path)
    eboot = eboot_patch.apply_eboot_patches(eboot)
    
    # So we can loop. :)
    ARCHIVE_INFO = [
      {
        "dir":  common.editor_config.data00_dir,
        "cpk":  os.path.join(USRDIR, "data00.cpk"),
        "csv":  os.path.join("data", "data00.csv" if not common.editor_config.quick_build else "data00-quick.csv"),
        "name": "data00.cpk",
        "pack": common.editor_config.pack_data00,
      },
      {
        "dir":  common.editor_config.data01_dir,
        "cpk":  os.path.join(USRDIR, "data01.cpk"),
        "csv":  os.path.join("data", "data01.csv" if not common.editor_config.quick_build else "data01-quick.csv"),
        "name": "data01.cpk",
        "pack": common.editor_config.pack_data01,
      },
    ]
    
    # temp_dir = tempfile.mkdtemp(prefix = "sdse-")
    temp_dir = common.editor_config.build_cache
    
    for archive in ARCHIVE_INFO:
      
      if not archive["pack"]:
        continue
      
      self.progress.setWindowTitle("Building " + archive["name"])
      
      toc_info = {}
      file_list = None
      
      if archive["toc"]:
        file_list = []
        
        toc = get_toc(eboot, archive["toc"])
        
        for entry in toc:
          filename  = entry["filename"]
          pos_pos   = entry["file_pos_pos"]
          len_pos   = entry["file_len_pos"]
          
          toc_info[filename] = [pos_pos, len_pos]
          file_list.append(filename)
      
      # Causes memory issues if I use the original order, for whatever reason.
      file_list = None
      
      csv_template_f  = open(archive["csv"], "rb")
      csv_template    = csv.reader(csv_template_f)
      
      csv_out_path    = os.path.join(temp_dir, "cpk.csv")
      csv_out_f       = open(csv_out_path, "wb")
      csv_out         = csv.writer(csv_out_f)
      
      for row in csv_template:
        if len(row) < 4:
          continue
        
        base_path = row[0]
        
        real_path = os.path.join(archive["dir"], base_path)
        out_path  = os.path.join(temp_dir, archive["name"], base_path)
        
        self.progress.setValue(self.progress.value() + 1)
        self.progress.setLabelText("Reading...\n%s" % real_path)
        
        # All items in the CPK list should be files.
        # Therefore, if we have a directory, then it needs to be packed.
        if os.path.isdir(real_path):
          if self.__cache_outdated(real_path, out_path):
            out_dir = os.path.dirname(out_path)
            try:
              os.makedirs(out_dir)
            except:
              pass
            
            data = pack_dir(real_path)
            with open(out_path, "wb") as out_file:
              data.tofile(out_file)
            del data
            
        elif os.path.isfile(real_path):
        # If it's a file, though, we can just use it directly.
          out_path = real_path
          
        row[0] = out_path
        csv_out.writerow(row)
      
      csv_template_f.close()
      csv_out_f.close()
      
      self.__pack_cpk(csv_out_path, archive["cpk"])
      
      # We're playing fast and loose with the file count anyway, so why not?
      self.file_count += 1
      self.progress.setValue(self.file_count)
      self.progress.setLabelText("Saving " + archive["name"] + "...")
      
      if archive["toc"]:
        for entry in table_of_contents:
          if not entry in toc_info:
            _LOGGER.warning("%s missing from %s table of contents." % (entry, archive["name"]))
            continue
          
          file_pos  = table_of_contents[entry]["pos"]
          file_size = table_of_contents[entry]["size"]
          
          eboot.overwrite(BitStream(uintle = file_pos, length = 32),  toc_info[entry][0] * 8)
          eboot.overwrite(BitStream(uintle = file_size, length = 32), toc_info[entry][1] * 8)
      
      del table_of_contents
    
    self.progress.setWindowTitle("Building...")
    self.progress.setLabelText("Saving EBOOT.BIN...")
    self.progress.setValue(self.progress.maximum())
    
    with open(eboot_path, "wb") as f:
      eboot.tofile(f)
      
    # Text replacement
    to_replace = eboot_text.get_eboot_text()
    for replacement in to_replace:
    
      orig = bytearray(replacement.orig, encoding = replacement.enc)
      
      # If they left something blank, write the original text back.
      if len(replacement.text) == 0:
        data = orig
      else:
        data = bytearray(replacement.text, encoding = replacement.enc)
      
      pos  = replacement.pos.int + eboot_offset
      
      padding = len(orig) - len(data)
      if padding > 0:
        # Null bytes to fill the rest of the space the original took.
        data.extend(bytearray(padding))
      
      data = ConstBitStream(bytes = data)
      eboot.overwrite(data, pos * 8)
    
    eboot_out = os.path.join(common.editor_config.iso_dir, "PSP_GAME", "SYSDIR", "EBOOT.BIN")
    
    with open(eboot_out, "wb") as f:
      eboot.tofile(f)
    
    self.progress.close()
Example #34
0
class OsmDownloaderDialog(QDialog, FORM_CLASS):
    """Downloader for OSM data."""
    def __init__(self, parent=None, iface=None):
        """Constructor for import dialog.

        :param parent: Optional widget to use as parent
        :type parent: QWidget

        :param iface: An instance of QGisInterface
        :type iface: QGisInterface
        """
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setupUi(self)

        self.setWindowTitle(self.tr('InaSAFE OpenStreetMap Downloader'))

        self.iface = iface
        self.buildings_url = 'http://osm.linfiniti.com/buildings-shp'
        self.building_points_url = \
            'http://osm.linfiniti.com/building-points-shp'
        self.roads_url = 'http://osm.linfiniti.com/roads-shp'

        self.help_context = 'openstreetmap_downloader'
        # creating progress dialog for download
        self.progress_dialog = QProgressDialog(self)
        self.progress_dialog.setAutoClose(False)
        title = self.tr('InaSAFE OpenStreetMap Downloader')
        self.progress_dialog.setWindowTitle(title)
        # Set up context help
        help_button = self.button_box.button(QtGui.QDialogButtonBox.Help)
        help_button.clicked.connect(self.show_help)

        self.show_info()

        # set up the validator for the file name prefix
        expression = QRegExp('^[A-Za-z0-9-_]*$')
        validator = QRegExpValidator(expression, self.filename_prefix)
        self.filename_prefix.setValidator(validator)

        # Set Proxy in webpage
        proxy = get_proxy()
        self.network_manager = QNetworkAccessManager(self)
        if proxy is not None:
            self.network_manager.setProxy(proxy)
        self.restore_state()

        # Setup the rectangle map tool
        self.canvas = iface.mapCanvas()
        self.rectangle_map_tool = \
            RectangleMapTool(self.canvas)
        self.rectangle_map_tool.rectangle_created.connect(
            self.update_extent_from_rectangle)
        self.button_extent_rectangle.clicked.connect(
            self.drag_rectangle_on_map_canvas)

        # Setup pan tool
        self.pan_tool = QgsMapToolPan(self.canvas)
        self.canvas.setMapTool(self.pan_tool)
        self.update_extent_from_map_canvas()

    def show_info(self):
        """Show usage info to the user."""
        # Read the header and footer html snippets
        header = html_header()
        footer = html_footer()

        string = header

        heading = m.Heading(self.tr('OSM Downloader'), **INFO_STYLE)
        body = self.tr(
            'This tool will fetch building (\'structure\') or road ('
            '\'highway\') data from the OpenStreetMap project for you. '
            'The downloaded data will have InaSAFE keywords defined and a '
            'default QGIS style applied. To use this tool effectively:')
        tips = m.BulletedList()
        tips.add(
            self.
            tr('Your current extent, when opening this window, will be used to '
               'determine the area for which you want data to be retrieved.'
               'You can interactively select the area by using the '
               '\'select on map\' button - which will temporarily hide this '
               'window and allow you to drag a rectangle on the map. After you '
               'have finished dragging the rectangle, this window will '
               'reappear.'))
        tips.add(
            self.
            tr('Check the output directory is correct. Note that the saved '
               'dataset will be called either roads.shp or buildings.shp (and '
               'associated files).'))
        tips.add(
            self.
            tr('By default simple file names will be used (e.g. roads.shp, '
               'buildings.shp). If you wish you can specify a prefix to '
               'add in front of this default name. For example using a prefix '
               'of \'padang-\' will cause the downloaded files to be saved as '
               '\'padang-roads.shp\' and \'padang-buildings.shp\'. Note that '
               'the only allowed prefix characters are A-Z, a-z, 0-9 and the '
               'characters \'-\' and \'_\'. You can leave this blank if you '
               'prefer.'))
        tips.add(
            self.
            tr('If a dataset already exists in the output directory it will be '
               'overwritten.'))
        tips.add(
            self.
            tr('This tool requires a working internet connection and fetching '
               'buildings or roads will consume your bandwidth.'))
        tips.add(
            m.Link(
                'http://www.openstreetmap.org/copyright',
                text=self.tr(
                    'Downloaded data is copyright OpenStreetMap contributors'
                    ' (click for more info).')))
        message = m.Message()
        message.add(heading)
        message.add(body)
        message.add(tips)
        string += message.to_html()
        string += footer

        self.web_view.setHtml(string)

    def restore_state(self):
        """ Read last state of GUI from configuration file."""
        settings = QSettings()
        try:
            last_path = settings.value('directory', type=str)
        except TypeError:
            last_path = ''
        self.output_directory.setText(last_path)

    def save_state(self):
        """ Store current state of GUI to configuration file """
        settings = QSettings()
        settings.setValue('directory', self.output_directory.text())

    def show_help(self):
        """Load the help text for the dialog."""
        show_context_help(self.help_context)

    def update_extent(self, extent):
        """Update extent value in GUI based from an extent.

        :param extent: A list in the form [xmin, ymin, xmax, ymax] where all
            coordinates provided are in Geographic / EPSG:4326.
        :type extent: list
        """
        self.min_longitude.setText(str(extent[0]))
        self.min_latitude.setText(str(extent[1]))
        self.max_longitude.setText(str(extent[2]))
        self.max_latitude.setText(str(extent[3]))

    def update_extent_from_map_canvas(self):
        """Update extent value in GUI based from value in map.

        .. note:: Delegates to update_extent()
        """

        self.groupBox.setTitle(self.tr('Bounding box from the map canvas'))
        # Get the extent as [xmin, ymin, xmax, ymax]
        extent = viewport_geo_array(self.iface.mapCanvas())
        self.update_extent(extent)

    def update_extent_from_rectangle(self):
        """Update extent value in GUI based from the QgsMapTool rectangle.

        .. note:: Delegates to update_extent()
        """

        self.show()
        self.canvas.unsetMapTool(self.rectangle_map_tool)
        self.canvas.setMapTool(self.pan_tool)

        rectangle = self.rectangle_map_tool.rectangle()
        if rectangle:
            self.groupBox.setTitle(self.tr('Bounding box from rectangle'))
            extent = rectangle_geo_array(rectangle, self.iface.mapCanvas())
            self.update_extent(extent)

    def validate_extent(self):
        """Validate the bounding box before user click OK to download.

        :return: True if the bounding box is valid, otherwise False
        :rtype: bool
        """
        min_latitude = float(str(self.min_latitude.text()))
        max_latitude = float(str(self.max_latitude.text()))
        min_longitude = float(str(self.min_longitude.text()))
        max_longitude = float(str(self.max_longitude.text()))

        # min_latitude < max_latitude
        if min_latitude >= max_latitude:
            return False

        # min_longitude < max_longitude
        if min_longitude >= max_longitude:
            return False

        # -90 <= latitude <= 90
        if min_latitude < -90 or min_latitude > 90:
            return False
        if max_latitude < -90 or max_latitude > 90:
            return False

        # -180 <= longitude <= 180
        if min_longitude < -180 or min_longitude > 180:
            return False
        if max_longitude < -180 or max_longitude > 180:
            return False

        return True

    @pyqtSignature('')  # prevents actions being handled twice
    def on_directory_button_clicked(self):
        """Show a dialog to choose directory."""
        # noinspection PyCallByClass,PyTypeChecker
        self.output_directory.setText(
            QFileDialog.getExistingDirectory(
                self, self.tr('Select download directory')))

    def drag_rectangle_on_map_canvas(self):
        """Hide the dialog and allow the user to draw a rectangle."""

        self.hide()
        self.rectangle_map_tool.reset()
        self.canvas.unsetMapTool(self.pan_tool)
        self.canvas.setMapTool(self.rectangle_map_tool)

    def accept(self):
        """Do osm download and display it in QGIS."""
        error_dialog_title = self.tr('InaSAFE OpenStreetMap Downloader Error')

        # Lock the groupbox
        self.groupBox.setDisabled(True)

        # Validate extent
        valid_flag = self.validate_extent()
        if not valid_flag:
            message = self.tr(
                'The bounding box is not valid. Please make sure it is '
                'valid or check your projection!')
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            display_warning_message_box(self, error_dialog_title, message)
            # Unlock the groupbox
            self.groupBox.setEnabled(True)
            return

        # Get all the feature types
        index = self.feature_type.currentIndex()
        if index == 0:
            feature_types = ['buildings', 'roads', 'building-points']
        elif index == 1:
            feature_types = ['buildings']
        elif index == 2:
            feature_types = ['building-points']
        else:
            feature_types = ['roads']

        try:
            self.save_state()
            self.require_directory()
            for feature_type in feature_types:

                output_directory = self.output_directory.text()
                output_prefix = self.filename_prefix.text()
                overwrite = self.overwrite_checkBox.isChecked()
                output_base_file_path = self.get_output_base_path(
                    output_directory, output_prefix, feature_type, overwrite)

                self.download(feature_type, output_base_file_path)
                try:
                    self.load_shapefile(feature_type, output_base_file_path)
                except FileMissingError as exception:
                    display_warning_message_box(self, error_dialog_title,
                                                exception.message)
            self.done(QDialog.Accepted)
            self.rectangle_map_tool.reset()

        except CanceledImportDialogError:
            # don't show anything because this exception raised
            # when user canceling the import process directly
            pass
        except Exception as exception:  # pylint: disable=broad-except
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            display_warning_message_box(self, error_dialog_title,
                                        exception.message)

            self.progress_dialog.cancel()

        finally:
            # Unlock the groupbox
            self.groupBox.setEnabled(True)

    def get_output_base_path(self, output_directory, output_prefix,
                             feature_type, overwrite):
        """Get a full base name path to save the shapefile.

        :param output_directory: The directory where to put results.
        :type output_directory: str

        :param output_prefix: The prefix to add for the shapefile.
        :type output_prefix: str

        :param feature_type: What kind of features should be downloaded.
            Currently 'buildings', 'building-points' or 'roads' are supported.
        :type feature_type: str

        :param overwrite: Boolean to know if we can overwrite existing files.
        :type overwrite: bool

        :return: The base path.
        :rtype: str
        """
        path = os.path.join(output_directory,
                            '%s%s' % (output_prefix, feature_type))

        if overwrite:

            # If a shapefile exists, we must remove it (only the .shp)
            shp = '%s.shp' % path
            if os.path.isfile(shp):
                os.remove(shp)

        else:
            separator = '-'
            suffix = self.get_unique_file_path_suffix('%s.shp' % path,
                                                      separator)

            if suffix:
                path = os.path.join(
                    output_directory, '%s%s%s%s' %
                    (output_prefix, feature_type, separator, suffix))

        return path

    @staticmethod
    def get_unique_file_path_suffix(file_path, separator='-', i=0):
        """Return the minimum number to suffix the file to not overwrite one.
        Example : /tmp/a.txt exists.
            - With file_path='/tmp/b.txt' will return 0.
            - With file_path='/tmp/a.txt' will return 1 (/tmp/a-1.txt)

        :param file_path: The file to check.
        :type file_path: str

        :param separator: The separator to add before the prefix.
        :type separator: str

        :param i: The minimum prefix to check.
        :type i: int

        :return: The minimum prefix you should add to not overwrite a file.
        :rtype: int
        """

        basename = os.path.splitext(file_path)
        if i != 0:
            file_path_test = os.path.join(
                '%s%s%s%s' % (basename[0], separator, i, basename[1]))
        else:
            file_path_test = file_path

        if os.path.isfile(file_path_test):
            return OsmDownloaderDialog.get_unique_file_path_suffix(
                file_path, separator, i + 1)
        else:
            return i

    def require_directory(self):
        """Ensure directory path entered in dialog exist.

        When the path does not exist, this function will ask the user if he
        want to create it or not.

        :raises: CanceledImportDialogError - when user choose 'No' in
            the question dialog for creating directory.
        """
        path = self.output_directory.text()

        if os.path.exists(path):
            return

        title = self.tr('Directory %s not exist') % path
        question = self.tr(
            'Directory %s not exist. Do you want to create it?') % path
        # noinspection PyCallByClass,PyTypeChecker
        answer = QMessageBox.question(self, title, question,
                                      QMessageBox.Yes | QMessageBox.No)

        if answer == QMessageBox.Yes:
            if len(path) != 0:
                os.makedirs(path)
            else:
                # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
                display_warning_message_box(
                    self, self.tr('InaSAFE error'),
                    self.tr('Output directory can not be empty.'))
                raise CanceledImportDialogError()
        else:
            raise CanceledImportDialogError()

    def download(self, feature_type, output_base_path):
        """Download shapefiles from Kartoza server.

        :param feature_type: What kind of features should be downloaded.
            Currently 'buildings', 'building-points' or 'roads' are supported.
        :type feature_type: str

        :param output_base_path: The base path of the shape file.
        :type output_base_path: str

        :raises: ImportDialogError, CanceledImportDialogError
        """

        # preparing necessary data
        min_longitude = str(self.min_longitude.text())
        min_latitude = str(self.min_latitude.text())
        max_longitude = str(self.max_longitude.text())
        max_latitude = str(self.max_latitude.text())

        box = ('{min_longitude},{min_latitude},{max_longitude},'
               '{max_latitude}').format(min_longitude=min_longitude,
                                        min_latitude=min_latitude,
                                        max_longitude=max_longitude,
                                        max_latitude=max_latitude)
        if feature_type == 'buildings':
            url = '{url}?bbox={box}&qgis_version=2'.format(
                url=self.buildings_url, box=box)
        elif feature_type == 'building-points':
            url = '{url}?bbox={box}&qgis_version=2'.format(
                url=self.building_points_url, box=box)
        else:
            url = '{url}?bbox={box}&qgis_version=2'.format(url=self.roads_url,
                                                           box=box)

        if 'LANG' in os.environ:
            env_lang = os.environ['LANG']
            url += '&lang=%s' % env_lang

        path = tempfile.mktemp('.shp.zip')

        # download and extract it
        self.fetch_zip(url, path, feature_type)
        self.extract_zip(path, output_base_path)

        self.progress_dialog.done(QDialog.Accepted)

    def fetch_zip(self, url, output_path, feature_type):
        """Download zip containing shp file and write to output_path.

        :param url: URL of the zip bundle.
        :type url: str

        :param output_path: Path of output file,
        :type output_path: str

        :param feature_type: What kind of features should be downloaded.
            Currently 'buildings', 'building-points' or 'roads' are supported.
        :type feature_type: str

        :raises: ImportDialogError - when network error occurred
        """
        LOGGER.debug('Downloading file from URL: %s' % url)
        LOGGER.debug('Downloading to: %s' % output_path)

        self.progress_dialog.show()

        # Infinite progress bar when the server is fetching data.
        # The progress bar will be updated with the file size later.
        self.progress_dialog.setMaximum(0)
        self.progress_dialog.setMinimum(0)
        self.progress_dialog.setValue(0)

        # Get a pretty label from feature_type, but not translatable
        label_feature_type = feature_type.replace('-', ' ')

        label_text = self.tr('Fetching %s' % label_feature_type)
        self.progress_dialog.setLabelText(label_text)

        # Download Process
        downloader = FileDownloader(self.network_manager, url, output_path,
                                    self.progress_dialog)
        try:
            result = downloader.download()
        except IOError as ex:
            raise IOError(ex)

        if result[0] is not True:
            _, error_message = result

            if result[0] == QNetworkReply.OperationCanceledError:
                raise CanceledImportDialogError(error_message)
            else:
                raise DownloadError(error_message)

    @staticmethod
    def extract_zip(zip_path, destination_base_path):
        """Extract different extensions to the destination base path.

        Example : test.zip contains a.shp, a.dbf, a.prj
        and destination_base_path = '/tmp/CT-buildings
        Expected result :
            - /tmp/CT-buildings.shp
            - /tmp/CT-buildings.dbf
            - /tmp/CT-buildings.prj

        If two files in the zip with the same extension, only one will be
        copied.

        :param zip_path: The path of the .zip file
        :type zip_path: str

        :param destination_base_path: The destination base path where the shp
            will be written to.
        :type destination_base_path: str

        :raises: IOError - when not able to open path or output_dir does not
            exist.
        """

        import zipfile

        handle = open(zip_path, 'rb')
        zip_file = zipfile.ZipFile(handle)
        for name in zip_file.namelist():
            extension = os.path.splitext(name)[1]
            output_final_path = u'%s%s' % (destination_base_path, extension)
            output_file = open(output_final_path, 'wb')
            output_file.write(zip_file.read(name))
            output_file.close()

        handle.close()

    def load_shapefile(self, feature_type, base_path):
        """Load downloaded shape file to QGIS Main Window.

        :param feature_type: What kind of features should be downloaded.
            Currently 'buildings', 'building-points' or 'roads' are supported.
        :type feature_type: str

        :param base_path: The base path of the shape file (without extension).
        :type base_path: str

        :raises: FileMissingError - when buildings.shp not exist
        """

        path = '%s.shp' % base_path

        if not os.path.exists(path):
            message = self.tr(
                '%s does not exist. The server does not have any data for '
                'this extent.' % path)
            raise FileMissingError(message)

        self.iface.addVectorLayer(path, feature_type, 'ogr')

        canvas_srid = self.canvas.mapRenderer().destinationCrs().srsid()
        on_the_fly_projection = self.canvas.hasCrsTransformEnabled()
        if canvas_srid != 4326 and not on_the_fly_projection:
            if QGis.QGIS_VERSION_INT >= 20400:
                self.canvas.setCrsTransformEnabled(True)
            else:
                display_warning_message_bar(
                    self.tr('Enable \'on the fly\''),
                    self.tr(
                        'Your current projection is different than EPSG:4326. '
                        'You should enable \'on the fly\' to display '
                        'correctly your layers'))

    def reject(self):
        """Redefinition of the reject() method
        to remove the rectangle selection tool.
        It will call the super method.
        """

        self.canvas.unsetMapTool(self.rectangle_map_tool)
        self.rectangle_map_tool.reset()

        super(OsmDownloaderDialog, self).reject()
Example #35
0
class OsmDownloader(QDialog, Ui_OsmDownloaderBase):
    """Downloader for OSM data."""

    def __init__(self, parent=None, iface=None):
        """Constructor for import dialog.

        :param parent: Optional widget to use as parent
        :type parent: QWidget

        :param iface: An instance of QGisInterface
        :type iface: QGisInterface
        """
        QDialog.__init__(self, parent)
        self.parent = parent
        self.setupUi(self)

        self.setWindowTitle(self.tr('InaSAFE OpenStreetMap Downloader'))

        self.iface = iface
        self.url = "http://osm.linfiniti.com/buildings-shp"

        # creating progress dialog for download
        self.progressDialog = QProgressDialog(self)
        self.progressDialog.setAutoClose(False)
        myTitle = self.tr("InaSAFE OpenStreetMap Downloader")
        self.progressDialog.setWindowTitle(myTitle)
        # Set up context help
        helpButton = self.buttonBox.button(QtGui.QDialogButtonBox.Help)
        QtCore.QObject.connect(helpButton, QtCore.SIGNAL('clicked()'),
                               self.show_help)

        self.show_info()

        self.network_manager = QNetworkAccessManager(self)
        self.restore_state()
        self.update_extent()

    def show_info(self):
        """Show usage info to the user."""
        # Read the header and footer html snippets
        header = html_header()
        footer = html_footer()

        string = header

        heading = m.Heading(self.tr('OSM Downloader'), **INFO_STYLE)
        body = self.tr(
            'This tool will fetch building (\'structure\') data from the '
            'OpenStreetMap project for you. The downloaded data will have '
            'InaSAFE keywords defined and a default QGIS style applied. To '
            'use this tool effectively:'
        )
        tips = m.BulletedList()
        tips.add(self.tr(
            'Use QGIS to zoom in to the area for which you want building data '
            'to be retrieved.'))
        tips.add(self.tr(
            'Check the output directory is correct. Note that the saved '
            'dataset will be called buildings.shp (and its associated files).'
        ))
        tips.add(self.tr(
            'If a dataset already exists in the output directory it will be '
            'overwritten.'
        ))
        tips.add(self.tr(
            'This tool requires a working internet connection and fetching '
            'buildings will consume your bandwidth.'))
        tips.add(m.Link(
            'http://www.openstreetmap.org/copyright',
            text=self.tr(
                'Downloaded data is copyright OpenStreetMap contributors'
                ' (click for more info).')
        ))
        message = m.Message()
        message.add(heading)
        message.add(body)
        message.add(tips)
        string += message.to_html()
        string += footer

        self.webView.setHtml(string)

    def restore_state(self):
        """ Read last state of GUI from configuration file."""
        mySetting = QSettings()
        self.outDir.setText(mySetting.value('directory'))

    def save_state(self):
        """ Store current state of GUI to configuration file """
        mySetting = QSettings()
        mySetting.setValue('directory', self.outDir.text())

    def show_help(self):
        """Load the help text for the dialog."""
        show_context_help('openstreetmap_downloader')

    def update_extent(self):
        """ Update extent value in GUI based from value in map."""
        myExtent = self.iface.mapCanvas().extent()
        self.minLongitude.setText(str(myExtent.xMinimum()))
        self.minLatitude.setText(str(myExtent.yMinimum()))
        self.maxLongitude.setText(str(myExtent.xMaximum()))
        self.maxLatitude.setText(str(myExtent.yMaximum()))

    @pyqtSignature('')  # prevents actions being handled twice
    def on_pBtnDir_clicked(self):
        """ Show a dialog to choose directory """
        # noinspection PyCallByClass,PyTypeChecker
        self.outDir.setText(QFileDialog.getExistingDirectory(
            self, self.tr("Select download directory")))

    def accept(self):
        """Do osm download and display it in QGIS."""

        try:
            self.save_state()

            self.require_directory()
            self.download()
            self.load_shapefile()
            self.done(QDialog.Accepted)
        except CanceledImportDialogError:
            # don't show anything because this exception raised
            # when user canceling the import process directly
            pass
        except Exception as myEx:
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QMessageBox.warning(
                self,
                self.tr("InaSAFE OpenStreetMap downloader error"),
                str(myEx))

            self.progressDialog.cancel()

    def require_directory(self):
        """Ensure directory path entered in dialog exist.

        When the path does not exist, this function will ask the user if he
        want to create it or not.

        :raises: CanceledImportDialogError - when user choose 'No' in
            the question dialog for creating directory.
        """

        myDir = str(self.outDir.text())

        if os.path.exists(myDir):
            return

        myTitle = self.tr("Directory %s not exist") % myDir
        myQuestion = self.tr(
            "Directory %s not exist. Do you want to create it?"
        ) % myDir
        # noinspection PyCallByClass,PyTypeChecker
        myAnswer = QMessageBox.question(
            self, myTitle,
            myQuestion, QMessageBox.Yes | QMessageBox.No)

        if myAnswer == QMessageBox.Yes:
            os.makedirs(myDir)
        else:
            raise CanceledImportDialogError()

    def download(self):
        """Download shapefiles from Linfinti server.

        :raises: ImportDialogError, CanceledImportDialogError
        """

        ## preparing necessary data
        myMinLng = str(self.minLongitude.text())
        myMinLat = str(self.minLatitude.text())
        myMaxLng = str(self.maxLongitude.text())
        myMaxLat = str(self.maxLatitude.text())

        myCoordinate = "{myMinLng},{myMinLat},{myMaxLng},{myMaxLat}".format(
            myMinLng=myMinLng,
            myMinLat=myMinLat,
            myMaxLng=myMaxLng,
            myMaxLat=myMaxLat
        )

        myShapeUrl = "{url}?bbox={myCoordinate}".format(
            url=self.url,
            myCoordinate=myCoordinate
        )

        myFilePath = tempfile.mktemp('.shp.zip')

        # download and extract it
        self.fetch_zip(myShapeUrl, myFilePath)
        print myFilePath
        print str(self.outDir.text())
        self.extract_zip(myFilePath, str(self.outDir.text()))

        self.progressDialog.done(QDialog.Accepted)

    def fetch_zip(self, url, output_path):
        """Download zip containing shp file and write to output_path.

        :param url: URL of the zip bundle.
        :type url: str

        :param output_path: Path of output file,
        :type output_path: str

        :raises: ImportDialogError - when network error occurred
        """

        self.progressDialog.show()
        self.progressDialog.setMaximum(100)
        self.progressDialog.setValue(0)

        # myLabelText = "Begin downloading shapefile from " \
        #               + "%s ..."
        # self.progressDialog.setLabelText(self.tr(myLabelText) % (url))
        myLabelText = self.tr("Downloading shapefile")
        self.progressDialog.setLabelText(myLabelText)

        myResult = download_url(
            self.network_manager, url, output_path,
            self.progressDialog)

        if myResult is not True:
            _, myErrorMessage = myResult
            raise ImportDialogError(myErrorMessage)

    def extract_zip(self, path, output_dir):
        """Extract all content of a .zip file from path to output_dir.

        :param path: The path of the .zip file
        :type path: str

        :param output_dir: Output directory where the shp will be written to.
        :type output_dir: str

        :raises: IOError - when not able to open path or output_dir does not
            exist.
        """

        import zipfile

        # extract all files...
        myHandle = open(path, 'rb')
        myZip = zipfile.ZipFile(myHandle)
        for myName in myZip.namelist():
            myOutPath = os.path.join(output_dir, myName)
            myOutFile = open(myOutPath, 'wb')
            myOutFile.write(myZip.read(myName))
            myOutFile.close()

        myHandle.close()

    def load_shapefile(self):
        """
        Load downloaded shape file to QGIS Main Window.

        :raises: ImportDialogError - when buildings.shp not exist
        """

        myDir = str(self.outDir.text())
        myPath = os.path.join(myDir, 'buildings.shp')

        if not os.path.exists(myPath):
            myMessage = self.tr(
                "%s don't exist. The server don't have buildings data."
            )
            raise ImportDialogError(myMessage)

        self.iface.addVectorLayer(myPath, 'buildings', 'ogr')
Example #36
0
    def choose_file(self, selected):
        global nb
        if os.path.isdir(selected[0]) :  # on a sélectionné un répertoire
            i = 0
            t = sum((len(f) for _, _, f in os.walk(selected[0])))
            progbar = QProgressDialog('Copie des fichiers', None, 0, t, self)
            progbar.setWindowTitle('Copie des fichiers')
            progbar.setWindowModality(QtCore.Qt.ApplicationModal)
            for root, dirs, files in os.walk(selected[0]) :  # on inspecte récursivement les sous-répertoires
                progbar.setLabelText('{0} fichiers examinés'.format(i))
                for name in files :
                    i += 1
                    if '%Resume%' in name :
                        continue
                    if fnmatch.fnmatch(name, '*.epub'):  # sélection des epub
                        jobfichier = []
                        jobfichier.append(os.path.abspath(os.path.join(root, name)))
                        racine, ext = os.path.splitext(os.path.join(root, name))
                        if os.path.isfile(os.path.join(root, 'metadata.opf')):
                            jobfichier.append(os.path.abspath(os.path.join(root, 'metadata.opf')))
                        elif os.path.isfile(os.path.join(racine, '.opf')):
                            jobfichier.append(os.path.abspath(os.path.join(racine, '.opf')))  # selection des opf
                        else :
                            jobfichier.append(None)
                        if os.path.isfile(os.path.join(root, 'cover.jpg')) :  # sélection des covers
                            jobfichier.append(os.path.abspath(os.path.join(root, 'cover.jpg')))
                        else :
                            jobfichier.append(None)
                        c = conn.cursor()
                        c.execute("insert into ebook(epub, meta, cover) values(?,?,?)", (jobfichier[0], jobfichier[1], jobfichier[2]))
                    progbar.setValue(i)
            progbar.setValue(t)
            progbar.hide()
        elif os.path.isfile(selected[0]) :  # on a sélectionné des fichiers epub
            for elt in selected :
                if not '%Resume%'  in elt :
                    jobfichier = []
                    jobfichier.append(os.path.abspath(elt))
                    racine = elt[0:-4]
                    # selection des opf
                    f = os.path.abspath(racine + 'opf')
                    if os.path.isfile(f) :
                        jobfichier.append(f)
                    elif  os.path.isfile(os.path.join(os.path.dirname(elt), 'metadata.opf')):
                        jobfichier.append(os.path.join(os.path.dirname(elt), 'metadata.opf'))
                    else :
                        jobfichier.append(None)
                    # selection des couvertures
                    f = os.path.abspath(racine + 'jpg')
                    if os.path.isfile(f):
                        jobfichier.append(f)
                    elif os.path.isfile(os.path.join(os.path.dirname(elt), 'cover.jpg')):
                        jobfichier.append(os.path.join(os.path.dirname(elt), 'cover.jpg'))
                    elif os.path.isfile(os.path.join(os.path.dirname(elt), 'cover.jpeg')):
                        jobfichier.append(os.path.join(os.path.dirname(elt), 'cover.jpeg'))
                    else :
                        jobfichier.append(None)

                c = conn.cursor()
                c.execute("insert into ebook values(?,?,?)", (jobfichier[0], jobfichier[1], jobfichier[2]))
        else :
            msg = QtGui.QMessageBox(QtGui.QMessageBox.Warning, 'Attention', 'Vous n\'avez pas sélectionné de fichiers', QtGui.QMessageBox.Ok)

        conn.commit()

        rowsQuery = "SELECT Count() FROM ebook"
        c = conn.cursor()
        c.execute(rowsQuery)
        global nb
        nb = c.fetchone()[0]
Example #37
0
class specread:
    def __init__(self, specfile, startLineNum=0, beamline='APS-15IDC',det='CCD',data={},par={}):
        self.Data=data
        self.Par=par
        self.specfile=specfile
        if beamline=='APS-15IDC':
            self.APS_15IDC(startLineNum=startLineNum,det=det)
        if beamline=='APS-9IDC':
            self.APS_9IDC(startLineNum=startLineNum,det=det)
        
    def updateProgress(self):
        self.progressDialog.setValue(self.progressDialog.value()+1)

    
    
    def APS_15IDC(self,startLineNum=0, det='CCD'):
        """
        Function to read a complete spec File collected at APS 15IDC 
        """
        self.progressDialog=QProgressDialog('Reading scans form SPEC File:','Abort',0,100)
        self.progressDialog.setWindowModality(Qt.WindowModal)
        self.progressDialog.setWindowTitle('Wait')
        self.progressDialog.setAutoClose(True)
        self.progressDialog.setAutoReset(True)
        self.progressDialog.setMinimum(1)
        self.Data['YCol']='Apex2'
        self.Data['NCol']='Monc'
        fid=open(self.specfile)
        fdata=fid.readlines()
        self.SpecFileFull=fdata
        fid.close()
        if fdata[0][:2]!='#F':
            self.Data['NumOfScans']=0
            self.Data['Message']='The file is not a valid specfile!!'
            print 'Error:: The file is not a valid specfile!!'
        else:
            startScanLineNums=[i for i in range(startLineNum,len(fdata)) if fdata[i][:2]=='#S']
            self.progressDialog.setMaximum(len(startScanLineNums))
            self.progressDialog.show()
            self.endLineNum=startScanLineNums[-1]
            if startLineNum>0:
                startScanLineNums=sorted(startScanLineNums)
            numOfScans=len(startScanLineNums)
            scanLines=[fdata[i] for i in startScanLineNums]
            if startLineNum==0:
                tmp=0
                self.Data['NumOfScans']=0#numOfScans
                self.Data['ScanLines']=[]#scanLines
                self.Data['StartScanLineNums']=[]#startScanLineNums
            else:
                tmp=self.Data['NumOfScans']-1
                self.Data['NumOfScans']=self.Data['NumOfScans']-1#+numOfScans
                self.Data['ScanLines']=self.Data['ScanLines'][:-1]#+scanLines[1:]
                self.Data['StartScanLineNums']=self.Data['StartScanLineNums'][:-1]#+startScanLineNums

            for i in range(numOfScans):
                start=startScanLineNums[i]+1
                line=fdata[start]
                i=i+tmp
                self.Data[i]={}
                self.Par[i]={}
                if fdata[start-1].split()[2]=='getandsave_mca' or fdata[start-1].split()[2]=='MCAscanpt':
                    self.Par[i]['Mca']=1
                    self.Data[i]['ScanVar']='Empty'
                else:
                    self.Par[i]['Mca']=0
                tmpdata=[]
                self.Par[i]['CCD']=0
                while line[:2]!='\n' and line[:2]!='#C':
                    if line[:2]=='#P':
                        parName=line[3:].split()
                        start=start+1
                        parValue=map(eval,fdata[start][1:].split())
                        for j in range(len(parName)):
                            self.Par[i][parName[j]]=parValue[j]
                    if line[:2]=='#W':
                        tmppar=line[2:].split()
                        self.Par[i]['Wavelength']=eval(tmppar[1])
                    if line[:3]=='#G0':
                        self.Par[i]['g_l1']=float(line[4:].split()[5])
                        self.Par[i]['g_l2']=float(line[4:].split()[6])
                        self.Par[i]['g_l3']=float(line[4:].split()[7])
                    if line[:2]=='#A':
                        tmppar=line[2:].split()
                        self.Par[i]['Absorber']=eval(tmppar[1])
                    if line[:2]=='#Q':
                        tmppar=line[2:].split()
                        self.Par[i]['Q']=map(eval, tmppar)
                    if line[:3]=='#B0':
                        tmppar=line[3:].split()
                        self.Par[i]['CCD']=1
                    if line[:3]=='#B2':
                        tmppar=map(eval, line[3:].split())
                        self.Par[i]['DBPos']=tmppar[:2]
                        self.Par[i]['S2D_Dist']=tmppar[2]
                        self.Par[i]['S7D_Dist']=tmppar[3]
                    if line[:2]=='#L':
                        scanVar=line[3:-1].split()
                        self.Data[i]['ScanVar']=scanVar
                    if line[0]!='#':
                        tmpdata.append(map(eval, line.split(  )))
                    start=start+1
                    try:
                        line=fdata[start]
                    except:
                        break
                for j in range(len(scanVar)):
                    try:
                        self.Data[i][scanVar[j]]=np.array(tmpdata)[:,j]
                    except:
                        self.Data[i][scanVar[j]]=None
                if len(self.Par[i])==1:
                    self.Par[i]['Message']='No parameters!!'
                self.progressDialog.setLabelText('Reading scans form SPEC File: '+str(i+1))         
                self.updateProgress()
                self.Data['NumOfScans']=i
                self.Data['ScanLines']=self.Data['ScanLines']+[scanLines[i-tmp]]
                self.Data['StartScanLineNums']=self.Data['StartScanLineNums']+[startScanLineNums[i-tmp]]
                self.endLineNum=startScanLineNums[i-tmp]
                if self.progressDialog.wasCanceled()==True:
                    break
        self.progressDialog.hide()
            
                  
    
    def APS_9IDC(self,startLineNum=0, det='CCD'):
        """
        Function to read a complete spec File collected at APS 15IDC 
        """
        self.progressDialog=QProgressDialog('Reading scans form SPEC File:','Abort',0,100)
        self.progressDialog.setWindowModality(Qt.WindowModal)
        self.progressDialog.setWindowTitle('Wait')
        self.progressDialog.setAutoClose(True)
        self.progressDialog.setAutoReset(True)
        self.progressDialog.setMinimum(1)
        self.Data['YCol']='Bicron1'
        self.Data['NCol']='i2'
        fid=open(self.specfile)
        fdata=fid.readlines()
        self.SpecFileFull=fdata
        fid.close()
        if fdata[0][:2]!='#F':
            self.Data['NumOfScans']=0
            self.Data['Message']='The file is not a valid specfile!!'
            print 'Error:: The file is not a valid specfile!!'
        else:
            startScanLineNums=[i for i in range(startLineNum, len(fdata)) if fdata[i][:2]=='#S']
            self.progressDialog.setMaximum(len(startScanLineNums))
            self.progressDialog.show()
            self.endLineNum=startScanLineNums[-1]
            if startLineNum>0:
                startScanLineNums=sorted(startScanLineNums)
            self.Data['StartScanLineNums']=startScanLineNums
            numOfScans=len(self.Data['StartScanLineNums'])
            scanLines=[fdata[i] for i in startScanLineNums]
            if startLineNum==0:
                tmp=0
                self.Data['NumOfScans']=0#numOfScans
                self.Data['ScanLines']=[]#scanLines
                self.Data['StartScanLineNums']=[]#startScanLineNums
                self.Par['ParName']=[]
                for i in range(startScanLineNums[0]):
                    line=fdata[i].split()
                    if fdata[i][:2]=='#O':
                        self.Par['ParName']=self.Par['ParName']+line[1:]
            else:
                tmp=self.Data['NumOfScans']
                self.Data['NumOfScans']=self.Data['NumOfScans']-1#+numOfScans
                self.Data['ScanLines']=self.Data['ScanLines'][:-1]#+scanLines[1:]
                self.Data['StartScanLineNums']=self.Data['StartScanLineNums'][:-1]#+startScanLineNums
            for i in range(numOfScans):
                start=startScanLineNums[i]+1
                line=fdata[start]
                i=i+tmp
                self.Data[i]={}
                self.Par[i]={}
                if fdata[start-1].split()[2]=='getandsave_mca' or fdata[start-1].split()[2]=='MCAscanpt':
                    self.Par[i]['Mca']=1
                    self.Data[i]['ScanVar']='Empty'
                else:
                    self.Par[i]['Mca']=0
                self.Par[i]['CCD']=0
                tmpdata=[]
                pstart=0
                while line[:2]!='\n' and line[:2]!='#C':
                    if line[:2]=='#P':
                        parValue=map(eval,fdata[start].split()[1:])
                        for j in range(len(parValue)):
                            self.Par[i][self.Par['ParName'][pstart]]=parValue[j]
                            pstart=pstart+1
                    if line[:2]=='#Q':
                        tmppar=line[2:].split()
                        self.Par[i]['Q']=map(eval, tmppar)
                    if line[:2]=='#L':
                        scanVar=line[3:-1].split()
                        self.Data[i]['ScanVar']=scanVar
                    if line[0]!='#':
                        tmpdata.append(map(eval, line.split(  )))
                    start=start+1
                    line=fdata[start]
                for j in range(len(scanVar)):
                    try:
                        self.Data[i][scanVar[j]]=np.array(tmpdata)[:,j]
                    except:
                        self.Data[i][scanVar[j]]=None
                if len(self.Par[i])==1:
                    self.Par[i]['Message']='No parameters!!'
                self.progressDialog.setLabelText('Reading scans form SPEC File: '+str(i+1)) 
                self.updateProgress()
                self.Data['NumOfScans']=i
                self.Data['ScanLines']=self.Data['ScanLines']+[scanLines[i-tmp]]
                self.Data['StartScanLineNums']=self.Data['StartScanLineNums']+[startScanLineNums[i-tmp]]
                self.endLineNum=startScanLineNums[i-tmp]
                if self.progressDialog.wasCanceled()==True:
                    break
        self.progressDialog.hide()
Example #38
0
class BAONQtApplication(QApplication):
    BACKUP_DIALOG_CAPTION = 'Rename Plan Backup Detected'
    BACKUP_DIALOG_ERROR_CAPTION = 'Error'
    BACKUP_INTRO_TEXT = 'BAON has detected a backed up rename plan from a previous run of the '\
        'application. This suggests that the application crashed partway through executing a rename operation. The '\
        'files may have been left in an inconsistent state.'
    BACKUP_PROMPT_TEXT = 'What do you want to do?'

    REVERT_BACKUP_PROGRESS_TEXT = 'Reverting the rename operation'

    SUCCESS_DIALOG_CAPTION = 'Success'
    WARNING_DIALOG_CAPTION = 'Warning'

    BACKUP_DELETED_DIALOG_TEXT =\
        'The backed up plan has been deleted. Further runs of the application will proceed normally.'
    BACKUP_REVERTED_SUCCESS_DIALOG_TEXT = 'The rename operation has been reverted successfully. The directory state '\
        'should now have been completely restored.'
    BACKUP_REVERTED_WARNING_DIALOG_TEXT = 'There were inconsistencies while trying to revert the previous rename '\
        'operation. The directory state may not have been fully restored.'

    REVERT_BACKUP_BUTTON_TEXT = 'Revert the rename (recommended)'
    DELETE_BACKUP_BUTTON_TEXT = 'Delete the backup file'
    EXAMINE_BACKUP_BUTTON_TEXT = 'Examine the plan in a text editor'
    QUIT_BUTTON_TEXT = 'Quit BAON'

    request_revert_backup = pyqtSignal()
    request_delete_backup = pyqtSignal()

    _main_window = None
    _core = None
    _progress_dialog = None

    _core_thread = None

    def __init__(self, args):
        super().__init__(sys.argv)

        # Actually we do quit when the last window is closed, but we need to do this in a more controlled way
        self.setQuitOnLastWindowClosed(False)

        self._init_threads()
        self._init_main_objects(args)
        self._connect_main_objects()
        self._start_core()

    def event(self, evt):
        if isinstance(evt, QFileOpenEvent):
            path = evt.file()
            if not os.path.isdir(path):
                path, _ = os.path.split(path)

            self._main_window.set_base_path(path)
            return True

        return super().event(evt)

    def _init_threads(self):
        self._core_thread = QThread()
        self._core_thread.start()

    def _init_main_objects(self, args):
        self._main_window = MainWindow(args)

        self._core = BAONQtCore(args)
        self._core.moveToThread(self._core_thread)

    def _connect_main_objects(self):
        self.aboutToQuit.connect(self._on_quit)

        # Core vs. application

        self._core.request_backup_decision.connect(self.backup_decision_requested)
        self._core.reverted_backup.connect(self.notify_backup_reverted)
        self._core.revert_backup_error.connect(self.handle_backup_op_error)
        self._core.deleted_backup.connect(self.notify_backup_deleted)
        self._core.delete_backup_error.connect(self.handle_backup_op_error)

        self.request_revert_backup.connect(self._core.revert_backup)
        self.request_delete_backup.connect(self._core.delete_backup)

        # Core vs. main window

        self._core.prologue_finished.connect(self._main_window.show_first_time)

        self._core.status_changed.connect(self._main_window.report_status)
        self._core.scanned_files_updated.connect(self._main_window.update_scanned_files)
        self._core.renamed_files_updated.connect(self._main_window.update_renamed_files)

        self._core.has_shutdown.connect(self.quit)

        self._main_window.base_path_edited.connect(self._core.update_base_path)
        self._main_window.scan_recursive_changed.connect(self._core.update_scan_recursive)

        self._main_window.rules_text_changed.connect(self._core.update_rules_text)
        self._main_window.use_path_changed.connect(self._core.update_use_path)
        self._main_window.use_extension_changed.connect(self._core.update_use_extension)

        self._main_window.request_add_override.connect(self._core.add_override)
        self._main_window.request_remove_override.connect(self._core.remove_override)

        self._main_window.request_do_rename.connect(self._core.do_rename)
        self._main_window.request_rescan.connect(self._core.rescan)

        self._main_window.rejected.connect(self._core.shutdown)

    def _start_core(self):
        QMetaObject.invokeMethod(self._core, 'start', Qt.QueuedConnection)

    def _on_quit(self):
        self._core_thread.quit()
        self._core_thread.wait()

    @pyqtSlot()
    def backup_decision_requested(self):
        self._show_backup_decision()

    @pyqtSlot(Exception)
    def handle_backup_op_error(self, error):
        self._close_progress_dialog()
        self._show_backup_decision(error=error)

    @pyqtSlot()
    def notify_backup_deleted(self):
        QMessageBox.information(
            None,
            self.SUCCESS_DIALOG_CAPTION,
            self.BACKUP_DELETED_DIALOG_TEXT,
        )

    @pyqtSlot(bool)
    def notify_backup_reverted(self, complete_success):
        self._close_progress_dialog()
        if complete_success:
            QMessageBox.information(
                None,
                self.SUCCESS_DIALOG_CAPTION,
                self.BACKUP_REVERTED_SUCCESS_DIALOG_TEXT,
            )
        else:
            QMessageBox.warning(
                None,
                self.WARNING_DIALOG_CAPTION,
                self.BACKUP_REVERTED_WARNING_DIALOG_TEXT,
            )

    def _show_backup_decision(self, error=None):
        text = '<p>{0}</p><p>{1}</p>'.format(
            self.BACKUP_INTRO_TEXT if error is None else error,
            self.BACKUP_PROMPT_TEXT,
        )

        dialog = QMessageBox(
            QMessageBox.Question if error is None else QMessageBox.Critical,
            self.BACKUP_DIALOG_CAPTION if error is None else self.BACKUP_DIALOG_ERROR_CAPTION,
            text,
        )

        revert_button = dialog.addButton(self.REVERT_BACKUP_BUTTON_TEXT, QMessageBox.AcceptRole)
        delete_button = dialog.addButton(self.DELETE_BACKUP_BUTTON_TEXT, QMessageBox.DestructiveRole)
        examine_button = dialog.addButton(self.EXAMINE_BACKUP_BUTTON_TEXT, QMessageBox.ActionRole)
        dialog.addButton(self.QUIT_BUTTON_TEXT, QMessageBox.RejectRole)

        dialog.exec()
        clicked_button = dialog.clickedButton()

        if clicked_button == examine_button:
            QMetaObject.invokeMethod(self, '_examine_backup', Qt.QueuedConnection)
        elif clicked_button == revert_button:
            self._progress_dialog = QProgressDialog(None)
            self._progress_dialog.setLabelText(self.REVERT_BACKUP_PROGRESS_TEXT)
            self._progress_dialog.setCancelButton(None)
            self._progress_dialog.setRange(0, 0)
            self._progress_dialog.forceShow()

            self.request_revert_backup.emit()
        elif clicked_button == delete_button:
            self.request_delete_backup.emit()
        else:
            self.quit()

    @pyqtSlot()
    def _examine_backup(self):
        error = None
        try:
            filename = get_rename_plan_backup_filename()
            QDesktopServices.openUrl(QUrl.fromLocalFile(filename))
        except Exception as err:
            error = err
        finally:
            self._show_backup_decision(error)

    def _close_progress_dialog(self):
        if self._progress_dialog is not None:
            self._progress_dialog.close()

        self._progress_dialog = None
Example #39
0
def import_labeling_layer(labelLayer, labelingSlots, parent_widget=None):
    """
    Prompt the user for layer import settings, and perform the layer import.
    :param labelLayer: The top label layer source
    :param labelingSlots: An instance of LabelingGui.LabelingSlots
    :param parent_widget: The Qt GUI parent object
    """
    writeSeeds = labelingSlots.labelInput
    assert isinstance(writeSeeds, lazyflow.graph.Slot), "slot is of type %r" % (type(writeSeeds))
    opLabels = writeSeeds.getRealOperator()
    assert isinstance(opLabels, lazyflow.graph.Operator), "slot's operator is of type %r" % (type(opLabels))


    recentlyImported = PreferencesManager().get('labeling', 'recently imported')
    mostRecentProjectPath = PreferencesManager().get('shell', 'recently opened')
    mostRecentImageFile = PreferencesManager().get( 'DataSelection', 'recent image' )
    if recentlyImported:
        defaultDirectory = os.path.split(recentlyImported)[0]
    elif mostRecentProjectPath:
        defaultDirectory = os.path.split(mostRecentProjectPath)[0]
    elif mostRecentImageFile:
        defaultDirectory = os.path.split(mostRecentImageFile)[0]
    else:
        defaultDirectory = os.path.expanduser('~')

    fileNames = DataSelectionGui.getImageFileNamesToOpen(parent_widget, defaultDirectory)
    fileNames = map(str, fileNames)

    if not fileNames:
        return

    PreferencesManager().set('labeling', 'recently imported', fileNames[0])

    try:
        # Initialize operators
        opImport = OpInputDataReader( parent=opLabels.parent )
        opCache = OpArrayCache( parent=opLabels.parent )
        opMetadataInjector = OpMetadataInjector( parent=opLabels.parent )
        opReorderAxes = OpReorderAxes( parent=opLabels.parent )
    
        # Set up the pipeline as follows:
        #
        #   opImport --> opCache --> opMetadataInjector --------> opReorderAxes --(inject via setInSlot)--> labelInput
        #                           /                            /
        #   User-specified axisorder    labelInput.meta.axistags
    
        opImport.WorkingDirectory.setValue(defaultDirectory)
        opImport.FilePath.setValue(fileNames[0] if len(fileNames) == 1 else
                                   os.path.pathsep.join(fileNames))
        assert opImport.Output.ready()
    
        opCache.blockShape.setValue( opImport.Output.meta.shape )
        opCache.Input.connect( opImport.Output )
        assert opCache.Output.ready()

        opMetadataInjector.Input.connect( opCache.Output )
        metadata = opCache.Output.meta.copy()
        opMetadataInjector.Metadata.setValue( metadata )
        opReorderAxes.Input.connect( opMetadataInjector.Output )

        # Transpose the axes for assignment to the labeling operator.
        opReorderAxes.AxisOrder.setValue( writeSeeds.meta.getAxisKeys() )
    
        # We'll show a little window with a busy indicator while the data is loading
        busy_dlg = QProgressDialog(parent=parent_widget)
        busy_dlg.setLabelText("Importing Label Data...")
        busy_dlg.setCancelButton(None)
        busy_dlg.setMinimum(100)
        busy_dlg.setMaximum(100)
        def close_busy_dlg(*args):
            QApplication.postEvent(busy_dlg, QCloseEvent())
    
        # Load the data from file into our cache
        # When it's done loading, close the progress dialog.
        req = opCache.Output[:]
        req.notify_finished( close_busy_dlg )
        req.notify_failed( close_busy_dlg )
        req.submit()
        busy_dlg.exec_()

        readData = req.result
        
        maxLabels = len(labelingSlots.labelNames.value)

        # Can't use return_counts feature because that requires numpy >= 1.9
        #unique_read_labels, readLabelCounts = numpy.unique(readData, return_counts=True)

        # This does the same as the above, albeit slower, and probably with more ram.
        unique_read_labels = numpy.unique(readData)
        readLabelCounts = vigra_bincount(readData)[unique_read_labels]

        labelInfo = (maxLabels, (unique_read_labels, readLabelCounts))
        del readData
    
        # Ask the user how to interpret the data.
        settingsDlg = LabelImportOptionsDlg( parent_widget,
                                             fileNames, opMetadataInjector.Output,
                                             labelingSlots.labelInput, labelInfo )

        def handle_updated_axes():
            # The user is specifying a new interpretation of the file's axes
            updated_axisorder = str(settingsDlg.axesEdit.text())
            metadata = opMetadataInjector.Metadata.value.copy()
            metadata.axistags = vigra.defaultAxistags(updated_axisorder)
            opMetadataInjector.Metadata.setValue( metadata )
            
            if opReorderAxes._invalid_axes:
                settingsDlg.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
                # Red background
                settingsDlg.axesEdit.setStyleSheet("QLineEdit { background: rgb(255, 128, 128);"
                                                   "selection-background-color: rgb(128, 128, 255); }")
        settingsDlg.axesEdit.editingFinished.connect( handle_updated_axes )
        
        # Initialize
        handle_updated_axes()

        dlg_result = settingsDlg.exec_()
        if dlg_result != LabelImportOptionsDlg.Accepted:
            return

        # Get user's chosen label mapping from dlg
        labelMapping = settingsDlg.labelMapping    

        # Get user's chosen offsets.
        # Offsets in dlg only include the file axes, not the 5D axes expected by the label input,
        # so expand them to full 5D 
        axes_5d = opReorderAxes.Output.meta.getAxisKeys()
        tagged_offsets = collections.OrderedDict( zip( axes_5d, [0]*len(axes_5d) ) )
        tagged_offsets.update( dict( zip( opMetadataInjector.Output.meta.getAxisKeys(), settingsDlg.imageOffsets ) ) )
        imageOffsets = tagged_offsets.values()

        # Optimization if mapping is identity
        if labelMapping.keys() == labelMapping.values():
            labelMapping = None

        # This will be fast (it's already cached)
        label_data = opReorderAxes.Output[:].wait()
        
        # Map input labels to output labels
        if labelMapping:
            # There are other ways to do a relabeling (e.g skimage.segmentation.relabel_sequential)
            # But this supports potentially huge values of unique_read_labels (in the billions),
            # without needing GB of RAM.
            mapping_indexes = numpy.searchsorted(unique_read_labels, label_data)
            new_labels = numpy.array([labelMapping[x] for x in unique_read_labels])
            label_data[:] = new_labels[mapping_indexes]

        label_roi = numpy.array( roiFromShape(opReorderAxes.Output.meta.shape) )
        label_roi += imageOffsets
        label_slice = roiToSlice(*label_roi)
        writeSeeds[label_slice] = label_data

    finally:
        opReorderAxes.cleanUp()
        opMetadataInjector.cleanUp()
        opCache.cleanUp()
        opImport.cleanUp()
Example #40
0
class MainWindow(QtGui.QWidget):
    label_text_update_require = pyqtSignal(str)

    def __init__(self):
        super(MainWindow, self).__init__()

        self.params = ParamsWidget()
        self.btn_run = QtGui.QPushButton(u"Запустити")
        self.progress_dialog = QProgressDialog(u'', u'Зупинити',
                                               0, 100, self)
        self.progress_dialog.setWindowModality(Qt.WindowModal)
        self.progress_dialog.setAutoClose(False)

        self.progress_dialog_base_title = None

        self.setWindowTitle(u'Аналіз моделі')

        self.init_layout()
        self.init_events()

        self.adjustSize()
        self.move(QApplication.desktop().screen().rect().center()
                  - self.rect().center())

        self.update_widgets_state()

    def init_layout(self):
        vbox_layout = QtGui.QVBoxLayout()

        vbox_layout.addWidget(self.params)
        vbox_layout.addStretch(1)
        vbox_layout.addWidget(self.btn_run)

        self.setLayout(vbox_layout)

    def init_events(self):
        self.params.updated.connect(self.update_widgets_state)
        self.btn_run.clicked.connect(self.calculate)
        self.label_text_update_require.connect(self.update_progressdialog_label)

    def update_widgets_state(self):
        params_ready = self.params.is_params_specified()
        self.btn_run.setEnabled(params_ready)

    def calculate(self):
        self.run_job(u'Обробка файла...', self.process)

    def run_job(self, title, target, args=None, result_handler=None):
        self.progress_dialog.setWindowTitle(title)
        self.progress_dialog.setValue(0)

        self.calc = Calculator(target=target, args=args,
                               clean_up_handler=self.calc_finished,
                               result_handler=result_handler)
        self.calc.updated.connect(self.progress_dialog.setValue)
        self.calc.eta_updated.connect(self.update_eta_label)
        self.calc.finished.connect(self.calc_finished)
        self.progress_dialog.canceled.connect(self.calc.cancel)
        self.calc.start()

    @pyqtSlot()
    def calc_finished(self):
        self.progress_dialog.setAutoClose(True)
        self.progress_dialog.setValue(100)

    def process(self, update_percentage=None, check_cancelled=None):
        params = self.params.get_params()
        model_path = str(params['model_path'])

        filename, extension = os.path.splitext(model_path)
        if extension == '.obj':
            self.prepare_progressdialog(u'Імпорт файла... ')
            faces = importutils.get_faces(model_path, update_percentage,
                                          check_cancelled)
            print 'Faces imported'
            self.prepare_progressdialog(u'Перетворення трикутників... ')
            triangles = importutils.build_triangles(faces, update_percentage,
                                                    check_cancelled)

            self.prepare_progressdialog(u'Корекція моделі... ')
            clean_triangles = importutils.discard_invalid_triangles(triangles,
                                                                    vector.Vector(20, 2, 20),
                                                                    update_percentage,
                                                                    check_cancelled)
            print 'Triangles: %d, clean triangles: %d, diff: %d' % (
                len(triangles), len(clean_triangles), len(triangles) - len(clean_triangles))
            pickle_path = model_path + '.pickle'
            with open(pickle_path, 'wb') as pickle_file:
                try:
                    pickle.dump(clean_triangles, pickle_file, -1)
                    print 'Pickle saved to %s' % pickle_path
                except Exception as e:
                    print 'Failed to save clean triangles list: %s' % e
        elif extension == '.pickle':
            with open(model_path) as pickle_file:
                clean_triangles = pickle.load(pickle_file)
        else:
            raise Exception('Invalid extension %s' % extension)

        triangles = clean_triangles

        self.prepare_progressdialog(u'Обчислення E... ')
        E, sum_cos, sum_sin = processor.calculate_viewpoint_sums(triangles, params['wavelength'],
                                                                 vector.Vector(20, 2, 20),
                                                                 update_percentage, check_cancelled)

    def prepare_progressdialog(self, label):
        self.progress_dialog_base_title = label
        self.label_text_update_require.emit('')
        self.calc.mark_process_time()

    @pyqtSlot(str)
    def update_progressdialog_label(self, label):
        if not label:
            label = self.progress_dialog_base_title
        self.progress_dialog.setLabelText(label)

    @pyqtSlot(float)
    def update_eta_label(self, seconds):
        if seconds == 0:
            self.label_text_update_require.emit('')
            return
        t = time.gmtime(seconds)
        time_string = time.strftime('%M:%S', t)
        label_text = '%s %s' % (self.progress_dialog_base_title,
                                time_string)
        self.label_text_update_require.emit(label_text)
Example #41
0
class AddonManagerDialog(QDialog):
    _packages = None

    def __init__(self, parent=None, **kwargs):
        super().__init__(parent, **kwargs)
        self.setLayout(QVBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.addonwidget = AddonManagerWidget()
        self.layout().addWidget(self.addonwidget)
        buttons = QDialogButtonBox(
            orientation=Qt.Horizontal,
            standardButtons=QDialogButtonBox.Ok | QDialogButtonBox.Cancel
        )
        buttons.accepted.connect(self.__accepted)
        buttons.rejected.connect(self.reject)

        self.layout().addWidget(buttons)

        self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
        if AddonManagerDialog._packages is None:
            self._f_pypi_addons = self._executor.submit(list_pypi_addons)
        else:
            self._f_pypi_addons = concurrent.futures.Future()
            self._f_pypi_addons.set_result(AddonManagerDialog._packages)

        self._f_pypi_addons.add_done_callback(
            method_queued(self._set_packages, (object,))
        )

        self.__progress = QProgressDialog(
            self, Qt.Sheet,
            minimum=0, maximum=0,
            labelText=self.tr("Retrieving package list"),
            sizeGripEnabled=False,
        )

        self.__progress.rejected.connect(self.reject)
        self.__thread = None
        self.__installer = None

    @Slot(object)
    def _set_packages(self, f):
        if self.__progress.isVisible():
            self.__progress.close()

        try:
            packages = f.result()
        except (IOError, OSError) as err:
            message_warning(
                "Could not retrieve package list",
                title="Error",
                informative_text=str(err),
                parent=self
            )
            packages = []
        except Exception:
            raise
        else:
            AddonManagerDialog._packages = packages

        installed = list_installed_addons()
        dists = {dist.project_name: dist for dist in installed}
        packages = {pkg.name: pkg for pkg in packages}

        project_names = unique(
            itertools.chain(packages.keys(), dists.keys())
        )

        items = []
        for name in project_names:
            if name in dists and name in packages:
                item = Installed(packages[name], dists[name])
            elif name in dists:
                item = Installed(None, dists[name])
            elif name in packages:
                item = Available(packages[name])
            else:
                assert False
            items.append(item)

        self.addonwidget.set_items(items)

    def showEvent(self, event):
        super().showEvent(event)

        if not self._f_pypi_addons.done():
            QTimer.singleShot(0, self.__progress.show)

    def done(self, retcode):
        super().done(retcode)
        self._f_pypi_addons.cancel()
        self._executor.shutdown(wait=False)
        if self.__thread is not None:
            self.__thread.quit()
            self.__thread.wait(1000)

    def closeEvent(self, event):
        super().closeEvent(event)
        self._f_pypi_addons.cancel()
        self._executor.shutdown(wait=False)

        if self.__thread is not None:
            self.__thread.quit()
            self.__thread.wait(1000)

    def __accepted(self):
        steps = self.addonwidget.item_state()

        if steps:
            # Move all uninstall steps to the front
            steps = sorted(
                steps, key=lambda step: 0 if step[0] == Uninstall else 1
            )
            self.__installer = Installer(steps=steps)
            self.__thread = QThread(self)
            self.__thread.start()

            self.__installer.moveToThread(self.__thread)
            self.__installer.finished.connect(self.__on_installer_finished)
            self.__installer.error.connect(self.__on_installer_error)
            self.__installer.installStatusChanged.connect(
                self.__progress.setLabelText)

            self.__progress.show()
            self.__progress.setLabelText("Installing")

            self.__installer.start()

        else:
            self.accept()

    def __on_installer_error(self, command, pkg, retcode, output):
        message_error(
            "An error occurred while running a subprocess", title="Error",
            informative_text="{} exited with non zero status.".format(command),
            details="".join(output),
            parent=self
        )
        self.reject()

    def __on_installer_finished(self):
        message_information(
            "Please restart the application for changes to take effect.",
            parent=self)
        self.accept()
Example #42
0
    def regenerateProjectTodos( self ):
        """ Collects TODO and FIXME items from the project files """

        if GlobalData().project.fileName == "":
            return

        self.clearAll()
        files = GlobalData().project.filesList

        # now process them
        progress = QProgressDialog( "Extracting project todo items...",
                                    "Abort", 0, len( files ) )
        progress.setMinimumDuration( 0 )

        count = 0
        for fileName in files:
            progress.setLabelText( "Extracting project todos...\n" + \
                                   fileName )
            progress.setValue( count )
            QApplication.processEvents()
            if progress.wasCanceled():
                break

            # Do nothing for the directories
            if fileName.endswith( os.path.sep ):
                count += 1
                continue

            # read the file and split it into textlines
            try:
                f = open( fileName, 'r' )
                text = f.read()
                lines = text.splitlines()
                f.close()
            except IOError:
                count += 1
                self.progress.setValue( count )
                continue

            # now look for todo items
            lineIndex = 0
            for line in lines:
                lineIndex += 1
                if not line.strip().startswith( '#' ):
                    continue

                index = line.find( "TODO" )
                if index >= 0:
                    description = line[ index: ]
                    self.addFileTodoItem( description, fileName, lineIndex )
                    continue

                index = line.find( "FIXME" )
                if index >= 0:
                    description = line[ index: ]
                    self.addFileTodoItem( description, fileName, lineIndex )

            count += 1

        progress.setValue( len(files) )
        return