示例#1
0
class PageItem():
    def __init__(self,
                 neoConName=None,
                 actionButton=None,
                 pageWidget=None,
                 pageWidgetIndex=None):
        self.settings = QSettings()
        self.helper = Helper()
        # the name of the neocon for this page
        self.neoConName = neoConName
        # see if we need to prompt for the password
        self.promptPW = None
        self.checkPW()
        # the qaction on the menubar
        self.actionButton = actionButton
        self.pageWidget = pageWidget
        self.pageWidgetIndex = pageWidgetIndex
        return

    def checkPW(self, ):
        '''If the connection is prompt for password, then prompt until the user enters something.
        '''
        # get the neocon dictionary
        neoDict = self.settings.value("NeoCon/connection/{}".format(
            self.neoConName))
        if not neoDict is None:
            if neoDict["prompt"] == "True":
                # prompt for a password if needed and save what the user enters
                pw = ''
                while len(pw) < 1:
                    pw = self.helper.passwordPrompt(conName=self.neoConName,
                                                    conURL=neoDict["URL"])
                    if not pw is None:
                        if len(pw) > 0:
                            # save the encrypted password in the page item so it's ready to be used by any function
                            self.promptPW = self.helper.putText(pw)
                        else:
                            self.helper.displayErrMsg(
                                "Prompt Password",
                                "You must enter a password.")
示例#2
0
class NeoDriver():

    def __init__(self, name=None,  promptPW=None):
        self.name = name
        self.settings = QSettings()     
        self.neoDict = None
        self.helper = Helper()
        
        # setup the dictionary that defines this neo4j connection
        self.getSavedConnection()

        # if we prompted the user for a password, save it in the neocon dictionary
        if not promptPW is None:
            self.neoDict["password"] = promptPW
        
        # driver used by this NeoDriver object
        self.myDriver = None
        # session used for unmanaged transaction
        self.session = None
        # transaction used for unmanaged transaction
        self.tx = None
        # result object used while consuming query results and saving them to self.resultSet
        self.result = None
        # persistent result set and summary
        self.resultSet = None
        self.resultSummary = None
        
        # manage chunking your way thru a result set
        self.cursorChunk = None
        self.chunkStart = 0         # this is the record number of the first record in the chunk
        self.chunkEnd = 0           # this is the record number of the last record in the chunk
        self.chunkSize = 10     # some day we'll make this a parameter setting
        self.curRecord = 0          # this is the last record retrieved
        self.endReached = False
        
        # track query statistics
        self.stats = None 
        # default to true
        self.autoCommit = True
        # dictionary that gathers up facts about an individual cypher execution.
        self.cypherLogDict = {} 

    def logMsg(self, msg):

        if logging:
            logging.info(msg)      

    def logScript(self, script):
#        if logging:
#            logging.info(script)
#        print(script)
        return

    def logDriverStatus(self, ):
        return
        
#        if not self.myDriver is None:
#            driverStat = "Open"
#        else:
#            driverStat = "None"
#        if not self.session is None:
#            sessionStat = "Open"
#        else:
#            sessionStat = "None"
#        if not self.tx is None:
#            if self.tx.closed():
#                txStat = "Closed"
#            else:
#                 txStat = "Open"
#        else:
#            txStat = "None"
#            
#        if not self.result is None:
#            if self.result.peek() == None:
#                resultStat = "No Data Left"
#            else:
#                resultStat = "Data Remains"
#        else:
#            resultStat = "None"
#            
#        driverStatus = "Driver: {} Session: {} Txn: {} Result: {}".format(driverStat, sessionStat, txStat, resultStat)
#        print(driverStatus)
            
    def setAutoCommit(self, setting):
        self.autoCommit = setting
        
    def getSavedConnection(self, ):
        '''
        get the dictionary from a saved connection in settings and use it to initialize this neoDriver
        if you don't find it, then create a new blank dictionary'
        '''
        if not (self.name is None):
            self.neoDict = self.settings.value("NeoCon/connection/{}".format(self.name))
            if self.neoDict is None:
                self.neoDict = self.newNeoDriverDict()  
            else:
                self.name = self.neoDict["slot"]
        else:
            self.neoDict = self.newNeoDriverDict()        
            
    def newNeoDriverDict(self, ):
        # returns a default empty dictionary of neodriver properties
        neoDict = {}
        if self.name is None:
            neoDict["slot"] = "Unnamed"
        else:
            neoDict["slot"] = self.name
        neoDict["URL"] = "never connected"
        neoDict["port"] = ""
        neoDict["conType"] = ""
        neoDict["host"] = ""
        neoDict["userid"] = ""
        neoDict["password"] = ""
        neoDict["usesecure"] = "False"
        neoDict["prompt"] = "False"

        return neoDict
        
    def localNeoConDict(self, ):
        # returns a neoCon dictionary ready to access a localhost system using bolt
        neoDict = {}
        neoDict["slot"] = "LOCAL"
        neoDict["URL"] = "never connected"
        neoDict["port"] = "7687"
        neoDict["conType"] = "bolt"
        neoDict["host"] = "localhost"
        neoDict["userid"] = "neo4j"
        pw = self.helper.putText("neo4j")
        neoDict["password"] = pw
        neoDict["usesecure"] = "False"
        neoDict["prompt"] = "False"

        return neoDict
        
    def displayNode(self, node):
        '''return the string representation of the node or a blank string
        '''
        strNode = ""
        if not node is None:
            strNode = str(node)
        
        return strNode

    def displayRelationship(self, relationship):
        '''return the string representation of the relationship or a blank string
        '''
        strRel = ""
        if not relationship is None:
            strRel = str(relationship)
        
        return strRel        

    def runCypherAuto(self, cypherText, cypherParms=None):
        '''
            run a cypher in an automatic transaction.
            save the entire result.
        '''
        
        # first create the driver  object if we haven't done that yet
        if self.myDriver is not None:
            pass
        else:
            rc, msg = self.setDriver()
            if rc == False:
                return False, msg
                

        # now run the query and save the result set
        errSuffix = "Run Cypher Auto Error"
        try:
            rc = False
            self.cypherLogDict = {}
            self.cypherLogDict["error"] = ""
            self.cypherLogDict["startTime"] = datetime.datetime.now()  
            self.cypherLogDict["offset"] = -1
            self.cypherLogDict["cypher"] = cypherText
            
            # create a session
            self.logScript('aSession = aDriver.session()')
            self.session = self.myDriver.session()
            self.logDriverStatus()
            
            # run an autocommit transaction
            self.logScript('aResult = aSession.run({})'.format(cypherText))
            self.result = self.session.run(cypherText)
            self.logDriverStatus()
            
            # save the result as a list of records
            self.logScript('self.resultSet = []')
            self.logScript('for rec in self.result:')
            self.logScript('    self.resultSet.append(rec)')
            self.resultSet = []
            for rec in self.result:
                self.resultSet.append(rec)            
            
