class BoardWidget(QWidget):
    def __init__(self, *args, **kwargs):
        engine = kwargs.pop('engine')

        super(BoardWidget, self).__init__(*args, **kwargs)

        self.setupEngine(engine)

        self.setupUi()

    def setupEngine(self, engine):
        self.engine = engine
        self.engine.playerMoved.connect(self.handlePlayerMoved)

    def setupUi(self):
        grid = QGridLayout()
        grid.setSpacing(GRID_SPACING)
        self.setLayout(grid)

        self.buttonGroup = QButtonGroup()
        for position in self.engine.board.positions:
            button = GameButton(position)
            self.buttonGroup.addButton(button, position)
            grid.addWidget(button, position / 3, position % 3)
        self.buttonGroup.buttonClicked['int'].connect(self.engine.handleInput)

        size = 4 * GRID_SPACING + 3 * BUTTON_SIZE
        self.setFixedSize(size, size)

    def handlePlayerMoved(self, position, player):
        self.buttonGroup.buttons()[position].markPlayer(player)

    def resetUi(self):
        for button in self.buttonGroup.buttons():
            button.clearText()
class ActionsPane(QWidget):
    def __init__(self):
        super().__init__()

        self.group = QButtonGroup()
        self.group.setExclusive(False)

        self.scope_widget = ActionsScope()
        self.action_buttons = QVBoxLayout()
        self.big_red_button = QPushButton("Automate !!!", clicked=self.automate)
        self.big_red_button.setStyleSheet("QPushButton { background-color : red}")

        self.layout = QVBoxLayout()
        self.setLayout(self.layout)

        self.layout.addWidget(self.scope_widget)
        self.layout.addLayout(self.action_buttons)
        self.layout.addStretch()
        self.layout.addWidget(self.big_red_button)

    def registerAction(self, action):
        button = ActionButton(action)
        self.group.addButton(button.checkbox)
        self.action_buttons.addWidget(button)

    def getCheckedActions(self):
        return [btn.parent().action for btn in self.group.buttons() if btn.isChecked()]

    def automate(self, event):
        for action in self.getCheckedActions():
            action.on_triggered()
class ScopeBox(QGroupBox):
    title = None
    button_type = None

    def __init__(self):
        if self.title is None or self.button_type is None:
            raise Exception("Still too abstract!")

        super().__init__(title=self.title)

        self.populate_button_id()
        self.build_layout()
        self.populate_box()
        self.select_default()

        if self.button_type == 'check':
            self.group.setExclusive(False)

    def populate_button_id(self):
        pass

    def build_layout(self):
        self.group = QButtonGroup()
        self.layout = QVBoxLayout()
        self.setLayout(self.layout)

    def populate_box(self):
        keys = list(self.button_id.keys())
        keys.sort()

        BtnClass = None
        if self.button_type == 'check':
            BtnClass = QCheckBox
        elif self.button_type == 'radio':
            BtnClass = QRadioButton

        for key in keys:
            btn = BtnClass(key)
            self.layout.addWidget(btn)
            self.group.addButton(btn, self.button_id[key])

    def select_default(self):
        pass

    def getSelection(self):
        selection = None

        if self.button_type == 'radio':
            selection = self.group.checkedId()
        elif self.button_type == 'check':
            selection = []

            for btn in self.group.buttons():
                if btn.isChecked():
                    selection.append(btn.text())

        return selection
class DBDatabasesWidget(QWidget):
    """Displays a list of Databases"""
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.debug = False

        self.db = None

        self.setWindowTitle("Databases")
        #s#elf.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)

        self.mainLayout = QVBoxLayout()
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.setSpacing(0)
        self.setLayout(self.mainLayout)

        #=============================================
        ## Top Toolbar
        topBar = QToolBar()
        topBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.mainLayout.addWidget(topBar)

        ## Add the action buttons
        topBar.addAction(Ico.icon(Ico.ServerAdd), "Add", self.on_server_add)
        self.actionServerEdit = topBar.addAction(Ico.icon(Ico.ServerEdit),
                                                 "Edit", self.on_server_edit)
        self.actionServerDelete = topBar.addAction(Ico.icon(Ico.ServerDelete),
                                                   "Delete",
                                                   self.on_server_delete)

        #=============================================
        ## Tree
        self.tree = QTreeWidget()
        self.mainLayout.addWidget(self.tree)
        self.tree.setHeaderLabels(["Server", "User", ""])
        self.tree.setUniformRowHeights(True)
        self.tree.setRootIsDecorated(False)
        self.tree.setColumnWidth(C.widget, 20)

        self.connect(self.tree, SIGNAL('itemSelectionChanged()'),
                     self.on_tree_selection_changed)
        self.connect(self.tree,
                     SIGNAL('itemDoubleClicked (QTreeWidgetItem *,int)'),
                     self.on_tree_double_clicked)

        self.buttGroup = QButtonGroup(self)
        self.connect(self.buttGroup, SIGNAL("buttonClicked(QAbstractButton*)"),
                     self.on_open_server)

        self.on_tree_selection_changed()

        self.load_servers()

    #=======================================
    ##== Tree Events
    def on_tree_selection_changed(self):

        disabled = self.tree.selectionModel().hasSelection() == False
        self.actionServerEdit.setDisabled(disabled)
        self.actionServerDelete.setDisabled(disabled)

    def on_tree_double_clicked(self):
        self.actionServerEdit.trigger()

    #=======================================
    ## Server Actions
    def on_server_add(self):
        self.show_server_dialog(None)

    def on_server_edit(self):
        item = self.tree.currentItem()
        if item == None:
            return
        server = str(item.text(C.server))
        self.show_server_dialog(server)

    def show_server_dialog(self, server=None):
        d = DBServerDialog.DBServerDialog(self, server)
        if d.exec_():
            self.load_servers()

    def on_open_server(self, butt):
        self.emit(SIGNAL("open_server"), butt.property("server").toString())

    def load_servers(self):
        """Load servers from :py:meth:`pyqtdb.XSettings.XSettings.get_servers` """

        self.tree.clear()

        for butt in self.buttGroup.buttons():
            self.buttGroup.removeButton(butt)

        for srv in G.settings.get_servers_list():

            item = QTreeWidgetItem()
            item.setText(C.server, srv['server'])
            item.setText(C.user, srv['user'])
            self.tree.addTopLevelItem(item)

            butt = QToolButton()
            butt.setIcon(Ico.icon(Ico.Connect))
            butt.setProperty("server", srv['server'])
            self.tree.setItemWidget(item, C.widget, butt)
            self.buttGroup.addButton(butt)

    def on_server_delete(self):
        item = self.tree.currentItem()
        if item == None:
            return
        srv = str(item.text(C.server))
        G.settings.delete_server(srv)
        self.load_servers()
Exemple #5
0
class OptionWidget(EditorWidget):
    widgettype = 'Option Row'

    def __init__(self, *args, **kwargs):
        super(OptionWidget, self).__init__(*args, **kwargs)
        self._bindvalue = None
        self.group = QButtonGroup()
        self.group.buttonClicked.connect(self.emitvaluechanged)

    def createWidget(self, parent=None):
        widget = QWidget(parent)
        return widget

    def _buildfromlist(self, listconfig, multiselect):
        def chunks(l, n):
            """ Yield successive n-sized chunks from l.
            """
            for i in xrange(0, len(l), n):
                yield l[i:i+n]

        items = listconfig['items']
        wrap = self.config.get('wrap', 0)
        showcolor = self.config.get('always_color', False)
        if wrap > 0:
            rows = list(chunks(items, wrap))
        else:
            rows = [items]

        for rowcount, row in enumerate(rows):
            for column, item in enumerate(row):
                parts = item.split(';')
                data = parts[0]
                try:
                    desc = parts[1]
                except IndexError:
                    desc = data

                button = QPushButton()
                button.setCheckable(multiselect)
                self.group.setExclusive(not multiselect)

                icon = QIcon()
                try:
                    path = parts[2]
                    if path.startswith("#"):
                        # Colour the button with the hex value.
                        # If show color is enabled we always show the color regardless of selection.
                        print showcolor
                        if not showcolor:
                            style = """
                                QPushButton::checked {{
                                    border: 3px solid rgb(137, 175, 255);
                                    background-color: {colour};
                                }}""".format(colour=path)
                        else:
                            style = """
                                QPushButton::checked {{
                                    border: 3px solid rgb(137, 175, 255);
                                }}
                                QPushButton {{
                                    background-color: {colour};
                                }}""".format(colour=path)
                        button.setStyleSheet(style)
                    elif path.endswith("_icon"):
                        icon = QIcon(":/icons/{}".format(path))
                    else:
                        icon = QIcon(path)
                except:
                    icon = QIcon()

                button.setCheckable(True)
                button.setText(desc)
                button.setProperty("value", data)
                button.setIcon(icon)
                button.setIconSize(QSize(24, 24))
                if isinstance(self.widget.layout(), QBoxLayout):
                    self.widget.layout().addWidget(button)
                else:
                    self.widget.layout().addWidget(button, rowcount, column)
                self.group.addButton(button)

    def initWidget(self, widget, config):
        if not widget.layout():
            widget.setLayout(QGridLayout())
            widget.layout().setContentsMargins(0, 0, 0, 0)

    def updatefromconfig(self):
        super(OptionWidget, self).updatefromconfig()

        for button in self.group.buttons():
            self.group.removeButton(button)
            self.widget.layout().removeWidget(button)
            button.deleteLater()
            button.setParent(None)

        listconfig = self.config['list']
        multiselect = self.config.get('multi', False)
        self._buildfromlist(listconfig, multiselect)

        super(OptionWidget, self).endupdatefromconfig()

    def validate(self, *args):
        button = self.group.checkedButton()
        if button:
            return True

        return False

    @property
    def buttons(self):
        return self.group.buttons()

    @property
    def nullvalues(self):
        return ['NULL']

    @property
    def multioption(self):
        return self.config.get('multi', False)

    def setvalue(self, value):
        def set_button(setvalue):
            for button in self.group.buttons():
                buttonvalue = button.property("value")
                if (setvalue is None and buttonvalue in self.nullvalues) or buttonvalue == str(setvalue):
                    button.setChecked(True)
                    self.emitvaluechanged()
                    return

        if value in self.nullvalues:
            value = None

        if self.multioption and value:
            values = value.split(';')
        else:
            values = [value]

        for value in values:
            set_button(value)

    def value(self):
        def _returnvalue():
            if self.multioption:
                _values = []
                checked = [button for button in self.group.buttons() if button.isChecked()]
                for button in checked:
                    value = button.property("value")
                    _values.append(value)
                if not _values:
                    return None
                return ";".join(_values)
            else:
                checked = self.group.checkedButton()
                if not checked:
                    return None

                value = checked.property("value")
                return value

        returnvalue = _returnvalue()

        if returnvalue in self.nullvalues:
            returnvalue = None

        return returnvalue
