예제 #1
0
class SLTest(unittest.TestCase):

    """
    Store the serverlist in this directory.
    """
    def setUp(self):
        #print "setUp"
        self.sl = ServerList(tempfile.gettempdir(), "serverlisttest.xml")
        #self.sl.__configFile = os.path.join(self.sl._configPrefix, "serverlist.xml")

    def tearDown(self):
        pass


    """
    Writes a serverlist in the current format to disk.
    """
    def writeList(self):
        #print "writeList"
        try:
            f = open(self.sl.getConfigFilePath(), "w")
            f.write("""
<!DOCTYPE LumaServerFile>
<LumaServerList version="1.2">
 <LumaLdapServer port="1337" clientCertFile="" followAliases="0" clientCertKeyfile="" bindPassword="******" useCertificate="0" bindDN="" host="directory.d-trust.de" authMethod="1" bindAnon="1" encryptionMethod="0" name="d-trust" autoBase="0" checkServerCertificate="1">
  <baseDNs>
   <base dn="dc=d-trust,dc=de"/>
   <base dn="dc=ntnu,dc=no.TULL"/>
  </baseDNs>
 </LumaLdapServer>
 <LumaLdapServer port="389" clientCertFile="" followAliases="0" clientCertKeyfile="" bindPassword="******" useCertificate="0" bindDN="" host="at.ntnu.no" authMethod="6" bindAnon="1" encryptionMethod="2" name="ntnu" autoBase="1" checkServerCertificate="2">
  <baseDNs>
   <base dn="dc=lol,dc=com"/>
   <base dn="dc=ntnu,dc=no"/>
  </baseDNs>
 </LumaLdapServer>
 <LumaLdapServer port="392" clientCertFile="" followAliases="1" clientCertKeyfile="" bindPassword="******" useCertificate="0" bindDN="" host="x500.bund.de" authMethod="0" bindAnon="1" encryptionMethod="1" name="bund" autoBase="0" checkServerCertificate="0">
  <baseDNs>
   <base dn="dc=bund,dc=de"/>
  </baseDNs>
 </LumaLdapServer>
</LumaServerList>
        """)
            f.close()
        except IOError:
            print "----------------------"
            print "WRITE TO DISK FAILED!"
            print "----------------------"
            raise

    def getEmptyServerObject(self):
        #print "getEmptryServerObject"
        return ServerObject()

    """
    Read and write and emtpy serverlist to/from disk.
    """
    def testEmptyList(self):
        #print "testEmptyList"
        self.sl.setTable([])
        self.sl.writeServerList()
        self.sl.readServerList()
        self.assertEqual(self.sl.getTable(), [])

    """
    Tests for Read, delete, add and write, better than one BIG test, but each test is still a bit to dependent on the previous tests
    """

    def testAdd(self):
        #print "testAdd"
        # Remove and add back the removed item
        self.sl.addServer(self.getEmptyServerObject())

        # Check if it has been added correctly
        self.assertNotEqual(None, self.sl.getServerObject(""))


    def testDelete(self):
        #print "testDelete"
        # Delete and see if object still in list
        self.sl.setTable([self.getEmptyServerObject()])
        self.assertNotEqual(None, self.sl.getServerObject(""))
        self.sl.deleteServer("")
        self.assertEqual(None, self.sl.getServerObject(""))


    def testRead(self):
        #print "testRead"
        # Write the list to disk and have ServerList read it.
        self.writeList()
        self._modifyTime = None #IMPORTANT - FORCES READ FROM DISK
        self.sl.readServerList()

        # Check that the server list was read correctly
        self.assertNotEqual(None, self.sl.getServerObject("d-trust"))
        self.assertNotEqual(None, self.sl.getServerObject("bund"))
        self.assertNotEqual(None, self.sl.getServerObject("ntnu"))

    def testWrite(self):
        #print "testWrite"
        # Write the list back to disk and read it back
        self.sl.setTable([self.getEmptyServerObject()])
        self.sl.writeServerList()


        f = open(self.sl.getConfigFilePath(), "r")
        s = """
<!DOCTYPE LumaServerFile>
<LumaServerList version="1.2">
 <LumaLdapServer port="389" clientCertFile="" followAliases="0" bindPassword="" useCertificate="0" clientCertKeyFile="" bindDN="" host="" authMethod="0" bindAnon="1" encryptionMethod="0" name="" autoBase="1" checkServerCertificate="0">
  <baseDNs/>
 </LumaLdapServer>
</LumaServerList>
    """
        #Verify the list is good
        read = f.read()
        f.close()
        s = s.strip()
        r = read.strip()
        self.assertEqual(s, r)
