def set_enable_all_widgets(cls, parent: QWidget, widget_type,
                            enabled: bool):
     """Set all widgets of a given type (or its subclasses) below given parent to given enabled state"""
     if isinstance(parent, widget_type):
         parent.setEnabled(enabled)
     for child in parent.children():
         cls.set_enable_all_widgets(child, widget_type, enabled)
Exemple #2
0
 def walk(cls, w: W.QWidget, tree_path=None, parent=None, collect=None):
     collect = collect or cls.collect
     tree_path = tree_path or TreePath.root()
     children = w.children()
     info = collect(w, parent=parent, children=children, tree_path=tree_path)
     yield tree_path, info
     for idx, child in enumerate(children):
         yield from cls.walk(
             child, tree_path=tree_path.with_appended(idx), parent=w, collect=collect
         )
Exemple #3
0
def clearWidget(widget: QWidget):
    num = 0
    for d in widget.children():
        #d.close()
        if isinstance(d, QLayout):
            clearLayout(d)
        else:
            d.close()
        d.deleteLater()
        num += 1
    return num
Exemple #4
0
 def __clearMainWindow_(self, widget: QWidget) -> None:
     if isinstance(widget, QLineEdit):
         widget.clear()
     elif isinstance(widget, QSpinBox):
         widget.setValue(0)
     elif isinstance(widget, QPlainTextEdit):
         widget.setPlainText('')
     elif isinstance(widget, QCheckBox):
         widget.setChecked(False)
     elif isinstance(widget, QComboBox):
         widget.setCurrentIndex(0)
     elif isinstance(widget, QTableView):
         model = widget.model()
         model.clear()
     else:
         l = widget.children()
         for w in l:
             self.__clearMainWindow_(w)