#            self.logScript('aResultSet = aResult.data()')
#            self.resultSet = self.result.data()
            self.logDriverStatus()
            
            # this gets the query stats
            self.logScript('aResultSummary = aResult.consume()')
            self.resultSummary = self.result.consume()
            self.logDriverStatus()
            
            rc = True
            msg = "Query Completed"
            
        except Neo4jError as e:
            msg =  "Neo4j Error :{} - {}".format(repr(e), errSuffix)
        except DriverError as e:
            msg =  "Driver Error :{} - {}".format(repr(e), errSuffix)
        except BaseException as e:
            msg =   "Base Exception :{} - {}".format(repr(e), errSuffix) 
            
        finally:
            self.cypherLogDict["endTime"] = datetime.datetime.now()
            
            # save query results if present
            if not self.resultSummary is None:
                if not self.resultSummary.plan is None:
                    self.cypherLogDict["plan"] = self.resultSummary.plan
                else:
                    self.cypherLogDict["plan"] = {}
                if not self.resultSummary.profile is None:
                    self.cypherLogDict["profile"] = self.resultSummary.profile
                else:
                    self.cypherLogDict["profile"] = {}
                if not self.resultSummary.counters is None:
                    self.stats = self.resultSummary.counters
                else:
                    self.stats  = None                    
            
            if rc == False:
                # save error message for log grid
                self.cypherLogDict["error"] = msg
                # see if there is a syntax error                
                if msg.find("CypherSyntaxError") > -1:
                    if msg.find("(offset: ") > -1:
                        self.cypherLogDict["offset"] =  int(msg[msg.find("(offset: ")+9 : msg.find(")", msg.find("(offset: ")) ])
            
            if not self.session is None:
                self.logScript('aSession.close()')
                self.session.close()
                self.logDriverStatus()
                
            return rc, msg         

    def runCypherExplicit(self, cypherText, parmData=None):
        '''  run a cypher query in an explicit txn
            consume the entire result set
            leave the transaction open for possible further queries
        '''
        

        # first create the driver  object if we haven't done that yet
        if self.myDriver is not None:
            pass
        else:
            rc, msg = self.setDriver()
            if rc == False:
                return False, msg
        
        try:
            rc = False
            errSuffix = "Run Cypher Explicit Error"   
            
            # create a session if we don't have one
            if self.session is None:
               self.logScript('aSession = aDriver.session()') 
               self.session =  self.myDriver.session()
               self.logDriverStatus()
               

                
            # get a new transaction if needed
            self.getNewTransaction()
            
            # now run the query 
            self.chunkStart = 0
            self.chunkEnd = 0    
            self.endReached = False
            self.cypherLogDict = {}
            self.cypherLogDict["error"] = ""
            self.cypherLogDict["offset"] = 0
            self.cypherLogDict["cypher"] = cypherText
            self.cypherLogDict["startTime"] = datetime.datetime.now()    

            if parmData is None:
                self.logScript('aResult = aTx.run("{}")'.format(cypherText))
                self.result = self.tx.run(cypherText)
                self.logDriverStatus()
            else:
                self.logScript('aResult = aTx.run("{}",parameters="{}"'.format(cypherText, parmData))
                self.result = self.tx.run(cypherText, parameters=parmData)
                self.logDriverStatus()
                

            # this consumes the entire result and saves it
#            self.logScript('aResultSet = aResult.data()')
            self.logScript('self.resultSet = []')
            self.logScript('for rec in self.result:')
            self.logScript('    self.resultSet.append(rec)')
            self.resultSet = []
            for rec in self.result:
                self.resultSet.append(rec)
            self.logDriverStatus()
            
            # this gets the query stats
            self.logScript('aResultSummary = aResult.consume()')
            self.resultSummary = self.result.consume()
            self.logDriverStatus() 
            
            # if autocommit is true then force a commit of this txn
            if self.autoCommit == True:
                self.commitTxn()
                             
            rc = True
            msg = "Cursor Created"
        except Neo4jError as e:
            msg =  "Neo4j Error :{} - {}".format(repr(e), errSuffix)
        except DriverError as e:
            msg =  "Driver Error :{} - {}".format(repr(e), errSuffix)
        except BaseException as e:
            msg =   "Base Exception :{} - {}".format(repr(e), errSuffix) 
        finally:
            self.cypherLogDict["endTime"] = datetime.datetime.now()
            # save query summary if present
            if not self.resultSummary is None:
                if not self.resultSummary.plan is None:
                    self.cypherLogDict["plan"] = self.resultSummary.plan
                else:
                    self.cypherLogDict["plan"] = {}
                if not self.resultSummary.profile is None:
                    self.cypherLogDict["profile"] = self.resultSummary.profile
                else:
                    self.cypherLogDict["profile"] = {}
                if not self.resultSummary.counters is None:
                    self.stats = self.resultSummary.counters
                else:
                    self.stats  = None                     

            if rc == False:
                # save error message for log grid
                self.cypherLogDict["error"] = msg
                # see if there is a syntax error
                if msg.find("SyntaxError") > -1:
                    if msg.find("(offset: ") > -1:
                        self.cypherLogDict["offset"] =  int(msg[msg.find("(offset: ")+9 : msg.find(")", msg.find("(offset: ")) ])

                # if we had an error then close the session
                if not self.session is None:
                    # if there's a transaction, then close it
                    if not self.tx is None:
                        self.closeTxn()
                        self.logDriverStatus()
                        
                    self.logScript('aSession.close()') 
                    self.session.close()
                    self.logDriverStatus()
                    
            return rc, msg  

    def forwardCursor(self, ):
        ctr = 0
        self.cursorChunk = []
        self.endReached = False
        try:
            errSuffix = "Error fetching rows"

            # make sure we have a result
            if not self.resultSet is None:
                # make sure there's at least one record
                if len(self.resultSet) > 0:
                    if len(self.resultSet) > self.chunkStart+self.chunkSize:
                        self.chunkEnd = self.chunkStart+self.chunkSize
                    else:
                        self.chunkEnd = len(self.resultSet)
                        self.endReached = True
                    # get the next chunk of records
                    for record in self.resultSet[self.chunkStart:self.chunkEnd]:
                        # append the next record to the chunk
                        self.cursorChunk.append(record)
                        ctr = ctr + 1
                        
                    self.chunkStart = self.chunkEnd
                    
                else:
                    self.endReached = True
                
            msg = "Fetch complete"
        except BaseException as e:
            msg =   "Base Exception :{} - {}".format(repr(e), errSuffix) 
        finally:
#            print('resultLen:{} chunkStart:{} chunkEnd:{}'.format(str(len(self.resultSet)), self.chunkStart, self.chunkEnd))
            return ctr, msg         
            
    def getNewTransaction(self, ):
        # create a new transaction if needed
        if self.tx is None:
            self.logScript('aTx = aSession.begin_transaction()')
            self.tx = self.session.begin_transaction()
            self.logDriverStatus()
            
            self.logMsg("Start first txn - AutoCommit = {}".format(self.autoCommit))
        else:
            if self.tx.closed() is True:
                self.logScript('aTx = aSession.begin_transaction()')
                self.tx = self.session.begin_transaction()
                self.logDriverStatus()
                
                self.logMsg("Start another txn - AutoCommit = {}".format(self.autoCommit))
            else:
                self.logMsg("Using the same transaction - AutoCommit = {}".format(self.autoCommit))    
                
    def commitTxn(self, ):
        '''
            if we are in a txn then commit it.
        '''
        try:
            rc = False
            errSuffix = "Commit Error"
            if not self.tx is None:
                if not self.tx.closed():
                    self.logScript('aTx.commit()')
                    self.tx.commit()
                    self.logDriverStatus()
                    
                    rc = True 
                    msg = "Transaction Committed"
                else:
                    rc = True
                    msg = "no active txn to commit"
            else:
                rc = True
                msg = "no txn exists to commit"
            
        except Neo4jError as e:
            msg =  "Neo4j Error :{} - {}".format(repr(e), errSuffix)
        except DriverError as e:
            msg =  "Driver Error :{} - {}".format(repr(e), errSuffix)
        except BaseException as e:
            msg =   "Base Exception :{} - {}".format(repr(e), errSuffix) 
        finally:
            self.logMsg(msg)
            return rc, msg             
        
    def closeTxn(self, ):
        '''
            if we are in a txn then close it.  uncommitted txn's will be rolled back
        '''
        try:
            rc = False
            errSuffix = "Txn Close Error"
            if not self.tx is None:
                if not self.tx.closed():
                    self.logScript('aTx.close() # implied rollback')
                    self.tx.close()
                    self.logDriverStatus()
                    
                    rc = True 
                    msg = "Transaction Closed"
                else:
                    rc = True
                    msg = "no active txn to close"
            else:
                rc = True
                msg = "no txn exists to close"
            
        except Neo4jError as e:
            msg =  "Neo4j Error :{} - {}".format(repr(e), errSuffix)
        except DriverError as e:
            msg =  "Driver Error :{} - {}".format(repr(e), errSuffix)
        except BaseException as e:
            msg =   "Base Exception :{} - {}".format(repr(e), errSuffix) 
        finally:
            self.logMsg(msg)
            return rc, msg             
        
        
    def rollbackTxn(self, ):    
        '''
            if we are in a txn then do a rollback.
        '''
        try:
            rc = False
            errSuffix = "RollBack Error"
            if not self.tx is None:
                if not self.tx.closed():
                    self.logScript('aTx.rollback()')
                    self.tx.rollback()
                    self.logDriverStatus()
                    
                    rc = True 
                    msg = "Transaction Rolled Back"
                else:
                    rc = True
                    msg = "no active txn to roll back"
            else:
                rc = True
                msg = "no txn exists to roll back"
            
        except Neo4jError as e:
            msg =  "Neo4j Error :{} - {}".format(repr(e), errSuffix)
        except DriverError as e:
            msg =  "Driver Error :{} - {}".format(repr(e), errSuffix)
        except BaseException as e:
            msg =   "Base Exception :{} - {}".format(repr(e), errSuffix) 
        finally:
            self.logMsg(msg)
            return rc, msg             
            
    def setDriver(self):
        # create a driver object to run transactions
        try:
            if self.myDriver is None:                
                rc = False
                errSuffix = "Driver Object Error"
                # get the keyword parameters from the necon dictionary
                uri = "bolt://{}:{}".format(self.neoDict["host"], self.neoDict["port"])
                # create a base driver graphdatabase object, this verifies connectivity and authentication and will produce usable error messages if anything is wrong.
                self.myDriver = None
                pw = self.helper.getText(self.neoDict['password'])
                self.logScript('aDriver = GraphDatabase.driver({},auth=({},{})'.format(uri, self.neoDict['userid'], pw))
                self.myDriver = GraphDatabase.driver(uri,auth=(self.neoDict['userid'], pw))
                self.logDriverStatus()
                
                rc = True 
                msg = "Connection Created"
                # save the URI 
                self.neoDict["URL"] = uri
            else:
                rc = True
                msg = "Connection Exists"
        except Neo4jError as e:
            msg =  "Neo4j Error :{} - {}".format(repr(e), errSuffix)
        except DriverError as e:
            msg =  "Driver Error :{} - {}".format(repr(e), errSuffix)
        except BaseException as e:
            msg =   "Base Exception :{} - {}".format(repr(e), errSuffix) 
        finally:
            if rc == False:
                self.myDriver = None
            return rc, msg             
            

    def test(self):
        # test the connection to see if it is working
        # this will create a new driver object if none has been created or it will use the existing driver
        try:
            rc = False
            errSuffix = "Test Neo4j Connection: {}".format(self.name)
            rc, msg = self.runCypherAuto("match (n) return n limit 1")
            if rc == True:
                msg = "Connection Successful: {}".format(self.name)
        except Neo4jError as e:
            msg =  "Neo4j Error :{} - {}".format(repr(e), errSuffix)
        except DriverError as e:
            msg =  "Driver Error :{} - {}".format(repr(e), errSuffix)
        except BaseException as e:
            msg =   "Base Exception :{} - {}".format(repr(e), errSuffix) 
        finally:
            return rc, msg                     