Exemple #6
0
class OptionWidget(EditorWidget):
    widgettype = 'Option Row'

    def __init__(self, *args):
        super(OptionWidget, self).__init__(*args)
        self._bindvalue = None
        self.group = QButtonGroup()
        self.group.setExclusive(True)
        self.group.buttonClicked.connect(self.emitvaluechanged)

    def createWidget(self, parent):
        widget = QWidget(parent)
        return widget

    def _buildfromlist(self, listconfig):
        items = listconfig['items']
        for item in items:
            parts = item.split(';')
            data = parts[0]
            try:
                desc = parts[1]
            except IndexError:
                desc = data

            button = QPushButton()

            icon = QIcon()
            try:
                path = parts[2]
                if path.startswith("#"):
                    # Colour the button with the hex value
                    style = """
                        QPushButton:checked  {{
                            border: 3px solid rgb(137, 175, 255);
                        background-color: {colour};
                        }}""".format(colour=path)
                    button.setStyleSheet(style)
                elif path.endswith("_icon"):
                    icon = QIcon(":/icons/{}".format(path))
                else:
                    icon = QIcon(path)
            except:
                icon = QIcon()

            button.setCheckable(True)
            button.setText(desc)
            button.setProperty("value", data)
            button.setIcon(icon)
            button.setIconSize(QSize(24, 24))
            self.widget.layout().addWidget(button)
            self.group.addButton(button)

    def initWidget(self, widget):
        if not widget.layout():
            widget.setLayout(QHBoxLayout())
            widget.layout().setContentsMargins(0, 0, 0, 0)

    def updatefromconfig(self):
        super(OptionWidget, self).updatefromconfig()

        for button in self.group.buttons():
            self.group.removeButton(button)
            self.widget.layout().removeWidget(button)
            button.deleteLater()
            button.setParent(None)

        listconfig = self.config['list']
        self._buildfromlist(listconfig)

        super(OptionWidget, self).endupdatefromconfig()

    def validate(self, *args):
        button = self.group.checkedButton()
        if button:
            return True

        return False

    @property
    def nullvalues(self):
        return ['NULL']

    def setvalue(self, value):
        if value in self.nullvalues:
            value = None

        for button in self.group.buttons():
            buttonvalue = button.property("value")
            if (value is None and buttonvalue in self.nullvalues) or buttonvalue == str(value):
                button.setChecked(True)
                self.emitvaluechanged()
                return

    def value(self):
        button = self.group.checkedButton()
        if not button:
            return None

        value = button.property("value")

        if value in self.nullvalues:
            value = None
        return value
Exemple #7
0
class XNavigationEdit(XLineEdit):
    """ """
    navigationChanged = Signal()
    
    __designer_icon__ = projexui.resources.find('img/ui/navigate.png')
    
    def __init__( self, parent = None ):
        super(XNavigationEdit, self).__init__( parent )
        
        # define custom properties
        self._separator             = '/'
        self._partsEditingEnabled   = True
        self._originalText          = ''
        self._scrollWidget          = QScrollArea(self)
        self._partsWidget           = QWidget(self._scrollWidget)
        self._buttonGroup           = QButtonGroup(self)
        self._scrollAmount          = 0
        self._navigationModel       = None
        
        # create the completer tree
        palette = self.palette()
        palette.setColor(palette.Base, palette.color(palette.Window))
        palette.setColor(palette.Text, palette.color(palette.WindowText))
        
        bg      = palette.color(palette.Highlight)
        abg     = bg.darker(115)
        fg      = palette.color(palette.HighlightedText)
        sbg     = 'rgb(%s, %s, %s)' % (bg.red(), bg.green(), bg.blue())
        sabg    = 'rgb(%s, %s, %s)' % (abg.red(), abg.green(), abg.blue())
        sfg     = 'rgb(%s, %s, %s)' % (fg.red(), fg.green(), fg.blue())
        style   = 'QTreeView::item:hover { '\
                  '     color: %s;'\
                  '     background: qlineargradient(x1:0,'\
                  '                                 y1:0,'\
                  '                                 x2:0,'\
                  '                                 y2:1,'\
                  '                                 stop: 0 %s,'\
                  '                                 stop: 1 %s);'\
                  '}' % (sfg, sbg, sabg)
        
        self._completerTree = QTreeView(self)
        self._completerTree.setStyleSheet(style)
        self._completerTree.header().hide()
        self._completerTree.setFrameShape(QTreeView.Box)
        self._completerTree.setFrameShadow(QTreeView.Plain)
        self._completerTree.setPalette(palette)
        self._completerTree.setEditTriggers(QTreeView.NoEditTriggers)
        self._completerTree.setWindowFlags(Qt.Popup)
        self._completerTree.installEventFilter(self)
        self._completerTree.setRootIsDecorated(False)
        self._completerTree.setItemsExpandable(False)
        
        # create the editing widget
        layout = QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        layout.addStretch()
        
        self._scrollWidget.setFrameShape( QScrollArea.NoFrame )
        self._scrollWidget.setFocusPolicy(Qt.NoFocus)
        self._scrollWidget.setWidget(self._partsWidget)
        self._scrollWidget.setWidgetResizable(True)
        self._scrollWidget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._scrollWidget.setAlignment(Qt.AlignTop | Qt.AlignRight)
        self._scrollWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._scrollWidget.setContentsMargins(0, 0, 0, 0)
        self._scrollWidget.setViewportMargins(0, 0, 0, 0)
        self._scrollWidget.move(2, 2)
        
        self._partsWidget.setLayout(layout)
        self._partsWidget.setCursor(Qt.ArrowCursor)
        self._partsWidget.setAutoFillBackground(True)
        self._partsWidget.setFixedHeight(self.height() - 12)
        
        palette = self._partsWidget.palette()
        palette.setColor(palette.Background, palette.color(palette.Base))
        self._partsWidget.setPalette(palette)
        
        # create connections
        self._completerTree.clicked.connect( self.navigateToIndex )
        self._buttonGroup.buttonClicked.connect( self.handleButtonClick )
        self._scrollWidget.horizontalScrollBar().valueChanged.connect( 
                                                        self.scrollParts )
    
    def acceptEdit( self ):
        """
        Accepts the current text and rebuilds the parts widget.
        """
        
        if ( self._partsWidget.isVisible() ):
            return False
        
        use_completion = self.completer().popup().isVisible()
        completion     = self.completer().currentCompletion()
        
        self._completerTree.hide()
        self.completer().popup().hide()
        
        if ( use_completion ):
            self.setText(completion)
        else:
            self.rebuild()
            
        return True
    
    def cancelEdit( self ):
        """
        Rejects the current edit and shows the parts widget.
        """
        
        if ( self._partsWidget.isVisible() ):
            return False
            
        self._completerTree.hide()
        self.completer().popup().hide()
        
        self.setText(self._originalText)
        return True
    
    def currentItem( self ):
        """
        Returns the current navigation item from the current path.
        
        :return     <XNavigationItem> || None
        """
        model = self.navigationModel()
        if ( not model ):
            return None
        
        return model.itemByPath(self.text())
    
    def eventFilter( self, object, event ):
        """
        Filters the events for the inputed object through this edit.
        
        :param      object | <QObject>
                    event  | <QEvent>
        
        :return     <bool> | consumed
        """
        if ( event.type() == event.KeyPress ):
            if ( event.key() == Qt.Key_Escape ):
                self._completerTree.hide()
                self.completer().popup().hide()
                
                self.cancelEdit()
                
            elif ( event.key() in (Qt.Key_Return, Qt.Key_Enter) ):
                self.acceptEdit()
                return True
                
            elif ( event.key() == Qt.Key_Tab ):
                if ( self.completer().popup().isVisible() ):
                    text   = str(self.completer().currentCompletion())
                    super(XNavigationEdit, self).setText(text)
                    return True
                else:
                    self.acceptEdit()
                    return False
            
        elif ( event.type() == event.MouseButtonPress ):
            if ( not self._completerTree.rect().contains(event.pos()) ):
                self._completerTree.hide()
                self.completer().popup().hide()
                
                self.cancelEdit()
        
        return False
    
    def focusOutEvent( self, event ):
        """
        Overloads the focus out event to cancel editing when the widget loses
        focus.
        
        :param      event | <QFocusEvent>
        """
        super(XNavigationEdit, self).focusOutEvent(event)
        
        self.cancelEdit()
    
    def handleButtonClick( self, button ):
        """
        Handle the event when a user clicks on one of the part buttons.
        
        :param      button | <QToolButton>
        """
        path            = button.property('path')
        is_completer    = button.property('is_completer')
        
        # popup a completion menu
        if ( unwrapVariant(is_completer) ):
            model = self.navigationModel()
            if ( not model ):
                return
            
            sep  = self.separator()
            path = str(unwrapVariant(path))
            item = model.itemByPath(path, includeRoot = True)
            if ( not item ):
                return
            
            curr_path = str(self.text()).strip(self.separator())
            curr_path = curr_path.replace(path, '').strip(self.separator())
            
            child_name = ''
            if ( curr_path ):
                child_name = curr_path.split(self.separator())[0]
            
            index = model.indexFromItem(item)
            
            self._completerTree.move(QCursor.pos())
            self._completerTree.setRootIndex(index)
            self._completerTree.verticalScrollBar().setValue(0)
            
            if ( child_name ):
                child_item = None
                for i in range(item.rowCount()):
                    child = item.child(i)
                    if ( child.text() == child_name ):
                        child_item = child
                        break
                
                if ( child_item ):
                    child_index = model.indexFromItem(child_item)
                    self._completerTree.setCurrentIndex(child_index)
                    self._completerTree.scrollTo(child_index)
            
            self._completerTree.show()
            self._completerTree.setUpdatesEnabled(True)
        else:
            self.setText(unwrapVariant(path))
    
    def keyPressEvent( self, event ):
        """
        Overloads the key press event to listen for escape calls to cancel the
        parts editing.
        
        :param      event | <QKeyPressEvent>
        """
        if ( self.scrollWidget().isHidden() ):
            if ( event.key() == Qt.Key_Escape ):
                self.cancelEdit()
                return
                
            elif ( event.key() in (Qt.Key_Return, Qt.Key_Enter) ):
                self.acceptEdit()
                return
            
        elif ( event.key() == Qt.Key_A and 
               event.modifiers() == Qt.ControlModifier ):
            self.startEdit()
        
        super(XNavigationEdit, self).keyPressEvent(event)
    
    def mouseDoubleClickEvent( self, event ):
        """
        Overloads the system to enable editing when a user double clicks.
        
        :param      event | <QMouseEvent>
        """
        super(XNavigationEdit, self).mouseDoubleClickEvent(event)
        
        self.startEdit()
    
    def navigationModel( self ):
        """
        Returns the navigation model linked with this edit.
        
        :return     <XNavigationModel> || None
        """
        return self._navigationModel
    
    def navigateToIndex( self, index ):
        """
        Navigates to the inputed action's path.
        
        :param      action | <QAction>
        """
        self._completerTree.hide()
        item = self._navigationModel.itemFromIndex(index)
        self.setText(self._navigationModel.itemPath(item))
    
    def parts( self ):
        """
        Returns the parts that are used for this system.
        
        :return     [<str>, ..]
        """
        path = str(self.text()).strip(self.separator())
        if ( not path ):
            return []
        return path.split(self.separator())
    
    def partsWidget( self ):
        """
        Returns the widget that contains the parts system.
        
        :return     <QScrollArea>
        """
        return self._partsWidget
    
    def startEdit( self ):
        """
        Rebuilds the pathing based on the parts.
        """
        self._originalText = self.text()
        self.scrollWidget().hide()
        self.setFocus()
        self.selectAll()
    
    def rebuild( self ):
        """
        Rebuilds the parts widget with the latest text.
        """
        navitem = self.currentItem()
        if ( navitem ):
            navitem.initialize()
            
        self.setUpdatesEnabled(False)
        self.scrollWidget().show()
        self._originalText = ''
        
        partsw = self.partsWidget()
        for button in self._buttonGroup.buttons():
            self._buttonGroup.removeButton(button)
            button.close()
            button.setParent(None)
            button.deleteLater()
        
        # create the root button
        layout = partsw.layout()
        parts  = self.parts()
        
        button = QToolButton(partsw)
        button.setAutoRaise(True)
        button.setMaximumWidth(12)
        button.setArrowType(Qt.RightArrow)
        
        button.setProperty('path',          wrapVariant(''))
        button.setProperty('is_completer',  wrapVariant(True))
        last_button = button
            
        self._buttonGroup.addButton(button)
        layout.insertWidget(0, button)
        
        # check to see if we have a navigation model setup
        if ( self._navigationModel ):
            last_item = self._navigationModel.itemByPath(self.text())
            show_last =  last_item and last_item.rowCount() > 0
        else:
            show_last = False
        
        # load the navigation system
        count = len(parts)
        for i, part in enumerate(parts):
            path = self.separator().join(parts[:i+1])
            
            button = QToolButton(partsw)
            button.setAutoRaise(True)
            button.setText(part)
            
            if ( self._navigationModel ):
                item = self._navigationModel.itemByPath(path)
                if ( item ):
                    button.setIcon(item.icon())
                    button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
            
            button.setProperty('path',         wrapVariant(path))
            button.setProperty('is_completer', wrapVariant(False))
            
            self._buttonGroup.addButton(button)
            layout.insertWidget((i * 2) + 1, button)
            
            # determine if we should show the final button
            if ( show_last or i < (count - 1) ):
                button = QToolButton(partsw)
                button.setAutoRaise(True)
                button.setMaximumWidth(12)
                button.setArrowType(Qt.RightArrow)
                
                button.setProperty('path',          wrapVariant(path))
                button.setProperty('is_completer',  wrapVariant(True))
            
                self._buttonGroup.addButton(button)
                layout.insertWidget((i * 2) + 2, button)
                
                last_button = button
        
        if ( self.scrollWidget().width() < partsw.width() ):
            self.scrollParts(partsw.width() - self.scrollWidget().width())
            
        self.setUpdatesEnabled(True)
        self.navigationChanged.emit()
    
    def resizeEvent( self, event ):
        """
        Resizes the current widget and its parts widget.
        
        :param      event | <QResizeEvent>
        """
        super(XNavigationEdit, self).resizeEvent(event)
        
        w = self.width()
        h = self.height()
        
        self._scrollWidget.resize(w - 4, h - 4)
        
        if ( self._scrollWidget.width() < self._partsWidget.width() ):
           self.scrollParts( self._partsWidget.width() - self._scrollWidget.width() )
    
    def scrollParts( self, amount ):
        """
        Scrolls the parts to offset the scrolling amount.
        
        :param      amount | <int>
        """
        change = self._scrollAmount - amount
        self._partsWidget.scroll(change, 0)
        self._scrollAmount = amount
    
    def scrollWidget( self ):
        """
        Returns the scrolling widget.
        
        :return     <QScrollArea>
        """
        return self._scrollWidget
    
    def separator( self ):
        """
        Returns the separation character that is used for this edit.
        
        :return     <str>
        """
        return self._separator
    
    def setTopLevelItems( self, items ):
        """
        Initializes the navigation system to start with the inputed root \
        item.
        
        :param      item | <XNavigationItem>
        """
        if ( not self._navigationModel ):
            self.setNavigationModel(XNavigationModel(self))
        
        self._navigationModel.setTopLevelItems(items)
    
    def setNavigationModel( self, model ):
        """
        Sets the navigation model for this edit.
        
        :param      model | <XNavigationModel>
        """
        self._navigationModel = model
        self._completerTree.setModel(model)
        
        if ( model ):
            model.setSeparator(self.separator())
            completer = XNavigationCompleter(model, self)
            self.setCompleter(completer)
            completer.popup().installEventFilter(self)
        else:
            self.setCompleter(None)
        
        self.rebuild()
    
    def setParts( self, parts ):
        """
        Sets the path for this edit widget by providing the parts to the path.
        
        :param      parts | [<str>, ..]
        """
        self.setText(self.separator().join(map(str, parts)))
    
    def setSeparator( self, separator ):
        """
        Sets the separator to the inputed character.
        
        :param      separator | <str>
        """
        self._separator = separator
        if ( self._navigationModel ):
            self._navigationModel.setSeparator(separator)
        self.rebuild()
    
    def setText( self, text ):
        """
        Sets the text for this edit to the inputed text.
        
        :param      text | <str>
        """
        super(XNavigationEdit, self).setText(text)
        
        self.scrollWidget().show()
        if ( text == '' or self._originalText != text ):
            self.rebuild()