Exemple #5
0
class ChannelOptions(QWidget):
    """ Class for the channel loading window """
    def __init__(self, data, parent):
        """ Constructor for channel loading.
        """
        super().__init__()
        self.left = 10
        self.top = 10
        self.title = 'Select signals'
        self.width = parent.width / 5
        self.height = parent.height / 2.5
        # self.unprocessed_data = data_for_preds
        # if loading new data make copies in case user cancels loading channels
        self.new_load = 0
        # if len(self.unprocessed_data) != 0:
        if data.edf_fn != parent.ci.edf_fn:
            self.pi = PredsInfo()
            self.new_load = 1
        else:
            self.pi = parent.pi
        self.data = data
        self.parent = parent
        self.organize_win_open = 0
        self.setup_ui()

    def setup_ui(self):
        """ Sets up UI for channel window.
        """
        layout = QGridLayout()
        grid_lt = QGridLayout()
        grid_rt = QGridLayout()

        self.scroll = QScrollArea()
        self.scroll.setMinimumWidth(120)
        self.scroll.setMinimumHeight(200)  # would be better if resizable
        self.scroll.setWidgetResizable(True)
        self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.chn_qlist = QListWidget()
        self.chn_qlist.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.scroll.setWidget(self.chn_qlist)

        self.populate_chn_list()
        self.data.converted_chn_names = []
        self.data.convert_chn_names()
        self.ar1020 = self.data.can_do_bip_ar(1, 0)
        self.bip1020 = self.data.can_do_bip_ar(0, 0)
        self.ar1010 = self.data.can_do_bip_ar(1, 1)
        #self.bip1010 = self.data.can_do_bip_ar(0,1)
        self.data.total_nchns = len(self.data.chns2labels)

        self.setWindowTitle(self.title)
        self.setGeometry(self.parent.width / 3, self.parent.height / 3,
                         self.width, self.height)

        lbl_info = QLabel("Select channels to plot: ")
        grid_lt.addWidget(lbl_info, 0, 0)

        self.scroll_chn_cbox = QScrollArea()
        self.scroll_chn_cbox.hide()
        self.scroll_chn_cbox.setWidgetResizable(True)
        self.scroll_chn_cbox.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.scroll_chn_cbox.setHorizontalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)

        if self.ar1020:
            self.cbox_ar = QCheckBox("Average reference (10-20)", self)
            self.cbox_ar.toggled.connect(self.ar_checked)
            grid_lt.addWidget(self.cbox_ar, 1, 0)

            self.cbox_bip = QCheckBox("Bipolar (10-20)", self)
            self.cbox_bip.toggled.connect(self.bip_checked)
            grid_lt.addWidget(self.cbox_bip, 2, 0)
        elif self.bip1020:
            self.cbox_bip = QCheckBox("Bipolar (10-20)", self)
            self.cbox_bip.toggled.connect(self.bip_checked)
            grid_lt.addWidget(self.cbox_bip, 1, 0)

        if self.ar1010:
            self.cbox_ar1010 = QCheckBox("Average reference (10-10)", self)
            self.cbox_ar1010.toggled.connect(self.ar_checked1010)
            grid_lt.addWidget(self.cbox_ar1010, 3, 0)

        #    self.cbox_bip1010 = QCheckBox("Bipolar (10-10)",self)
        #    self.cbox_bip1010.toggled.connect(self.bip_checked1010)
        #    grid_lt.addWidget(self.cbox_bip1010,4,0)
        #elif self.bip1010:
        #    self.cbox_bip1010 = QCheckBox("Bipolar (10-10)",self)
        #    self.cbox_bip1010.toggled.connect(self.bip_checked1010)
        #    grid_lt.addWidget(self.cbox_bip1010,3,0)

        self.chn_cbox_list = QWidget()
        self.scroll_chn_cbox.setWidget(self.chn_cbox_list)
        self.chn_cbox_layout = QVBoxLayout()
        self.chn_cbox_list.setLayout(self.chn_cbox_layout)
        self.cbox_list_items = []
        for k in self.data.labels_from_txt_file.keys():
            self.add_txt_file(k)
        self.uncheck_txt_files()

        grid_lt.addWidget(self.scroll_chn_cbox, 5, 0)
        #self.cbox_txtfile = QCheckBox("",self)
        #self.cbox_txtfile.toggled.connect(self.txtFileChecked)
        #grid_lt.addWidget(self.cbox_txtfile,6,0)

        self.btn_loadtxtfile = QPushButton("Load text file", self)
        self.btn_loadtxtfile.clicked.connect(self.load_txt_file)
        grid_lt.addWidget(self.btn_loadtxtfile, 6, 0)

        #self.btn_cleartxtfile = QPushButton("Clear text file",self)
        #self.btn_cleartxtfile.clicked.connect(self.clearTxtFile)
        #self.btn_cleartxtfile.setVisible(0)
        #grid_lt.addWidget(self.btn_cleartxtfile,6,0)

        if len(self.data.txt_file_fn) > 0:
            if self.data.use_loaded_txt_file:
                self.cbox_txtfile.setChecked(1)
            self.btn_loadtxtfile.setVisible(0)
            self.btn_cleartxtfile.setVisible(1)
            self.cbox_txtfile.setVisible(1)
            self.cbox_txtfile.setText(self.data.txt_file_fn)

        lbl = QLabel("")
        grid_lt.addWidget(lbl, 7, 0)

        btn_organize = QPushButton('Organize', self)
        btn_organize.clicked.connect(self.organize)
        grid_lt.addWidget(btn_organize, 8, 0)

        btn_colors = QPushButton('Change colors', self)
        btn_colors.clicked.connect(self.chg_colors)
        grid_lt.addWidget(btn_colors, 9, 0)

        btn_exit = QPushButton('Ok', self)
        btn_exit.clicked.connect(self.okay_pressed)
        grid_lt.addWidget(btn_exit, 10, 0)

        grid_rt.addWidget(self.scroll, 0, 1)

        layout.addLayout(grid_lt, 0, 0)
        layout.addLayout(grid_rt, 0, 1)
        self.setLayout(layout)

        if (not self.parent.argv.montage_file is None
            ) and self.parent.init == 0:
            self.load_txt_file(self.parent.argv.montage_file)
            self.okay_pressed()
        else:
            self.show()

    def populate_chn_list(self):
        """ Fills the list with all of the channels in the edf file.
            PREDICTION channels are ignored and saved into self.pi
        """
        chns = self.data.chns2labels
        lbls = self.data.labels2chns
        self.data.pred_chn_data = []
        edf_reader_obj = pyedflib.EdfReader(self.data.edf_fn)
        # if len(self.unprocessed_data) > 0: # reset predicted
        #    self.parent.predicted = 0
        if len(chns) == 0:
            self.parent.throw_alert("There are no named channels in the file.")
            self.close_window()
        else:
            self.chn_items = []
            for i in range(len(chns)):
                if chns[i].find("PREDICTIONS") == -1:
                    self.chn_items.append(
                        QListWidgetItem(chns[i], self.chn_qlist))
                    self.chn_qlist.addItem(self.chn_items[i])
                # elif len(self.unprocessed_data) > 0:
                # load in the prediction channels if they exist
                # if they do, then the file was saved which
                # means that there are a reasonable amount of channels
                elif self.new_load:
                    # self.data.pred_chn_data.append(self.unprocessed_data[i])
                    self.data.pred_chn_data.append(
                        edf_reader_obj.readSignal(i))
                    lbls.pop(chns[i])
                    chns.pop(i)

            # if len(self.unprocessed_data) > 0 and len(self.data.pred_chn_data) != 0:
            if self.new_load and len(self.data.pred_chn_data) != 0:
                self.data.pred_chn_data = np.array(self.data.pred_chn_data)
                self.data.pred_chn_data = self.data.pred_chn_data.T
                if self.data.pred_chn_data.shape[1] > 1:
                    self.pi.pred_by_chn = 1
                else:
                    self.data.pred_chn_data = np.squeeze(
                        self.data.pred_chn_data)
                if len(self.data.pred_chn_data) > 0:
                    self.pi.preds = self.data.pred_chn_data
                    self.pi.preds_to_plot = self.data.pred_chn_data
                    self.pi.preds_loaded = 1
                    self.pi.plot_loaded_preds = 1
                    self.pi.preds_fn = "loaded from .edf file"
                    self.pi.pred_width = ((self.data.fs * self.data.max_time) /
                                          self.pi.preds.shape[0])
                    self.parent.predicted = 1

            # select the previously selected channels if they exist
            if len(self.data.list_of_chns) != 0 and not self.new_load:
                for k in range(len(self.data.list_of_chns)):
                    self.chn_items[self.data.list_of_chns[k]].setSelected(True)
            self.scroll.show()

    def ar_checked(self):
        """ Called when average reference is checked.
        """
        cbox = self.sender()
        chns = self.data.get_chns(self.data.labelsAR1020)
        if cbox.isChecked():
            self.uncheck_txt_files()
            self.cbox_bip.setChecked(0)
            #if self.ar1010:
            #    self.cbox_ar1010.setChecked(0)
            #    self.cbox_bip1010.setChecked(0)
            #elif self.bip1010:
            #    self.cbox_bip1010.setChecked(0)
            # select all AR channels, deselect all others
            self._select_chns(chns, 0)
        else:
            self._select_chns(chns, 1)

    def bip_checked(self):
        """ Called when bipolar is checked.
        """
        cbox = self.sender()
        chns = self.data.get_chns(self.data.labelsBIP1020)
        if cbox.isChecked():
            if self.ar1010:
                self.cbox_ar1010.setChecked(0)
        #        self.cbox_bip1010.setChecked(0)
        #    elif self.bip1010:
        #        self.cbox_bip1010.setChecked(0)
        if self.ar1020:
            chns = self.data.get_chns(self.data.labelsAR1020)
            if cbox.isChecked():
                self.cbox_ar.setChecked(0)
                self.uncheck_txt_files()
                self._select_chns(chns, 0)
            else:
                self._select_chns(chns, 1)
        elif cbox.isChecked():
            self.uncheck_txt_files()
            # select all bipolar channels, deselect all others
            self._select_chns(chns, 0)
        else:
            self._select_chns(chns, 1)

    def ar_checked1010(self):
        """ Called when average reference 1010 is called.
        """
        cbox = self.sender()
        chns = self.data.get_chns(self.data.labelsAR1010)
        if cbox.isChecked():
            self.uncheck_txt_files()
            self.cbox_bip.setChecked(0)
            self.cbox_ar.setChecked(0)
            # self.cbox_bip1010.setChecked(0)
            # select all AR channels, deselect all others
            self._select_chns(chns, 0)
        else:
            self._select_chns(chns, 1)

    def bip_checked1010(self):
        """ Called when bipolar 1010 is called.
        """
        cbox = self.sender()
        chns = self.data.get_chns(self.data.labelsBIP1010)
        if self.ar1020:
            chns = self.data.get_chns(self.data.labelsAR1010)
            if cbox.isChecked():
                self.cbox_ar.setChecked(0)
                self.uncheck_txt_files()
                if self.ar1010:
                    self.cbox_ar1010.setChecked(0)
                self.cbox_bip.setChecked(0)
                self._select_chns(chns, 0)
            else:
                self._select_chns(chns, 1)
        elif cbox.isChecked():
            self.uncheck_txt_files()
            self.cbox_bip.setChecked(0)
            # select all bipolar channels, deselect all others
            self._select_chns(chns, 0)
        else:
            self._select_chns(chns, 1)

    def uncheck_txt_files(self):
        """ Deselect all text files.
        """
        for child in self.chn_cbox_list.children():
            for grand_child in child.children():
                if isinstance(grand_child, QCheckBox):
                    grand_child.setChecked(0)

    def txt_file_checked(self):
        # Called if a text file is selected.
        c = self.sender()
        name = c.text()
        chns = self.data.get_chns(self.data.labels_from_txt_file[name])
        if c.isChecked():
            if self.ar1020:
                self.cbox_ar.setChecked(0)
                self.cbox_bip.setChecked(0)
                if self.ar1010:
                    self.cbox_ar1010.setChecked(0)
                #    self.cbox_bip1010.setChecked(0)
            if self.bip1020:
                self.cbox_bip.setChecked(0)
                #if self.bip1010:
                #    self.cbox_bip1010.setChecked(0)
            for child in self.chn_cbox_list.children():
                for ch in child.children():
                    if isinstance(ch, QCheckBox):
                        if ch.text() != name:
                            ch.setChecked(0)
            self._select_chns(chns, 0)
            self.data.use_loaded_txt_file = 1
        else:
            self._select_chns(chns, 1)
            self.data.use_loaded_txt_file = 0

    def _select_chns(self, chns, deselect_only):
        """ Selects given channels.

            Args:
                chns - the channels to select / deselect
                deselect_only - whether to only deselect given channels
        """
        if deselect_only:
            for k, val in enumerate(chns):
                if val:
                    self.chn_items[k].setSelected(0)
        else:
            for k, val in enumerate(chns):
                if val:
                    self.chn_items[k].setSelected(1)
                else:
                    self.chn_items[k].setSelected(0)

    def add_txt_file(self, name):
        """ Called to load in the new text file and add to the list.
        """
        # show the scroll area if it is hidden
        if self.scroll_chn_cbox.isHidden():
            self.scroll_chn_cbox.show()
        # add text file to the list
        main_wid = QWidget()
        wid = QGridLayout()
        wid_name = QCheckBox(name)
        wid_name.toggled.connect(self.txt_file_checked)
        wid_name.setChecked(1)
        wid.addWidget(wid_name, 0, 0)
        main_wid.setLayout(wid)
        self.chn_cbox_layout.addWidget(main_wid)

    def load_txt_file(self, name=""):
        """ Called to load a text file.
        """
        if self.parent.argv.montage_file is None or self.parent.init:
            name = QFileDialog.getOpenFileName(self, 'Open file', '.',
                                               'Text files (*.txt)')
            name = name[0]
        if name is None or len(name) == 0:
            return

        short_name = name.split('/')[-1]
        if len(name.split('/')[-1]) > 15:
            short_name = name.split('/')[-1][0:15] + "..."
        if short_name in self.data.labels_from_txt_file.keys():
            self.parent.throw_alert(
                "Each loaded text file must have a unique " +
                "name (first 14 characters). Please rename your file.")
            return
        if self._check_chns(name, short_name):
            self.add_txt_file(short_name)
        else:
            # throw error
            self.parent.throw_alert(
                "The channels in this file do not match" +
                " those of the .edf file you have loaded. Please check your file."
            )

    def _check_chns(self, txt_fn, txt_fn_short):
        """ Function to check that this file has the appropriate channel names.
            Sets self.data.labels_from_txt_file if valid.

            Args:
                txt_fn: the file name to be loaded
                txt_fn_short: the name to be used in the dict
            Returns:
                1 for sucess, 0 for at least one of the channels was not found in
                the .edf file
        """
        try:
            text_file = open(txt_fn, "r")
        except:
            self.parent.throw_alert("The .txt file is invalid.")
        lines = text_file.readlines()
        l = 0
        while l < len(lines):
            loc = lines[l].find("\n")
            if loc != -1:
                lines[l] = lines[l][0:loc]
            if len(lines[l]) == 0:
                lines.pop(l)
            else:
                l += 1
        text_file.close()
        ret = 1
        for l in lines:
            if not l in self.data.converted_chn_names and not l in self.data.labels2chns:
                ret = 0
        if ret:
            self.data.labels_from_txt_file[txt_fn_short] = []
            for i in range(len(lines)):
                if not lines[len(lines) - 1 -
                             i] in self.data.converted_chn_names:
                    lines[len(lines) - 1 - i] = convert_txt_chn_names(
                        lines[len(lines) - 1 - i])
                self.data.labels_from_txt_file[txt_fn_short].append(
                    lines[len(lines) - 1 - i])
        return ret

    def check_multi_chn_preds(self):
        """ Check if plotting predictions by channel. If so, check
            whether the number of channels match.

            Sets parent.predicted to 1 if correct, 0 if incorrect.
        """
        if self.parent.pi.pred_by_chn and self.parent.predicted:
            if self.parent.ci.nchns_to_plot != self.parent.pi.preds_to_plot.shape[
                    1]:
                self.parent.predicted = 0

    def overwrite_temp_info(self):
        """ If temporary data was created in case the user cancels loading channels,
            it is now overwritten.

            Things to be overwritten:
                - parent.edf_info
                - parent.data
                - parent.fs
                - parent.max_time
                - parent.pi
                - parent.ci
                - parent.predicted
                - parent.count (set to 0 if new load)
        """
        self.parent.edf_info = self.parent.edf_info_temp
        self.parent.max_time = self.parent.max_time_temp
        self.parent.pi.write_data(self.pi)
        self.parent.ci.write_data(self.data)
        self.data = self.parent.ci
        self.parent.sei.fn = self.parent.fn_full_temp
        if self.new_load:
            self.parent.count = 0
            self.parent.lbl_fn.setText("Plotting: " + self.parent.fn_temp)

    def organize(self):
        """ Function to open the window to change signal order.
        """
        if not self.parent.organize_win_open:
            ret = self.check()
            if ret == 0:
                self.parent.organize_win_open = 1
                self.parent.chn_org = OrganizeChannels(self.data, self.parent)
                self.parent.chn_org.show()
                self.close_window()

    def chg_colors(self):
        """ Function to open the window to change signal color.
        """
        if not self.parent.color_win_open:
            ret = self.check()
            if ret == 0:
                self.parent.color_win_open = 1
                self.parent.color_ops = ColorOptions(self.data, self.parent,
                                                     self)
                self.parent.color_ops.show()
                self.close_window()

    def check(self):
        """ Function to check the clicked channels and exit.

            Returns:
                -1 if there are no selected channels, 0 otherwise
        """
        selected_list_items = self.chn_qlist.selectedItems()
        idxs = []
        for k in range(len(self.chn_items)):
            if self.chn_items[k] in selected_list_items:
                idxs.append(self.data.labels2chns[self.data.chns2labels[k]])
        if len(idxs) > self.parent.max_channels:
            self.parent.throw_alert("You may select at most " +
                                    str(self.parent.max_channels) +
                                    " to plot. " + "You have selected " +
                                    str(len(idxs)) + ".")
            return -1
        if len(idxs) == 0:
            self.parent.throw_alert("Please select channels to plot.")
            return -1
        # Overwrite if needed, and prepare to plot
        if self.new_load:
            self.overwrite_temp_info()
            if self.parent.si.plot_spec:
                self.parent.si.plot_spec = 0
                self.parent.removeSpecPlot()
        plot_bip_from_ar = 0
        if (self.ar1020 and self.cbox_bip.isChecked()):  # or
            #self.ar1010 and self.cbox_bip1010.isChecked()):
            plot_bip_from_ar = 1
        mont_type, txt_file_name = self._get_mont_type()
        self.data.prepare_to_plot(idxs, self.parent, mont_type,
                                  plot_bip_from_ar, txt_file_name)
        # check if multi-chn pred and number of chns match
        self.check_multi_chn_preds()
        return 0

    def _get_mont_type(self):
        """ Gets the type of montage from the cboxes.

            Returns:
                0 = ar 1020
                1 = bip 1020
                2 = ar 1010
                3 = ar 1010
                4 = text file
                5 = selected channels don't match selection
                txt_file_name, the name of the text file
        """
        mont_type = 5
        txt_file_name = ""
        if self.ar1020 and self.cbox_ar.isChecked():
            mont_type = 0
        elif (self.ar1020 or self.bip1020) and self.cbox_bip.isChecked():
            mont_type = 1
        elif self.ar1010 and self.cbox_ar1010.isChecked():
            mont_type = 2
        #elif self.bip1010 and self.cbox_bip1010.isChecked():
        #    mont_type = 3
        else:
            for child in self.chn_cbox_list.children():
                for ch in child.children():
                    if isinstance(ch, QCheckBox) and ch.isChecked():
                        txt_file_name = ch.text()
                        mont_type = 4
        return mont_type, txt_file_name

    def okay_pressed(self):
        """ Called when okay is pressed. Calls check function and returns
            if channels were sucessfully selected.
        """
        ret = self.check()
        if ret == 0:
            self.parent.call_initial_move_plot()
            self.close_window()

    def close_window(self):
        """ Closes the window.
        """
        self.parent.chn_win_open = 0
        self.close()

    def closeEvent(self, event):
        """ Called when the window is closed.
        """
        self.parent.chn_win_open = 0
        event.accept()
