Exemple #1
0
    def drawGUI(self):
        form_layout = QFormLayout(self)
        form_layout.setFormAlignment(Qt.AlignLeft)
        title = QLabel(tr("<H1>DHCP Configuration</H1>"))
        form_layout.addRow(title)

        self.enable = QCheckBox(tr("Enable DHCP Server on configured LANs"))
        form_layout.addRow(self.enable)
        self.main_window.writeAccessNeeded(self.enable)

        self.add_button = AddButton()
        self.add_button.setText(tr("Add a range"))
        self.main_window.writeAccessNeeded(self.add_button)
        form_layout.addRow(self.add_button, QLabel())
        if not self.main_window.readonly:
            self.connect(self.enable, SIGNAL('stateChanged(int)'), self.setDHCPEnabled)
            self.connect(self.add_button, SIGNAL('clicked()'), self.addRange)

        self.setLayout(form_layout)
Exemple #2
0
    def __init__(self, parent=None, isChild=False):
        QWidget.__init__(self, parent)
        QGridLayout(self)

        # FIXME: call self.setLayout(layout)?
        self._readonly = False

        self.up_down = QFrame()
        self.up = UpButton()
        self.down = DownButton()
        self.add = AddButton()
        self.rem = RemButton()
        self.listEditView = ListEditView(isChild, parent=self)

        self.connect(self.listEditView, SIGNAL('itemAdded'), SIGNAL('itemAdded'))
        self.connect(self.listEditView, SIGNAL('itemModified'), SIGNAL('itemModified'))
        self.connect(self.listEditView.model, SIGNAL('dataChanged(QModelIndex,QModelIndex)'),
            SIGNAL('dataChanged(QModelIndex,QModelIndex)'))
        self.connect(self.listEditView.model, SIGNAL('rowsRemoved(QModelIndex,int,int)'),
            SIGNAL('rowsRemoved(QModelIndex,int,int)'))
        self.connect(self.listEditView.model, SIGNAL('headerDataChanged(Qt::Orientation,int,int)'),
            SIGNAL('headerDataChanged(Qt::Orientation,int,int)'))
        self.connect(self.listEditView, SIGNAL('itemDeleted'), SIGNAL('itemDeleted'))
        self.connect(self.listEditView, SIGNAL('itemSorted'), SIGNAL('itemSorted'))
        self.connect(self.listEditView.horizontalHeader(), SIGNAL('sectionClicked(int)'),
            SIGNAL('sectionClicked(int)'))
        self.connect(self.listEditView, SIGNAL('clicked(QModelIndex)'),
            SIGNAL('clicked(QModelIndex)'))

        self.layout().addWidget(self.listEditView, 0, 0)

        self.buildUpDown()
        if not isChild:
            self.buildAddRem()
        self.setDisplayUpDown(False)
        self.setReadOnly(False)