class FilteringModule(PreprocessorModule):
    DEFAULT_SETTINGS = {
        'is_enabled': True,
        'methods': [True, False, False],
        'recent_sw_files': [],
        'min_df': None,
        'max_df': None,
    }

    English, Custom, DocumentFrequency = 0, 1, 2
    filtering_values = {
        English: 'english',
        Custom: [],
        DocumentFrequency: (None, None),
    }
    filter_names = {
        English: 'English stop words',
        Custom: 'Custom stop words',
        DocumentFrequency: 'Filter by token frequency',
    }

    filtering_methods = [True, False, False]

    dlgFormats = 'Only text files (*.txt)'
    recent_sw_files = []

    def __init__(self, data):
        data = data or self.DEFAULT_SETTINGS
        PreprocessorModule.__init__(
                self, 'Token filtering', True,
                data.get('is_enabled')
        )

        self.group = QButtonGroup(self, exclusive=False)

        # --- English ---
        cb = QCheckBox(self, text=self.filter_names[self.English])
        self.add_to_content_area(cb)
        self.group.addButton(cb, self.English)

        # --- Custom ---
        cb = QCheckBox(self, text=self.filter_names[self.Custom])
        self.add_to_content_area(cb)
        self.group.addButton(cb, self.Custom)

        # File browser.
        file_browser_layout = QHBoxLayout()
        file_browser_layout.setContentsMargins(20, 0, 0, 0)
        self.sw_file_combo = QComboBox()
        self.sw_file_combo.setMinimumWidth(200)
        file_browser_layout.addWidget(self.sw_file_combo)
        self.sw_file_combo.activated[int].connect(self.select_file)

        self.browse_button = QPushButton(self)
        self.browse_button.clicked.connect(self.browse_file)
        self.browse_button.setIcon(self.style()
                                   .standardIcon(QStyle.SP_DirOpenIcon))
        self.browse_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        file_browser_layout.addWidget(self.browse_button)

        # Reload button
        self.reload_button = QPushButton(self)
        self.reload_button.clicked.connect(self.on_reload_button_clicked)
        self.reload_button.setIcon(self.style()
                                   .standardIcon(QStyle.SP_BrowserReload))
        self.reload_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        file_browser_layout.addWidget(self.reload_button)

        self.add_layout_to_content_area(file_browser_layout)

        # --- DF ---
        df_info_text = """
        Remove all tokens that appear in less than 'min-df' documents.
        Remove all tokens that appear in more than 'max-df' documents.
        Values can be either integers or floats (ratio of documents).
        """
        cb = QCheckBox(self, text=self.filter_names[self.DocumentFrequency])
        self.add_to_content_area(cb)
        self.group.addButton(cb, self.DocumentFrequency)
        df_info_text = QLabel(df_info_text)
        df_info_text.setContentsMargins(0,0,0,0)
        df_info_text.setStyleSheet("""
        font-size: 11px;
        font-style: italic;
        """)
        self.add_to_content_area(df_info_text)
        # Min/Max-Df setter.
        df_setter_layout = QHBoxLayout()
        df_setter_layout.setContentsMargins(20, 0, 0, 0)
        self.min_df_input = QLineEdit()
        self.min_df_input.textChanged.connect(self.update_df_parameters)
        self.max_df_input = QLineEdit()
        self.max_df_input.textChanged.connect(self.update_df_parameters)
        df_setter_layout.addWidget(QLabel('Min-df:'))
        df_setter_layout.addWidget(self.min_df_input)
        df_setter_layout.addWidget(QLabel('Max-df:'))
        df_setter_layout.addWidget(self.max_df_input)

        self.add_layout_to_content_area(df_setter_layout)
        self.group.buttonClicked.connect(self.group_button_clicked)

        # Restore the widget to its previous state.
        self.restore_data(data)

    def str_to_num(self, s):
        if not s:
            return None

        try:
            return int(s)
        except ValueError:
            pass  # Not an int. Continue.
        try:
            return float(s)
        except ValueError:  # Not a float either.
            self.send_message('Input "{}" cannot be cast into a number.'
                              .format(s))
            return None

    def send_message(self, message):
        # Sends a message with the "message" signal, to the main widget.
        self.error_signal.emit(message)

    # --- File selection.
    def select_file(self, n):
        if n < len(self.recent_sw_files):
            name = self.recent_sw_files[n]
            del self.recent_sw_files[n]
            self.recent_sw_files.insert(0, name)

        if len(self.recent_sw_files) > 0:
            self.set_file_list()
            self.open_file(self.recent_sw_files[0])

    def set_file_list(self):
        self.sw_file_combo.clear()
        if not self.recent_sw_files:
            self.sw_file_combo.addItem('(none)')
        else:
            for file in self.recent_sw_files:
                self.sw_file_combo.addItem(os.path.split(file)[1])

    def browse_file(self):
        # Opens the file browser, starting at the home directory.
        start_file = os.path.expanduser('~/')
        # Get the file path from the browser window.
        path = QFileDialog.getOpenFileName(self, 'Open a stop words source',
                                           start_file, self.dlgFormats)
        if not path:
            return

        if path in self.recent_sw_files:
            self.recent_sw_files.remove(path)
        self.recent_sw_files.insert(0, path)
        self.set_file_list()
        self.open_file(path)

    def update_df_parameters(self):
        min_df = None if not self.min_df_input.text() else self.min_df_input.text()
        max_df = None if not self.max_df_input.text() else self.max_df_input.text()
        self.filtering_values[self.DocumentFrequency] = (min_df, max_df)
        self.notify_on_change()

    def open_file(self, path):
        try:
            with open(path) as f:  # Read most recent.
                self.filtering_values[self.Custom] = [sw.strip() for sw in
                                                      f.read().splitlines()]
                self.notify_on_change()
        except Exception:  # Raise an exception otherwise.
            self.send_message('Could not open "{}".'
                              .format(path))

    def on_reload_button_clicked(self):
        if self.recent_sw_files:
            self.select_file(0)
    # END File selection.

    def group_button_clicked(self):
        self.filtering_methods = [ch_box.isChecked() for ch_box in
                                  self.group.buttons()]

        self.enable_choice_settings()

        # Emit the signal.
        self.notify_on_change()

    def enable_choice_settings(self):
        self.sw_file_combo.setEnabled(self.filtering_methods[1])
        self.browse_button.setEnabled(self.filtering_methods[1])
        self.reload_button.setEnabled(self.filtering_methods[1])

        self.min_df_input.setEnabled(self.filtering_methods[2])
        self.max_df_input.setEnabled(self.filtering_methods[2])

    def get_pp_setting(self):
        flag_english = self.filtering_methods[0]
        flag_custom = self.filtering_methods[1]
        flag_df = self.filtering_methods[2]
        if flag_english and flag_custom:  # Use custom.
            stop_words = {
                'stop_words': stopwords.words('english') +
                              self.filtering_values[self.Custom]
            }
        elif flag_english and not flag_custom:
            stop_words = {
                'stop_words': 'english'
            }
        elif flag_custom:
            stop_words = {
                'stop_words': self.filtering_values[self.Custom]
            }
        else:
            stop_words = {}

        if flag_df:
            stop_words.update({
                'min_df': self.str_to_num(self.min_df_input.text()),
                'max_df': self.str_to_num(self.max_df_input.text()),
            })
        return stop_words

    def restore_data(self, data):
        self.recent_sw_files = data.get('recent_sw_files')
        self.min_df_input.setText(data.get('min_df'))
        self.max_df_input.setText(data.get('max_df'))
        self.filtering_methods = data.get('methods')

        for flag, ch_box in zip(self.filtering_methods, self.group.buttons()):
            ch_box.setChecked(flag)

        self.enable_choice_settings()  # Enable the settings if set.
        self.set_file_list()  # Fill the combo box with the recent sw files.
        self.select_file(0)  # Select the first file.

    def export_data(self):
        return {
            'is_enabled': self.enabled,
            'methods': self.filtering_methods,
            'recent_sw_files': self.recent_sw_files,
            'min_df': self.min_df_input.text(),
            'max_df': self.max_df_input.text(),
        }