Exemple #6
0
class AboutDialog(QDialog):
    def __init__(self, main_window):
        super().__init__(main_window)
        
        self.setWindowTitle(_("About UML .FRI"))
        
        main_layout = QVBoxLayout()
        
        desc_layout = QHBoxLayout()
        
        logo_pixmap = QPixmap()
        logo_pixmap.load(os.path.join(GRAPHICS, "logo", "logo_full.png"))
        
        logo = QLabel()
        logo.setPixmap(logo_pixmap)
        
        desc_layout.addWidget(logo, 0, Qt.AlignTop)
        
        desc_text_layout = QVBoxLayout()
        
        desc_text_layout.addWidget(QLabel("<h1>{0}</h1>".format(Application().about.name)))
        desc_text_layout.addWidget(QLabel("{0} {1}".format(_("Version"), Application().about.version)))
        desc_text_layout.addItem(QSpacerItem(0, 20))
        desc_label = QLabel(Application().about.description)
        desc_label.setWordWrap(True)
        desc_text_layout.addWidget(desc_label)
        desc_text_layout.addStretch(1)
        for author, year in Application().about.author:
            desc_text_layout.addWidget(QLabel("<small>{0}</small>".format(self.__about_line(author, year))))
        
        for url in Application().about.urls:
            desc_text_layout.addWidget(self.__create_link(url))
        
        desc_layout.addLayout(desc_text_layout, 1)
        
        main_layout.addLayout(desc_layout)
        
        tabs = QTabWidget()
        tabs.setUsesScrollButtons(False)
        main_layout.addWidget(tabs, 1)

        self.__updates_tab = None
        
        tabs.addTab(self.__create_used_libraries_tab(), _("Used libraries"))
        
        if os.path.exists(LICENSE_FILE):
            tabs.addTab(self.__create_license_tab(), _("License"))
        
        tabs.addTab(self.__create_version_1_0_tab(), _("Version 1.0 contributions"))

        tabs.addTab(self.__create_updates_tab(), _("Updates"))
        
        if Application().about.is_debug_version:
            debug_layout = QHBoxLayout()
            debug_icon = QLabel()
            debug_icon.setPixmap(QIcon.fromTheme("dialog-warning").pixmap(QSize(16, 16)))
            debug_layout.addWidget(debug_icon)
            debug_text = QLabel(_("You are running UML .FRI in the debug mode"))
            debug_layout.addWidget(debug_text, 1)
            main_layout.addLayout(debug_layout)
        
        button_box = QDialogButtonBox(QDialogButtonBox.Ok)
        button_box.button(QDialogButtonBox.Ok).setText(_("Ok"))
        button_box.accepted.connect(self.accept)
        
        main_layout.addWidget(button_box)
        
        self.setLayout(main_layout)
        
        Application().event_dispatcher.subscribe(UpdateCheckStartedEvent, self.__update_started)
        Application().event_dispatcher.subscribe(UpdateCheckFinishedEvent, self.__update_finished)
    
    def __create_used_libraries_tab(self):
        versions_layout = QFormLayout()
        for depencency, version in Application().about.dependency_versions:
            versions_layout.addRow(_("{0} version").format(depencency), QLabel(version))
        versions_widget = QWidget()
        versions_widget.setLayout(versions_layout)
        return versions_widget
    
    def __create_license_tab(self):
        license_text = QTextEdit()
        with open(LICENSE_FILE, 'rt') as license_file:
            license_text.setPlainText(license_file.read())
        license_text.setReadOnly(True)
        license_text.setLineWrapMode(QTextEdit.NoWrap)
        return license_text
    
    def __create_version_1_0_tab(self):
        version_1_layout = QVBoxLayout()
        for author, year in Application().about.version_1_contributions:
            version_1_layout.addWidget(QLabel(self.__about_line(author, year)))
        version_1_widget = QWidget()
        version_1_widget.setLayout(version_1_layout)
        version_1_scroll = QScrollArea()
        version_1_scroll.setWidget(version_1_widget)
        return version_1_scroll
    
    def __create_updates_tab(self):
        if self.__updates_tab is None:
            self.__updates_tab = QWidget()
        else:
            self.__updates_tab.children()[0].deleteLater()
        
        updates_layout = QGridLayout()
        updates_widget = QWidget(self.__updates_tab)
        updates_widget.setLayout(updates_layout)
        self.__check_updates = QPushButton(_("Check for updates"))
        self.__check_updates.clicked.connect(lambda checked=False: Application().about.updates.recheck_update())
        updates_layout.addWidget(self.__check_updates, 0, 0, 1, 3, Qt.AlignLeft)
        
        latest_version = Application().about.updates.latest_version
        updates_layout.addWidget(QLabel(_("Latest version available:")), 1, 0)
        if latest_version is None:
            updates_layout.addWidget(QLabel("-"), 1, 1)
        else:
            updates_layout.addWidget(QLabel(str(latest_version.version)), 1, 1)
            if Application().about.updates.latest_version.is_newer:
                updates_layout.addWidget(self.__create_download_link(latest_version.url), 1, 2)
        
        latest_prerelease = Application().about.updates.latest_prerelease
        if latest_prerelease is not None:
            updates_layout.addWidget(QLabel(_("Latest unstable version available:")), 2, 0)
            updates_layout.addWidget(QLabel(str(latest_prerelease.version)), 2, 1)

            if latest_prerelease.is_newer:
                updates_layout.addWidget(self.__create_download_link(latest_prerelease.url), 2, 2)
        
        if Application().about.updates.has_error:
            updates_layout.addWidget(QLabel("<b>{0}</b>".format(_("Error while checking update:"))), 3, 0)
            more_info = QPushButton(_("More info"))
            more_info.clicked.connect(self.__show_update_error)
            updates_layout.addWidget(more_info, 3, 1)
            
        updates_widget.setVisible(True)
        return self.__updates_tab
    
    def __show_update_error(self, checked=False):
        ExceptionDialog(Application().about.updates.error).exec()
    
    def __create_link(self, url):
        ret = QLabel("<a href=\"{0}\">{1}</a>".format(url, url))
        ret.setOpenExternalLinks(True)
        return ret
    
    def __create_download_link(self, url):
        ret = QLabel("<a href=\"{0}\">{1}</a>".format(url, _("download update")))
        ret.setToolTip(url)
        ret.setOpenExternalLinks(True)
        return ret
    
    def __about_line(self, author, year):
        line = "© "
        if isinstance(year, tuple):
            line += "{0}-{1} ".format(year[0], year[1])
        else:
            line += "{0} ".format(author[1])
        line += author
        return line
    
    def __update_started(self, event):
        self.__check_updates.setEnabled(False)

    def __update_finished(self, event):
        self.__create_updates_tab()