Exemple #3
0
class ListEdit(QWidget):
    def __init__(self, parent=None, isChild=False):
        QWidget.__init__(self, parent)
        QGridLayout(self)

        # FIXME: call self.setLayout(layout)?
        self._readonly = False

        self.up_down = QFrame()
        self.up = UpButton()
        self.down = DownButton()
        self.add = AddButton()
        self.rem = RemButton()
        self.listEditView = ListEditView(isChild, parent=self)

        self.connect(self.listEditView, SIGNAL('itemAdded'), SIGNAL('itemAdded'))
        self.connect(self.listEditView, SIGNAL('itemModified'), SIGNAL('itemModified'))
        self.connect(self.listEditView.model, SIGNAL('dataChanged(QModelIndex,QModelIndex)'),
            SIGNAL('dataChanged(QModelIndex,QModelIndex)'))
        self.connect(self.listEditView.model, SIGNAL('rowsRemoved(QModelIndex,int,int)'),
            SIGNAL('rowsRemoved(QModelIndex,int,int)'))
        self.connect(self.listEditView.model, SIGNAL('headerDataChanged(Qt::Orientation,int,int)'),
            SIGNAL('headerDataChanged(Qt::Orientation,int,int)'))
        self.connect(self.listEditView, SIGNAL('itemDeleted'), SIGNAL('itemDeleted'))
        self.connect(self.listEditView, SIGNAL('itemSorted'), SIGNAL('itemSorted'))
        self.connect(self.listEditView.horizontalHeader(), SIGNAL('sectionClicked(int)'),
            SIGNAL('sectionClicked(int)'))
        self.connect(self.listEditView, SIGNAL('clicked(QModelIndex)'),
            SIGNAL('clicked(QModelIndex)'))

        self.layout().addWidget(self.listEditView, 0, 0)

        self.buildUpDown()
        if not isChild:
            self.buildAddRem()
        self.setDisplayUpDown(False)
        self.setReadOnly(False)

    # Qt Properties ...
    def getReadOnly(self):
        return self._readonly

    def setReadOnly(self, readonly):
        self._readonly = readonly
        self.up.setEnabled(not self.readOnly)
        self.down.setEnabled(not self.readOnly)
        self.add.setEnabled(not self.readOnly)
        self.rem.setEnabled(not self.readOnly)
        self.listEditView.setReadOnly(self.readOnly)

    def resetReadOnly(self):
        self._readonly = False

    readOnly = pyqtProperty('bool', getReadOnly, setReadOnly, resetReadOnly)


    def getAcceptDrops(self):
        return self.listEditView.acceptDrops()

    def setAcceptDrops(self, mode):
        self.listEditView.setAcceptDrops(mode)
        flags = self.listEditView.model.getFlags()
        if mode:
            flags |= Qt.ItemIsDropEnabled
        else:
            flags &= ~Qt.ItemIsDropEnabled
        self.listEditView.model.setFlags(flags)

    def resetAcceptDrops(self):
        self.setAcceptDrops(False)

    acceptDrops = pyqtProperty('bool', getAcceptDrops, setAcceptDrops,
        resetAcceptDrops)


    def getDragDropMode(self):
        return self.listEditView.dragDropMode()

    Q_ENUMS('QAbstractItemView.DragDropMode')
    def setDragDropMode(self, mode):
        self.listEditView.setDragDropMode(mode)

    def resetDragDropMode(self):
        self.listEditView.setDragDropMode(QAbstractItemView.NoDragDrop)

    dragDropMode = pyqtProperty('QAbstractItemView::DragDropMode',
        getDragDropMode, setDragDropMode, resetDragDropMode)


    def getShowDropIndicator(self):
        return self.listEditView.showDropIndicator()

    def setShowDropIndicator(self, mode):
        self.listEditView.setShowDropIndicator(mode)

    def resetShowDropIndicator(self):
        self.listEditView.setShowDropIndicator(False)

    showDropIndicator = pyqtProperty('bool', getShowDropIndicator,
        setShowDropIndicator, resetShowDropIndicator)


    def getDisplayUpDown(self):
        return self.up_down.isVisible()

    def setDisplayUpDown(self, displayUpDown):
        self.up_down.setVisible(displayUpDown)

    def resetDisplayUpDown(self):
        self.up_down.setVisible(False)

    displayUpDown = pyqtProperty('bool', getDisplayUpDown, setDisplayUpDown,
        resetDisplayUpDown)


    def getEditBoxDescription(self):
        return self.listEditView.getEditBoxDescription()

    def setEditBoxDescription(self, description):
        self.listEditView.setEditBoxDescription(description)

    def resetEditBoxDescription(self):
        self.listEditView.resetEditBoxDescription()

    editBoxDescription = pyqtProperty('QString', getEditBoxDescription,
        setEditBoxDescription, resetEditBoxDescription)


    def getHeaders(self):
        return self.listEditView.getHeaders()

    def setHeaders(self, headers):
        self.listEditView.setHeaders(headers)

    def resetHeaders(self):
        self.listEditView.resetHeaders()

    headers = pyqtProperty('QStringList', getHeaders, setHeaders, resetHeaders)


    def getEditInPopup(self):
        return self.listEditView.editInPopup

    def setEditInPopup(self, in_popup):
        self.listEditView.editInPopup = in_popup

    def resetEditInPopup(self):
        self.listEditView.editInPopup = True

    editInPopup = pyqtProperty('bool', getEditInPopup, setEditInPopup,
        resetEditInPopup)

    def getEditInPlace(self):
        return self.listEditView.editInPlace

    def setEditInPlace(self, edit_in_place):
        self.listEditView.editInPlace = edit_in_place

    def resetEditInPlace(self):
        self.listEditView.editInPlace = False

    editInPlace = pyqtProperty('bool', getEditInPlace, setEditInPlace,
        resetEditInPlace)

    # ... Qt Properties

    def setDropMimeData(self, callback):
        self.listEditView.model.dropMimeData_cb = callback

    def setEditBox(self, editBox):
        """allow to customize edit popup"""
        #   box = editBox([row1, row2, row3], listEditOption, windowTitle)
        #   ret = box.exec_()
        #   if QDialog.Accepted == ret:
        #       newData = box.getData()
        #       # newData : [ modifiedRow1, modifiedRow2, modifiedRow3 ]
        # box must return QDialog.Accepted if data have been modified / created
        # then data must be returned by box.getData()
        self.listEditView.editBox = editBox

    def setColDelegate(self, callback):
        """callback prototype: createDelegate(view, column)"""
        self.listEditView.setColDelegate(callback)

    def buildUpDown(self):
        up_down_layout = QVBoxLayout(self.up_down)
        up_down_layout.addWidget(self.up)
        up_down_layout.addWidget(self.down)
        up_down_layout.insertStretch(0)
        up_down_layout.insertStretch(-1)
        self.layout().addWidget(self.up_down, 0, 1)
        self.connect(self.up, SIGNAL('clicked()'), self.listEditView.upItem)
        self.connect(self.down, SIGNAL('clicked()'), self.listEditView.downItem)

    def buildAddRem(self):
        buttons = QFrame()
        buttons_layout = QHBoxLayout(buttons)
        buttons_layout.insertStretch(1)
        self.connect(self.add, SIGNAL('clicked()'), self.listEditView.addItem)
        self.connect(self.rem, SIGNAL('clicked()'), self.listEditView.removeItem)
        buttons_layout.addWidget(self.add)
        buttons_layout.addWidget(self.rem)
        self.layout().addWidget(buttons, 1, 0)

    def hideRow(self, row):
        self.listEditView.verticalHeader().setSectionHidden(row, True)

    def showRow(self, row):
        self.listEditView.verticalHeader().setSectionHidden(row, False)

    def hideColumn(self, col):
        self.listEditView.horizontalHeader().setSectionHidden(col, True)

    def showColumn(self, col):
        self.listEditView.horizontalHeader().setSectionHidden(col, False)

    def reset(self, data):
        """
        TODO call clean & setData & reset
        """
        self.listEditView.model.newData(data)
        self.listEditView.model.emit(SIGNAL("modelReset()"))

    def rawData(self):
        # TODO use model.data(...)
        return deepcopy(self.listEditView.model._data)