예제 #2
0
class TemplateWidget(QWidget, Ui_TemplateWidget):

    def __init__(self):
        QWidget.__init__(self)
        self.setupUi(self)
        self.setObjectName('TemplatePlugin')
        self._serverList = ServerList()

        templateList = TemplateList()
        self._templateList = copy.deepcopy(templateList)
        self._templateListCopy = None
        self._returnList = None

        #ObjectclassAttributeInfo
        self.preloadedServerMeta = {}

        self.templateTM = TemplateTableModel(self._templateList, self)
        self.listViewTemplates.setModel(self.templateTM)

        self.objectclassTM = ObjectclassTableModel(self)
        self.listViewObjectclasses.setModel(self.objectclassTM)

        self.attributeTM = AttributeTableModel(self)
        self.tableViewAttributes.setModel(self.attributeTM)

        # Enable/disable editing depending on if we have a server to edit
        if self.templateTM.rowCount(QModelIndex()) > 0:
            self.setRightSideEnabled(True)
        else:
            self.setRightSideEnabled(False)
        # Select the first template in the model)
        index = self.templateTM.index(0,0)
        # Select the template in the view
        self.listViewTemplates.selectionModel().select(index, QItemSelectionModel.ClearAndSelect)
        self.listViewTemplates.selectionModel().setCurrentIndex(index, QItemSelectionModel.ClearAndSelect)
        self.listViewTemplates.selectionModel().selectionChanged.connect(self.selectedTemplate)
        # Map columns of the model to fields in the gui
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.templateTM)
        self.mapper.addMapping(self.lineEditDescription, 2)
        # Set-up of the non-mapped information
        self.selectedTemplate()

    def selectedTemplate(self):
        index = self.listViewTemplates.selectionModel().currentIndex().row()
        if index >= 0:
            self.mapper.setCurrentIndex(index)

            server = self._templateList._templateList[index].server
            self.labelServerName.setText(server)
            self.loadServerMeta(server)

            self.setObjectclasses()
            self.setAttributes()
            self.tableViewAttributes.resizeColumnsToContents()
            self.tableViewAttributes.resizeRowsToContents()

    def setObjectclasses(self):
        templateObject = self.getSelectedTemplateObject()
        if templateObject:
            self.objectclassTM.setTemplateObject(templateObject)


    def setAttributes(self):
        templateObject = self.getSelectedTemplateObject()
        if templateObject:
            self.attributeTM.setTemplateObject(templateObject)

    def loadServerMeta(self, serverName):
        serverName = unicode(serverName)
        if not (serverName in self.preloadedServerMeta.keys()):
            serverMeta = self._serverList.getServerObject(serverName)
            self.preloadedServerMeta[serverName] = ObjectClassAttributeInfo(serverMeta)
        return self.preloadedServerMeta[serverName]

    def setRightSideEnabled(self, enabled):
        self.lineEditDescription.setEnabled(enabled)
        self.groupBoxObjectclasses.setEnabled(enabled)
        self.groupBoxAttributes.setEnabled(enabled)

    def clearAll(self):
        self.lineEditDescription.clear()
        self.labelServerName.clear()
        self.objectclassTM.setTemplateObject(None)
        self.attributeTM.setTemplateObject(None)

    def getSelectedTemplateObject(self):
        templateIndexes = self.listViewTemplates.selectedIndexes()
        if len(templateIndexes) > 0:
            return self._templateList.getTable()[templateIndexes[0].row()]
        return None

    def getSelectedObjectclass(self, index):
        return self.objectclassTM.getObjectclass(index)

    def getSelectedAttribute(self, index):
        return self.attributeTM.getAttribute(index)

    def addTemplate(self):
        dialog = AddTemplateDialog(self._serverList)
        if dialog.exec_():
            name = dialog.lineEditTemplateName.text()
            if len(name) < 1 or self._templateList.getTemplateObject(name) != None:
                QMessageBox.information(self, 'Error', "Invalid name or already used.")
                return
            server = dialog.comboBoxServer.currentText()
            if len(server) < 1:
                QMessageBox.information(self, 'Error', "Invalid server.")
                return
            description = dialog.lineEditDescription.text()
            tO = TemplateObject(name, server, description)

            m = self.templateTM
            m.beginInsertRows(QModelIndex(), m.rowCount(), m.rowCount())
            m.insertRow(tO)
            m.endInsertRows()

            i = m.index(m.rowCount()-1,0)
            self.listViewTemplates.selectionModel().select(i, QItemSelectionModel.ClearAndSelect)
            self.listViewTemplates.selectionModel().setCurrentIndex(i, QItemSelectionModel.ClearAndSelect) #Mark it as current
            self.mapper.setCurrentIndex(i.row())
            self.selectedTemplate()
            if i.row() == 0:
                self.setRightSideEnabled(True)


    def deleteTemplate(self):
        if self.listViewTemplates.selectionModel().currentIndex().row() < 0:
            return

        re = QMessageBox.question(self, "Delete", "Are you sure?", QMessageBox.Yes, QMessageBox.No)

        if re == QMessageBox.Yes:
            index = self.listViewTemplates.selectedIndexes()[0] #Currently selected

            # Delete the template
            self.listViewTemplates.model().removeRow(index)

            # When deleting, the view gets updated and selects a new current.
            # Get it and give it to the mapper
            newIndex = self.listViewTemplates.selectionModel().currentIndex()
            self.mapper.setCurrentIndex(newIndex.row())

        # Disable editing if no templates left
        if self.templateTM.rowCount() == 0:
            self.setRightSideEnabled(False)
            self.clearAll()

    def duplicateTemplate(self):
        name, ok = QInputDialog.getText(self, 'Duplicate', 'Template name')
        if ok:
            if len(name) < 1 or self._templateList.getTemplateObject(name) != None:
                QMessageBox.information(self, 'Error', "Invalid name or already used.")
                return
            tO = copy.deepcopy(self.getSelectedTemplateObject())
            tO.templateName = name

            m = self.listViewTemplates.model()
            m.insertRow(tO)
            i = m.index(m.rowCount()-1,0)
            self.listViewTemplates.selectionModel().select(i, QItemSelectionModel.ClearAndSelect)
            self.listViewTemplates.selectionModel().setCurrentIndex(i, QItemSelectionModel.ClearAndSelect) #Mark it as current
            self.mapper.setCurrentIndex(i.row())
            self.selectedTemplate()

    def saveTemplate(self):
        self._templateList.save()

    def addObjectclass(self):
        server = self.labelServerName.text()
        dialog = AddObjectclassDialog(self.loadServerMeta(server), self.getSelectedTemplateObject())
        if dialog.exec_():
            for i in dialog.listWidgetObjectclasses.selectedIndexes():
                item = dialog.listWidgetObjectclasses.itemFromIndex(i)
                self.objectclassTM.insertRow(str(item.text()))

        self.refreshMustAttributes()

    def deleteObjectclass(self):
        dOc = self.listViewObjectclasses.selectedIndexes()
        if dOc:
            server = self.labelServerName.text()
            tO = self.getSelectedTemplateObject()
            attributes = self.attributeTM.attributes
            dialog = DeleteObjectclassDialog(self.loadServerMeta(server), tO, dOc, attributes)
            if dialog.exec_():
                self.objectclassTM.removeRows(dOc)
                self.refreshAllAttributes()


    def refreshMustAttributes(self):
        tO = self.getSelectedTemplateObject()
        for attr in tO.attributes.values():
            if attr.must:
                self.attributeTM.removeAlways(attr)


        server = self.labelServerName.text()
        ocai = self.loadServerMeta(server)
        attributeNameList = ocai.getAllMusts(tO.objectclasses)
        for name in attributeNameList:
            single = ocai.isSingle(name)
            binary = ocai.isBinary(name)
            self.attributeTM.addRow(name, True, single, binary, "", False)

    def refreshAllAttributes(self):
        tO = self.getSelectedTemplateObject()
        server = self.labelServerName.text()
        ocai = self.loadServerMeta(server)
        must, may = ocai.getAllAttributes(tO.objectclasses)
        for attr in tO.attributes.items():
            if (not attr[0] in must) and (not attr[0] in may):
                self.attributeTM.removeAlways(attr[1])
            elif not attr[0] in must:
                attr[1].must = False

    def addAttribute(self):
        server = self.labelServerName.text()
        dialog = AddAttributeDialog(self.loadServerMeta(server), self.getSelectedTemplateObject())
        if dialog.exec_():
            for i in dialog.tableView.selectedIndexes():
                if(i.column() == 0):
                    a = dialog.attributeTM.getAttribute(i)
                    self.attributeTM.addRow(a.attributeName, a.must, a.single, a.binary, a.defaultValue, a.customMust)

        self.tableViewAttributes.resizeRowsToContents()
        self.tableViewAttributes.resizeColumnsToContents()

    def deleteAttributes(self):
        if len(self.tableViewAttributes.selectedIndexes()):
            re = QMessageBox.question(self, self.tr('Delete'),
                                      self.tr("Are you sure you want to delete the selected attributes?"), QMessageBox.Yes, QMessageBox.No)
            if re == QMessageBox.Yes:
                self.attributeTM.removeRows(self.tableViewAttributes.selectedIndexes())

    def changeEvent(self, e):
        """Overloaded so we can catch the LanguageChange event, and at
        translation support to the plugin
        """
        if e.type() == QtCore.QEvent.LanguageChange:
            self.retranslateUi(self)
        else:
            QWidget.changeEvent(self, e)

    def retranslate(self, all=True):
        """For dynamic retranslation of the plugin text strings
        """

        self.retranslateUi(self)