Exemple #7
0
class App(QMainWindow):
    PATH = None

    def __init__(self):
        super().__init__()
        self.old_disk_data = reusables.load_json('database.json')
        self.window_title = 'Movies'
        self.left = 300
        self.top = 300
        self.width = 920
        self.height = 600
        self.data = {}
        tmdb2imdb = {}
        # self.getConfig()
        self.movies = {}  # Contains the id -> title of movies
        self.popular_movies = []
        self.threaded_search = ThreadedSearcher()
        self.threaded_search.search_result.connect(self.search_response)
        self.initUI()
        # Contains all the movies that fetched as popular movies form tmdb at intialization

    def getConfig(self):
        config = reusables.load_json('config.json')
        self.PATH = config['path']

    @QtCore.pyqtSlot(dict)
    def updateData(self, movie):
        self.data[movie['id']] = movie
        self.statusBar.showMessage('Received info about: ' + movie['title'])
        # It is callback function from infoGetter, that tells to update UI
        btn = self.movieAreaContents.findChild(QtWidgets.QToolButton,
                                               str(movie['id']))
        if btn:
            btn.setText('{} ({})'.format(movie['title'], movie['Year']))
            icon = QtGui.QIcon()
            icon.addPixmap(QtGui.QPixmap(movie['poster_value']),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
            btn.setIcon(icon)

    def infoGetterThreaded(self):
        # It starts the threaded info getter that obtains the images, plots and other info from tmbd (database.py)
        # self.updater = Updater(self.data, self.movies)
        self.updater = Updater()
        self.updater.update_signal.connect(self.updateData)
        self.updater.start()
        # self.insertSearchStack()

    def put_in_updater_stack(self, id):
        # if id not in
        if id in self.old_disk_data.keys(
        ):  # If already avaiable disk data is avaiable, use that
            self.updateData(self.old_disk_data[id])
            return
        threading.Thread(target=self.updater.putStack, args=(id, )).start()

    def updateAvailabeInfo(self):
        for iid, info in self.data.items():
            btn = self.movieAreaContents.findChild(QtWidgets.QToolButton, iid)
            btn.setText('{} ({})'.format(info['title'], info['Year']))
            icon = QtGui.QIcon()
            icon.addPixmap(QtGui.QPixmap(info['poster_value']),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
            btn.setIcon(icon)

    def initUI(self):
        self.setWindowTitle(self.window_title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        # Topmost widget in the program
        self.mainWigdet = QWidget()
        self.mainWigdet.setObjectName('main Widget')
        self.mainLayout = QVBoxLayout()

        # Gets the toolbar layout from the function
        self.toolbar = self.addToolbar()

        # Layout for the main area of the application ie movieArea & infoArea
        self.mainArea = QHBoxLayout()

        movieArea = self.movieArea()
        self.mainArea.addWidget(movieArea)

        spacerItem2 = QtWidgets.QSpacerItem(20, 40,
                                            QtWidgets.QSizePolicy.Minimum,
                                            QtWidgets.QSizePolicy.Expanding)
        self.mainArea.addItem(spacerItem2)

        infoArea = self.infoArea()
        self.mainArea.addWidget(infoArea)

        # Finally setting of the application
        self.mainLayout.addLayout(self.toolbar)
        self.mainLayout.addLayout(self.mainArea)
        self.mainWigdet.setLayout(self.mainLayout)
        self.setCentralWidget(self.mainWigdet)

        self.insertMenuBar()
        self.insertStatusbar()

        # for a in ['title', 'tagline', 'Year', 'Rating', 'Director', 'Duration', 'Genre', 'Budget', 'Box Office',
        #           'cast','plot']:
        #     self.contents.findChild(QLabel, a).setText(a)

        # Call the threaded function, to update the info about the movies simultaneously

        self.infoGetterThreaded()

        # Update the icons for the data that is already avaiable
        self.updateAvailabeInfo()

        #
        self.installEventFilter(self)

        # All the buttons in movieArea, used by search
        self.popular_movies_buttons = self.movieAreaContents.children()[1:]

        for id in self.movies:
            self.put_in_updater_stack(id)

        # print('done')

        # Set the inital infoArea to the first movie on the list
        # if self.movies:
        #     self.showInfoArea(list(self.movies.keys())[0])

    def create_movie_button(self, movie_name, id):
        icon_size = QtCore.QSize(156, 210)
        btn_size = QtCore.QSize(167, 240)
        icon = QtGui.QIcon()

        btn = QtWidgets.QToolButton()
        btn.setText(movie_name)
        btn.setObjectName(str(id))

        # if iid in self.data.keys():  # Already searched movies uses database
        #     btn.setText('{} ({})'.format(self.data[iid]['title'], self.data[iid]['Year']))
        #     btn.setObjectName(str(iid))
        # else:  ## Still unsearched movies uses pathname
        #     btn.setText(movie.split(os.path.sep)[-1])
        #     btn.setObjectName(str(iid))

        path = './media/poster/' + 'na' + '.jpg'
        # print(movie, path)
        icon.addPixmap(QtGui.QPixmap(path), QtGui.QIcon.Normal,
                       QtGui.QIcon.Off)
        btn.setIcon(icon)
        btn.setAutoRaise(True)
        btn.setStyleSheet('''text-align:left;''')
        btn.setIconSize(icon_size)
        btn.setAutoExclusive(True)
        btn.setCheckable(True)
        btn.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
        btn.setFixedSize(btn_size)
        btn.installEventFilter(self)
        self.lyt.addWidget(btn)

    def movieArea(self):
        scrollArea = QScrollArea()  # Main scroll Area
        self.movieAreaContents = QWidget(
        )  # Contents for inside the scroll area i.e. Buttons
        self.setObjectName('movieAreaContents')
        self.lyt = FlowLayout(hspacing=15,
                              vspacing=10)  # Layout for those contents/buttons
        self.lyt.setContentsMargins(0, 0, 0, 50)

        # Setup the properties of scrollbar
        scrollArea.setGeometry(QtCore.QRect(0, 0, 405, 748))
        scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scrollArea.setWidgetResizable(True)

        movies = self.getMovieNamesList()
        for iid, movie in movies.items():
            self.create_movie_button(movie, iid)

        self.movieAreaContents.setLayout(self.lyt)
        scrollArea.setWidget(self.movieAreaContents)

        # Register buttons for events
        return scrollArea

    def infoArea(self):
        scrollArea = QScrollArea()  # Main scroll Area
        self.contents = QWidget(
        )  # Contents for inside the scroll area i.e. Buttons
        lyt = QVBoxLayout()  # Layout for those contents/buttons

        # Setup Properties for Content
        self.contents.setGeometry(QtCore.QRect(0, 0, 670, 806))
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred,
                                           QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.contents.sizePolicy().hasHeightForWidth())
        self.contents.setSizePolicy(sizePolicy)
        self.contents.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.contents.setObjectName("info_scroll_area")

        # Setup properties for box layout
        lyt.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
        lyt.setSpacing(10)
        lyt.setContentsMargins(10, -1, -1, -1)

        # Setup the properties of scrollarea
        scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scrollArea.setWidgetResizable(True)
        scrollArea.setMinimumSize(QtCore.QSize(675, 0))

        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                           QtWidgets.QSizePolicy.Minimum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            scrollArea.sizePolicy().hasHeightForWidth())
        scrollArea.setSizePolicy(sizePolicy)

        # Basic icon size
        icon_size = QtCore.QSize(154, 210)
        btn_size = QtCore.QSize(154, 240)
        icon = QtGui.QIcon()

        # #Function to rapidly create common heading value rows
        # sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        # sizePolicy.setHorizontalStretch(0)
        # sizePolicy.setVerticalStretch(0)

        def infoRow(name):
            row = QHBoxLayout()
            row.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)

            font = QtGui.QFont()
            font.setPointSize(9)
            font.setBold(True)
            font.setWeight(75)

            first = QLabel()
            first.setFont(font)
            first.setText(name)
            first.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTop
                               | QtCore.Qt.AlignTrailing)

            font = QtGui.QFont()
            font.setPointSize(9)

            second = QLabel(text='')
            second.setFont(font)
            second.setObjectName(name)
            second.setOpenExternalLinks(True)
            second.setAlignment(QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft
                                | QtCore.Qt.AlignTop)

            row.addWidget(first)
            row.addWidget(second)
            return row

        ####    Title
        self.title = QLabel('')
        font = QtGui.QFont()
        font.setFamily("Calibri")
        font.setPointSize(16)
        font.setBold(True)
        font.setWeight(75)
        self.title.setFont(font)
        self.title.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignTop)
        self.title.setWordWrap(True)
        self.title.setObjectName("title")
        lyt.addWidget(self.title)

        # Backdrop
        self.image = QtWidgets.QVBoxLayout()
        self.image.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)
        self.image.setSpacing(0)
        self.image.setObjectName("image")
        self.backdrop_value = QtWidgets.QLabel()
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred,
                                           QtWidgets.QSizePolicy.Ignored)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.backdrop_value.sizePolicy().hasHeightForWidth())
        self.backdrop_value.setSizePolicy(sizePolicy)
        self.backdrop_value.setMinimumSize(QtCore.QSize(624, 351))
        self.backdrop_value.setMaximumSize(QtCore.QSize(624, 351))
        self.backdrop_value.setPixmap(QtGui.QPixmap("./media/backdrop/na.jpg"))
        self.backdrop_value.setScaledContents(True)
        # self.setStyleSheet('''padding: 0px 0px 0px 0px;''')
        self.backdrop_value.setAlignment(QtCore.Qt.AlignHCenter
                                         | QtCore.Qt.AlignTop)
        self.backdrop_value.setObjectName("backdrop_value")
        self.image.addWidget(self.backdrop_value)

        # Poster
        self.poster_value = QtWidgets.QLabel()
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored,
                                           QtWidgets.QSizePolicy.Minimum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.poster_value.sizePolicy().hasHeightForWidth())
        self.poster_value.setSizePolicy(sizePolicy)
        self.poster_value.setMinimumSize(QtCore.QSize(0, 52))
        self.poster_value.setMaximumSize(QtCore.QSize(16777215, 240))
        self.poster_value.setPixmap(QtGui.QPixmap('./media/poster/na.jpg'))
        self.poster_value.setScaledContents(False)
        self.poster_value.setAlignment(QtCore.Qt.AlignLeading
                                       | QtCore.Qt.AlignLeft
                                       | QtCore.Qt.AlignTop)
        self.poster_value.setIndent(0)
        self.poster_value.setStyleSheet('''padding: 0px 0px 0px 40px;''')
        self.poster_value.setObjectName("poster_value")
        self.image.addWidget(self.poster_value)
        lyt.addLayout(self.image)

        ## Tagline
        self.tagline = QLabel(text='')
        font = QtGui.QFont()
        font.setPointSize(10)
        font.setWeight(50)
        self.tagline.setFont(font)
        self.tagline.setAlignment(QtCore.Qt.AlignLeading
                                  | QtCore.Qt.AlignHCenter
                                  | QtCore.Qt.AlignTop)
        self.tagline.setWordWrap(True)
        self.tagline.setObjectName('tagline')
        lyt.addWidget(self.tagline)

        spacer = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding,
                                       QtWidgets.QSizePolicy.Minimum)
        lyt.addItem(spacer)

        lyt.addLayout(infoRow('Year'))
        lyt.addLayout(infoRow('Rating'))
        lyt.addLayout(infoRow('Director'))
        lyt.addLayout(infoRow('Duration'))
        lyt.addLayout(infoRow('Genre'))
        lyt.addLayout(infoRow('Budget'))
        lyt.addLayout(infoRow('Box Office'))

        # Cast
        self.cast_box = QtWidgets.QVBoxLayout()
        self.cast_box.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
        self.cast_box.setSpacing(4)

        self.cast = QtWidgets.QLabel(text='Cast')
        font = QtGui.QFont()
        font.setPointSize(9)
        font.setBold(True)
        font.setWeight(75)
        self.cast.setFont(font)
        self.cast.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignTop)
        self.cast_box.addWidget(self.cast)

        self.cast_value = QtWidgets.QLabel(text='')
        font = QtGui.QFont()
        font.setPointSize(9)
        self.cast_value.setFont(font)
        self.cast_value.setOpenExternalLinks(True)
        self.cast_value.setAlignment(QtCore.Qt.AlignHCenter
                                     | QtCore.Qt.AlignTop)
        self.cast_value.setWordWrap(True)
        self.cast_value.setObjectName("cast")
        self.cast_box.addWidget(self.cast_value)

        lyt.addLayout(self.cast_box)

        # Spacer
        spacer = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding,
                                       QtWidgets.QSizePolicy.Minimum)
        lyt.addItem(spacer)

        # Description
        self.plot_value = QtWidgets.QLabel(text='')
        font = QtGui.QFont()
        font.setPointSize(9)
        self.plot_value.setFont(font)
        self.plot_value.setTextFormat(QtCore.Qt.AutoText)
        self.plot_value.setAlignment(QtCore.Qt.AlignHCenter
                                     | QtCore.Qt.AlignTop)
        self.plot_value.setWordWrap(True)
        self.plot_value.setObjectName("plot")
        lyt.addWidget(self.plot_value)

        lyt.addItem(
            QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding,
                        QtWidgets.QSizePolicy.Minimum))
        # rating_box = QHBoxLayout()
        #
        # self.slider = QSlider(Qt.Horizontal)
        # self.slider.setMinimum(1)
        # self.slider.setMaximum(10)
        # self.slider.setTickInterval(1)
        # self.slider.setTickPosition(QSlider.TicksBelow)

        # self.rating_value = QLabel(text=' (0/5) ')
        #
        # self.slider.valueChanged[int].connect(self.rating_value_changed)
        #
        # rating_box.addWidget(QLabel(text='Your Rating'))
        # rating_box.addWidget(self.slider)
        # rating_box.addWidget(self.rating_value)

        # rating_box.setAlignment(Qt.AlignVCenter)
        # rating_box.setAlignment(Qt.AlignBottom)

        # lyt.addLayout(rating_box)

        self.contents.setLayout(lyt)

        # child = contents.findChild(QLabel, 'a')
        scrollArea.setWidget(self.contents)

        return scrollArea

    # def rating_value_changed(self, x):
    #     my_ratings = reusables.load_json('my_ratings.json')
    #     self.rating_value.setText('({:.1f}/5)'.format(x / 2))
    #     self.data[self.CURRENT_MOVIE]['my_rating'] = x / 2
    #     my_ratings[self.data[self.CURRENT_MOVIE]['imdb']] = x / 2
    #
    #     reusables.save_json(my_ratings, 'my_ratings.json', indent=2)
    #     reusables.save_json(self.data, 'database_v2.json', indent=2)

    def insertStatusbar(self):
        self.statusBar = QStatusBar()
        self.setStatusBar(self.statusBar)
        self.statusBar.showMessage('Loaded {} movies'.format(len(self.movies)))

    def openSettings(self):
        config = reusables.load_json('config.json')
        dlg = Setting_UI(self)
        dlg.path_line_edit.setText(config['path'])
        if dlg.exec_():
            # If okay is pressed
            new_path = dlg.path_line_edit.text()

            if os.path.exists(new_path):
                self.PATH = new_path
                print(self.PATH)
                self.initUI()

        else:
            # If cancel is pressed
            pass

    def insertMenuBar(self):
        # create menu
        menubar = QMenuBar()

        # layout.addWidget(menubar, 0, 0)
        actionFile = menubar.addMenu("File")
        actionSetting = actionFile.addAction("Settings")
        # actionFile.addAction("New")
        # actionFile.addAction("Open")
        # actionFile.addAction("Save")
        actionFile.addSeparator()
        actionQuit = actionFile.addAction("Quit")
        menubar.addMenu("Edit")
        menubar.addMenu("View")
        menubar.addMenu("Help")

        # Event Handlers
        actionSetting.triggered.connect(self.openSettings)
        actionQuit.triggered.connect(self.close)

        self.setMenuBar(menubar)

    def addToolbar(self):
        layout = QtWidgets.QHBoxLayout()
        # layout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)

        # Add the widgets with size contrainsts

        self.search_field = QLineEdit()
        self.search_field.setMaximumSize(QtCore.QSize(500, 32))
        self.search_field.setAlignment(Qt.AlignLeft)

        search_button = QPushButton('Search')
        search_button.setMaximumSize(QtCore.QSize(68, 34))

        spacerItem = QtWidgets.QSpacerItem(10, 35,
                                           QtWidgets.QSizePolicy.Minimum,
                                           QtWidgets.QSizePolicy.Preferred)

        sort_label = QLabel('Sort By')
        sort_label.setOpenExternalLinks(True)

        sort_label.setMaximumSize(QtCore.QSize(72, 32))

        comboBox = QComboBox()
        comboBox.setMaximumSize(QtCore.QSize(100, 32))
        comboBox.addItems(
            ['Name A-Z', 'Name Z-A', 'Rating', 'Year', 'Runtime'])

        propertiesButton = QPushButton('Properties')
        propertiesButton.setMaximumSize(QtCore.QSize(95, 34))

        spacerItem2 = QtWidgets.QSpacerItem(10, 35,
                                            QtWidgets.QSizePolicy.Expanding,
                                            QtWidgets.QSizePolicy.Preferred)

        ## Events
        search_button.clicked.connect(self.search_option)
        self.search_field.returnPressed.connect(self.search_option)
        self.search_field.textChanged.connect(self.search_option)
        comboBox.currentIndexChanged['QString'].connect(
            self.sort_option_changed)

        # Add the widgets to the layout
        layout.addWidget(self.search_field)
        layout.addWidget(search_button)
        layout.addItem(spacerItem)
        layout.addWidget(sort_label)
        layout.addWidget(comboBox)
        layout.addWidget(propertiesButton)
        layout.addItem(spacerItem2)
        layout.setAlignment(Qt.AlignLeft)
        layout.setAlignment(Qt.AlignHCenter)
        return layout

    # def search_option(self):
    #     query = self.search_field.text()
    #
    #     child_dict = defaultdict(str)
    #
    #     accepted_list = []
    #     for child in self.childs:
    #         if query == '':  # If the query is None, the  add all the widgets
    #             self.lyt.addWidget(child)
    #         elif query.lower() not in self.data[child.objectName()]['title'].lower():
    #             child.setParent(None)
    #         else:
    #             self.lyt.addWidget(child)
    #
    #     self.statusBar.showMessage('{}'.format(self.movieAreaContents.children()[:1]))

    @QtCore.pyqtSlot(list)
    def search_response(self, list_of_results):
        print(len(list_of_results))

        for child in self.movieAreaContents.children(
        )[1:]:  # Remove all the button from movieArea
            child.setParent(None)

        for title, year, id in list_of_results:  # Add newly searched movies
            if id not in self.popular_movies:
                self.create_movie_button('{} ({})'.format(title, year),
                                         str(id))
                self.put_in_updater_stack(str(id))

        for child in self.popular_movies_buttons:  # Add the popular movies again
            self.lyt.addWidget(child)

    def threadedSearcherRequest(self, query):
        # print('here', query)
        self.threaded_search.putStack(query)

    def search_option(self):
        query = self.search_field.text()

        child_dict = defaultdict(str)

        self.threadedSearcherRequest(query)

        accepted_list = []
        # for child in self.popular_movies_buttons:
        #     if query == '':  # If the query is None, the  add all the widgets
        #         self.lyt.addWidget(child)
        #     elif query.lower() not in self.data[child.objectName()]['title'].lower():
        #         child.setParent(None)
        #     else:
        #         self.lyt.addWidget(child)
        #
        # self.statusBar.showMessage('{}'.format(self.movieAreaContents.children()[:1]))

    def sort_option_changed(self):
        sort_option = self.sender().currentText()

        childs = self.movieAreaContents.children()[1:]
        child_dict = defaultdict(str)
        child_dict = {child.objectName(): child for child in childs}

        for c in childs:
            c.setParent(None)
        dat = self.movies.keys()

        if sort_option == 'Name A-Z':
            dat = sorted(self.data,
                         key=lambda x: self.data[x]['title'],
                         reverse=False)
        elif sort_option == 'Name Z-A':
            dat = sorted(self.data,
                         key=lambda x: self.data[x]['title'],
                         reverse=True)
        elif sort_option == 'Rating':
            dat = sorted(self.data,
                         key=lambda x: self.data[x]['Rating'],
                         reverse=True)
        elif sort_option == 'Year':
            dat = sorted(self.data,
                         key=lambda x: int(self.data[x]['Year']),
                         reverse=True)
        elif sort_option == 'Runtime':
            dat = sorted(self.data,
                         key=lambda x: int(self.data[x]['runtime_mins']),
                         reverse=False)

        for k, v in self.movies.items():
            if k not in dat:
                dat.append(k)

        for iid in dat:
            self.lyt.addWidget(child_dict[iid])

        self.repaint()

    def showInfoArea(self, id):
        self.CURRENT_MOVIE = id
        linkgetter = lambda lst: ''.join([
            '''<a style="text-decoration:none; color:black;" href="https://google.com/search?q={}">{}, </a> '''
            .format(urllib.parse.quote(item), item) for item in lst
        ])
        if id in self.data.keys():
            info = self.data[id]
            for k in [
                    'title', 'tagline', 'Year', 'Rating', 'Director',
                    'Duration', 'Genre', 'Budget', 'Box Office', 'cast', 'plot'
            ]:
                text = info[k]

                if type(text) == list:
                    text = linkgetter(text)
                    # print(text)

                self.contents.findChild(QLabel, k).setText(text)
            self.contents.findChild(QLabel, 'poster_value').setPixmap(
                QtGui.QPixmap(info['poster_value']))
            self.contents.findChild(QLabel, 'backdrop_value').setPixmap(
                QtGui.QPixmap(info['backdrop_value']))

            # Set the my_ratings
            # if 'my_rating' in self.data[self.CURRENT_MOVIE]:
            #     if self.data[self.CURRENT_MOVIE]['my_rating']:
            #         self.rating_value.setText('({:.1f}/5)'.format(self.data[self.CURRENT_MOVIE]['my_rating']))
            #         self.slider.setValue(int(self.data[self.CURRENT_MOVIE]['my_rating'] * 2))

    def play_torrent(self, imdb_id):
        threading.Thread(target=player.play, args=(imdb_id, )).start()

    def eventFilter(self, obj, event):
        if type(obj) is QtWidgets.QToolButton:
            if event.type() == QtCore.QEvent.MouseButtonDblClick:
                # print("Double Click")
                print('Playing: ', self.data[obj.objectName()]['title'])
                self.play_torrent(self.data[obj.objectName()]['imdb_id'])
                # os.startfile(self.movies[obj.objectName()])

            if event.type() == QtCore.QEvent.MouseButtonPress:
                if event.button() == QtCore.Qt.LeftButton:
                    # print(self.movie_name_json[obj.objectName()], "Left click")
                    # self.update_movie_info(movie_name=obj.objectName())
                    self.showInfoArea(obj.objectName())

                elif event.button() == QtCore.Qt.RightButton:
                    # print(obj.objectName(), "Right click", event.globalPos())
                    self.movieButtonContextMenu(obj.objectName())
                    # self.actionRight(obj)
                    # print(self.db.database[obj.objectName()]['location'])
                    # subprocess.Popen(r'explorer /select, ' + self.db.database[obj.objectName()]['location'])
        else:
            # For global keys
            if event.type() == QtCore.QEvent.KeyPress:
                key = event.key()

                # for a in self.movieAreaContents.children()[1:]:
                #     a.hide()
                #     if a.isChecked():
                #         print(self.movie_name_json[a.objectName()])

                if key == Qt.Key_Return:
                    print('Return Key pressed')

                    # print(obj.childern())
                elif key == Qt.Key_Delete:
                    print('Delete Key Pressed')

        return QtCore.QObject.event(obj, event)

    def movieButtonContextMenu(self, id):
        contextMenu = QMenu(self)
        open_location = contextMenu.addAction("Open Folder Location")
        search = contextMenu.addAction("Search in Google")
        delete = contextMenu.addAction("Delete")
        # print(self.mapToGlobal(point))
        action = contextMenu.exec_(QCursor.pos())
        if action == search:
            webbrowser.open('https://google.com/search?q=' +
                            urllib.parse.quote(self.data[id]['title']))
        elif action == open_location:
            subprocess.Popen(r'explorer /select, ' + self.movies[id])
        elif action == delete:
            pass

    def getMovieNamesList(self):
        movie = Movie()
        popular = movie.popular()
        #
        # lst = [(p.title, p.release_date[:4]) for p in popular]
        self.movies = {}
        for p in popular:
            # det = movie.details(p.id, append_to_response='append_to_response=videos')
            # print(p.id, p.title, p.release_date[:4], det.imdb_id)
            self.movies[str(p.id)] = p.title
            self.popular_movies.append(str(p.id))

        return self.movies
