示例#1
0
class TabLayout(QWidget):
    def __init__(self, toplabel):
        super().__init__()

        ## Get label from ctor args
        self.label = QLabel(toplabel)

        ## Create and bind spinbox to update function
        self.spinbox = QSpinBox()
        self.spinbox.setMinimum(1)
        self.spinbox.valueChanged.connect(self.update)

        ## Keep track of how many elements we have in sublayout 2
        self.counter = 1

        ## Layouts
        self.toplayout = QVBoxLayout()
        self.sublayout1 = QHBoxLayout()
        self.sublayout2 = QHBoxLayout()

        ## Build the first line with label and spinbox
        self.sublayout1.addWidget(self.label)
        self.sublayout1.addWidget(self.spinbox)

        ## Build the entity container
        self.sublayout2.addWidget( EntityData() )

        ## Build top level layout
        self.toplayout.addLayout(self.sublayout1)
        self.toplayout.addLayout(self.sublayout2)

        ## Display
        self.setLayout(self.toplayout)

    def update(self):        
        if self.spinbox.value() > self.counter:
            for i in range( 0, self.spinbox.value() - self.counter ):
                self.sublayout2.addWidget( EntityData() )
        elif self.spinbox.value() < self.counter:
            # Delete all widgets
            while self.sublayout2.count() > self.spinbox.value():
                item = self.sublayout2.takeAt( self.sublayout2.count() - 1 )

                if not item:
                    continue

                w = item.widget()
                if w:
                    w.setParent(None)

            # Recreate all widgets
            #for i in range( 0, self.spinbox.value() ):
            #    self.sublayout2.addWidget( EntityData() )

        self.sublayout2.update()
        self.toplayout.update()
        self.counter = self.spinbox.value()
示例#2
0
    def _init_option_ui(self):
        label_start_time = QLabel("Start time: ")
        self._line_edit_start_time = QLineEdit()

        label_end_time = QLabel("End time: ")
        self._line_edit_end_time = QLineEdit()

        label_duration = QLabel("Duration: ")
        self._line_edit_duration = QLineEdit()

        label_num_clip = QLabel("No. of clips: ")
        self._line_edit_num_clip = QLineEdit()

        button_preview = QPushButton("Preview")
        button_preview.clicked.connect(self.button_preview_clicked)

        hbox = QHBoxLayout()
        hbox.addWidget(label_start_time)
        hbox.addWidget(self._line_edit_start_time)
        hbox.addWidget(label_end_time)
        hbox.addWidget(self._line_edit_end_time)
        hbox.addWidget(label_duration)
        hbox.addWidget(self._line_edit_duration)
        hbox.addWidget(label_num_clip)
        hbox.addWidget(self._line_edit_num_clip)
        hbox.addWidget(button_preview)

        for i in range(hbox.count() - 1):
            hbox.itemAt(i).widget().setObjectName("option")

        self.vbox.addLayout(hbox)
示例#3
0
    def _init_browse_ui(self):
        label_file_name = QLabel("File name: ")

        self._list_widget_file_names = QListWidget()
        self._list_widget_file_names.setFixedHeight(100)

        button_browse = QPushButton("Browse")
        button_browse.clicked.connect(self.button_browse_clicked)
        button_add = QPushButton("Add")
        button_add.clicked.connect(self.button_add_clicked)
        button_remove = QPushButton("Remove")
        button_remove.clicked.connect(self.button_remove_clicked)

        vbox = QVBoxLayout()
        vbox.addWidget(button_browse)
        vbox.addWidget(button_add)
        vbox.addWidget(button_remove)

        hbox = QHBoxLayout()
        hbox.addWidget(label_file_name)
        hbox.addWidget(self._list_widget_file_names)
        hbox.addLayout(vbox)

        for i in range(hbox.count()):
            hbox.setAlignment(hbox.itemAt(i).widget(), Qt.AlignTop)

        self.vbox.addLayout(hbox)
示例#4
0
class Page(QWidget):
    Hiding = QtCore.pyqtSignal(int)
    Showing = QtCore.pyqtSignal(int)

    def __init__(self, index: int, page_name: str, parent: QWidget = None):
        super(Page, self).__init__(parent)

        self.myIndex: int = index
        self.setObjectName(page_name)
        self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.MinimumExpanding)
        self.setContentsMargins(0, 0, 0, 0)

        self.hboxlayout = QHBoxLayout(self)
        self.hboxlayout.setContentsMargins(0, 0, 0, 0)
        self.hboxlayout.setSpacing(0)
        self.setLayout(self.hboxlayout)

        scroll_area = QScrollArea(self)
        scroll_area.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        scroll_area.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        scroll_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.MinimumExpanding)

        scroll_area.setFrameShape(QFrame.NoFrame)
        scroll_area.setFrameShadow(QFrame.Plain)
        scroll_area.setLineWidth(0)
        scroll_area.setWidgetResizable(True)
        scroll_area.installEventFilter(TTScroller(scroll_area))

        self.inner_area = QFrame()
        self.inner_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Ignored)
        self.inner_area.setProperty("TTPage", QtCore.QVariant(True))
        self.inner_area.setContentsMargins(0, 0, 0, 0)
        self.inner_area.setFrameShape(QFrame.Box)
        self.inner_area.setLineWidth(0)

        self.innerLayout = QHBoxLayout(self.inner_area)
        self.innerLayout.setContentsMargins(0, 0, 0, 0)
        self.innerLayout.setSpacing(2)
        self.inner_area.setLayout(self.innerLayout)

        spacer = QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.innerLayout.addItem(spacer)
        scroll_area.setWidget(self.inner_area)
        self.hboxlayout.addWidget(scroll_area)

    def add_group(self, name: str):
        grp = group.Group(name, self.inner_area)
        self.innerLayout.insertWidget(self.innerLayout.count() - 1, grp)
        parent_toolbar = tabtoolbar.find_tabtoolbar(self)  # type: ignore[attr-defined]
        if not parent_toolbar:
            raise Exception("Could not find Parent Tabtoolbar")

        parent_toolbar.adjust_verticalsize(grp.height())
        return grp

    def hide(self):
        self.Hiding.emit(self.myIndex)

    def show(self):
        self.Showing.emit(self.myIndex)
示例#5
0
    def __init__(self, options, parent=None):
        super().__init__(parent)
        self.options = options
        self.setWindowFlags(Qt.Dialog | Qt.WindowTitleHint
                            | Qt.WindowCloseButtonHint)
        topLayout = QVBoxLayout(self)
        self.setLayout(topLayout)
        columnLayout = QHBoxLayout()
        topLayout.addLayout(columnLayout)
        rowLayout = QVBoxLayout()
        columnLayout.addLayout(rowLayout)
        groupBox = None
        for option in self.options.values():
            if option.columnNum > columnLayout.count() - 1:
                rowLayout = QVBoxLayout()
                columnLayout.addLayout(rowLayout)
            if not groupBox or groupBox.title() != option.category:
                groupBox = QGroupBox(option.category)
                rowLayout.addWidget(groupBox)
                QGridLayout(groupBox)
            option.addDialogControl(groupBox)

        ctrlLayout = QHBoxLayout()
        topLayout.addLayout(ctrlLayout)
        ctrlLayout.addStretch(0)
        okButton = QPushButton(_('&OK'))
        ctrlLayout.addWidget(okButton)
        okButton.clicked.connect(self.accept)
        cancelButton = QPushButton(_('&Cancel'))
        ctrlLayout.addWidget(cancelButton)
        cancelButton.clicked.connect(self.reject)
示例#6
0
class ShipSlot(QWidget):
    sloticon_table = None
    type_table = {1: 'MainCanonLight',
                  2: 'MainCanonMedium',
                  3: 'MainCanonHeavy',
                  4: 'SecondaryCanon',
                  5: 'Torpedo',
                  6: 'Fighter',
                  7: 'DiveBomber',
                  8: 'TorpedoBomber',
                  9: 'ReconPlane',
                  10:'ReconSeaplane',
                  11:'Rader',
                  12:'AAShell',
                  13:'APShell',
                  14:'DamageControl',
                  15:'AAGun',
                  16:'HighAngleGun',
                  17:'ASW',
                  18:'Soner',
                  19:'EngineImprovement',
                  20:'LandingCraft',
                  21:'Autogyro',
                  22:'ArtillerySpotter',
                  23:'AntiTorpedoBulge',
                  24:'SearchLight',
                  25:'DrumCanister',
                  26:'Facility',
                  27:'Flare',
                  28:'FleetCommandFacility',
                  29:'MaintenancePersonnel',
                  30:'AntiAircraftFireDirector',
                  31:'RocketLauncher',
                  32:'SurfaceShipPersonnel',
                  33:'FlyingBoat'
    }

    def __init__(self,parent):
        super(ShipSlot, self).__init__(parent)

        if self.sloticon_table is None:
            self.sloticon_table = slotitem.create_sloticontable()

        self.box = QHBoxLayout()
        self.box.setSpacing(3)
        self.box.setContentsMargins(0,5,0,5)

        self.setLayout(self.box)

    def set_slot(self, types):
        # remove all icon
        for i in reversed(list(range(self.box.count()))):
            self.box.itemAt(i).widget().setParent(None)

        for t in types:
            type_name = self.type_table.get(t, 'unknown')
            if not type_name in self.sloticon_table:
                type_name = 'unknown'
            self.box.addWidget(slotitem.IconBox(self.sloticon_table[type_name]))
示例#7
0
class MenuBar(QTabWidget):
    def __init__(self, parent=None):
        super(MenuBar, self).__init__(parent)

        tabbar = TabBar(parent)
        self.setTabBar(tabbar)
        self.setMinimumHeight(135)
        self.setMouseTracking(True)

        self._drop = False
        self.currentChanged.connect(self.currentChangedFunc)

    def currentChangedFunc(self, index):
        tab_text = self.tabText(index)
        menu = self.findChild(MenuWidget, tab_text)
        self.anim = QPropertyAnimation(menu, b'_height')
        self.anim.setDuration(100)
        self.anim.setStartValue(0)
        self.anim.setEndValue(100)
        self.anim.start()

    def addMenu(self, p_str):
        p_str = "  {p_str}  ".format(p_str=p_str)
        menu = MenuWidget()
        menu.setObjectName(p_str)
        self.addTab(menu, p_str)
        self.hlayout = QHBoxLayout(menu)
        self.hlayout.setObjectName(p_str)
        self.hlayout.setContentsMargins(0, 0, 0, 0)
        self.hlayout.setSpacing(0)
        hs = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.hlayout.addItem(hs)
        return (menu)

    def addGroup(self, p_str, menu):
        group = GroupWidget(p_str, menu)
        group.setObjectName('group')
        insert_index = len(menu.findChildren(GroupWidget, 'group')) - 1
        self.hlayout.insertWidget(insert_index, group)
        return (group)

    def listGroups(self, menu):
        self.group_list = []
        for i in range(self.hlayout.count()):
            try:
                w = self.hlayout.itemAt(i).widget()
                self.group_list.append(w._title)
            except:
                AttributeError
        return (self.group_list)

    def addSliderChoiceWidget(self, menu):
        slider_choice = SliderChoiceWidget()
        insert_index = len(menu.findChildren(GroupWidget, 'group'))
        self.hlayout.insertWidget(insert_index, slider_choice)
        return (slider_choice)
示例#8
0
class ThumbnailRow(QWidget):

    def __init__(self):
        super().__init__()
        self.labels = []
        self.layout = QHBoxLayout()
        self.layout.setSpacing(3)
        self.layout.setContentsMargins(3, 0, 0, 3)
        self.setLayout(self.layout)
        self.items = []

    def add_items(self, items):
        self.items = items
        self.draw_items()

    def draw_items(self):
        self.clear()
        for item in self.items:
            thumbnail = Thumbnail(item)
            self.layout.addWidget(thumbnail, 0)
        self.layout.addWidget(QWidget(), 1)

    def clear(self):
        for i in reversed(range(self.layout.count())):
            widget = self.layout.itemAt(i).widget()
            # remove it from the layout list
            self.layout.removeWidget(widget)
            # remove it from the gui
            widget.setParent(None)

    def zoom(self, scale):
        for i in reversed(range(self.layout.count())):
            widget = self.layout.itemAt(i).widget()
            if isinstance(widget, Thumbnail):
                widget.zoom(scale)

    def mousePressEvent(self, a0: QtGui.QMouseEvent):
        print("Mouse Press")

    def mouseDoubleClickEvent(self, a0: QtGui.QMouseEvent):
        print("Mouse Double Click")
示例#9
0
class HorizontalImageScrollArea(QScrollArea):
    def __init__(self, parent=None):
        super(HorizontalImageScrollArea, self).__init__(parent)
        self.setWidgetResizable(True)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.setFrameShape(QFrame.NoFrame)

        self.layout = QHBoxLayout()

        scroll = QWidget()
        scroll.setLayout(self.layout)
        self.setWidget(scroll)

    def eventFilter(self, obj, event):
        if obj == self.widget() and event.type() == QEvent.Resize:
            self.widget().resize(self.calcNewSize())
            return True

        return super(HorizontalImageScrollArea, self).eventFilter(obj, event)

    def calcNewSize(self):
        height = self.viewport().height()

        layoutMargins = self.layout.contentsMargins()
        heightForCalc = height - layoutMargins.top() - layoutMargins.bottom()

        width = self.calcWidthForHeight(heightForCalc)
        return QSize(width, height)

    def calcWidthForHeight(self, height):
        width = 0
        for wgt in range(self.layout.count()):
            width += self.layout.itemAt(wgt).widget().widthForHeight(height)

        if self.layout.count() > 1:
            width += self.layout.spacing() * (self.layout.count() - 1)
        return width
示例#10
0
class MyRow(QWidget):

    def __init__(self, parent):
    
        super(MyRow,self).__init__(parent)
        self.__initUI()

    def __initUI(self):

        self.setStyleSheet('margin:1px;')
        self.layout = QHBoxLayout(self)
        self.layout.addStretch(1)
        pass

    def addWidget(self,item):

        self.layout.insertWidget(self.layout.count()-1,item)

        pass
示例#11
0
    def _init_info_ui(self):
        self._text_edit = QTextEdit()
        self._text_edit.setFixedHeight(80)
        self._text_edit.setReadOnly(True)
        button_create = QPushButton("Create")
        button_create.clicked.connect(self.button_create_clicked)
        button_upload = QPushButton("Upload")
        button_upload.clicked.connect(self.button_upload_clicked)

        vbox = QVBoxLayout()
        vbox.addWidget(button_create)
        vbox.addWidget(button_upload)

        hbox = QHBoxLayout()
        hbox.addWidget(self._text_edit)
        hbox.addLayout(vbox)

        for i in range(hbox.count()):
            hbox.setAlignment(hbox.itemAt(i).widget(), Qt.AlignTop)

        self.vbox.addLayout(hbox)
示例#12
0
class FileWidget(QWidget):
    """
    Represents a file.
    """
    def __init__(self,
                 source_db_object,
                 submission_db_object,
                 controller,
                 file_ready_signal,
                 align="left"):
        """
        Given some text, an indication of alignment ('left' or 'right') and
        a reference to the controller, make something to display a file.

        Align is set to left by default because currently SecureDrop can only
        accept files from sources to journalists.
        """
        super().__init__()
        self.controller = controller
        self.source = source_db_object
        self.submission = submission_db_object
        self.file_uuid = self.submission.uuid
        self.align = align

        self.layout = QHBoxLayout()
        self.update()
        self.setLayout(self.layout)

        file_ready_signal.connect(self._on_file_download)

    def update(self):
        icon = QLabel()
        icon.setPixmap(load_image('file.png'))

        if self.submission.is_downloaded:
            description = QLabel("Open")
        else:
            human_filesize = humanize_filesize(self.submission.size)
            description = QLabel("Download ({})".format(human_filesize))

        if self.align != "left":
            # Float right...
            self.layout.addStretch(5)

        self.layout.addWidget(icon)
        self.layout.addWidget(description, 5)

        if self.align == "left":
            # Add space on right hand side...
            self.layout.addStretch(5)

    def clear(self):
        while self.layout.count():
            child = self.layout.takeAt(0)
            if child.widget():
                child.widget().deleteLater()

    @pyqtSlot(str)
    def _on_file_download(self, file_uuid: str) -> None:
        if file_uuid == self.file_uuid:
            self.clear()  # delete existing icon and label
            self.update()  # draw modified widget

    def mouseReleaseEvent(self, e):
        """
        Handle a completed click via the program logic. The download state
        of the file distinguishes which function in the logic layer to call.
        """
        if self.submission.is_downloaded:
            # Open the already downloaded file.
            self.controller.on_file_open(self.submission)
        else:
            # Download the file.
            self.controller.on_file_download(self.source, self.submission)
示例#13
0
class ConfigUI(QWidget):

    configFilePath = ""
    parseConfigSignal = pyqtSignal(etree._Element)
    selectResGroupSignal = pyqtSignal(list)

    def __init__(self, parent=None):
        super(ConfigUI, self).__init__(parent)

        grid = QGridLayout()
        self.setLayout(grid)
        ##
        grid.addWidget(QLabel("配置文件:"), 0, 0)
        grid.addWidget(QLabel("资源分组:"), 1, 0)
        grid.addWidget(QLabel("数据编码:"), 2, 0)
        ##
        self.configFileLE = QLineEdit()
        # self.configFileLE.setEnabled(False)
        self.configFileLE.setFocusPolicy(Qt.NoFocus)
        grid.addWidget(self.configFileLE, 0, 1)
        browsePB = QPushButton("浏览")
        browsePB.clicked.connect(self.browse_config_path)
        grid.addWidget(browsePB, 0, 2)
        ##
        self.resGroupWidget = QWidget()
        self.resGroupLayout = QHBoxLayout()
        self.resGroupWidget.setLayout(self.resGroupLayout)
        grid.addWidget(self.resGroupWidget, 1, 1)
        selectPB = QPushButton("选择")
        selectPB.clicked.connect(self.select_res_group)
        grid.addWidget(selectPB, 1, 2)

    # def create_config

    def browse_config_path(self):
        open = QFileDialog()
        # self.configFilePath = open.getOpenFileUrl(None, "选择转换列表文件")
        self.configFilePath = open.getOpenFileName(None, "选择转换列表文件", "./")
        self.configFileLE.setText(self.configFilePath[0])
        if self.configFilePath[0] != "":
            list = etree.parse(self.configFilePath[0])
            root = list.getroot()
            for item in root:
                if item.tag == "ConvTree":
                    # 转换树
                    self.parseConfigSignal.emit(item)
                elif item.tag == "ResStyleList":
                    # 资源分组
                    self.parse_res_group(item)

            pass

    def select_res_group(self):
        groups = self.resGroupWidget.children()
        if len(groups) > 0:
            resGroupArr = []
            for item in groups:
                if isinstance(item, QCheckBox):
                    if item.isChecked():
                        resGroupArr.append(int(item.text().split(" ")[1]))
            self.selectResGroupSignal.emit(resGroupArr)

    def parse_res_group(self, item):
        while self.resGroupLayout.count():
            self.resGroupLayout.takeAt(0)

        for node in item:
            if node.tag != "ResStyle":
                continue

            print(node.attrib["Name"])
            checkBox = QCheckBox(node.attrib["Name"] + " " + str(node.attrib["ID"]))
            self.resGroupLayout.addWidget(checkBox)
        self.resGroupLayout.addStretch()
示例#14
0
class TaskGeneratorDialog(QDialog):
    def __init__(self, nbprocessors):
        QDialog.__init__(self)
        self.layout = QVBoxLayout(self)
        self.taskset = None

        # Utilizations:
        vbox_utilizations = QVBoxLayout()
        group = QGroupBox("Task Utilizations:")

        hbox = QHBoxLayout()
        hbox.addWidget(QLabel("Generator:", self))
        self.comboGenerator = QComboBox()
        self.comboGenerator.addItem("RandFixedSum")
        self.comboGenerator.addItem("UUniFast-Discard")
        self.comboGenerator.addItem("Kato's method")
        self.comboGenerator.currentIndexChanged.connect(self.generator_changed)
        hbox.addWidget(self.comboGenerator)
        vbox_utilizations.addLayout(hbox)

        # Load slider + spinner:
        hbox_load = QHBoxLayout()
        sld = _DoubleSlider(QtCore.Qt.Horizontal, self)
        sld.setMinimum(0)
        sld.setMaximum(32)
        self.spin_load = QDoubleSpinBox(self)
        self.spin_load.setMinimum(0)
        self.spin_load.setMaximum(32)
        self.spin_load.setSingleStep(0.1)
        hbox_load.addWidget(QLabel("Total utilization: ", self))
        hbox_load.addWidget(sld)
        hbox_load.addWidget(self.spin_load)
        sld.doubleValueChanged.connect(self.spin_load.setValue)
        self.spin_load.valueChanged.connect(sld.setValue)
        self.spin_load.setValue(nbprocessors / 2.)
        vbox_utilizations.addLayout(hbox_load)

        # Number of periodic tasks:
        self.hbox_tasks = QHBoxLayout()
        self.spin_tasks = QSpinBox(self)
        self.spin_tasks.setMinimum(0)
        self.spin_tasks.setMaximum(999)  # That's arbitrary.
        self.hbox_tasks.addWidget(QLabel("Number of periodic tasks: ", self))
        self.hbox_tasks.addStretch(1)
        self.hbox_tasks.addWidget(self.spin_tasks)
        vbox_utilizations.addLayout(self.hbox_tasks)

        # Number of sporadic tasks:
        self.hbox_sporadic_tasks = QHBoxLayout()
        self.spin_sporadic_tasks = QSpinBox(self)
        self.spin_sporadic_tasks.setMinimum(0)
        self.spin_sporadic_tasks.setMaximum(999)  # That's arbitrary.
        self.hbox_sporadic_tasks.addWidget(
            QLabel("Number of sporadic tasks: ", self))
        self.hbox_sporadic_tasks.addStretch(1)
        self.hbox_sporadic_tasks.addWidget(self.spin_sporadic_tasks)
        vbox_utilizations.addLayout(self.hbox_sporadic_tasks)

        # Min / Max utilizations
        self.hbox_utilizations = QHBoxLayout()
        self.hbox_utilizations.addWidget(QLabel("Min/Max utilizations: ",
                                                self))
        self.interval_utilization = IntervalSpinner(
            self, min_=0, max_=1, step=.01, round_option=False)
        self.hbox_utilizations.addWidget(self.interval_utilization)
        vbox_utilizations.addLayout(self.hbox_utilizations)

        group.setLayout(vbox_utilizations)
        self.layout.addWidget(group)

        # Periods:
        vbox_periods = QVBoxLayout()
        group = QGroupBox("Task Periods:")

        # Log uniform
        self.lunif = QRadioButton("log-uniform distribution between:")
        vbox_periods.addWidget(self.lunif)
        self.lunif.setChecked(True)

        self.lunif_interval = IntervalSpinner(self)
        self.lunif_interval.setEnabled(self.lunif.isChecked())
        self.lunif.toggled.connect(self.lunif_interval.setEnabled)
        vbox_periods.addWidget(self.lunif_interval)

        # Uniform
        self.unif = QRadioButton("uniform distribution between:")
        vbox_periods.addWidget(self.unif)

        self.unif_interval = IntervalSpinner(self)
        self.unif_interval.setEnabled(self.unif.isChecked())
        self.unif.toggled.connect(self.unif_interval.setEnabled)
        vbox_periods.addWidget(self.unif_interval)

        # Discrete
        discrete = QRadioButton("chosen among these (space separated) values:")
        vbox_periods.addWidget(discrete)

        self.periods = QLineEdit(self)
        self.periods.setValidator(QRegExpValidator(
            QRegExp("^\\d*(\.\\d*)?( \\d*(\.\\d*)?)*$")))

        vbox_periods.addWidget(self.periods)
        self.periods.setEnabled(discrete.isChecked())
        discrete.toggled.connect(self.periods.setEnabled)
        vbox_periods.addStretch(1)

        group.setLayout(vbox_periods)
        self.layout.addWidget(group)

        buttonBox = QDialogButtonBox()
        cancel = buttonBox.addButton(QDialogButtonBox.Cancel)
        generate = buttonBox.addButton("Generate", QDialogButtonBox.AcceptRole)
        cancel.clicked.connect(self.reject)
        generate.clicked.connect(self.generate)
        self.layout.addWidget(buttonBox)

        self.show_randfixedsum_options()

    def generator_changed(self, value):
        if value == 2:
            self.show_kato_options()
        else:
            self.show_randfixedsum_options()

    def show_randfixedsum_options(self):
        for i in range(self.hbox_utilizations.count()):
            self.hbox_utilizations.itemAt(i).widget().hide()
        for i in range(self.hbox_tasks.count()):
            if self.hbox_tasks.itemAt(i).widget():
                self.hbox_tasks.itemAt(i).widget().show()
        for i in range(self.hbox_sporadic_tasks.count()):
            if self.hbox_sporadic_tasks.itemAt(i).widget():
                self.hbox_sporadic_tasks.itemAt(i).widget().show()

    def show_kato_options(self):
        for i in range(self.hbox_utilizations.count()):
            if self.hbox_utilizations.itemAt(i).widget():
                self.hbox_utilizations.itemAt(i).widget().show()
        for i in range(self.hbox_tasks.count()):
            if self.hbox_tasks.itemAt(i).widget():
                self.hbox_tasks.itemAt(i).widget().hide()
        for i in range(self.hbox_sporadic_tasks.count()):
            if self.hbox_sporadic_tasks.itemAt(i).widget():
                self.hbox_sporadic_tasks.itemAt(i).widget().hide()

    def get_min_utilization(self):
        return self.interval_utilization.getMin()

    def get_max_utilization(self):
        return self.interval_utilization.getMax()

    def generate(self):

        n = self.get_nb_tasks()
        if (n == 0):
            QMessageBox.warning(
                    self, "Generation failed",
                    "Please check the utilization and the number of tasks.")
            return

        if self.comboGenerator.currentIndex() == 0:
            u = StaffordRandFixedSum(n, self.get_utilization(), 1)
        elif self.comboGenerator.currentIndex() == 1:
            u = UUniFastDiscard(n, self.get_utilization(), 1)
        else:
            u = gen_kato_utilizations(1, self.get_min_utilization(),
                                      self.get_max_utilization(),
                                      self.get_utilization())
            n = len(u[0])

        p_types = self.get_periods()
        if p_types[0] == "unif":
            p = gen_periods_uniform(n, 1, p_types[1], p_types[2], p_types[3])
        elif p_types[0] == "lunif":
            p = gen_periods_loguniform(n, 1, p_types[1], p_types[2],
                                       p_types[3])
        else:
            p = gen_periods_discrete(n, 1, p_types[1])
            
        if u and p:
            self.taskset = gen_tasksets(u, p)[0]
            self.accept()
        elif not u:
            QMessageBox.warning(
                self, "Generation failed",
                "Please check the utilization and the number of tasks.")
        else:
            QMessageBox.warning(
                self, "Generation failed",
                "Pleache check the periods.")

    def get_nb_tasks(self):
        return self.spin_tasks.value() + self.spin_sporadic_tasks.value()

    def get_nb_periodic_tasks(self):
        return self.spin_tasks.value()

    def get_nb_sporadic_tasks(self):
        return self.spin_sporadic_tasks.value()

    def get_utilization(self):
        return self.spin_load.value()

    def get_periods(self):
        if self.unif.isChecked():
            return ("unif", self.unif_interval.getMin(),
                    self.unif_interval.getMax(), self.unif_interval.getRound())
        elif self.lunif.isChecked():
            return ("lunif", self.lunif_interval.getMin(),
                    self.lunif_interval.getMax(),
                    self.lunif_interval.getRound())
        else:
            return ("discrete", map(float, str(self.periods.text()).split()))
