示例#1
0
class DatasourceRegister(object):
    '''Wraps a dict of OGR DS references controlling access, instantiation and destruction'''
    #{'name':(rc=Ref Count,type={SOURCE|TRANSIENT|DESTINATION},uri={http://url/|file://path/file.gdb},ds=<ds_object>, ...}
    register = {}
    #sopposed to work something like;
    #SOURCE=check ref hasn't changed, if it has update the object
    #TRANSIENT=free DB locks by closing as soon as not needed (FileGDB, SQLite)
    #DESTINATION=normal rw access with object kept open
    TYPE = LU.enum('SOURCE', 'TRANSIENT', 'DESTINATION')
    REQ = LU.enum('INCR', 'FEAT', 'FULL')

    def __init__(self):
        pass

    def _register(self, fn, uri):
        '''Registers a new DS under the provided name overwriting any previous entries'''
        self._assignRef(uri)
        if fn:
            type = self._type(fn)
            if type == self.TYPE.SOURCE:
                endpoint = self._newSRC()
            else:
                endpoint = self._newDST(fn)
            self.register[fn] = {}
            self.register[fn]['rc'] = 0
            self.register[fn]['type'] = type
            self.register[fn]['uri'] = uri
            self.register[fn]['ep'] = endpoint

        else:
            raise UnknownDSTypeException('Unknown DS requested, ' + str(fn))

    def _deregister(self, name):
        fn = LU.standardiseDriverNames(name)
        #sync/rel the DS
        #self.register[fn]['ep'].closeDS()#DS should already have closed
        self.register[fn]['ep'] = None
        self.register[fn]['type'] = None
        self.register[fn]['uri'] = None
        del self.register[fn]

    def _assignRef(self, uri):
        '''mark ref value as either user config or a connection string based on the assumption conn strings contain certain suff/prefixes...'''  #TODO Test different sl/fg cases
        self.cs, self.uc = (uri, None) if uri and re.search(
            'PG:|MSSQL:|\.gdb|\.sqlite|\.db', uri, flags=re.IGNORECASE) else (
                None, uri)

    def _type(self, fn):
        #fn = LU.standardiseDriverNames(name)
        #if fn == FileGDBDataStore.DRIVER_NAME:
        #    return self.TYPE.TRANSIENT
        if fn == WFSDataStore.DRIVER_NAME:
            return self.TYPE.SOURCE
        return self.TYPE.DESTINATION

    def _connect(self, fn, req=None):
        '''Initialise an OGR datasource on the DST/SRC object or just return note the existing and increment count'''
        endpoint = self.register[fn]['ep']
        self.register[fn]['rc'] += 1
        if not endpoint.getDS():
            if self.register[fn]['type'] == self.TYPE.SOURCE:
                self._connectSRC(fn, req)
            else:
                self._connectDST(fn)

    def _connectDST(self, fn):
        endpoint = self.register[fn]['ep']
        uri = endpoint.destinationURI(None)
        conn = endpoint.initDS(uri)
        endpoint.setDS(conn)

    def _connectSRC(self,
                    fn,
                    req=None):  #layername=None,fromdate=None,todate=None):
        endpoint = self.register[fn]['ep']
        if req and req['type'] == self.REQ.INCR and (req['fromdate']
                                                     or req['todate']):
            uri = endpoint.sourceURIIncremental(req['layername'],
                                                req['fromdate'], req['todate'])
        elif req and req['type'] == self.REQ.FEAT:
            uri = endpoint.sourceURIFeatureCount(req['layername'])
        elif req and req['type'] == self.REQ.FULL:
            uri = endpoint.sourceURI(req['layername'])
        else:
            pass
        #conn = ep.initDS(uri)

    def _disconnect(self, fn):
        '''Decrement reference to the DS and delete it entirely if its the last one'''
        endpoint = self.register[fn]['ep']
        self.register[fn]['rc'] -= 1
        if self.register[fn]['rc'] <= 0:
            ldslog.info('Release EP ' + str(fn))
            if self.register[fn]['type'] == self.TYPE.DESTINATION:
                self.closeLayerConfig(endpoint)
            endpoint.closeDS()

    #---------------------

    def refCount(self, fn):
        return self.register[fn]['rc']

    def openEndPoint(self, name, uri=None, req=None):
        #print 'GEP',name,uri,req
        '''Gets a named EP incrementing a refcount or registers a new one as needed'''
        fn = LU.standardiseDriverNames(name)
        #if fn+uri exist AND fn is valid AND (fn not prev registered OR the saved URI != uri)
        if (fn and uri)\
        and (fn in DataStore.DRIVER_NAMES.values() or fn == WFSDataStore.DRIVER_NAME) \
        and (not self.register.has_key(fn) or self.register[fn]['uri']!=uri):
            self._register(fn, uri)
            self._connect(fn, req)
        elif fn in self.register:
            self._connect(fn, req)
        else:
            raise EndpointConnectionException(
                'Register Entry {} has not been initialised.'.format(fn))
        return self.register[fn]['ep']

    def closeEndPoint(self, name):
        '''Closes the DS is a named EP or delete the EP completely if not needed'''
        fn = LU.standardiseDriverNames(name)
        #<HACK6>. Bypass DS closing for FileGDB connections
        if fn == 'FileGDB': return
        #</HACK6>
        if self.register.has_key(fn):
            self._disconnect(fn)
            if self.register[fn]['rc'] == 0:
                self._deregister(fn)

    def _newDST(self, fn):
        '''Init a new destination using instantiated uconf (and dest str if provided)'''
        dest = {
            PostgreSQLDataStore.DRIVER_NAME: PostgreSQLDataStore,
            MSSQLSpatialDataStore.DRIVER_NAME: MSSQLSpatialDataStore,
            SpatiaLiteDataStore.DRIVER_NAME: SpatiaLiteDataStore,
            FileGDBDataStore.DRIVER_NAME: FileGDBDataStore
        }.get(fn)
        return dest(self.cs, self.uc)

    def _newSRC(self):
        '''Initialise a new source, LDS nominally'''
        src = LDSDataStore(self.cs, self.uc)
        #src.setPartitionSize(partition_size)#partitionsize may not exist when this is called but thats okay!
        src.applyConfigOptions()
        return src

    def __str__(self):
        s = ''
        for k in self.register.keys():
            r = self.register[k]
            s += 'key=' + k + ': rc=' + str(r['rc']) + ' uri=' + str(
                r['uri']) + ': type=' + str(r['type']) + ': ep=' + str(
                    r['ep']) + '\n'
        return s

    #----------------------------------------------------------------------------------
    #This is the Layer Config stuff, its a bit of a mess!

    @staticmethod
    def setupLayerConfig(tp, sep, dep, initlc=None):
        '''Calls the TP LC setup function'''
        tp.getLayerConf(sep, dep, bool(initlc))

    @staticmethod
    def closeLayerConfig(ep):
        '''Attempts to release DS resources used by LayerConfig'''
        layerconf = ep.getLayerConf()
        if layerconf:
            if layerconf.getDS():  #hasattr(lc,'ds'):
                #dont close the DS (lc not owner) just sync so any lc values are saved
                layerconf.syncDS()
            layerconf.close()
            ep.setLayerConf(None)