Exemple #9
0
class PeriodicTableWidget(QWidget):
    selectionChanged = pyqtSignal()
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        # Widgets, layouts and signals
        self._group = QButtonGroup()
        layout = QGridLayout()
        layout.setSpacing(0)
        ## Element
        for z, position in _ELEMENT_POSITIONS.items():
            widget = ElementPushButton(z)
            widget.setStyle(QStyleFactory.create("windows"))
            widget.setCheckable(True)
            layout.addWidget(widget, *position)
            self._group.addButton(widget, z)
        ## Labels
        layout.addWidget(QLabel(''), 7, 0) # Dummy
        layout.addWidget(QLabel('*'), 5, 2, Qt.AlignRight)
        layout.addWidget(QLabel('*'), 8, 2, Qt.AlignRight)
        layout.addWidget(QLabel('**'), 6, 2, Qt.AlignRight)
        layout.addWidget(QLabel('**'), 9, 2, Qt.AlignRight)

        for row in [0, 1, 2, 3, 4, 5, 6, 8, 9]:
            layout.setRowStretch(row, 1)

        self.setLayout(layout)

        # Signals
        self._group.buttonClicked.connect(self.selectionChanged)

        # Default
        self.setColorFunction(_category_color_function)

    def setColorFunction(self, func):
        if not callable(func):
            raise ValueError('Not a function')
        self._color_function = func

        # Redraw
        for widget in self._group.buttons():
            z = self._group.id(widget)
            bcolor = func(z)
            fcolor = 'white' if _calculate_brightness(bcolor) < 128 else 'black'
            sheet = 'background-color: %s; color: %s' % (bcolor.name(), fcolor)
            widget.setStyleSheet(sheet)

    def colorFunction(self):
        return self._color_function

    def setSelection(self, selection):
        self.selectionChanged.emit()
#
    def selection(self):
        selection = None
        for widget in self._group.buttons():
            if widget.isChecked():
                selection = self._group.id(widget)
        if selection != None:
            return [selection, get_symbol(selection)]
        else:
            return None
Exemple #10
0
class DefaultSelectParameterWidget(SelectParameterWidget):
    """Widget class for Default Select Parameter."""
    def __init__(self, parameter, parent=None):
        """Constructor

        :param parameter: A DefaultSelectParameter object.
        :type parameter: DefaultSelectParameter
        """
        super(DefaultSelectParameterWidget, self).__init__(parameter, parent)

        self.default_layout = QHBoxLayout()
        self.radio_button_layout = QHBoxLayout()
        self.radio_button_widget = QWidget()

        self.default_label = QLabel(tr('Default'))

        # Create radio button group
        self.default_input_button_group = QButtonGroup()

        # Define string enabler for radio button
        self.radio_button_enabler = self.input.itemData(0, Qt.UserRole)

        for i in range(len(self._parameter.default_labels)):
            if '%s' in self._parameter.default_labels[i]:
                label = (self._parameter.default_labels[i] %
                         self._parameter.default_values[i])
            else:
                label = self._parameter.default_labels[i]

            radio_button = QRadioButton(label)
            self.radio_button_layout.addWidget(radio_button)
            self.default_input_button_group.addButton(radio_button, i)
            if self._parameter.default_value == \
                    self._parameter.default_values[i]:
                radio_button.setChecked(True)

        # Create double spin box for custom value
        self.custom_value = QDoubleSpinBox()
        if self._parameter.default_values[-1]:
            self.custom_value.setValue(self._parameter.default_values[-1])
        has_min = False
        if self._parameter.minimum is not None:
            has_min = True
            self.custom_value.setMinimum(self._parameter.minimum)
        has_max = False
        if self._parameter.maximum is not None:
            has_max = True
            self.custom_value.setMaximum(self._parameter.maximum)
        if has_min and has_max:
            step = (self._parameter.maximum - self._parameter.minimum) / 100.0
            self.custom_value.setSingleStep(step)
        self.radio_button_layout.addWidget(self.custom_value)

        self.toggle_custom_value()

        # Reset the layout
        self.input_layout.setParent(None)
        self.help_layout.setParent(None)

        self.label.setParent(None)
        self.inner_input_layout.setParent(None)

        self.input_layout = QGridLayout()
        self.input_layout.setSpacing(0)

        self.input_layout.addWidget(self.label, 0, 0)
        self.input_layout.addLayout(self.inner_input_layout, 0, 1)
        self.input_layout.addWidget(self.default_label, 1, 0)
        self.input_layout.addLayout(self.radio_button_layout, 1, 1)

        self.main_layout.addLayout(self.input_layout)
        self.main_layout.addLayout(self.help_layout)

        # check every added combobox, it could have been toggled by
        # the existing keyword
        self.toggle_input()

        # Connect
        # noinspection PyUnresolvedReferences
        self.input.currentIndexChanged.connect(self.toggle_input)
        self.default_input_button_group.buttonClicked.connect(
            self.toggle_custom_value)

    def raise_invalid_type_exception(self):
        message = 'Expecting element type of %s' % (
            self._parameter.element_type.__name__)
        err = ValueError(message)
        return err

    def get_parameter(self):
        """Obtain list parameter object from the current widget state.

        :returns: A DefaultSelectParameter from the current state of widget.
        """
        current_index = self.input.currentIndex()
        selected_value = self.input.itemData(current_index, Qt.UserRole)
        if hasattr(selected_value, 'toPyObject'):
            selected_value = selected_value.toPyObject()

        try:
            self._parameter.value = selected_value
        except ValueError:
            err = self.raise_invalid_type_exception()
            raise err

        radio_button_checked_id = self.default_input_button_group.checkedId()
        # No radio button checked, then default value = None
        if radio_button_checked_id == -1:
            self._parameter.default = None
        # The last radio button (custom) is checked, get the value from the
        # line edit
        elif (radio_button_checked_id == len(self._parameter.default_values) -
              1):
            self._parameter.default_values[radio_button_checked_id] \
                = self.custom_value.value()
            self._parameter.default = self.custom_value.value()
        else:
            self._parameter.default = self._parameter.default_values[
                radio_button_checked_id]

        return self._parameter

    def set_default(self, default):
        """Set default value by item's string.

        :param default: The default.
        :type default: str, int

        :returns: True if success, else False.
        :rtype: bool
        """
        # Find index of choice
        try:
            default_index = self._parameter.default_values.index(default)
            self.default_input_button_group.button(default_index).setChecked(
                True)
        except ValueError:
            last_index = len(self._parameter.default_values) - 1
            self.default_input_button_group.button(last_index).setChecked(True)
            self.custom_value.setValue(default)

        self.toggle_custom_value()

    def toggle_custom_value(self):
        radio_button_checked_id = self.default_input_button_group.checkedId()
        if (radio_button_checked_id == len(self._parameter.default_values) -
                1):
            self.custom_value.setDisabled(False)
        else:
            self.custom_value.setDisabled(True)

    def toggle_input(self):
        """Change behaviour of radio button based on input."""
        current_index = self.input.currentIndex()
        # If current input is not a radio button enabler, disable radio button.
        if self.input.itemData(current_index,
                               Qt.UserRole) != (self.radio_button_enabler):
            self.disable_radio_button()
        # Otherwise, enable radio button.
        else:
            self.enable_radio_button()

    def set_selected_radio_button(self):
        """Set selected radio button to 'Do not report'."""
        dont_use_button = self.default_input_button_group.button(
            len(self._parameter.default_values) - 2)
        dont_use_button.setChecked(True)

    def disable_radio_button(self):
        """Disable radio button group and custom value input area."""
        checked = self.default_input_button_group.checkedButton()
        if checked:
            self.default_input_button_group.setExclusive(False)
            checked.setChecked(False)
            self.default_input_button_group.setExclusive(True)
        for button in self.default_input_button_group.buttons():
            button.setDisabled(True)
        self.custom_value.setDisabled(True)

    def enable_radio_button(self):
        """Enable radio button and custom value input area then set selected
        radio button to 'Do not report'.
        """
        for button in self.default_input_button_group.buttons():
            button.setEnabled(True)
        self.set_selected_radio_button()
        self.custom_value.setEnabled(True)
Exemple #11
0
class OptionWidget(EditorWidget):
    widgettype = 'Option Row'
    def __init__(self, *args):
        super(OptionWidget, self).__init__(*args)
        self._bindvalue = None
        self.group = QButtonGroup()
        self.group.setExclusive(True)
        self.group.buttonClicked.connect(self.emitvaluechanged)

    def createWidget(self, parent):
        widget = QWidget(parent)
        widget.setLayout(QHBoxLayout())
        widget.layout().setContentsMargins(0,0,0,0)
        return widget

    def _buildfromlist(self, listconfig):
        items = listconfig['items']
        for item in items:
            parts = item.split(';')
            data = parts[0]
            try:
                desc = parts[1]
            except IndexError:
                desc = data

            try:
                path = parts[2]
                if path.endswith("_icon"):
                    icon = QIcon(":/icons/{}".format(path))
                else:
                    icon = QIcon(path)
            except:
                icon = QIcon()


            button = QPushButton()
            button.setCheckable(True)
            button.setText(desc)
            button.setProperty("value", data)
            button.setIcon(icon)
            button.setIconSize(QSize(24,24))
            self.widget.layout().addWidget(button)
            self.group.addButton(button)

    def initWidget(self, widget):
        pass

    def updatefromconfig(self):
        super(OptionWidget, self).updatefromconfig()
        listconfig = self.config['list']
        self._buildfromlist(listconfig)

        super(OptionWidget, self).endupdatefromconfig()

    def validate(self, *args):
        button = self.group.checkedButton()
        if button:
            self.raisevalidationupdate(True)
        else:
            self.raisevalidationupdate(False)
        self.emitvaluechanged()

    def setvalue(self, value):
        for button in self.group.buttons():
            if button.property("value") == value:
                button.setChecked(True)
                return

    def value(self):
        button = self.group.checkedButton()
        if not button:
            return None
        return button.property("value")