예제 #3
0
class TemplateWidget(QWidget, Ui_TemplateWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.setupUi(self)
        self.setObjectName('TemplatePlugin')
        self._serverList = ServerList()

        templateList = TemplateList()
        self._templateList = copy.deepcopy(templateList)
        self._templateListCopy = None
        self._returnList = None

        #ObjectclassAttributeInfo
        self.preloadedServerMeta = {}

        self.templateTM = TemplateTableModel(self._templateList, self)
        self.listViewTemplates.setModel(self.templateTM)

        self.objectclassTM = ObjectclassTableModel(self)
        self.listViewObjectclasses.setModel(self.objectclassTM)

        self.attributeTM = AttributeTableModel(self)
        self.tableViewAttributes.setModel(self.attributeTM)

        # Enable/disable editing depending on if we have a server to edit
        if self.templateTM.rowCount(QModelIndex()) > 0:
            self.setRightSideEnabled(True)
        else:
            self.setRightSideEnabled(False)
        # Select the first template in the model)
        index = self.templateTM.index(0, 0)
        # Select the template in the view
        self.listViewTemplates.selectionModel().select(
            index, QItemSelectionModel.ClearAndSelect)
        self.listViewTemplates.selectionModel().setCurrentIndex(
            index, QItemSelectionModel.ClearAndSelect)
        self.listViewTemplates.selectionModel().selectionChanged.connect(
            self.selectedTemplate)
        # Map columns of the model to fields in the gui
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.templateTM)
        self.mapper.addMapping(self.lineEditDescription, 2)
        # Set-up of the non-mapped information
        self.selectedTemplate()

    def selectedTemplate(self):
        index = self.listViewTemplates.selectionModel().currentIndex().row()
        if index >= 0:
            self.mapper.setCurrentIndex(index)

            server = self._templateList._templateList[index].server
            self.labelServerName.setText(server)
            self.loadServerMeta(server)

            self.setObjectclasses()
            self.setAttributes()
            self.tableViewAttributes.resizeColumnsToContents()
            self.tableViewAttributes.resizeRowsToContents()

    def setObjectclasses(self):
        templateObject = self.getSelectedTemplateObject()
        if templateObject:
            self.objectclassTM.setTemplateObject(templateObject)

    def setAttributes(self):
        templateObject = self.getSelectedTemplateObject()
        if templateObject:
            self.attributeTM.setTemplateObject(templateObject)

    def loadServerMeta(self, serverName):
        serverName = unicode(serverName)
        if not (serverName in self.preloadedServerMeta.keys()):
            serverMeta = self._serverList.getServerObject(serverName)
            self.preloadedServerMeta[serverName] = ObjectClassAttributeInfo(
                serverMeta)
        return self.preloadedServerMeta[serverName]

    def setRightSideEnabled(self, enabled):
        self.lineEditDescription.setEnabled(enabled)
        self.groupBoxObjectclasses.setEnabled(enabled)
        self.groupBoxAttributes.setEnabled(enabled)

    def clearAll(self):
        self.lineEditDescription.clear()
        self.labelServerName.clear()
        self.objectclassTM.setTemplateObject(None)
        self.attributeTM.setTemplateObject(None)

    def getSelectedTemplateObject(self):
        templateIndexes = self.listViewTemplates.selectedIndexes()
        if len(templateIndexes) > 0:
            return self._templateList.getTable()[templateIndexes[0].row()]
        return None

    def getSelectedObjectclass(self, index):
        return self.objectclassTM.getObjectclass(index)

    def getSelectedAttribute(self, index):
        return self.attributeTM.getAttribute(index)

    def addTemplate(self):
        dialog = AddTemplateDialog(self._serverList)
        if dialog.exec_():
            name = dialog.lineEditTemplateName.text()
            if len(name) < 1 or self._templateList.getTemplateObject(
                    name) != None:
                QMessageBox.information(self, 'Error',
                                        "Invalid name or already used.")
                return
            server = dialog.comboBoxServer.currentText()
            if len(server) < 1:
                QMessageBox.information(self, 'Error', "Invalid server.")
                return
            description = dialog.lineEditDescription.text()
            tO = TemplateObject(name, server, description)

            m = self.templateTM
            m.beginInsertRows(QModelIndex(), m.rowCount(), m.rowCount())
            m.insertRow(tO)
            m.endInsertRows()

            i = m.index(m.rowCount() - 1, 0)
            self.listViewTemplates.selectionModel().select(
                i, QItemSelectionModel.ClearAndSelect)
            self.listViewTemplates.selectionModel().setCurrentIndex(
                i, QItemSelectionModel.ClearAndSelect)  #Mark it as current
            self.mapper.setCurrentIndex(i.row())
            self.selectedTemplate()
            if i.row() == 0:
                self.setRightSideEnabled(True)

    def deleteTemplate(self):
        if self.listViewTemplates.selectionModel().currentIndex().row() < 0:
            return

        re = QMessageBox.question(self, "Delete", "Are you sure?",
                                  QMessageBox.Yes, QMessageBox.No)

        if re == QMessageBox.Yes:
            index = self.listViewTemplates.selectedIndexes()[
                0]  #Currently selected

            # Delete the template
            self.listViewTemplates.model().removeRow(index)

            # When deleting, the view gets updated and selects a new current.
            # Get it and give it to the mapper
            newIndex = self.listViewTemplates.selectionModel().currentIndex()
            self.mapper.setCurrentIndex(newIndex.row())

        # Disable editing if no templates left
        if self.templateTM.rowCount() == 0:
            self.setRightSideEnabled(False)
            self.clearAll()

    def duplicateTemplate(self):
        name, ok = QInputDialog.getText(self, 'Duplicate', 'Template name')
        if ok:
            if len(name) < 1 or self._templateList.getTemplateObject(
                    name) != None:
                QMessageBox.information(self, 'Error',
                                        "Invalid name or already used.")
                return
            tO = copy.deepcopy(self.getSelectedTemplateObject())
            tO.templateName = name

            m = self.listViewTemplates.model()
            m.insertRow(tO)
            i = m.index(m.rowCount() - 1, 0)
            self.listViewTemplates.selectionModel().select(
                i, QItemSelectionModel.ClearAndSelect)
            self.listViewTemplates.selectionModel().setCurrentIndex(
                i, QItemSelectionModel.ClearAndSelect)  #Mark it as current
            self.mapper.setCurrentIndex(i.row())
            self.selectedTemplate()

    def saveTemplate(self):
        self._templateList.save()

    def addObjectclass(self):
        server = self.labelServerName.text()
        dialog = AddObjectclassDialog(self.loadServerMeta(server),
                                      self.getSelectedTemplateObject())
        if dialog.exec_():
            for i in dialog.listWidgetObjectclasses.selectedIndexes():
                item = dialog.listWidgetObjectclasses.itemFromIndex(i)
                self.objectclassTM.insertRow(str(item.text()))

        self.refreshMustAttributes()

    def deleteObjectclass(self):
        dOc = self.listViewObjectclasses.selectedIndexes()
        if dOc:
            server = self.labelServerName.text()
            tO = self.getSelectedTemplateObject()
            attributes = self.attributeTM.attributes
            dialog = DeleteObjectclassDialog(self.loadServerMeta(server), tO,
                                             dOc, attributes)
            if dialog.exec_():
                self.objectclassTM.removeRows(dOc)
                self.refreshAllAttributes()

    def refreshMustAttributes(self):
        tO = self.getSelectedTemplateObject()
        for attr in tO.attributes.values():
            if attr.must:
                self.attributeTM.removeAlways(attr)

        server = self.labelServerName.text()
        ocai = self.loadServerMeta(server)
        attributeNameList = ocai.getAllMusts(tO.objectclasses)
        for name in attributeNameList:
            single = ocai.isSingle(name)
            binary = ocai.isBinary(name)
            self.attributeTM.addRow(name, True, single, binary, "", False)

    def refreshAllAttributes(self):
        tO = self.getSelectedTemplateObject()
        server = self.labelServerName.text()
        ocai = self.loadServerMeta(server)
        must, may = ocai.getAllAttributes(tO.objectclasses)
        for attr in tO.attributes.items():
            if (not attr[0] in must) and (not attr[0] in may):
                self.attributeTM.removeAlways(attr[1])
            elif not attr[0] in must:
                attr[1].must = False

    def addAttribute(self):
        server = self.labelServerName.text()
        dialog = AddAttributeDialog(self.loadServerMeta(server),
                                    self.getSelectedTemplateObject())
        if dialog.exec_():
            for i in dialog.tableView.selectedIndexes():
                if (i.column() == 0):
                    a = dialog.attributeTM.getAttribute(i)
                    self.attributeTM.addRow(a.attributeName, a.must, a.single,
                                            a.binary, a.defaultValue,
                                            a.customMust)

        self.tableViewAttributes.resizeRowsToContents()
        self.tableViewAttributes.resizeColumnsToContents()

    def deleteAttributes(self):
        if len(self.tableViewAttributes.selectedIndexes()):
            re = QMessageBox.question(
                self, self.tr('Delete'),
                self.
                tr("Are you sure you want to delete the selected attributes?"),
                QMessageBox.Yes, QMessageBox.No)
            if re == QMessageBox.Yes:
                self.attributeTM.removeRows(
                    self.tableViewAttributes.selectedIndexes())

    def changeEvent(self, e):
        """Overloaded so we can catch the LanguageChange event, and at
        translation support to the plugin
        """
        if e.type() == QtCore.QEvent.LanguageChange:
            self.retranslateUi(self)
        else:
            QWidget.changeEvent(self, e)

    def retranslate(self, all=True):
        """For dynamic retranslation of the plugin text strings
        """

        self.retranslateUi(self)