示例#15
0
class ChurchUI:
    def __init__(self, window, church, target_layout):
        self.church = church
        self.target_layout = target_layout
        self.window = window
        self.layout = None
        self.church_button = None
        self.del_button = None
        self.edit_button = None
        self.church_text = None
        self.place_text = None
        self.msg = None
        self.student_ui = None

        self.create()

    def create(self):
        self.layout = QHBoxLayout()
        self.layout.setSpacing(2)

        # Create Church Button
        self.church_button = Button(self.church.get_name(),
                                    width=None,
                                    height=40)
        self.church_button.align_text()

        # Create church Text
        self.church_text = TextBox(self.church.name, height=40)

        # Create Place Text
        self.place_text = TextBox(self.church.place, height=40)

        # Create Edit Button
        self.edit_button = Button('EDIT', width=40, height=40)

        # Create Del button
        self.del_button = Button('DEL', width=40, height=40)

        self.layout.addWidget(self.church_text)
        self.layout.addWidget(self.place_text)
        self.layout.addWidget(self.church_button)
        self.layout.addWidget(self.edit_button)
        self.layout.addWidget(self.del_button)

        self.target_layout.insertLayout(self.target_layout.count() - 1,
                                        self.layout)

        self.church_button.clicked.connect(self.select)
        self.church_text.returnPressed.connect(self.finish_edit)
        self.place_text.returnPressed.connect(self.finish_edit)
        self.edit_button.clicked.connect(self.edit)
        self.del_button.clicked.connect(self.passive_delete)

    def delete(self):
        if self.layout is not None:
            while self.layout.count():
                item = self.layout.takeAt(0)
                widget = item.widget()
                if widget is not None:
                    widget.deleteLater()
                else:
                    pass
            self.church.delete()
            del self

    def hide(self):
        pass

    def select(self):
        try:
            if not self.student_ui:
                self.student_ui = student.Students(self.window, self.church)

            data.selection.select(self.student_ui)
        except Exception as e:
            print(e)

    def deselect(self):
        self.window.setCentralWidget(None)

    def passive_delete(self):
        self.msg = display.QuestionMessageBox(
            self.window, 'Delete Church', 'Do You want to delete church ' +
            self.church.name + ' and all the students?', self.delete)

    def edit(self):
        if self.church_button.isVisible():
            data.editing.start_edit(self)
        else:
            data.editing.finish_edit()

    def start_edit(self):
        self.church_button.hide()
        # self.box_layout
        self.church_text.show()
        self.place_text.show()

    def finish_edit(self):
        if self.church_text.text() and self.place_text.text():
            self.church_text.hide()
            self.place_text.hide()
            self.church.name = self.church_text.text()
            self.church.place = self.place_text.text()
            self.church_button.setText(self.church.get_name())
            self.church_button.show()

    def revert_edit(self):
        self.church_text.hide()
        self.place_text.hide()
        self.church_button.setText(self.church_text.text() + ', ' +
                                   self.place_text.text())
        self.church_button.show()
class LibraryWidget(QWidget):
    def __init__(self, parent, item, link, list_widget, show_new=False):
        super(LibraryWidget, self).__init__(None)

        self.parent = parent
        self.item = item
        self.link = link
        self.list_widget = list_widget
        self.show_new = show_new
        self.observer = None
        self.build_info = None

        self.destroyed.connect(lambda: self._destroyed())
        self.setEnabled(False)

        self.layout = QHBoxLayout()
        self.layout.setContentsMargins(2, 2, 2, 2)
        self.setLayout(self.layout)

        self.infoLabel = QLabel("Loading build information...")

        self.launchButton = QPushButton("Launch")
        self.launchButton.setMinimumWidth(75)
        self.launchButton.setProperty("CancelButton", True)

        self.layout.addWidget(self.launchButton)
        self.layout.addWidget(self.infoLabel, stretch=1)

        self.thread = BuildInfoReader(link)
        self.thread.finished.connect(self.draw)
        self.thread.start()

        self.item.setSizeHint(self.sizeHint())

    def draw(self, build_info):
        if build_info is None:
            self.infoLabel.setText(
                ("Build *{0}* is damaged!").format(Path(self.link).name))
            self.launchButton.setText("Delete")
            self.launchButton.clicked.connect(self.ask_remove_from_drive)
            self.setEnabled(True)
            return

        for i in reversed(range(self.layout.count())):
            self.layout.itemAt(i).widget().setParent(None)

        self.build_info = build_info
        self.branch = self.build_info.branch
        self.item.date = build_info.commit_time

        self.icon_favorite = QIcon(":resources/icons/favorite.svg")
        self.icon_fake = QIcon(":resources/icons/fake.svg")
        self.icon_delete = QIcon(":resources/icons/delete.svg")

        self.launchButton = QPushButton("Launch")
        self.launchButton.setMinimumWidth(75)
        self.launchButton.setProperty("LaunchButton", True)

        self.subversionLabel = QLabel()
        self.branchLabel = QLabel()
        self.commitTimeLabel = QLabel()
        self.buildHashLabel = QLabel()

        self.countButton = QPushButton("0")
        self.countButton.setEnabled(False)
        self.countButton.setProperty("Count", True)
        self.countButton.hide()
        self.countButton.setFixedSize(24, 24)

        self.widgetFavorite = QPushButton()
        self.widgetFavorite.setEnabled(False)
        self.widgetFavorite.setFixedSize(24, 24)
        self.widgetFavorite.setIcon(self.icon_fake)
        self.widgetFavorite.setProperty("Icon", True)

        self.layout.addWidget(self.launchButton)
        self.layout.addWidget(self.subversionLabel)
        self.layout.addWidget(self.branchLabel)
        self.layout.addWidget(self.commitTimeLabel)
        self.layout.addWidget(self.buildHashLabel)
        self.layout.addStretch()
        self.layout.addWidget(self.countButton)
        self.layout.addWidget(self.widgetFavorite)

        self.launchButton.clicked.connect(self.launch)
        self.subversionLabel.setText(self.build_info.subversion)

        if self.branch == 'lts':
            branch_name = "LTS"
        else:
            branch_name = self.branch.replace('-', ' ').title()

        self.branchLabel.setText(branch_name)

        self.commitTimeLabel.setText(self.build_info.commit_time)
        self.buildHashLabel.setText(self.build_info.build_hash)

        # Context menu
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.context_menu)

        self.menu = QMenu()
        self.menu.setFont(self.parent.font)

        self.menu_extended = QMenu()
        self.menu_extended.setFont(self.parent.font)

        self.deleteAction = QAction("Delete From Drive", self)
        self.deleteAction.setIcon(self.icon_delete)
        self.deleteAction.triggered.connect(self.ask_remove_from_drive)

        self.setAsFavoriteAction = QAction("Mark As Favorite", self)
        self.setAsFavoriteAction.setIcon(self.icon_favorite)
        self.setAsFavoriteAction.triggered.connect(self.set_favorite)

        self.registerExtentionAction = QAction("Register Extension")
        self.registerExtentionAction.triggered.connect(self.register_extension)

        self.createShortcutAction = QAction("Create Shortcut")
        self.createShortcutAction.triggered.connect(self.create_shortcut)

        self.showFolderAction = QAction("Show Folder")
        self.showFolderAction.triggered.connect(self.show_folder)

        self.createSymlinkAction = QAction("Create Symlink")
        self.createSymlinkAction.triggered.connect(self.create_symlink)

        self.menu.addAction(self.setAsFavoriteAction)

        if get_platform() == 'Windows':
            self.menu.addAction(self.registerExtentionAction)

        self.menu.addAction(self.createShortcutAction)
        self.menu.addAction(self.createSymlinkAction)
        self.menu.addAction(self.showFolderAction)
        self.menu.addAction(self.deleteAction)

        self.menu_extended.addAction(self.deleteAction)

        if self.show_new:
            self.NewItemLabel = QLabel("New")
            self.NewItemLabel.setAlignment(Qt.AlignRight | Qt.AlignCenter)
            self.NewItemLabel.setIndent(6)
            self.layout.addWidget(self.NewItemLabel)

            if get_mark_as_favorite() == 0:
                pass
            elif (get_mark_as_favorite() == 1 and self.branch == "stable"):
                self.set_favorite()
            elif (get_mark_as_favorite() == 2 and self.branch == "daily"):
                self.set_favorite()
            elif get_mark_as_favorite() == 3:
                self.set_favorite()
        elif get_favorite_path() == self.link:
            self.set_favorite()

        self.setEnabled(True)
        self.list_widget.sortItems()
        self.list_widget.resize_labels(
            ('subversionLabel', 'branchLabel',
             'commitTimeLabel', 'buildHashLabel'))

    def context_menu(self):
        if len(self.list_widget.selectedItems()) > 1:
            self.menu_extended.exec_(QCursor.pos())
            return

        link_path = Path(get_library_folder()) / "bl_symlink"
        link = link_path.as_posix()

        if os.path.exists(link):
            if (os.path.isdir(link) or os.path.islink(link)):
                if link_path.resolve() == self.link:
                    self.createSymlinkAction.setEnabled(False)
                    self.menu.exec_(QCursor.pos())
                    return

        self.createSymlinkAction.setEnabled(True)
        self.menu.exec_(QCursor.pos())

    def mouseDoubleClickEvent(self, event):
        if self.build_info is not None:
            self.launch()

    def mouseReleaseEvent(self, event):
        if event.button == Qt.LeftButton:
            if hasattr(self, "NewItemLabel"):
                self.NewItemLabel.hide()

            mod = QApplication.keyboardModifiers()
            if not (mod == Qt.ShiftModifier or mod == Qt.ControlModifier):
                self.list_widget.clearSelection()
                self.item.setSelected(True)

            event.accept()

        event.ignore()

    @QtCore.pyqtSlot()
    def launch(self):
        self.item.setSelected(True)

        if hasattr(self, "NewItemLabel"):
            self.NewItemLabel.hide()

        platform = get_platform()
        library_folder = Path(get_library_folder())

        if platform == 'Windows':
            b3d_exe = library_folder / self.link / "blender.exe"
            proc = _popen(b3d_exe.as_posix())
        elif platform == 'Linux':
            b3d_exe = library_folder / self.link / "blender"
            proc = _popen('nohup "' + b3d_exe.as_posix() + '"')

        if self.observer is None:
            self.observer = Observer(self)
            self.observer.count_changed.connect(self.proc_count_changed)
            self.observer.started.connect(self.observer_started)
            self.observer.finished.connect(self.observer_finished)
            self.observer.start()

        self.observer.append_proc(proc)

    def proc_count_changed(self, count):
        self.countButton.setText(str(count))

    def observer_started(self):
        self.countButton.show()
        self.deleteAction.setEnabled(False)

    def observer_finished(self):
        self.observer = None
        self.countButton.hide()
        self.deleteAction.setEnabled(True)

    @QtCore.pyqtSlot()
    def ask_remove_from_drive(self):
        self.item.setSelected(True)
        self.dlg = DialogWindow(
            self.parent, title="Warning",
            text="Are you sure you want to<br>delete selected builds?",
            accept_text="Yes", cancel_text="No", icon=DialogIcon.WARNING)

        if len(self.list_widget.selectedItems()) > 1:
            self.dlg.accepted.connect(self.remove_from_drive_extended)
        else:
            self.dlg.accepted.connect(self.remove_from_drive)

    @QtCore.pyqtSlot()
    def remove_from_drive_extended(self):
        for item in self.list_widget.selectedItems():
            self.list_widget.itemWidget(item).remove_from_drive()

    @QtCore.pyqtSlot()
    def remove_from_drive(self):
        self.launchButton.setText("Deleting")
        self.setEnabled(False)
        self.item.setFlags(self.item.flags() & ~Qt.ItemIsSelectable)
        path = Path(get_library_folder()) / self.link
        self.remover = Remover(path)
        self.remover.finished.connect(self.remover_finished)
        self.remover.start()

    def remover_finished(self, code):
        if code == 0:
            self.parent.draw_from_cashed(self.build_info)
            self.list_widget.remove_item(self.item)
            return
        else:
            self.launchButton.setText("Launch")
            self.setEnabled(True)
            return

    @QtCore.pyqtSlot()
    def set_favorite(self):
        set_favorite_path(self.link)

        if self.parent.favorite is not None:
            self.parent.favorite.widgetFavorite.setIcon(self.icon_fake)
            self.parent.favorite.setAsFavoriteAction.setVisible(True)

        self.parent.favorite = self
        self.widgetFavorite.setIcon(self.icon_favorite)
        self.setAsFavoriteAction.setVisible(False)

    @QtCore.pyqtSlot()
    def register_extension(self):
        path = Path(get_library_folder()) / self.link
        self.register = Register(path)
        self.register.start()

    @QtCore.pyqtSlot()
    def create_shortcut(self):
        name = "Blender {0} {1}".format(
            self.build_info.subversion.replace('(', '').replace(')', ''),
            self.build_info.branch.replace('-', ' ').title())

        create_shortcut(self.link, name)

    @QtCore.pyqtSlot()
    def create_symlink(self):
        target = self.link.as_posix()
        link = (Path(get_library_folder()) / "bl_symlink").as_posix()
        platform = get_platform()

        if platform == 'Windows':
            if os.path.exists(link):
                if os.path.isdir(link):
                    os.rmdir(link)

            _check_call('mklink /J "{0}" "{1}"'.format(link, target))
        elif platform == 'Linux':
            if os.path.exists(link):
                if os.path.islink(link):
                    os.unlink(link)

            os.symlink(target, link)

    @QtCore.pyqtSlot()
    def show_folder(self):
        platform = get_platform()
        library_folder = Path(get_library_folder())
        folder = library_folder / self.link

        if platform == 'Windows':
            os.startfile(folder.as_posix())
        elif platform == 'Linux':
            subprocess.call(["xdg-open", folder.as_posix()])

    def _destroyed(self):
        if self.parent.favorite == self:
            self.parent.favorite = None
示例#17
0
文件: E-Mapp.py 项目: MERTULAS/E-Mapp
class Window(QWidget):
    def __init__(self, login_id, login_password):
        super().__init__()
        self.id = login_id
        self.password = login_password
        self.inbox = ""
        self.init_ui()

    def inbox_mails(self, mail):
        self.incoming_mail = QGroupBox()
        self.incoming_mail_group = QVBoxLayout(self.incoming_mail)
        self.inbox_subject = QLabel("Subject: " + mail[0])
        self.inbox_from = QLabel("From: " + mail[1])
        self.incoming_mail_group.addWidget(self.inbox_subject)
        self.incoming_mail_group.addWidget(self.inbox_from)
        self.box_palette = QPalette()
        self.box_palette.setColor(QPalette.Background, QColor(100, 100, 100))
        self.setPalette(self.box_palette)
        return self.incoming_mail

    def inbox_container(self):
        self.scrollArea = QScrollArea(self)
        self.scrollArea.setMaximumWidth(250)
        self.scrollArea.setMinimumWidth(100)
        self.scrollArea.setWidgetResizable(True)
        self.widget = QWidget()
        self.scrollArea.setWidget(self.widget)
        self.layoutScrollArea = QVBoxLayout()
        self.inbox = MailSettings.inbox_getter(self.id, self.password)
        for index, mail_in_inbox in enumerate(self.inbox):
            self.layoutScrollArea.addWidget(self.inbox_mails(mail_in_inbox))
        self.widget.setLayout(self.layoutScrollArea)

    def init_ui(self):
        self.mail_address = QLineEdit()
        self.send_button = QPushButton("Send!")
        self.mail_text = QTextEdit()
        self.mail_subject = QLineEdit()
        self.label_to = QLabel("To:")
        self.label_subject = QLabel("Subject:")
        self.label_text = QLabel("Text:")
        self.label_text.setFixedWidth(50)
        self.attached_file_paths = []
        self.warning_label = QLabel("")
        self.warning_label_head = QLabel("")
        self.hidden_inbox_button = QPushButton("<", self)
        self.hidden_inbox_button.setFixedSize(30, 70)
        self.file_open_button = QPushButton("Attach")
        self.file_open_button.setIcon(QIcon('attach-paperclip-symbol.png'))
        self.delete_all_files = QPushButton("Delete All")
        self.delete_all_files.hide()

        self.delete_all_files.clicked.connect(self.del_all_files)
        self.hidden_inbox_button.clicked.connect(self.hidden_inbox)
        self.file_open_button.clicked.connect(self.file_open)

        v_box1 = QVBoxLayout()
        v_box1.addWidget(self.label_to)
        v_box1.addWidget(self.label_subject)

        v_box2 = QVBoxLayout()
        v_box2.addWidget(self.mail_address)
        v_box2.addWidget(self.mail_subject)

        h_box1 = QHBoxLayout()
        h_box1.addLayout(v_box1)
        h_box1.addLayout(v_box2)

        h_box2 = QHBoxLayout()
        h_box2.addWidget(self.label_text)
        h_box2.addWidget(self.mail_text)

        v_box_attach = QVBoxLayout()
        v_box_attach.addWidget(self.file_open_button)

        self.h_box_files = QHBoxLayout()

        h_box3 = QHBoxLayout()
        h_box3.addLayout(self.h_box_files)
        h_box3.addStretch()
        h_box3.addWidget(self.delete_all_files)
        h_box3.addWidget(self.file_open_button)

        self.v_box = QVBoxLayout()
        self.v_box.addLayout(h_box1)
        self.v_box.addLayout(h_box2)
        self.v_box.addLayout(h_box3)
        self.v_box.addWidget(self.warning_label_head)
        self.v_box.addWidget(self.warning_label)
        self.v_box.addWidget(self.send_button, 10)

        self.inbox_container()
        h_box4 = QHBoxLayout()
        h_box4.addWidget(self.scrollArea)
        h_box4.addWidget(self.hidden_inbox_button)

        h_box5 = QHBoxLayout()
        h_box5.addLayout(h_box4)
        h_box5.addLayout(self.v_box)
        self.setLayout(h_box5)
        self.send_button.clicked.connect(self.send)

    def send(self):
        to = self.mail_address.text()
        subject = self.mail_subject.text()
        text = self.mail_text.toPlainText()
        file = self.attached_file_paths
        mail = MailSettings(to, subject, text, file, self.id, self.password)
        warnings = mail.mail_sender()
        if warnings:
            warning = "\n".join(warnings)
            self.warning_label_head.setText("Invalid e-mail addresses:\n")
            self.warning_label_head.setStyleSheet(
                "color: red; border: 2px solid red; border-radius: 5px")
            self.warning_label.setText(warning)

    def hidden_inbox(self):
        if self.scrollArea.isHidden():
            self.scrollArea.show()
            self.hidden_inbox_button.setText("<")
            self.setGeometry(self.x() + 1,
                             self.y() + 1,
                             self.width() + 1,
                             self.height() + 1)
            self.update()
        else:
            self.scrollArea.hide()
            self.hidden_inbox_button.setText(">")
            self.setGeometry(self.x() + 1,
                             self.y() + 1,
                             self.width() + 1,
                             self.height() + 1)
            self.update()

    def file_open(self):
        file_name = QFileDialog.getOpenFileName(self, "Select File",
                                                os.getenv("HOME"))
        if file_name[0] not in self.attached_file_paths and file_name[0] != "":
            self.attached_file_paths.append(str(file_name[0]))
            self.h_box_files.addWidget(
                QLabel("{}-)".format(len(self.attached_file_paths)) +
                       file_name[0].split("/")[-1] + " "))
            # print(self.attached_file_paths)
            self.delete_all_files.show()
        else:
            pass

    def del_all_files(self):
        self.attached_file_paths = []
        self.delete_all_files.hide()
        for i in reversed(range(self.h_box_files.count())):
            self.h_box_files.itemAt(i).widget().setParent(None)
        self.setGeometry(self.x() + 1,
                         self.y() + 1,
                         self.width() + 1,
                         self.height() + 1)
        self.update()