class DBDatabasesWidget(QWidget):
    """Displays a list of Databases"""

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.debug = False
        
        self.db = None
        
        self.setWindowTitle("Databases")
        #s#elf.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)

        
        self.mainLayout = QVBoxLayout()
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.setSpacing(0)
        self.setLayout(self.mainLayout)

        #=============================================
        ## Top Toolbar
        topBar = QToolBar()
        topBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.mainLayout.addWidget(topBar)
        
        ## Add the action buttons
        topBar.addAction(Ico.icon(Ico.ServerAdd), "Add", self.on_server_add)
        self.actionServerEdit = topBar.addAction(Ico.icon(Ico.ServerEdit), "Edit", self.on_server_edit)
        self.actionServerDelete = topBar.addAction(Ico.icon(Ico.ServerDelete), "Delete", self.on_server_delete)
        
        #=============================================
        ## Tree
        self.tree = QTreeWidget()
        self.mainLayout.addWidget(self.tree)
        self.tree.setHeaderLabels(["Server", "User", ""])
        self.tree.setUniformRowHeights(True)
        self.tree.setRootIsDecorated(False)
        self.tree.setColumnWidth(C.widget, 20)
        
        
        self.connect( self.tree, SIGNAL( 'itemSelectionChanged()' ), self.on_tree_selection_changed )
        self.connect( self.tree, SIGNAL( 'itemDoubleClicked (QTreeWidgetItem *,int)' ), self.on_tree_double_clicked )
    
        self.buttGroup = QButtonGroup(self)
        self.connect(self.buttGroup, SIGNAL("buttonClicked(QAbstractButton*)"), self.on_open_server)
    
        self.on_tree_selection_changed()
    
    
        self.load_servers()
        
    #=======================================
    ##== Tree Events
    def on_tree_selection_changed(self):
        
        disabled = self.tree.selectionModel().hasSelection() == False
        self.actionServerEdit.setDisabled(disabled)
        self.actionServerDelete.setDisabled(disabled)
        
    def on_tree_double_clicked(self):
        self.actionServerEdit.trigger()


    
    #=======================================
    ## Server Actions
    def on_server_add(self):
        self.show_server_dialog(None)
        
    def on_server_edit(self):
        item = self.tree.currentItem()
        if item == None:
            return
        server = str(item.text(C.server))
        self.show_server_dialog(server)
    
    def show_server_dialog(self, server=None):
        d = DBServerDialog.DBServerDialog(self, server)
        if d.exec_():
            self.load_servers()
       
       
    def on_open_server(self, butt):
        self.emit(SIGNAL("open_server"), butt.property("server").toString())
              
             
    
    def load_servers(self):
        """Load servers from :py:meth:`pyqtdb.XSettings.XSettings.get_servers` """
        
        self.tree.clear()
        
        for butt in self.buttGroup.buttons():
            self.buttGroup.removeButton(butt)
        
        for srv in G.settings.get_servers_list():
            
            item = QTreeWidgetItem()
            item.setText(C.server, srv['server'])
            item.setText(C.user, srv['user'])
            self.tree.addTopLevelItem(item)
            
            butt = QToolButton()
            butt.setIcon(Ico.icon(Ico.Connect))
            butt.setProperty("server", srv['server'])
            self.tree.setItemWidget(item, C.widget, butt)
            self.buttGroup.addButton(butt)
        
        
    def on_server_delete(self):
        item = self.tree.currentItem()
        if item == None:
            return
        srv = str(item.text(C.server))
        G.settings.delete_server(srv)
        self.load_servers()
        
Exemple #13
0
class OptionWidget(EditorWidget):
    widgettype = 'Option Row'

    def __init__(self, *args):
        super(OptionWidget, self).__init__(*args)
        self._bindvalue = None
        self.group = QButtonGroup()
        self.group.setExclusive(True)
        self.group.buttonClicked.connect(self.emitvaluechanged)

    def createWidget(self, parent):
        widget = QWidget(parent)
        widget.setLayout(QHBoxLayout())
        widget.layout().setContentsMargins(0, 0, 0, 0)
        return widget

    def _buildfromlist(self, listconfig):
        items = listconfig['items']
        for item in items:
            parts = item.split(';')
            data = parts[0]
            try:
                desc = parts[1]
            except IndexError:
                desc = data

            try:
                path = parts[2]
                if path.endswith("_icon"):
                    icon = QIcon(":/icons/{}".format(path))
                else:
                    icon = QIcon(path)
            except:
                icon = QIcon()

            button = QPushButton()
            button.setCheckable(True)
            button.setText(desc)
            button.setProperty("value", data)
            button.setIcon(icon)
            button.setIconSize(QSize(24, 24))
            self.widget.layout().addWidget(button)
            self.group.addButton(button)

    def initWidget(self, widget):
        pass

    def updatefromconfig(self):
        super(OptionWidget, self).updatefromconfig()
        listconfig = self.config['list']
        self._buildfromlist(listconfig)

        super(OptionWidget, self).endupdatefromconfig()

    def validate(self, *args):
        button = self.group.checkedButton()
        if button:
            return True

        return False

    def setvalue(self, value):
        for button in self.group.buttons():
            if button.property("value") == str(value):
                button.setChecked(True)
                return

    def value(self):
        button = self.group.checkedButton()
        if not button:
            return None
        return button.property("value")
Exemple #14
0
class DBServersWidget(QWidget):
    """Displays a list of servers"""

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.debug = False
        
        self.connections = {}
        
        self.setWindowTitle("Servers")
        #s#elf.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)

        
        self.mainLayout = QVBoxLayout()
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.setSpacing(0)
        self.setLayout(self.mainLayout)

        #=============================================
        ## Top Toolbar
        topBar = QToolBar()
        topBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.mainLayout.addWidget(topBar)
        
        ## Add the action buttons
        topBar.addAction(Ico.icon(Ico.ServerAdd), "Add", self.on_server_add)
        self.actionServerEdit = topBar.addAction(Ico.icon(Ico.ServerEdit), "Edit", self.on_server_edit)
        self.actionServerDelete = topBar.addAction(Ico.icon(Ico.ServerDelete), "Delete", self.on_server_delete)
        
        #=============================================
        ## Tree
        self.tree = QTreeWidget()
        self.mainLayout.addWidget(self.tree)
        self.tree.setUniformRowHeights(True)
        self.tree.setRootIsDecorated(True)
        
        
        self.tree.setHeaderLabels(["Server", "Butt"]) # set header, but hide anyway
        self.tree.header().hide()
        self.tree.header().setResizeMode(C.node, QHeaderView.Stretch)
        self.tree.setColumnWidth(C.butt, 20)
        
        
        self.connect( self.tree, SIGNAL( 'itemSelectionChanged()' ), self.on_tree_selection_changed )
        self.connect( self.tree, SIGNAL( 'itemDoubleClicked (QTreeWidgetItem *,int)' ), self.on_tree_double_clicked )
    
        self.buttGroup = QButtonGroup(self)
        self.connect(self.buttGroup, SIGNAL("buttonClicked(QAbstractButton*)"), self.on_open_server)
    
        self.on_tree_selection_changed()
    
    
        self.load_servers()
        
    #=======================================
    ##== Tree Events
    def on_tree_selection_changed(self):
        
        disabled = self.tree.selectionModel().hasSelection() == False
        self.actionServerEdit.setDisabled(disabled)
        self.actionServerDelete.setDisabled(disabled)
        
    def on_tree_double_clicked(self):
        self.actionServerEdit.trigger()


    
    #=======================================
    ## Server Actions
    def on_server_add(self):
        self.show_server_dialog(None)
        
    def on_server_edit(self):
        item = self.tree.currentItem()
        if item == None:
            return
        server = str(item.text(C.server))
        self.show_server_dialog(server)
    
    def show_server_dialog(self, server=None):
        d = DBServerDialog.DBServerDialog(self, server)
        if d.exec_():
            self.load_servers()
    

            
    
    def load_servers(self):
        """Load servers from :py:meth:`pyqtdb.XSettings.XSettings.get_servers` """
        
        self.tree.clear()
        
        for butt in self.buttGroup.buttons():
            self.buttGroup.removeButton(butt)
        
        for srv in G.settings.get_servers_list():
            
            item = QTreeWidgetItem()
            item.setText(C.node, srv['server'])
            #item.setText(C.user, srv['user'])
            self.tree.addTopLevelItem(item)
            
            butt = QToolButton()
            butt.setIcon(Ico.icon(Ico.Connect))
            butt.setProperty("server", srv['server'])
            self.tree.setItemWidget(item, C.butt, butt)
            self.buttGroup.addButton(butt)
        
        
    def on_server_delete(self):
        item = self.tree.currentItem()
        if item == None:
            return
        srv = str(item.text(C.server))
        G.settings.delete_server(srv)
        self.load_servers()
        
        
    def on_open_server(self, butt):
        
        # self.emit(SIGNAL("open_server"), butt.property("server").toString())
        srv_ki = str(butt.property("server").toString())
        server = G.settings.get_server(srv_ki)
        db = QSqlDatabase.addDatabase("QMYSQL", srv_ki)
        db.setHostName(server['server'])
        db.setUserName(server['user'])
        db.setPassword(server['passwd'])
        
        ok = db.open()
        if ok:
            #self.connections[srv_ki] = 
            self.load_databases(srv_ki)
            print "open", ok
            
            
    def load_databases(self, srv_ki):
        """Load databases into tree node for server;  executes 'show databases;' or aslike """
        
        sql = "show databases;"
        query = QSqlQuery(QSqlDatabase.database(srv_ki))
        ok = query.exec_(sql)
        print ok, sql, query.result()
        
        # Get the parent node, ie the server node
        pItem = self.tree.findItems(srv_ki, Qt.MatchExactly, C.node)[0]
        
        ## Assumed value(0) is the table.. we need the defs (ie mysql case)
        while query.next():
            table_name =  query.value(0).toString()
            nuItem = QTreeWidgetItem(pItem)
            nuItem.setText(C.node, table_name)
            #print table_name
            
            
        self.tree.setItemExpanded(pItem, True)
        
        
        
            
class CategoriesTab(QWidget):
    """ 
    Widget for displaying the categories tab in the SettingsDialog. 
    This is embedded into the SettingsDialog. 
    The user can add or remove a category using several options. 
    For some reason, PyQt does not recognize QButtonGroup objects, hence they
    need to be defined explicitely. 
    Also, a reference to FinanceagerWindow is stored as private attribute
    self.__parent because later referencing does not work otherwise.
    """
    def __init__(self, parent=None):
        super(CategoriesTab, self).__init__(parent)
        loadUi(__file__, self)
        self.__parent = parent

        self.removeFromMonthButtons = QButtonGroup()
        self.removeFromMonthButtons.addButton(self.removeAllMonthsButton)
        self.removeFromMonthButtons.addButton(
            self.removeAllMonthsFromNowButton)
        self.removeFromMonthButtons.addButton(self.removeCurrentMonthButton)
        self.addToMonthButtons = QButtonGroup()
        self.addToMonthButtons.addButton(self.addAllMonthsButton)
        self.addToMonthButtons.addButton(self.addAllMonthsFromNowButton)
        self.addToMonthButtons.addButton(self.addCurrentMonthButton)
        self.expAndRecButtons = QButtonGroup()
        self.expAndRecButtons.addButton(self.expendituresButton)
        self.expAndRecButtons.addButton(self.receiptsButton)
        self.removeCategoryCombo.addItems(self.categoriesStringList())
        # CONNECTIONS
        self.addCategoryGroup.clicked.connect(
            self.newCategoryLineEdit.setFocus)

    def categoriesStringList(self):
        """
        Returns a sorted list of all the categories that occur in the parentwidget's 
        (== FinanceagerWindow's) tabs.
        Used for both populating the removeCategoryCombo and preventing the
        user from adding an already existing category. The latter is important
        in order to avoid ambiguities when removing a category. 

        :return     list(str)
        """
        categories = set()
        tabWidget = self.__parent.monthsTabWidget
        for m in range(12):
            monthTab = tabWidget.widget(m)
            categories = categories.union(monthTab.categoriesStringList())
        categories = list(categories)
        categories.sort()
        return categories

    def checkForUniqueCategory(self, name):
        """
        Called from updateChangesToApply() to verify that the given category
        name is unique. Pops up a warning and resets newCategoryLineEdit if not. 

        :param      name | str 
        :return     uniqueCategory | bool 
        """
        #FIXME this also prevents adding a category that exists in any other month!
        if name in self.categoriesStringList():
            QMessageBox.warning(
                self.__parent, 'Name conflict',
                'This category name already exists. Please enter a unique name.'
            )
            self.newCategoryLineEdit.setText('')
            self.newCategoryLineEdit.setFocus()
            return False
        else:
            return True

    def updateChangesToApply(self, changes):
        """
        Checks for checked GroupBoxes. 
        Creates a tuple consisting of a function string and a tuple that contains 
        name, typ and option. Those three are fetched from the tab's widgets. 
        function:   'addCategory' | 'removeCategory' 
        name:       new category name | category to delete 
        option:     0 (all months) | 1 (all months from now) | 2 (current month)
        typ:        0 (expenditure) | 1 (receipt)
        The tuple is eventually evaluated by SettingsDialog.applyChanges() 
        if the dialog is not cancelled.

        :param      changes | set 
        """
        if self.addCategoryGroup.isChecked():
            name = unicode(self.newCategoryLineEdit.text()).strip()
            if len(name):
                if self.checkForUniqueCategory(name):
                    typ = self.expAndRecButtons.buttons().index(
                        self.expAndRecButtons.checkedButton())
                    option = self.addToMonthButtons.buttons().index(
                        self.addToMonthButtons.checkedButton())
                    changes.add(('addCategory', (name, typ, option)))
        if self.removeCategoryGroup.isChecked():
            name = unicode(self.removeCategoryCombo.currentText())
            option = self.removeFromMonthButtons.buttons().index(
                self.removeFromMonthButtons.checkedButton())
            changes.add(('removeCategory', (name, option)))