示例#2
0
class LDSControls(QFrame):
        
    STATIC_IMG = ('error_static.png','linz_static.png','busy_static.png','clean_static.png')
    ANIM_IMG   = ('error.gif','linz.gif','layer.gif','clean.gif')
    
    IMG_SPEED  = 100
    IMG_WIDTH  = 64
    IMG_HEIGHT = 64
    
    MAX_WD = 450
    
    GD_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../bin/gdal/gdal-data'))
    STATUS = LU.enum('ERROR','IDLE','BUSY','CLEAN')
    
    def __init__(self,parent):
        super(LDSControls, self).__init__()
        self.parent = parent
        self.initConf()
        self.initEPSG()
        self.initUI()
        
    def initConf(self):
        '''Read files in conf dir ending in conf'''
        self.cflist = ConfigInitialiser.getConfFiles()
        #self.imgset = self.STATIC_IMG if ConfigWrapper().readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG
        #self.imgset = self.STATIC_IMG if self.parent.confconn.tp.src.confwrap.readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG
        sep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.SRCNAME,self.parent.confconn.uconf)
        self.imgset = self.STATIC_IMG if sep.confwrap.readDSProperty('Misc','indicator')=='static' else self.ANIM_IMG
        self.parent.confconn.reg.closeEndPoint(self.parent.confconn.SRCNAME)
        
    def initEPSG(self):
        '''Read GDAL EPSG files, splitting by NZ(RSR) and RestOfTheWorld'''

        gcsf = gdal.FindFile('gdal','gcs.csv') 
        if not gcsf:
            gcsf = os.path.join(self.GD_PATH,'gcs.csv')
        pcsf = gdal.FindFile('gdal','pcs.csv') 
        if not pcsf: 
            pcsf = os.path.join(self.GD_PATH,'pcs.csv')
        gcs = ConfigInitialiser.readCSV(gcsf)
        pcs = ConfigInitialiser.readCSV(pcsf)

        self.nzlsr = [(e[0],e[0]+' - '+e[3]) for e in gcs if 'NZGD'     in e[1] or  'RSRGD'     in e[1]] \
                   + [(e[0],e[0]+' - '+e[1]) for e in pcs if 'NZGD'     in e[1] or  'RSRGD'     in e[1]]
        self.rowsr = [(e[0],e[0]+' - '+e[3]) for e in gcs if 'NZGD' not in e[1] and 'RSRGD' not in e[1]] \
                   + [(e[0],e[0]+' - '+e[1]) for e in pcs if 'NZGD' not in e[1] and 'RSRGD' not in e[1]]
                   
                   
    def initUI(self):
        
        # 0      1          2       3       4       5      6    7    8
        #'destname','lgselect','layer','uconf','group','epsg','fd','td','int'
        
        #self.rdest,rlgselect,self.rlayer,ruconf,self.rgroup,repsg,rfd,rtd,rint = readlist 
        
        QToolTip.setFont(QFont('SansSerif', 10))
        
        #labels
        destLabel = QLabel('Destination')
        lgLabel = QLabel('Group/Layer')
        epsgLabel = QLabel('EPSG')
        fromDateLabel = QLabel('From Date')
        toDateLabel = QLabel('To Date')
        confLabel = QLabel('User Config')
        
        self.view = QLabel() 
        self.view.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.view.setAlignment(Qt.AlignCenter)

        self.confcombo = QComboBox(self)
        self.confcombo.setToolTip('Enter your user config name (file) here')
        self.confcombo.addItems(self.cflist)
        self.confcombo.setEditable(False)
        #self.confcombo.currentIndexChanged.connect(self.doLGEditUpdate)
        
        #combos
        self.lgcombo = QComboBox(self)
        self.lgcombo.setMaximumWidth(self.MAX_WD)
        self.lgcombo.setDuplicatesEnabled(False)
        #self.lgcombo.setInsertPolicy(QComboBox.InsertAlphabetically)#?doesnt seem to work
        self.lgcombo.setToolTip('Select either Layer or Group entry')
        self.lgcombo.setEditable(False)
        self.sepindex = None
        #self.updateLGValues()
        
        self.epsgcombo = QComboBox(self)
        self.epsgcombo.setMaximumWidth(self.MAX_WD)
        self.epsgcombo.setToolTip('Setting an EPSG number here determines the output SR of the layer')  
        self.epsgcombo.addItems([i[1] for i in self.nzlsr])
        self.epsgcombo.insertSeparator(len(self.nzlsr))
        self.epsgcombo.addItems([i[1] for i in self.rowsr])
        self.epsgcombo.setEditable(True)
        self.epsgcombo.setEnabled(False)
        
        self.destlist = self.getConfiguredDestinations()
        self.destcombo = QComboBox(self)
        self.destcombo.setToolTip('Choose the desired output type')   
        self.destcombo.setEditable(False)
        self.destcombo.addItems(self.destlist)

        #date selection
        self.fromdateedit = QDateEdit()
        self.fromdateedit.setCalendarPopup(True)
        self.fromdateedit.setEnabled(False)
        
        self.todateedit = QDateEdit()
        self.todateedit.setCalendarPopup(True)
        self.todateedit.setEnabled(False)
        
        #check boxes
        self.epsgenable = QCheckBox()
        self.epsgenable.setCheckState(False)
        self.epsgenable.clicked.connect(self.doEPSGEnable)       
        
        self.fromdateenable = QCheckBox()
        self.fromdateenable.setCheckState(False)
        self.fromdateenable.clicked.connect(self.doFromDateEnable)
        
        self.todateenable = QCheckBox()
        self.todateenable.setCheckState(False) 
        self.todateenable.clicked.connect(self.doToDateEnable)
        
        self.progressbar = QProgressBar()
        self.progressbar.setRange(0,100)
        self.progressbar.setVisible(True)
        self.progressbar.setMinimumWidth(self.MAX_WD)
        
        
        #buttons        
        self.initbutton = QPushButton("waiting")
        self.initbutton.setToolTip('Initialise the Layer Configuration')
        self.initbutton.clicked.connect(self.doInitClickAction)
        
        self.cleanbutton = QPushButton("Clean")
        self.cleanbutton.setToolTip('Clean the selected layer/group from local storage')
        self.cleanbutton.clicked.connect(self.doCleanClickAction)
        
        self.replicatebutton = QPushButton("Replicate")
        self.replicatebutton.setToolTip('Execute selected replication')
        self.replicatebutton.clicked.connect(self.doReplicateClickAction)
        
        self.cancelbutton = QPushButton("Close")
        self.cancelbutton.setToolTip('Close the LDS Replicate application')       
        self.cancelbutton.clicked.connect(self.parent.close)


        #set dialog values using GPR
        self.updateGUIValues(self.parent.gvs)
        
        #set onchange here otherwise we get circular initialisation
        self.destcombo.currentIndexChanged.connect(self.doDestChanged)
        self.confcombo.currentIndexChanged.connect(self.doConfChanged)
        self.lgcombo.currentIndexChanged.connect(self.doLGComboChanged)

        self.setStatus(self.STATUS.IDLE)
        
        #grid
        grid = QGridLayout()
        grid.setSpacing(10)
        
        
        #placement section ------------------------------------
        #---------+---------+--------+---------+--------
        # dest LB |         | dest DD
        # grp LB  |         | grp DD
        # conf LB |         | conf DD
        # epsg L  | epsg CB | epsg DD
        # f dt L  | f dt CB | f dt DD
        # t td L  | t td CB | t td DD
        # icon    |       <- progress ->
        # layer B | <- . -> |repl B  | clean B | close B 
        #---------+---------+--------+---------+--------

        grid.addWidget(destLabel, 1, 0)
        grid.addWidget(self.destcombo, 1, 2)

        #grid.addWidget(layerLabel, 2, 0)
        grid.addWidget(lgLabel, 2, 0)
        grid.addWidget(self.lgcombo, 2, 2)
        
        grid.addWidget(confLabel, 3, 0)
        grid.addWidget(self.confcombo, 3, 2)
        
        #grid.addWidget(groupLabel, 4, 0)
        #grid.addWidget(self.groupEdit, 4, 2)
        
        grid.addWidget(epsgLabel, 5, 0)
        grid.addWidget(self.epsgenable, 5, 1)
        grid.addWidget(self.epsgcombo, 5, 2)

        grid.addWidget(fromDateLabel, 6, 0)
        grid.addWidget(self.fromdateenable, 6, 1)
        grid.addWidget(self.fromdateedit, 6, 2)
        
        grid.addWidget(toDateLabel, 7, 0)
        grid.addWidget(self.todateenable, 7, 1)
        grid.addWidget(self.todateedit, 7, 2)
        
        hbox3 = QHBoxLayout()
        hbox3.addWidget(self.view) 
        hbox3.addStretch(1)
        hbox3.addWidget(self.progressbar)

        #hbox3.addLayout(vbox2)
        #hbox3.addLayout(vbox3)
        
        hbox4 = QHBoxLayout()
        hbox4.addWidget(self.initbutton)
        hbox4.addStretch(1)
        hbox4.addWidget(self.replicatebutton)
        hbox4.addWidget(self.cleanbutton)
        hbox4.addWidget(self.cancelbutton)
        

        vbox = QVBoxLayout()
        #vbox.addStretch(1)
        vbox.addLayout(grid)
        vbox.addLayout(hbox3)
        vbox.addLayout(hbox4)
        
        self.setLayout(vbox)  
       
    #def setProgress(self,pct):
    #    self.progressbar.setValue(pct)
        
    def setStatus(self,status,message='',tooltip=None):
        '''Sets indicator icon and statusbar message'''
        self.parent.statusbar.showMessage(message)
        self.parent.statusbar.setToolTip(tooltip if tooltip else '')

        #progress
        loc = os.path.abspath(os.path.join(IMG_LOC,self.imgset[status]))
        #loc = os.path.abspath(os.path.join(os.path.dirname(__file__),self.parent.IMG_LOC,self.imgset[status]))
        self.progressbar.setVisible(status in (self.STATUS.BUSY, self.STATUS.CLEAN))
        
        #icon
        anim = QMovie(loc, QByteArray(), self)
        anim.setScaledSize(QSize(self.IMG_WIDTH,self.IMG_HEIGHT))
        anim.setCacheMode(QMovie.CacheAll)
        anim.setSpeed(self.IMG_SPEED)
        self.view.clear()
        self.view.setMovie(anim)
        anim.start()

        self.view.repaint()
        QApplication.processEvents(QEventLoop.AllEvents)

    def mainWindowEnable(self,enable=True):
        cons = (self.lgcombo, self.confcombo, self.destcombo, 
                self.initbutton, self.replicatebutton, self.cleanbutton, self.cancelbutton,
                self.epsgenable,self.fromdateenable,self.todateenable,
                self.parent.menubar)
        for c in cons:
            c.setEnabled(enable)
            
        if enable:
            self.epsgcombo.setEnabled(self.epsgenable.checkState())
            self.fromdateedit.setEnabled(self.fromdateenable.checkState())
            self.todateedit.setEnabled(self.todateenable.checkState())
        else:
            self.epsgcombo.setEnabled(False)
            self.fromdateedit.setEnabled(False)
            self.todateedit.setEnabled(False)
   
        QApplication.restoreOverrideCursor() if enable else QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) 

    def refreshLGCombo(self):
        '''Re index LG combobox since a refreshLG call (new dest?) will usually mean new groups'''
        self.lgcombo.clear()
        self.lgcombo.addItems([i[2] for i in self.parent.confconn.lglist])
        #NOTE the separator consumes an index, if not clearing the combobox selectively remove the old sepindex (assumes g preceeds l)
        #if self.sepindex:
        #    self.lgcombo.removeItem(self.sepindex)
        self.sepindex = [i[0] for i in self.parent.confconn.lglist].count(LORG.GROUP)
        self.lgcombo.insertSeparator(self.sepindex)
        
    def updateLGValues(self,uconf,lgval,dest):
        '''Sets the values displayed in the Layer/Group combo'''
        #because we cant seem to sort combobox entries and want groups at the top, clear and re-add
        #TRACE#        
        #pdb.set_trace()
        sf = None
        try:
            self.parent.confconn.initConnections(uconf,lgval,dest)
        except Exception as e:
            sf=1
            ldslog.error('Error Updating UC Values. '+str(e))
            
        if sf:
            self.setStatus(self.STATUS.ERROR,'Error Updating UC Values', str(e))
        else:
            self.setStatus(self.STATUS.IDLE)
            
        self.refreshLGCombo()
        
    def centre(self):
        
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
    
    def gprParameters(self,rdest):
        '''Zip default and GPR values'''
        return [x if LU.assessNone(x) else y for x,y in zip(self.parent.gpr.readsec(rdest),self.parent.DEF_RVALS[1:])]
    
    def getLCE(self,ln):
        '''Read layer parameters'''
        dep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.destname,self.parent.confconn.uconf)
        #sep = self.parent.confconn.reg.openEndPoint('WFS',self.parent.confconn.uconf)
        self.parent.confconn.reg.setupLayerConfig(self.parent.confconn.tp,None,dep,initlc=False)
        lce = dep.getLayerConf().readLayerParameters(ln)
        #self.parent.confconn.reg.closeEndPoint('WFS')
        self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname)
        sep,dep = None,None
        return lce
    
    
    def doDestChanged(self):
        '''Read the destname parameter and fill dialog with matching GPR values'''
        rdest = str(self.destlist[self.destcombo.currentIndex()])
        rvals = self.gprParameters(rdest)
        self.updateGUIValues([rdest]+rvals)    
        
        
    def doConfChanged(self):
        '''Read the user conf parameter and fill dialog with matching GPR values'''
        rdest = str(self.destlist[self.destcombo.currentIndex()])
        rlg,_,rep,rfd,rtd = self.gprParameters(rdest)
        ruc = str(self.cflist[self.confcombo.currentIndex()])
        self.updateGUIValues((rdest,rlg,ruc,rep,rfd,rtd))
        
        
    def doLGComboChanged(self):
        '''Read the layer/group value and change epsg to layer or gpr match'''
        #get a matching LG entry and test whether its a layer or group
        #lgi = self.parent.confconn.getLayerGroupIndex(self.lgcombo.currentText().toUtf8().data())
        lgi = self.parent.confconn.getLayerGroupIndex(LQ.readWidgetText(self.lgcombo.currentText()))
        #lgi can be none if we init a new group, in which case we use the GPR value
        if lgi:
            lge = self.parent.confconn.lglist[lgi]
            lce = self.getLCE(lge[1]) if lge[0]==LORG.LAYER else None
        else:
            lce = None
        
        #look for filled layer conf epsg OR use prefs stored in gpr
        if lce and LU.assessNone(lce.epsg):
            epsgval = lce.epsg
        else:
            rdest = str(self.destlist[self.destcombo.currentIndex()])
            _,_,epsgval,_,_ = self.gprParameters(rdest)
        epsgindex = [i[0] for i in self.nzlsr+[(0,0)]+self.rowsr].index(epsgval)
        if self.epsgcombo.currentIndex() != epsgindex:
            self.epsgcombo.setCurrentIndex(int(epsgindex))

        
    def updateGUIValues(self,readlist):
        '''Fill dialog values from provided list'''
        #TODO. Remove circular references when setCurrentIndex() triggers do###Changed()
        #Read user input
        rdest,self.rlgval,ruconf,repsg,rfd,rtd = readlist
        
        #--------------------------------------------------------------------
        
        #Destination Menu
        selecteddest = LU.standardiseDriverNames(rdest)
        if selecteddest not in self.destlist:
            self.destlist = self.getConfiguredDestinations()
            self.destcombo.addItem(selecteddest)
        destindex = self.destlist.index(selecteddest) if selecteddest else 0
        
        if self.destcombo.currentIndex() != destindex:
            self.destcombo.setCurrentIndex(destindex)
        
        #InitButton
        self.initbutton.setText('Layer Select')
        
        #Config File
        confindex = 0
        if LU.assessNone(ruconf):
            ruconf = ruconf.split('.')[0]
            if ruconf not in self.cflist:
                self.cflist += [ruconf,]
                self.confcombo.addItem(ruconf)
            confindex = self.cflist.index(ruconf)
            
        if self.confcombo.currentIndex() != confindex:
            self.confcombo.setCurrentIndex(confindex)
        #self.confEdit.setText(ruconf if LU.assessNone(ruconf) else '')
        
        #Layer/Group Selection
        self.updateLGValues(ruconf,self.rlgval,rdest)
        lgindex = None
        if LU.assessNone(self.rlgval):
            #index of list value
            lgindex = self.parent.confconn.getLayerGroupIndex(self.rlgval,col=1)
            
        if LU.assessNone(lgindex):
            #advance by 1 for sep
            lgindex += 1 if lgindex>self.sepindex else 0 
        else:
            #using the separator index sets the combo to blank
            lgindex = self.sepindex
        if self.lgcombo.currentIndex() != lgindex:
            self.lgcombo.setCurrentIndex(lgindex)
        #self.doLGEditUpdate()
        
        #EPSG
        #                                user > layerconf
        #useepsg = LU.precedence(repsg, lce.epsg if lce else None, None)
        epsgindex = [i[0] for i in self.nzlsr+[(None,None)]+self.rowsr].index(repsg)
        if self.epsgcombo.currentIndex() != epsgindex:
            self.epsgcombo.setCurrentIndex(epsgindex)
            
        #epsgedit = self.epsgcombo.lineEdit()
        #epsgedit.setText([e[1] for e in self.nzlsr+self.rowsr if e[0]==repsg][0])
        
        #epsgedit.setText([e for e in self.nzlsr+self.rowsr if re.match('^\s*(\d+).*',e).group(1)==repsg][0])
        
        #To/From Dates
        if LU.assessNone(rfd):
            self.fromdateedit.setDate(QDate(int(rfd[0:4]),int(rfd[5:7]),int(rfd[8:10])))
        else:
            early = DataStore.EARLIEST_INIT_DATE
            self.fromdateedit.setDate(QDate(int(early[0:4]),int(early[5:7]),int(early[8:10])))
            
        if LU.assessNone(rtd):
            self.todateedit.setDate(QDate(int(rtd[0:4]),int(rtd[5:7]),int(rtd[8:10]))) 
        else:
            today = DataStore.getCurrent()
            self.todateedit.setDate(QDate(int(today[0:4]),int(today[5:7]),int(today[8:10])))
            
        #Internal/External CheckBox