Exemple #4
0
class DHCPWidget(QFrame):
    def __init__(self, client, main_window, parent):
        QFrame.__init__(self, parent)
        self._parent = parent
        self._loading = True
        self._modified = False
        self.client = client
        self.main_window = main_window
        self.addToInfoArea = self.main_window.addToInfoArea
        self.q_netobject = QNetObject.getInstance()
#        try:
#            self.q_netobject.registerCallbacks(self.acceptNetworkChange, self.handleNetworkChange)
#        except Exception, err:
#            raise

        self.dhcpcfg = None
        self.range_widgets = set()
        self.drawGUI()
        self.resetConf()
        self._loading = False

    def drawGUI(self):
        form_layout = QFormLayout(self)
        form_layout.setFormAlignment(Qt.AlignLeft)
        title = QLabel(tr("<H1>DHCP Configuration</H1>"))
        form_layout.addRow(title)

        self.enable = QCheckBox(tr("Enable DHCP Server on configured LANs"))
        form_layout.addRow(self.enable)
        self.main_window.writeAccessNeeded(self.enable)

        self.add_button = AddButton()
        self.add_button.setText(tr("Add a range"))
        self.main_window.writeAccessNeeded(self.add_button)
        form_layout.addRow(self.add_button, QLabel())
        if not self.main_window.readonly:
            self.connect(self.enable, SIGNAL('stateChanged(int)'), self.setDHCPEnabled)
            self.connect(self.add_button, SIGNAL('clicked()'), self.addRange)

        self.setLayout(form_layout)

    def addRange(self):
        self.setModified(True)
        self.addRangeFrontend()

    def fetchCfg(self):
        dhcpcfg_repr = self.main_window.init_call("dhcp", "getDhcpConfig")
        if dhcpcfg_repr is None:
            #Failing to fetch dhcp config
            return None
        netcfg = self.q_netobject.netcfg
        if netcfg is None:
            return None
        return deserialize(dhcpcfg_repr, netcfg)

    def setDHCPEnabled(self, state):
        self.setModified(True)
        if state == Qt.Unchecked:
            self.dhcpcfg.enabled = DISABLED
        else:
            self.dhcpcfg.enabled = ENABLED

    def isModified(self):
        return self._modified

    def setModified(self, bool=True):
        if self._loading:
            return
        if bool == True:
            self.main_window.setModified(self._parent, True)
        if self._modified is False and bool is True:
            self.addToInfoArea(tr("DHCP Server configuration edited."))
        self._modified = bool

    def resetConf(self):
        self.dhcpcfg = self.fetchCfg()
        if self.dhcpcfg is None:
            self._clearWidgets()
            msg_area = MessageArea()
            msg_area.setMessage(
                tr("Problem loading the network or dhcp configuration!"),
                tr("A problem occured while loading the network "
                "or dhcp config from the appliance!"),
                "critical"
                )
            self.layout().insertRow(2, msg_area)
            self.enable.setEnabled(False)
            self.add_button.setEnabled(False)
        else:
            self.fillView()
        self._modified = False

    def _clearWidgets(self):
        for widget in self.range_widgets:
            # sometimes the widget stay visible
            widget.close()

        self.range_widgets.clear()

    def fillView(self):
        self._clearWidgets()
        if self.dhcpcfg is None:
            return

        for range in self.dhcpcfg.ranges:
            self.addRangeFrontend(range=range)
        if  self.dhcpcfg.enabled == ENABLED:
            check_state = Qt.Checked
        else:
            check_state = Qt.Unchecked
        self.enable.setCheckState(check_state)

    def addRangeFrontend(self, range=None):
        # called by resetConf so we can access to QNetObject.getInstance().netcfg
        range_widget = NewRangeFrontend(dhcprange=range)

        self.main_window.writeAccessNeeded(range_widget)
        self.range_widgets.add(range_widget)
        self.connect(range_widget, SIGNAL('deleted'), self.delRangeFrontend)
        self.connect(range_widget, SIGNAL('modified'), self.setModified)
        if range is None:
            self.dhcpcfg.ranges.add(range_widget.dhcprange)
        layout = self.layout()
        layout.insertRow(2, range_widget)

        range_widget.setParent(self)

    def getWidgetFromRange(self, range):
        for widget in self.range_widgets:
            if widget.range is range:
                return widget

    def delRangeFrontend(self, range_widget):
        self.dhcpcfg.ranges.discard(range_widget.dhcprange)
        self.range_widgets.discard(range_widget)
        self.setModified(True)

    def isValid(self):
        to_remove = set()
        for range_widget in self.range_widgets:
            dhcprange = range_widget.dhcprange
            if dhcprange not in self.dhcpcfg.ranges or dhcprange.is_fully_unset():
                to_remove.add(range_widget)
                continue
        for range_widget in to_remove:
            self.delRangeFrontend(range_widget)
            range_widget.close()
        return self.dhcpcfg.isValid()

    def saveConf(self, message):
        dhcpcfg_repr = self.dhcpcfg.serialize()
        self.client.call("dhcp", 'setDhcpConfig', dhcpcfg_repr, message)
        self.setModified(False)
        self.addToInfoArea(tr("DHCP server configuration uploaded to server."))

    def acceptNetworkChange(self):
        deletable = set()
        translatable = set()

        translated_ranges = {}

        if self.dhcpcfg is None:
            return True, translated_ranges, deletable

        deletable, translatable = self.dhcpcfg.computeChanges(self.q_netobject.netcfg)

        if not (deletable | translatable):
            #Nothing to do (yay!) we agree with proposed changes
            return True

        #oh, questions arrive
        accept = True
        generic_text = "<h2>%s</h2>" % tr("This change affects the DHCP server configuration")

        #TODO: add questions and return


        for range in translatable:

            if not accept:
                break

            if not isinstance(range.router, IP):
                new_router_ip = UNSET
            else:
                new_router_ip = adjust_ip(range.net.net, range.router)

            widget_range = self.getWidgetFromRange(range)
            simulation = {
                'start': adjust_ip(range.net.net, range.start),
                'end': adjust_ip(range.net.net, range.end),
                'router': new_router_ip,
                'custom_dns': widget_range.custom_dns,
                }

            cur_router = _valuefromrouter(range.router)
            new_router = _valuefromrouter(simulation['router'])

            help_items = []
            help_items.append(tr("Clicking \"Yes\" will change the DHCP range."))
            help_items.append(tr("Clicking \"Ignore\" will not change the DHCP range. Double-check the DHCP server configuration before saving."))
            help_items.append(tr("Clicking \"Cancel\" will cancel your changes to the network configuration"))
            help_text = unicode(htmlList(help_items))

            title = tr("DHCP: Translate a range?")

            html = u"""<table>
                %(title)s<br />
                %(ask)s<br />
                <tr>
                    <td><h2>%(start)s</h2></td>
                    <td>%(cur_start)s</td>
                    <td><img src=":/icons-32/go-next"/></td>
                    <td>%(simu_start)s</td>
                </tr>
                <tr>
                    <td><h2>%(end)s</h2></td>
                    <td>%(cur_end)s</td>
                    <td><img src=":/icons-32/go-next"/></td>
                    <td>%(simu_end)s</td>
                </tr>
                <tr>
                    <td><h2>%(router)s</h2></td>
                    <td>%(cur_router)s</td>
                    <td><img src=":/icons-32/go-next"/></td>
                    <td>%(simu_router)s</td>
                </tr>
            </table>
            """ % {
                'title' : tr("You changed the network address for the '<i>%s</i>' network") % range.net.label,
                'ask' : tr("Do you want to adjust the range?"),
                'start' : tr("Start IP"),
                'cur_start' : range.start,
                'simu_start' : unicode(simulation['start']),
                'end' : tr("End IP"),
                'cur_end' : range.end,
                'simu_end' : unicode(simulation['end']),
                'router' : tr("Router IP"),
                'cur_router' : cur_router,
                'simu_router' : unicode(new_router),
            }

            html += help_text

            message_box = QMessageBox(self)
            message_box.setWindowTitle(title)
            message_box.setText(generic_text)
            message_box.setInformativeText(html)
            message_box.setStandardButtons(
                QMessageBox.Yes | QMessageBox.Ignore | QMessageBox.Cancel
            )

            clicked_button = message_box.exec_()
            accept = clicked_button in (QMessageBox.Yes, QMessageBox.Ignore)
            if clicked_button == QMessageBox.Yes:
                translated_ranges[range] = simulation

        deletable_ranges = frozenset()

        if accept and deletable:
            deletable_tr = tr("Consequence: the following DHCP range will be deleted:")
            deletable_html = u"<ul>"
            for range in deletable:
                deletable_html += "<li>%s %s: %s > %s</li>" % (
                    deletable_tr,
                    unicode(range.net),
                    unicode(range.start),
                    unicode(range.end)
                    )
            deletable_html += u"</ul>"
            title = tr("DHCP configuration")
            message_box = QMessageBox(self)
            message_box.setWindowTitle(title)
            message_box.setText(generic_text)
            message_box.setInformativeText(deletable_html)
            message_box.setStandardButtons(
                QMessageBox.Yes | QMessageBox.Cancel
            )

            clicked_button = message_box.exec_()
            accept = (clicked_button == QMessageBox.Yes)
            if accept:
                deletable_ranges = deletable

        if not accept:
            return False

        return True, translated_ranges, deletable_ranges

    def handleNetworkChange(self, *args):
        if args:
            translated_ranges, deleted_ranges = args

            changed = False
            for range in deleted_ranges:
                self.dhcpcfg.ranges.remove(range)
                changed = True

            for range, translation in translated_ranges.iteritems():
                range.start = translation['start']
                range.end = translation['end']
                range.router = translation['router']
                changed = True

            if changed:
                self.setModified(True)
        self.fillView()