示例#18
0
文件: gui.py 项目: Gareth001/500
class Controller(QWidget):
    def __init__(self):
        super().__init__()

        # game details
        self._player = 0
        self._players = None
        self._round = None
        self._cards_played = 0

        # child processes
        self._server = None
        self._client = None
        self._parent_conn = None  # connection to child

        # set graphics properties
        self.setWindowTitle('500')
        self.setGeometry(50, 50, WIDTH, HEIGHT)
        self.setFixedSize(self.size())

        # check for background image
        if os.path.exists("bkg.jpg"):
            bg = QtGui.QPixmap("bkg.jpg")
            palette = QtGui.QPalette()
            palette.setBrush(10, QtGui.QBrush(bg))
            self.setPalette(palette)

        else:
            print(
                "No background image found. Copy bkg.jpg to the directory to add one."
            )

        # default font
        self.setFont(QtGui.QFont("Book Antiqua", 11, QtGui.QFont.Bold))

        # create main menu
        self._main_menu = QWidget()
        self.create_main_menu_view()

        # create game options view
        self._options_type = None  # which options screen to display
        self._port = None
        self._username = None
        self._ip = None
        self._password = None
        self._player_types = [None] * 3
        self._game_options_view = QWidget()
        self.create_game_options_view()

        # create game view
        self._game_view = QWidget()
        self._card_layout = [None] * NUMBER_PLAYERS  # array of players cards
        self._played_cards = None  # four cards in center of screen
        self._player_info = [None
                             ] * NUMBER_PLAYERS  # info label for each player
        self._bet_controls = []
        self._card_winning = None
        self.create_game_view()

        # create stacked layout
        self._stacked_layout = QStackedWidget(self)
        self._stacked_layout.addWidget(self._main_menu)
        self._stacked_layout.addWidget(self._game_options_view)
        self._stacked_layout.addWidget(self._game_view)

        self.show()

    # create main menu and add it to _main_menu layout
    def create_main_menu_view(self):

        menu = QVBoxLayout()
        menu.setAlignment(QtCore.Qt.AlignHCenter)
        menu.addStretch(1)

        # create a pretty title layout
        title_layout = QHBoxLayout()
        title_layout.addStretch(1)

        # add some bowers for nice looks
        svgWidget = QtSvg.QSvgWidget('img/JH.svg')
        svgWidget.setMinimumHeight(CARD_HEIGHT)
        svgWidget.setMaximumHeight(CARD_HEIGHT)
        svgWidget.setMinimumWidth(CARD_WIDTH)
        svgWidget.setMaximumWidth(CARD_WIDTH)
        title_layout.addWidget(svgWidget)
        title_layout.addStretch(1)

        # create title
        title = QLabel("500 Online!")
        font = QtGui.QFont("Book Antiqua", 50, QtGui.QFont.Bold)
        title.setFont(font)
        title_layout.addWidget(title)
        title_layout.addStretch(1)

        svgWidget = QtSvg.QSvgWidget('img/JD.svg')
        svgWidget.setMinimumHeight(CARD_HEIGHT)
        svgWidget.setMaximumHeight(CARD_HEIGHT)
        svgWidget.setMinimumWidth(CARD_WIDTH)
        svgWidget.setMaximumWidth(CARD_WIDTH)
        title_layout.addWidget(svgWidget)

        title_layout.addStretch(1)
        menu.addLayout(title_layout)
        menu.addStretch(1)

        # create layout
        layout = QVBoxLayout()
        layout.setAlignment(QtCore.Qt.AlignCenter)

        # bots button
        button = QPushButton('Play against bots', self)
        button.clicked.connect(lambda: self.goto_game_options(0))
        layout.addWidget(button)

        # join server
        button = QPushButton('Join a server', self)
        button.clicked.connect(lambda: self.goto_game_options(1))
        layout.addWidget(button)

        # host and play
        button = QPushButton('Host and play', self)
        button.clicked.connect(lambda: self.goto_game_options(2))
        layout.addWidget(button)

        # options TODO
        # button = QPushButton('Options', self)
        # layout.addWidget(button)

        # exit
        button = QPushButton('Exit', self)
        button.clicked.connect(self.close)
        layout.addWidget(button)

        menu.addLayout(layout)
        menu.addStretch(2)

        # title = QLabel("By Gareth Booth") TODO
        # font = QtGui.QFont("Book Antiqua", 8, QtGui.QFont.Bold)
        # title.setFont(font)
        # menu.addWidget(title)

        # add to layout
        self._main_menu.setLayout(menu)

    # go to the game options screen
    # type is which screen button you came from:
    # 0 for bots
    # 1 for join server
    # 2 for host and play
    def goto_game_options(self, options_type):
        self._options_type = options_type
        self._stacked_layout.setCurrentIndex(1)
        self.reset_game_options()

        # hide layouts depending on which options type we are
        if options_type == 0:
            self._ip.hide()
            self._password.hide()
            for index in range(0, 3):
                self._player_types[index].hide()

        elif options_type == 1:
            for index in range(0, 3):
                self._player_types[index].hide()

        elif options_type == 2:
            self._ip.hide()

    # unhide all game options (note port and username are never hidden)
    def reset_game_options(self):
        self._ip.show()
        self._password.show()
        for index in range(0, 3):
            self._player_types[index].show()

    # create the options for joining game menu
    def create_game_options_view(self):
        # create layout
        layout = QVBoxLayout()
        layout.setAlignment(QtCore.Qt.AlignCenter)

        # username
        edit = QLineEdit()
        edit.setText("Jimmy")
        edit.setMaximumWidth(200)
        self._username = QWidget()
        self._username.setLayout(create_menu_entry("Username: "******"Port: ", port))
        layout.addWidget(self._port)

        # ip
        ip = QLineEdit()
        ip.setMaximumWidth(200)
        self._ip = QWidget()
        self._ip.setLayout(create_menu_entry("Ip Address: ", ip))
        layout.addWidget(self._ip)

        # password
        password = QLineEdit()
        password.setMaximumWidth(200)
        self._password = QWidget()
        self._password.setLayout(create_menu_entry("Password: "******"Human", "lvl 1 bot", "lvl 2 bot"])
            player_type.setMaximumWidth(200)
            self._player_types[index] = QWidget()
            self._player_types[index].setLayout(
                create_menu_entry("Player " + str(index + 2) + " is a :",
                                  player_type))
            layout.addWidget(self._player_types[index])

        # join button
        button = QPushButton('Go', self)
        button.clicked.connect(self.create_game)
        layout.addWidget(button)

        # back button
        button = QPushButton('Back to Menu', self)
        button.clicked.connect(lambda: self._stacked_layout.setCurrentIndex(0))
        layout.addWidget(button)

        # create layout with stretch to force center the controls
        hcentered_layout = QHBoxLayout()
        hcentered_layout.addStretch(1)
        hcentered_layout.addLayout(layout)
        hcentered_layout.addStretch(1)

        self._game_options_view.setLayout(hcentered_layout)

    # returns username from the game options screen
    def get_username(self):
        return self._username.layout().itemAt(1).widget().text()

    # returns port from the game options screen
    def get_port(self):
        return self._port.layout().itemAt(1).widget().value()

    # returns password from the game options screen
    def get_password(self):
        return self._password.layout().itemAt(1).widget().text()

    # returns password from the game options screen
    def get_ip(self):
        return self._ip.layout().itemAt(1).widget().text()

    # returns player type from the game options screen for given player
    def get_player_type(self, index):
        return self._player_types[index].layout().itemAt(
            1).widget().currentIndex()

    # creates game view and adds it to _game_view layout
    def create_game_view(self):
        # layout
        game_layout = QVBoxLayout()

        self._card_layout[2] = QHBoxLayout()
        # create card iamges for teammate
        for _ in range(0, 10):
            svgWidget = QtSvg.QSvgWidget('img/BACK.svg')
            svgWidget.setFixedSize(CARD_WIDTH, CARD_HEIGHT)
            self._card_layout[2].addWidget(svgWidget)

        # add this card layout
        game_layout.addLayout(self._card_layout[2])

        # Hbox for center of the screen
        middle_layout = QHBoxLayout()

        # player on other team
        self._card_layout[1] = QVBoxLayout()
        self._card_layout[1].setAlignment(QtCore.Qt.AlignLeft)

        for _ in range(0, 10):
            svgWidget = QtSvg.QSvgWidget('img/BACK.svg')
            svgWidget.setFixedSize(CARD_WIDTH / 2, CARD_HEIGHT / 2)
            self._card_layout[1].addWidget(svgWidget)

        # add this card layout
        middle_layout.addLayout(self._card_layout[1])

        # add other team info label
        self._player_info[1] = QLabel(self)
        self._player_info[1].setAlignment(QtCore.Qt.AlignLeft
                                          | QtCore.Qt.AlignVCenter)
        middle_layout.addWidget(self._player_info[1])

        # layout in middle center (for teammate and your info)
        middle_center_layout = QVBoxLayout()

        # add teammate info label
        self._player_info[2] = QLabel(self)
        self._player_info[2].setAlignment(QtCore.Qt.AlignTop
                                          | QtCore.Qt.AlignHCenter)
        middle_center_layout.addWidget(self._player_info[2])

        middle_center_layout.addStretch(1)

        # add where the 4 cards will go during play
        self._played_cards = QHBoxLayout()
        for _ in range(0, NUMBER_PLAYERS):

            # layout containing this tricks details
            sublayout = QVBoxLayout()
            sublayout.setAlignment(QtCore.Qt.AlignVCenter)

            # text
            top_text = QLabel()
            sublayout.addWidget(top_text)

            # card image
            svgWidget = QtSvg.QSvgWidget('img/BACK.svg')
            svgWidget.setFixedSize(CARD_WIDTH, CARD_HEIGHT)
            sublayout.addWidget(svgWidget)

            # text
            bottom_text = QLabel()
            sublayout.addWidget(bottom_text)

            self._played_cards.addLayout(sublayout)

        # add this card layout
        middle_center_layout.addLayout(self._played_cards)

        middle_center_layout.addStretch(1)

        # add player info label
        self._player_info[0] = QLabel(self)
        self._player_info[0].setAlignment(QtCore.Qt.AlignBottom
                                          | QtCore.Qt.AlignCenter)
        middle_center_layout.addWidget(self._player_info[0])

        # add middle center layout to middle layout
        middle_layout.addLayout(middle_center_layout)

        # add other team info label
        self._player_info[3] = QLabel(self)
        self._player_info[3].setAlignment(QtCore.Qt.AlignRight
                                          | QtCore.Qt.AlignVCenter)
        middle_layout.addWidget(self._player_info[3])

        # set player info as waiting
        for index in range(0, 4):
            self._player_info[index].setText("Waiting for player")

        self._card_layout[3] = QVBoxLayout()
        self._card_layout[3].setAlignment(QtCore.Qt.AlignRight)
        # create card iamges for other team
        for _ in range(0, 10):
            svgWidget = QtSvg.QSvgWidget('img/BACK.svg')
            svgWidget.setFixedSize(CARD_WIDTH / 2, CARD_HEIGHT / 2)
            self._card_layout[3].addWidget(svgWidget)

        # add this card layout
        middle_layout.addLayout(self._card_layout[3])

        # add the middle layout
        game_layout.addLayout(middle_layout)

        # create card iamges for player
        self._card_layout[0] = QHBoxLayout()
        self._card_layout[0].setAlignment(QtCore.Qt.AlignBottom)
        for index in range(0, 13):
            svgWidget = QtSvg.QSvgWidget('img/BACK.svg')
            svgWidget.setFixedSize(CARD_WIDTH, CARD_HEIGHT)

            if index >= 10:
                svgWidget.hide()

            self._card_layout[0].addWidget(svgWidget)

        # add this card layout
        game_layout.addLayout(self._card_layout[0])

        # add to layout
        game_layout.addLayout(self.create_bet_controls())
        self._game_view.setLayout(game_layout)

    # returns layout containing all bet controls
    def create_bet_controls(self):
        # create layout for betting actions
        layout = QHBoxLayout()

        # number bet choice button
        number_bet = QComboBox()
        number_bet.addItems(["6", "7", "8", "9", "10"])
        layout.addWidget(number_bet)
        self._bet_controls.append(number_bet)

        # suit bet choice button
        suit_bet = QComboBox()
        suit_bet.addItems(
            ["Spades", "Clubs", "Diamonds", "Hearts", "No Trumps"])
        layout.addWidget(suit_bet)
        self._bet_controls.append(suit_bet)

        # bet button, sends bet based on what we entered in the choice boxes above
        button = QPushButton('Bet', self)
        button.clicked.connect(lambda: self.send_to_client(
            number_bet.currentText() + suit_to_letter(suit_bet.currentText())))
        layout.addWidget(button)
        self._bet_controls.append(button)

        # pass button
        button = QPushButton('Pass', self)
        button.clicked.connect(lambda: self.send_to_client("PASS"))
        layout.addWidget(button)
        self._bet_controls.append(button)

        # misere button
        button = QPushButton('Bet Misere', self)
        button.clicked.connect(lambda: self.send_to_client("MISERE"))
        layout.addWidget(button)
        self._bet_controls.append(button)

        # open misere button (TODO functionality, such as seeing persons hand)
        button = QPushButton('Bet Open Misere', self)
        button.clicked.connect(lambda: self.send_to_client("OPENMISERE"))
        layout.addWidget(button)
        self._bet_controls.append(button)

        layout.addStretch(1)

        # main menu button
        button = QPushButton('Exit to menu', self)
        layout.addWidget(button)
        button.clicked.connect(lambda: self.exit_to_menu())
        self._bet_controls.append(button)

        # disable bet buttons by default
        self.activate_bet_controls(set=False)

        return layout

    # toggles button activation
    # leave bool as None to toggle bet
    def activate_bet_controls(self, set=None):
        for elem in self._bet_controls[:len(self._bet_controls) - 1]:
            elem.setEnabled(not elem.isEnabled() if set == None else set)

    # reset bet controls
    def reset_bet_controls(self):
        self.activate_bet_controls(set=False)
        self._bet_controls[0].setCurrentIndex(0)
        self._bet_controls[1].setCurrentIndex(0)

    # given deck, updates the players hand
    def update_player_hand(self, deck, setEvent=False):
        # update each card
        for i, card in enumerate(deck):
            widget = self._card_layout[self._player].itemAt(i).widget()
            widget.load('img/' + card + '.svg')

            # show kitty cards if we are in kitty round
            if i >= 10:
                widget.show()

            # we only need this set after it is possible to choose a card
            if setEvent:
                # note the extra card=card argument to stop each
                # lambda using local variable card

                # if we are in the kitty round, you can't
                # choose an invalid card, so remove it instantly
                widget.mouseReleaseEvent = (
                    lambda event, card=card: self.send_card(
                        card, remove=bool(len(deck) > 10)))

    # resets all players hands
    def reset_players_hands(self):
        # show each players cards again
        for i in range(0, NUMBER_PLAYERS):
            for j in range(0, 10):
                widget = self._card_layout[i].itemAt(j).widget()
                widget.load('img/BACK.svg')
                widget.show()

        # hide kitty cards again
        for i in range(10, 13):
            self._card_layout[self._player].itemAt(i).widget().hide()

        # reset card layout to what it was before
        self.rearrange_card_layout(
            -int(self._player))  # int to remove pylint errors

    # show the players first 10 cards and hide the last 3
    def reset_player_hand_after_kitty(self):
        for i in range(0, 10):
            self._card_layout[self._player].itemAt(i).widget().show()
        for i in range(10, 13):
            self._card_layout[self._player].itemAt(i).widget().hide()

    # sends card to client, optionally remove them
    def send_card(self, card, remove=False):
        self.send_to_client(card)

        if remove == True:
            self.remove_card_from_hand(self._player, card)

    # toggles card controls
    # supply set to give them a value
    def activate_card_controls(self, set=None):

        for i in range(0, self._card_layout[self._player].count()):
            widget = self._card_layout[self._player].itemAt(i).widget()
            widget.setEnabled(not widget.isEnabled() if set == None else set)

    # removes given card from our hand
    # note closing the widget does not decrease the count of cards in the layout
    def remove_card_from_hand(self, player, card):

        # find location of card in our deck and close that widget
        if player == self._player:
            index = self._players[self._player]["deck"].index(card)
        else:
            index = self._round
        self._card_layout[player].itemAt(index).widget().hide()

    # resets the cards played interface
    def reset_cards_played(self):
        self._cards_played = 0

        # reset image and text
        for i in range(0, self._played_cards.count()):
            self._played_cards.itemAt(i).layout().itemAt(0).widget().setText(
                "")
            self._played_cards.itemAt(i).layout().itemAt(1).widget().load(
                'img/BACK.svg')

        self.reset_card_winning()

    # reset the winning text
    def reset_card_winning(self):
        for i in range(0, self._played_cards.count()):
            self._played_cards.itemAt(i).layout().itemAt(2).widget().setText(
                "")

    # adds the card to the center
    def add_card_played(self, card, player, winning):
        self._played_cards.itemAt(self._cards_played).layout().\
                itemAt(0).widget().setText("Player " + str(player + 1))
        self._played_cards.itemAt(self._cards_played).layout().\
                itemAt(1).widget().load('img/' + card + '.svg')

        # update winning text
        if winning:
            self.reset_card_winning()
            self._played_cards.itemAt(self._cards_played).layout().\
                    itemAt(2).widget().setText("WINNING")

        self._cards_played += 1

    # reset player info
    def reset_player_info(self):
        # set player info as waiting
        for index in range(0, 4):
            self._player_info[index].setText("Waiting for player")

    # change the card layout so that number is the player at the base of the
    # interface. player 0 is there by default.
    def rearrange_card_layout(self, number):
        b = self._card_layout[-number:]
        b.extend(self._card_layout[:-number])
        self._card_layout = b

        # same for self._player_info
        c = self._player_info[-number:]
        c.extend(self._player_info[:-number])
        self._player_info = c

    # check for new input from our Client regularly
    # this means that our GUI is not being blocked for waiting
    # also note that multiprocess poll is not the same as subprocess poll,
    # hence the need for Client on seperate process
    # see MsgTypes enum for details on message contents
    def handle_client_input(self):

        # slow down interaction for when you are playing with bots
        after = POLL_DELAY

        # check if game is still going
        if self._parent_conn == None:
            return

        # attempt to poll
        try:
            self._parent_conn.poll()
        except:
            # if we cannot poll it is because we could not connect to the server
            QMessageBox.information(self, '500', "Failed to connect")
            self.exit_to_menu()
            return

        # repeatedly poll if we have input from Client
        while self._parent_conn.poll():
            data = self.recieve_from_client()
            print(data)

            # recieve game details
            if data["type"] is MsgType.PLAYER:
                self._player = data["player"]
                self._players = data["players"]

                # reset details in case we are restarting
                self.reset_players_hands()
                self.reset_player_info()
                self.reset_cards_played()
                self.reset_bet_controls()

                # we want to arrange the self._card_layout indexes so that
                # index 0 becomes the new index self._player.
                self.rearrange_card_layout(self._player)

                # update deck on screen
                # we only will add the click event either during choosing the kitty
                # or when the first round begins
                self.update_player_hand(data["players"][self._player]["deck"])
                self.activate_card_controls(set=False)

                # update all info on screen
                for index in range(0, NUMBER_PLAYERS):
                    self._player_info[index].setText(
                        str(index + 1) + ": " +
                        data["players"][index]["name"] + os.linesep)

            # enable bet controls on our bet
            elif data["type"] is MsgType.BETOURS:
                # activate bet controls
                self.activate_bet_controls(set=True)

            elif data["type"] is MsgType.BETINFO:
                # reset error text and disable bet controls if this was us
                if data["player"] == self._player:
                    self.activate_bet_controls(set=False)

                # add betting text
                self._player_info[data["player"]].setText(
                    self._player_info[data["player"]].text() + os.linesep +
                    string_to_bet(data["bet"]))

                if MIN_TIME_BETWEEN_MOVES:
                    after = MIN_TIME_BETWEEN_MOVES
                    break

            # display why the users bet failed
            elif data["type"] is MsgType.BETFAILED:
                QMessageBox.information(self, '500', data["message"])

            # disable controls after betting is done
            elif data["type"] is MsgType.BETWON:
                self.activate_bet_controls(set=False)

                if MIN_TIME_BETWEEN_MOVES:
                    after = MIN_TIME_BETWEEN_MOVES
                    break

            # update the deck with the kitty cards
            elif data["type"] is MsgType.KITTYDECK:
                self._players[self._player]["deck"] = data["deck"]
                self.update_player_hand(data["deck"], setEvent=True)

            # activate card controls on kitty
            elif data["type"] is MsgType.KITTYCHOOSE:
                self.activate_card_controls(set=True)

            # we are required to choose a joker suit
            elif data["type"] is MsgType.JOKERCHOOSE:

                # create message box with suit choices
                msg = QMessageBox()
                msg.setWindowTitle('500')
                msg.setText('Choose a joker suit.')
                msg.addButton(QPushButton('Spades'), QMessageBox.YesRole)
                msg.addButton(QPushButton('Clubs'), QMessageBox.YesRole)
                msg.addButton(QPushButton('Diamonds'), QMessageBox.YesRole)
                msg.addButton(QPushButton('Hearts'), QMessageBox.YesRole)
                ret = msg.exec_()

                # send our chosen suit to the client
                if ret == 0:
                    ret = "S"
                elif ret == 1:
                    ret = "C"
                elif ret == 2:
                    ret = "D"
                elif ret == 3:
                    ret = "H"

                self.send_to_client(ret)

            # waiting on another player to choose joker suit
            elif data["type"] is MsgType.JOKERSTART:
                QMessageBox.information(self, '500',
                                        "A player is choosing joker suit.")

            # joker suit chosen
            elif data["type"] is MsgType.JOKERDONE:
                QMessageBox.information(
                    self, '500',
                    "The joker is a " + letter_to_suit(data["suit"]) + ".")

            # update bet (cards are now sorted by suit)
            elif data["type"] is MsgType.GAMESTART:
                self.reset_player_hand_after_kitty()
                self._players[self._player]["deck"] = data["deck"]
                self.update_player_hand(data["deck"], setEvent=True)

            # new round
            elif data["type"] is MsgType.ROUNDNEW:
                # reset number of cards played
                self.reset_cards_played()
                self._round = data["round"]

            # we can play a card, activate card controls
            elif data["type"] is MsgType.ROUNDCHOOSE:
                self.activate_card_controls(set=True)

            # card has been played
            elif data["type"] is MsgType.ROUNDCARDPLAYED:
                # remove card from the hand
                self.activate_card_controls(set=False)
                self.remove_card_from_hand(data["player"], data["card"])

                # play card to self._played_cards, updating winning text
                # if the winning card is different
                self.add_card_played(
                    data["card"], data["player"],
                    bool(self._card_winning != data["winningcard"]))
                self._card_winning = data["winningcard"]

                # only have a break if we are not next
                if MIN_TIME_BETWEEN_MOVES and \
                        not (data["player"] + 1) % NUMBER_PLAYERS == self._player:
                    after = MIN_TIME_BETWEEN_MOVES
                    break

            # player played bad card, show them a message
            elif data["type"] is MsgType.ROUNDBAD:
                QMessageBox.information(self, '500', data["message"])

            # also case that we are in the last round of play
            elif data["type"] is MsgType.ROUNDWON:
                # remove card from the hand
                self.activate_card_controls(set=False)
                self.remove_card_from_hand(data["player"], data["card"])

                # play card to self._played_cards
                self.add_card_played(
                    data["card"], data["player"],
                    bool(self._card_winning != data["winningcard"]))
                self._card_winning = None

                if MIN_TIME_BETWEEN_MOVES:
                    after = MIN_TIME_BETWEEN_MOVES
                    break

            # game over
            elif data["type"] is MsgType.GAMEOVER:
                QMessageBox.information(self, '500', "Game over!")
                self.exit_to_menu()
                return

        # repeat
        QtCore.QTimer.singleShot(after, self.handle_client_input)

    # when user presses join
    def join(self, port, password, ip, username):
        # communication
        self._parent_conn, child_conn = Pipe()

        # this call is blocking if the game loop method is in our controller class!
        self._client = Process(target=Client,
                               args=(
                                   [ip, port, password, username],
                                   child_conn,
                               ))
        self._client.start()

        # switch to game view
        self._stacked_layout.setCurrentIndex(2)

        # check for new data sent by Client in regular intervals
        QtCore.QTimer.singleShot(POLL_DELAY, self.handle_client_input)

    # sends data to the client, must be a string (non blocking)
    def send_to_client(self, data):
        if self._parent_conn != None:
            self._parent_conn.send(data)

    # recieves data from client (blocking)
    def recieve_from_client(self):
        if self._parent_conn != None:
            return self._parent_conn.recv()

        return None

    # when user presses the go button
    def create_game(self):

        # these details are always required details
        port = str(self.get_port())
        if port == "" or port == "0":
            QMessageBox.information(self, '500', "Please enter a valid port")
            return

        username = self.get_username()
        if username == "":
            QMessageBox.information(self, '500', "Please enter a username")
            return

        # rest of the details are different for each options type
        if self._options_type == 0:
            password = "******"
            ptypes = "0222"
            ip = get_localhost_ip()
            self.create_server(port, password, ptypes)

        else:
            # get password for next 2 cases
            password = self.get_password()
            if password == "":
                QMessageBox.information(self, '500', "Please enter a password")
                return

            if self._options_type == 1:
                ip = self.get_ip()

                # check if ip is valid, ensure it is seperated by 4 dots and
                # all are numbers between 0 and 255
                check = ip.split('.')
                error = 0

                if len(check) == 4:
                    for index in range(0, 4):
                        if (check[index].isnumeric() == True
                                and int(check[index]) >= 0
                                and int(check[index]) < 256):

                            error += 1

                if error != 4:
                    QMessageBox.information(self, '500',
                                            "Please enter a valid IP address")
                    return

            elif self._options_type == 2:
                ip = get_localhost_ip()
                ptypes = ["0"]

                for index in range(0, 3):
                    ptypes.append(str(self.get_player_type(index)))

                self.create_server(port, password, ''.join(ptypes))

        self.join(port, password, ip, username)

    # ensure we exit only after cleaning up
    def closeEvent(self, event):
        self.close_subprocesses()
        return QWidget.closeEvent(self, event)

    # closes server and client subprocesses
    def close_subprocesses(self):
        if self._server != None:
            self._server.kill()
            self._server = None
            self._parent_conn = None
            print("Server Terminated")

        if self._client != None:
            self._client.terminate()
            self._client = None
            print("Client Terminated")

    # change layout and close server and client subprocesses
    def exit_to_menu(self):
        self._stacked_layout.setCurrentIndex(0)
        self.close_subprocesses()
        self.reset()

    # reset game variables
    def reset(self):
        # reset all parts of gui
        self.reset_player_info()
        self.reset_bet_controls()
        self.reset_cards_played()
        self.reset_player_hand_after_kitty()
        self.activate_card_controls(set=False)

        # the below resets the hand locations, so ensure all card
        # related resetting done before this
        self.reset_players_hands()

        # reset all player details
        self._player = 0
        self._players = None
        self._round = None
        self._cards_played = 0

    # creates the server
    def create_server(self, port, password, playertypes):

        # create server args
        srvargs = ["./server", port, password, playertypes]

        # create server
        self._server = subprocess.Popen(srvargs, stdout=subprocess.DEVNULL)
        print("Server Created.")
示例#19
0
class QRuleEditor(QDialog):
    def __init__(self, project, editor,
                 rule):  # Rule is some fontFeatures object
        self.project = project
        self.editor = editor
        self.inputslots = []
        self.precontextslots = []
        self.postcontextslots = []
        self.outputslots = []
        self.buffer_direction = "RTL"
        self.buffer_script = "Latin"
        self.all_valuerecord_editors = []
        self.index = None
        if rule:
            self.backup_rule = Rule.fromXML(rule.toXML())  # Deep copy
        else:
            self.backup_rule = None

        super(QRuleEditor, self).__init__()

        splitter = QSplitter()
        self.slotview = QHBoxLayout()
        scroll = QScrollArea()
        scroll.setLayout(self.slotview)

        self.outputview_before = QBufferRenderer(
            project, VariationAwareBuffer(self.project.font))
        self.outputview_after = QBufferRenderer(
            project, VariationAwareBuffer(self.project.font))
        self.before_after = QWidget()
        self.before_after_layout_v = QVBoxLayout()

        self.asFea = QLabel()

        featureButtons = QWidget()
        self.featureButtonLayout = QHBoxLayout()
        featureButtons.setLayout(self.featureButtonLayout)
        self.selectedFeatures = []

        layoutarea = QWidget()
        self.before_after_layout_h = QHBoxLayout()
        self.before_after_layout_h.addWidget(self.outputview_before)
        self.before_after_layout_h.addWidget(self.outputview_after)
        layoutarea.setLayout(self.before_after_layout_h)

        if self.project.variations:
            self.master_selection = QComboBox()
            for mastername in self.project.variations.masters:
                self.master_selection.addItem(mastername)
            self.master_selection.currentTextChanged.connect(
                self.masterChanged)
            self.before_after_layout_v.addWidget(self.master_selection)
        else:
            self.master_selection = None

        self.before_after_layout_v.addWidget(featureButtons)
        self.before_after_layout_v.addWidget(self.asFea)
        self.before_after_layout_v.addWidget(layoutarea)

        self.before_after.setLayout(self.before_after_layout_v)

        splitter.setOrientation(Qt.Vertical)
        splitter.addWidget(scroll)

        splitter.addWidget(self.before_after)
        buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
        for button in buttons.buttons():
            button.setDefault(False)
            button.setAutoDefault(False)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)
        v_box_1 = QVBoxLayout()
        self.setLayout(v_box_1)
        v_box_1.addWidget(splitter)
        v_box_1.addWidget(buttons)
        self.setRule(rule)

    @property
    def currentMaster(self):
        if not self.master_selection:
            return None
        return self.master_selection.currentText()

    def masterChanged(self):
        for qvre in self.all_valuerecord_editors:
            qvre.change_master(self.currentMaster)
        self.resetBuffer()

    def keyPressEvent(self, evt):
        return

    def accept(self):
        self.editor.fontfeaturespanel.lookuplist.update(self.index)
        self.editor.setWindowModified(True)
        self.editor.showDebugger()

    def reject(self):
        for k in dir(self.backup_rule):
            self.rule = getattr(self.backup_rule, k)
        self.editor.fontfeaturespanel.lookuplist.update()
        self.editor.showDebugger()

    def setRule(self, rule, index=None):
        self.rule = rule
        self.index = index
        self.arrangeSlots()
        self.representative_string = self.makeRepresentativeString()
        self.resetBuffer()

    @property
    def location(self):
        sourceIndex = list(self.project.variations.masters.keys()).index(
            self.currentMaster)
        return self.project.variations.designspace.sources[
            sourceIndex].location

    def resetBuffer(self):
        if self.rule:
            try:
                self.asFea.setText(self.rule.asFea())
            except Exception as e:
                print("Can't serialize", e)
        self.outputview_before.set_buf(self.makeBuffer("before"))
        self.outputview_after.set_buf(self.makeBuffer("after"))
        if self.currentMaster:
            self.outputview_before.set_location(self.location)
            self.outputview_after.set_location(self.location)

    @pyqtSlot()
    def changeRepresentativeString(self):
        l = self.sender()
        if l.text().startswith("@"):
            self.representative_string[
                l.slotnumber] = self.project.fontfeatures.namedClasses[
                    l.text()[1:]][0]
        else:
            self.representative_string[l.slotnumber] = l.text()

        self.resetBuffer()

    @pyqtSlot()
    def replacementChanged(self):
        l = self.sender()
        replacements = l.text().split()
        self.rule.replacement = [[x] for x in replacements]
        self.resetBuffer()

    @pyqtSlot()
    def addGlyphToSlot(self):
        l = self.sender()
        glyphname = l.text()
        # Check for class names
        if (glyphname.startswith("@") and glyphname[1:]
                in self.project.fontfeatures.namedClasses.keys()):
            # It's OK
            pass
        elif glyphname not in self.project.font.keys():
            print(f"{glyphname} not found")
            l.setText("")
            return
        print("Adding ", glyphname)
        l.owner.contents[l.owner.slotindex].append(glyphname)
        self.arrangeSlots()
        self.representative_string = self.makeRepresentativeString()
        self.resetBuffer()

    @pyqtSlot()
    def removeGlyphFromSlot(self):
        l = self.sender()
        del l.contents[l.slotindex][l.indexWithinSlot]
        self.arrangeSlots()
        self.representative_string = self.makeRepresentativeString()
        self.resetBuffer()

    @pyqtSlot()
    def addRemoveSlot(self):
        sender = self.sender()
        action = sender.text()
        if action == "<+":
            sender.contents.insert(0, [])
            # If these are input glyphs, add another replacement etc.
            if sender.contents == self.rule.shaper_inputs():
                if isinstance(self.rule, Positioning):
                    self.rule.valuerecords.insert(0, ValueRecord())
                elif (isinstance(self.rule, Substitution)
                      and len(self.rule.shaper_inputs()) == 1):
                    self.rule.replacement.insert(0, [])
                elif isinstance(self.rule, Chaining):
                    self.rule.lookups.insert(0, [])
        elif action == "+>":
            sender.contents.append([])
            # If these are input glyphs, add another replacement etc.
            if sender.contents == self.rule.shaper_inputs():
                if isinstance(self.rule, Positioning):
                    self.rule.valuerecords.append(ValueRecord())
                elif (isinstance(self.rule, Substitution)
                      and len(self.rule.shaper_inputs()) == 1):
                    self.rule.replacement.append([])
                elif isinstance(self.rule, Chaining):
                    self.rule.lookups.append([])

        elif action == "-":
            del sender.contents[self.sender().ix]
        self.arrangeSlots()
        self.representative_string = self.makeRepresentativeString()
        self.resetBuffer()

    def makeASlot(self, slotnumber, contents, style=None, editingWidgets=None):
        for ix, glyphslot in enumerate(contents):
            slot = QWidget()
            slotLayout = QVBoxLayout()
            if style:
                slot.setStyleSheet(style)

            scroll = QScrollArea()
            scroll.setWidgetResizable(True)
            scrollWidget = QWidget()
            scrollLayout = QVBoxLayout()
            scrollWidget.setLayout(scrollLayout)
            scroll.setWidget(scrollWidget)
            for ixWithinSlot, glyph in enumerate(glyphslot):
                glyphHolder = QWidget()
                glyphHolderLayout = QHBoxLayout()
                glyphHolder.setLayout(glyphHolderLayout)
                l = QPushButton(glyph)
                l.setDefault(False)
                l.setAutoDefault(False)
                l.slotnumber = slotnumber
                l.clicked.connect(self.changeRepresentativeString)
                glyphHolderLayout.addWidget(l)

                remove = QPushButton("x")
                remove.slotindex = ix
                remove.indexWithinSlot = ixWithinSlot
                remove.contents = contents
                remove.clicked.connect(self.removeGlyphFromSlot)
                glyphHolderLayout.addWidget(remove)
                scrollLayout.addWidget(glyphHolder)

            slotLayout.addWidget(scroll)

            # This is the part that adds a new glyph to a slot
            newglyph = QGlyphName(self.project, allow_classes=True)
            newglyph.slotindex = ix
            newglyph.contents = contents
            newglyph.glyphline.returnPressed.connect(self.addGlyphToSlot)
            slotLayout.addWidget(newglyph)

            slotLayout.addStretch()
            if editingWidgets and ix < len(editingWidgets):
                slotLayout.addWidget(editingWidgets[ix])

            pushbuttonsArea = QWidget()
            pushbuttonsLayout = QHBoxLayout()
            pushbuttonsArea.setLayout(pushbuttonsLayout)
            if ix == 0:
                addASlotLeft = QPushButton("<+")
                addASlotLeft.contents = contents
                addASlotLeft.clicked.connect(self.addRemoveSlot)
                pushbuttonsLayout.addWidget(addASlotLeft)
            pushbuttonsLayout.addStretch()
            if not (editingWidgets and len(contents) == 1):
                removeASlot = QPushButton("-")
                removeASlot.contents = contents
                removeASlot.ix = ix
                removeASlot.clicked.connect(self.addRemoveSlot)
                pushbuttonsLayout.addWidget(removeASlot)
            pushbuttonsLayout.addStretch()
            if ix == len(contents) - 1:
                addASlotRight = QPushButton("+>")
                addASlotRight.contents = contents
                addASlotRight.clicked.connect(self.addRemoveSlot)
                pushbuttonsLayout.addWidget(addASlotRight)
            slotLayout.addWidget(pushbuttonsArea)

            slotnumber = slotnumber + 1

            slot.setLayout(slotLayout)
            self.slotview.addWidget(slot)
        return slotnumber

    def lookupCombobox(self, current, warning):
        c = QComboBox()
        c.warning = warning
        names = [
            x.name for x in self.project.fontfeatures.routines
            if not hasattr(x, "comment")
        ]
        names = ["--- No lookup ---"] + names
        for name in names:
            c.addItem(name)
        if current in names:
            c.setCurrentIndex(names.index(current))
        self.setComboboxWarningIfNeeded(c)
        return c

    @pyqtSlot()
    def chainingLookupChanged(self):
        l = self.sender()
        if l.currentIndex() == 0:
            self.rule.lookups[l.ix] = []
        else:
            self.rule.lookups[l.ix] = [RoutineReference(name=l.currentText())]
        self.setComboboxWarningIfNeeded(l)
        self.resetBuffer()

    def changesGlyphstringLength(self, routine, depth=1):
        if depth > 10:
            return False
        for r in routine.rules:
            if isinstance(r,
                          Substitution) and len(r.input) != len(r.replacement):
                return True
            elif isinstance(r, Chaining):
                for lus in r.lookups:
                    for l in (lus or []):
                        if self.changesGlyphstringLength(l.routine, depth + 1):
                            return True
        return False

    def setComboboxWarningIfNeeded(self, combobox):
        # Find routine
        rname = combobox.currentText()
        warningNeeded = False
        if rname:
            routine = None
            for r in self.project.fontfeatures.routines:
                if r.name == rname:
                    routine = r
        if routine and self.changesGlyphstringLength(routine):
            stdicon = self.style().standardIcon(QStyle.SP_MessageBoxWarning)
            combobox.warning.setPixmap(
                stdicon.pixmap(stdicon.actualSize(QSize(16, 16))))
            combobox.warning.setToolTip(
                "<qt>This lookup may change the length of the glyph stream. Subsequent lookups may not fire at the glyph slots you expect.</qt>"
            )
        else:
            combobox.warning.clear()
            combobox.warning.setToolTip("")

    def addPrecontext(self):
        self.rule.precontext = [[]]
        self.arrangeSlots()

    def addPostcontext(self):
        self.rule.postcontext = [[]]
        self.arrangeSlots()

    def makeEditingWidgets(self):
        editingWidgets = []
        if isinstance(self.rule, Substitution):
            replacements = [x[0] for x in self.rule.replacement if x]
            widget = QGlyphName(self.project,
                                multiple=len(self.rule.shaper_inputs()) < 2)
            widget.setText(" ".join(replacements) or "")
            widget.position = 0
            widget.returnPressed.connect(self.replacementChanged)
            editingWidgets.append(widget)
        else:
            for ix, i in enumerate(self.rule.shaper_inputs()):
                if isinstance(self.rule, Positioning):
                    widget = QValueRecordEditor(self.rule.valuerecords[ix],
                                                vf=self.project.variations,
                                                master=self.currentMaster)
                    widget.changed.connect(self.resetBuffer)
                    editingWidgets.append(widget)
                    self.all_valuerecord_editors.append(widget)
                elif isinstance(self.rule, Chaining):
                    lookup = self.rule.lookups[ix] and self.rule.lookups[ix][
                        0].name
                    w = QWidget()
                    wl = QHBoxLayout(w)
                    w.setLayout(wl)
                    warning = QLabel()
                    widget = self.lookupCombobox(lookup, warning)
                    widget.ix = ix
                    widget.currentTextChanged.connect(
                        self.chainingLookupChanged)
                    wl.addWidget(widget)
                    wl.addWidget(warning)
                    editingWidgets.append(w)
        return editingWidgets

    def clearLayout(self, layout):
        if layout is not None:
            while layout.count():
                item = layout.takeAt(0)
                widget = item.widget()
                if widget is not None:
                    widget.deleteLater()
                else:
                    self.clearLayout(item.layout())

    def arrangeSlots(self):
        self.all_valuerecord_editors = []
        self.clearLayout(self.slotview)
        if not self.rule:
            return

        slotnumber = 0

        if not hasattr(self.rule, "precontext") or not self.rule.precontext:
            widget = QPushButton("<<+")
            widget.clicked.connect(self.addPrecontext)
            self.slotview.addWidget(widget)
        else:
            self.slotview.addStretch()
            slotnumber = self.makeASlot(slotnumber, self.rule.precontext,
                                        precontext_style)

        editingWidgets = self.makeEditingWidgets()
        slotnumber = self.makeASlot(slotnumber,
                                    self.rule.shaper_inputs(),
                                    editingWidgets=editingWidgets)

        if not hasattr(self.rule, "postcontext") or not self.rule.postcontext:
            widget = QPushButton("+>>")
            widget.clicked.connect(self.addPostcontext)
            self.slotview.addWidget(widget)
        else:
            self.makeASlot(slotnumber, self.rule.postcontext,
                           postcontext_style)

        self.slotview.addStretch()

    def makeRepresentativeString(self):
        inputglyphs = []
        if not self.rule:
            return inputglyphs
        # "x and x[0]" thing because slots may be empty if newly added
        if hasattr(self.rule, "precontext"):
            inputglyphs.extend([x and x[0] for x in self.rule.precontext])

        inputglyphs.extend([x and x[0] for x in self.rule.shaper_inputs()])

        if hasattr(self.rule, "postcontext"):
            inputglyphs.extend([x and x[0] for x in self.rule.postcontext])

        representative_string = [x for x in inputglyphs if x]
        for ix, g in enumerate(representative_string):
            if (g.startswith("@") and g[1:]
                    in self.project.fontfeatures.namedClasses.keys()):
                representative_string[
                    ix] = self.project.fontfeatures.namedClasses[g[1:]][0]

        # We use this representative string to guess information about
        # how the *real* shaping process will take place; buffer direction
        # and script, and hence choice of complex shaper, and hence from
        # that choice of features to be processed.
        unicodes = [
            self.project.font.codepointForGlyph(x)
            for x in representative_string
        ]
        unicodes = [x for x in unicodes if x]
        tounicodes = "".join(map(chr, unicodes))
        bufferForGuessing = Buffer(self.project.font, unicodes=tounicodes)
        self.buffer_direction = bufferForGuessing.direction
        self.buffer_script = bufferForGuessing.script
        # print("Guessed buffer direction ", self.buffer_direction)
        # print("Guessed buffer script ", self.buffer_script)
        shaper = Shaper(self.project.fontfeatures, self.project.font)
        bufferForGuessing = Buffer(self.project.font,
                                   glyphs=representative_string)
        shaper.execute(bufferForGuessing)
        self.availableFeatures = []
        for stage in shaper.stages:
            if not isinstance(stage, list):
                continue
            for f in stage:
                if (f not in self.availableFeatures
                        and f in self.project.fontfeatures.features):
                    self.availableFeatures.append(f)
        self.makeFeatureButtons()

        return representative_string

    def makeFeatureButtons(self):
        self.clearLayout(self.featureButtonLayout)
        for f in self.availableFeatures:
            self.selectedFeatures.append(f)
            featureButton = QCheckBox(f)
            featureButton.setChecked(True)
            featureButton.stateChanged.connect(self.resetBuffer)
            self.featureButtonLayout.addWidget(featureButton)

    def makeShaperFeatureArray(self):
        features = []
        for i in range(self.featureButtonLayout.count()):
            item = self.featureButtonLayout.itemAt(i).widget()
            features.append({"tag": item.text(), "value": item.isChecked()})
        return features

    def makeBuffer(self, before_after="before"):
        buf = VariationAwareBuffer(
            self.project.font,
            direction=self.buffer_direction,
        )
        if self.project.variations:
            buf.location = self.location
            buf.vf = self.project.variations
        buf.items = [
            VariationAwareBufferItem.new_glyph(g, self.project.font, buf)
            for g in self.representative_string
        ]
        shaper = Shaper(self.project.fontfeatures, self.project.font)

        shaper.execute(buf, features=self.makeShaperFeatureArray())
        routine = Routine(rules=[self.rule])
        # print("Before shaping: ", buf.serialize())
        if before_after == "after" and self.rule:
            print("Before application: ", buf.serialize())
            print(self.rule.asFea())
            buf.clear_mask()  # XXX
            try:
                routine.apply_to_buffer(buf)
            except Exception as e:
                print("Couldn't shape: " + str(e))
            print("After application: ", buf.serialize())
        return buf