#        if LU.assessNone(rint):
#            self.internalTrigger.setChecked(rint.lower()==DataStore.CONF_INT)
#        else:
#            self.internalTrigger.setChecked(DataStore.DEFAULT_CONF==DataStore.CONF_INT)
        
        
    def getConfiguredDestinations(self):
        defml = ['',]+DataStore.DRIVER_NAMES.values()
        return [d for d in self.parent.gpr.getDestinations() if d in defml]
        
    def doEPSGEnable(self):
        self.epsgcombo.setEnabled(self.epsgenable.isChecked())
        
    def doFromDateEnable(self):
        self.fromdateedit.setEnabled(self.fromdateenable.isChecked())
          
    def doToDateEnable(self):
        self.todateedit.setEnabled(self.todateenable.isChecked())  
          
    def readParameters(self):
        '''Read values out of dialogs'''
        destination = LU.assessNone(str(self.destlist[self.destcombo.currentIndex()]))
        #lgindex = self.parent.confconn.getLayerGroupIndex(self.lgcombo.currentText().toUtf8().data())
        lgindex = self.parent.confconn.getLayerGroupIndex(LQ.readWidgetText(self.lgcombo.currentText()))
        #NB need to test for None explicitly since zero is a valid index
        lgval = self.parent.confconn.lglist[lgindex][1] if LU.assessNone(lgindex) else None       
        #uconf = LU.standardiseUserConfigName(str(self.confcombo.lineEdit().text()))
        #uconf = str(self.confcombo.lineEdit().text())
        uconf = str(self.cflist[self.confcombo.currentIndex()])
        ee = self.epsgenable.isChecked()
        epsg = None if ee is False else re.match('^\s*(\d+).*',str(self.epsgcombo.lineEdit().text())).group(1)
        fe = self.fromdateenable.isChecked()
        te = self.todateenable.isChecked()
        fd = None if fe is False else str(self.fromdateedit.date().toString('yyyy-MM-dd'))
        td = None if te is False else str(self.todateedit.date().toString('yyyy-MM-dd'))
        
        return destination,lgval,uconf,epsg,fe,te,fd,td
    
    def doInitClickAction(self):
        '''Initialise the LC on LC-button-click, action'''
        try:
            try:
                self.setStatus(self.STATUS.BUSY,'Opening Layer-Config Editor')  
                self.progressbar.setValue(0)
                self.parent.runLayerConfigAction()
            finally:
                self.setStatus(self.STATUS.IDLE,'Ready')
        except Exception as e:
            self.setStatus(self.STATUS.ERROR,'Error in Layer-Config',str(sys.exc_info()))#e))
        
    def doCleanClickAction(self):
        '''Set clean anim and run clean'''
        #lgo = self.lgcombo.currentText().toUtf8().data()
        lgo = LQ.readWidgetText(self.lgcombo.currentText())
        
        try:
            self.setStatus(self.STATUS.CLEAN,'Running Clean '+lgo)
            self.progressbar.setValue(0)
            self.runReplicationScript(True)
        except Exception as e:
            self.setStatus(self.STATUS.ERROR,'Failed Clean of '+lgo,str(sys.exc_info()))#e))
        
    def doReplicateClickAction(self):
        '''Set busy anim and run repl'''
        lgo = self.lgcombo.currentText()#.toUtf8().data()#only used for error messages
        try:
            self.setStatus(self.STATUS.BUSY,'Running Replicate '+lgo)
            self.progressbar.setValue(0)
            self.runReplicationScript(False)
            ldslog.debug('TRPfinish')
        except Exception as e:
            self.setStatus(self.STATUS.ERROR,'Failed Replication of '+lgo,str(sys.exc_info()))#e))

    def runReplicationScript(self,clean=False):
        '''Run the layer/group repliction script'''
        destination,lgval,uconf,epsg,fe,te,fd,td = self.readParameters()
        uconf_path = LU.standardiseUserConfigName(uconf)
        destination_path = LU.standardiseLayerConfigName(destination)
        destination_driver = LU.standardiseDriverNames(destination)

        if not os.path.exists(uconf_path):
            self.userConfMessage(uconf_path)
            return
        elif not MainFileReader(uconf_path).hasSection(destination_driver):
            self.userConfMessage(uconf_path,destination_driver)
            return
        #-----------------------------------------------------
        #'destname','layer','uconf','group','epsg','fd','td','int'
     
        self.parent.gpr.write((destination_driver,lgval,uconf,epsg,fd,td))        
        ldslog.info(u'dest={0}, lg={1}, conf={2}, epsg={3}'.format(destination_driver,lgval,uconf,epsg))
        ldslog.info('fd={0}, td={1}, fe={2}, te={3}'.format(fd,td,fe,te))
        lgindex = self.parent.confconn.getLayerGroupIndex(lgval,col=1)
        #lorg = self.parent.confconn.lglist[lgindex][0]
        #----------don't need lorg in TP anymore but it is useful for sorting/counting groups
        #self.parent.confconn.tp.setLayerOrGroup(lorg)
        self.parent.confconn.tp.setLayerGroupValue(lgval)
        if self.fromdateenable.isChecked(): self.parent.confconn.tp.setFromDate(fd)
        if self.todateenable.isChecked(): self.parent.confconn.tp.setToDate(td)
        self.parent.confconn.tp.setUserConf(uconf)
        if self.epsgenable: self.parent.confconn.tp.setEPSG(epsg)
        
        #because clean state persists in TP
        if clean:
            self.parent.confconn.tp.setCleanConfig()
        else:
            self.parent.confconn.tp.clearCleanConfig()
        #(re)initialise the data source since uconf may have changed
        #>>#self.parent.confconn.tp.src = self.parent.confconn.initSourceWrapper()
        #--------------------------
        ###ep = self.parent.confconn.reg.openEndPoint(self.parent.confconn.destname,self.parent.confconn.uconf)
        
        ###self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname)
        ###ep = None
        #Open ProcessRunner and run with TP(proc)/self(gui) instances
        #HACK temp add of dest_drv to PR call
        try:
            #TODO. Test for valid LC first
            self.tpr = ProcessRunner(self,destination_driver)
        except Exception as e:
            ldslog.error('Cannot create ProcessRunner {}. NB Possible missing Layer Config {}'.format(str(e),destination_path))
            self.layerConfMessage(destination_path)
            return
        #If PR has been successfully created we must vave a valid dst    
        ldslog.debug('TRPstart')
        self.tpr.start()
        