示例#3
0
class NodeeraMain(QMainWindow, Ui_NodeeraMain):

    displayWelcomeMsg = pyqtSignal(str)
    closeWelcomeMsg = pyqtSignal()
    """
    Create Ui_NodeeraMain and display it.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget
        @type QWidget
        """
        super(NodeeraMain, self).__init__(parent)
        self.setupUi(self)
        self.parent = parent

        # object data
        self.pageDict = {}
        self.curPage = None
        self.helper = Helper()

        # get startup settings
        self.initSettings()

        # launch the welcome wagon
        self.welcomeDlg = HelloUserDlg(self)
        self.welcomeDlg.show()
        QApplication.processEvents()
        self.displayWelcomeMsg.emit("Starting NodeEra...")

        # setup stuff not covered by generated code
        icon = QIcon()
        icon.addPixmap(QPixmap("icons/RUN and DATA TAB/Disconnected.png"),
                       QIcon.Normal, QIcon.Off)
        self.actionOpen_Connection.setIcon(icon)

        # main window
        self.setTitle("No Connection")
        self.resize(self.winSize)
        self.move(self.position)

        # display welcome message
        self.displayWelcomeMsg.emit("Welcome To NodeEra")

        # display announcement message from website
        try:
            url = 'https://{}'.format(appPage)
            response = requests.get(url)
            if response.status_code == 200:
                start = response.text.find('class="display"') + 16
                end = response.text.find('</p>', start)
                self.displayWelcomeMsg.emit(response.text[start:end])
                self.displayWelcomeMsg.emit(
                    "For more information see www.singerlinks.com/nodeera")
            else:
                self.logMsg(
                    "Unable to access announcement page:{} http response:{}".
                    format(appPage, response.status_code))
                self.displayWelcomeMsg.emit(
                    "Unable to access announcement page:{} http response:{}".
                    format(appPage, response.status_code))

        except Exception as e:
            self.logMsg("Error accessing announcement page - {}".format(
                repr(e)))
            self.displayWelcomeMsg.emit(
                "Error accessing announcement page - {}".format(repr(e)))

        # auto open last used connection
        try:
            lastNeoConName = self.settings.value("NeoCon/LastUsed")
            if not lastNeoConName is None:
                neoDict = self.settings.value(
                    "NeoCon/connection/{}".format(lastNeoConName))
                self.openConnection(neoConName=lastNeoConName,
                                    neoConDict=neoDict)
                self.displayWelcomeMsg.emit(" ")
                self.displayWelcomeMsg.emit(
                    "Opened most recent connection: {}".format(lastNeoConName))

            self.setTitle(lastNeoConName)

        except:
            self.logMsg(
                "Unable to open last connection: {}".format(lastNeoConName))
            self.displayWelcomeMsg.emit(
                "Unable to open last connection: {}".format(lastNeoConName))

        # auto close the welcome dialog box