示例#20
0
class Connect_Directions(QObject):
    """
    This class is used to connect the directions modifications at the
    GUI level. It modifies the module according to the newly selected
    parameter value.
    """

    signal_paramChanged = pyqtSignal(str, list)

    # ----------------------------------------------------------------------
    def __init__(self, paramName, chosen_value, all_Values, nb_directions):
        """
        Constructor
        """
        super().__init__()
        self.paramName = paramName
        self.l = QHBoxLayout()
        self.chosen_value = chosen_value

        self.create_the_comboBoxes(chosen_value, all_Values, nb_directions)

    # ----------------------------------------------------------------------
    def create_the_comboBoxes(self, chosen_value, all_Values, nb_directions):
        """
        Creates nb_directions directions, list the possible values and select the chosen_value.
        
        paramName = Name of the parameter corresponding to the widget to create 
        chosen_value = the subject's specific parameter values.
        all_Values = list of all possible values for a parameter
        nb_directions = number of directions to add.
        """
        nb_val = range(len(chosen_value))
        for i in nb_val:
            self.l.addWidget(
                self.add_To_ComboBox(all_Values, chosen_value[i], i))

            # Add a vertical separator
            if i != nb_directions:
                add_v_separator(self.l)

        nb_val = range(len(chosen_value), nb_directions)
        for i in nb_val:
            self.l.addWidget(self.add_To_ComboBox(all_Values, None, i))

            # Add a vertical separator
            if i != nb_val[-1]:
                add_v_separator(self.l)

    # ----------------------------------------------------------------------
    def add_To_ComboBox(self, values, chosenValue, pos):
        """
        Add the possibles values found in the structure file to a QComboBox.
        Highlight the subject's specific value.
        values = list of values.
        chosenValue = subject's specific value.
        pos = QComboBox position in the directions list
        """
        templateChoices = QComboBox_Directions(pos)

        # Iterates over the possible choices
        for val in values:
            templateChoices.addItem(str(val), val)
            if val == chosenValue:
                templateChoices.setCurrentText(val)

        templateChoices.signal_paramChanged[int,
                                            object].connect(self.on_modify)

        return templateChoices

    #----------------------------------------------------------------------
    def clear_hBoxLayout(self):
        """
        #Removes all the widgets added to the layout
        """
        for i in reversed(range(self.l.count())):
            self.l.itemAt(i).widget().setParent(None)

    @pyqtSlot(str, str)
    #----------------------------------------------------------------------
    def on_new_tdef_file(self, key, trigger_file):
        """
        Update the QComboBox with the new events from the new tdef file.
        """
        self.clear_hBoxLayout()
        tdef = trigger_def(trigger_file)
        nb_directions = 4
        #  Convert 'None' to real None (real None is removed when selected in the GUI)
        tdef_values = [None if i == 'None' else i for i in list(tdef.by_name)]
        self.create_the_comboBoxes(self.chosen_value, tdef_values,
                                   nb_directions)

    @pyqtSlot(int, object)
    # ----------------------------------------------------------------------
    def on_modify(self, pos, new_Value):
        """
        Slot connected to comboBox param value change
        
        pos = QComboBox position in the directions list
        new_value = direction new_value
        """
        if pos >= len(self.chosen_value):
            self.chosen_value.append(new_Value)
        else:
            self.chosen_value[pos] = (new_Value)

        try:
            self.chosen_value.remove(None)
        except:
            pass

        self.signal_paramChanged[str, list].emit(self.paramName,
                                                 self.chosen_value)
示例#21
0
class AddNewKey(QFrame):
    """ QFrame popup widget for adding new element """
    def __init__(self, connection: sqlite3.Connection, cursor: sqlite3.Cursor,
                 secret_key: str, data: typing.Union[typing.List,
                                                     None], parent: object):
        super().__init__(parent)
        self.parent = parent
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.connection = connection
        self.cursor = cursor
        self.secret_key = secret_key
        self.data = data
        self.w = self.parent.width()
        self.h = self.parent.height()
        self.setFixedSize(self.w, self.h)
        self.setObjectName("AddFrame")
        self.setStyleSheet(qframe_css.add_new_key_style)
        # Elements
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        close_button = QPushButton()
        close_button.setObjectName("close")
        close_button.setFixedSize(QSize(13, 13))
        close_button.setCursor(Qt.PointingHandCursor)
        close_button.setIcon(QIcon(":/quit"))
        close_button.clicked.connect(self._close)
        if not self.data:
            self.combo = QComboBox()
            self.combo.setObjectName("combo")
            self.combo.addItems(
                ("Web Sites", "Web Accounts", "Emails", "Credit Cards",
                 "E-commerce", "Secrets", "Software", "Forums"))
            self.combo.currentTextChanged.connect(self.generate_child_list)
            self.child = QLineEdit()
            self.child.setPlaceholderText("Branch *")
        self.title = QLineEdit()
        self.title.setPlaceholderText("Title *")
        self.name = QLineEdit()
        self.name.setPlaceholderText("Login")
        self.email = QLineEdit()
        self.email.setPlaceholderText("Email")
        self.password = QLineEdit()
        self.password.setPlaceholderText("Password *")
        self.password.setEchoMode(QLineEdit.Password)
        self.url = QLineEdit()
        self.url.setPlaceholderText("Url")
        self.phone = QLineEdit()
        self.phone.setPlaceholderText("Phone")
        self.created = QLineEdit()
        self.created.setPlaceholderText("Create Date *")
        if not self.data:
            self.created.setText(current_time)
        else:
            self.created.setText(self.data[6])
        self.created.setEnabled(False)
        self.modified = QLineEdit()
        self.modified.setPlaceholderText("Modified Date *")
        self.modified.setText(current_time)
        self.modified.setEnabled(False)
        if not self.data:
            for elements in (self.combo, self.child):
                elements.setFixedSize(400, 40)
                elements.setObjectName("field")
        for elements in (self.title, self.name, self.email, self.password,
                         self.url, self.phone, self.created, self.modified):
            elements.setFixedSize(400, 40)
            elements.setObjectName("field")
        save_button = QPushButton()
        save_button.setObjectName("save")
        save_button.setText("Сохранить")
        save_button.setFixedSize(300, 40)
        save_button.setCursor(Qt.PointingHandCursor)
        save_button.clicked.connect(self._save)
        # Animation
        self.animation = AnimationService(self, b"geometry", 200,
                                          QRect(0, -self.h, self.w, self.h),
                                          QRect(0, 0, self.w,
                                                self.h)).init_animation()
        self.animation.start()
        # Timer
        self.timer = QTimer(self)
        self.timer.setInterval(210)
        self.timer.timeout.connect(self._quit)
        # LAYOUTS
        if not self.data:
            self.cc = QHBoxLayout()
            self.cc.setContentsMargins(0, 6, 0, 4)
            self.cc.setAlignment(Qt.AlignCenter)
        layout = QVBoxLayout()
        layout.addWidget(close_button, alignment=Qt.AlignRight)
        layout.addSpacing(10)
        if not self.data:
            layout.addWidget(self.combo, alignment=Qt.AlignCenter)
            layout.addLayout(self.cc)
            layout.addWidget(self.child, alignment=Qt.AlignCenter)
            layout.addSpacing(10)
        layout.addWidget(self.title, alignment=Qt.AlignCenter)
        layout.addSpacing(10)
        layout.addWidget(self.name, alignment=Qt.AlignCenter)
        layout.addSpacing(10)
        layout.addWidget(self.email, alignment=Qt.AlignCenter)
        layout.addSpacing(10)
        layout.addWidget(self.password, alignment=Qt.AlignCenter)
        layout.addSpacing(10)
        layout.addWidget(self.url, alignment=Qt.AlignCenter)
        layout.addSpacing(10)
        layout.addWidget(self.phone, alignment=Qt.AlignCenter)
        layout.addSpacing(10)
        layout.addWidget(self.created, alignment=Qt.AlignCenter)
        layout.addSpacing(10)
        layout.addWidget(self.modified, alignment=Qt.AlignCenter)
        layout.addSpacing(20)
        layout.addWidget(save_button, alignment=Qt.AlignCenter)
        layout.addStretch(1)
        self.setLayout(layout)
        self.title.setFocus(True)
        if not self.data:
            self.generate_child_list()
        else:
            self.title.setText(self.data[0])
            self.name.setText(self.data[1])
            self.email.setText(self.data[2])
            self.url.setText(self.data[4])
            self.phone.setText(self.data[5])

    def generate_child_list(self):
        self.sender().blockSignals(True)
        for pos in reversed(range(self.cc.count())):
            curr_item = self.cc.takeAt(pos).widget()
            if curr_item is not None:
                curr_item.deleteLater()
        sql = "SELECT DISTINCT child " \
              "FROM passwords " \
              "WHERE parent=? " \
              "ORDER BY child ASC"
        query = self.cursor.execute(sql, (self.combo.currentText(), ))
        for item in query.fetchall():
            r_elem = QRadioButton()
            r_elem.setObjectName("child-element")
            r_elem.setText(item[0])
            r_elem.setFixedHeight(20)
            r_elem.setCursor(Qt.PointingHandCursor)
            r_elem.clicked.connect(self.child_text_replace)
            self.cc.addWidget(r_elem)
        self.sender().blockSignals(False)

    def child_text_replace(self):
        self.child.setText(self.sender().text())

    def _save(self):
        crypt_password = run_encode(self.secret_key,
                                    self.password.text().encode("utf-8"))
        if not self.data:
            sql = "INSERT INTO passwords " \
                  "(parent, child, title, login, email, password, url, phone, created, modified) " \
                  "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
            self.cursor.execute(
                sql, (self.combo.currentText(), self.child.text(),
                      self.title.text(), self.name.text(), self.email.text(),
                      crypt_password, self.url.text(), self.phone.text(),
                      self.created.text(), self.modified.text()))
        else:
            sql = "UPDATE passwords " \
                  "SET title=?, login=?, email=?, password=?, url=?, phone=?, modified=? " \
                  "WHERE id=?"
            self.cursor.execute(
                sql, (self.title.text(), self.name.text(), self.email.text(),
                      crypt_password, self.url.text(), self.phone.text(),
                      self.modified.text(), self.data[3]))
        self.connection.commit()
        self._close()
        chime.success()

    def _close(self):
        self.animation.setStartValue(QRect(0, 0, self.w, self.h))
        self.animation.setEndValue(QRect(0, -self.h, self.w, self.h))
        self.animation.start()
        self.timer.start()

    def _quit(self):
        self.close()
        self.deleteLater()
        self.parent._add = None

    def keyPressEvent(self, event: QEvent) -> None:
        """ Track key press """

        if event.key() == Qt.Key_Escape:
            self._close()
示例#22
0
class MyWindow(QWidget):
    """main window"""
    def __init__(self):
        super().__init__()
        self.auths = {}
        self.activeaccounts = []
        self.streams = []
        self.tweets = []
        self.tagarray = []
        self.tweettags = []
        self.receivetags = []
        self.following = []
        self.searchstream = None

        self.init_main()
        self.init_accounts()
        self.init_tweets()
        self.init_widgets()

        self.show()
        sys.exit(app.exec_())

    def init_main(self):
        """options of main window"""
        self.setGeometry(300, 100, 1000, 600)
        self.setWindowTitle("tomoebi")
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_timeline)
        self.timer.start(500)

    def init_tweets(self):
        """create initial tweet"""
        self.tweets = ["start"]

    #initialize widgets
    def init_widgets(self):
        """initialize widgets"""
        #upper half of main window consists of accounts, composer and buttons
        self.compose_vbox = QVBoxLayout()
        self.accounts_hbox = QHBoxLayout()
        self.accbuttons = []
        for a in self.auths:
            accbutton = QPushButton(self)
            accbutton.setWhatsThis(a)
            accbutton.setCheckable(True)
            accbutton.toggled.connect(self.choose_account)
            accbutton.setChecked(True)
            accbutton.setIcon(PyQt5.QtGui.QIcon('images/' + a + '.jpg'))
            accbutton.setIconSize(QSize(48, 48))
            self.accounts_hbox.addWidget(accbutton)
        self.addaccbutton = QPushButton("+", self)
        self.addaccbutton.clicked.connect(self.add_account)
        self.accounts_hbox.addWidget(self.addaccbutton)
        self.composer = ComposeTextEdit(self)
        #self.composer.setPlaceholderText("いまなにしてる?")
        self.composer.setMaximumHeight(60)

        self.compose_hbox = QHBoxLayout()
        self.imagebutton = QPushButton("image", self)
        self.submitbutton = QPushButton("tweet", self)
        self.submitbutton.clicked.connect(self.submit)

        self.hashtag_hbox = QHBoxLayout()
        self.hashtagedit = QLineEdit(self)
        self.hashtagedit.setPlaceholderText("hashtags")
        self.hashtagbutton = QPushButton("set")
        self.hashtagbutton.setCheckable(True)
        self.hashtagbutton.toggled.connect(self.sethashtag)
        self.hashtag_hbox.addWidget(self.hashtagedit)
        self.hashtag_hbox.addWidget(self.hashtagbutton)

        self.compose_hbox.addWidget(self.imagebutton)
        self.compose_hbox.addWidget(self.submitbutton)
        self.compose_vbox.addLayout(self.accounts_hbox)
        self.compose_vbox.addWidget(self.composer)
        self.compose_vbox.addLayout(self.compose_hbox)
        self.compose_vbox.addLayout(self.hashtag_hbox)

        #lower half of main window consists of timeline
        l = QTextEdit()
        l.setPlainText(self.tweets[0])
        l.setReadOnly(True)
        l.setFixedHeight(350)
        self.inner = QWidget()
        self.timeline_vbox = QVBoxLayout(self.inner)
        self.timeline_vbox.addWidget(l)
        self.tweets = []
        self.timeline_vbox.addStretch()
        self.scroll = QScrollArea()
        self.scroll.setWidgetResizable(True)
        self.scroll.setWidget(self.inner)

        #integrate upper and lower part of main window
        self.whole_vbox = QVBoxLayout()
        self.whole_vbox.addLayout(self.compose_vbox)
        self.whole_vbox.addWidget(self.scroll)

        #right half of the main window
        self.image_collumn = QVBoxLayout()
        self.imageinner = QWidget()
        self.imagetimeline = QVBoxLayout(self.imageinner)
        self.imagescroll = QScrollArea()
        self.imagescroll.setWidgetResizable(True)
        self.imagescroll.setWidget(self.imageinner)
        self.imagetext = QTextEdit()
        self.imagetext.setMaximumHeight(60)
        self.imagetext.setReadOnly(True)
        self.image_collumn.addWidget(self.imagetext)
        self.image_collumn.addWidget(self.imagescroll)

        self.whole_hbox = QHBoxLayout()
        self.whole_hbox.addLayout(self.whole_vbox)
        self.whole_hbox.addLayout(self.image_collumn)
        self.setLayout(self.whole_hbox)

    #initialize registered accounts
    def init_accounts(self):
        """load account AT and AS from local and create api object and stream"""
        if not os.path.exists("images"):
            os.mkdir("images")
        if os.path.isfile("auth.json"):
            with open('auth.json', 'r') as f:
                authdic = json.load(f)
            for name, keys in authdic["Twitter"].items():
                api = twitter.connect(keys["ACCESS_TOKEN"],
                                      keys["ACCESS_SECRET"])
                self.auths[name] = api
                #self.following = self.following + api.friends_ids(k)
                self.streams.append(
                    twitter.open_userstream(api, self.receive_tweet, name))
                if not os.path.isfile("images/" + name + ".jpg"):
                    twitter.getmyicon(api, name)
            #twitter.open_filterstream(self.auths["XXXX"], self.receive_tweet,
            #  "XXXX", [str(x) for x in self.following])
        else:
            default = {"Twitter": {}, "Mastodon": {}}
            with open('auth.json', 'w') as f:
                json.dump(default, f, indent=2)
            self.authdic = {}

    def add_account(self):
        """add account and register it to local file"""
        api, screen_name = twitter.authentication()
        self.auths[screen_name] = api
        self.streams.append(
            twitter.open_userstream(api, self.receive_tweet, screen_name))
        twitter.getmyicon(api, screen_name)
        accbutton = QPushButton(self)
        accbutton.setWhatsThis(screen_name)
        accbutton.setCheckable(True)
        accbutton.toggled.connect(self.choose_account)
        accbutton.setIcon(PyQt5.QtGui.QIcon('images/' + screen_name + '.jpg'))
        accbutton.setIconSize(QSize(48, 48))
        self.accounts_hbox.insertWidget(self.accounts_hbox.count() - 1,
                                        accbutton)

    def choose_account(self):
        """
        called when accbutton are toggled.
        add or remove active accounts
        """
        acc = self.sender()
        if acc.isChecked():
            self.activeaccounts.append(acc.whatsThis())
        else:
            self.activeaccounts.remove(acc.whatsThis())

    def receive_tweet(self, status, name, icon):
        """called when stream receive a tweet"""
        self.tweets.append((status, name, icon))

    def update_timeline(self):
        """called every 500ms and update gui timeline according to self.tweets"""
        for t in self.tweets:
            if hasattr(t[0], "in_reply_to_status_id"):
                self.addTweet(*t)
            elif hasattr(t[0], "event"):
                self.addEvent(*t)
        self.tweets = []

    def addTweet(self, t, name, icon):
        rtby = None
        if hasattr(t, "retweeted_status"):
            rtby = [t.user.profile_image_url_https, t.user.screen_name]
            t = t.retweeted_status
        tweet = self.create_tweet(t)
        tweet_hbox = QHBoxLayout()
        if icon:
            if not glob.glob("images/" + t.user.screen_name + ".*"):
                twitter.geticon(t.user.profile_image_url_https,
                                t.user.screen_name)
            icon = PyQt5.QtGui.QPixmap(
                glob.glob("images/" + t.user.screen_name + ".*")[0])
            scaled_icon = icon.scaled(QSize(48, 48), 1, 1)
            iconviewer = IconLabel(t.id, name, self.retweet, self.reply)
            iconviewer.setPixmap(scaled_icon)
            icon_vbox = QVBoxLayout()
            icon_vbox.addWidget(iconviewer, alignment=Qt.AlignTop)
            if rtby:
                if not glob.glob("images/" + rtby[1] + ".*"):
                    twitter.geticon(*rtby)
                icon = PyQt5.QtGui.QPixmap(
                    glob.glob("images/" + rtby[1] + ".*")[0])
                scaled_icon = icon.scaled(QSize(24, 24), 1, 1)
                rticonviewer = QLabel()
                rticonviewer.setPixmap(scaled_icon)
                rticon_hbox = QHBoxLayout()
                #rticon_hbox.addStretch()
                rticon_hbox.addWidget(rticonviewer,
                                      alignment=(Qt.AlignRight | Qt.AlignTop))
                icon_vbox.addLayout(rticon_hbox)
                icon_vbox.addStretch()
            tweet_hbox.addLayout(icon_vbox)
        tweet_hbox.addWidget(tweet)
        favbutton = QPushButton("fav")
        favbutton.setSizePolicy(QSizePolicy.MinimumExpanding,
                                QSizePolicy.MinimumExpanding)
        favbutton.setCheckable(True)
        favbutton.toggled.connect(lambda: self.fav(t.id, name))
        tweet_hbox.addWidget(favbutton)
        self.timeline_vbox.insertLayout(0, tweet_hbox)
        if "media" in t.entities:
            images = twitter.get_allimages(self.auths[name], t.id)
            self.imagetext.setPlainText("@" + t.user.screen_name + "\n" +
                                        t.text)
            for n, _ in enumerate(images):
                pixmap = PyQt5.QtGui.QPixmap()
                pixmap.loadFromData(QByteArray(images[n]))
                scaled = pixmap.scaled(QSize(320, 180), 1, 1)
                imageviewer = QLabel()
                imageviewer.setPixmap(scaled)
                self.imagetimeline.insertWidget(0, imageviewer)

    def addEvent(self, t, name, icon):
        if t.event == "favorite" and not (t.source["screen_name"]
                                          in self.auths.keys()):
            text = t.source["screen_name"] + " favored " + t.target_object[
                "text"]
            favLabel = QLabel(text)
            self.timeline_vbox.insertWidget(0, favLabel)

    def create_tweet(self, t):
        """create tweet widget"""
        text = "@" + t.user.screen_name + "\n" + t.text
        tweetdocument = PyQt5.QtGui.QTextDocument()
        tweetdocument.setTextWidth(
            300)  #this line is not working so it needs to be fixed someday
        tweetdocument.setPlainText(text)
        tweettext = QTextEdit()
        tweettext.setDocument(tweetdocument)
        tweettext.setReadOnly(True)
        tweettext.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        tweettext.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        tweettext.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        tweettext.setAttribute(103)
        tweettext.show()
        tweettext.setFixedHeight(tweettext.document().size().height() +
                                 tweettext.contentsMargins().top() * 2)
        return tweettext

    def submit(self):
        """called when tweet button is pressed and submit tweet"""
        if not self.activeaccounts:
            return
        submittext = self.composer.toPlainText()
        for t in self.tweettags:
            submittext = submittext + " " + t
        if not submittext:
            return
        for a in self.activeaccounts:
            self.auths[a].update_status(submittext)
        self.composer.setPlainText("")

    def fav(self, tweetid, name):
        '''favor or unfavor a tweet from an account from which the tweet was obtained'''
        switch = self.sender()
        if switch.isChecked():
            try:
                self.auths[name].create_favorite(tweetid)
            except:
                print("already favored")
        else:
            try:
                self.auths[name].destroy_favorite(tweetid)
            except:
                print("not favored")

    def retweet(self, id, account):
        self.auths[account].retweet(id)

    def reply(self, id, account):
        if not self.activeaccounts:
            return
        submittext = self.composer.toPlainText()
        if not submittext:
            return
        self.auths[account].update_status(submittext,
                                          in_reply_to_status_id=id,
                                          auto_populate_reply_metadata=True)
        self.composer.setPlainText("")

    def sethashtag(self):
        """set hashtab for receive and tweet"""
        switch = self.sender()
        if switch.isChecked():
            htinput = self.hashtagedit.text()
            htlist = htinput.strip().split()
            for t in htlist:
                if not t[0] == "*":
                    self.receivetags.append(t)
                    self.tweettags.append(t)
                else:
                    self.receivetags.append(t[1:])
            repl_screen_name = list(self.auths.keys())[0]
            self.searchstream = twitter.open_filterstream(
                self.auths[repl_screen_name], self.receive_tweet,
                repl_screen_name, self.receivetags)
        else:
            self.receivetags = []
            self.tweettags = []
            self.searchstream.disconnect()

    def closeEvent(self, event):
        """called when gui window is closed and terminate all streams and thread"""
        for s in self.streams:
            s.disconnect()
        os._exit(1)