예제 #4
0
파일: BrowserView.py 프로젝트: einaru/luma
class BrowserView(QWidget):
    """Luma LDAP Browser plugin
    """

    # Custom signals used
    reloadSignal = QtCore.pyqtSignal(QtCore.QModelIndex)
    clearSignal = QtCore.pyqtSignal(QtCore.QModelIndex)

    __logger = logging.getLogger(__name__)

    def __init__(self, parent=None, configPrefix=None):
        """
        :param configPrefix: defines the location of serverlist.
        :type configPrefix: string
        """
        super(BrowserView, self).__init__(parent)

        self.__logger = logging.getLogger(__name__)

        self.setObjectName("PLUGIN_BROWSER")

        self.templateList = TemplateList()

        # The serverlist used
        self.serverList = ServerList(configPrefix)
        self.serversChangedMessage = QtGui.QErrorMessage()
        self.mainLayout = QtGui.QHBoxLayout(self)

        self.splitter = QtGui.QSplitter(self)

        # Create the model
        self.ldaptreemodel = LDAPTreeItemModel(self.serverList, self)
        self.ldaptreemodel.workingSignal.connect(self.setBusy)

        # Set up the entrylist (uses the model)
        self.__setupEntryList()

        # The editor for entries
        self.tabWidget = QtGui.QTabWidget(self)
        #self.tabWidget.setDocumentMode(True)
        self.tabWidget.setMovable(True)
        self.setMinimumWidth(200)
        self.tabWidget.setTabsClosable(True)
        self.tabWidget.tabCloseRequested.connect(self.tabCloseClicked)
        self.tabWidget.setUsesScrollButtons(True)
        sizePolicy = self.tabWidget.sizePolicy()
        sizePolicy.setHorizontalStretch(1)
        self.tabWidget.setSizePolicy(sizePolicy)
        # Remember and looks up open tabs
        self.openTabs = {}

        self.splitter.addWidget(self.entryList)
        self.splitter.addWidget(self.tabWidget)
        self.mainLayout.addWidget(self.splitter)

        # Used to signal the ldaptreemodel with a index
        # which needs processing (reloading, clearing)
        self.reloadSignal.connect(self.ldaptreemodel.reloadItem)
        self.clearSignal.connect(self.ldaptreemodel.clearItem)

        eventFilter = BrowserPluginEventFilter(self)
        self.installEventFilter(eventFilter)

        self.__createContextMenu()
        self.retranslateUi()

        self.progress = QMessageBox(
            1, self.str_PLEASE_WAIT, self.str_PLEASE_WAIT_MSG,
            QMessageBox.Ignore, parent=self
        )

        # For testing ONLY
        # AND ONLY ON SMALL LDAP-SERVERS SINCE IT LOADS BASICALLY ALL ENTIRES
        #import modeltest
        #self.modeltest = modeltest.ModelTest(self.ldaptreemodel, self);

    def setBusy(self, status):
        """
        Helper-method.
        """
        if status == True:
            self.progress.show()
            qApp.setOverrideCursor(Qt.WaitCursor)
        else:
            if not self.progress.isHidden():
                self.progress.hide()
            qApp.restoreOverrideCursor()

    def __setupEntryList(self):
        # The view for server-content
        self.entryList = QtGui.QTreeView(self)
        self.entryList.setMinimumWidth(200)
        #self.entryList.setMaximumWidth(400)
        #self.entryList.setAlternatingRowColors(True)

        # Somewhat cool, but should be removed if deemed too taxing
        self.entryList.setAnimated(True)
        self.entryList.setUniformRowHeights(True)  # MAJOR optimalization
        #self.entryList.setExpandsOnDoubleClick(False)
        self.entryList.setModel(self.ldaptreemodel)
        self.entryList.setMouseTracking(True)
        self.entryList.viewport().setMouseTracking(True)
        # For right-clicking in the tree
        self.entryList.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.entryList.customContextMenuRequested.connect(self.rightClick)
        # When something is activated (doubleclick, <enter> etc.)
        self.entryList.activated.connect(self.viewItem)
        self.delegate = LoadingDelegate(self.entryList)
        self.entryList.setItemDelegate(self.delegate)
        self.entryList.setSelectionMode(
            QtGui.QAbstractItemView.ExtendedSelection)

    def __createContextMenu(self):
        """Creates the context menu for the tree view.
        """
        self.contextMenu = QMenu()
        self.contextMenuServerSettings = QAction(self)
        self.contextMenu.addAction(self.contextMenuServerSettings)
        self.contextMenu.addSeparator()
        self.contextMenuOpen = QAction(self)
        self.contextMenu.addAction(self.contextMenuOpen)
        self.contextMenuReload = QAction(self)
        self.contextMenu.addAction(self.contextMenuReload)
        self.contextMenuClear = QAction(self)
        self.contextMenu.addAction(self.contextMenuClear)
        self.contextMenuFilter = QAction(self)
        self.contextMenu.addAction(self.contextMenuFilter)
        self.contextMenuLimit = QAction(self)
        self.contextMenu.addAction(self.contextMenuLimit)
        self.contextMenu.addSeparator()
        self.contextMenuAdd = QMenu()
        self.contextMenu.addMenu(self.contextMenuAdd)
        self.contextMenuDelete = QMenu()
        self.contextMenu.addMenu(self.contextMenuDelete)
        self.contextMenuExport = QMenu()
        self.contextMenu.addMenu(self.contextMenuExport)

        # Connect the context menu actions to the correct slots
        self.contextMenuServerSettings.triggered.connect(
            self.editServerSettings)
        self.contextMenuOpen.triggered.connect(self.openChoosen)
        self.contextMenuReload.triggered.connect(self.reloadChoosen)
        self.contextMenuClear.triggered.connect(self.clearChoosen)
        self.contextMenuFilter.triggered.connect(self.filterChoosen)
        self.contextMenuLimit.triggered.connect(self.limitChoosen)

    def rightClick(self, point):
        """ Called when the view is right-clicked.
        Displays a context menu with possible actions.

        :param point: contains the global screen coordinates for the
         right-click that generated this call.
        :type potin: QPoint
        """
        # This is a list of QModelIndex objects, which will be used by
        # the various context menu slots.
        # We therfore store it as a class member
        self.selection = self.entryList.selectedIndexes()

        openSupport = True
        reloadSupport = True
        clearSupport = True
        filterSupport = True
        limitSupport = True
        addSupport = True
        deleteSupport = True
        exportSupport = True
        editServerSupport = True

        # The number of selected items is used for naming of the actions
        # added to the submenues
        numselected = len(self.selection)

        # View disabled menu if nothing selected
        self.contextMenu.setEnabled(True)  # Remember to enable if a selection
        if not numselected > 0:  # If nothing is selected
            self.contextMenu.setEnabled(False)  # Disable
            self.contextMenu.exec_(self.entryList.mapToGlobal(point))  # Show
            return

        # Iterate through the list of selected indexes, and
        # validate what operations are supported. That is,
        # if one of the selected indexes do not support an
        # operation, we cannot allow to apply that operation
        # on the whole selection
        for index in self.selection:
            item = index.internalPointer()
            operations = item.getSupportedOperations()
            if not AbstractLDAPTreeItem.SUPPORT_OPEN & operations:
                openSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_RELOAD & operations:
                reloadSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_CLEAR & operations:
                clearSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_FILTER & operations:
                filterSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_LIMIT & operations:
                limitSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_ADD & operations:
                addSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_DELETE & operations:
                deleteSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_EXPORT & operations:
                exportSupport = False

        if index.internalPointer().getParentServerItem() == None:
            editServerSupport = False

        # Now we just use the *Support variables to enable|disable
        # the context menu actions.
        self.contextMenuOpen.setEnabled(openSupport)
        self.contextMenuReload.setEnabled(reloadSupport)
        self.contextMenuClear.setEnabled(clearSupport)
        self.contextMenuFilter.setEnabled(filterSupport)
        self.contextMenuLimit.setEnabled(limitSupport)
        self.contextMenuServerSettings.setEnabled(editServerSupport)

        # For the submenues in the context menu, we add appropriate
        # actions, based on single|multi selection, or disable the menu
        # altogether if there is no support for the operation.
        if (limitSupport or filterSupport or openSupport) \
           and not numselected == 1:
                self.contextMenuLimit.setEnabled(False)
                self.contextMenuFilter.setEnabled(False)
                self.contextMenuOpen.setEnabled(False)
        if addSupport and numselected == 1:
            self.contextMenuAdd.setEnabled(True)
            # template
            templateMenu = QMenu(self.str_TEMPLATE)
            self.contextMenuAdd.addMenu(templateMenu)
            index = self.selection[0]
            for template in self.templateList.getTable():
                sO = index.internalPointer().smartObject()
                if template.server == sO.serverMeta.name:
                    method = lambda name = template.templateName, i = index : self.addTemplateChoosen(name, i)
                    templateMenu.addAction(template.templateName, method)

        else:
            self.contextMenuAdd.setEnabled(False)

        if numselected != 1:
            self.contextMenuServerSettings.setEnabled(False)

        if deleteSupport:
            self.contextMenuDelete.setEnabled(True)
            if numselected == 1:
                self.contextMenuDelete.addAction(
                    self.str_ITEM, self.deleteSelection
                )
                self.contextMenuDelete.addAction(
                    self.str_SUBTREE_ONLY, self.deleteSubtree
                )
                #self.contextMenuDelete.addAction(
                #    self.str_SUBTREE_PARENTS, self.deleteSelection
                #)
            else:
                self.contextMenuDelete.addAction(
                    self.str_ITEMS, self.deleteSelection
                )
                self.contextMenuDelete.addAction(
                    self.str_SUBTREES, self.deleteSubtree
                )
                #self.contextMenuDelete.addAction(
                #    self.str_SUBTREES_PARENTS, self.deleteSelection
                #)
        else:
            self.contextMenuDelete.setEnabled(False)

        if exportSupport:
            self.contextMenuExport.setEnabled(True)
            if numselected == 1:
                self.contextMenuExport.addAction(
                    self.str_ITEM, self.exportItems
                )
                self.contextMenuExport.addAction(
                    self.str_SUBTREE, self.exportSubtrees
                )
                self.contextMenuExport.addAction(
                    self.str_SUBTREE_PARENTS, self.exportSubtreeWithParents
                )
            else:
                self.contextMenuExport.addAction(
                    self.str_ITEMS, self.exportItems
                )
                self.contextMenuExport.addAction(
                    self.str_SUBTREES, self.exportSubtrees
                )
                self.contextMenuExport.addAction(
                    self.str_SUBTREES_PARENTS, self.exportSubtreeWithParents
                )
        else:
            self.contextMenuExport.setEnabled(False)

        # Finally we execute the context menu
        self.contextMenu.exec_(self.entryList.mapToGlobal(point))

        # We need to clear all the submenues after each right click
        # selection, if not; the submenu actions will be added and
        # thus duplicated for every selection the user makes.
        # FIXME: Find a better way of handling this issue.
        self.contextMenuAdd.clear()
        self.contextMenuDelete.clear()
        self.contextMenuExport.clear()

    """
    Following methods are called from a context-menu.
    """
    def openChoosen(self):
        if len(self.selection) == 1:
            self.viewItem(self.selection[0])

    def reloadChoosen(self):
        for index in self.selection:
            self.reloadSignal.emit(index)

    def clearChoosen(self):
        for index in self.selection:
            self.clearSignal.emit(index)

    def limitChoosen(self):
        # Have the item set the limit for us, the reload
        for index in self.selection:
            ok = index.internalPointer().setLimit()
            if ok:
                self.reloadSignal.emit(index)

    def filterChoosen(self):
        # Have the item set the filter, then reload
        for index in self.selection:
            ok = index.internalPointer().setFilter()
            if ok:
                self.reloadSignal.emit(index)

    def addTemplateChoosen(self, templateName, index):
        serverMeta = index.internalPointer().smartObject().serverMeta
        baseDN = index.internalPointer().smartObject().getDN()
        template = self.templateList.getTemplateObject(templateName)
        smartO = template.getDataObject(serverMeta, baseDN)
        self.addNewEntry(index, smartO, template)

    def addNewEntry(self, parentIndex, defaultSmartObject=None, template=None):
        tmp = NewEntryDialog(parentIndex, defaultSmartObject,
                             entryTemplate=template)
        if tmp.exec_():
            ret = QMessageBox.question(self, QtCore.QCoreApplication.translate("BrowserView","Add"), QtCore.QCoreApplication.translate("BrowserView", "Do you want to reload to show the changes?"), QMessageBox.Yes|QMessageBox.No)
            if ret == QMessageBox.Yes:
                self.ldaptreemodel.reloadItem(self.selection[0])

    """
    Utility-methods
    """
    def isOpen(self, smartObject):
        rep = self.getRepForSmartObject(smartObject)
        # The {}.has_key() method will be removed in the future version
        # of Python. Use the 'in' operation instead. [PEP8]
        #if self.openTabs.has_key(str(rep)):
        if str(rep) in self.openTabs:
            return True
        else:
            return False

    def getRepForSmartObject(self, smartObject):
        serverName = smartObject.getServerAlias()
        dn = smartObject.getDN()
        return (serverName, dn)

    def viewItem(self, index):
        """Opens items for viewing.
        """
        item = index.internalPointer()
        supports = item.getSupportedOperations()

        # If we can't open this item, then don't
        if not supports & AbstractLDAPTreeItem.SUPPORT_OPEN:
            self.__logger.debug("Item didn't support open.")
            return

        smartObject = index.internalPointer().smartObject()
        rep = self.getRepForSmartObject(smartObject)

        # If the smartobject is already open, switch to it
        if self.isOpen(smartObject):
            x = self.openTabs[str(rep)]
            self.tabWidget.setCurrentWidget(x)
            return

        # Saves a representation of the opened entry to avoid opening duplicates
        # and open it
        x = AdvancedObjectWidget(QtCore.QPersistentModelIndex(index))
        x.initModel(smartObject)

        self.openTabs[str(rep)] = x
        self.tabWidget.addTab(x, smartObject.getPrettyRDN())
        self.tabWidget.setCurrentWidget(x)

    def deleteIndex(self, index):
        # Remember the smartObject for later
        sO = index.internalPointer().smartObject()
        # Try to delete
        (success, message) = self.ldaptreemodel.deleteItem(index)
        if success:
            # Close open edit-windows if any
            self.__closeTabIfOpen(sO)
            # Notify success
            return (True, message)
        else:
            # Notify fail
            return (False, message)

    def __closeTabIfOpen(self, sO):
        if self.isOpen(sO):
                rep = self.getRepForSmartObject(sO)
                x = self.openTabs.pop(str(rep))
                i = self.tabWidget.indexOf(x)
                if i != -1:
                    self.tabWidget.removeTab(i)

    def deleteSelection(self, subTree=False):
        """Slot for the context menu.

        Opens the DeleteDialog with the selected entries, giving the
        user the option to validate the selection before deleting.

        This is for deleting the item + possibly it's subtree.
        See deleteOnlySubtreeOfSelection() for only subtree.
        """

        # Only a single item
        if len(self.selection) == 1 and not subTree:
            # Confirmation-message
            ok = QMessageBox.question(
                self, self.str_DELETE, self.str_REALLY_DELETE,
                QMessageBox.Yes | QMessageBox.No
            )
            if ok == QMessageBox.No:
                return
            index = self.selection[0]
            (status, message) = self.deleteIndex(index)
            if not status:
                QMessageBox.critical(
                    self, self.str_ERROR, self.str_ERROR_MSG.format(
                        index.data().toPyObject(), message
                    )
                )
            return

        # Make persistent indexes and list of smartObjects to be deleted
        persistenSelection = []
        sOList = []
        for x in self.selection:
            persistenSelection.append(QPersistentModelIndex(x))
            sOList.append(x.internalPointer().smartObject())

        # Create gui
        self.setBusy(True)
        deleteDialog = DeleteDialog(sOList, subTree)
        self.setBusy(False)
        status = deleteDialog.exec_()

        if status:  # the dialog was not canceled
            if subTree:
                # Reload the items whos subtree was deleted
                for x in self.selection:
                    self.ldaptreemodel.reloadItem(x)
                return
            # If all rows were removed successfully, just call
            # removeRows on all selected items (reloading all items of
            # the parent can be expensive)
            if deleteDialog.passedItemsWasDeleted:
                for x in persistenSelection:
                    if x.isValid:
                        i = x.sibling(x.row(), 0)  # QModelIndex
                        self.__closeTabIfOpen(
                            i.internalPointer().smartObject())
                        self.ldaptreemodel.removeRow(x.row(), x.parent())
                return

            # If not, call reload on the parent of all the items?
            else:
                tmp = QMessageBox.question(
                    self, self.str_DELETION, self.str_DELETION_MSG,
                    buttons=QMessageBox.Yes | QMessageBox.No,
                    defaultButton=QMessageBox.Yes
                )
                if tmp == QMessageBox.Yes:
                    for x in persistenSelection:
                        # index might not be valid if the parent was
                        # reloaded by a previous item
                        if x.isValid():
                            self.ldaptreemodel.reloadItem(x.parent())
                        return

        # Was cancelled so do nothing
        else:
            pass

    def deleteSubtree(self):
        self.deleteSelection(subTree=True)

    def exportItems(self):
        """Slot for the context menu.
        """
        self.__exportSelection(scope=0)

    def exportSubtrees(self):
        """Slot for the context menu.
        """
        self.__exportSelection(scope=1)

    def exportSubtreeWithParents(self):
        """Slot for the context menu.
        """
        self.__exportSelection(scope=2)

    def __exportSelection(self, scope=0):
        """Slot for the context menu.

        Opens the ExportDialog with the selected entries, giving the
        user the option to validate the selection before exporting.

        :param scope: The scope selection.
         0 = SCOPE_BASE -> Item(s),
         1 = SCOPE_ONELEVEL -> Subtree(s);
         2 = SCOPE_SUBTREE -> Subtree(s) with parent
        :type scope: int
        """
        exportObjects = []
        msg = ''

        self.setBusy(True)
        for index in self.selection:
            smartObject = index.internalPointer().smartObject()

            serverName = smartObject.getServerAlias()
            dn = smartObject.getDN()
            serverObject = self.serverList.getServerObject(serverName)
            con = LumaConnectionWrapper(serverObject, self)

            # For both subtree and subtree with parent, we fetch the
            # whole subtree including the parent, with a basic sync
            # search operation. Then, if only the subtree is to be
            # exported, we remove the smartObject(s) selected.
            if scope > 0:
                pass

            # Do a search on the whole subtree
            # 2 = ldap.SCOPE_SUBTREE
            #elif scope == 2:

                success, e = con.bindSync()

                if not success:
                    self.__logger.error(str(e))
                    continue
                success, result, e = con.searchSync(base=dn, scope=2)

                if success:
                    exportObjects.extend(result)
                else:
                    self.__logger.error(str(e))

                # If only the subtree is to be selected, we remove
                # the parent, which happens to be the smartObject(s)
                # initialy selected.
                if scope == 1:
                    exportObjects.remove(smartObject)

            # For scope == 0 we need not do any LDAP search operation
            # because we already got what we need
            else:
                exportObjects.append(smartObject)

        # Initialize the export dialog
        # and give it the items for export
        dialog = ExportDialog(msg)
        dialog.setExportItems(exportObjects)
        self.setBusy(False)
        dialog.exec_()

    def editServerSettings(self):
        """Slot for the context menu.
        Opens the ServerDialog with the selected server.
        """
        try:
            items = self.selection
            serverItem = items[0].internalPointer().getParentServerItem()
            serverName = serverItem.serverMeta.name
            serverDialog = ServerDialog(serverName)
            r = serverDialog.exec_()
            if r:
                self.serversChangedMessage.showMessage(
                    self.str_SERVER_CHANGED_MSG
                )
        except Exception, e:
            self.__logger.error(str(e))
            QMessageBox.information(
                self, self.str_ERROR, self.str_SEE_LOG_DETAILS
            )