#        time.sleep(5)
#        self.closeWelcomeMsg.emit()

    def logMsg(self, msg):
        if logging:
            logging.info(msg)

    def initSettings(self, ):
        '''
        get the system settings needed to start NodeEra.
        If a system setting doesn't exist then create it with default value - this happens on initial startup
        '''
        self.settings = QSettings()
        try:
            self.expirationDate = self.helper.getText(
                self.settings.value("License/expirationDate"))
            if self.expirationDate is None:
                self.expirationDate = 'No expiration date set'
                self.settings.setValue(
                    "License/expirationDate",
                    self.helper.putText(self.expirationDate))
        except:
            self.expirationDate = 'No expiration date set'
            self.settings.setValue("License/expirationDate",
                                   self.helper.putText(self.expirationDate))

        try:
            self.currentVersion = self.settings.value("License/currentVersion")
            if self.currentVersion is None:
                self.currentVersion = currentVersion
                self.settings.setValue("License/currentVersion",
                                       self.currentVersion)
            elif self.currentVersion != currentVersion:
                self.currentVersion = currentVersion
                self.settings.setValue("License/currentVersion",
                                       self.currentVersion)
        except:
            self.currentVersion = currentVersion
            self.settings.setValue("License/currentVersion",
                                   self.currentVersion)

        try:
            self.winSize = self.settings.value("MainWindow/Size")
            if self.winSize is None:
                self.winSize = QSize(800, 500)
        except:
            self.winSize = QSize(800, 500)

        try:
            self.position = self.settings.value("MainWindow/Position")
            if self.position is None:
                self.position = QPoint(0, 0)
        except:
            self.position = QPoint(0, 0)

        try:
            self.recentList = self.settings.value("Default/RecentList")
            if self.recentList is None:
                self.recentList = []
                self.settings.setValue("Default/RecentList", self.recentList)
        except:
            self.recentList = []
            self.settings.setValue("Default/RecentList", self.recentList)

        try:
            self.defaultLoggingPath = self.settings.value(
                "Default/LoggingPath")
            if self.defaultLoggingPath is None:
                self.logDir = os.getcwd()
                self.logDir = os.path.realpath(os.path.abspath(self.logDir))
                self.settings.setValue("Default/LoggingPath", self.logDir)
        except:
            self.logDir = os.getcwd()
            self.logDir = os.path.realpath(os.path.abspath(self.logDir))
            self.settings.setValue("Default/LoggingPath", self.logDir)

        try:
            self.defaultProjPath = self.settings.value("Default/ProjPath")
            if self.defaultProjPath is None:
                self.defaultProjPath = os.getcwd()
                self.defaultProjPath = os.path.realpath(
                    os.path.abspath(self.defaultProjPath))
                self.settings.setValue("Default/ProjectPath",
                                       self.defaultProjPath)
        except:
            self.defaultProjPath = os.getcwd()
            self.defaultProjPath = os.path.realpath(
                os.path.abspath(self.defaultProjPath))
            self.settings.setValue("Default/ProjectPath", self.defaultProjPath)

        # default custom formats for diagram objects
        # Display Format - Instance Node
        try:
            test = self.settings.value("Default/Format/InstanceNode")
            if test is None:
                self.settings.setValue("Default/Format/InstanceNode",
                                       INodeFormat().formatDict)
        except:
            self.settings.setValue("Default/Format/InstanceNode",
                                   INodeFormat().formatDict)

        # Display Format - Instance Relationship
        try:
            test = self.settings.value("Default/Format/InstanceRelation")
            if test is None:
                self.settings.setValue("Default/Format/InstanceRelation",
                                       IRelFormat().formatDict)
        except:
            self.settings.setValue("Default/Format/InstanceRelation",
                                   IRelFormat().formatDict)

        # Display Format - Template Node
        try:
            test = self.settings.value("Default/Format/TemplateNode")
            if test is None:
                self.settings.setValue("Default/Format/TemplateNode",
                                       TNodeFormat().formatDict)
        except:
            self.settings.setValue("Default/Format/TemplateNode",
                                   TNodeFormat().formatDict)

        # Display Format - Template Relationship
        try:
            test = self.settings.value("Default/Format/TemplateRelation")
            if test is None:
                self.settings.setValue("Default/Format/TemplateRelation",
                                       TRelFormat().formatDict)
        except:
            self.settings.setValue("Default/Format/TemplateRelation",
                                   TRelFormat().formatDict)

        # page setup
        try:
            test = self.settings.value("Default/PageSetup")
            if test is None:
                self.settings.setValue("Default/PageSetup",
                                       PageSetup().objectDict)
        except:
            self.settings.setValue("Default/PageSetup", PageSetup().objectDict)

        # default project neocon
        try:
            defaultNeoConName = self.settings.value("NeoCon/Default")
            if defaultNeoConName is None:
                self.settings.setValue("NeoCon/Default", "LOCAL")
        except:
            self.settings.setValue("NeoCon/Default", "LOCAL")

        # LOCAL neocon definition
        try:
            self.localNeoCon = self.settings.value("NeoCon/connection/LOCAL")
            if self.localNeoCon is None:
                self.settings.setValue("NeoCon/connection/LOCAL",
                                       NeoDriver().localNeoConDict())
        except:
            self.settings.setValue("NeoCon/connection/LOCAL",
                                   NeoDriver().localNeoConDict())

        # default lexer font size
        try:
            defaultLexerFontSize = self.settings.value("Lexer/FontSize")
            if defaultLexerFontSize is None:
                self.settings.setValue("Lexer/FontSize", "10")
        except:
            self.settings.setValue("Lexer/FontSize", "10")

        # validate all neocons have the prompt dictionary key which was added in 1.04
        self.settings.beginGroup("NeoCon/connection")
        neoKeys = self.settings.childKeys()
        for key in neoKeys:
            neoDict = self.settings.value(key)
            promptVal = neoDict.get("prompt", None)
            if promptVal is None:
                neoDict["prompt"] = "False"
                self.settings.setValue(key, neoDict)

        self.settings.endGroup()

    def setTitle(self, filename):
        self.setWindowTitle("{} - {}".format(productName, filename))

    def setMenuAccess(self, ):
        '''
        determine what connection tab is currently selected and enable/disable menu items as needed
        '''
        # turn on all Settings menu items
        for action in self.menuSettings.actions():
            if type(action) == QAction and not action.isSeparator():
                action.setEnabled(True)

        try:
            # get tab widget (schema or project) that is currently active - if there isn't one this will cause an exception
            currentTab = self.stackedPageItems.currentWidget(
            ).tabPage.currentWidget()
            # enable all the schema actions
            for action in self.menuNeo.actions():
                if type(action) == QAction and not action.isSeparator():
                    action.setEnabled(True)
            for action in self.menuProject.actions():
                # enable project actions
                if type(action) == QAction and not action.isSeparator():
                    if currentTab.pageType == "PROJECT":
                        action.setEnabled(True)
                    else:
                        if action.text() in [
                                "New", "Open...", "Recent Projects"
                        ]:
                            action.setEnabled(True)
                        else:
                            action.setEnabled(False)

        except:
            # no connection tabs are open
            # disable all project menu actions
            for action in self.menuProject.actions():
                if type(action) == QAction and not action.isSeparator():
                    action.setEnabled(False)
            for action in self.menuNeo.actions():
                if type(action) == QAction and not action.isSeparator():
                    if action.text() in [
                            "Close Connection", "Generate Schema..."
                    ]:
                        action.setEnabled(False)
                    else:
                        action.setEnabled(True)

    ########################################################################
    #     NEO CONNECTION Dropdown Menu Actions
    ########################################################################
    @pyqtSlot()
    def on_actionOpen_Connection_triggered(self):
        """
        This slot provides functionality for the open connection button
        """
        d = dlgNeoCons(parent=self)
        if d.exec_():
            if d.selectedNeoConName:
                # make sure it isn't already opened
                if d.selectedNeoConName not in self.pageDict:
                    self.openConnection(neoConName=d.selectedNeoConName,
                                        neoConDict=d.selectedNeoConDict)
                else:
                    self.helper.displayErrMsg(
                        "NodeEra - Open Connection",
                        "Connection {} is already open.".format(
                            d.selectedNeoConName))
                    # switch to the page they tried to open
                    self.pageDict[d.selectedNeoConName].actionButton.trigger()

    def openConnection(self, neoConName=None, neoConDict=None):
        '''
        User selects a connection to open so create the schema page and display it
        '''
        # set the last used neocon in system settings
        self.settings.setValue("NeoCon/LastUsed", neoConName)
        # create a new toolbar button and add it to the toolbar
        newConAction = QAction(self)
        newConAction.setObjectName("newConnection")
        newConAction.setText("Neo4j - {}".format(neoConName))
        newConAction.setData(neoConName)

        newConAction.setToolTip(neoConDict["URL"])
        newConAction.setCheckable(True)
        newConAction.setChecked(True)
        newConAction.triggered.connect(self.connectionClicked)
        self.tbConnection.addAction(newConAction)

        # add a tabPage widget to the stacked widget
        newPageWidget = PageWidget(parent=self)
        newPageWidget.pageType = "Schema"
        widgetIndex = self.stackedPageItems.addWidget(newPageWidget)
        # save new pageItem
        newPageItem = PageItem(neoConName=neoConName,
                               actionButton=newConAction,
                               pageWidget=newPageWidget,
                               pageWidgetIndex=widgetIndex)
        self.pageDict[neoConName] = newPageItem
        # add the schema tab
        cypherTab = CypherPageWidget(parent=self, pageItem=newPageItem)
        newPageWidget.tabPage.addTab(cypherTab,
                                     "Schema - {}".format(neoConName))

        # click the new action to force selection logic
        newConAction.trigger()
        self.logMsg("Open Connection: {}".format(neoConName))

    @pyqtSlot()
    def connectionClicked(self):
        '''
        User clicks on a connection in the menu bar so switch to that stacked widget
        '''
        self.logMsg("connection clicked {}".format(self.sender().text()))
        # uncheck all the page action buttons
        for pageName in self.pageDict:
            self.pageDict[pageName].actionButton.setChecked(False)
        # check the one just clicked
        self.sender().setChecked(True)
        # save the current page name
        self.curPage = self.sender().data()
        # switch the stacked page widget to the one just clicked
        self.stackedPageItems.setCurrentIndex(
            self.pageDict[self.curPage].pageWidgetIndex)
        # update the main window title
        self.setTitle(self.curPage)
        # adjust the menu items
        self.setMenuAccess()

    @pyqtSlot()
    def on_actionClose_Connection_triggered(self):
        """
        Close the active connection and remove the page from the UI
        """
        if self.curPage:
            if self.curPage in self.pageDict:
                # must find the schema tab and tell it to close, it will tell all other tabs to close.  schema tab is always the first one (index=0)
                self.pageDict[self.curPage].pageWidget.closeSchemaTab()
                self.removeConnection()

    def removeConnection(self, ):
        '''if the tab page widget is responding to the close request it only needs this logic to remove the connection
        '''
        curPage = self.pageDict.get(self.curPage, None)
        if not curPage is None:
            # remove the pageWidget from the stacked widget
            self.stackedPageItems.removeWidget(
                self.pageDict[self.curPage].pageWidget)
            del self.pageDict[self.curPage].pageWidget
            # remove the action from menu's and toolbars
            self.tbConnection.removeAction(
                self.pageDict[self.curPage].actionButton)
            # take the page out of the dictionary
            del self.pageDict[self.curPage]
            # if any pages left select the first one
            if len(self.pageDict) > 0:
                for pageName in self.pageDict:
                    self.pageDict[pageName].actionButton.trigger()
                    break
            else:
                # there are no open connections and the home page is closed
                self.setTitle("No Connection")

    @pyqtSlot()
    def on_actionNeo4j_Connection_Manager_triggered(self):
        """
        Display the Connection Manager
        """
        d = dlgNeoCons(parent=self)
        if d.exec_():
            pass

    @pyqtSlot()
    def on_actionExit_triggered(self):
        """
        User selected the File / Exit menu item.  Tell all the open connections to close
        """
        self.closeOpenStuff()
        # close the app
        self.close()

    def closeEvent(self, event):
        # close open connections
        self.closeOpenStuff()
        #save the window state
        self.settings.setValue("MainWindow/Size", self.size())
        self.settings.setValue("MainWindow/Position", self.pos())

        event.accept()

    def closeOpenStuff(self):
        # get a list of all the keys in the pageDict dictionary
        keys = list(self.pageDict.keys())
        # iterate thru the list of dictionary keys.  this is required as the dictionary will be changing size, i.e. you can't simply iterate thru the dictionary
        for key in keys:
            pageItem = self.pageDict[key]
            actionButton = pageItem.actionButton
            actionButton.trigger()
            # must find the schema tab and tell it to close, it will tell all other tabs to close.  schema tab is always the first one (index=0)
            pageItem.pageWidget.closeSchemaTab()
            self.removeConnection()