Exemple #8
0
class Maps(QWidget):

    def __init__(self, settings):
        # Settings
        self.settings = settings

        # Class Init
        self._active = False
        self.map_pairs = MapData(None).map_pairs

        # UI Init
        super(QWidget, self).__init__()
        self.setWindowTitle("Map")
        self.setWindowIcon(QIcon('ui/icon.png'))
        self.setWindowFlags(Qt.WindowStaysOnTopHint
                            | Qt.WindowCloseButtonHint
                            | Qt.FramelessWindowHint
                            | Qt.WindowMinMaxButtonsHint)
        self.setFocusPolicy(Qt.StrongFocus)
        if self.settings.get_value('maps', 'geometry') is not None:
            self.setGeometry(
                self.settings.get_value('maps', 'geometry')
            )
        else:
            self.setGeometry(100, 100, 400, 400)
        self.grid = QGridLayout()
        self.grid.setSpacing(0)
        self.grid.setContentsMargins(0, 0, 0, 0)
        self.map_canvas = MapCanvas()
        self.grid.addWidget(self.map_canvas, 1, 0, 1, 1)
        self.setLayout(self.grid)
        self.setAttribute(Qt.WA_ShowWithoutActivating)
        with open('maps/style/qss.css') as css_file:
            self.setStyleSheet(css_file.read().replace('\n', ''))
        # self.setWindowOpacity(0.85)

        # Menu
        self.menu_container = QWidget()
        self.menu_container.setObjectName('menu_container')
        self.menu = QHBoxLayout()
        self.menu_container.setLayout(self.menu)
        self.menu_container.hide()  # Start with menu hidden
        self.menu.setSpacing(5)
        self.menu.setContentsMargins(0, 0, 0, 0)

        # Map Buttons
        self.create_menu_buttons()

        # Add menu to window
        self.grid.addWidget(self.menu_container, 0, 0, 1, 1, Qt.AlignLeft)

        # Events
        self._filter = Filter(self)
        self.map_canvas.installEventFilter(self._filter)
        for child in self.menu_container.children():
            child.installEventFilter(self._filter)

        # Testing
        self.toggle()
        self.map_canvas.load_map('The Overthere')

    def create_menu_buttons(self):
        # Center on Player Button
        button_center_player = QPushButton(
            QIcon('maps/graphics/map_menu_center_player.png'),
            ''
        )
        button_center_player.setCheckable(True)  # Make toggle button
        button_center_player.setToolTip('Center on Player')
        button_center_player.setObjectName('button_center_player')
        # Center on Last Point Button
        button_center_point = QPushButton(
            QIcon('maps/graphics/map_menu_center_map.png'),
            ''
        )
        button_center_point.setCheckable(True)  # Make toggle button
        button_center_point.setToolTip('Center Normally')
        button_center_point.setObjectName('button_center_point')
        # Create Button Group for Exclusive Toggling
        toggle_group = QButtonGroup(self)
        toggle_group.addButton(button_center_player, 1)
        toggle_group.addButton(button_center_point, 2)
        toggle_group.buttonClicked.connect(self.center_button_toggled)
        self.menu.addWidget(button_center_player)
        self.menu.addWidget(button_center_point)

        # Apply settings for current toggle
        if self.settings.get_value('maps', 'center_on') == 'point':
            button_center_point.setChecked(True)
        else:
            button_center_player.setChecked(True)

        # Fit to Window Button
        button_fit_window = QPushButton(
            QIcon('maps/graphics/map_menu_fit_window.png'),
            ''
        )
        button_fit_window.setToolTip('Fit Map to Window')
        button_fit_window.clicked.connect(self.fit_to_window)
        self.menu.addWidget(button_fit_window, 0, Qt.AlignLeft)

        # Maps Combo Box
        self.combo_load_map = QComboBox(self)
        # Need to setView otherwise CSS doesn't work
        self.combo_load_map.setView(QListView())
        self.combo_load_map.setToolTip('Manually Load Selected Map')
        for map_name in sorted(self.map_pairs.keys(), key=str.lower):
            self.combo_load_map.addItem(map_name)
        self.combo_load_map.currentIndexChanged.connect(
            self.load_map_from_combo
        )
        self.menu.addWidget(self.combo_load_map, 0, Qt.AlignLeft)

    def load_map_from_combo(self, widget):
        self.map_canvas.load_map(
            self.combo_load_map.currentText().strip()
        )
        self.fit_to_window(False)

    def fit_to_window(self, button):
        # Can't use QGraphicsView().fitInView because of scaling issues.
        # So calculate scale and use the lesser numeric scale to fit window
        # Use 0.9 against width/height to create a 10% border around map
        x_scale = self.map_canvas.geometry().width() * 0.9 \
            / self.map_canvas.map_data.map_grid_geometry.width
        y_scale = self.map_canvas.geometry().height() * 0.9 \
            / self.map_canvas.map_data.map_grid_geometry.height
        if x_scale <= y_scale:
            self.map_canvas.set_scale(x_scale)
        else:
            self.map_canvas.set_scale(y_scale)
        # Center Map on middle of map
        self.map_canvas.centerOn(
            self.map_canvas.map_data.map_grid_geometry.center_x,
            self.map_canvas.map_data.map_grid_geometry.center_y
        )

    def center_button_toggled(self, button):
        if button.objectName() == 'button_center_point':
            self.settings.set_value('maps', 'center_on', 'point')
        else:
            self.settings.set_value('maps', 'center_on', 'player')
            if '__you__' in self.map_canvas.players.keys():
                player = self.map_canvas.players['__you__']
                self.map_canvas.centerOn(
                    player.x,
                    player.y
                )

    def closeEvent(self, event):
        event.ignore()
        self.settings.set_value('maps', 'geometry', self.geometry())
        self._active = False
        self.hide()

    def hide_menu(self):
        if not self.isActiveWindow():
            self.setWindowFlags(self.windowFlags()
                                | Qt.FramelessWindowHint)
            self.show()
            self.menu_container.hide()

    def show_menu(self):
        self.setWindowFlags(self.windowFlags() &
                            ~Qt.FramelessWindowHint)
        self.show()
        self.menu_container.show()

        self.activateWindow()

    def is_active(self):
        return self._active

    def toggle(self):
        if self.is_active():
            self._active = False
            self.hide()
        else:
            self._active = True
            self.show()

    def parse(self, item):
        if item[27:50] == "LOADING, PLEASE WAIT...":
            self.map_canvas.draw_loading_screen()
        if item[27:43] == 'You have entered':
            self.map_canvas.load_map(item[44:-2])
        if item[27:43] == 'Your Location is':
            try:
                self.map_canvas.add_player('__you__', item[:27], item[43:])
                self.map_canvas.update_players()
            except Exception as e:
                print(e)