示例#23
0
class PadCalc(QWidget):
    def __init__(self):
        super().__init__()
        load_data()

        card_tags = ['leader','sub1','sub2','sub3','sub4','friend']
        self.cards = { t: CardIcon() for t in card_tags }

        self.vlayout = QVBoxLayout(self)
        self.vlayout.setSpacing(0)
        self.setLayout(self.vlayout)

        self.userbox = QHBoxLayout()
        userfield = QLineEdit()
        userbutton = QPushButton('Load')
        userbutton.clicked.connect(lambda: self.set_user(userfield.text()))
        self.userbox.addWidget(userfield)
        self.userbox.addWidget(userbutton)
        userfield.returnPressed.connect(userbutton.click)
        self.vlayout.addLayout(self.userbox)

        maxcheckbox = QCheckBox('Use maxed stats?')
        maxcheckbox.stateChanged[int].connect(self.setMaxed)
        self.vlayout.addWidget(maxcheckbox)


        self.teamchooser = QComboBox(self)
        self.teamchooser.currentIndexChanged[int].connect(self.set_team)
        self.vlayout.addWidget(self.teamchooser)

        teambox = QHBoxLayout()
        teambox.addStretch(1)
        for card in card_tags:
            teambox.addWidget(self.cards[card])

        teambox.setSpacing(0)
        teambox.addStretch(1)
        teambox.setAlignment(Qt.AlignCenter)
        self.vlayout.addLayout(teambox)

        self.board = Board()
        self.vlayout.addWidget(self.board)
        self.vlayout.itemAt(self.vlayout.indexOf(self.board)).setAlignment(Qt.AlignCenter)

        self.orbchooser = QHBoxLayout()
        b = OrbButton(value = 0)
        b.clicked.connect(functools.partial(self.setPaintOrb,Orb.Null))
        self.orbchooser.addWidget(b)
        for i in ORBS:
            b = OrbButton(value=i)
            #print('Setting click value of button %s to %s' % (id(b),i))
            b.clicked.connect(functools.partial(self.setPaintOrb,i))
            self.orbchooser.addWidget(b)

        self.vlayout.addLayout(self.orbchooser)

        self.damagereadout = QLabel()
        font = QFont()
        font.setPointSize(30)
        self.damagereadout.setAlignment(Qt.AlignCenter)
        self.damagereadout.setFont(font)
        self.vlayout.addWidget(self.damagereadout)
        self.board.valueChanged.connect(self.update_damage)

        labels = ['atk','combos','leaders','enhance','prongs','rows']
        lfont = QFont()
        lfont.setPointSize(9)
        vfont = QFont()
        vfont.setPointSize(12)
        self.details = {key: QVBoxLayout() for key in labels}
        for i in labels:
            label = QLabel(i)
            label.setFont(lfont)
            label.setAlignment(Qt.AlignCenter)
            label.setMargin(0)
            label.setContentsMargins(0,0,0,0)
            label.setIndent(0)
            self.details[i].label = label
            self.details[i].addWidget(self.details[i].label)
            value = QLabel('1')
            value.setFont(vfont)
            value.setAlignment(Qt.AlignCenter)
            value.setMargin(0)
            value.setIndent(0)
            value.setContentsMargins(0,0,0,0)
            self.details[i].value = value
            self.details[i].addWidget(self.details[i].value)
            self.details[i].setContentsMargins(1,1,1,1)

        self.detailreadout = QHBoxLayout()
        for i in labels:
            self.detailreadout.addLayout(self.details[i])
            timeslabel = QLabel('\u00d7')
            timeslabel.setMargin(0)
            timeslabel.setIndent(0)
            timeslabel.setAlignment(Qt.AlignCenter)
            timeslabel.setContentsMargins(0,0,0,0)
            self.detailreadout.addWidget(timeslabel)

        self.detailreadout.takeAt(self.detailreadout.count()-1)
        self.vlayout.addLayout(self.detailreadout)

        self.vlayout.addStretch(1000)
        self.skillbox = QHBoxLayout()
        self.vlayout.addLayout(self.skillbox)
        #self.set_user('korora')

    def setMaxed(self,state):
        Card.use_max_stats = (state == Qt.Checked)
        self.drawui()
        self.update_damage()
        self.set_team(self.teamchooser.currentIndex())

    def setPaintOrb(self,orb):
        global paintOrb
        paintOrb = orb

    def set_user(self,username):
        newuser = User(username)

        if hasattr(self,'user'):
            olduser = self.user.username
        else:
            olduser = ''

        if hasattr(newuser,'teams') and len(newuser.teams) > 0:
            teamchooser = self.teamchooser
            self.user = newuser
            index = teamchooser.currentIndex()
            try:
                teamchooser.currentIndexChanged[int].disconnect()
            except:
                return

            teamchooser.clear()
            for team in self.user.teams:
                teamchooser.addItem('%s' % (team['name']))

            if newuser.username != olduser:
                self.set_team(0)
            else:
                teamchooser.setCurrentIndex(index)
                self.set_team(index)

            teamchooser.currentIndexChanged[int].connect(self.set_team)

    def update_damage(self):
        (match,enhanced,row) = self.board.match()
        nmatch = sum(len(v) for v in match.values())
        nrow = sum(v for v in row.values())
        (dmg, multipliers) = compute_damage((match,enhanced,row),self.team)
        self.damagereadout.setText('{:,}'.format(round(sum([sum(i) for i in dmg.values()]))))
        for i in multipliers:
            if i is not 'atk':
                self.details[i].value.setText('%.2f' % multipliers[i])
            else:
                self.details[i].value.setText('%d' % multipliers[i])

        for card in self.cards.values():
            # add a damage label
            dam = dmg[card.card]
            card.main_attack = dam[0]
            card.sub_attack = dam[1]
            card.repaint()

    def set_team(self,index):
        teamdata = self.user.teams[index]
        team = []
        for i in ['leader','sub1','sub2','sub3','sub4']:
            team += [Card().load_from_id(self.user,teamdata[i])]
        friend = {
                'monster': teamdata['friend_leader'],
                'plus_atk': teamdata['friend_atk'],
                'plus_hp': teamdata['friend_hp'],
                'plus_rcv': teamdata['friend_rcv'],
                'current_awakening': teamdata['friend_awakening'],
                'lv': teamdata['friend_level'],
                'current_skill': teamdata['friend_skill']
                }
        team += [Card().load_from_card(friend)]
        self.team = Team(team)
        #print('|'+self.teamchooser.itemText(index)+'|')
        #print(len(self.teamchooser.itemText(index)))
        self.teamchooser.setMinimumContentsLength(len(self.teamchooser.itemText(index))-3)
        for i in range(self.skillbox.count()):
            w = self.skillbox.takeAt(i)
            w.widget().deleteLater()
            
        #svc = SkillViewController(skill=self.team.lskills[0])
        #svc.skillsChanged.connect(self.update_damage)
        #self.skillbox.addWidget(svc)
        self.drawui()
        self.update_damage()

    def drawui(self):
        self.cards['leader'].card = (self.team.cards[0])
        self.cards['sub1'].card = (self.team.cards[1])
        self.cards['sub2'].card = (self.team.cards[2])
        self.cards['sub3'].card = (self.team.cards[3])
        self.cards['sub4'].card = (self.team.cards[4])
        self.cards['friend'].card = (self.team.cards[5])
        for card in self.cards.values():
            card.load_icon()
示例#24
0
class ParameterContainer(QWidget, object):
    """Container to hold Parameter Widgets."""

    def __init__(
            self,
            parameters=None,
            description_text='',
            extra_parameters=None,
            parent=None,
            vertical=True):
        """Constructor

        .. versionadded:: 2.2

        :param parameters: List of Parameter Widget
        :type parameters: list

        :param description_text: Text for description of the parameter
            container.
        :type description_text: str

        """
        super().__init__(parent)
        # attributes
        if not parameters:
            self.parameters = []
        else:
            self.parameters = parameters
        self.description_text = description_text
        self.extra_parameters = extra_parameters
        self.parent = parent
        self.validators = []
        self.validators_kwargs = []

        # UI
        if vertical:
            self.vertical_layout = QVBoxLayout()
        else:
            self.vertical_layout = QHBoxLayout()
        self.widget = QWidget()
        self.description_label = QLabel()
        self.description_label.setWordWrap(True)
        self.scroll_area = QScrollArea()
        self.group_frame = QFrame()
        self.qt5_parameter_factory = Qt5ParameterFactory()
        self.main_layout = QGridLayout()

# NOTES(IS) : These functions are commented since the architecture is not
    #  ready yet.
    # def register_widget(self, parameter, parameter_widget):
    #     """Register new custom widget.
    #
    #     :param parameter:
    #     :type parameter: GenericParameter
    #
    #     :param parameter_widget:
    #     :type parameter_widget: GenericParameterWidget
    #     """
    #     self.qt5_parameter_factory.register_widget(
    # parameter, parameter_widget)
    #
    # def remove_widget(self, parameter):
    #     """Register new custom widget.
    #
    #     :param parameter:
    #     :type parameter: GenericParameter
    #     """
    #     if parameter.__name__ in self.dict_widget.keys():
    #         self.dict_widget.pop(parameter.__name__)

    def get_parameters(self, validate=True):
        """Return list of parameters from the current state of widget.

        :param validate: If true, run validator, else no.
        :type validate: bool

        :returns: List of parameter
        :rtype: list
        """
        if validate:
            validation_result = self.validate()
            if not validation_result['valid']:
                raise InvalidValidationException(validation_result['message'])

        parameter_widgets = self.get_parameter_widgets()

        parameters = []

        for widget_item in parameter_widgets:
            parameter_widget = widget_item.widget()

            parameter = parameter_widget.get_parameter()
            parameters.append(parameter)

        # returns based on the object type of self.parameters
        if isinstance(self.parameters, list):
            return parameters
        else:
            # just return single parameter
            return parameters[0]

    def get_parameter_widgets(self):
        """Return list of parameter widgets from the current state of widget.

        :returns: List of parameter widget
        :rtype: list
        """

        parameter_widgets = [self.vertical_layout.itemAt(i) for i in range(
            self.vertical_layout.count())]

        return parameter_widgets

    def setup_ui(self, must_scroll=True):
        """Setup the UI of this parameter container.
        """
        # Vertical layout to place the parameter widgets
        self.vertical_layout.setContentsMargins(0, 0, 0, 0)
        self.vertical_layout.setSpacing(0)

        # Widget to hold the vertical layout
        self.widget = QWidget()
        self.widget.setLayout(self.vertical_layout)

        # Label for description
        self.description_label.setText(self.description_text)

        self.group_frame.setLineWidth(0)
        self.group_frame.setFrameStyle(QFrame.NoFrame)
        vlayout = QVBoxLayout()
        vlayout.setContentsMargins(0, 0, 0, 0)
        vlayout.setSpacing(0)
        self.group_frame.setLayout(vlayout)

        if must_scroll:
            vlayout.addWidget(self.scroll_area)
            self.scroll_area.setWidgetResizable(True)
            self.scroll_area.setWidget(self.widget)
        else:
            vlayout.addWidget(self.widget)

        # Main layout of the container
        if self.description_text:
            self.main_layout.addWidget(self.description_label)
        self.main_layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.main_layout)

        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.MinimumExpanding)

        if not isinstance(self.parameters, list):
            parameters = [self.parameters]
        else:
            parameters = self.parameters

        if len(parameters) == 0:
            self.set_empty_parameters()
            return

        self.main_layout.addWidget(self.group_frame)

        self.qt5_parameter_factory = Qt5ParameterFactory()
        if self.extra_parameters is not None:
            for extra_parameter in self.extra_parameters:
                if (type(extra_parameter) == tuple and
                        len(extra_parameter) == 2):
                    self.qt5_parameter_factory.register_widget(
                        extra_parameter[0], extra_parameter[1])

        for parameter in parameters:
            parameter_widget = self.qt5_parameter_factory.get_widget(parameter)
            parameter_widget.setAutoFillBackground(True)
            self.vertical_layout.addWidget(parameter_widget)

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    def set_description(self, description):
        """Set description of the parameter container.

        :param description: A new description fot the parameter container.
        :type description: str
        """
        self.description_text = description
        self.description_label.setText(self.description_text)

    def set_empty_parameters(self):
        """Update UI if there is no parameters in the container.
        """
        new_description = self.description_text
        new_description += '\n'
        new_description += 'But, currently there is no parameters available.'
        self.description_label.setText(new_description)

    def add_validator(self, validator, **kwargs):
        """Add validator for this parameter container.

        :param validator: validator function for this parameter container.
        :type validator: function
        """
        validator.parent = self
        self.validators.append(validator)
        if kwargs:
            self.validators_kwargs.append(kwargs)
        else:
            self.validators_kwargs.append({})

    def validate(self):
        """Validate of all rule for all parameter in this container.

        :return: True if all valid, False
        :rtype: dict
        """
        for i in range(len(self.validators)):
            validator = self.validators[i]
            validator_kwargs = self.validators_kwargs[i]
            validation_result = validator(self, **validator_kwargs)
            if not validation_result['valid']:
                return validation_result

        return {
            'valid': True,
            'message': ''
        }

    def get_parameter_by_guid(self, parameter_guid):
        """Return a parameter based on its uuid

        :param parameter_guid: The parameter uuid
        :type parameter_guid: str

        :returns: The parameter or None if not exist
        :rtype: GenericParameter, None
        """
        parameters = self.get_parameters(validate=False)
        for parameter in parameters:
            if parameter.guid == parameter_guid:
                return parameter
        return None

    def get_parameter_widget_by_guid(self, parameter_guid):
        """Return a parameter widget based on its uuid

        :param parameter_guid: The parameter uuid
        :type parameter_guid: str

        :returns: The parameter widget or None if not exist
        :rtype: GenericParameterWidget, None
        """
        parameter_widgets = self.get_parameter_widgets()
        for parameter_widget in parameter_widgets:
            if (parameter_widget.widget().get_parameter().guid ==
                    parameter_guid):
                return parameter_widget.widget()
        return None
示例#25
0
    def refresh(self):
        addons = sorted(self._addons, key=lambda item: item.name)
        
        prev_checked = set(addon.identifier for addon in self.__checked_addons)
        prev_unchecked = set(addon.identifier for addon in self.__addons if addon not in self.__checked_addons)
        
        self.__addons = list(addons)
        
        self.__checked_addons = set()
        
        button_factory = self._addon_button_factory()
        
        self.setRowCount(len(self.__addons))
        
        for no, addon in enumerate(self.__addons):
            check_widget = QWidget()
            check_layout = QHBoxLayout()
            check_layout.setAlignment(Qt.AlignCenter)
            check_check = QCheckBox()
            if addon.identifier not in prev_unchecked:
                check_check.setChecked(True)
                self.__checked_addons.add(addon)
            check_check.toggled.connect(partial(self.__check_checked, addon))
            check_check.setFocusPolicy(Qt.NoFocus)
            check_layout.addWidget(check_check)
            check_widget.setLayout(check_layout)
            self.setCellWidget(no, 0, check_widget)
            
            if addon.icon:
                icon_widget = QWidget()
                icon_layout = QVBoxLayout()
                icon_layout.setSpacing(0)
                icon_widget.setLayout(icon_layout)
                icon_label = QLabel()
                icon_label.setAutoFillBackground(False)
                icon_label.setPixmap(image_loader.load(addon.icon))
                icon_label.setAlignment(Qt.AlignTop)
                icon_layout.addWidget(icon_label)
                
                lp, tp, rp, bp = icon_layout.getContentsMargins()
                icon_layout.setContentsMargins(lp, tp, 0, bp)
                
                self.setCellWidget(no, 1, icon_widget)
            
            layout = QVBoxLayout()
            layout.setSpacing(0)
            layout.setAlignment(Qt.AlignTop)
            
            name_layout = QHBoxLayout()
            name_layout.setSpacing(20)
            name_layout.setAlignment(Qt.AlignLeft)
            
            name_label = QLabel(addon.name)
            name_label.setAutoFillBackground(False)
            name_label.setTextFormat(Qt.PlainText)
            font = name_label.font()
            font.setWeight(QFont.Bold)
            name_label.setFont(font)
            name_layout.addWidget(name_label)
            
            if isinstance(addon, OnlineAddOn):
                if self.__show_prev_version:
                    version = "{0} ⟶ {1}".format(addon.local_addon.version, addon.latest_version.version)
                else:
                    version = addon.latest_version.version
            else:
                version = addon.version
            
            version_label = QLabel(str(version))
            version_label.setAutoFillBackground(False)
            version_label.setTextFormat(Qt.PlainText)
            name_layout.addWidget(version_label)
            
            layout.addLayout(name_layout)
            
            if addon.description:
                description_label = QLabel(addon.description)
                description_label.setAutoFillBackground(False)
                description_label.setTextFormat(Qt.PlainText)
                description_label.setWordWrap(True)
                layout.addWidget(description_label)
            
            addon_button_box = QHBoxLayout()
            addon_button_box.setAlignment(Qt.AlignRight)
            
            addon_button_box_widget = QWidget()
            addon_button_box_widget.setLayout(addon_button_box)
            if self.EXPANDING_BUTTON_BOX:
                addon_button_box_widget.setVisible(False)
            addon_button_box_widget.setObjectName("button_box")
            
            if button_factory is not None:
                button_factory.add_buttons(addon, addon_button_box, addon_button_box_widget)
            
            if addon_button_box.count() > 0:
                layout.addWidget(addon_button_box_widget)
            
            widget = QWidget()
            widget.setLayout(layout)
            self.setCellWidget(no, 2, widget)

            self.__refresh_selection_colors(widget, False)
        
        self.resizeColumnsToContents()
        self.resizeRowsToContents()
        
        cur_checked = set(addon.identifier for addon in self.__checked_addons)
        
        if prev_checked != cur_checked:
            self.check_changed.emit()
示例#26
0
class LineEdit(QLineEdit):
    inactiveText  = QtDynamicProperty('inactiveText',  unicode)
    widgetSpacing = QtDynamicProperty('widgetSpacing', int)

    def __init__(self, parent=None, contents=u""):
        super(LineEdit, self).__init__(contents, parent)
        box_direction = QBoxLayout.RightToLeft if self.isRightToLeft() else QBoxLayout.LeftToRight
        self.inactiveText = u""
        self.left_widget = SideWidget(self)
        self.left_widget.resize(0, 0)
        self.left_layout = QHBoxLayout(self.left_widget)
        self.left_layout.setContentsMargins(0, 0, 0, 0)
        self.left_layout.setDirection(box_direction)
        self.left_layout.setSizeConstraint(QLayout.SetFixedSize)
        self.right_widget = SideWidget(self)
        self.right_widget.resize(0, 0)
        self.right_layout = QHBoxLayout(self.right_widget)
        self.right_layout.setContentsMargins(0, 0, 0, 0)
        self.right_layout.setDirection(box_direction)
        self.right_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum))
        self.widgetSpacing = 2
        self.left_widget.sizeHintChanged.connect(self._update_text_margins)
        self.right_widget.sizeHintChanged.connect(self._update_text_margins)

    @property
    def left_margin(self):
        return self.left_widget.sizeHint().width() + 2*self.left_layout.spacing()

    @property
    def right_margin(self):
        return self.right_widget.sizeHint().width() + 2*self.right_layout.spacing()

    def _update_text_margins(self):
        self.setTextMargins(self.left_margin, 0, self.right_margin, 0)
        self._update_side_widget_locations()

    def _update_side_widget_locations(self):
        option = QStyleOptionFrame()
        self.initStyleOption(option)
        spacing = self.right_layout.spacing()
        text_rect = self.style().subElementRect(QStyle.SE_LineEditContents, option, self)
        text_rect.adjust(spacing, 0, -spacing, 0)
        mid_height = text_rect.center().y() + 1 - (text_rect.height() % 2)  # need -1 correction for odd heights -Dan
        if self.left_layout.count() > 0:
            left_height = mid_height - self.left_widget.height()/2
            left_width = self.left_widget.width()
            if left_width == 0:
                left_height = mid_height - self.left_widget.sizeHint().height()/2
            self.left_widget.move(text_rect.x(), left_height)
        text_rect.setX(self.left_margin)
        text_rect.setY(mid_height - self.right_widget.sizeHint().height()/2.0)
        text_rect.setHeight(self.right_widget.sizeHint().height())
        self.right_widget.setGeometry(text_rect)

    def event(self, event):
        event_type = event.type()
        if event_type == QEvent.LayoutDirectionChange:
            box_direction = QBoxLayout.RightToLeft if self.isRightToLeft() else QBoxLayout.LeftToRight
            self.left_layout.setDirection(box_direction)
            self.right_layout.setDirection(box_direction)
        elif event_type == QEvent.DynamicPropertyChange:
            property_name = event.propertyName()
            if property_name == 'widgetSpacing':
                self.left_layout.setSpacing(self.widgetSpacing)
                self.right_layout.setSpacing(self.widgetSpacing)
                self._update_text_margins()
            elif property_name == 'inactiveText':
                self.update()
        return QLineEdit.event(self, event)

    def resizeEvent(self, event):
        self._update_side_widget_locations()
        QLineEdit.resizeEvent(self, event)

    def paintEvent(self, event):
        QLineEdit.paintEvent(self, event)
        if not self.hasFocus() and not self.text() and self.inactiveText:
            options = QStyleOptionFrame()
            self.initStyleOption(options)
            text_rect = self.style().subElementRect(QStyle.SE_LineEditContents, options, self)
            text_rect.adjust(self.left_margin+2, 0, -self.right_margin, 0)
            painter = QPainter(self)
            painter.setPen(self.palette().brush(QPalette.Disabled, QPalette.Text).color())
            painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignVCenter, self.inactiveText)

    def addHeadWidget(self, widget):
        if self.isRightToLeft():
            self.right_layout.insertWidget(1, widget)
        else:
            self.left_layout.addWidget(widget)

    def addTailWidget(self, widget):
        if self.isRightToLeft():
            self.left_layout.addWidget(widget)
        else:
            self.right_layout.insertWidget(1, widget)

    def removeWidget(self, widget):
        self.left_layout.removeWidget(widget)
        self.right_layout.removeWidget(widget)
        widget.hide()
示例#27
0
class MainWindow(QMainWindow):
    def __init__(self, dataBaseName):
        super().__init__()
        self._dataBase = myDatabase.MyDataBase(dataBaseName)

        self._dictexe = {
            "первый запрос": (self.firstQuery, self.firstExe),
            "второй запрос": (self.secondQuery, self.secondExe),
            "третий запрос": (self.thirdQuery, self.thirdExe)
        }

        self._view = QTreeView()

        self._buttonAdd = QPushButton("Добавить")
        self._buttonAdd.clicked.connect(self.getItems)
        self._addSpinBox = QSpinBox()
        self._addComboBox = QComboBox()
        self._addComboBox.addItems(self._dataBase.dishes())

        self._layout = QHBoxLayout()
        self._qSpinBox = QSpinBox()
        self._qComboBox = QComboBox()
        self._qLineEdit = QLineEdit()
        self._qCalendarWidget = QCalendarWidget()

        self._queryDisc = QLabel()

        self._buttonExe = QPushButton("Исполнить")
        self._buttonExe.clicked.connect(self.onButtonExe)

        self._combox = QComboBox()
        self._combox.currentTextChanged.connect(self.comboChanged)
        self._combox.addItems(self._dictexe.keys())

        self.initUi()

    def initUi(self):
        self.setGeometry(300, 300, 200, 200)
        self.setWindowTitle('Ресторан')
        #self.setWindowIcon(QIcon(''))

        w = QWidget()

        mainLayout = QVBoxLayout()
        w.setLayout(mainLayout)

        self.setCentralWidget(w)

        mainLayout.addWidget(self._view)

        tmpLayout = QHBoxLayout()
        mainLayout.addLayout(tmpLayout)
        tmpLayout.addWidget(QLabel("Добавления ингредиента"))
        tmpLayout.addWidget(self._addSpinBox)
        tmpLayout.addWidget(self._addComboBox)
        tmpLayout.addWidget(self._buttonAdd)

        mainLayout.addWidget(self._queryDisc)

        tmpLayout = QHBoxLayout()
        mainLayout.addLayout(tmpLayout)
        tmpLayout.addWidget(self._combox)
        tmpLayout.addLayout(self._layout)
        tmpLayout.addWidget(self._buttonExe)

        self.adjustSize()

    def comboChanged(self, text):
        self._dictexe[text][0]()

    def clearLayout(self):
        while self._layout.count() > 0:
            self._layout.itemAt(0).widget().setParent(None)

    #Названия и калорийность блюд по рецептам автора X
    def firstQuery(self):
        self._queryDisc.setText(
            "Названия и калорийность блюд по рецептам автора X")
        self.clearLayout()
        #self._qSpinBox.setValue(0)
        #self._layout.insertWidget(1,self._qSpinBox)
        self._qComboBox.clear()
        self._qComboBox.addItems(self._dataBase.authors())
        self._layout.insertWidget(1, self._qComboBox)

    def firstExe(self):
        model = self._dataBase.first(self._qComboBox.currentText())
        self.setModel(model)

    #Названия ресторанов, к которым относятся повара, готовящие блюда содержащие в
    #названии подстроку X (например, «картофельный»), отсортированные по алфавиту
    def secondQuery(self):
        self._queryDisc.setText(
            "Названия ресторанов, к которым относятся повара,\n готовящие блюда содержащие в названии подстроку X (например, «картофельный»),\n отсортированные по алфавиту"
        )
        self.clearLayout()
        self._qLineEdit.clear()
        self._layout.insertWidget(1, self._qLineEdit)

    def secondExe(self):
        model = self._dataBase.second(self._qLineEdit.text())
        self.setModel(model)

    #Названия и количества ингредиентов и названия мероприятий, на которых разливают
    #напитки в количестве меньше X после даты Y
    def thirdQuery(self):
        self._queryDisc.setText(
            "Названия и количества ингредиентов и названия мероприятий, на которых разливают\n напитки в количестве меньше X после даты Y"
        )
        self.clearLayout()
        self._layout.insertWidget(1, self._qCalendarWidget)
        self._qSpinBox.setMaximum(self._dataBase.maxDrinkCount() * 10)
        self._qSpinBox.setValue(0)
        self._layout.insertWidget(1, self._qSpinBox)

    def thirdExe(self):
        model = self._dataBase.third(
            self._qSpinBox.value(),
            self._qCalendarWidget.selectedDate().toPyDate())
        self.setModel(model)

    def setModel(self, model):
        if model is None:
            return
        self._view.setVisible(False)
        self._view.setModel(model)
        for i in range(model.columnCount()):
            self._view.resizeColumnToContents(i)
        self._view.setVisible(True)
        self.adjustSize()

    def onButtonExe(self):
        self._dictexe[self._combox.currentText()][1]()

    def getItems(self):
        name, ok = QInputDialog.getText(self, "Ингредиент", "Введите название")
        if not ok:
            return

        self._dataBase.add(self._addSpinBox.value(),
                           self._addComboBox.currentText(), name)