Exemple #16
0
    def __init__(self):
        # Inicializo el parent y audio module
        super(EGPSWindow, self).__init__()
        self.audio_mod = AudioModule(OUTPUT_FILE_PATH)

        # Titulo, tamano y tamano fijo (no resize)
        win_height = 130 + len(TRANSFER_FUNCTIONS) * 40
        self.setWindowTitle("EGPS-1")
        self.setGeometry(70, 70, 600, win_height)
        self.setFixedSize(600, win_height)

        # Funcion y lista de parametros para la creacion de las labels
        labels_func = self.create_label
        nm_px_py_labels = [("Transductor de entrada", 10, 105),
                           ("Grabacion", 400, 120), ("Salida", 400, 330),
                           ("Archivo de entrada", 10, 10),
                           ("Transductor de salida", 200, 105),
                           ("Entrada a procesar", 400, 230)]

        # Funcion y lista de parametros para la creacion de radiobuttons
        in_bq = QButtonGroup(self)
        out_bq = QButtonGroup(self)
        process_bq = QButtonGroup(self)
        radio_buttons_func = self.create_radio_button
        nm_px_py_cb_radio_buttons = [
            ("Archivo de entrada", 405, 255, PROCESS_GROUP, process_bq),
            ("Grabacion", 405, 280, PROCESS_GROUP, process_bq)
        ]

        #Creacion de los radio buttons para el grupo de transductores de entrada y de salida
        for index, transfer_function in enumerate(TRANSFER_FUNCTIONS.keys()):
            nm_px_py_cb_radio_buttons.append(
                (transfer_function, 30, 125 + index * 40, INPUT_GROUP, in_bq))
            nm_px_py_cb_radio_buttons.append(
                (transfer_function, 220, 125 + index * 40, OUTPUT_GROUP,
                 out_bq))

        # Funcion y lista de parametros para la creacion de los pushbuttons
        push_buttons_func = self.define_push_button
        nm_px_py_callb_push_buttons = [
            ("", 55, 70, self.audio_mod.stop_file, STOP_IMAGE_PATH, True),
            ("Elegir archivo", 15, 35, self.select_file),
            ("", 15, 70, self.audio_mod.play_file, PLAY_IMAGE_PATH, True),
            ("", 405, 145, self.audio_mod.rec, REC_IMAGE_PATH, True),
            ("", 445, 145, self.audio_mod.stop_rec, STOP_IMAGE_PATH, True),
            ("", 485, 145, self.audio_mod.play_rec, PLAY_IMAGE_PATH, True),
            ("", 525, 145, self.rec_file_save, SAVE_IMAGE_PATH, True),
            ("", 405, 355, self.out_file_play, PLAY_IMAGE_PATH, True),
            ("", 445, 355, self.audio_mod.stop_out, STOP_IMAGE_PATH, True),
            ("", 485, 355, self.out_file_save, SAVE_IMAGE_PATH, True)
        ]

        # Se define una lista de tuplas con (constructor, lista de parametros del constructor) para los diferentes
        # tipos de elementos
        elements_constructors = [
            (labels_func, nm_px_py_labels),
            (radio_buttons_func, nm_px_py_cb_radio_buttons),
            (push_buttons_func, nm_px_py_callb_push_buttons)
        ]

        for const, params_list in elements_constructors:
            for params in params_list:
                const(*params)

        # Se eligen los radiobuttons iniciales
        self.input_output = dict()
        self.input_output[INPUT_GROUP] = str(in_bq.buttons()[0].text())
        self.input_output[OUTPUT_GROUP] = str(out_bq.buttons()[1].text())
        self.input_output[PROCESS_GROUP] = str(process_bq.buttons()[0].text())
        in_bq.buttons()[0].setChecked(True)
        out_bq.buttons()[1].setChecked(True)
        process_bq.buttons()[0].setChecked(True)

        # Se define el pop up para salir de la aplicacion
        self.msg_box = QMessageBox()
        self.msg_box.setWindowTitle("Salir")
        self.msg_box.setText("Esta seguro que desea salir?")
        self.msg_box.addButton("Si", QMessageBox.AcceptRole)
        self.msg_box.addButton("No", QMessageBox.RejectRole)

        # Error para formato incorrecto
        self.wrong_file_box = QMessageBox()
        self.wrong_file_box.setWindowTitle("Error")
        self.wrong_file_box.setText("El archivo tiene formato incorrecto")

        # Error para el path file
        self.no_data_box = QMessageBox()
        self.no_data_box.setWindowTitle("Error")
        self.no_data_box.setText(
            "No se puede utilizar la ruta indicada o los datos son inexistentes"
        )

        # Create select play file
        self.path_label = QLabel(os.path.abspath(OUTPUT_FILE_PATH), self)
        self.path_label.move(128, 40)
        self.path_label.resize(self.path_label.minimumSizeHint())

        # Metodo del parent QWidget. QWidget -> QMainWindow -> EGPSWindow

        self.show()
class DefaultSelectParameterWidget(SelectParameterWidget):

    """Widget class for Default Select Parameter."""

    def __init__(self, parameter, parent=None):
        """Constructor

        :param parameter: A DefaultSelectParameter object.
        :type parameter: DefaultSelectParameter
        """
        super(DefaultSelectParameterWidget, self).__init__(parameter, parent)

        self.default_layout = QHBoxLayout()
        self.radio_button_layout = QHBoxLayout()
        self.radio_button_widget = QWidget()

        self.default_label = QLabel(tr('Default'))

        # Create radio button group
        self.default_input_button_group = QButtonGroup()

        # Define string enabler for radio button
        self.radio_button_enabler = self.input.itemData(0, Qt.UserRole)

        for i in range(len(self._parameter.default_labels)):
            if '%s' in self._parameter.default_labels[i]:
                label = (
                    self._parameter.default_labels[i] %
                    self._parameter.default_values[i])
            else:
                label = self._parameter.default_labels[i]

            radio_button = QRadioButton(label)
            self.radio_button_layout.addWidget(radio_button)
            self.default_input_button_group.addButton(radio_button, i)
            if self._parameter.default_value == \
                    self._parameter.default_values[i]:
                radio_button.setChecked(True)

        # Create double spin box for custom value
        self.custom_value = QDoubleSpinBox()
        if self._parameter.default_values[-1]:
            self.custom_value.setValue(self._parameter.default_values[-1])
        has_min = False
        if self._parameter.minimum is not None:
            has_min = True
            self.custom_value.setMinimum(self._parameter.minimum)
        has_max = False
        if self._parameter.maximum is not None:
            has_max = True
            self.custom_value.setMaximum(self._parameter.maximum)
        if has_min and has_max:
            step = (self._parameter.maximum - self._parameter.minimum) / 100.0
            self.custom_value.setSingleStep(step)
        self.radio_button_layout.addWidget(self.custom_value)

        self.toggle_custom_value()

        # Reset the layout
        self.input_layout.setParent(None)
        self.help_layout.setParent(None)

        self.label.setParent(None)
        self.inner_input_layout.setParent(None)

        self.input_layout = QGridLayout()
        self.input_layout.setSpacing(0)

        self.input_layout.addWidget(self.label, 0, 0)
        self.input_layout.addLayout(self.inner_input_layout, 0, 1)
        self.input_layout.addWidget(self.default_label, 1, 0)
        self.input_layout.addLayout(self.radio_button_layout, 1, 1)

        self.main_layout.addLayout(self.input_layout)
        self.main_layout.addLayout(self.help_layout)

        # check every added combobox, it could have been toggled by
        # the existing keyword
        self.toggle_input()

        # Connect
        # noinspection PyUnresolvedReferences
        self.input.currentIndexChanged.connect(self.toggle_input)
        self.default_input_button_group.buttonClicked.connect(
            self.toggle_custom_value)

    def raise_invalid_type_exception(self):
        message = 'Expecting element type of %s' % (
            self._parameter.element_type.__name__)
        err = ValueError(message)
        return err

    def get_parameter(self):
        """Obtain list parameter object from the current widget state.

        :returns: A DefaultSelectParameter from the current state of widget.
        """
        current_index = self.input.currentIndex()
        selected_value = self.input.itemData(current_index, Qt.UserRole)
        if hasattr(selected_value, 'toPyObject'):
            selected_value = selected_value.toPyObject()

        try:
            self._parameter.value = selected_value
        except ValueError:
            err = self.raise_invalid_type_exception()
            raise err

        radio_button_checked_id = self.default_input_button_group.checkedId()
        # No radio button checked, then default value = None
        if radio_button_checked_id == -1:
            self._parameter.default = None
        # The last radio button (custom) is checked, get the value from the
        # line edit
        elif (radio_button_checked_id ==
                len(self._parameter.default_values) - 1):
            self._parameter.default_values[radio_button_checked_id] \
                = self.custom_value.value()
            self._parameter.default = self.custom_value.value()
        else:
            self._parameter.default = self._parameter.default_values[
                radio_button_checked_id]

        return self._parameter

    def set_default(self, default):
        """Set default value by item's string.

        :param default: The default.
        :type default: str, int

        :returns: True if success, else False.
        :rtype: bool
        """
        # Find index of choice
        try:
            default_index = self._parameter.default_values.index(default)
            self.default_input_button_group.button(default_index).setChecked(
                True)
        except ValueError:
            last_index = len(self._parameter.default_values) - 1
            self.default_input_button_group.button(last_index).setChecked(
                True)
            self.custom_value.setValue(default)

        self.toggle_custom_value()

    def toggle_custom_value(self):
        radio_button_checked_id = self.default_input_button_group.checkedId()
        if (radio_button_checked_id ==
                len(self._parameter.default_values) - 1):
            self.custom_value.setDisabled(False)
        else:
            self.custom_value.setDisabled(True)

    def toggle_input(self):
        """Change behaviour of radio button based on input."""
        current_index = self.input.currentIndex()
        # If current input is not a radio button enabler, disable radio button.
        if self.input.itemData(current_index, Qt.UserRole) != (
                self.radio_button_enabler):
            self.disable_radio_button()
        # Otherwise, enable radio button.
        else:
            self.enable_radio_button()

    def set_selected_radio_button(self):
        """Set selected radio button to 'Do not report'."""
        dont_use_button = self.default_input_button_group.button(
            len(self._parameter.default_values) - 2)
        dont_use_button.setChecked(True)

    def disable_radio_button(self):
        """Disable radio button group and custom value input area."""
        checked = self.default_input_button_group.checkedButton()
        if checked:
            self.default_input_button_group.setExclusive(False)
            checked.setChecked(False)
            self.default_input_button_group.setExclusive(True)
        for button in self.default_input_button_group.buttons():
            button.setDisabled(True)
        self.custom_value.setDisabled(True)

    def enable_radio_button(self):
        """Enable radio button and custom value input area then set selected
        radio button to 'Do not report'.
        """
        for button in self.default_input_button_group.buttons():
            button.setEnabled(True)
        self.set_selected_radio_button()
        self.custom_value.setEnabled(True)