Exemple #9
0
class ParameterizedQueryDialog(QDialog):
    def __init__(self, name, parameters=None, connections=None):
        QDialog.__init__(self)

        self.result = []

        self.setWindowTitle("Define query parameters")
        self.setWindowIcon(QIcon(":\plugins\GeODinQGIS\icons\transparent.png"))

        self.buttonBox = QDialogButtonBox(self)
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.NoButton
                                          | QDialogButtonBox.Ok)
        self.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self.ok)
        self.buttonBox.button(QDialogButtonBox.Cancel).clicked.connect(
            self.cancel)

        layout = QVBoxLayout(self)

        l1 = QLabel("Parameters in red are required entries.")
        l1.setStyleSheet('color: red')
        l2 = QLabel(
            "Parameters in blue are optional (empty entry fields are not evaluated in the query)."
        )
        l2.setStyleSheet('color: blue')

        self.w = QWidget()
        self.w.setAutoFillBackground(True)
        p = self.w.palette()
        p.setColor(self.w.backgroundRole(), QColor(255, 221, 161))
        self.w.setPalette(p)

        tableLayout = QGridLayout(self.w)
        j = 0
        for i, parameter in enumerate(parameters):
            label = QLabel(parameter[0])
            le1 = QLineEdit(parameter[1])
            le1.setFixedSize(50, 25)
            le2 = QLineEdit()
            le2.setFixedSize(250, 25)
            tableLayout.addWidget(QLabel(connections[i]), i + j, 0)
            tableLayout.addWidget(label, i + j + 1, 1)
            tableLayout.addWidget(le1, i + j + 1, 2)
            tableLayout.addWidget(le2, i + j + 1, 3)
            j += 1

        layout.addWidget(
            QLabel("Enter the required values of the query '" + name + "'"))
        layout.addWidget(QLabel(""))
        #layout.addWidget(l1)
        #layout.addWidget(l2)
        layout.addWidget(
            QLabel("This operators are available:  <  <=  =  >=  >  <>  like"))
        layout.addWidget(self.w)
        layout.addWidget(self.buttonBox)

        self.exec_()

    def ok(self):
        for i in range(1, len(self.w.children()), 4):
            if not self.w.children()[i + 3].text().isdigit():
                self.w.children()[i +
                                  3].setText("'" +
                                             self.w.children()[i + 3].text() +
                                             "'")
            self.result.append([
                self.w.children()[i + 1].text(),
                self.w.children()[i + 2].text(),
                self.w.children()[i + 3].text()
            ])
        self.accept()

    def cancel(self):
        self.close()