示例#28
0
class EstimhabW(StatModUseful):
    """
    The Estimhab class provides the graphical interface for the version of the Estimhab model written in HABBY.
    The Estimhab model is described elsewhere. EstimhabW() just loads the data for Estimhab given by the user.
    """

    save_signal_estimhab = pyqtSignal()
    """
    PyQtsignal to save the Estimhab data.
    """
    def __init__(self, path_prj, name_prj):

        super().__init__()
        self.tab_name = "estimhab"
        self.tab_position = 7
        self.model_type = "Estimhab"
        self.eq50 = QLineEdit()
        self.esub = QLineEdit()
        self.path_prj = path_prj
        self.name_prj = name_prj
        self.path_bio_estimhab = os.path.join(self.path_bio, 'estimhab')
        self.total_lineedit_number = 1
        self.init_iu()
        self.process_manager = MyProcessManager(
            "estimhab_plot")  # SC (Suitability Curve)
        self.read_estimhab_dict()
        self.fill_input_data()
        self.fill_fish_name()
        self.check_if_ready_to_compute()
        self.eq1.textChanged.connect(self.check_if_ready_to_compute)
        self.eq2.textChanged.connect(self.check_if_ready_to_compute)
        self.ew1.textChanged.connect(self.check_if_ready_to_compute)
        self.ew2.textChanged.connect(self.check_if_ready_to_compute)
        self.eh1.textChanged.connect(self.check_if_ready_to_compute)
        self.eh2.textChanged.connect(self.check_if_ready_to_compute)
        self.eq50.textChanged.connect(self.check_if_ready_to_compute)
        self.eqmin.textChanged.connect(self.check_if_ready_to_compute)
        self.eqmax.textChanged.connect(self.check_if_ready_to_compute)
        self.esub.textChanged.connect(self.check_if_ready_to_compute)
        self.selected_aquatic_animal_qtablewidget.model().rowsInserted.connect(
            self.check_if_ready_to_compute)
        self.selected_aquatic_animal_qtablewidget.model().rowsRemoved.connect(
            self.check_if_ready_to_compute)

    def init_iu(self):
        """
        This function is used to initialized an instance of the EstimhabW() class. It is called by __init__().

         **Technical comments and walk-through**

         First we looked if some data for Estimhab was saved before by an user. If yes, we will fill the GUI with
         the information saved before. Estimhab information is saved in hdf5 file format and the path/name of the
         hdf5 file is saved in the xml project file. So we open the xml project file and look if the name of an hdf5
         file was saved for Estimhab. If yes, the hdf5 file is read.

         The format of hdf5 file is relatively simple. Each input data for Estimhab has its own dataset (qmes, hmes,
         wmes, q50, qrange, and substrate).  Then, we have a list of string which are a code for the fish species which
         were analyzed.  All the data contained in hdf5 file is loaded into variable.

         The different label are written on the graphical interface. Then, two QListWidget are modified. The first
         list contains all the fish species on which HABBY has info (see XML Estimhab format for more info).
         The second list is the fish selected by the user on which Estimhab will be run. Here, we link these lists
         with two functions so that the user can select/deselect fish using the mouse. The function name are add_fish()
         and remove_fish().

         Then, we fill the first list. HABBY look up all file of xml type in the “Path_bio” folder (the one indicated in
         the xml project file under the attribute “Path_bio”).  The name are them modified so that the only the name of
         species appears (and not the full path). We set the layout with all the different QLineEdit where the user
         can write the needed data.

         Estimhab model is saved using a function situated in MainWindows_1.py  (frankly, I am not so sure why I did put
         the save function there, but anyway). So the save button just send a signal to MainWindows
         here, which save the data.
        """

        available_model_label = QLabel(self.tr('Available'))
        selected_model_label = QLabel(self.tr('Selected'))

        self.lineedit_width = 50
        self.spacer_width = 50

        # input
        q1_layout = QHBoxLayout()
        q1_layout.addWidget(QLabel('Q1 [m<sup>3</sup>/s]'))
        q1_layout.addWidget(self.eq1)
        q1_layout.addItem(QSpacerItem(self.spacer_width, 1))
        self.eq1.setFixedWidth(self.lineedit_width)

        q2_layout = QHBoxLayout()
        q2_layout.addWidget(QLabel('Q2 [m<sup>3</sup>/s]'))
        q2_layout.addWidget(self.eq2)
        q2_layout.addItem(QSpacerItem(self.spacer_width, 1))
        self.eq2.setFixedWidth(self.lineedit_width)

        w1_layout = QHBoxLayout()
        w1_layout.addWidget(QLabel(self.tr("Width1 [m]")))
        w1_layout.addWidget(self.ew1)
        w1_layout.addItem(QSpacerItem(self.spacer_width, 1))
        self.ew1.setFixedWidth(self.lineedit_width)

        w2_layout = QHBoxLayout()
        w2_layout.addWidget(QLabel(self.tr("Width2 [m]")))
        w2_layout.addWidget(self.ew2)
        w2_layout.addItem(QSpacerItem(self.spacer_width, 1))
        self.ew2.setFixedWidth(self.lineedit_width)

        h1_layout = QHBoxLayout()
        h1_layout.addWidget(QLabel(self.tr("Height1 [m]")))
        h1_layout.addWidget(self.eh1)
        self.eh1.setFixedWidth(self.lineedit_width)

        h2_layout = QHBoxLayout()
        h2_layout.addWidget(QLabel(self.tr("Height2 [m]")))
        h2_layout.addWidget(self.eh2)
        self.eh2.setFixedWidth(self.lineedit_width)

        q50_layout = QHBoxLayout()
        q50_layout.addWidget(QLabel('Qmedian/Q50 [m<sup>3</sup>/s]'))
        q50_layout.addWidget(self.eq50)
        q50_layout.addItem(QSpacerItem(self.spacer_width, 1))
        self.eq50.setFixedWidth(self.lineedit_width)

        sub_layout = QHBoxLayout()
        sub_layout.addWidget(QLabel(self.tr('Mean substrate size [m]')))
        sub_layout.addWidget(self.esub)
        sub_layout.addItem(QSpacerItem(self.spacer_width, 1))
        self.esub.setFixedWidth(self.lineedit_width)

        # output
        q1out_layout = QHBoxLayout()
        q1out_layout.addWidget(QLabel(self.tr("Qmin [m<sup>3</sup>/s]")))
        q1out_layout.addWidget(self.eqmin)
        q1out_layout.addItem(QSpacerItem(self.spacer_width, 1))
        self.eqmin.setFixedWidth(self.lineedit_width)

        q2out_layout = QHBoxLayout()
        q2out_layout.addWidget(QLabel(self.tr("Qmax [m<sup>3</sup>/s]")))
        q2out_layout.addWidget(self.eqmax)
        q2out_layout.addItem(QSpacerItem(self.spacer_width, 1))
        self.eqmax.setFixedWidth(self.lineedit_width)

        self.q2target_layout = QHBoxLayout()
        self.q2target_layout.addWidget(
            QLabel(self.tr("Qtarget [m<sup>3</sup>/s]")))
        self.q2target_layout.addWidget(self.add_qtarget_button)
        self.q2target_layout.addWidget(self.remove_qtarget_button)
        self.add_qtarget_button.clicked.connect(self.add_new_qtarget)
        self.remove_qtarget_button.clicked.connect(self.remove_one_qtarget)

        # create lists with the possible fishes
        self.list_f.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list_f.setDragDropMode(QAbstractItemView.DragDrop)
        self.list_f.setDefaultDropAction(Qt.MoveAction)
        self.list_f.setAcceptDrops(True)
        self.list_f.setSortingEnabled(True)

        self.selected_aquatic_animal_qtablewidget.setSelectionMode(
            QAbstractItemView.ExtendedSelection)
        self.selected_aquatic_animal_qtablewidget.setDragDropMode(
            QAbstractItemView.DragDrop)
        self.selected_aquatic_animal_qtablewidget.setDefaultDropAction(
            Qt.MoveAction)
        self.selected_aquatic_animal_qtablewidget.setAcceptDrops(True)
        self.selected_aquatic_animal_qtablewidget.setSortingEnabled(True)

        # insist on white background color (for linux, mac)
        self.setAutoFillBackground(True)
        p = self.palette()
        p.setColor(self.backgroundRole(), Qt.white)
        self.setPalette(p)

        # send model
        self.run_stop_button = QPushButton(self.tr('Run Estimhab'), self)
        self.run_stop_button.clicked.connect(self.run_estmihab)
        change_button_color(self.run_stop_button, "#47B5E6")
        self.run_stop_button.setEnabled(False)

        # empty frame scrolable
        content_widget = QFrame()

        # hydraulic_data_group
        hydraulic_data_group = QGroupBox(self.tr('Hydraulic data input'))
        hydraulic_data_group.setToolTip(
            self.tr("Double click to reset the input data group."))
        hydraulic_data_layout = QGridLayout(hydraulic_data_group)
        hydraulic_data_layout.addLayout(q1_layout, 0, 0)
        hydraulic_data_layout.addLayout(w1_layout, 0, 1)
        hydraulic_data_layout.addLayout(h1_layout, 0, 2)
        hydraulic_data_layout.addLayout(q2_layout, 1, 0)
        hydraulic_data_layout.addLayout(w2_layout, 1, 1)
        hydraulic_data_layout.addLayout(h2_layout, 1, 2)
        hydraulic_data_layout.addLayout(q50_layout, 2, 0)
        hydraulic_data_layout.addLayout(sub_layout, 2, 1)
        hydraulic_data_group.setSizePolicy(QSizePolicy.Maximum,
                                           QSizePolicy.Maximum)
        self.doubleclick_input_group = DoubleClicOutputGroup()
        hydraulic_data_group.installEventFilter(self.doubleclick_input_group)
        self.doubleclick_input_group.double_clic_signal.connect(
            self.reset_hydraulic_data_input_group)

        # hydraulic_data_output_group
        hydraulic_data_output_group = QGroupBox(
            self.tr('Desired hydraulic output data'))
        hydraulic_data_output_group.setToolTip(
            self.tr("Double click to reset the outpout data group."))
        hydraulic_data_layout = QGridLayout(hydraulic_data_output_group)
        hydraulic_data_layout.addLayout(q1out_layout, 0, 0)
        hydraulic_data_layout.addLayout(q2out_layout, 0, 1)
        hydraulic_data_layout.addLayout(self.q2target_layout, 0, 2)
        hydraulic_data_output_group.setSizePolicy(QSizePolicy.Maximum,
                                                  QSizePolicy.Maximum)
        self.doubleclick_output_group = DoubleClicOutputGroup()
        hydraulic_data_output_group.installEventFilter(
            self.doubleclick_output_group)
        self.doubleclick_output_group.double_clic_signal.connect(
            self.reset_hydraulic_data_output_group)

        # models_group
        models_group = QGroupBox(self.tr('Biological models'))
        models_layout = QGridLayout(models_group)
        models_layout.addWidget(available_model_label, 0, 0)
        models_layout.addWidget(selected_model_label, 0, 1)
        models_layout.addWidget(self.list_f, 1, 0)
        models_layout.addWidget(self.selected_aquatic_animal_qtablewidget, 1,
                                1)
        models_layout.addWidget(self.run_stop_button, 2, 1)
        self.doubleclick_models_group = DoubleClicOutputGroup()
        models_group.installEventFilter(self.doubleclick_models_group)
        self.doubleclick_models_group.double_clic_signal.connect(
            self.reset_models_group)

        # gereral_layout
        self.layout3 = QVBoxLayout(content_widget)
        self.layout3.addWidget(hydraulic_data_group, Qt.AlignLeft)
        self.layout3.addWidget(hydraulic_data_output_group)
        self.layout3.addWidget(models_group)

        # self.setLayout(self.layout3)
        self.setWidgetResizable(True)
        self.setFrameShape(QFrame.NoFrame)
        self.setWidget(content_widget)

    def add_new_qtarget(self):
        # count existing number of lineedit
        total_widget_number = self.q2target_layout.count()
        self.total_lineedit_number = total_widget_number - 2  # - first : qlabel and plus and moins button + New lineedit
        lineedit_name = 'new_qtarget' + str(self.total_lineedit_number)
        setattr(self, lineedit_name, QLineEdit())
        getattr(self, lineedit_name).setFixedWidth(self.lineedit_width)
        self.target_lineedit_list.append(getattr(self, lineedit_name))
        self.q2target_layout.insertWidget(total_widget_number - 2,
                                          getattr(self, lineedit_name))

    def remove_one_qtarget(self):
        # count existing number of lineedit
        total_widget_number = self.q2target_layout.count()
        self.total_lineedit_number = total_widget_number - 3  # - first : qlabel and plus and moins button - New lineedit
        if self.total_lineedit_number > 0:
            self.target_lineedit_list.pop(-1)
            self.q2target_layout.itemAt(total_widget_number -
                                        3).widget().setParent(None)
            self.total_lineedit_number = self.total_lineedit_number - 1

    def reset_hydraulic_data_input_group(self):
        # remove txt in lineedit
        self.eq1.setText("")
        self.eq2.setText("")
        self.ew1.setText("")
        self.ew2.setText("")
        self.eh1.setText("")
        self.eh2.setText("")
        self.eq50.setText("")
        self.esub.setText("")

    def reset_hydraulic_data_output_group(self):
        # remove txt in lineedit
        self.eqmin.setText("")
        self.eqmax.setText("")
        # remove lineedits qtarget
        for i in reversed(range(1, self.q2target_layout.count() - 1)):
            self.q2target_layout.itemAt(i).widget().setParent(None)
            self.total_lineedit_number = self.total_lineedit_number - 1
        self.target_lineedit_list = []

    def reset_models_group(self):
        if self.selected_aquatic_animal_qtablewidget.count() > 0:
            self.selected_aquatic_animal_qtablewidget.clear()
            self.fill_fish_name()

    def read_estimhab_dict(self):
        """
        This function opens the json data created by estimhab
        """
        # load_project_properties
        self.estimhab_dict = load_specific_properties(self.path_prj,
                                                      [self.model_type])[0]

    def fill_fish_name(self):
        """
        This function reads all latin fish name from the xml files which are contained in the biological directory
        related to estimhab and fill GUI fish names
        """
        all_xmlfile = glob.glob(os.path.join(self.path_bio_estimhab, r'*.xml'))

        if self.estimhab_dict:
            selected_fish = self.estimhab_dict["fish_list"]
        else:
            selected_fish = []

        for f in all_xmlfile:
            # open xml
            try:
                try:
                    docxml = ET.parse(f)
                    root = docxml.getroot()
                except IOError:
                    self.send_log.emit(
                        self.tr("Warning: ") +
                        self.tr("The .habby project file ") + f +
                        self.tr(" could not be open.\n"))
                    return
            except ET.ParseError:
                self.send_log.emit(
                    self.tr("Warning: ") +
                    self.tr("The .habby project file ") + f +
                    self.tr(" is not well-formed.\n"))
                return

            # find fish name
            fish_name = root.find(".//LatinName")
            # None is null for python 3
            if fish_name is not None:
                fish_name = fish_name.text.strip()

            # find fish stage
            stage = root.find(".//estimhab/stage")
            # None is null for python 3
            if stage is not None:
                stage = stage.text.strip()
            if stage != 'all_stage':
                fish_name += ' ' + stage

            # check if not selected
            if fish_name not in selected_fish:
                # add to the list
                item = QListWidgetItem(fish_name)
                item.setData(1, f)
                self.list_f.addItem(item)
            else:
                # add to the list
                item2 = QListWidgetItem(fish_name)
                item2.setData(1, f)
                self.selected_aquatic_animal_qtablewidget.addItem(item2)

    def fill_input_data(self):
        if self.estimhab_dict:
            # input data
            self.eq1.setText(str(self.estimhab_dict["q"][0]))
            self.eq2.setText(str(self.estimhab_dict["q"][1]))
            self.eh1.setText(str(self.estimhab_dict["h"][0]))
            self.eh2.setText(str(self.estimhab_dict["h"][1]))
            self.ew1.setText(str(self.estimhab_dict["w"][0]))
            self.ew2.setText(str(self.estimhab_dict["w"][1]))
            self.eq50.setText(str(self.estimhab_dict["q50"]))
            self.eqmin.setText(str(self.estimhab_dict["qrange"][0]))
            self.eqmax.setText(str(self.estimhab_dict["qrange"][1]))
            self.esub.setText(str(self.estimhab_dict["substrate"]))
            # qtarg
            if len(self.estimhab_dict["qtarg"]) > 0:
                while self.total_lineedit_number != len(
                        self.estimhab_dict["qtarg"]):
                    self.add_new_qtarget()
                for qtarg_num, qtarg_value in enumerate(
                        self.estimhab_dict["qtarg"][1:]):
                    getattr(self, 'new_qtarget' + str(qtarg_num + 2)).setText(
                        str(qtarg_value))

    def check_if_ready_to_compute(self):
        all_string_selection = (self.eq1.text(), self.eq2.text(),
                                self.ew1.text(), self.ew2.text(),
                                self.eh1.text(), self.eh2.text(),
                                self.eq50.text(), self.eqmin.text(),
                                self.eqmax.text(), self.esub.text())
        # minimum one fish and string in input lineedits to enable run_stop_button
        if self.selected_aquatic_animal_qtablewidget.count(
        ) > 0 and "" not in all_string_selection:
            self.run_stop_button.setEnabled(True)
        else:
            self.run_stop_button.setEnabled(False)

    def change_folder(self):
        """
        A small method to change the folder which indicates where is the biological data
        """
        # user find new path
        self.path_bio_estimhab = QFileDialog.getExistingDirectory(
            self, self.tr("Open Directory"), os.getenv('HOME'))
        # update list
        self.list_f.clear()
        all_file = glob.glob(os.path.join(self.path_bio_estimhab, r'*.xml'))
        # make it look nicer
        for i in range(0, len(all_file)):
            all_file[i] = all_file[i].replace(self.path_bio_estimhab, "")
            all_file[i] = all_file[i].replace("\\", "")
            all_file[i] = all_file[i].replace(".xml", "")
            item = QListWidgetItem(all_file[i])
            # add them to the menu
            self.list_f.addItem(item)

    def run_estmihab(self):
        """
        A function to execute Estimhab by calling the estimhab function.

        **Technical comment**

        This is the function making the link between the GUI and the source code proper. The source code for Estimhab
        is in src/Estimhab.py.

        This function loads in memory the data given in the graphical interface and call sthe Estimhab model.
        The data could be written by the user now or it could be data which was saved in the hdf5 file before and
        loaded when HABBY was open (and the init function called).  We check that all necessary data is present and
        that the data given makes sense (e.g.,the minimum discharge should not be bigger than the maximal discharge,
        the data should be a float, etc.). We then remove the duplicate fish species (in case the user select one
        specie twice) and the Estimhab model is called. The log is then written (see the paragraph on the log for more
        information). Next, the figures created by Estimmhab are shown. As there is only a short number of outputs
        for Estimhab, we create a figure in all cases (it could be changed by adding a checkbox on the GUI like
        in the Telemac or other hydrological class).

        """
        # prepare data
        try:
            q = [
                float(self.eq1.text().replace(",", ".")),
                float(self.eq2.text().replace(",", "."))
            ]
            w = [
                float(self.ew1.text().replace(",", ".")),
                float(self.ew2.text().replace(",", "."))
            ]
            h = [
                float(self.eh1.text().replace(",", ".")),
                float(self.eh2.text().replace(",", "."))
            ]
            q50 = float(self.eq50.text().replace(",", "."))
            qrange = [
                float(self.eqmin.text().replace(",", ".")),
                float(self.eqmax.text().replace(",", "."))
            ]
            qtarget_values_list = []
            for qtarg_lineedit in self.target_lineedit_list:
                if qtarg_lineedit.text():
                    qtarget_values_list.append(
                        float(qtarg_lineedit.text().replace(",", ".")))
            substrate = float(self.esub.text().replace(",", "."))
        except ValueError:
            self.send_log.emit('Error: ' + self.tr(
                'Some data are empty or not float. Cannot run Estimhab'))
            return

        # get the list of xml file
        fish_list = []
        fish_name2 = []
        for i in range(0, self.selected_aquatic_animal_qtablewidget.count()):
            fish_item = self.selected_aquatic_animal_qtablewidget.item(i)
            fish_item_str = fish_item.text()
            fish_list.append(os.path.basename(fish_item.data(1)))
            fish_name2.append(fish_item_str)
        # check internal logic
        if not fish_list:
            self.send_log.emit(
                'Error: ' + self.tr('No fish selected. Cannot run Estimhab.'))
            return
        if qrange[0] >= qrange[1]:
            self.send_log.emit('Error: ' + self.tr(
                'Minimum discharge bigger or equal to max discharge. Cannot run Estimhab.'
            ))
            return
        if qtarget_values_list:
            for qtarg in qtarget_values_list:
                if qtarg < qrange[0] or qtarg > qrange[1]:
                    self.send_log.emit('Error: ' + self.tr(
                        'Target discharge is not between Qmin and Qmax. Cannot run Estimhab.'
                    ))
                    return
        if q[0] == q[1]:
            self.send_log.emit(
                'Error: ' +
                self.tr('Estimhab needs two differents measured discharges.'))
            return
        if h[0] == h[1]:
            self.send_log.emit(
                'Error: ' +
                self.tr('Estimhab needs two different measured height.'))
            return
        if w[0] == w[1]:
            self.send_log.emit(
                'Error: ' +
                self.tr('Estimhab needs two different measured width.'))
            return
        if (q[0] > q[1] and h[0] < h[1]) or (q[0] > q[1] and w[0] < w[1]) or (q[1] > q[0] and h[1] < h[0]) \
                or (q[1] > q[0] and w[1] < w[0]):
            self.send_log.emit(
                'Error: ' +
                self.tr('Discharge, width, and height data are not coherent.'))
            return
        if q[0] <= 0 or q[1] <= 0 or w[0] <= 0 or w[1] <= 0 or h[0] <= 0 or h[1] <= 0 or qrange[0] <= 0 or qrange[1] <= 0 \
                or substrate <= 0 or q50 <= 0:
            self.send_log.emit('Error: ' + self.tr(
                'Negative or zero data found. Could not run Estimhab.'))
            return
        if substrate > 3:
            self.send_log.emit(
                'Error: ' +
                self.tr('Substrate is too large. Could not run Estimhab.'))
            return

        self.send_log.emit(self.tr('# Computing: Estimhab...'))

        # check if the discharge range is realistic with the result
        self.qall = [q[0], q[1], qrange[0], qrange[1], q50]
        self.check_all_q()

        # run and save
        project_properties = load_project_properties(self.path_prj)
        sys.stdout = mystdout = StringIO()

        self.estimhab_dict = dict(q=q,
                                  w=w,
                                  h=h,
                                  q50=q50,
                                  qrange=qrange,
                                  qtarg=qtarget_values_list,
                                  substrate=substrate,
                                  path_bio=self.path_bio_estimhab,
                                  xml_list=fish_list,
                                  fish_list=fish_name2)

        # change_specific_properties
        change_specific_properties(self.path_prj, ["Estimhab"],
                                   [self.estimhab_dict])

        # process
        state = Value("d", 0)
        self.p = Process(target=estimhab_mod.estimhab_process,
                         args=(self.estimhab_dict, project_properties,
                               self.path_prj, state),
                         name="Estimhab")
        self.p.start()
        self.p.join()

        # plot
        plot_attr = lambda: None
        plot_attr.name_hdf5 = self.name_prj + '_ESTIMHAB' + '.hab'
        plot_attr.nb_plot = 1

        self.process_manager.set_estimhab_plot_mode(
            self.path_prj, plot_attr, load_project_properties(self.path_prj))
        self.process_manager.start()

        # log info
        str_found = mystdout.getvalue()
        str_found = str_found.split('\n')
        for i in range(0, len(str_found)):
            if len(str_found[i]) > 1:
                self.send_log.emit(str_found[i])

        self.send_log.emit(
            self.
            tr("Estimhab computation done. Figure and text files created in output project folder."
               ))
        self.send_log.emit("py    data = [" + str(q) + ',' + str(w) + ',' +
                           str(h) + ',' + str(q50) + ',' + str(substrate) +
                           ']')
        self.send_log.emit("py    qrange =[" + str(qrange[0]) + ',' +
                           str(qrange[1]) + ']')
        self.send_log.emit(
            "py    path1= os.path.join(os.path.dirname(path_bio),'" +
            self.path_bio_estimhab + "')")
        fish_list_str = "py    fish_list = ["
        for i in range(0, len(fish_list)):
            fish_list_str += "'" + fish_list[i] + "',"
        fish_list_str = fish_list_str[:-1] + ']'
        self.send_log.emit(fish_list_str)
        self.send_log.emit(
            "py    [OSI, WUA] = estimhab.estimhab(data[0], data[1], data[2], data[3] ,"
            " qrange, data[4], path1, fish_list, '.', True, {}, '.')\n")
示例#29
0
    def __init__(self, parent=None):
        super().__init__(parent)

        self.record = -1
        self.inspected = None
        self.oob_update = False
        prefs = QSettings()
        prefs.beginGroup("/General")
        timeout = prefs.value("/Timeout")
        dark_mode = prefs.value("/DarkMode")
        prefs.endGroup()

        # Instantiate core objects
        self.timeout_timer = QTimer()
        self.timeout_timer.setTimerType(Qt.VeryCoarseTimer)
        self.timeout_timer.setInterval(timeout * 1000)
        self.timeout_timer.setSingleShot(True)
        self.timeout_timer.timeout.connect(self.update_temp_log)
        self.systems = ActionsWidget(LogSource.SYSTEM)
        self.systems.acted.connect(self.log_item)
        self.events = ActionsWidget(LogSource.EVENT)
        self.events.acted.connect(self.log_item)

        self.compass = Compass()
        self.compass_widget = QWidget()
        compass_layout = QHBoxLayout()
        self.compass_widget.setLayout(compass_layout)
        compass_layout.addWidget(self.compass)
        self.compass.angle_event.connect(self.log_item)

        self.exact_angle = ExactAngle()
        self.exact_angle_widget = QWidget()
        exact_angle_layout = QHBoxLayout()
        self.exact_angle_widget.setLayout(exact_angle_layout)
        exact_angle_layout.addWidget(self.exact_angle)
        self.exact_angle.btn_event.connect(self.reset_timer)
        self.exact_angle.angle_event.connect(self.log_item)

        tab_widget = QTabWidget()
        tab_bar = tab_widget.tabBar()
        tab_bar.setFont(QFont('Consolas', 12, 3))
        tab_widget.addTab(self.compass_widget, "Compass")
        tab_widget.addTab(self.exact_angle_widget, "Precise Angle")
        tab_widget.setStyleSheet("""
                QTabWidget::pane {
                    border-top: 2px solid #C2C7CB;
                }
                /* Style the tab using the tab sub-control. Note that
                    it reads QTabBar _not_ QTabWidget */
                QTabBar::tab {
                    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
                                stop: 0 #E1E1E1, stop: 0.4 #DDDDDD,
                                stop: 0.5 #D8D8D8, stop: 1.0 #D3D3D3);
                    border: 2px solid #C4C4C3;
                    border-bottom-color: #C2C7CB; /* same as the pane color */
                    border-top-left-radius: 4px;
                    border-top-right-radius: 4px;
                    min-width: 8ex;
                    padding: 2px;
                    color: black;
                }

                QTabBar::tab:selected, QTabBar::tab:hover {
                    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
                                stop: 0 #fafafa, stop: 0.4 #f4f4f4,
                                stop: 0.5 #e7e7e7, stop: 1.0 #fafafa);
                }

                QTabBar::tab:selected {
                    border-color: #ff0000;
                    border-bottom-color: #C2C7CB; /* same as pane color */
                }

                QTabBar::tab:!selected {
                    margin-top: 2px; /* make non-selected tabs look smaller */
                }
            """)

        header_layout = QHBoxLayout()
        self.zulu_time_label = QLabel()
        self.assessor_label = QLabel()
        self.date_label = QLabel()
        self.dl_label = QLabel()
        self.mnemonic_label = QLabel()
        header_layout.addWidget(self.zulu_time_label)
        header_layout.addWidget(self.assessor_label)
        header_layout.addWidget(self.date_label)
        header_layout.addWidget(self.dl_label)
        header_layout.addWidget(self.mnemonic_label)
        res = QApplication.primaryScreen().size()
        w, h = res.width(), res.height()
        if w > 1920 or h > 1080:
            hdr_font = QFont("Consolas", 16, 2)
            end_font = QFont("Consolas", 32, 5)
        else:
            hdr_font = QFont("Consolas", 14, 2)
            end_font = QFont("Consolas", 28, 5)
        for index in range(header_layout.count()):
            widget = header_layout.itemAt(index).widget()
            widget.setSizePolicy(
                QSizePolicy.Preferred, QSizePolicy.Maximum
            )
            widget.setFont(hdr_font)
            widget.setAlignment(Qt.AlignCenter)

        # Setup logging state machine
        self.init_log_sm()

        # Setup splitters
        actions_splitter = QSplitter(
            Qt.Horizontal,
            frameShape=QFrame.StyledPanel,
            frameShadow=QFrame.Plain
        )
        actions_splitter.addWidget(self.systems)
        actions_splitter.addWidget(self.events)
        actions_splitter.addWidget(tab_widget)
        actions_splitter.setChildrenCollapsible(False)
        main_splitter = QSplitter(
            Qt.Vertical,
            frameShape=QFrame.StyledPanel,
            frameShadow=QFrame.Plain
        )
        self.log_area = QTableWidget(0, 3)
        self.log_area.cellDoubleClicked.connect(self.entry_inspected)
        self.log_area.cellChanged.connect(self.entry_changed)
        self.log_area.setHorizontalHeaderLabels(
            ["Time", "System", "Events"]
        )
        self.log_area.horizontalHeader().setStretchLastSection(True)
        self.set_dark_mode(dark_mode)
        end_msn_btn = QPushButton("END\r\nMISSION")
        end_msn_btn.clicked.connect(self.end_mission)
        end_msn_btn.setFont(end_font)
        end_msn_btn.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        end_msn_btn.setStyleSheet("background-color: red; color: white")
        bottom_layout = QGridLayout()
        bottom_widget = QWidget()
        bottom_widget.setLayout(bottom_layout)
        bottom_layout.addWidget(self.log_area, 0, 0, 1, 7)
        bottom_layout.addWidget(end_msn_btn, 0, 8, 1, 1)
        main_splitter.addWidget(actions_splitter)
        main_splitter.addWidget(bottom_widget)
        main_splitter.setChildrenCollapsible(False)
        handle_css = """
            QSplitter::handle {
                background-image: url(:/imgs/dot_pattern.png);
                background-repeat: repeat-xy;
                background-color: none;
                border: 1px solid gray;
            }
            QSplitter::handle:pressed {
                background-image: url(:/imgs/pressed.png);
            }
        """
        actions_splitter.setStyleSheet(handle_css)
        main_splitter.setStyleSheet(handle_css)

        # Finalize layout
        main_layout = QVBoxLayout()
        main_layout.addLayout(header_layout)
        main_layout.addWidget(main_splitter)
        self.setLayout(main_layout)