Exemple #18
0
class FilteringModule(PreprocessorModule):
    DEFAULT_SETTINGS = {
        'is_enabled': True,
        'methods': [True, False, False],
        'recent_sw_files': [],
        'min_df': None,
        'max_df': None,
    }

    English, Custom, DocumentFrequency = 0, 1, 2
    filtering_values = {
        English: 'english',
        Custom: [],
        DocumentFrequency: (None, None),
    }
    filter_names = {
        English: 'English stop words',
        Custom: 'Custom stop words',
        DocumentFrequency: 'Filter by token frequency',
    }

    filtering_methods = [True, False, False]

    dlgFormats = 'Only text files (*.txt)'
    recent_sw_files = []

    def __init__(self, data):
        data = data or self.DEFAULT_SETTINGS
        PreprocessorModule.__init__(self, 'Token filtering', True,
                                    data.get('is_enabled'))

        self.group = QButtonGroup(self, exclusive=False)

        # --- English ---
        cb = QCheckBox(self, text=self.filter_names[self.English])
        self.add_to_content_area(cb)
        self.group.addButton(cb, self.English)

        # --- Custom ---
        cb = QCheckBox(self, text=self.filter_names[self.Custom])
        self.add_to_content_area(cb)
        self.group.addButton(cb, self.Custom)

        # File browser.
        file_browser_layout = QHBoxLayout()
        file_browser_layout.setContentsMargins(20, 0, 0, 0)
        self.sw_file_combo = QComboBox()
        self.sw_file_combo.setMinimumWidth(200)
        file_browser_layout.addWidget(self.sw_file_combo)
        self.sw_file_combo.activated[int].connect(self.select_file)

        self.browse_button = QPushButton(self)
        self.browse_button.clicked.connect(self.browse_file)
        self.browse_button.setIcon(self.style().standardIcon(
            QStyle.SP_DirOpenIcon))
        self.browse_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        file_browser_layout.addWidget(self.browse_button)

        # Reload button
        self.reload_button = QPushButton(self)
        self.reload_button.clicked.connect(self.on_reload_button_clicked)
        self.reload_button.setIcon(self.style().standardIcon(
            QStyle.SP_BrowserReload))
        self.reload_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        file_browser_layout.addWidget(self.reload_button)

        self.add_layout_to_content_area(file_browser_layout)

        # --- DF ---
        df_info_text = """
        Remove all tokens that appear in less than 'min-df' documents.
        Remove all tokens that appear in more than 'max-df' documents.
        Values can be either integers or floats (ratio of documents).
        """
        cb = QCheckBox(self, text=self.filter_names[self.DocumentFrequency])
        self.add_to_content_area(cb)
        self.group.addButton(cb, self.DocumentFrequency)
        df_info_text = QLabel(df_info_text)
        df_info_text.setContentsMargins(0, 0, 0, 0)
        df_info_text.setStyleSheet("""
        font-size: 11px;
        font-style: italic;
        """)
        self.add_to_content_area(df_info_text)
        # Min/Max-Df setter.
        df_setter_layout = QHBoxLayout()
        df_setter_layout.setContentsMargins(20, 0, 0, 0)
        self.min_df_input = QLineEdit()
        self.min_df_input.textChanged.connect(self.update_df_parameters)
        self.max_df_input = QLineEdit()
        self.max_df_input.textChanged.connect(self.update_df_parameters)
        df_setter_layout.addWidget(QLabel('Min-df:'))
        df_setter_layout.addWidget(self.min_df_input)
        df_setter_layout.addWidget(QLabel('Max-df:'))
        df_setter_layout.addWidget(self.max_df_input)

        self.add_layout_to_content_area(df_setter_layout)
        self.group.buttonClicked.connect(self.group_button_clicked)

        # Restore the widget to its previous state.
        self.restore_data(data)

    def str_to_num(self, s):
        if not s:
            return None

        try:
            return int(s)
        except ValueError:
            pass  # Not an int. Continue.
        try:
            return float(s)
        except ValueError:  # Not a float either.
            self.send_message(
                'Input "{}" cannot be cast into a number.'.format(s))
            return None

    def send_message(self, message):
        # Sends a message with the "message" signal, to the main widget.
        self.error_signal.emit(message)

    # --- File selection.
    def select_file(self, n):
        if n < len(self.recent_sw_files):
            name = self.recent_sw_files[n]
            del self.recent_sw_files[n]
            self.recent_sw_files.insert(0, name)

        if len(self.recent_sw_files) > 0:
            self.set_file_list()
            self.open_file(self.recent_sw_files[0])

    def set_file_list(self):
        self.sw_file_combo.clear()
        if not self.recent_sw_files:
            self.sw_file_combo.addItem('(none)')
        else:
            for file in self.recent_sw_files:
                self.sw_file_combo.addItem(os.path.split(file)[1])

    def browse_file(self):
        # Opens the file browser, starting at the home directory.
        start_file = os.path.expanduser('~/')
        # Get the file path from the browser window.
        path = QFileDialog.getOpenFileName(self, 'Open a stop words source',
                                           start_file, self.dlgFormats)
        if not path:
            return

        if path in self.recent_sw_files:
            self.recent_sw_files.remove(path)
        self.recent_sw_files.insert(0, path)
        self.set_file_list()
        self.open_file(path)

    def update_df_parameters(self):
        min_df = None if not self.min_df_input.text(
        ) else self.min_df_input.text()
        max_df = None if not self.max_df_input.text(
        ) else self.max_df_input.text()
        self.filtering_values[self.DocumentFrequency] = (min_df, max_df)
        self.notify_on_change()

    def open_file(self, path):
        try:
            with open(path) as f:  # Read most recent.
                self.filtering_values[self.Custom] = [
                    sw.strip() for sw in f.read().splitlines()
                ]
                self.notify_on_change()
        except Exception:  # Raise an exception otherwise.
            self.send_message('Could not open "{}".'.format(path))

    def on_reload_button_clicked(self):
        if self.recent_sw_files:
            self.select_file(0)

    # END File selection.

    def group_button_clicked(self):
        self.filtering_methods = [
            ch_box.isChecked() for ch_box in self.group.buttons()
        ]

        self.enable_choice_settings()

        # Emit the signal.
        self.notify_on_change()

    def enable_choice_settings(self):
        self.sw_file_combo.setEnabled(self.filtering_methods[1])
        self.browse_button.setEnabled(self.filtering_methods[1])
        self.reload_button.setEnabled(self.filtering_methods[1])

        self.min_df_input.setEnabled(self.filtering_methods[2])
        self.max_df_input.setEnabled(self.filtering_methods[2])

    def get_pp_setting(self):
        flag_english = self.filtering_methods[0]
        flag_custom = self.filtering_methods[1]
        flag_df = self.filtering_methods[2]
        if flag_english and flag_custom:  # Use custom.
            stop_words = {
                'stop_words':
                stopwords.words('english') + self.filtering_values[self.Custom]
            }
        elif flag_english and not flag_custom:
            stop_words = {'stop_words': 'english'}
        elif flag_custom:
            stop_words = {'stop_words': self.filtering_values[self.Custom]}
        else:
            stop_words = {}

        if flag_df:
            stop_words.update({
                'min_df':
                self.str_to_num(self.min_df_input.text()),
                'max_df':
                self.str_to_num(self.max_df_input.text()),
            })
        return stop_words

    def restore_data(self, data):
        self.recent_sw_files = data.get('recent_sw_files')
        self.min_df_input.setText(data.get('min_df'))
        self.max_df_input.setText(data.get('max_df'))
        self.filtering_methods = data.get('methods')

        for flag, ch_box in zip(self.filtering_methods, self.group.buttons()):
            ch_box.setChecked(flag)

        self.enable_choice_settings()  # Enable the settings if set.
        self.set_file_list()  # Fill the combo box with the recent sw files.
        self.select_file(0)  # Select the first file.

    def export_data(self):
        return {
            'is_enabled': self.enabled,
            'methods': self.filtering_methods,
            'recent_sw_files': self.recent_sw_files,
            'min_df': self.min_df_input.text(),
            'max_df': self.max_df_input.text(),
        }
class DBServersWidget(QWidget):
    """Displays a list of servers"""
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.debug = False

        self.connections = {}

        self.setWindowTitle("Servers")
        #s#elf.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)

        self.mainLayout = QVBoxLayout()
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.setSpacing(0)
        self.setLayout(self.mainLayout)

        #=============================================
        ## Top Toolbar
        topBar = QToolBar()
        topBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.mainLayout.addWidget(topBar)

        ## Add the action buttons
        topBar.addAction(Ico.icon(Ico.ServerAdd), "Add", self.on_server_add)
        self.actionServerEdit = topBar.addAction(Ico.icon(Ico.ServerEdit),
                                                 "Edit", self.on_server_edit)
        self.actionServerDelete = topBar.addAction(Ico.icon(Ico.ServerDelete),
                                                   "Delete",
                                                   self.on_server_delete)

        #=============================================
        ## Tree
        self.tree = QTreeWidget()
        self.mainLayout.addWidget(self.tree)
        self.tree.setUniformRowHeights(True)
        self.tree.setRootIsDecorated(True)

        self.tree.setHeaderLabels(["Server",
                                   "Butt"])  # set header, but hide anyway
        self.tree.header().hide()
        self.tree.header().setResizeMode(C.node, QHeaderView.Stretch)
        self.tree.setColumnWidth(C.butt, 20)

        self.connect(self.tree, SIGNAL('itemSelectionChanged()'),
                     self.on_tree_selection_changed)
        self.connect(self.tree,
                     SIGNAL('itemDoubleClicked (QTreeWidgetItem *,int)'),
                     self.on_tree_double_clicked)

        self.buttGroup = QButtonGroup(self)
        self.connect(self.buttGroup, SIGNAL("buttonClicked(QAbstractButton*)"),
                     self.on_open_server)

        self.on_tree_selection_changed()

        self.load_servers()

    #=======================================
    ##== Tree Events
    def on_tree_selection_changed(self):

        disabled = self.tree.selectionModel().hasSelection() == False
        self.actionServerEdit.setDisabled(disabled)
        self.actionServerDelete.setDisabled(disabled)

    def on_tree_double_clicked(self):
        self.actionServerEdit.trigger()

    #=======================================
    ## Server Actions
    def on_server_add(self):
        self.show_server_dialog(None)

    def on_server_edit(self):
        item = self.tree.currentItem()
        if item == None:
            return
        server = str(item.text(C.server))
        self.show_server_dialog(server)

    def show_server_dialog(self, server=None):
        d = DBServerDialog.DBServerDialog(self, server)
        if d.exec_():
            self.load_servers()

    def load_servers(self):
        """Load servers from :py:meth:`pyqtdb.XSettings.XSettings.get_servers` """

        self.tree.clear()

        for butt in self.buttGroup.buttons():
            self.buttGroup.removeButton(butt)

        for srv in G.settings.get_servers_list():

            item = QTreeWidgetItem()
            item.setText(C.node, srv['server'])
            #item.setText(C.user, srv['user'])
            self.tree.addTopLevelItem(item)

            butt = QToolButton()
            butt.setIcon(Ico.icon(Ico.Connect))
            butt.setProperty("server", srv['server'])
            self.tree.setItemWidget(item, C.butt, butt)
            self.buttGroup.addButton(butt)

    def on_server_delete(self):
        item = self.tree.currentItem()
        if item == None:
            return
        srv = str(item.text(C.server))
        G.settings.delete_server(srv)
        self.load_servers()

    def on_open_server(self, butt):

        # self.emit(SIGNAL("open_server"), butt.property("server").toString())
        srv_ki = str(butt.property("server").toString())
        server = G.settings.get_server(srv_ki)
        db = QSqlDatabase.addDatabase("QMYSQL", srv_ki)
        db.setHostName(server['server'])
        db.setUserName(server['user'])
        db.setPassword(server['passwd'])

        ok = db.open()
        if ok:
            #self.connections[srv_ki] =
            self.load_databases(srv_ki)
            print "open", ok

    def load_databases(self, srv_ki):
        """Load databases into tree node for server;  executes 'show databases;' or aslike """

        sql = "show databases;"
        query = QSqlQuery(QSqlDatabase.database(srv_ki))
        ok = query.exec_(sql)
        print ok, sql, query.result()

        # Get the parent node, ie the server node
        pItem = self.tree.findItems(srv_ki, Qt.MatchExactly, C.node)[0]

        ## Assumed value(0) is the table.. we need the defs (ie mysql case)
        while query.next():
            table_name = query.value(0).toString()
            nuItem = QTreeWidgetItem(pItem)
            nuItem.setText(C.node, table_name)
            #print table_name

        self.tree.setItemExpanded(pItem, True)