예제 #5
0
class BrowserView(QWidget):
    """Luma LDAP Browser plugin
    """

    # Custom signals used
    reloadSignal = QtCore.pyqtSignal(QtCore.QModelIndex)
    clearSignal = QtCore.pyqtSignal(QtCore.QModelIndex)

    __logger = logging.getLogger(__name__)

    def __init__(self, parent=None, configPrefix=None):
        """
        :param configPrefix: defines the location of serverlist.
        :type configPrefix: string
        """
        super(BrowserView, self).__init__(parent)

        self.__logger = logging.getLogger(__name__)

        self.setObjectName("PLUGIN_BROWSER")

        self.templateList = TemplateList()

        # The serverlist used
        self.serverList = ServerList(configPrefix)
        self.serversChangedMessage = QtGui.QErrorMessage()
        self.mainLayout = QtGui.QHBoxLayout(self)

        self.splitter = QtGui.QSplitter(self)

        # Create the model
        self.ldaptreemodel = LDAPTreeItemModel(self.serverList, self)
        self.ldaptreemodel.workingSignal.connect(self.setBusy)

        # Set up the entrylist (uses the model)
        self.__setupEntryList()

        # The editor for entries
        self.tabWidget = QtGui.QTabWidget(self)
        #self.tabWidget.setDocumentMode(True)
        self.tabWidget.setMovable(True)
        self.setMinimumWidth(200)
        self.tabWidget.setTabsClosable(True)
        self.tabWidget.tabCloseRequested.connect(self.tabCloseClicked)
        self.tabWidget.setUsesScrollButtons(True)
        sizePolicy = self.tabWidget.sizePolicy()
        sizePolicy.setHorizontalStretch(1)
        self.tabWidget.setSizePolicy(sizePolicy)
        # Remember and looks up open tabs
        self.openTabs = {}

        self.splitter.addWidget(self.entryList)
        self.splitter.addWidget(self.tabWidget)
        self.mainLayout.addWidget(self.splitter)

        # Used to signal the ldaptreemodel with a index
        # which needs processing (reloading, clearing)
        self.reloadSignal.connect(self.ldaptreemodel.reloadItem)
        self.clearSignal.connect(self.ldaptreemodel.clearItem)

        eventFilter = BrowserPluginEventFilter(self)
        self.installEventFilter(eventFilter)

        self.__createContextMenu()
        self.retranslateUi()

        self.progress = QMessageBox(1,
                                    self.str_PLEASE_WAIT,
                                    self.str_PLEASE_WAIT_MSG,
                                    QMessageBox.Ignore,
                                    parent=self)

        # For testing ONLY
        # AND ONLY ON SMALL LDAP-SERVERS SINCE IT LOADS BASICALLY ALL ENTIRES
        #import modeltest
        #self.modeltest = modeltest.ModelTest(self.ldaptreemodel, self);

    def setBusy(self, status):
        """
        Helper-method.
        """
        if status == True:
            self.progress.show()
            qApp.setOverrideCursor(Qt.WaitCursor)
        else:
            if not self.progress.isHidden():
                self.progress.hide()
            qApp.restoreOverrideCursor()

    def __setupEntryList(self):
        # The view for server-content
        self.entryList = QtGui.QTreeView(self)
        self.entryList.setMinimumWidth(200)
        #self.entryList.setMaximumWidth(400)
        #self.entryList.setAlternatingRowColors(True)

        # Somewhat cool, but should be removed if deemed too taxing
        self.entryList.setAnimated(True)
        self.entryList.setUniformRowHeights(True)  # MAJOR optimalization
        #self.entryList.setExpandsOnDoubleClick(False)
        self.entryList.setModel(self.ldaptreemodel)
        self.entryList.setMouseTracking(True)
        self.entryList.viewport().setMouseTracking(True)
        # For right-clicking in the tree
        self.entryList.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.entryList.customContextMenuRequested.connect(self.rightClick)
        # When something is activated (doubleclick, <enter> etc.)
        self.entryList.activated.connect(self.viewItem)
        self.delegate = LoadingDelegate(self.entryList)
        self.entryList.setItemDelegate(self.delegate)
        self.entryList.setSelectionMode(
            QtGui.QAbstractItemView.ExtendedSelection)

    def __createContextMenu(self):
        """Creates the context menu for the tree view.
        """
        self.contextMenu = QMenu()
        self.contextMenuServerSettings = QAction(self)
        self.contextMenu.addAction(self.contextMenuServerSettings)
        self.contextMenu.addSeparator()
        self.contextMenuOpen = QAction(self)
        self.contextMenu.addAction(self.contextMenuOpen)
        self.contextMenuReload = QAction(self)
        self.contextMenu.addAction(self.contextMenuReload)
        self.contextMenuClear = QAction(self)
        self.contextMenu.addAction(self.contextMenuClear)
        self.contextMenuFilter = QAction(self)
        self.contextMenu.addAction(self.contextMenuFilter)
        self.contextMenuLimit = QAction(self)
        self.contextMenu.addAction(self.contextMenuLimit)
        self.contextMenu.addSeparator()
        self.contextMenuAdd = QMenu()
        self.contextMenu.addMenu(self.contextMenuAdd)
        self.contextMenuDelete = QMenu()
        self.contextMenu.addMenu(self.contextMenuDelete)
        self.contextMenuExport = QMenu()
        self.contextMenu.addMenu(self.contextMenuExport)

        # Connect the context menu actions to the correct slots
        self.contextMenuServerSettings.triggered.connect(
            self.editServerSettings)
        self.contextMenuOpen.triggered.connect(self.openChoosen)
        self.contextMenuReload.triggered.connect(self.reloadChoosen)
        self.contextMenuClear.triggered.connect(self.clearChoosen)
        self.contextMenuFilter.triggered.connect(self.filterChoosen)
        self.contextMenuLimit.triggered.connect(self.limitChoosen)

    def rightClick(self, point):
        """ Called when the view is right-clicked.
        Displays a context menu with possible actions.

        :param point: contains the global screen coordinates for the
         right-click that generated this call.
        :type potin: QPoint
        """
        # This is a list of QModelIndex objects, which will be used by
        # the various context menu slots.
        # We therfore store it as a class member
        self.selection = self.entryList.selectedIndexes()

        openSupport = True
        reloadSupport = True
        clearSupport = True
        filterSupport = True
        limitSupport = True
        addSupport = True
        deleteSupport = True
        exportSupport = True
        editServerSupport = True

        # The number of selected items is used for naming of the actions
        # added to the submenues
        numselected = len(self.selection)

        # View disabled menu if nothing selected
        self.contextMenu.setEnabled(True)  # Remember to enable if a selection
        if not numselected > 0:  # If nothing is selected
            self.contextMenu.setEnabled(False)  # Disable
            self.contextMenu.exec_(self.entryList.mapToGlobal(point))  # Show
            return

        # Iterate through the list of selected indexes, and
        # validate what operations are supported. That is,
        # if one of the selected indexes do not support an
        # operation, we cannot allow to apply that operation
        # on the whole selection
        for index in self.selection:
            item = index.internalPointer()
            operations = item.getSupportedOperations()
            if not AbstractLDAPTreeItem.SUPPORT_OPEN & operations:
                openSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_RELOAD & operations:
                reloadSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_CLEAR & operations:
                clearSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_FILTER & operations:
                filterSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_LIMIT & operations:
                limitSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_ADD & operations:
                addSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_DELETE & operations:
                deleteSupport = False
            if not AbstractLDAPTreeItem.SUPPORT_EXPORT & operations:
                exportSupport = False

        if index.internalPointer().getParentServerItem() == None:
            editServerSupport = False

        # Now we just use the *Support variables to enable|disable
        # the context menu actions.
        self.contextMenuOpen.setEnabled(openSupport)
        self.contextMenuReload.setEnabled(reloadSupport)
        self.contextMenuClear.setEnabled(clearSupport)
        self.contextMenuFilter.setEnabled(filterSupport)
        self.contextMenuLimit.setEnabled(limitSupport)
        self.contextMenuServerSettings.setEnabled(editServerSupport)

        # For the submenues in the context menu, we add appropriate
        # actions, based on single|multi selection, or disable the menu
        # altogether if there is no support for the operation.
        if (limitSupport or filterSupport or openSupport) \
           and not numselected == 1:
            self.contextMenuLimit.setEnabled(False)
            self.contextMenuFilter.setEnabled(False)
            self.contextMenuOpen.setEnabled(False)
        if addSupport and numselected == 1:
            self.contextMenuAdd.setEnabled(True)
            # template
            templateMenu = QMenu(self.str_TEMPLATE)
            self.contextMenuAdd.addMenu(templateMenu)
            index = self.selection[0]
            for template in self.templateList.getTable():
                sO = index.internalPointer().smartObject()
                if template.server == sO.serverMeta.name:
                    method = lambda name=template.templateName, i=index: self.addTemplateChoosen(
                        name, i)
                    templateMenu.addAction(template.templateName, method)

        else:
            self.contextMenuAdd.setEnabled(False)

        if numselected != 1:
            self.contextMenuServerSettings.setEnabled(False)

        if deleteSupport:
            self.contextMenuDelete.setEnabled(True)
            if numselected == 1:
                self.contextMenuDelete.addAction(self.str_ITEM,
                                                 self.deleteSelection)
                self.contextMenuDelete.addAction(self.str_SUBTREE_ONLY,
                                                 self.deleteSubtree)
                #self.contextMenuDelete.addAction(
                #    self.str_SUBTREE_PARENTS, self.deleteSelection
                #)
            else:
                self.contextMenuDelete.addAction(self.str_ITEMS,
                                                 self.deleteSelection)
                self.contextMenuDelete.addAction(self.str_SUBTREES,
                                                 self.deleteSubtree)
                #self.contextMenuDelete.addAction(
                #    self.str_SUBTREES_PARENTS, self.deleteSelection
                #)
        else:
            self.contextMenuDelete.setEnabled(False)

        if exportSupport:
            self.contextMenuExport.setEnabled(True)
            if numselected == 1:
                self.contextMenuExport.addAction(self.str_ITEM,
                                                 self.exportItems)
                self.contextMenuExport.addAction(self.str_SUBTREE,
                                                 self.exportSubtrees)
                self.contextMenuExport.addAction(self.str_SUBTREE_PARENTS,
                                                 self.exportSubtreeWithParents)
            else:
                self.contextMenuExport.addAction(self.str_ITEMS,
                                                 self.exportItems)
                self.contextMenuExport.addAction(self.str_SUBTREES,
                                                 self.exportSubtrees)
                self.contextMenuExport.addAction(self.str_SUBTREES_PARENTS,
                                                 self.exportSubtreeWithParents)
        else:
            self.contextMenuExport.setEnabled(False)

        # Finally we execute the context menu
        self.contextMenu.exec_(self.entryList.mapToGlobal(point))

        # We need to clear all the submenues after each right click
        # selection, if not; the submenu actions will be added and
        # thus duplicated for every selection the user makes.
        # FIXME: Find a better way of handling this issue.
        self.contextMenuAdd.clear()
        self.contextMenuDelete.clear()
        self.contextMenuExport.clear()

    """
    Following methods are called from a context-menu.
    """

    def openChoosen(self):
        if len(self.selection) == 1:
            self.viewItem(self.selection[0])

    def reloadChoosen(self):
        for index in self.selection:
            self.reloadSignal.emit(index)

    def clearChoosen(self):
        for index in self.selection:
            self.clearSignal.emit(index)

    def limitChoosen(self):
        # Have the item set the limit for us, the reload
        for index in self.selection:
            ok = index.internalPointer().setLimit()
            if ok:
                self.reloadSignal.emit(index)

    def filterChoosen(self):
        # Have the item set the filter, then reload
        for index in self.selection:
            ok = index.internalPointer().setFilter()
            if ok:
                self.reloadSignal.emit(index)

    def addTemplateChoosen(self, templateName, index):
        serverMeta = index.internalPointer().smartObject().serverMeta
        baseDN = index.internalPointer().smartObject().getDN()
        template = self.templateList.getTemplateObject(templateName)
        smartO = template.getDataObject(serverMeta, baseDN)
        self.addNewEntry(index, smartO, template)

    def addNewEntry(self, parentIndex, defaultSmartObject=None, template=None):
        tmp = NewEntryDialog(parentIndex,
                             defaultSmartObject,
                             entryTemplate=template)
        if tmp.exec_():
            ret = QMessageBox.question(
                self, QtCore.QCoreApplication.translate("BrowserView", "Add"),
                QtCore.QCoreApplication.translate(
                    "BrowserView",
                    "Do you want to reload to show the changes?"),
                QMessageBox.Yes | QMessageBox.No)
            if ret == QMessageBox.Yes:
                self.ldaptreemodel.reloadItem(self.selection[0])

    """
    Utility-methods
    """

    def isOpen(self, smartObject):
        rep = self.getRepForSmartObject(smartObject)
        # The {}.has_key() method will be removed in the future version
        # of Python. Use the 'in' operation instead. [PEP8]
        #if self.openTabs.has_key(str(rep)):
        if str(rep) in self.openTabs:
            return True
        else:
            return False

    def getRepForSmartObject(self, smartObject):
        serverName = smartObject.getServerAlias()
        dn = smartObject.getDN()
        return (serverName, dn)

    def viewItem(self, index):
        """Opens items for viewing.
        """
        item = index.internalPointer()
        supports = item.getSupportedOperations()

        # If we can't open this item, then don't
        if not supports & AbstractLDAPTreeItem.SUPPORT_OPEN:
            self.__logger.debug("Item didn't support open.")
            return

        smartObject = index.internalPointer().smartObject()
        rep = self.getRepForSmartObject(smartObject)

        # If the smartobject is already open, switch to it
        if self.isOpen(smartObject):
            x = self.openTabs[str(rep)]
            self.tabWidget.setCurrentWidget(x)
            return

        # Saves a representation of the opened entry to avoid opening duplicates
        # and open it
        x = AdvancedObjectWidget(QtCore.QPersistentModelIndex(index))
        x.initModel(smartObject)

        self.openTabs[str(rep)] = x
        self.tabWidget.addTab(x, smartObject.getPrettyRDN())
        self.tabWidget.setCurrentWidget(x)

    def deleteIndex(self, index):
        # Remember the smartObject for later
        sO = index.internalPointer().smartObject()
        # Try to delete
        (success, message) = self.ldaptreemodel.deleteItem(index)
        if success:
            # Close open edit-windows if any
            self.__closeTabIfOpen(sO)
            # Notify success
            return (True, message)
        else:
            # Notify fail
            return (False, message)

    def __closeTabIfOpen(self, sO):
        if self.isOpen(sO):
            rep = self.getRepForSmartObject(sO)
            x = self.openTabs.pop(str(rep))
            i = self.tabWidget.indexOf(x)
            if i != -1:
                self.tabWidget.removeTab(i)

    def deleteSelection(self, subTree=False):
        """Slot for the context menu.

        Opens the DeleteDialog with the selected entries, giving the
        user the option to validate the selection before deleting.

        This is for deleting the item + possibly it's subtree.
        See deleteOnlySubtreeOfSelection() for only subtree.
        """

        # Only a single item
        if len(self.selection) == 1 and not subTree:
            # Confirmation-message
            ok = QMessageBox.question(self, self.str_DELETE,
                                      self.str_REALLY_DELETE,
                                      QMessageBox.Yes | QMessageBox.No)
            if ok == QMessageBox.No:
                return
            index = self.selection[0]
            (status, message) = self.deleteIndex(index)
            if not status:
                QMessageBox.critical(
                    self, self.str_ERROR,
                    self.str_ERROR_MSG.format(index.data().toPyObject(),
                                              message))
            return

        # Make persistent indexes and list of smartObjects to be deleted
        persistenSelection = []
        sOList = []
        for x in self.selection:
            persistenSelection.append(QPersistentModelIndex(x))
            sOList.append(x.internalPointer().smartObject())

        # Create gui
        self.setBusy(True)
        deleteDialog = DeleteDialog(sOList, subTree)
        self.setBusy(False)
        status = deleteDialog.exec_()

        if status:  # the dialog was not canceled
            if subTree:
                # Reload the items whos subtree was deleted
                for x in self.selection:
                    self.ldaptreemodel.reloadItem(x)
                return
            # If all rows were removed successfully, just call
            # removeRows on all selected items (reloading all items of
            # the parent can be expensive)
            if deleteDialog.passedItemsWasDeleted:
                for x in persistenSelection:
                    if x.isValid:
                        i = x.sibling(x.row(), 0)  # QModelIndex
                        self.__closeTabIfOpen(
                            i.internalPointer().smartObject())
                        self.ldaptreemodel.removeRow(x.row(), x.parent())
                return

            # If not, call reload on the parent of all the items?
            else:
                tmp = QMessageBox.question(self,
                                           self.str_DELETION,
                                           self.str_DELETION_MSG,
                                           buttons=QMessageBox.Yes
                                           | QMessageBox.No,
                                           defaultButton=QMessageBox.Yes)
                if tmp == QMessageBox.Yes:
                    for x in persistenSelection:
                        # index might not be valid if the parent was
                        # reloaded by a previous item
                        if x.isValid():
                            self.ldaptreemodel.reloadItem(x.parent())
                        return

        # Was cancelled so do nothing
        else:
            pass

    def deleteSubtree(self):
        self.deleteSelection(subTree=True)

    def exportItems(self):
        """Slot for the context menu.
        """
        self.__exportSelection(scope=0)

    def exportSubtrees(self):
        """Slot for the context menu.
        """
        self.__exportSelection(scope=1)

    def exportSubtreeWithParents(self):
        """Slot for the context menu.
        """
        self.__exportSelection(scope=2)

    def __exportSelection(self, scope=0):
        """Slot for the context menu.

        Opens the ExportDialog with the selected entries, giving the
        user the option to validate the selection before exporting.

        :param scope: The scope selection.
         0 = SCOPE_BASE -> Item(s),
         1 = SCOPE_ONELEVEL -> Subtree(s);
         2 = SCOPE_SUBTREE -> Subtree(s) with parent
        :type scope: int
        """
        exportObjects = []
        msg = ''

        self.setBusy(True)
        for index in self.selection:
            smartObject = index.internalPointer().smartObject()

            serverName = smartObject.getServerAlias()
            dn = smartObject.getDN()
            serverObject = self.serverList.getServerObject(serverName)
            con = LumaConnectionWrapper(serverObject, self)

            # For both subtree and subtree with parent, we fetch the
            # whole subtree including the parent, with a basic sync
            # search operation. Then, if only the subtree is to be
            # exported, we remove the smartObject(s) selected.
            if scope > 0:
                pass

                # Do a search on the whole subtree
                # 2 = ldap.SCOPE_SUBTREE
                #elif scope == 2:

                success, e = con.bindSync()

                if not success:
                    self.__logger.error(str(e))
                    continue
                success, result, e = con.searchSync(base=dn, scope=2)

                if success:
                    exportObjects.extend(result)
                else:
                    self.__logger.error(str(e))

                # If only the subtree is to be selected, we remove
                # the parent, which happens to be the smartObject(s)
                # initialy selected.
                if scope == 1:
                    exportObjects.remove(smartObject)

            # For scope == 0 we need not do any LDAP search operation
            # because we already got what we need
            else:
                exportObjects.append(smartObject)

        # Initialize the export dialog
        # and give it the items for export
        dialog = ExportDialog(msg)
        dialog.setExportItems(exportObjects)
        self.setBusy(False)
        dialog.exec_()

    def editServerSettings(self):
        """Slot for the context menu.
        Opens the ServerDialog with the selected server.
        """
        try:
            items = self.selection
            serverItem = items[0].internalPointer().getParentServerItem()
            serverName = serverItem.serverMeta.name
            serverDialog = ServerDialog(serverName)
            r = serverDialog.exec_()
            if r:
                self.serversChangedMessage.showMessage(
                    self.str_SERVER_CHANGED_MSG)
        except Exception, e:
            self.__logger.error(str(e))
            QMessageBox.information(self, self.str_ERROR,
                                    self.str_SEE_LOG_DETAILS)