示例#30
0
class ProblemPage(QWidget):
    def __init__(self, mode, timer):
        super().__init__()
        self.solution_stack = []
        self.start_time = 0
        self.timer = timer
        self.mode = mode
        self.numbers = []
        self.target = 0
        self.back_button = QPushButton("Back")
        self.big_number_count = QSpinBox()
        self.big_number_count.setRange(1, 4)
        self.generate_number_box = QPushButton("Generate")
        self.reset_button = QPushButton("Reset")
        self.reset_button.setDisabled(True)
        self.number_group = QHBoxLayout()
        self.set_numbers = QPushButton("Set Numbers")
        self.set_numbers.setDisabled(True)
        self.number_line()
        self.target_window = QLineEdit("Target")
        self.set_target = QPushButton("Set Target")
        self.set_target.setDisabled(True)
        self.target_check = QLabel("Target should be between 100 and 999")
        self.timer_bar = QProgressBar()
        self.timer_bar.setRange(0, 100)
        self.time_keeper = QTimer()
        self.counter = 0
        self.time_keeper.timeout.connect(lambda: self.timer_props())

        self.setLayout(self.set_layout())

        if self.mode == 0:
            self.generate_number_box.clicked.connect(
                lambda: self.generate_button_mode0_action())
            self.set_numbers.clicked.connect(lambda: self.set_numbers_action())
            self.reset_button.clicked.connect(lambda: self.reset_actions())
            self.set_target.clicked.connect(
                lambda: self.target_button_action())
            self.back_button.clicked.connect(lambda: self.reset_actions())

    def solve(self):
        solver = CountDownSolver(self.big_number_count.value(), self.numbers,
                                 self.target)
        print('Solver started')
        start_time = time.time()
        solver.solve()
        self.solution_stack = solver.solution_stack
        print('solver done')
        end_time = time.time()
        print('solver took :', round(end_time - start_time, 3), 'secs')

    def timer_props(self):
        self.counter += 1
        value = (self.counter / 100) / self.timer * 100
        self.timer_bar.setValue(value)
        if value > 100:
            self.time_keeper.stop()
            self.solve()
            print(self.solution_stack)

    def target_button_action(self):
        try:
            if 100 <= int(self.target_window.text()) <= 999:
                self.set_target.setDisabled(True)
                self.target = int(self.target_window.text())
                print('valid target: ', self.target)

                self.time_keeper.start(1)

            else:
                self.target = 0
                print('target not in range')
        except ValueError:
            print('invalid target')

    def reset_actions(self):
        self.generate_number_box.setDisabled(False)
        self.set_numbers.setDisabled(True)
        self.set_target.setDisabled(True)
        for i in range(self.number_group.count()):
            item = self.number_group.itemAt(i).widget()
            if isinstance(item, QComboBox):
                for j in range(item.count()):
                    item.removeItem(0)

    def set_numbers_action(self):
        self.numbers = []
        for i in range(self.number_group.count()):
            item = self.number_group.itemAt(i).widget()
            if isinstance(item, QComboBox):
                self.numbers.append(int(item.currentText()))
        print(self.numbers)
        self.set_target.setDisabled(False)

    def generate_button_mode0_action(self):
        big = self.big_number_count.value()
        box = 0
        for i in range(self.number_group.count()):
            item = self.number_group.itemAt(i).widget()
            if isinstance(item, QComboBox):
                if box < big:
                    item.addItems(str(25 * j) for j in [1, 2, 3, 4])
                elif big <= box < 6:
                    item.addItems(str(j) for j in range(1, 11))
                box += 1
        self.generate_number_box.setDisabled(True)
        self.set_numbers.setDisabled(False)
        self.reset_button.setDisabled(False)

    def set_layout(self):
        back_line = QHBoxLayout()
        back_line.addStretch(1)
        back_line.addWidget(self.back_button)
        back_line.addStretch(1)

        big_number_line = QHBoxLayout()
        big_number_line.addWidget(QLabel("Big Number Count : "))
        big_number_line.addStretch(1)
        big_number_line.addWidget(self.big_number_count)
        big_number_line.addStretch(1)
        big_number_line.addWidget(self.generate_number_box)
        big_number_line.addStretch(1)
        big_number_line.addWidget(self.reset_button)

        target_line = QHBoxLayout()
        target_line.addWidget(self.target_window)
        target_line.addStretch(1)
        target_line.addWidget(self.set_target)
        target_line.addStretch(1)
        target_line.addWidget(self.target_check)

        main_layout = QVBoxLayout()
        main_layout.addLayout(back_line)
        main_layout.addStretch(1)
        main_layout.addLayout(big_number_line)
        main_layout.addStretch(1)
        main_layout.addLayout(self.number_group)
        main_layout.addStretch(1)
        main_layout.addLayout(target_line)
        main_layout.addStretch(1)
        main_layout.addWidget(self.timer_bar)
        main_layout.addStretch(1)
        return main_layout

    def number_line(self):
        for i in range(6):
            if self.mode == 1:
                self.number_group.addWidget(QLabel(" "))
                self.number_group.addStretch(1)
            elif self.mode == 0:
                self.number_group.addWidget(QComboBox())
                self.number_group.addStretch(1)
        self.number_group.addWidget(self.set_numbers)
class Weijiejue(QDialog):

    def __init__(self,list,i,parent = None):
        super(Weijiejue,self).__init__(parent)
        #设置界面大小、名称、背景
        #self.resize(800,900)
        self.setWindowTitle('故障诊断专家系统')
        self.setStyleSheet("background-image:url(tubiao_meitu.jpg)")
        QApplication.setStyle("Fusion")
        font = QtGui.QFont('微软雅黑',20)
        font1 = QtGui.QFont('微软雅黑light', 15)
        #窗体属性


        self.i1=i
        self.list1=list

        #
        #查询self.list1[self.i1],得到cankaoziliao字符串,转换为列表
        db = pymysql.connect("localhost", "root", "123456", "expertsy", charset='utf8')
        cur=db.cursor()



        #self.ckzl= ["手册1.pdf","图片1.jpg"]

        vbj = QVBoxLayout()
        vbj.setAlignment(Qt.AlignCenter)
        vbj.setSpacing(50)

        self.hbj1=QHBoxLayout()
        hbj2=QHBoxLayout()
        #

        self.setWindowFlags(Qt.Widget)
        self.paichatishi = QLabel(self.list1[self.i1])
        self.paichatishi.setFont(font)

        sql = 'SELECT 参考资料 FROM 问题关联 WHERE 问题="%s"' % self.list1[self.i1]
        cur.execute(sql)
        string = cur.fetchone()
        print(string)
        if len(string)!=0:
            string0 = string[0]
            self.ckzl = string0.split(",")


            for fuzu in self.ckzl:
                self.title1= QPushButton(fuzu)
                self.title1.setStyleSheet('''
                    QPushButton{
                        border:none;
                        color:blue;
                        font-size:15px;
                        height:30px;
                        padding-left:5px;
                        padding-right:5px;
                        text-align:center;
                    }
                    QPushButton:hover{
                        color:black;
                        border:1px solid #F3F3F5;
                        border-radius:10px;
                        background:LightGray;
                    }
                ''')
                file_path= fuzu
                self.title1.clicked.connect(partial(self.lianjie))
                #title1.clicked.connect(lambda :self.lianjie(file_path))
                self.hbj1.addWidget(self.title1)


        self.jiejuebut=QPushButton("解决了")
        self.jiejuebut.setFont(font1)
        self.weijiejuebut = QPushButton("未解决")
        self.weijiejuebut.setFont(font1)
        self.weijiejuebut.clicked.connect(partial(self.tonext))
        self.jiejuebut.clicked.connect(partial(self.showjiejue))

        hbj2.addStretch(1)
        hbj2.addWidget(self.weijiejuebut)
        hbj2.addStretch(2)
        hbj2.addWidget(self.jiejuebut)
        hbj2.addStretch(1)

        vbj.addStretch(1)
        vbj.addWidget(self.paichatishi)
        vbj.addStretch(2)
        vbj.addLayout(self.hbj1)
        vbj.addStretch(2)
        vbj.addLayout(hbj2)
        vbj.addStretch(1)
        self.setLayout(vbj)

    def tonext(self):

        for i in reversed (range(self.hbj1.count())):

            self.hbj1.itemAt(i).widget().close()
            self.hbj1.takeAt(i)

        changdu=len(self.list1)
        self.i1=self.i1+1
        if self.i1+1<changdu:
            self.paichatishi.setText(self.list1[self.i1])
        if self.i1+1==changdu:
            self.paichatishi.setText(self.list1[self.i1])
            self.weijiejuebut.setText("已经是最后一条")
            self.weijiejuebut.setEnabled(False)

        db = pymysql.connect("localhost", "root", "123456", "expertsy", charset='utf8')
        cur = db.cursor()
        sql = 'SELECT 参考资料 FROM 问题关联 WHERE 问题="%s"' % self.list1[self.i1]
        cur.execute(sql)
        string = cur.fetchone()
        string0 = string[0]
        if not string0 is None:
            print("assa")
            self.ckzl = string0.split(",")
            for fuzu in self.ckzl:
                self.title1= QPushButton(fuzu)
                self.title1.setStyleSheet('''
                                QPushButton{
                                    border:none;
                                    color:blue;
                                    font-size:15px;
                                    height:30px;
                                    padding-left:5px;
                                    padding-right:5px;
                                    text-align:center;
                                }
                                QPushButton:hover{
                                    color:black;
                                    border:1px solid #F3F3F5;
                                    border-radius:10px;
                                    background:LightGray;
                                }
                            ''')
                self.title1.clicked.connect(partial(self.lianjie))
                #title1.clicked.connect(lambda :self.lianjie(file_path))
                self.hbj1.addWidget(self.title1)


    def showjiejue(self):
        self.w3=Jiejue()
        self.w3.show()

    def lianjie(self):
        sender=self.sender()
        os.startfile(sender.text())
示例#32
0
class MainWindow(QWidget):
    ##
    # \brief Initialization Function
    def __init__(self):
        super(MainWindow, self).__init__()

        #Default variables
        self.valid = False  #Field to determine if the value is valid
        self.selectorLayout = None  #Layout used for selecting a specific source
        self.sources = ["none", "text", "file", "database"]
        self.source = {"type": None}
        self.dests = ["console", "file"]
        self.dest = {"type": "console"}

        self.sourceValue = None
        self.sourceSchema = None

        #Determine screen settings
        geo = self.frameGeometry()
        self.width = QDesktopWidget().availableGeometry().width()
        self.height = QDesktopWidget().availableGeometry().height()

        #Define window par meters
        self.resize(self.width * .5, self.height * .5)
        self.setWindowTitle("Aqueti Schema Editor")
        self.show()

        #create Layouts in UI
        self.titleLayout = QHBoxLayout()
        self.mainLayout = QVBoxLayout()
        self.sourceLayout = QHBoxLayout()
        self.destLayout = QHBoxLayout()
        self.valueLayout = QVBoxLayout()
        self.buttonLayout = QHBoxLayout()

        #Create frames
        self.sourceFrame = QFrame()
        self.destFrame = QFrame()
        self.valueFrame = QFrame()
        self.sourceFrame.setFrameStyle(QFrame.Box)
        self.valueFrame.setFrameStyle(QFrame.Box)
        self.destFrame.setFrameStyle(QFrame.Box)

        self.sourceFrame.setLayout(self.sourceLayout)
        self.destFrame.setLayout(self.destLayout)
        self.valueFrame.setLayout(self.valueLayout)
        self.valueFrame.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Expanding)

        #Create Scoll Area for valueFrame
        self.valueScrollArea = QScrollArea()
        self.valueScrollArea.updateGeometry()
        self.valueScrollArea.setWidget(self.valueFrame)
        self.valueScrollArea.setWidgetResizable(True)

        #Create title
        title = QLabel()
        title.setText("Aqueti Schema Editor")
        self.titleLayout.addWidget(title)

        #Add persistent source items
        sourceTitle = QLabel()
        sourceTitle.setText("Source:")
        self.sourceCombo = QComboBox()
        self.sourceCombo.addItems(self.sources)
        self.sourceCombo.currentTextChanged.connect(
            lambda: self.sourceChangeCallback())
        selectSourceButton = QPushButton("Load")
        self.sourceLayout.addWidget(sourceTitle)
        self.sourceLayout.addWidget(self.sourceCombo)

        self.sourceMetaLayout = QHBoxLayout()
        self.sourceMetaLayout.setSizeConstraint(QHBoxLayout.SetMinimumSize)
        self.sourceLayout.addLayout(self.sourceMetaLayout)
        self.sourceLayout.addWidget(selectSourceButton)

        #Add persistent dest
        destTitle = QLabel()
        destTitle.setText("Dest:")
        self.destCombo = QComboBox()
        self.destCombo.addItems(self.dests)
        self.destCombo.currentTextChanged.connect(
            lambda: self.destChangeCallback())
        selectDestButton = QPushButton("Load")
        self.destLayout.addWidget(destTitle)
        self.destLayout.addWidget(self.destCombo)

        self.destMetaLayout = QHBoxLayout()
        self.destMetaLayout.setSizeConstraint(QHBoxLayout.SetMinimumSize)
        self.destLayout.addLayout(self.destMetaLayout)
        self.destLayout.addWidget(selectDestButton)

        #Add Submit Button
        self.submitButton = QPushButton("Submit")
        self.submitButton.clicked.connect(lambda: self.submitCallback())
        self.buttonLayout.addWidget(self.submitButton)

        #Add cancel Button
        cancelButton = QPushButton("Cancel")
        cancelButton.clicked.connect(lambda: self.cancelCallback())
        self.buttonLayout.addWidget(cancelButton)

        #Add Layouts and draw
        self.mainLayout.addLayout(self.titleLayout)
        self.mainLayout.addWidget(self.sourceFrame)
        self.mainLayout.addWidget(self.destFrame)

        #        self.mainLayout.addWidget( self.valueFrame )
        self.mainLayout.addWidget(self.valueScrollArea)
        #        self.mainLayout.addStretch(1)
        self.mainLayout.addLayout(self.buttonLayout)
        self.draw()

    ##
    # \brief updates the source Layout
    def updateSourceLayout(self):
        #Remove current layout information
        #Remove all widgets from the current layout
        while self.sourceMetaLayout.count():
            item = self.sourceMetaLayout.takeAt(0)
            self.sourceMetaLayout.removeItem(item)
            widget = item.widget()
            if widget is not None:
                widget.deleteLater()
            try:
                item.deleteLater()
            except:
                pass

        #Find what our current source is and set the appropriate index
        index = 0
        for i in range(0, self.sourceCombo.count()):
            if self.sourceCombo.itemText(i) == self.source["type"]:
                index = i

        self.sourceCombo.setCurrentIndex(index)

        #Add fields based on source type
        if self.source["type"] == "file":
            #Add filename
            fileLabel = QLabel()
            fileLabel.setText("file: ")

            try:
                name = self.source["filename"]
            except:
                name = ""

            self.sourceFilenameBox = QLineEdit()
            self.sourceFilenameBox.setSizePolicy(QSizePolicy.Expanding,
                                                 QSizePolicy.Minimum)
            self.sourceFilenameBox.setText(name)
            #            self.sourceFilenameBox.readOnly = True
            #            self.sourceFilenameBox.sizeHint()
            #            self.sourceFilenameBox.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)

            self.sourceMetaLayout.addWidget(fileLabel)
            self.sourceMetaLayout.addWidget(self.sourceFilenameBox)

#        #Add a submitSource Button
#        selectSourceButton = QPushButton("Load")
#        selectSourceButton.clicked.connect( lambda: self.sourceChangeCallback())

#        self.sourceLayout.addWidget(selectSourceButton)

#        self.sourceLayout.addStretch(1)

##
# \brief updates the destination layout
#

    def updateDestLayout(self):
        #Remove current layout information
        #Remove all widgets from the current layout
        while self.destMetaLayout.count():
            item = self.destMetaLayout.takeAt(0)
            self.destMetaLayout.removeItem(item)
            widget = item.widget()
            if widget is not None:
                widget.deleteLater()
            try:
                item.deleteLater()
            except:
                pass
        """
        #############################################
        # Layout to select a destination
        #############################################
        destTitle = QLabel()
        destTitle.setText("Dest:")
        self.destCombo = QComboBox()
        self.destCombo.addItems(self.dests)
        """

        #Find what our current dest is and set the appropriate index
        index = 0
        for i in range(0, self.destCombo.count()):
            if self.destCombo.itemText(i) == self.dest["type"]:
                index = i

        self.destCombo.setCurrentIndex(index)
        self.destCombo.currentTextChanged.connect(
            lambda: self.destChangeCallback())

        #        self.destLayout.addWidget(destTitle)
        #        self.destLayout.addWidget(self.destCombo)
        #        self.destLayout.addStretch(1)

        ####
        # Fill in details base on dest tpye
        ####
        if self.dest["type"] == "console":
            pass
        elif self.dest["type"] == "file":
            fileLabel = QLabel()
            fileLabel.setText("file: ")

            try:
                name = self.dest["filename"]
            except:
                name = ""

            self.fileNameBox = QLineEdit()
            self.fileNameBox.setText(name)

            #            self.destMetaLayout.addWidget(fileLabel)
            self.destMetaLayout.addWidget(self.fileNameBox)

    ##
    # \brief function that is called when the source is changed
    #
    def destChangeCallback(self):
        print("Changing dest")

        newType = self.destCombo.itemText(self.destCombo.currentIndex())

        print("New Type: " + str(newType))

        if newType != self.dest["type"]:
            self.dest = {}

        self.dest["type"] = newType

        if self.dest["type"] == "console":
            pass

        elif self.dest["type"] == "file":
            options = QFileDialog.Options()
            options |= QFileDialog.DontUseNativeDialog
            destName, _ = QFileDialog.getSaveFileName(
                self,
                "QFileDialog.getSaveFileName()",
                "",
                "All Files (*);;JSON Files (*.json)",
                options=options)

            self.dest["filename"] = str(destName)

        else:
            print("Unsupported Type")

        self.draw()

    ##
    # \brief Update the value layout
    def updateValueLayout(self):
        #Remove all widgets from the current layout
        while self.valueLayout.count():
            item = self.valueLayout.takeAt(0)
            self.valueLayout.removeItem(item)
            widget = item.widget()
            if widget is not None:
                widget.deleteLater()
            try:
                item.deleteLater()
            except:
                pass

        #If we have data, let's display it
        if self.sourceSchema != None:

            valueTitle = QLabel()
            valueTitle.setText("Schema")

            self.schemaWidget = SmartWidget().init("Schema",
                                                   self.sourceValue,
                                                   self.sourceSchema,
                                                   showSchema=False)
            self.valueLayout.addWidget(self.schemaWidget.frame)

        #Disable the submit button if we don't have a schema
        if self.sourceSchema == None:
            self.submitButton.setEnabled(False)
        else:
            self.submitButton.setEnabled(True)

        self.setLayout(self.mainLayout)

    ##
    # \brief redraws all dynamic layouts
    def draw(self):
        self.updateDestLayout()
        self.updateSourceLayout()
        self.updateValueLayout()

    ##
    # \brief callback for when the source type changes
    #
    def sourceChangeCallback(self):

        #SDF Add popup to notify of schema loss

        #Clear the schema to disable the submit button
        self.sourceSchema = None
        self.source["type"] = self.sourceCombo.itemText(
            self.sourceCombo.currentIndex())

        if self.source["type"] == "none":
            self.sourceSchema = {"bsonType": "object"}

        #If we are a file  read the file contents as the value
        elif self.source["type"] == "file":
            options = QFileDialog.Options()
            options |= QFileDialog.DontUseNativeDialog
            sourceName, _ = QFileDialog.getOpenFileName(
                self,
                "QFileDialog.getOpenFileName()",
                "",
                "All Files (*);;JSON Files (*.json)",
                options=options)

            self.source["filename"] = str(sourceName)
            print("Loading: " + str(self.source["filename"]))

            with open(self.source["filename"]) as json_file:
                self.sourceSchema = json.load(json_file)

            print("Loaded Schema:" +
                  str(json.dumps(self.sourceSchema, indent=4)))

        self.updateSourceLayout()
        self.updateValueLayout()

    ##
    #\brief callback to get result from SmartWidget
    #
    # This function assumes that the schema is done. It will produce a popup
    # asking where and how to save the data
    #
    def submitCallback(self):
        schema = self.schemaWidget.getSchema()

        if self.dest["type"] == "console":
            print()
            print("Schema: (" + str(time.time()) + ")")
            print(json.dumps(schema, indent=4))

        elif self.dest["type"] == "file":
            print("Writing to: " + str(self.dest["filename"]))
            with open(self.dest["filename"], 'w') as outfile:
                json.dump(schema, outfile, indent=4)
        else:
            print("Source type: " + str(self.dest["type"]) +
                  " is not currently supported")

        self.close()

        #Use save pop-up to save data
        #self.saveWindow = SaveDataWindow(self.source, schema, self.saveCallback )

        print(str(time.time()) + "- schema:")
        print(str(schema))

    ##
    # \brief Function called after data is saved
    #
    def saveCallback(self, success):
        print("Data Result: " + str(success))

    ##
    # \brief Cancels the change and exits
    #
    def cancelCallback(self):
        print("Exited. No changes were saved")
        sys.exit(1)