#####################################################################
# SETTINGS DROPDOWNS
#####################################################################

    @pyqtSlot()
    def on_actionSystem_Preferences_triggered(self):
        """
        User selects the System Preferences menu item.  Display the system preferences dialog box.
        """
        self.editSystemPreferences()

    def editSystemPreferences(self, ):
        """
        User selects the System Preferences menu item.  Display the system preferences dialog box.
        """
        if not (self.settings is None):
            d = SystemPreferenceBox(self, settings=self.settings)
            if d.exec_():
                self.settings.sync()

#####################################################################
# PROJECT METHODS
#####################################################################

    @pyqtSlot()
    def on_actionNewProject_triggered(self):
        """
        Open new project
        """
        self.loadProject(fileName=None)

    @pyqtSlot()
    def on_actionOpenProject_triggered(self):
        """
        Open an existing project file
        """
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.ExistingFile)
        dlg.setAcceptMode(QFileDialog.AcceptOpen)
        dlg.setNameFilters(["NodeEra Project (*.mdl)", "all files (*.*)"])
        dlg.setDirectory(self.settings.value("Default/ProjPath"))
        if dlg.exec_():
            fileNames = dlg.selectedFiles()
            if fileNames:
                fileName = fileNames[0]
                self.loadProject(fileName=fileName)

    @pyqtSlot()
    def on_actionSaveProject_triggered(self):
        """
        Save the open project
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "PROJECT":
                newName = curPageWidget.tabPage.currentWidget().saveProject()
                # if this was an unsaved project then it was really a save as so the tab name has to be updated
                if newName is not None:
                    curPageWidget.tabPage.setTabText(
                        curPageWidget.tabPage.currentIndex(),
                        "Project: {} - {}".format(
                            newName, self.pageDict[self.curPage].neoConName))

    @pyqtSlot()
    def on_actionSaveProjectAs_triggered(self):
        """
        Save Project As
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "PROJECT":
                newName = curPageWidget.tabPage.currentWidget().saveProjectAs()
                if newName is not None:
                    curPageWidget.tabPage.setTabText(
                        curPageWidget.tabPage.currentIndex(),
                        "Project: {} - {}".format(
                            newName, self.pageDict[self.curPage].neoConName))

    @pyqtSlot()
    def on_actionReverse_Engineer_triggered(self):
        """
        User selects the Reverse Engineer menu item.  Display the Reverse Engineer dialog box.
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "PROJECT":
                curPageWidget.tabPage.currentWidget().reverseEngineerGraph()
            else:
                self.helper.displayErrMsg(
                    "Reverse Engineer", "{} not a project".format(
                        curPageWidget.tabPage.currentWidget().pageType))

    @pyqtSlot()
    def on_actionProjectProperties_triggered(self):
        """
        User selects the project properties menu item. Display the project properties dialog box.
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "PROJECT":
                curPageWidget.tabPage.currentWidget().editProjectProperties()
            else:
                self.helper.displayErrMsg(
                    "Project Properties", "{} not a project".format(
                        curPageWidget.tabPage.currentWidget().pageType))

    def getSchemaObject(self, ):
        curPageWidget = self.stackedPageItems.currentWidget()
        for ctr in range(0, curPageWidget.tabPage.count()):
            tab = curPageWidget.tabPage.widget(ctr)
            if tab.pageType == "CYPHER":
                return tab.schemaModel
        return None

    def getSchemaTab(self, ):
        curPageWidget = self.stackedPageItems.currentWidget()
        for ctr in range(0, curPageWidget.tabPage.count()):
            tab = curPageWidget.tabPage.widget(ctr)
            if tab.pageType == "CYPHER":
                return tab
        return None

    def loadProject(self, fileName=None):
        '''
        Load the project file with name fileName.  If fileName is None, create a new empty project.
        '''

        # create a temporary file name if its a new project
        if fileName is None:
            # update unnamed file counter
            global unNamedFileCounter
            unNamedFileCounter = unNamedFileCounter + 1
            shortName = "{}".format(
                "New Project-0{}".format(unNamedFileCounter))
        else:
            head, shortName = ntpath.split(QFileInfo(fileName).fileName())

        # make sure the project isn't already loaded
        curPageWidget = self.stackedPageItems.currentWidget()
        for ctr in range(0, curPageWidget.tabPage.count()):
            tab = curPageWidget.tabPage.widget(ctr)
            if tab.pageType == "PROJECT":
                if (not fileName is None) and (tab.fileName == fileName):
                    self.helper.displayErrMsg(
                        "Open Project",
                        "The project file: {} is already open.  It can only be open once."
                        .format(fileName))
                    return

        # create the project widget
        projectTab = ProjectPageWidget(parent=self,
                                       settings=self.settings,
                                       pageItem=self.pageDict[self.curPage],
                                       fileName=fileName)

        curPageWidget = self.stackedPageItems.currentWidget()

        # add the project widget as a tab on the current page widget
        x = curPageWidget.tabPage.addTab(
            projectTab,
            "Project: {} - {}".format(shortName,
                                      self.pageDict[self.curPage].neoConName))
        curPageWidget.tabPage.setCurrentIndex(x)

    @pyqtSlot()
    def on_actionOnline_Help_triggered(self):
        """
        User selects the Online Help menu item.  Dislay Online Help menu.
        """
        d = OnlineHelpDLG(self)
        if d.exec_():
            pass

    @pyqtSlot()
    def on_actionAbout_triggered(self):
        """
        User selects Help / About menu item.  Display the about dialog box
        """
        d = HelpAboutDLG(self)
        if d.exec_():
            pass

    @pyqtSlot()
    def on_actionGenerate_Schema_triggered(self):
        """
        User requests the generate schema dialog box from main menu
        """
        d = GenerateSchemaDlg(self)
        if d.exec_():
            pass

    @pyqtSlot()
    def on_actionForward_Engineer_triggered(self):
        """
        User requests to perform forward engineering from the open project from main menu
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "PROJECT":
                curPageWidget.tabPage.currentWidget().forwardEngineerGraph()
            else:
                self.logMsg(
                    "User requested to forward engineer but current tab is not a Project"
                )

    @pyqtSlot()
    def on_actionGenerate_Reports_triggered(self):
        """
        User selects the Generate Project Reports menu item.  Display the Generate Reports dialog box.
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "PROJECT":
                curPageWidget.tabPage.currentWidget().generateProjectReports()

    @pyqtSlot()
    def on_actionReset_User_Password_triggered(self):
        """
        User requests the change user password from main menu
        """
        curPageWidget = self.stackedPageItems.currentWidget()
        if not curPageWidget is None:
            if curPageWidget.tabPage.currentWidget().pageType == "CYPHER":
                curPageWidget.tabPage.currentWidget().resetPassword()

    @pyqtSlot(QAction)
    def on_menuRecent_Projects_triggered(self, action):
        """
        User clicked on a recent file menu item
        
        @param action DESCRIPTION
        @type QAction
        """
        self.loadProject(fileName=action.data())

    @pyqtSlot()
    def on_menuRecent_Projects_aboutToShow(self):
        """
        user hovering on recent projects menu item
        """
        recentList = self.settings.value("Default/RecentList")
        if len(recentList) == 0:
            return
        else:
            # remove any existing actions
            self.menuRecent_Projects.clear()
            for projectFile in recentList:
                # create actions for the recent files
                aSubAction = self.menuRecent_Projects.addAction(projectFile)
                aSubAction.setData(projectFile)