#     def quitProcessRunner(self):
#         self.tpr.join()
#         self.tpr.quit()
#         self.trp = None

        
    def userConfMessage(self,uconf,secname=None):
        ucans = QMessageBox.warning(self, 'User Config Missing/Incomplete', 
                                'Specified User-Config file, '+str(uconf)+' does not exist' if secname is None else 'User-Config file does not contain '+str(secname)+' section', 
                                'Back','Initialise User Config')
        if not ucans:
            #Retry
            ldslog.warn('Retry specifying UC')
            #self.confcombo.setCurrentIndex(0)
            return
        #Init
        ldslog.warn('Reset User Config Wizard')
        self.parent.runWizardAction()


    def layerConfMessage(self,dest):
        lcans = QMessageBox.warning(self, 'Layer Config Missing', 
                                'Required Layer-Config file, '+str(dest)+' does not exist', 
                                'Back','Run Layer Select')
        if not lcans:
            #Retry
            ldslog.warn('Retry specifying LC')
            #self.destcombo.setCurrentIndex(0)
            return
        #Init
        ldslog.warn('Reset Layer Config')
        self.doInitClickAction()
class LayerConfigSelector(QMainWindow):
    STEP = LU.enum('PRE', 'POST')

    #def __init__(self,tp,uconf,group,dest='PostgreSQL',parent=None):
    def __init__(self, parent=None):
        '''Main entry point for the Layer selection dialog'''
        super(LayerConfigSelector, self).__init__(parent)

        self.parent = parent

        #Build models splitting by keyword if necessary
        #print 'LGVAL in LCS',self.parent.confconn.lgval
        av_sl = self.splitData(
            LU.recode(self.parent.confconn.lgval),
            self.parent.confconn.complete
        )  #if self.parent.confconn.lgval and self.parent.confconn.complete else (list(self.parent.confconn.complete),[])

        self.available_model = LayerTableModel('L::available', self)
        self.available_model.initData(av_sl[0], self.parent.confconn.inclayers)

        self.selection_model = LayerTableModel('R::selection', self)
        self.selection_model.initData(av_sl[1], self.parent.confconn.inclayers)

        self.page = LayerSelectionPage(self)
        self.setCentralWidget(self.page)

        self.setWindowTitle("LDS Layer Selection")
        self.resize(725, 480)

    def resetLayers(self):
        '''Rebuilds lconf from scratch'''
        dep = self.parent.confconn.reg.openEndPoint(
            self.parent.confconn.destname, self.parent.confconn.uconf)
        sep = self.parent.confconn.reg.openEndPoint(
            self.parent.confconn.SRCNAME, self.parent.confconn.uconf)
        #self.parent.confconn.reg.setupLayerConfig(self.parent.confconn.tp,sep,dep)
        self.parent.confconn.reg.setupLayerConfig(self.parent.confconn.tp,
                                                  sep,
                                                  dep,
                                                  initlc=True)
        self.refreshLayers(dep)
        self.parent.confconn.reg.closeEndPoint(self.parent.confconn.SRCNAME)
        self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname)

    def refreshLayers(self, dep, customkey=None):
        '''Refreshes from a reread of the lconf object'''
        self.parent.confconn.setupCompleteLayerList(dep)

        av_sl = self.splitData(customkey, self.parent.confconn.complete)
        self.signalModels(self.STEP.PRE)
        self.available_model.initData(av_sl[0], self.parent.confconn.inclayers)
        self.selection_model.initData(av_sl[1], self.parent.confconn.inclayers)
        self.signalModels(self.STEP.POST)

    def writeKeysToLayerConfig(self, ckey):
        '''Add custom key to the selection_model list of layers (assumes required av->sl transfer completed) not just the transferring entry'''
        layerlist = [ll[0] for ll in self.selection_model.mdata]
        replacementlist = ()
        dep = self.parent.confconn.reg.openEndPoint(
            self.parent.confconn.destname, self.parent.confconn.uconf)
        #print 'opened dep=',dep,'reg=',self.parent.confconn.reg#DEBUG
        self.parent.confconn.reg.setupLayerConfig(self.parent.confconn.tp,
                                                  None,
                                                  dep,
                                                  initlc=False)
        #categorylist = [f.encode('utf8').strip() for f in dep.getLayerConf().readLayerProperty(layerlist, 'category') if f]
        categorylist = [
            LU.assessNone(f) for f in dep.getLayerConf().readLayerProperty(
                layerlist, 'category')
        ]
        for cat in categorylist:
            replacementlist += ((cat if ckey in cat.split(',') else cat + ',' +
                                 ckey) if cat else ckey, )
        #print '>>> writing this replacementlist to LC',replacementlist
        dep.getLayerConf().writeLayerProperty(layerlist, 'category',
                                              replacementlist)
        #new keyword written so re-read complete (LC) and update assigned keys list
        self.parent.confconn.setupCompleteLayerList(dep, refresh=True)
        self.parent.confconn.setupAssignedLayerList()
        self.parent.confconn.buildLayerGroupList()
        #self.refreshLayers(dep,customkey)
        #print 'closing dep=',dep,'reg=',self.parent.confconn.reg#DEBUG
        self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname)
        dep = None

    def deleteKeysFromLayerConfig(self, layerlist, ckey):
        '''Remove custom keys from selected layers'''
        replacementlist = ()
        dep = self.parent.confconn.reg.openEndPoint(
            self.parent.confconn.destname, self.parent.confconn.uconf)
        #print 'opening',dep#DEBUG
        self.parent.confconn.reg.setupLayerConfig(self.parent.confconn.tp,
                                                  None,
                                                  dep,
                                                  initlc=False)
        categorylist = [
            f.encode('utf8').strip()
            for f in dep.getLayerConf().readLayerProperty(
                layerlist, 'category') if f
        ]
        for cat in categorylist:
            #replacementlist += (re.sub(',+',',',''.join(cat.split(ckey)).strip(',')),)
            try:
                cat = cat.split(',')
                cat.remove(LU.recode(ckey, uflag='encode'))
            except ValueError:
                pass
            replacementlist += (','.join(cat), )
        dep.getLayerConf().writeLayerProperty(layerlist, 'category',
                                              replacementlist)

        #-----------------------------------
        self.parent.confconn.setupCompleteLayerList(dep)
        self.parent.confconn.setupAssignedLayerList()
        self.parent.confconn.buildLayerGroupList()
        #self.refreshLayers(dep,customkey)
        self.parent.confconn.reg.closeEndPoint(self.parent.confconn.destname)
        #print 'closing', dep,self.parent.confconn.reg#DEBUG
        dep = None
        return self.selection_model.rowCount()

    @staticmethod
    def splitData(keyword, complete):
        '''Splits up the 'complete' layer list according to whether it has the selection keyword or not'''
        alist = []
        slist = []
        #assert complete, 'Need complete layerlist to generate selection menu'#it'll be empty prior to init
        for dp in complete:
            if keyword and keyword in dp[2]:
                slist.append(dp)
            else:
                alist.append(dp)
        return alist, slist

    def signalModels(self, prepost):
        '''Convenience method to call the Layout Change signals when models are modified'''
        if prepost == self.STEP.PRE:
            self.available_model.layoutAboutToBeChanged.emit()
            self.selection_model.layoutAboutToBeChanged.emit()
        elif prepost == self.STEP.POST:
            self.available_model.layoutChanged.emit()
            self.selection_model.layoutChanged.emit()

    def closeEvent(self, event):
        '''Intercept close event to signal parent to update status'''
        self.parent.controls.setStatus(self.parent.controls.STATUS.IDLE,
                                       'Done')
        #return last group selection
        #lastgroup = LU.recode(self.page.keywordcombo.lineEdit().text().toUtf8().data())
        lastgroup = LU.recode(
            LQ.readWidgetText(self.page.keywordcombo.lineEdit().text()))
        #self.parent.controls.gpr.writeline('lgvalue',lastgroup)
        if LU.assessNone(lastgroup):
            dep = self.parent.confconn.reg.openEndPoint(
                self.parent.confconn.destname, self.parent.confconn.uconf)
            #sep = self.parent.confconn.reg.openEndPoint('WFS',self.parent.confconn.uconf)
            self.parent.confconn.reg.setupLayerConfig(self.parent.confconn.tp,
                                                      None, dep)
            self.parent.confconn.setupCompleteLayerList(dep)
            self.parent.confconn.setupAssignedLayerList()
            self.parent.confconn.buildLayerGroupList()
            lgindex = self.parent.confconn.getLayerGroupIndex(lastgroup, col=1)
            self.parent.controls.refreshLGCombo()
            #current index wont be available in parent if this is the init run
            self.parent.controls.lgcombo.setCurrentIndex(
                lgindex if lgindex else 0)
            #self.parent.confconn.reg.closeEndPoint('WFS')
            self.parent.confconn.reg.closeEndPoint(
                self.parent.confconn.destname)
            sep, dep = None, None
