class SingleCategoryView(QWidget):
    def __init__(self, action, parent, logger, category=None, mode=None):
        super(SingleCategoryView, self).__init__(parent)
        
        self.logger = logger
        self._action = action
        self._category = category
        self._resetting = False
        
        if mode is not None:
            topWidget = None
            self._determineOwnMode = False
        else:
            self._determineOwnMode = True
            mode = PrivacySettings.get().getPolicy(self._action, self._category, useModified=True, categoryPolicy=self._getCategoryPolicy())
            topWidget = self._initTopView(mode)
            
        centralWidget = self._initPeerList(mode)
        bottomWidget = self._initBottomWidget()
        
        mainLayout = QVBoxLayout(self)
        if topWidget is None:
            # inside multiple categories view -> no margins
            mainLayout.setContentsMargins(0, 0, 0, 0)
        if topWidget is not None:
            mainLayout.addWidget(topWidget)
        mainLayout.addWidget(centralWidget, 1)
        mainLayout.addWidget(bottomWidget)
        self._modeChanged(mode, notify=False, resetModel=False)
        
        get_notification_center().connectPeerNameAdded(self._peerModel.peerNameAdded)
        get_notification_center().connectDisplayedPeerNameChanged(self._peerModel.peerNameChanged)
        get_notification_center().connectPrivacySettingsChanged(self._privacySettingsChanged)
        get_notification_center().connectPrivacySettingsDiscarded(self._privacySettingsChanged)
        
    def finish(self):
        get_notification_center().disconnectPeerNameAdded(self._peerModel.peerNameAdded)
        get_notification_center().disconnectDisplayedPeerNameChanged(self._peerModel.peerNameChanged)
        get_notification_center().disconnectPrivacySettingsChanged(self._privacySettingsChanged)
        get_notification_center().disconnectPrivacySettingsDiscarded(self._privacySettingsChanged)
        
    def _getCategoryPolicy(self):
        return PrivacySettings.CATEGORY_NEVER if self._category is None else PrivacySettings.CATEGORY_ALWAYS
        
    def _initTopView(self, mode):
        topWidget = QWidget(self)
        
        self._modeCombo = QComboBox(topWidget)
        self._modeCombo.addItem(u"nobody")
        self._modeCombo.addItem(u"nobody, except")
        self._modeCombo.addItem(u"everybody, except")
        self._modeCombo.addItem(u"everybody")
        self._modeCombo.setCurrentIndex(mode)
        self._modeCombo.currentIndexChanged.connect(self._modeChanged)
        
        topLayout = QHBoxLayout(topWidget)
        topLayout.setContentsMargins(0, 0, 0, 0)
        topLayout.addWidget(QLabel(u"Accept from"), 0)
        topLayout.addWidget(self._modeCombo, 1, Qt.AlignLeft)
        return topWidget
        
    def _initPeerList(self, mode):
        capsuleWidget = QWidget()
        capsuleLayout = QVBoxLayout(capsuleWidget)
        capsuleLayout.setContentsMargins(10, 0, 10, 0)
        
        if mode in (PrivacySettings.POLICY_EVERYBODY_EX, PrivacySettings.POLICY_NOBODY_EX, PrivacySettings.POLICY_PEER_EXCEPTION):
            exceptions = PrivacySettings.get().getExceptions(self._action, self._category, mode, useModified=True, categoryPolicy=self._getCategoryPolicy())
        else:
            exceptions = {}
        self._peerModel = PeerModel(exceptions,
                                    mode == PrivacySettings.POLICY_PEER_EXCEPTION,
                                    self.logger)
        self._peerModel.itemChanged.connect(self._peerDataChanged)
        
        proxyModel = QSortFilterProxyModel(self)
        proxyModel.setDynamicSortFilter(True)
        proxyModel.setSortCaseSensitivity(Qt.CaseInsensitive)
        proxyModel.setSourceModel(self._peerModel)
        proxyModel.sort(0)
        
        self._peerList = QTreeView(self)
        self._peerList.setAlternatingRowColors(False)
        self._peerList.setHeaderHidden(True)
        self._peerList.setItemsExpandable(False)
        self._peerList.setIndentation(0)
        self._peerList.setModel(proxyModel)
        self._peerList.setSelectionMode(QTreeView.NoSelection)
        self._peerList.setAutoFillBackground(False)
        self._peerList.viewport().setAutoFillBackground(False)
        self._peerList.setFrameShape(QFrame.NoFrame)
        self._peerList.setFocusPolicy(Qt.NoFocus)
        
        capsuleLayout.addWidget(self._peerList)
        return capsuleWidget
    
    def _initBottomWidget(self):
        self._askForConfirmationBox = QCheckBox(u"Ask if state is unknown", self)
        self._askForConfirmationBox.stateChanged.connect(self._askForConfirmationChanged)
        return self._askForConfirmationBox
    
    @loggingSlot(QStandardItem)
    def _peerDataChanged(self, item):
        if not self._resetting:
            PrivacySettings.get().addException(self._action,
                                               self._category,
                                               self._mode,
                                               convert_string(item.data(PeerModel.KEY_ROLE).toString()),
                                               1 if item.checkState() == Qt.Checked else 0 if item.checkState() == Qt.Unchecked else -1,
                                               applyImmediately=False,
                                               categoryPolicy=self._getCategoryPolicy())
    
    @loggingSlot(int)
    def _askForConfirmationChanged(self, newState):
        if not self._resetting:
            PrivacySettings.get().setAskForConfirmation(self._action, self._category, newState == Qt.Checked, applyImmediately=False, categoryPolicy=self._getCategoryPolicy())
        
    @loggingSlot(int)
    def _modeChanged(self, newMode, notify=True, resetModel=True):
        self._resetting = True
        if newMode in (PrivacySettings.POLICY_EVERYBODY_EX, PrivacySettings.POLICY_NOBODY_EX, PrivacySettings.POLICY_PEER_EXCEPTION):
            if resetModel:
                # no change notifications, we are just resetting the model
                self._peerModel.itemChanged.disconnect(self._peerDataChanged)
                self._peerModel.setExceptionData(PrivacySettings.get().getExceptions(self._action, self._category, newMode, useModified=True, categoryPolicy=self._getCategoryPolicy()))
                self._peerModel.itemChanged.connect(self._peerDataChanged)
            self._peerList.setVisible(True)
        else:
            self._peerList.setVisible(False)
        
        if newMode == PrivacySettings.POLICY_NOBODY_EX:
            ask = PrivacySettings.get().getAskForConfirmation(self._action, self._category, useModified=True, categoryPolicy=self._getCategoryPolicy())
            self._askForConfirmationBox.setCheckState(Qt.Checked if ask else Qt.Unchecked)
            self._askForConfirmationBox.setVisible(True)
        else:
            self._askForConfirmationBox.setVisible(False)
        self._mode = newMode
        
        self._resetting = False
        if notify:
            PrivacySettings.get().setPolicy(self._action, self._category, self._mode, applyImmediately=False, categoryPolicy=self._getCategoryPolicy())
        
    def setMode(self, newMode):
        self._modeChanged(newMode, notify=False)

    def getCategory(self):
        return self._category

    @loggingSlot(object, object)
    def _privacySettingsChanged(self, pluginName, actionName):
        if pluginName != self._action.getPluginName() or actionName != self._action.getName():
            return
        if self._determineOwnMode:
            newMode = PrivacySettings.get().getPolicy(self._action, self._category, categoryPolicy=self._getCategoryPolicy())
        else:
            newMode = self._mode
        self._modeChanged(newMode, notify=False)