示例#33
0
class Calendar(QWidget):
    def __init__(self,
                 parent=None,
                 year=int(time.strftime('%Y', time.localtime(time.time()))),
                 month=int(time.strftime('%m', time.localtime(time.time())))):
        super().__init__(parent)

        # Set Schedule Layout Components ===============
        self.scheduleLayout = QVBoxLayout()
        # -------------------------------
        self.titleBox = QHBoxLayout()
        self.titleLabel = QLabel("title: ")
        self.titleLineEdit = QLineEdit()
        # -------------------------------
        self.placeBox = QHBoxLayout()
        self.placeLabel = QLabel("place: ")
        self.placeLineEdit = QLineEdit()
        # -------------------------------
        self.dateBox = QHBoxLayout()
        self.dateLabel = QLabel("time:")
        self.fromHour = QSpinBox()
        self.fromMin = QSpinBox()
        self.toHour = QSpinBox()
        self.toMin = QSpinBox()
        # -------------------------------
        self.discription = QHBoxLayout()
        self.contentLabel = QLabel("content: ")
        self.content = QTextEdit()
        # -------------------------------
        self.modifyBtn = Button("Modifying", self.modifying)
        # ==============================================

        self.displayCalendar = MyCalendar()
        self.startDay = 0
        self.maxDay = 0
        self.currentYear = year
        self.currentMonth = month
        self.currentDay = 0
        self.firstClick = True
        self.displayCalendar.loadHoliday()
        self.today = time.localtime()

        if os.name == 'nt':
            self.fileRoot = ".\schedules\schedules.txt"

        else:
            self.fileRoot = "./schedules/schedules.txt"

        try:
            scheduleFile = open(self.fileRoot, "rb")
            self.displayCalendar.schedule = pickle.load(scheduleFile)
            print(self.displayCalendar.schedule)

        except EOFError:
            pass

        # main layout
        self.mainLayout = QHBoxLayout()

        # Left side Layout ================================
        self.leftLayout = QVBoxLayout()

        # Stacked Widget Part -----------------------------
        # Setting Stacked Widget(like a switching Tabs)
        self.setSchedule = QWidget()
        self.lunaDate = QWidget()

        # Design And Setting Actions each Tab. if want to Append any action, plz input the action in here.
        self.setScheduleUI()
        self.lunaDateUI()

        # Appending tabs in Stack
        self.Stack = QStackedWidget()
        self.Stack.addWidget(self.setSchedule)
        self.Stack.addWidget(self.lunaDate)

        # Switching Button layout Design And binding button with action.
        self.tabLayout = QHBoxLayout()
        self.tabLayout.addWidget(Button("스케쥴러", lambda: self.display(0)))
        self.tabLayout.addWidget(Button("음력", lambda: self.display(1)))

        for i in range(self.tabLayout.count()):
            self.tabLayout.itemAt(i).widget().setStyleSheet('font-size: 8pt')

        self.leftLayout.addLayout(self.tabLayout)
        # -------------------------------------------------

        # handling Year & month ----------------------------------
        self.moveMonth = QHBoxLayout()

        self.previousBtn = Button("<", self.previousMonth)

        # showing Year and month using Combobox(Year range: 1980 ~ 2040, Month range: 1, 12)
        self.yearCombo = QComboBox()
        self.yearCombo.addItems([str(x) for x in range(1980, 2041)])
        self.yearCombo.setCurrentText(str(self.currentYear))

        self.monthCombo = QComboBox()
        self.monthCombo.addItems([str(x) for x in range(1, 13)])
        self.monthCombo.setCurrentText(str(self.currentMonth))

        self.nextBtn = Button(">", self.nextMonth)

        self.moveMonth.addStretch()
        self.moveMonth.addWidget(self.previousBtn)
        self.moveMonth.addWidget(self.yearCombo)
        self.moveMonth.addWidget(self.monthCombo)
        self.moveMonth.addWidget(self.nextBtn)
        self.moveMonth.addStretch()
        self.leftLayout.addLayout(self.moveMonth)
        self.leftLayout.addStretch()
        # -------------------------------------------------

        # Set Day of Week ---------------------------------
        self.weekDayLayout = QHBoxLayout()
        enumDays = ["일", "월", "화", "수", "목", "금", "토"]

        for i in enumDays:
            label = QLabel(i)
            label.setAlignment(Qt.AlignCenter)
            self.weekDayLayout.addWidget(label)

        self.leftLayout.addLayout(self.weekDayLayout)
        # -------------------------------------------------

        # grid layout to appending date Buttons
        self.calendarGrid = QGridLayout()
        self.calendarGrid.setSizeConstraint(QLayout.SetFixedSize)
        self.leftLayout.addLayout(self.calendarGrid)
        self.leftLayout.addStretch(7)

        # showing status
        self.statusLabel = QLabel("btn Status")
        self.leftLayout.addWidget(self.statusLabel)
        # ==================================================

        # Set grid
        self.displayCalendar.setCalander(self.currentYear, self.currentMonth)
        self.renderDate(self.displayCalendar.getCalander())

        # Set ComboBox Changing Event
        self.yearCombo.currentTextChanged.connect(
            lambda: self.selectionChanged())
        self.monthCombo.currentTextChanged.connect(
            lambda: self.selectionChanged())

        self.mainLayout.addLayout(self.leftLayout)
        self.mainLayout.addWidget(self.Stack)
        self.Stack.setCurrentIndex(0)  # default Tab -> set calendar
        self.setLayout(self.mainLayout)
        self.setWindowTitle("Calendar")

    def renderDate(self, newCalendar):
        # =========== Append Day Buttons ===============
        self.clearLayout(self.calendarGrid)
        todayYear = self.today.tm_year
        todayMonth = self.today.tm_mon
        todayDay = self.today.tm_mday
        toggle = True

        for i in newCalendar:
            print(i)

        # Enroll button
        for row, column in enumerate(newCalendar):
            for col, day in enumerate(column):
                btn = Button(str(day), self.btnEvent)

                # deactivate button condition
                if toggle:
                    if day != 1:
                        btn.setEnabled(False)

                    else:
                        toggle = False

                else:
                    if (row == len(newCalendar) - 1) and (day // 10 == 0):
                        btn.setEnabled(False)

                # set today button color
                if (self.currentYear, self.currentMonth,
                        day) == (todayYear, todayMonth, todayDay):
                    btn.setStyleSheet('font-style: italic;')

                # if this day have any event represent event
                key = '-'.join(
                    [str(self.currentYear),
                     str(self.currentMonth),
                     str(day)])
                if key in self.displayCalendar.schedule.keys(
                ) and btn.isEnabled():
                    btn.setStyleSheet('color: blue;')
                    btn.setStyleSheet('background-color: skyblue;')
                    btn.setToolTip(
                        self.displayCalendar.schedule[key].getTitle())

                for restMonth, restDay, title in self.displayCalendar.holidays:
                    if restMonth == self.currentMonth and restDay == day and btn.isEnabled(
                    ):
                        if key in self.displayCalendar.schedule.keys(
                        ) and btn.isEnabled():
                            btn.setStyleSheet(
                                'background-color: skyblue; color: red;')
                            btn.setToolTip(title)

                        else:
                            btn.setStyleSheet('color: red;')
                            btn.setToolTip(title)
                            break

                # 공휴일은 빨간색으로 설정해준다.
                if col == 0 and btn.isEnabled():
                    btn.setStyleSheet('color: red;')

                self.calendarGrid.addWidget(btn, row, col)
        # ===============================================
        self.displayCalendar.enrollHoliday(self.currentYear)
        self.displayCalendar.loadHoliday()

    def btnEvent(self):
        # self.showingWidget(self.scheduleLayout)

        self.setFixedSize(self.mainLayout.sizeHint())

        btn = self.sender()
        self.statusLabel.setText("Day: " + btn.text() + " is Clicked.")
        self.currentDay = btn.text()

        target = "-".join([
            str(self.currentYear),
            str(self.currentMonth),
            str(self.currentDay)
        ])
        targetEvent = self.displayCalendar.schedule.get(target)

        if not targetEvent:
            self.titleLineEdit.setText("None")
            self.placeLineEdit.clear()
            self.fromHour.setValue(0)
            self.fromMin.setValue(0)
            self.toHour.setValue(0)
            self.toMin.setValue(0)
            self.content.clear()

        else:
            self.titleLineEdit.setText(targetEvent.getTitle())
            self.placeLineEdit.setText(targetEvent.getPlace())

            timeSet = targetEvent.getDate().split(",")
            self.fromHour.setValue(int(timeSet[0]))
            self.fromMin.setValue(int(timeSet[1]))
            self.toHour.setValue(int(timeSet[2]))
            self.toMin.setValue(int(timeSet[3]))

            self.content.setText(targetEvent.getDescription())

    def modifying(self):
        newEvent = MyEvent()
        eventList = [
            self.titleLineEdit.text(),
            self.placeLineEdit.text(),
            ",".join([
                str(self.fromHour.value()),
                str(self.fromMin.value()),
                str(self.toHour.value()),
                str(self.toMin.value())
            ]),
            self.content.toPlainText(),
        ]

        newEvent.setEvent(*eventList)

        target = "-".join([
            str(self.currentYear),
            str(self.currentMonth),
            str(self.currentDay)
        ])
        self.displayCalendar.schedule[target] = newEvent
        self.statusLabel.setText("modified")

    # rendering previous month calendar
    def previousMonth(self):
        if self.currentMonth is 1:
            self.currentYear -= 1
            self.yearCombo.setCurrentText(str(self.currentYear))
            self.currentMonth = 12
            self.monthCombo.setCurrentText(str(self.currentMonth))

        else:
            self.currentMonth -= 1
            self.monthCombo.setCurrentText(str(self.currentMonth))

    # rendering next month calendar
    def nextMonth(self):
        if self.currentMonth is 12:
            self.currentYear += 1
            self.yearCombo.setCurrentText(str(self.currentYear))
            self.currentMonth = 1
            self.monthCombo.setCurrentText(str(self.currentMonth))
        else:
            self.currentMonth += 1
            self.monthCombo.setCurrentText(str(self.currentMonth))

    def selectionChanged(self):
        self.currentYear = int(self.yearCombo.currentText())
        self.currentMonth = int(self.monthCombo.currentText())

        self.displayCalendar.setYear(self.currentYear)
        self.displayCalendar.setMonth(self.currentMonth)
        self.displayCalendar.setCalander(self.currentYear, self.currentMonth)
        self.renderDate(self.displayCalendar.getCalander())

    def clearLayout(self, layout):
        while layout.count():
            child = layout.takeAt(0)
            if child.widget():
                child.widget().deleteLater()

    def closeEvent(self, event):
        keys = []
        myEvent = self.displayCalendar.schedule

        for target in myEvent.keys():
            title = myEvent[target].title
            place = myEvent[target].place

            description = myEvent[target].description

            if (title, place, description) == ('', '', ''):
                keys.append(target)

        for target in keys:
            del self.displayCalendar.schedule[target]

        with open(self.fileRoot, "wb") as file:
            pickle.dump(self.displayCalendar.schedule, file)

    def setScheduleUI(self):
        # Schedules layout ==================================
        self.titleBox.addWidget(self.titleLabel)
        self.titleBox.addWidget(self.titleLineEdit)

        self.placeBox.addWidget(self.placeLabel)
        self.placeBox.addWidget(self.placeLineEdit)

        self.fromHour.setRange(0, 24)
        self.toHour.setRange(0, 24)
        self.fromMin.setRange(0, 59)
        self.toMin.setRange(0, 59)

        self.fromHour.valueChanged.connect(
            lambda: self.toHour.setRange(self.fromHour.value(), 24))
        # self.toHour.valueChanged.connect(lambda: self.fromHour.setRange(0, self.toHour.value()))

        self.fromMin.valueChanged.connect(
            lambda: self.toMin.setRange(self.fromMin.value(), 59))
        # self.toMin.valueChanged.connect(lambda: self.fromMin.setRange(0, self.toMin.value()))

        self.dateBox.addWidget(self.dateLabel)
        self.dateBox.addWidget(self.fromHour)
        self.dateBox.addWidget(self.fromMin)
        self.dateBox.addWidget(QLabel("    ~ "))
        self.dateBox.addWidget(self.toHour)
        self.dateBox.addWidget(self.toMin)

        self.contentLabel.setAlignment(Qt.AlignTop)
        self.discription.addWidget(self.contentLabel)
        self.discription.addWidget(self.content)

        self.scheduleLayout.addLayout(self.titleBox)
        self.scheduleLayout.addLayout(self.placeBox)
        self.scheduleLayout.addLayout(self.dateBox)
        self.scheduleLayout.addLayout(self.discription)
        # modifying schedule Button
        self.scheduleLayout.addWidget(self.modifyBtn)
        self.setSchedule.setLayout(self.scheduleLayout)

    def lunaDateUI(self):
        month_31 = [1, 3, 5, 7, 8, 10, 12]

        layout = QVBoxLayout()
        #layout.addWidget(QLabel("Luna Date"))
        topLayout = QHBoxLayout()
        self.yearSpinner = QSpinBox()
        self.yearSpinner.setRange(1980, 2040)
        self.monthSpinner = QSpinBox()
        self.monthSpinner.setRange(1, 12)
        self.daySpinner = QSpinBox()

        self.yearSpinner.setValue(self.today.tm_year)
        self.monthSpinner.setValue(self.today.tm_mon)
        self.daySpinner.setValue(self.today.tm_mday)

        self.monthSpinner.valueChanged.connect(
            lambda: self.daySpinner.setRange(
                1,
                self.displayCalendar.getMaxday(self.yearSpinner.value(),
                                               self.monthSpinner.value())))

        self.modeComboBox = QComboBox()
        self.modeComboBox.addItems(["양력 -> 음력", "음력 -> 양력"])
        convertBtn = Button("convert", self.lunarBtnEvent)
        resetBtn = Button("reset", self.lunarBtnEvent)

        bottomLayout = QVBoxLayout()
        titleBox = QHBoxLayout()
        solarBox = QHBoxLayout()
        lunarBox = QHBoxLayout()
        self.todayLabel = QLabel("오늘의 날짜정보")
        self.todayLabel.setStyleSheet('color: red; font-size: 18px;')
        solarLabel = QLabel("양력날짜")
        solarLabel.setStyleSheet('color: gray;')
        todaySolarDay = "%04d-%02d-%02d" % (
            self.today.tm_year, self.today.tm_mon, self.today.tm_mday)
        self.solarDateLabel = QLabel(todaySolarDay)
        lunarLabel = QLabel("음력날짜")
        lunarLabel.setStyleSheet('color: gray;')
        self.lunarDateLabel = QLabel(
            self.displayCalendar.calculator.getToLunarDate(
                self.today.tm_year, self.today.tm_mon, self.today.tm_mday))

        titleBox.addWidget(self.todayLabel)
        solarBox.addWidget(solarLabel)
        solarBox.addWidget(self.solarDateLabel)
        lunarBox.addWidget(lunarLabel)
        lunarBox.addWidget(self.lunarDateLabel)
        bottomLayout.addLayout(titleBox)
        bottomLayout.addLayout(solarBox)
        bottomLayout.addLayout(lunarBox)

        topLayout.addWidget(self.yearSpinner)
        topLayout.addWidget(self.monthSpinner)
        topLayout.addWidget(self.daySpinner)
        topLayout.addWidget(self.modeComboBox)
        topLayout.addWidget(convertBtn)
        topLayout.addWidget(resetBtn)

        layout.addStretch()
        layout.addLayout(bottomLayout)
        layout.addLayout(topLayout)
        layout.addStretch()
        self.lunaDate.setLayout(layout)

    def display(self, i):
        self.Stack.setCurrentIndex(i)

    def hidingWidget(self, layout):
        for i in range(layout.count()):
            item = layout.itemAt(i)

            if item.widget() is not None:
                layout.itemAt(i).widget().hide()

            elif item.layout() is not None:
                self.hidingWidget(layout.itemAt(i).layout())

    def showingWidget(self, layout):
        for i in range(layout.count()):
            item = layout.itemAt(i)
            if item.widget() is not None:
                layout.itemAt(i).widget().show()
            elif item.layout() is not None:
                self.showingWidget(layout.itemAt(i).layout())

    def lunarBtnEvent(self):
        btn = self.sender()
        key = btn.text()

        if key == 'reset':
            self.todayLabel.setText('오늘의 날짜정보')
            self.todayLabel.setStyleSheet('color: red; font-size: 18px;')

        elif key == 'convert':
            if self.modeComboBox.currentIndex() is 0:
                self.todayLabel.setText("양력 {}년 {}월 {}일".format(
                    self.yearSpinner.value(), self.monthSpinner.value(),
                    self.daySpinner.value()))
                self.todayLabel.setStyleSheet(
                    'font-weight: bold; color: black; font-size: 12px;')
                lunarDate = self.displayCalendar.calculator.getToLunarDate(
                    self.yearSpinner.value(), self.monthSpinner.value(),
                    self.daySpinner.value())
                self.solarDateLabel.setText(
                    str(self.yearSpinner.value()) + "-" +
                    str(self.monthSpinner.value()) + "-" +
                    str(self.daySpinner.value()))
                self.lunarDateLabel.setText(lunarDate)
            else:
                self.todayLabel.setText("음력 {}년 {}월 {}일".format(
                    self.yearSpinner.value(), self.monthSpinner.value(),
                    self.daySpinner.value()))
                self.todayLabel.setStyleSheet(
                    'font-weight: bold; color: black; font-size: 12px;')
                solarDate = self.displayCalendar.calculator.toSolarDate(
                    self.yearSpinner.value(), self.monthSpinner.value(),
                    self.daySpinner.value())
                self.solarDateLabel.setText(
                    str(solarDate[0]) + "-" + str(solarDate[1]) + "-" +
                    str(solarDate[2]))
                self.lunarDateLabel.setText(
                    str(self.yearSpinner.value()) + "-" +
                    str(self.monthSpinner.value()) + "-" +
                    str(self.daySpinner.value()))
示例#34
0
class SaveDataWindow(QWidget):
    def __init__(self, dest, schema, callback, parent=None):
        super(SaveDataWindow, self).__init__()

        self.dests = ["console", "text", "file", "database"]
        self.dest = dest
        self.schema = schema

        #Determine screen settings
        geo = self.frameGeometry()
        self.width = QDesktopWidget().availableGeometry().width()
        self.height = QDesktopWidget().availableGeometry().height()

        #Define window par meters
        self.resize(self.width * .5, self.height * .5)
        self.setWindowTitle("Aqueti Schema Editor")

        #
        self.mainLayout = QVBoxLayout()
        self.titleLayout = QHBoxLayout()
        self.destLayout = QHBoxLayout()

        #Create title
        title = QLabel()
        title.setText("Schema Saving Dialog")
        self.titleLayout.addWidget(title)
        self.mainLayout.addLayout(self.titleLayout)

        #Destination Layout
        self.destLayout = QHBoxLayout()
        self.mainLayout.addLayout(self.destLayout)

        #Add Button Layout
        self.buttonLayout = QHBoxLayout()
        self.submitButton = QPushButton("Save")
        self.submitButton.clicked.connect(lambda: self.saveButtonCallback())
        self.buttonLayout.addWidget(self.submitButton)
        cancelButton = QPushButton("Cancel")
        cancelButton.clicked.connect(lambda: self.cancelButtonCallback())
        self.buttonLayout.addWidget(cancelButton)
        self.mainLayout.addLayout(self.buttonLayout)
        self.setLayout(self.mainLayout)
        self.show()

        self.updateDestLayout()
        self.draw()

    ##
    # \brief updates the destinatino layout
    #
    def updateDestLayout(self):
        #Remove current layout information
        #Remove all widgets from the current layout
        while self.destLayout.count():
            item = self.destLayout.takeAt(0)
            self.destLayout.removeItem(item)
            widget = item.widget()
            if widget is not None:
                widget.deleteLater()
            try:
                item.deleteLater()
            except:
                pass

        #############################################
        # Layout to select a destination
        #############################################
        destTitle = QLabel()
        destTitle.setText("OutputType:")
        self.destCombo = QComboBox()
        self.destCombo.addItems(self.dests)

        #Find what our current dest is and set the appropriate index
        index = 0
        for i in range(0, self.destCombo.count()):
            if self.destCombo.itemText(i) == self.dest["type"]:
                index = i

        self.destCombo.setCurrentIndex(index)

        self.destLayout.addWidget(destTitle)
        self.destLayout.addWidget(self.destCombo)

        ####
        # Fill in details base on source tpye
        ####
        if self.dest["type"] == "console":
            pass
        elif self.dest["type"] == "file":
            fileLabel = QLabel()
            fileLabel.setText("file: ")

            try:
                name = self.dest["filename"]
            except:
                name = ""

            self.fileNameBox = QLineEdit()
            self.fileNameBox.setText(name)

            self.destLayout.addWidget(fileLabel)
            self.destLayout.addWidget(self.fileNameBox)

    ##
    # \brief Function to draw the object
    def draw(self):

        #Add a submitDest Button
        selectDestButton = QPushButton("Select")
        selectDestButton.currentIndexChanged.connect(
            lambda: self.destChangeCallback())

        self.destLayout.addWidget(destTitle)
        self.destLayout.addWidget(self.destCombo)
        self.destLayout.addWidget(selectDestButton)

        self.destLayout.addLayout(self.destLayout)

    ##
    # \brief callback for the Cancel button
    #
    def cancelButtonCallback(self):
        self.close()

    ##
    # \brief callback for a save button press
    #
    def saveButtonCallback(self):
        print("Saving:" + str(self.dest))

        if self.dest["type"] == "console":
            print()
            print("Schema (" + str(time.time()) + ")")
            print(str(self.schema))

        elif self.dest["type"] == "file":
            with open(self.dest["filename"], 'w') as outfile:
                json.dump(self.schema, outfile)
        else:
            print("Source type: " + str(self.dest["type"]) +
                  " is not currently supported")

        self.close()
示例#35
0
class MyPlotWidget(QWidget):
    COLORS=('r','g','b','c','m')
    def __init__(self):
        QWidget.__init__(self)

        vBox = QVBoxLayout(self)

        self._labels = QHBoxLayout()
        #self._labels.setSpacing(0)
        self._labels.addStretch(1)
        vBox.addLayout(self._labels)

        self.pw = pg.PlotWidget()
        vBox.addWidget(self.pw)

        self.pw.setBackground('w')
        self.pw.showGrid(x=True, y=True)

        self.setAcceptDrops(True)
        self.pw.setAcceptDrops(True)

        self.cidx = 0

    def dragEnterEvent(self, e):
        if e.mimeData().hasFormat("application/x-DataItem"):
            e.accept()
        else:
            e.ignore()

    def dropEvent(self, e):
        data = e.mimeData()
        bstream = data.retrieveData("application/x-DataItem", QVariant.ByteArray)
        selected = pickle.loads(bstream)

        name = f"{e.source().filename} : {selected.var_name}"
        
        print(type(selected.data))
        item = self.pw.getPlotItem().plot(x=selected.time.to_numpy(),
                                          y=selected.data.to_numpy(),
                                          pen=pg.mkPen(color=MyPlotWidget.COLORS[self.cidx],
                                                       width=2),
                                          name=name)
        label = self.makeLabel(item)
        self._labels.insertWidget(self._labels.count()-1, label)
        e.source().onClose.connect(lambda : self.removeItem(item, label))
        
        self.pw.autoRange()
        self.cidx = (self.cidx + 1) % len(MyPlotWidget.COLORS)
        e.accept()

    def makeLabel(self, plot_item):
        label = QLabel(plot_item.name())
        label.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed))

        palette = QPalette()
        color = plot_item.opts['pen'].color()
        palette.setColor(QPalette.WindowText, color)
        label.setPalette(palette)

        return label

    def removeItem(self, item, label):
        self.pw.removeItem(item)
        self._labels.removeWidget(label)
        # self._labels.takeAt(self._labels.indexOf(label))
        label.deleteLater()
示例#36
0
class ProjectsWindow(QMdiSubWindow):
    def __init__(self, app, OAuth_token, parent):
        super().__init__()

        self.app = app
        self.token = OAuth_token
        self.parent = parent

        self.open_windows = self.parent.open_windows

        self.initFig()
        self.initUI()

    def initFig(self):
        """
        Initialize Figshare information
        """
        self.project_list = self.get_project_list(self.token)

    def initUI(self):

        self.format_window()

        # Create a horizontal box layout to hold the project buttons
        self.project_buttons_box = QHBoxLayout()
        # Create a vertical box layout to hold the project window widgets and layouts
        self.vbox = QVBoxLayout()

        # Add the Projects button to the vertical box layout
        init_finish = len(self.project_list)
        if init_finish > 4:
            init_finish = 4
        self.create_project_bar(0, init_finish)
        self.vbox.addLayout(self.project_buttons_box)

        # Add the scroll bar to the vertical box layout
        self.s_bar = self.scroll_bar()
        self.vbox.addWidget(self.s_bar)

        self.hbox = QHBoxLayout()
        temp = QVBoxLayout()
        temp.addWidget(self.search_bar())
        temp.addLayout(self.management_buttons())
        self.hbox.addLayout(temp)
        self.hbox.addLayout(self.vbox)

        # Create a central widget for the projects window
        window_widget = QWidget()
        # Add the vertical box layout
        window_widget.setLayout(self.hbox)
        # Set the projects window widget
        self.setWidget(window_widget)

    #####
    # Window Formatting
    #####

    def format_window(self):
        """
        Formats the Projects window
        """
        # Gets the QRect of the main window
        geom = self.parent.geometry()
        # Gets the Qrect of the sections window
        section_geom = self.parent.section_geom

        # Define geometries for the projects window
        x0 = section_geom.x() + section_geom.width()
        y0 = section_geom.y()
        w = geom.width() - x0
        h = ((geom.height() - y0) / 6)
        self.setGeometry(x0, y0, w, h)
        # Remove frame from projects window
        self.setWindowFlags(Qt.FramelessWindowHint)

    #####
    # Window Widgets
    #####

    def scroll_bar(self):
        """
        Creates a scroll bar set to the size of the projects list
        :return: QScrollBar Object
        """
        s_bar = QScrollBar(Qt.Horizontal)
        s_bar.setMaximum(len(self.project_list) - 4)
        s_bar.sliderMoved.connect(self.slider_val)
        s_bar.valueChanged.connect(self.slider_val)
        return s_bar

    def create_proj_thumb(self, title, published_date, project_id):
        """
        Creates a large pushbutton for a project
        :param title: string. Project title
        :param published_date: string. project published date
        :param id: int. figshare project id number
        :return: QPushButton object
        """
        geom = self.geometry()

        # Get the scalig ratios for the current window
        w_ratio, f_ratio = scaling_ratio(self.app)
        # Scale the font sizes
        title_fnt_size = 12 * f_ratio
        date_ftn_size = 8 * f_ratio

        # Create the title label
        title_lbl = QLabel()
        title_lbl.setText("{}".format(title))
        title_lbl_fnt = QFont('SansSerif', title_fnt_size)
        title_lbl_fnt.setBold(True)
        title_lbl.setFont(title_lbl_fnt)
        title_lbl.setWordWrap(True)

        # Create the date label
        date_lbl = QLabel()
        if published_date is None:
            published_date = 'Private'
        date_lbl.setText("Published: {}".format(published_date))
        date_lbl_fnt = QFont('SansSerif', date_ftn_size)
        date_lbl.setFont(date_lbl_fnt)
        date_lbl.setStyleSheet('color: gray')
        date_lbl.setWordWrap(True)

        # Create a layout to hold the labels
        lbl_box = QVBoxLayout()
        # Add labels to layout
        lbl_box.addWidget(title_lbl)
        lbl_box.addWidget(date_lbl)

        # Create a button for the project
        btn = QPushButton(self)
        checkable_button(self.app, btn)
        btn.setLayout(lbl_box)
        btn.clicked[bool].connect(lambda: self.on_project_pressed(project_id))

        self.project_buttons_box.addWidget(btn)

    def create_project_bar(self, start, finish):
        """
        Creates a series of Project push buttons
        :param start: start position in projects list
        :param finish: finish position in projects list
        """
        self.buttons = {}
        i = 0
        for project_pos in range(start, finish):
            title = self.project_list[project_pos]['title']
            pub_date = self.project_list[project_pos]['published_date']
            project_id = self.project_list[project_pos]['id']
            self.create_proj_thumb(title, pub_date, project_id)
            self.buttons[project_id] = self.project_buttons_box.itemAt(
                i).widget()
            i += 1

    def management_buttons(self):
        """
        Creates a layout that holds buttons to be used for creating and deleting projects
        :return: QVBoxLayout holding the create, and delete projects buttons
        """

        # Create New Project Button
        np_btn = QPushButton()
        np_btn.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
        np_btn.setIcon(
            QIcon(os.path.abspath(__file__ + '/../..' + '/img/Folder-48.png')))
        np_btn.setToolTip('Create a new Figshare Project')
        np_btn.setToolTipDuration(1)
        np_btn.pressed.connect(self.on_projects_btn_pressed)

        # Create Delete Project Button
        del_btn = QPushButton()
        del_btn.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
        del_btn.setIcon(
            QIcon(os.path.abspath(__file__ + '/../..' +
                                  '/img/del_folder.png')))
        del_btn.setToolTip('Delete Selected Project')
        del_btn.setToolTipDuration(1)
        del_btn.pressed.connect(self.on_delete_btn_pressed)

        # Create layout to hold buttons
        hbox = QHBoxLayout()
        # Add Buttons to layout
        hbox.addWidget(np_btn)
        hbox.addWidget(del_btn)

        return hbox

    def search_bar(self):
        """
        Creates a QLineEdit object for the user to enter a search query
        :return: Edits the projects list object according to the filter
        """

        # Create text box
        edit = QLineEdit()
        # Set font style
        search_bar(self.app, edit)
        # Set place holder text
        edit.setPlaceholderText('Search')
        # Add a clear button to the line edit
        edit.setClearButtonEnabled(True)
        # Add mouse over text
        edit.setToolTip('Search for specific Figshare Projects')
        edit.setToolTipDuration(1)
        # Connect search function to the return key
        edit.returnPressed.connect(lambda: self.search_on_return(edit.text()))
        edit.textChanged.connect(lambda: self.search_on_clear(edit.text()))
        return edit

    #####
    # Widget Actions
    #####

    def slider_val(self):
        """
        Called when the projects button slider is changed.
        Removes all existing buttons and regenerates from the new position
        :return:
        """
        while self.project_buttons_box.count():
            item = self.project_buttons_box.takeAt(0)
            item.widget().deleteLater()

        s_bar_pos = self.s_bar.value()

        if 1 < len(self.project_list) < 4:
            number = len(self.project_list)
        else:
            number = 4
        self.s_bar.setMaximum(len(self.project_list) - number)

        self.create_project_bar(s_bar_pos, s_bar_pos + number)

    def search_init(self):
        """
        Called when the projects search bar is used.
        Removes all existing buttons and regenerates from new projects list
        :return:
        """
        while self.project_buttons_box.count():
            item = self.project_buttons_box.takeAt(0)
            item.widget().deleteLater()

        if 1 <= len(self.project_list) <= 4:
            number = len(self.project_list)
        else:
            number = 4

        self.s_bar.setMaximum(len(self.project_list) - number)

        self.create_project_bar(0, number)

    def search_on_return(self, search_text):
        """
        Called when return is pressed in the search bar.
        :return:
        """
        if search_text != '':
            self.project_list = self.search_projects(search_text, self.token)
            self.search_init()

    def search_on_clear(self, lineedit_text):
        """
        Called when the search bar is cleared
        :return:
        """
        if lineedit_text == '':
            self.project_list = self.get_project_list(self.token)
            self.slider_val()

    def on_projects_btn_pressed(self):
        """
        Called when the create new project button is pressed
        """
        if 'new_project_window' in self.open_windows:
            self.open_windows.remove('new_project_window')
            self.parent.new_project_window.close()
        else:
            self.open_windows.remove('projects_window')
            self.close()

            if 'project_info_window' in self.open_windows:
                self.parent.project_info_window.close()
                self.open_windows.remove('project_info_window')
            if 'project_articles_window' in self.open_windows:
                self.parent.project_articles_window.close()
                self.open_windows.remove('project_articles_window')
            if 'article_edit_window' in self.open_windows:
                self.open_windows.remove('article_edit_window')
                self.parent.article_edit_window.close()

            self.open_windows.add('new_project_window')
            self.parent.new_project_window = NewProjectWindow(
                self.app, self.token, self.parent)
            self.parent.mdi.addSubWindow(self.parent.new_project_window)
            self.parent.new_project_window.show()

    def on_project_pressed(self, project_id):
        """
        Called when a project is clicked.
        :return:
        """
        # For if there is already a project info window open
        if 'project_info_window' in self.open_windows:
            # Get the project id number of the current window
            open_proj = self.parent.project_info_window.project_id

            # For a different project than the currently open project
            if open_proj != project_id:
                # If the current project is in the current view of project buttons (it may have been scrolled away from)
                if open_proj in self.buttons:
                    # If that button is checked, uncheck it
                    if self.buttons[open_proj].isChecked():
                        self.buttons[open_proj].toggle()
                # Close the currently open project info window
                self.parent.project_info_window.close()
                # Create a new project info window for the different project
                self.parent.project_info_window = ProjectInfoWindow(
                    self.app, self.token, self.parent, project_id)
                # Add it as a sub window to the framing window
                self.parent.mdi.addSubWindow(self.parent.project_info_window)
                self.parent.project_info_window.show()

            # If the current projects button is pressed
            else:
                # Close the window and remove from the open window list
                self.open_windows.remove('project_info_window')
                self.parent.project_info_window.close()

            # If any sub windows are open close them as well
            if 'project_articles_window' in self.open_windows:
                self.open_windows.remove('project_articles_window')
                self.parent.project_articles_window.close()
            if 'article_edit_window' in self.open_windows:
                self.open_windows.remove('article_edit_window')
                self.parent.article_edit_window.close()

        # For when no project info window is open
        else:
            self.open_windows.add('project_info_window')
            self.parent.project_info_window = ProjectInfoWindow(
                self.app, self.token, self.parent, project_id)
            self.parent.mdi.addSubWindow(self.parent.project_info_window)
            self.parent.project_info_window.show()

    def on_delete_btn_pressed(self):
        """
        Called when the project delete button is pressed/
        :return:
        """
        open_proj = self.parent.project_info_window.project_id
        project_title = self.parent.project_info_window.project_info['title']

        msg = "Are you sure you want to delete Figshare Project: {}".format(
            project_title)
        msg_box = QMessageBox.question(self, 'Message', msg, QMessageBox.Yes,
                                       QMessageBox.No)

        if msg_box == QMessageBox.Yes:
            successful = self.delete_project(self.token, open_proj)

            if successful:
                con_reply = QMessageBox.information(
                    self, 'Deletion Confirmation',
                    'Project successfully deleted', QMessageBox.Ok)
                if con_reply == QMessageBox.Ok:
                    self.reopen_projects()
                else:
                    self.reopen_projects()
            else:
                con_reply = QMessageBox.warning(
                    self, 'Deletion Confirmation',
                    'Unknown error occurred.\n Project may not have been deleted.',
                    QMessageBox.Ok)
                if con_reply == QMessageBox.Ok:
                    self.reopen_projects()
                else:
                    self.reopen_projects()

    def reopen_projects(self):
        """
        Called to open and close the projects window.
        :return:
        """
        for i in range(2):
            self.parent.section_window.on_projects_btn_pressed()

    #####
    # Figshare API Interface Calls
    #####

    def get_project_list(self, token):
        """
        Returns the users private project list
        :param token: Figshare OAuth token
        :return: array of project
        """
        projects = Projects(token)
        return projects.get_list()

    def search_projects(self, search_text, token):
        """
        Returns a list of projects matching the users search criteria
        :param search_text: String. Figshare style elastic search string
        :param token: Figshare OAuth token
        :return:
        """
        projects = Projects(token)

        result = projects.search(search_text)
        if len(result) == 0:
            result = projects.get_list()

        return result

    def delete_project(self, token, project_id):
        """
        Deletes the given project from Figshare
        :param token:
        :param project_id: Int. Figshare project ID number
        :return:
        """
        projects = Projects(token)
        try:
            projects.delete(
                project_id, safe=False
            )  # Suppresses command line requirement for acknowledgement
            return True
        except:
            return False