示例#4
0
from __builtin__ import classmethod

ldslog = LU.setupLogging()


class InputMisconfigurationException(Exception): 
    def __init__(self, msg):
        super(InputMisconfigurationException,self).__init__(msg)
        ldslog.error('InputMisconfigurationException :: Improperly formatted input argument, '+str(msg))
        
class PrimaryKeyUnavailableException(Exception): pass
class LayerConfigurationException(Exception): pass
class DatasourceInitialisationException(Exception): pass
class IncompleteParametersForInitialisation(Exception): pass

LORG = LU.enum('GROUP','LAYER')

class TransferProcessor(object):
    '''Primary class controlling data transfer objects and the parameters for these'''

    #Hack. To read 64bit integers we have to translate tables without GDAL's driver copy mechanism. 
    #Step 1 identify tables where 64 bit ints are used
    #Step 2 intercept feature build and copy and overwrite with string values
    #The tables listed below are ASP tables using a sufi number which is 64bit 
    ###layers_with_64bit_ints = map(lambda s: 'v:x'+s, ('1203','1204','1205','1028','1029'))
    #Note. This won't work for any layers that don't have a primary key, i.e. Topo and Hydro. Since feature ids are only used in ASP this shouldnt be a problem
    
    LP_SUFFIX = ".layer.properties"
    DEF_IE = DataStore.CONF_EXT
        
    POLL_INTERVAL = 1