Exemple #10
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()
Exemple #11
0
class Visual(QMainWindow):
    def __init__(self, render_frequency: float, window_zoom: int = 0.7):
        super().__init__()
        self._screen_size = QApplication.primaryScreen().size()
        self._central_widget = QWidget(self)
        self._central_widget.setAttribute(Qt.WA_AcceptTouchEvents
                                          | Qt.WA_TranslucentBackground)
        self._central_widget.setWindowFlags(Qt.NoDropShadowWindowHint)
        self._central_widget.resize(self._screen_size)
        self._vtk_widget = QVTKRenderWindowInteractor(self._central_widget)
        self._vtk_widget.SetInteractorStyle(
            vtk.vtkInteractorStyleMultiTouchCamera())
        self._vtk_widget.resize(self._screen_size)
        self.setCentralWidget(self._central_widget)
        sw, sh = self._screen_size.width(), self._screen_size.height()
        self.resize(sw * window_zoom, sh * window_zoom)
        self.move(sw * (1 - window_zoom) / 2, sh * (1 - window_zoom) / 2)
        self._central_widget.setFocus()
        # UI
        # self._ui = Ui_Form()
        # self._ui.setupUi(Form=self._central_widget)
        for widget in self._central_widget.children():
            widget.setStyleSheet(f"""
                    QGroupBox {{
                    background-color: rgba(200, 200, 200, 1); 
                    border-radius: 5; 
                    }}""")
        # QT_STYLE
        self.setWindowFlags(Qt.NoDropShadowWindowHint)
        self._render = vtk.vtkRenderer()
        self._ren_win = self._vtk_widget.GetRenderWindow()
        self._ren_win.AddRenderer(self._render)
        self._interactor = self._ren_win.GetInteractor()
        # TIMER
        self._timer = QTimer()
        self._timer.setInterval(int(1000 / render_frequency))
        self._timer.timeout.connect(self._working)
        self._is_running = False
        self.set_render_ena(False)

    def _working(self):
        if self._is_running:
            self._interactor.Render()

    def set_render_ena(self, ena: bool):
        if ena != self._is_running:
            self._is_running = bool(ena)
            if ena:
                self._timer.start()
            else:
                self._timer.stop()

    def add_actor(self, actor: Union[vtk.vtkProp3D, vtk.vtkOpenGLTextActor,
                                     vtk.vtkAxesActor, vtk.vtkScalarBarActor,
                                     vtk.vtkOpenGLActor, list]):
        if actor.__class__ in [
                vtk.vtkProp3D, vtk.vtkOpenGLTextActor, vtk.vtkAxesActor,
                vtk.vtkAssembly, vtk.vtkOpenGLActor
        ]:
            self._render.AddActor(actor)
        elif actor.__class__ in [vtk.vtkScalarBarActor]:
            self._render.AddActor2D(actor)
        elif actor.__class__ == list:
            for this_actor in actor:
                self._render.AddActor(this_actor)

    def del_actor(self, actor: vtk.vtkProp3D):
        self._render.RemoveActor(actor)

    def render_once(self):
        self._interactor.Render()

    def get_ui_form(self) -> Ui_Form:
        return self._ui

    def show(self):
        self._vtk_widget.GetRenderWindow().GetInteractor().Initialize()
        self._vtk_widget.GetRenderWindow().GetInteractor().Start()
        super().show()

    def exit(self):
        self._interactor.DestroyTimer()
        self._timer.stop()
        self.close()