class PrivacyConfirmationDialog(QDialog):
    POLICY_ONCE = 0
    POLICY_FOREVER = 1

    SCOPE_PEER_CATEGORY = 0
    SCOPE_PEER = 1
    SCOPE_EVERYONE_CATEGORY = 2
    SCOPE_EVERYONE = 3

    def __init__(self, parent, title, peerName, peerID, action, category, msgData):
        super(PrivacyConfirmationDialog, self).__init__(parent)

        self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)

        self._peerID = peerID
        self._peerName = peerName
        self._action = action
        self._category = category if category is not None else PrivacySettings.NO_CATEGORY
        self._useCategories = self._action.usesPrivacyCategories()

        layout = QVBoxLayout(self)
        layout.setContentsMargins(15, 15, 15, 10)

        messageLabel = QLabel(self._createMessage(msgData), self)
        messageLabel.setWordWrap(True)

        policyWidget = self._initPolicyWidget()
        scopeWidget = self._initScopeWidget(peerName, category)
        buttonBox = self._initButtonBox()

        bottomWidget = QWidget(self)
        bottomLayout = QHBoxLayout(bottomWidget)
        bottomLayout.setContentsMargins(0, 0, 0, 0)
        bottomLayout.setSpacing(0)
        self._timeoutLabel = QLabel(bottomWidget)
        bottomLayout.addWidget(self._timeoutLabel, 1)
        bottomLayout.addWidget(buttonBox)

        layout.addWidget(messageLabel)
        layout.addWidget(policyWidget, 0)
        layout.addWidget(scopeWidget)
        layout.addWidget(bottomWidget, 1)

        self.setWindowTitle(title)
        size = self.sizeHint()
        self.setMaximumHeight(size.height())

        self._setPolicy(0)
        if action.getTimeout() is not None and action.getTimeout() > 0:
            self._timeout = action.getTimeout()
            self._timer = QTimer(self)
            self._timer.timeout.connect(self._decrementTimer)
            self._timer.start(1000)
        else:
            self._timer = None

    @loggingSlot()
    def _decrementTimer(self):
        self._timeout -= 1
        if self._timeout <= 0:
            self.reject()
        self._timeoutLabel.setText(u"%d s" % self._timeout)

    def _createMessage(self, msgData):
        message = self._action.getConfirmationMessage(self._peerID, self._peerName, msgData)
        if message is None:
            # create default message
            if self._action.usesPrivacyCategories():
                if self._category == PrivacySettings.NO_CATEGORY:
                    message = "%s wants to perform the following action: %s (uncategorized)" % (
                        self._peerName,
                        self._action.getName(),
                    )
                else:
                    message = "%s wants to perform the following action: %s, in category %s" % (
                        self._peerName,
                        self._action.getName(),
                        self._category,
                    )
            else:
                message = "%s wants to perform the following action: %s" % (self._peerName, self._action.getName())
        return message

    def _initPolicyWidget(self):
        policyWidget = QWidget(self)
        self._policyGroup = QButtonGroup(self)

        once = QRadioButton("Once", policyWidget)
        once.setChecked(True)
        once.clicked.connect(partial(self._setPolicy, self.POLICY_ONCE))
        self._policyGroup.addButton(once)

        forever = QRadioButton("Forever", policyWidget)
        forever.clicked.connect(partial(self._setPolicy, self.POLICY_FOREVER))
        self._policyGroup.addButton(forever)

        policyLayout = QHBoxLayout(policyWidget)
        policyLayout.setContentsMargins(5, 0, 5, 0)
        policyLayout.addWidget(once, 0)
        policyLayout.addWidget(forever, 1, Qt.AlignLeft)
        return policyWidget

    def _initScopeWidget(self, peerName, category):
        scopeWidget = QWidget(self)
        self._scopeGroup = QButtonGroup(self)

        if not self._useCategories:
            thisPeer = QRadioButton(peerName, scopeWidget)
            thisPeer.clicked.connect(partial(self._setScope, self.SCOPE_PEER))
            self._scopeGroup.addButton(thisPeer)

            everyone = QRadioButton(u"Everyone", scopeWidget)
            everyone.clicked.connect(partial(self._setScope, self.SCOPE_EVERYONE))
            self._scopeGroup.addButton(everyone)
        else:
            if self._category == PrivacySettings.NO_CATEGORY:
                catDesc = u"uncategorized"
            else:
                catDesc = u"category %s" % category

            b = QRadioButton(u"%s, %s" % (peerName, catDesc), scopeWidget)
            b.clicked.connect(partial(self._setScope, self.SCOPE_PEER_CATEGORY))
            self._scopeGroup.addButton(b)

            b = QRadioButton(u"%s, all categories" % (peerName), scopeWidget)
            b.clicked.connect(partial(self._setScope, self.SCOPE_PEER))
            self._scopeGroup.addButton(b)

            b = QRadioButton(u"Everyone, %s" % (catDesc), scopeWidget)
            b.clicked.connect(partial(self._setScope, self.SCOPE_EVERYONE_CATEGORY))
            self._scopeGroup.addButton(b)

            b = QRadioButton(u"Everyone, all categories", scopeWidget)
            b.clicked.connect(partial(self._setScope, self.SCOPE_EVERYONE))
            self._scopeGroup.addButton(b)

        self._scopeGroup.buttons()[0].click()
        scopeLayout = QVBoxLayout(scopeWidget)
        scopeLayout.setContentsMargins(5, 0, 5, 0)
        for button in self._scopeGroup.buttons():
            scopeLayout.addWidget(button, 0)
        return scopeWidget

    def _initButtonBox(self):
        cancelButton = QPushButton("Deny", self)
        cancelButton.clicked.connect(self.reject)

        okButton = QPushButton("Accept", self)
        okButton.clicked.connect(self.accept)

        buttonBox = QDialogButtonBox(Qt.Horizontal, self)
        buttonBox.addButton(cancelButton, QDialogButtonBox.RejectRole)
        buttonBox.addButton(okButton, QDialogButtonBox.AcceptRole)
        return buttonBox

    def _setPolicy(self, policy):
        self._policy = policy
        for button in self._scopeGroup.buttons():
            button.setEnabled(policy == self.POLICY_FOREVER)

    def _setScope(self, scope):
        self._scope = scope

    def _clickNext(self, group):
        curIdx = group.buttons().index(group.checkedButton())
        if curIdx + 1 < len(group.buttons()):
            group.buttons()[curIdx + 1].click()

    def _clickPrev(self, group):
        curIdx = group.buttons().index(group.checkedButton())
        if curIdx - 1 >= 0:
            group.buttons()[curIdx - 1].click()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Right:
            self._clickNext(self._policyGroup)
            event.accept()
        elif event.key() == Qt.Key_Left:
            self._clickPrev(self._policyGroup)
            event.accept()
        elif event.key() == Qt.Key_Up:
            self._clickPrev(self._scopeGroup)
            event.accept()
        elif event.key() == Qt.Key_Down:
            self._clickNext(self._scopeGroup)
            event.accept()
        else:
            return QDialog.keyPressEvent(self, event)

    def _storeDecision(self, accepted):
        # store decision
        if not self._useCategories:
            if self._scope == self.SCOPE_PEER:
                PrivacySettings.get().addException(
                    self._action,
                    None,
                    PrivacySettings.POLICY_NOBODY_EX,
                    self._peerID,
                    1 if accepted else 0,
                    categoryPolicy=PrivacySettings.CATEGORY_NEVER,
                )
            elif self._scope == self.SCOPE_EVERYONE:
                PrivacySettings.get().setPolicy(
                    self._action,
                    None,
                    PrivacySettings.POLICY_EVERYBODY if accepted else PrivacySettings.POLICY_NOBODY,
                    categoryPolicy=PrivacySettings.CATEGORY_NEVER,
                )
        else:
            if self._scope == self.SCOPE_PEER_CATEGORY:
                PrivacySettings.get().addException(
                    self._action,
                    self._category,
                    PrivacySettings.POLICY_NOBODY_EX,
                    self._peerID,
                    1 if accepted else 0,
                    categoryPolicy=PrivacySettings.CATEGORY_ALWAYS,
                )
            elif self._scope == self.SCOPE_PEER:
                PrivacySettings.get().addException(
                    self._action,
                    None,
                    PrivacySettings.POLICY_PEER_EXCEPTION,
                    self._peerID,
                    1 if accepted else 0,
                    categoryPolicy=PrivacySettings.CATEGORY_NEVER,
                )
            elif self._scope == self.SCOPE_EVERYONE_CATEGORY:
                PrivacySettings.get().setPolicy(
                    self._action,
                    self._category,
                    PrivacySettings.POLICY_EVERYBODY if accepted else PrivacySettings.POLICY_NOBODY,
                    categoryPolicy=PrivacySettings.CATEGORY_ALWAYS,
                )
            elif self._scope == self.SCOPE_EVERYONE:
                PrivacySettings.get().setPolicy(
                    self._action,
                    None,
                    PrivacySettings.POLICY_EVERYBODY if accepted else PrivacySettings.POLICY_NOBODY,
                    categoryPolicy=PrivacySettings.CATEGORY_NEVER,
                )

    def _finish(self):
        if self._timer is not None:
            self._timer.stop()
            self._timer = None

    @loggingSlot()
    def accept(self):
        self._finish()
        if self._action is not None and self._policy == self.POLICY_FOREVER:
            self._storeDecision(True)
        return QDialog.accept(self)

    @loggingSlot()
    def reject(self):
        self._finish()
        if self._action is not None and self._policy == self.POLICY_FOREVER:
            self._storeDecision(False)
        return QDialog.reject(self)