示例#4
0
class ChangeUserPW(QDialog, Ui_ChangeUserPW):
    """
    Class documentation goes here.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget
        @type QWidget
        """
        super(ChangeUserPW, self).__init__(parent)
        self.setupUi(self)
        self.helper = Helper()
        self.settings = QSettings()
        self.parent = parent
        self.editPW.setEchoMode(QLineEdit.Password)
        self.editNewPW.setEchoMode(QLineEdit.Password)
        self.editRepeatPW.setEchoMode(QLineEdit.Password)
        
    def logMessage(self, msg):
        if logging:
            logging.info(msg)                    
            
    @pyqtSlot()
    def on_btnCurrentShow_clicked(self):
        """
        User clicks the show button for the current password
        """
        if self.btnCurrentShow.text() == "Show":
            self.btnCurrentShow.setText("Hide")
            self.editPW.setEchoMode(QLineEdit.Normal)
        else:
            self.btnCurrentShow.setText("Show")
            self.editPW.setEchoMode(QLineEdit.Password)            
    
    @pyqtSlot()
    def on_btnNewShow_clicked(self):
        """
        User clicks the show button for the new passwords
        """
        if self.btnNewShow.text() == "Show":
            self.btnNewShow.setText("Hide")
            self.editNewPW.setEchoMode(QLineEdit.Normal)
            self.editRepeatPW.setEchoMode(QLineEdit.Normal)
        else:
            self.btnNewShow.setText("Show")
            self.editNewPW.setEchoMode(QLineEdit.Password)      
            self.editRepeatPW.setEchoMode(QLineEdit.Password)      
    
    @pyqtSlot()
    def on_btnReset_clicked(self):
        """
        User clicks the reset password button so do it
        """
        if self.validate():
            self.resetPassword()

    def validate(self, ):
        if self.helper.NoTextValueError(self.editUserID.text(), "You must enter a user ID to login with."):
            self.editUserID.setFocus()
            return False        
        if self.helper.NoTextValueError(self.editPW.text(), "You must enter a password to login with."):
            self.editPW.setFocus()
            return False        
        if self.helper.NoTextValueError(self.editNewPW.text(), "You must enter a new password."):
            self.editNewPW.setFocus()
            return False        
        if self.helper.NoTextValueError(self.editRepeatPW.text(), "You must repeat the new password."):
            self.editRepeatPW.setFocus()
            return False      
        if self.editNewPW.text() != self.editRepeatPW.text():
            self.helper.displayErrMsg("Reset Password", "The new password does not match the repeat password.")
            self.editNewPW.setFocus()
            return False    
        
        return True

    def resetPassword(self):
        '''login to Neo4j and reset the password
        '''
        # get the currently selected schema tab's neocon name
        newConName = self.parent.pageItem.neoConName
        # get the neocon dictionary from settings
        newConDict = self.settings.value("NeoCon/connection/{}".format(newConName))
        newConDict["userid"]=self.editUserID.text()
        savePW = self.helper.putText(self.editPW.text())
        newConDict["password"]=savePW
        # create a new neoCon using the userid/password the person entered on this form
        self.newNeoCon = NeoDriver(name=newConName,  neoDict = newConDict)
        
        QApplication.setOverrideCursor(Qt.WaitCursor)
        rc, msg = self.changePassword(userName=self.editUserID.text(), pw=self.editNewPW.text(), forceChange=False)
        if rc:
            self.helper.displayErrMsg("Change Password", msg)
        else:
            self.helper.displayErrMsg("Change Password Error", msg)
        QApplication.restoreOverrideCursor()         

    def changePassword(self, userName=None, pw=None, forceChange=None):
        try:
#            cypherCmd = "CALL dbms.security.changeUserPassword('{}','{}',{})".format(userName, pw, str(forceChange))
            cypherCmd = "CALL dbms.changePassword('{}')".format(pw)
            self.logMessage("Attempting: {}".format(cypherCmd))
            #run the query
            rc1, msg1 = self.newNeoCon.runCypherAuto(cypherCmd)
            if rc1:
                msg = "Password Changed."       
            else:
                msg = "Change Password Error {}".format(msg1)
        except BaseException as e:
            msg = "{} - Change Password Error.".format(repr(e))
        finally: 
            self.logMessage(msg) 
            return rc1, msg                          
        
    @pyqtSlot()
    def on_btnClose_clicked(self):
        """
        User clicks the Close button so exit the dialog
        """
        QDialog.accept(self)
示例#5
0
class NeoConPropertyBox(QDialog, Ui_NeoConPropertyBox):
    """
    Display the property editor for a neo4j connection definition
    """
    def __init__(self, parent=None, mode=None, objectDict=None):
        """
        Constructor
        
        @param parent reference to the parent widget
        @type QWidget
        """
        super(NeoConPropertyBox, self).__init__(parent)
        self.parent = parent
        self.mode = mode
        self.objectDict = objectDict
        self.helper = Helper()
        self.setupUi(self)
        self.chkSecureCon.setTristate(False)
        self.populateUIfromObject()

    def populateUIfromObject(self, ):

        # window title
        self.setWindowTitle("Neo4j Connection: {}".format(
            self.objectDict["slot"]))

        if self.objectDict["usesecure"] == "True":
            self.chkSecureCon.setCheckState(Qt.Checked)
        else:
            self.chkSecureCon.setCheckState(Qt.Unchecked)

        if self.objectDict["prompt"] == "True":
            self.chkPromptForPW.setCheckState(Qt.Checked)
            self.editPassWord.setReadOnly(True)
            self.btnShow.setEnabled(False)
        else:
            self.chkPromptForPW.setCheckState(Qt.Unchecked)

        self.conType = self.objectDict.get("conType", "bolt")
        index = self.cboScheme.findText(self.conType)
        if index >= 0:
            self.cboScheme.setCurrentIndex(index)

        self.editHostName.insert(self.objectDict["host"])
        self.editPort.insert(self.objectDict.get("port", ""))
        self.editUserid.insert(self.objectDict["userid"])
        pw = self.objectDict["password"]
        if len(pw) > 0:
            displayPw = self.helper.getText(pw)
        else:
            displayPw = ""
        # only display the password if the prompt checkbox is unchecked.
        if self.objectDict["prompt"] == "False":
            self.editPassWord.insert(displayPw)

    @pyqtSlot(str)
    def on_cboScheme_currentIndexChanged(self, p0):
        """
        User selects the connection type from the dropdown.
        Change the secure connection checkbox as appropriate
        
        @param p0 DESCRIPTION
        @type str
        """
        pass

    @pyqtSlot()
    def on_okButton_clicked(self):
        """
        User selects OK button, edit data, then save/close the dialog box if ok.
        """
        if self.validate():
            self.apply()
            QDialog.accept(self)
        else:
            return

    @pyqtSlot()
    def on_cancelButton_clicked(self):
        """
        User selects Cancel button, close dialog box without saving
        """
        QDialog.reject(self)

    def validate(self):
        '''
        Validate the user has entered correct data.
        '''
        # edit host name field
        if self.helper.NoTextValueError(self.editHostName.text(),
                                        "Must supply a host name."):
            return False
        # edit port field
        if self.helper.NoTextValueError(self.editPort.text(),
                                        "Must supply a port number."):
            return False
        # userid field
        if self.helper.NoTextValueError(self.editUserid.text(),
                                        "Must supply a user id."):
            return False

        return True

    def apply(self, ):
        self.objectDict["conType"] = self.cboScheme.currentText()
        self.objectDict["port"] = self.editPort.text()
        self.objectDict["host"] = self.editHostName.text()
        self.objectDict["userid"] = self.editUserid.text()
        pw = self.editPassWord.text()
        if len(pw) > 0:
            savePw = self.helper.putText(pw)
        else:
            savePw = ""
        self.objectDict["password"] = savePw
        if self.chkSecureCon.isChecked():
            self.objectDict["usesecure"] = "True"
        else:
            self.objectDict["usesecure"] = "False"
        if self.chkPromptForPW.isChecked():
            self.objectDict["prompt"] = "True"
        else:
            self.objectDict["prompt"] = "False"

        return

    @pyqtSlot()
    def on_btnShow_clicked(self):
        """
        User clicked the Show button so show the password in clear text
        """
        if self.btnShow.text() == "Show":
            self.btnShow.setText("Hide")
            self.editPassWord.setEchoMode(QLineEdit.Normal)
        else:
            self.btnShow.setText("Show")
            self.editPassWord.setEchoMode(QLineEdit.Password)
        return

    @pyqtSlot(bool)
    def on_chkPromptForPW_clicked(self, checked):
        """
        User selects to prompt for password instead of saving the password.
        
        @param checked DESCRIPTION
        @type bool
        """
        # user sets prompt for password to true
        if checked:
            # warn user the currently set password will be cleared
            if len(self.editPassWord.text()) > 0:
                msgBox = QMessageBox()
                msgBox.setIcon(QMessageBox.Warning)
                msgBox.setText(
                    "Warning: This will clear the password from the screen. Do you want to continue?"
                )
                msgBox.setWindowTitle("CONFIRM CLEAR PASSWORD")
                msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
                result = msgBox.exec_()
                if result == QMessageBox.No:
                    # clear the checkbox
                    self.chkPromptForPW.setChecked(Qt.Unchecked)
                    return
            # return password text edit to normal state if it is currently showing
            if self.btnShow.text() == "Hide":
                self.btnShow.setText("Show")
            self.editPassWord.setEchoMode(QLineEdit.Password)
            # clear the text edit
            self.editPassWord.setText("")
            # disable password entry
            self.editPassWord.setReadOnly(True)
            self.btnShow.setEnabled(False)
            # clear the password from settings

        else:
            # enable password entry
            self.editPassWord.setReadOnly(False)
            self.btnShow.setEnabled(True)
            self.editPassWord.setEchoMode(QLineEdit.Password)
            if self.btnShow.text() == "Hide":
                self.btnShow.setText("Show")