Exemple #12
0
class ChatBoxTemplate(QWidget):
    def __init__(self, servcon, chat_heading):
        super().__init__()
        PATH_ONE = r"./production/view/chat_box_template.ui"
        PATH_TWO = r""
        try:
            file = check_for_file(PATH_ONE, PATH_TWO)
            uic.loadUi(file, self)
        except Exception as e:
            print(e)

        self.servcon = servcon

        self.chat_heading.setText(chat_heading)
        self.send.clicked.connect(self.send_message)
        # self.bt.clicked.connect(self.recieve_message)
        self.fbor = QWidget()
        self.vbox = QVBoxLayout()
        self.fbor.setLayout(self.vbox)
        self.vbox.addStretch()
        self.chat_message_list.setWidget(self.fbor)

    def resizeEvent(self, event):
        km = iter(self.fbor.children())
        next(km)
        for i in km:
            if isinstance(i, MessageTextTemplate):
                wid = self.set_message_size(i)
                # i.self_evaluate()
            elif isinstance(i, MessageTextRecieveTemplate):
                wid = self.set_message_receive_size(i)
        super().resizeEvent(event)

    def set_message_size(self, msg_widget):
        horizontal_spacer = msg_widget.children()[0].itemAt(0)
        msg_text = msg_widget.message_text
        msg_widget_width = msg_text.fontMetrics().boundingRect(msg_text.text()).width()
        left_bound = self.width() * 0.5

        if msg_widget_width < left_bound:
            msg_text.setWordWrap(False)
            horizontal_spacer.changeSize(
                200, 20, QSizePolicy.MinimumExpanding, QSizePolicy.Minimum
            )
        else:
            msg_text.setWordWrap(True)
            horizontal_spacer.changeSize(
                200, 20, QSizePolicy.Fixed, QSizePolicy.Minimum
            )
            if msg_widget.message_text.width() >= msg_widget_width:
                msg_text.setWordWrap(False)
                horizontal_spacer.changeSize(
                    200, 20, QSizePolicy.MinimumExpanding, QSizePolicy.Minimum
                )

        if msg_widget.width() > self.width():
            msg_text.setWordWrap(True)
            horizontal_spacer.changeSize(
                200, 20, QSizePolicy.Fixed, QSizePolicy.Minimum
            )
        horizontal_spacer.invalidate()
        msg_text.updateGeometry()

    def set_message_receive_size(self, msg_widget):
        horizontal_spacer = msg_widget.children()[0].itemAt(1)
        msg_text = msg_widget.message_text
        msg_widget_width = msg_text.fontMetrics().boundingRect(msg_text.text()).width()
        left_bound = self.width() * 0.5

        if msg_widget_width < left_bound:
            msg_text.setWordWrap(False)
            horizontal_spacer.changeSize(
                200, 20, QSizePolicy.MinimumExpanding, QSizePolicy.Minimum
            )
        else:
            msg_text.setWordWrap(True)
            horizontal_spacer.changeSize(
                200, 20, QSizePolicy.Fixed, QSizePolicy.Minimum
            )
            if msg_widget.message_text.width() >= msg_widget_width:
                msg_text.setWordWrap(False)
                horizontal_spacer.changeSize(
                    200, 20, QSizePolicy.MinimumExpanding, QSizePolicy.Minimum
                )

        if msg_widget.width() > self.width():
            msg_text.setWordWrap(True)
            horizontal_spacer.changeSize(
                200, 20, QSizePolicy.Fixed, QSizePolicy.Minimum
            )
        horizontal_spacer.invalidate()
        msg_text.updateGeometry()

    def send_message(self):
        msg_text = self.input_field.text()
        self.load_send_message(msg_text)
        self.servcon.send_some(msg_text, self.chat_heading.text())

    def load_send_message(self, msg_text):
        m = MessageTextTemplate()
        m.message_text.setText(msg_text)

        self.set_message_size(m)

        self.vbox.addWidget(m)
        self.scroll_to_last()

    def scroll_to_last(self):

        scroll_bar = self.chat_message_list.verticalScrollBar()

        scroll_bar.setMaximum(self.fbor.height())
        scroll_bar.setValue(self.fbor.height())

    def load_recieve_message(self, msg_text):
        m = MessageTextRecieveTemplate()
        m.message_text.setText(msg_text)

        self.set_message_receive_size(m)
        self.vbox.addWidget(m)
        self.scroll_to_last()
Exemple #13
0
class ClientWindow(QMainWindow):
    """
    This is the game's main window. It abstracts the single elements of the window into single
    methods one can call and use.
    """

    return_pressed = pyqtSignal()

    def __init__(self):
        QMainWindow.__init__(self)

        self.command_stack = []

        self.setObjectName("client_window")
        self.setWindowModality(Qt.NonModal)
        self.resize(800, 600)
        self.setDocumentMode(False)
        self.raw_title = Core.get_res_man().get_string("core.windowTitle")
        self.setWindowTitle(self.raw_title)

        central_widget = QWidget(self)
        central_widget.setObjectName("central_widget")
        self.setCentralWidget(central_widget)

        vertical_layout = QVBoxLayout(central_widget)
        vertical_layout.setObjectName("vertical_layout")
        central_widget.setLayout(vertical_layout)

        self.text_area = QTextEdit(central_widget)
        self.text_area.setReadOnly(True)
        self.text_area.setObjectName("text_area")
        vertical_layout.addWidget(self.text_area)

        self.command_row = QWidget(central_widget)
        self.command_row.setObjectName("command_row")
        vertical_layout.addWidget(self.command_row)

        command_row_layout = QHBoxLayout(self.command_row)
        command_row_layout.setObjectName("command_row_layout")
        command_row_layout.setContentsMargins(0, 0, 0, 0)
        command_row_layout.setSpacing(0)
        self.command_row.setLayout(command_row_layout)

        self.add_command_line()

        menu_bar = QMenuBar(self)
        menu_bar.setObjectName("menubar")
        self.setMenuBar(menu_bar)

    def get_raw_title(self):
        """
        This constant method returns our raw window title.
        """
        return self.raw_title

    def get_command_stack(self):
        """
        This constant method returns a stack with all commands we ran.
        """
        return self.command_stack

    def stack_command(self, command_text):
        """
        This non-constant method puts another command on our command stack.
        """
        self.command_stack.append(command_text)

    def get_text_area(self):
        """
        This constant method returns our text area widget.
        """
        return self.text_area

    def get_command_text(self, show_command=False, clear_prompt=False):
        """
        This non-constant method Returns the text of the command prompt widget. If show_command is
        True, it will also show the entered text in the text area and if clear_prompt is True, it
        will also add the command to our command stack and clear the prompt.
        """
        if self.command_line is not None:
            text = self.command_line.text()
            if show_command and len(text) > 0:
                self.show_command(text)
            if clear_prompt:
                self.stack_command(text)
                self.command_line.clear()
            return text
        else:
            return str()

    def scroll_text_area_down(self):
        """
        This non-constant method scrolls our text area down until the end of our text is visible.
        """
        self.text_area.ensureCursorVisible()

    def show_text(self, text, emplace_res_strings=True, add_html_tags=True):
        """
        Thi non-constant method prints the given text in the text area as it's own paragraph.
        If emplace_res_strings is True (default), it will also decode resource string keys in
        it and if add_html_tags is True (default), it will add tags to the text that indicate that
        it should be handled as an HTML snippet.
        """
        self.text_area.setTextColor(QColor(0, 0, 0))
        if emplace_res_strings:
            text = Core.get_res_man().decode_string(text)
        if add_html_tags:
            text = '<html><body>' + text + '</body></html>'
        self.text_area.append(text)
        self.text_area.show()
        self.scroll_text_area_down()

    def show_command(self, text):
        """
        This non-constant method shows the given text to the user, but displays it in a grey color
        and adds a "> " to show that the given text is a command or something else the user said or
        did.
        """
        self.text_area.setTextColor(QColor(125, 125, 125))
        self.text_area.append("> " + text)

    def clear_command_row(self):
        """
        This non-constant method removes all widgets from our command row.
        """
        while self.command_row.layout().count() > 0:
            self.command_row.layout().takeAt(0).widget().setParent(None)
        self.scroll_text_area_down()

    def add_command_line(self):
        """
        This non-constant method adds a command line to our command row.
        """
        self.command_line = CommandLine(self.command_row)
        child_number = len(self.command_row.children())
        self.command_line.setObjectName("command_line_" + str(child_number))
        self.command_row.layout().addWidget(self.command_line)
        self.command_line.returnPressed.connect(self.return_pressed)
        self.command_line.setFocus(Qt.ActiveWindowFocusReason)
        self.command_line.show()
        self.scroll_text_area_down()

    def add_option_button(self, text):
        """
        This non-constant method adds an option button with the given text to the command row and
        returns it. The text may contain unresolved resource string keys as they will be resolved
        inside this method.
        """
        text = Core.get_res_man().decode_string(text)
        button = QPushButton(text, self.command_row)
        child_number = len(self.command_row.children())
        button.setObjectName("option_button_" + str(child_number))
        self.command_row.layout().addWidget(button)
        self.scroll_text_area_down()
        return button

    def closeEvent(self, event):
        """
        This overriden non-constant method gets called when the window is closed and saves the game.
        """
        QCoreApplication.instance().save_world()
        event.accept()