예제 #1
0
 def to_model(self) -> QStandardItemModel:
     root = QStandardItemModel()
     root.invisibleRootItem()
     for package in self.packages:
         item = package.to_model()
         root.appendRow(item)
     return root
예제 #2
0
class NestedDictView(QTreeView):
    def __init__(self):
        super().__init__()

        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(['Key', 'Value'])

        self.header().setSectionResizeMode(3) # QHeaderView::ResizeMode = ResizeToContents
        self.setModel(self.model)

        self.table = NestedDict()

    def on_edit(self, callback):
        self.model.itemChanged.connect(callback)

    def clear(self, parent=None):
        parent = parent or self.model.invisibleRootItem()
        parent.removeRows(0, parent.rowCount())

    def set(self, data, parent=None, parent_node=None):
        self.clear(parent)
        parent = parent or self.model.invisibleRootItem()
        parent_node = parent_node or self.table

        for k, v in sorted(data.items()):
            if type(v) is NestedDict:
                parent.appendRow([QStandardItem(k), QStandardItem('')])
                entry = parent.child(parent.rowCount() - 1)
                parent_node[k] = NestedDict()
                self.set(v, parent=entry, parent_node=parent_node[k])
            else:
                parent.appendRow([QStandardItem(k), QStandardItem(str(v))])
                parent_node[k] = parent

        self.expand(parent.index())
예제 #3
0
    def model_from_file(self, file_name):
        # file = QFile(file_name)
        # if not file.open(QFile.ReadOnly):
        #     return QStringListModel(self._completer)
        QApplication.instance().setOverrideCursor(QCursor(Qt.WaitCursor))
        model = QStandardItemModel(self._completer)
        parents = [model.invisibleRootItem()]

        with open(file_name) as file:
            pat = re.compile("^\\s+")
            for line in file:
                if not line:
                    continue
                trimmed_line = line.strip()
                if not trimmed_line:
                    continue
                match = pat.match(line)
                if not match:
                    level = 0
                else:
                    length = match.end() - match.start()
                    if line.startswith("\t"):
                        level = length
                    else:
                        level = length // 4

                while len(parents) < level + 2:
                    parents.append(None)

                item = QStandardItem()
                item.setText(trimmed_line)
                parents[level].appendRow(item)
                parents[level + 1] = item
        QApplication.instance().restoreOverrideCursor()
        return model
예제 #4
0
    def __init__(self, parent=None):
        super(UniverseTreeView, self).__init__(parent)

        model = QStandardItemModel()
        self.setModel(model)

        root_item = model.invisibleRootItem()

        self.areas_item = QStandardItem("Areas")
        self.areas_item.setData(Areas, Qt.UserRole)
        self.areas_item.setEditable(False)
        root_item.appendRow(self.areas_item)

        Areas.added.connect(self.init_areas)
        Areas.removed.connect(self.init_areas)
        Areas.reset.connect(self.init_areas)


        self.characters_item = QStandardItem("Characters")
        self.characters_item.setData(Characters, Qt.UserRole)
        self.characters_item.setEditable(False)
        root_item.appendRow(self.characters_item)

        Characters.added.connect(self.init_characters)
        Characters.removed.connect(self.init_characters)
        Characters.reset.connect(self.init_characters)


        self.races_item = QStandardItem("Races")
        self.races_item.setEditable(False)
        self.races_item.setData(Races, Qt.UserRole)
        root_item.appendRow(self.races_item)

        Races.added.connect(self.init_races)
        Races.removed.connect(self.init_races)
        Races.reset.connect(self.init_races)


        self.item_prototypes_item = QStandardItem("Item Prototypes")
        self.item_prototypes_item.setData(ItemPrototypes, Qt.UserRole)
        self.item_prototypes_item.setEditable(False)
        root_item.appendRow(self.item_prototypes_item)

        ItemPrototypes.added.connect(self.init_item_prototypes)
        ItemPrototypes.removed.connect(self.init_item_prototypes)
        ItemPrototypes.reset.connect(self.init_item_prototypes)


        self.groups_item = QStandardItem("Groups")
        self.groups_item.setData(Groups, Qt.UserRole)
        self.groups_item.setEditable(False)
        root_item.appendRow(self.groups_item)

        Groups.added.connect(self.init_groups)
        Groups.removed.connect(self.init_groups)
        Groups.reset.connect(self.init_groups)

        self.init_all()

        self.activated.connect(self.item_activated)
예제 #5
0
    def onFileDropped(self, filename):
        filename = parse.unquote(filename)
        if filename.startswith('file:/'):
            filename = filename[6:]
        print(filename)
        if os.path.isfile(filename) is not True:
            return

        tree = ET.parse(filename)
        root = tree.getroot()
        self.currentDict = XmlDictConfig(root)
        '''
        QList<QStandardItem *> preparedRow =prepareRow("first", "second", "third");
        QStandardItem *item = standardModel->invisibleRootItem();
        // adding a row to the invisible root item produces a root element
        item->appendRow(preparedRow);

        QList<QStandardItem *> secondRow =prepareRow("111", "222", "333");
        // adding a row to an item starts a subtree
        preparedRow.first()->appendRow(secondRow);

        treeView->setModel(standardModel);
        treeView->expandAll();
        '''
        standardModel = QStandardItemModel()
        preparedRow = (QStandardItem("Title"), QStandardItem("Description"))
        item = standardModel.invisibleRootItem()
        item.appendRow(preparedRow)
        self.addDictTree(self.currentDict, item)
        self.contents.setModel(standardModel)
        self.contents.expandAll()

        print("dict reading finished")
예제 #6
0
 def add1(self):
     text, ok = QInputDialog.getText(self, "菜单添加", "请输入:父目录节点-添加菜单名称")
     if ok:
         print(text)
     else:
         return
     global list_1, list1tp
     ss = text.split('-')
     try:
         list_1[ss[0]].append(ss[1])
         list_1[ss[1]] = []
     except:
         reply = QMessageBox.warning(self, '警告', '父节点不存在', QMessageBox.Yes)
     print(id2string)
     for key, value in id2string.items():
         if value == ss[0]:
             fakey = key
             break
     mxid = 1
     for key in id2string.keys():
         if key != fakey and key.startswith(fakey):
             mxid = max(mxid, int(key[len(fakey) + 1]))
     print(fakey + '.' + str(mxid + 1) + '-' + ss[1])
     list1tp.append(fakey + '.' + str(mxid + 1) + '-' + ss[1])
     self.treeView.setHeaderHidden(True)
     treeModel = QStandardItemModel()
     rootNode = treeModel.invisibleRootItem()
     self.get_menu(rootNode, 'root')
     self.treeView.setModel(treeModel)
     self.treeView.expandAll()
     self.write_menu()
예제 #7
0
    def _from_xml(self, keywords):

        model = QStandardItemModel()
        model.setHorizontalHeaderLabels(['Thesaurus', 'Keyword'])

        rootNode = model.invisibleRootItem()

        if keywords.xpath('place'):
            self.ui.rbtn_yes.setChecked(True)
        else:
            self.ui.rbtn_yes.setChecked(False)

        for place in keywords.xpath('place'):
            thesaurus_name = place.xpath('placekt')[0].text
            branch = QStandardItem(thesaurus_name)
            branch.setFont(QFont('Arial', 9))

            for kw in place.xpath('placekey'):
                childnode = QStandardItem(kw.text)
                childnode.setFont(QFont('Arial', 10))
                branch.appendRow([None, childnode])

            rootNode.appendRow([branch, None])

        self.ui.place.setModel(model)
        # self.ui.place.setColumnWidth(250, 150)
        self.ui.place.expandAll()
예제 #8
0
    def load_iso(self):
        self.ui.label_search_term.hide()
        self.ui.search_term.hide()
        self.ui.button_search.hide()
        self.ui.label_search_results.text = "ISO 19115 Topic Categories"

        self.populate_thesauri_lookup()

        iso_url = "https://www2.usgs.gov/science/term.php?thcode=15&text=ISO 19115 Topic Category"
        results = utils.requests_pem_get(iso_url).json()

        thesaurus_name = "ISO 19115 Topic Category"
        branch = QStandardItem(thesaurus_name)
        branch.setFont(QFont('Arial', 11))
        for item in results['nt']:
            childnode = QStandardItem(item['name'])
            childnode.setFont(QFont('Arial', 9))
            branch.appendRow([childnode])

        model = QStandardItemModel(0, 0)

        rootNode = model.invisibleRootItem()
        rootNode.appendRow(branch)

        self.ui.treeview_results.setModel(model)
        self.ui.treeview_results.expandAll()
예제 #9
0
    def __update_tree_modules(self, current):
        modules = current['modules'] if 'modules' in current else {}
        model = QStandardItemModel()
        parent_item = model.invisibleRootItem()  # type: QStandardItem

        for m in sorted(modules):
            text_item = QStandardItem(m)
            text_item.setEditable(False)
            text_item.setCheckState(
                Qt.Checked if json.loads(modules[m].lower()) else Qt.Unchecked)

            # NOTE: some modules name their parameters differently than themselves
            if json.loads(modules[m].lower()) and m in current:
                for i in sorted(current[m]):
                    item = QStandardItem(i + " = " + current[m][i])
                    item.setEditable(False)
                    font = QFont()
                    font.setItalic(True)
                    item.setFont(font)
                    text_item.appendRow(item)

            parent_item.appendRow(text_item)

        model.setHeaderData(0, Qt.Horizontal, "Modules")
        self.ui.modules.setModel(model)
예제 #10
0
class CatalogueManager:
    """
        单例化,管理目录结构
    """

    def __init__(self):
        self._root_abs_path = GlobalVarManager.root_abs_path
        self._lattice_edt = GlobalVarManager.lattice_edt
        self._file_mgr = FileManager()
        # 用于充当ListView数据源
        self._cat_list_model = QStandardItemModel()
        # 初始化目录
        self.init_catalogue()

    def init_catalogue(self):
        """从图数据库中读取路径用于填充"""
        self._cat_list_model.clear()
        self._cat_list_model.setHorizontalHeaderLabels(['节点名', '路径', '备注'])
        root_item: QStandardItem = self._cat_list_model.invisibleRootItem()
        parent_item = QStandardItem(QIcon(self._root_abs_path + "\\resources\\go-home.png"), "root")
        root_item.appendRow(parent_item)
        for path in self._lattice_edt.tree_model.get_root2leaf_path():
            print(path)
            depth = 1
            self._add_path(path, depth, parent_item, "root", len(path))

    def _add_path(self, path: List[str], depth: int, parent_item: QStandardItem, path_str: str, path_len: int):
        is_file = False
        if depth == path_len:
            return
        if depth == path_len - 1:
            # 为文件
            is_file = True
        node_name_list = path[depth]
        for node_name in node_name_list:
            # 检查节点名在是否重复
            index = 0
            child_item = parent_item.child(index)
            while child_item:
                child_name = child_item.index().data()
                if child_name == node_name:
                    node_item = child_item
                    break
                index += 1
                child_item = parent_item.child(index)
            else:
                note_str = "文件" if is_file else "文件夹"
                icon = QIcon(self._root_abs_path + "\\resources\\folder.png") if not is_file else IconExtractor(
                    self._file_mgr.get_abs_path(node_name)).get_icon()
                node_item = QStandardItem(icon, node_name)
                path_str += "\\" + node_name
                path_item = QStandardItem(path_str)
                note_item = QStandardItem(note_str)
                parent_item.appendRow([node_item, path_item, note_item])
            self._add_path(path, depth + 1, node_item, path_str, path_len)

    @property
    def cat_list_model(self):
        return self._cat_list_model
예제 #11
0
 def _setupModel(self):
     """
     definimos el modelo.  
     """
     newModel = QStandardItemModel()
     newModel.setColumnCount(5)
     self.hiddenRoot = newModel.invisibleRootItem()
     self.baseModel = newModel  #proxyModel
예제 #12
0
    def search_thesaurus(self):

        if not self.populate_thesauri_lookup():
            return False

        term = self.ui.search_term.text()

        search_url = "https://www2.usgs.gov/science/term-search.php?thcode=any&term={}".format(
            term
        )

        results = self.get_result(search_url)
        if results is None:
            return False

        if not results:
            msg = "The Metadata Wizard was unable to locate the provided search term in the controlled vocabulary search"
            msg += "\n\n'{}' Not Found".format(self.ui.search_term.text())
            QMessageBox.information(self, "Search Term Not Found", msg, QMessageBox.Ok)
            return False

        self.branch_lookup = {}
        unique_children = []
        for item in results:
            thesaurus_name = self.thesauri_lookup[item["thcode"]]
            if (
                item["thcode"] != "1"
                and not self.place
                or item["thcode"] == "1"
                and self.place
            ):
                branch = self.branch_lookup.get(
                    thesaurus_name, QStandardItem(thesaurus_name)
                )
                branch.setFont(QFont("Arial", 11))
                if item["label"] != item["value"]:
                    childnode = QStandardItem(
                        "{} (use: {})".format(item["label"], item["value"])
                    )
                else:
                    childnode = QStandardItem(item["label"])

                childnode.setFont(QFont("Arial", 9))
                if (thesaurus_name, item["value"]) not in unique_children:
                    branch.appendRow([childnode, None])
                    unique_children.append((thesaurus_name, item["value"]))

                self.branch_lookup[thesaurus_name] = branch

        model = QStandardItemModel(0, 0)

        rootNode = model.invisibleRootItem()

        for thesaurus_node in self.branch_lookup.items():
            rootNode.appendRow(thesaurus_node[1])

        self.ui.treeview_results.setModel(model)
        self.ui.treeview_results.expandAll()
예제 #13
0
    def search_thesaurus(self):

        self.populate_thesauri_lookup()

        search_url = "https://www2.usgs.gov/science/term-search.php?thcode=any&term={}".format(
            self.ui.search_term.text())
        results = requests.get(search_url).json()

        if not results:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Information)
            msg.setText("'{}' Not Found".format(self.ui.search_term.text()))
            msg.setInformativeText(
                "The Metadata Wizard was unable to locate the provided search term in the controlled vocabulary search"
            )
            msg.setWindowTitle("Keyword Not Found")
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec_()

        branch_lookup = {}
        unique_children = []
        for item in results:
            thesaurus_name = self.thesauri_lookup[item['thcode']]
            if item['thcode'] != '1' and not self.place or \
               item['thcode'] == '1' and self.place:
                branch = branch_lookup.get(thesaurus_name,
                                           QStandardItem(thesaurus_name))
                branch.setFont(QFont('Arial', 11))
                childnode = QStandardItem(item['value'])
                childnode.setFont(QFont('Arial', 9))
                if (thesaurus_name, item['value']) not in unique_children:
                    branch.appendRow([childnode])
                    unique_children.append((thesaurus_name, item['value']))

                branch_lookup[thesaurus_name] = branch

        model = QStandardItemModel(0, 0)
        # model.setHorizontalHeaderLabels(['Theme Keywords (thesaurus/keywords)'])

        rootNode = model.invisibleRootItem()
        # branch1 = QStandardItem("Branch 1")
        # branch1.appendRow([QStandardItem("Child A")])
        # childnode = QStandardItem("Child B")
        # branch1.appendRow([childnode])
        #
        # branch2 = QStandardItem("Branch 2")
        # branch2.appendRow([QStandardItem("Child C")])
        # branch2.appendRow([QStandardItem("Child D")])

        for thesaurus_node in branch_lookup.items():
            rootNode.appendRow(thesaurus_node[1])
        # rootNode.appendRow([ branch1])
        # rootNode.appendRow([ branch2])

        self.ui.treeview_results.setModel(model)
        # self.ui.treeview_results.setColumnWidth(0, 150)
        self.ui.treeview_results.expandAll()
예제 #14
0
파일: project.py 프로젝트: mfkiwl/DGP
    def generate_model(self) -> Tuple[QStandardItemModel, QModelIndex]:
        """Generate a Qt Model based on the project structure."""
        model = QStandardItemModel()
        root = model.invisibleRootItem()

        # TODO: Add these icon resources to library or something so they are not loaded every time
        dgs_ico = QIcon('ui/assets/DGSIcon.xpm')
        flt_ico = QIcon('ui/assets/flight_icon.png')

        prj_header = QStandardItem(
            dgs_ico, "{name}: {path}".format(name=self.name,
                                             path=self.projectdir))
        prj_header.setEditable(False)
        fli_header = QStandardItem(flt_ico, "Flights")
        fli_header.setEditable(False)
        # TODO: Add a human readable identifier to flights
        first_flight = None
        for uid, flight in self.flights.items():
            fli_item = QStandardItem(flt_ico, "Flight: {}".format(flight.name))
            if first_flight is None:
                first_flight = fli_item
            fli_item.setToolTip("UUID: {}".format(uid))
            fli_item.setEditable(False)
            fli_item.setData(flight, QtCore.Qt.UserRole)

            gps_path, gps_uid = flight.gps_file
            gps = QStandardItem("GPS: {}".format(gps_uid))
            gps.setToolTip("File Path: {}".format(gps_path))
            gps.setEditable(False)
            gps.setData(gps_uid)  # For future use

            grav_path, grav_uid = flight.gravity_file
            if grav_path is not None:
                _, grav_fname = os.path.split(grav_path)
            else:
                grav_fname = '<None>'
            grav = QStandardItem("Gravity: {}".format(grav_fname))
            grav.setToolTip("File Path: {}".format(grav_path))
            grav.setEditable(False)
            grav.setData(grav_uid)  # For future use

            fli_item.appendRow(gps)
            fli_item.appendRow(grav)

            for line in flight:
                line_item = QStandardItem("Line {}:{}".format(
                    line.start, line.end))
                line_item.setEditable(False)
                fli_item.appendRow(line_item)
            fli_header.appendRow(fli_item)
        prj_header.appendRow(fli_header)

        root.appendRow(prj_header)
        self.log.debug("Tree Model generated")
        first_index = model.indexFromItem(first_flight)
        return model, first_index
예제 #15
0
 def delete1(self):
     text = self.treeView.selectedIndexes()[0].data()
     print(text)
     self.delet_menu('root', text)
     self.treeView.setHeaderHidden(True)
     treeModel = QStandardItemModel()
     rootNode = treeModel.invisibleRootItem()
     self.get_menu(rootNode, 'root')
     self.treeView.setModel(treeModel)
     self.treeView.expandAll()
     self.write_menu()
 def update_commands(self,meas_prog_list_byname):
     global Regexprogramfile
     Regexprogramfile="("+"|".join(meas_prog_list_byname)+")"
     self.valid_list_of_commands = self.get_list_of_commands()
     #initiate syntax highlighting for the macro editor
     self.highlighter = MacroHighlighter(self.ui.macro_textbox.document(),self.valid_list_of_commands)
     #update the list of available macro commands in the user interface
     model=QStandardItemModel()
     parentItem = model.invisibleRootItem()
     for command in self.valid_list_of_commands:
         parentItem.appendRow(QStandardItem(command.label))
     self.ui.macrocommandtree.setModel(model)
예제 #17
0
    def build_ui(self):
        self.ui = self.ui_class()
        self.ui.setupUi(self)

        # self.setup_dragdrop(self)

        model = QStandardItemModel()
        model.setHorizontalHeaderLabels(['Thesaurus', 'Keyword'])
        rootNode = model.invisibleRootItem()

        self.ui.theme.setModel(model)
        self.ui.theme.setColumnWidth(0, 250)
        self.ui.theme.expandAll()
예제 #18
0
    def setup(self, iface):
        self.iface = iface

        LAYER_GROUP_ITEMS = ((q3dconst.TYPE_DEM, "DEM"), (q3dconst.TYPE_POINT,
                                                          "Point"),
                             (q3dconst.TYPE_LINESTRING,
                              "Line"), (q3dconst.TYPE_POLYGON, "Polygon"))

        model = QStandardItemModel(0, 1)
        self.layerParentItem = {}
        for geomType, name in LAYER_GROUP_ITEMS:
            item = QStandardItem(name)
            item.setIcon(self.icons[geomType])
            item.setEditable(False)

            self.layerParentItem[geomType] = item
            model.invisibleRootItem().appendRow([item])

        self.setModel(model)
        self.expandAll()

        self.model().itemChanged.connect(self.treeItemChanged)
예제 #19
0
class CommentTree(QTreeView):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setUniformRowHeights(False)
        self.setAnimated(True)
        self.model = QStandardItemModel()
        self.filter = CommentModel()
        self.filter.setSourceModel(self.model)
        self.setModel(self.filter)
        self.filter.setDynamicSortFilter(False)
        self.rootItem = self.model.invisibleRootItem()
        self.setWordWrap(True)
        self.setItemDelegate(ItemWordWrap())
예제 #20
0
    def __init__(self, parent=None):
        super(UniverseTreeView, self).__init__(parent)

        model = QStandardItemModel()
        self.setModel(model)

        root_item = model.invisibleRootItem()
        self.characters_item = QStandardItem("Characters")
        self.characters_item.setEditable(False)

        self.races_item = QStandardItem("Races")
        self.races_item.setEditable(False)

        self.skills_item = QStandardItem("Skills")
        self.skills_item.setEditable(False)

        self.personalities_item = QStandardItem("Personalities")
        self.personalities_item.setEditable(False)

        self.backgrounds_item = QStandardItem("Backgrounds")
        self.backgrounds_item.setEditable(False)

        root_item.appendRow(self.characters_item)
        root_item.appendRow(self.races_item)
        root_item.appendRow(self.skills_item)
        root_item.appendRow(self.personalities_item)
        root_item.appendRow(self.backgrounds_item)
        
        self.init_all()

        GlobalData.character_added.connect(self.init_characters)
        GlobalData.character_removed.connect(self.init_characters)
        GlobalData.characters_reset.connect(self.init_characters)

        GlobalData.race_added.connect(self.init_races)
        GlobalData.race_removed.connect(self.init_races)
        GlobalData.races_reset.connect(self.init_races)

        GlobalData.skill_added.connect(self.init_skills)
        GlobalData.skill_removed.connect(self.init_skills)
        GlobalData.skills_reset.connect(self.init_skills)

        GlobalData.personality_added.connect(self.init_personalities)
        GlobalData.personality_removed.connect(self.init_personalities)
        GlobalData.personalities_reset.connect(self.init_personalities)

        GlobalData.background_added.connect(self.init_backgrounds)
        GlobalData.background_removed.connect(self.init_backgrounds)
        GlobalData.backgrounds_reset.connect(self.init_backgrounds)
        
        self.activated.connect(self.item_activated)
예제 #21
0
    def setup(self, iface):
        self.iface = iface

        TREE_TOP_ITEMS = ("Scene", "Lights & Shadow", "Layers")  # tr
        LAYER_GROUP_ITEMS = ((q3dconst.TYPE_DEM, "DEM"), (q3dconst.TYPE_POINT,
                                                          "Point"),
                             (q3dconst.TYPE_LINESTRING,
                              "Line"), (q3dconst.TYPE_POLYGON, "Polygon"))

        model = QStandardItemModel(0, 2)
        self.treeItems = []
        for name in TREE_TOP_ITEMS:
            item = QStandardItem(name)
            item.setIcon(QgsApplication.getThemeIcon("/propertyicons/CRS.svg"))
            #item.setData(itemId)
            item.setEditable(False)
            self.treeItems.append(item)
            model.invisibleRootItem().appendRow([item])

        itemLayers = self.treeItems[2]  # Layers
        self.layerParentItem = {}
        for geomType, name in LAYER_GROUP_ITEMS:
            item = QStandardItem(name)
            item.setIcon(self.icons[geomType])
            #item.setData(itemId)
            item.setEditable(False)
            itemLayers.appendRow([item])
            self.layerParentItem[geomType] = item

        self.setModel(model)
        self.header().setStretchLastSection(False)
        self.header().setSectionResizeMode(0, QHeaderView.Stretch)
        self.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
        self.expandAll()

        self.model().itemChanged.connect(self.treeItemChanged)
        self.doubleClicked.connect(self.treeItemDoubleClicked)
예제 #22
0
    def build_ui(self):
        self.ui = self.ui_class()
        self.ui.setupUi(self)

        # self.setup_dragdrop(self)

        model = QStandardItemModel()
        model.setHorizontalHeaderLabels(['Thesaurus', 'Keyword'])
        rootNode = model.invisibleRootItem()

        self.ui.place.setModel(model)
        self.ui.place.setColumnWidth(0, 250)
        self.ui.place.expandAll()

        self.contact_include_place_change(self.ui.rbtn_yes.isChecked())
예제 #23
0
class QDictTreeView(QTreeView):
    def __init__(self, data=None):
        super().__init__()
        self.header().hide()
        self.root_model = QStandardItemModel()
        self.setModel(self.root_model)
        if data:
            self.populate_tree(data)

    def populate_tree(self, children, parent=None):
        if not parent:
            parent = self.root_model.invisibleRootItem()
        for child in sorted(children):
            child_item = QStandardItem(child)
            parent.appendRow(child_item)
            if isinstance(children, dict) and bool(list(children)):
                self.populate_tree(children[child], child_item)
예제 #24
0
 def getOutlines(self, doc):
     toc = doc.toc()
     if not toc:
         self.dockWidget.hide()
         return
     self.dockWidget.show()
     outline_model = QStandardItemModel(self)
     parent_item = outline_model.invisibleRootItem()
     node = toc.firstChild()
     loadOutline(doc, node, parent_item)
     self.treeView.setModel(outline_model)
     if parent_item.rowCount() < 4:
         self.treeView.expandToDepth(0)
     self.treeView.setHeaderHidden(True)
     self.treeView.header().setSectionResizeMode(0, 1)
     self.treeView.header().setSectionResizeMode(1, 3)
     self.treeView.header().setStretchLastSection(False)
예제 #25
0
class TreeView(QTreeView):
    """
    TreeView contains the detailed list of packages for a given recipe.
    """
    def __init__(self):
        super(TreeView, self).__init__()
        self.setAlternatingRowColors(True)
        self.model = QStandardItemModel(0, 2, self)
        self.model.setHeaderData(0, Qt.Horizontal, "Package")
        self.model.setHeaderData(1, Qt.Horizontal, "Values")
        self.rootNode = self.model.invisibleRootItem()
        self.setModel(self.model)
        self.setColumnWidth(0, 150)
        self.expandAll()

    def populate(self, info, clear=False):
        if clear:
            if self.rootNode.rowCount() > 0:
                self.rootNode.removeRows(0, self.rootNode.rowCount())
        if info == []:
            branch = QStandardItem("No packages found.")
        else:
            for package in info:
                branch = QStandardItem(package["id"])
                for key, value in package.items():
                    if key == "id":  # Already got it
                        continue
                    if isinstance(value, list):
                        p = QStandardItem(key)
                        branch.appendRow([p])
                        for item in value:
                            p.appendRow(item)
                    elif isinstance(value, dict):
                        p = QStandardItem(key)
                        branch.appendRow([p])
                        for key_, value_ in value.items():
                            p.appendRow(
                                [QStandardItem(key_),
                                 QStandardItem(value_)])
                    else:
                        p = QStandardItem(key)
                        q = QStandardItem(str(value))
                        branch.appendRow([p, q])

        self.rootNode.appendRow([branch])
예제 #26
0
    def createCentralWidget(self):
        # Create table
        self.centralWidget = QSplitter(Qt.Horizontal)
        self.treeView = QTreeView()
        self.treeView.setHeaderHidden(True)
        standardModel = QStandardItemModel()
        rootNode = standardModel.invisibleRootItem()
        self.ports = QStandardItem("本地端口")
        self.attackerIP = QStandardItem("攻击者IP")
        self.ports.setEditable(False)
        self.attackerIP.setEditable(False)

        rootNode.appendRow(self.ports)
        rootNode.appendRow(self.attackerIP)

        self.treeView.setModel(standardModel)

        self.tableWidget = QTableWidget(self)
        self.tableWidget.setRowCount(1500)
        self.tableWidget.setColumnCount(11)
        self.tableWidget.verticalHeader().setVisible(False)
        self.tableWidget.setHorizontalHeaderLabels([
            '日期', '时间', '远程IP', '远程端口', '方向', '本地IP', '本地端口', '协议', '字节', '国家',
            '数据包详细信息'
        ])
        self.tableWidget.setColumnWidth(0, 100)
        self.tableWidget.setColumnWidth(2, self.width * 0.1)
        self.tableWidget.setColumnWidth(3, self.width * 0.07)
        self.tableWidget.setColumnWidth(4, self.width * 0.05)
        self.tableWidget.setColumnWidth(5, self.width * 0.1)
        self.tableWidget.setColumnWidth(6, self.width * 0.06)
        self.tableWidget.setColumnWidth(7, self.width * 0.05)
        self.tableWidget.setColumnWidth(8, self.width * 0.04)
        self.tableWidget.setColumnWidth(10, self.width * 0.095)
        #        self.tableWidget.move(30,10)

        # table selection change
        self.tableWidget.doubleClicked.connect(self.on_click)
        self.treeView.setMinimumWidth(self.width * 0.15)
        self.tableWidget.setMinimumWidth(self.width * 0.85)
        self.centralWidget.addWidget(self.treeView)
        self.centralWidget.addWidget(self.tableWidget)
        self.centralWidget.setMinimumHeight(self.height * 0.95)
예제 #27
0
    def createCentralWidget(self):
        # Create table
        self.centralWidget = QSplitter(Qt.Horizontal)
        self.treeView = QTreeView()
        self.treeView.setHeaderHidden(True)
        standardModel = QStandardItemModel()
        rootNode = standardModel.invisibleRootItem()
        self.ports = QStandardItem("Local Ports")
        self.attackerIP = QStandardItem("Attacker IPs")
        self.ports.setEditable(False)
        self.attackerIP.setEditable(False)

        rootNode.appendRow(self.ports)
        rootNode.appendRow(self.attackerIP)

        self.treeView.setModel(standardModel)

        self.tableWidget = QTableWidget(self)
        self.tableWidget.setRowCount(1500)
        self.tableWidget.setColumnCount(11)
        self.tableWidget.verticalHeader().setVisible(False)
        self.tableWidget.setHorizontalHeaderLabels([
            'Date', 'Time', 'RemoteIP', 'Remote Port', 'Direction', 'Local IP',
            'Local Port', 'Protocol', 'Bytes', 'Country', 'Packet Detail'
        ])
        self.tableWidget.setColumnWidth(0, 100)
        self.tableWidget.setColumnWidth(2, self.width * 0.1)
        self.tableWidget.setColumnWidth(3, self.width * 0.07)
        self.tableWidget.setColumnWidth(4, self.width * 0.05)
        self.tableWidget.setColumnWidth(5, self.width * 0.1)
        self.tableWidget.setColumnWidth(6, self.width * 0.06)
        self.tableWidget.setColumnWidth(7, self.width * 0.05)
        self.tableWidget.setColumnWidth(8, self.width * 0.04)
        self.tableWidget.setColumnWidth(10, self.width * 0.095)
        #        self.tableWidget.move(30,10)

        # table selection change
        self.tableWidget.doubleClicked.connect(self.on_click)
        self.treeView.setMinimumWidth(self.width * 0.15)
        self.tableWidget.setMinimumWidth(self.width * 0.85)
        self.centralWidget.addWidget(self.treeView)
        self.centralWidget.addWidget(self.tableWidget)
        self.centralWidget.setMinimumHeight(self.height * 0.95)
예제 #28
0
class TreeView(QTreeView):
    """
    TreeView contains the list of packages for each remote.
    It reads a cache file
    """
    def __init__(self, cache):
        super(TreeView, self).__init__()
        self.setAlternatingRowColors(False)
        self.model = QStandardItemModel(0, 1, self)
        self.model.setHeaderData(0, Qt.Horizontal, "Remote")
        self.rootNode = self.model.invisibleRootItem()
        for remote in cache:
            branch = QStandardItem(remote["name"])
            for package in remote["packages"]:
                p = QStandardItem(package)
                branch.appendRow([p])
            self.rootNode.appendRow([branch])
        self.setModel(self.model)
        self.setColumnWidth(0, 150)
        self.expandAll()
예제 #29
0
    def set_items(self, items):
        self.items = items
        self.itemsTree = QTreeView()
        self.itemsTree.setHeaderHidden(True)

        treeModel = QStandardItemModel()
        rootNode = treeModel.invisibleRootItem()

        groups = {}
        for item in items:
            category = item['data']['category']
            node = self.__get_node(item['name'])
            if (category not in groups):
                groups[category] = self.__get_node(category)
            groups[category].appendRow(node)

        for key in groups:
            rootNode.appendRow(groups[key])

        self.itemsTree.setModel(treeModel)
        self.itemsTree.expandAll()
        self.setWidget(self.itemsTree)
예제 #30
0
파일: tree.py 프로젝트: yqsy/qttest
    def get_tree_model(self):
        item_model = QStandardItemModel()
        root = item_model.invisibleRootItem()

        item_model.setHorizontalHeaderLabels(
            ['名称', '账号', '交易类型', '金额', '进度', '委托详情', '开始时间', '结束时间'])

        row1 = [
            '组合指令2', '37000033/37000034', '买入', '1.50万', '1500/3600', '15',
            '13:01:12', '13:01:12'
        ]

        for idx, ele in enumerate(row1):
            row1[idx] = QStandardItem(ele)

        row1_1 = ['37000033', '', '买入', '7032.00', '700/1600', '7', '']
        for idx, ele in enumerate(row1_1):
            row1_1[idx] = QStandardItem(ele)

        row1_1_1 = [
            'SZ000002 万科A', '', '买入', '1183.00', '100/100', '1', '', ''
        ]
        for idx, ele in enumerate(row1_1_1):
            # 每一个元素都是一个item!!!!!!!!!!
            row1_1_1[idx] = QStandardItem(ele)

        root.appendRow(row1)
        row1[0].appendRow(row1_1)
        row1_1[0].appendRow(row1_1_1)

        row1[2].setData(QBrush(Qt.red), Qt.ForegroundRole)
        row1_1[2].setData(QBrush(Qt.red), Qt.ForegroundRole)
        row1_1_1[2].setData(QBrush(Qt.red), Qt.ForegroundRole)

        row1[5].setData(QBrush(QColor(43, 145, 175)), Qt.ForegroundRole)
        row1_1[5].setData(QBrush(QColor(43, 145, 175)), Qt.ForegroundRole)
        row1_1_1[5].setData(QBrush(QColor(43, 145, 175)), Qt.ForegroundRole)

        return item_model
예제 #31
0
    def to_model(self):
        """ Convert history to Model vor QTreeView """
        from PyQt5.QtGui import QStandardItemModel, QStandardItem
        from PyQt5.QtGui import QColor, QBrush

        model = QStandardItemModel()
        root = model.invisibleRootItem()

        for turn in range(self.turns_count):
            color = QColor(0, 0, 0) if self.is_history_log(
                turn, 0, 0) else QColor(255, 0, 0)
            _round = QStandardItem('Round {}'.format(turn))
            _round.setForeground(color)
            _round.setData((turn, None, None))
            root.appendRow(_round)
            player_turn = self.__turns[turn]

            for p_turn in range(len(player_turn)):
                color = QColor(0, 0, 0) if self.is_history_log(
                    turn, p_turn, 0) else QColor(255, 0, 0)
                player = QStandardItem('Player {} - {}'.format(
                    p_turn, self.__players[p_turn].name))
                player.setForeground(color)
                player.setData((turn, p_turn, None))
                _round.appendRow(player)
                actions = player_turn[p_turn]

                for i, action in enumerate(actions):
                    color = QColor(0, 0, 0) if self.is_history_log(
                        turn, p_turn, i) else QColor(255, 0, 0)
                    _action = QStandardItem(str(action))
                    _action.setForeground(QBrush(color))
                    _action.setToolTip(str(action))
                    _action.setData((turn, p_turn, i))

                    player.appendRow(_action)

        return model
예제 #32
0
    def __update_tree_parameters(self, current):
        model = QStandardItemModel()
        parent_item = model.invisibleRootItem()  # type: QStandardItem

        for m in sorted(current):
            # skip modules
            if m == 'modules':
                continue
            text_item = QStandardItem(m)
            text_item.setEditable(False)

            for i in sorted(current[m]):
                item = QStandardItem(i + " = " + current[m][i])
                item.setEditable(False)
                font = QFont()
                font.setItalic(True)
                item.setFont(font)
                text_item.appendRow(item)

            parent_item.appendRow(text_item)

        model.setHeaderData(0, Qt.Horizontal, "Parameters")
        self.ui.parameters.setModel(model)
예제 #33
0
class StacktraceWidget(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.parent = parent
        self.tree = QTreeView(self)
        layout = QVBoxLayout(self)
        layout.addWidget(self.tree)
        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(["Level", "Values"])
        self.tree.header().setDefaultSectionSize(180)
        self.tree.setModel(self.model)

    def importData(self, data):
        self.model.setRowCount(0)
        root = self.model.invisibleRootItem()
        for index, stack_values in enumerate(data):
            parent = QStandardItem(
                str(stack_values.f_code.co_name)
                + str(
                    inspect.signature(
                        types.FunctionType(stack_values.f_code, {})
                    )
                )
            )
            parent.setEditable(False)
            for key, value in stack_values.f_locals.items():
                keyWidget = QStandardItem(str(key))
                keyWidget.setEditable(False)
                try:
                    value_as_str = repr(value)
                except BaseException:
                    value_as_str = "Can't see"
                valueWidget = ValueWidget(
                    self.parent, value_as_str, str(key), str(index)
                )
                parent.appendRow([keyWidget, valueWidget])
            root.appendRow(parent)
예제 #34
0
class TapeWidget(QWidget):
    def __init__(self, parent = None):
        super().__init__(parent)

        self._main_layout    = QVBoxLayout(self)
        self._search_box     = QLineEdit(self)
        self._button_layout  = QHBoxLayout()

        self._view = QTreeView()
        self._view.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
        self._view.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self._view.setHeaderHidden(True)

        self._add_note_button = QPushButton(self)
        self._add_note_button.setText("New note")

        self._add_child_button = QPushButton(self)
        self._add_child_button.setText("New child")

        self._add_sibling_button = QPushButton(self)
        self._add_sibling_button.setText("New sibling")

        self._delete_note_button = QPushButton(self)
        self._delete_note_button.setText("Delete note")

        self._button_layout.addWidget(self._add_note_button)
        self._button_layout.addWidget(self._add_sibling_button)
        self._button_layout.addWidget(self._add_child_button)
        self._button_layout.addWidget(self._delete_note_button)
        self._button_layout.addStretch()

        self._main_layout.addWidget(self._search_box)
        self._main_layout.addLayout(self._button_layout)
        self._main_layout.addWidget(self._view)

        self._tape_filter_proxy_model = TapeFilterProxyModel()
        self._note_delegate           = NoteDelegate()

        self._tape_model = QStandardItemModel()
        self.set_model(self._tape_model)
        self._view.setItemDelegate(self._note_delegate)
        self._view.setModel(self._tape_filter_proxy_model)

        self._add_note_button.clicked.connect(lambda checked: self.add_and_focus_note())
        self._add_sibling_button.clicked.connect(self._new_sibling_handler)
        self._add_child_button.clicked.connect(self._new_child_handler)
        self._delete_note_button.clicked.connect(self.delete_selected_notes)
        self._search_box.textChanged.connect(self._tape_filter_proxy_model.setFilterFixedString)

    def model(self):
        """ Returns the model that contains all notes managed by the tape.

            The model should be treated as read-only. You can only modify it indirectly through
            the methods provided by TapeWidget. """

        return self._tape_model

    def proxy_model(self):
        """ Returns the model that contains notes matching current filter.

            The model should be treated as read-only. You can only modify it indirectly through
            the methods provided by TapeWidget. """

        return self._tape_filter_proxy_model

    def set_model(self, model):
        assert (
            len(set([item_to_id(item) for item in all_items(model) if item_to_id(item) != None])) ==
            len(    [item_to_id(item) for item in all_items(model) if item_to_id(item) != None])
        )

        # NOTE: If there's an exception in setSourceModel(), we can hope that the source model
        # remains unchanged. That's why we assing to _tape_model only if that instruction succeeds.
        self._tape_filter_proxy_model.setSourceModel(model)
        self._tape_model = model

    def notes(self):
        return all_notes(self._tape_model)

    def assign_ids(self):
        assign_note_ids(self._tape_model)

    def create_empty_note(self):
        return Note(
            body       = "",
            tags       = [],
            created_at = datetime.utcnow()
        )

    def add_note(self, note = None, parent_index = None):
        # NOTE: Remember to use indexes from _tape_model, not _tape_filter_proxy_model here
        assert parent_index == None or self._tape_model.itemFromIndex(parent_index) != None and parent_index.isValid()

        root_item = self._tape_model.invisibleRootItem()
        if parent_index == None:
            parent_item = root_item
        else:
            parent_item = self._tape_model.itemFromIndex(parent_index)

        if note != None:
            assert note not in self.notes()
        else:
            note = self.create_empty_note()

        item = QStandardItem()
        set_item_note(item, note)
        parent_item.appendRow(item)

    def add_and_focus_note(self, parent_proxy_index = None):
        if parent_proxy_index != None:
            parent_index = self._tape_filter_proxy_model.mapToSource(parent_proxy_index)
        else:
            parent_index = None

        self.add_note(parent_index = parent_index)

        if parent_proxy_index != None:
            self._view.expand(parent_proxy_index)

            parent_item = self._tape_model.itemFromIndex(parent_index)
        else:
            parent_item = self._tape_model.invisibleRootItem()

        # NOTE: It's likely that the new note does not match the filter and won't not be present
        # in the proxy model. We want to select it and focus on it so the filter must be cleared.
        # And it must be cleared before taking the index in the proxy because changing the filter
        # may change the set of notes present in the proxy and invalidate the index.
        self.set_filter('')

        new_note_index       = parent_item.child(parent_item.rowCount() - 1).index()
        new_note_proxy_index = self._tape_filter_proxy_model.mapFromSource(new_note_index)

        self.clear_selection()
        self.set_note_selection(new_note_proxy_index, True)
        self._view.scrollTo(new_note_proxy_index)

    def remove_notes(self, indexes):
        remove_items(self._tape_model, indexes)

    def clear(self):
        self._tape_model.clear()

    def set_filter(self, text):
        # NOTE: This triggers textChanged() signal which applies the filter
        self._search_box.setText(text)

    def get_filter(self):
        return self._search_box.text()

    def selected_proxy_indexes(self):
        return self._view.selectedIndexes()

    def selected_indexes(self):
        return [self._tape_filter_proxy_model.mapToSource(proxy_index) for proxy_index in self.selected_proxy_indexes()]

    def set_note_selection(self, proxy_index, select):
        assert proxy_index != None and proxy_index.isValid()
        assert self._tape_model.itemFromIndex(self._tape_filter_proxy_model.mapToSource(proxy_index)) != None

        self._view.selectionModel().select(
            QItemSelection(proxy_index, proxy_index),
            QItemSelectionModel.Select if select else QItemSelectionModel.Deselect
        )

    def clear_selection(self):
        self._view.selectionModel().clear()

    def delete_selected_notes(self):
        self.remove_notes(self.selected_indexes())

    def _new_sibling_handler(self):
        selected_proxy_indexes = self._view.selectedIndexes()
        if len(selected_proxy_indexes) > 1:
            self.clear_selection()
            selected_proxy_indexes = []

        if len(selected_proxy_indexes) == 0 or selected_proxy_indexes[0].parent() == QModelIndex():
            self.add_and_focus_note()
        else:
            self.add_and_focus_note(selected_proxy_indexes[0].parent())

    def add_child_to_selected_element(self):
        selected_proxy_indexes = self._view.selectedIndexes()
        if len(selected_proxy_indexes) != 1:
            return False
        else:
            self.add_and_focus_note(selected_proxy_indexes[0])
            return True

    def _new_child_handler(self):
        added = self.add_child_to_selected_element()
        if not added:
            QMessageBox.warning(self, "Can't add note", "To be able to add a new child note select exactly one parent")
예제 #35
0
class TapeFilterProxyModelTest(unittest.TestCase):
    def setUp(self):
        self.source_model            = QStandardItemModel()
        self.tape_filter_proxy_model = TapeFilterProxyModel()

        self.notes = [
            Note(
                body       = "H+X",
                tags       = ["Z"],
                created_at = datetime.utcnow()
            ),
            Note(
                body       = "B",
                tags       = ["C", "PPP RRR"],
                created_at = datetime.utcnow()
            ),
            Note(
                body       = "2",
                tags       = ["3", "PPP\tRRR"],
                created_at = datetime.utcnow()
            ),
            Note(
                body       = "b",
                tags       = ["VVV", "III"],
                created_at = datetime.utcnow()
            )
        ]

        root_item = self.source_model.invisibleRootItem()
        for note in self.notes:
            item = QStandardItem()
            set_item_note(item, note)
            root_item.appendRow(item)

        assert self.source_model.rowCount() == len(self.notes)

        self.tape_filter_proxy_model.setSourceModel(self.source_model)

    def select_note_dicts(self, model, mask = None):
        assert mask == None or model.rowCount() == len(mask)
        assert mask == None or all(bit in [True, False] for bit in mask)

        dicts = []
        for i in range(model.rowCount()):
            if mask == None or mask[i]:
                index = model.index(i, 0)
                dicts.append(model.data(index).to_dict())

        return dicts

    def test_unfiltered_model_should_contain_all_notes(self):
        mask = [True, True, True, True]
        self.assertEqual(self.select_note_dicts(self.tape_filter_proxy_model), self.select_note_dicts(self.source_model, mask))

    def test_filtered_model_should_contain_all_notes_if_searching_for_empty_string(self):
        self.tape_filter_proxy_model.setFilterFixedString('')

        mask = [True, True, True, True]
        self.assertEqual(self.select_note_dicts(self.tape_filter_proxy_model), self.select_note_dicts(self.source_model, mask))

    def test_filtered_model_should_contain_only_matching_notes(self):
        keyword = 'B'

        assert keyword in self.notes[1].body
        assert not keyword.lower() in self.notes[0].body.lower()
        assert not keyword.lower() in self.notes[2].body.lower()
        assert all(keyword.lower() not in Note.join_tags(note.tags).lower() for note in self.notes[0:3])

        self.tape_filter_proxy_model.setFilterFixedString(keyword)

        mask = [False, True, False, True]
        self.assertEqual(self.select_note_dicts(self.tape_filter_proxy_model), self.select_note_dicts(self.source_model, mask))

    def test_filtered_model_should_treat_fixed_string_as_case_insensitive(self):
        keyword = 'B'

        assert keyword         != keyword.lower()
        assert keyword         in self.notes[1].body
        assert keyword.lower() in self.notes[3].body
        assert not keyword.lower() in self.notes[0].body.lower()
        assert not keyword.lower() in self.notes[2].body.lower()
        assert all(keyword.lower() not in Note.join_tags(note.tags).lower() for note in self.notes[0:4])

        self.tape_filter_proxy_model.setFilterFixedString(keyword)

        mask = [False, True, False, True]
        self.assertEqual(self.select_note_dicts(self.tape_filter_proxy_model), self.select_note_dicts(self.source_model, mask))

    def test_filtered_model_should_contain_items_with_matching_tags(self):
        keyword = 'III'

        assert all(keyword.lower() not in note.body.lower()                 for note in self.notes[0:4])
        assert all(keyword.lower() not in Note.join_tags(note.tags).lower() for note in self.notes[0:3])
        assert keyword.lower() in self.notes[3].tags[1].lower()

        self.tape_filter_proxy_model.setFilterFixedString(keyword)

        mask = [False, False, False, True]
        self.assertEqual(self.select_note_dicts(self.tape_filter_proxy_model), self.select_note_dicts(self.source_model, mask))

    def test_filtered_model_should_only_contain_notes_with_exactly_matching_whitespace(self):
        keyword = 'PPP RRR'

        assert all(keyword.lower() not in note.body.lower()  for note in self.notes[0:4])
        assert 'PPP RRR'  in self.notes[1].tags[1]
        assert 'PPP\tRRR' in self.notes[2].tags[1]

        self.tape_filter_proxy_model.setFilterFixedString(keyword)

        mask = [False, True, False, False]
        self.assertEqual(self.select_note_dicts(self.tape_filter_proxy_model), self.select_note_dicts(self.source_model, mask))
예제 #36
0
class NoteModelHelpersTest(unittest.TestCase):
    def setUp(self):
        self.model = QStandardItemModel()

    def sample_note_dict(self, id, parent_id, prev_item_id):
        timestamp = Note.serialize_timestamp(datetime.utcnow())
        return {
            'body':            'body\n\t\n',
            'tags':            ['a tag', 'another tag'],
            'created_at':      timestamp,
            'modified_at':     timestamp,
            'id':              id,
            'parent_id':       parent_id,
            'prev_sibling_id': prev_item_id
        }

    def create_note_and_append(self, parent_item, body):
        note = Note(body = body)
        item = QStandardItem()
        set_item_note(item, note)
        parent_item.appendRow(item)
        return item

    def prepare_tree(self):
        root_item = self.model.invisibleRootItem()

        self.item_0         = self.create_note_and_append(root_item,         "Note 0")
        self.item_0_0       = self.create_note_and_append(self.item_0,       "Note 0_0")
        self.item_0_0_0     = self.create_note_and_append(self.item_0_0,     "Note 0_0_0")
        self.item_0_0_0_0   = self.create_note_and_append(self.item_0_0_0,   "Note 0_0_0_0")
        self.item_1         = self.create_note_and_append(root_item,         "Note 1")
        self.item_1_0       = self.create_note_and_append(self.item_1,       "Note 1_0")
        self.item_1_0_0     = self.create_note_and_append(self.item_1_0,     "Note 1_0_0")
        self.item_1_0_1     = self.create_note_and_append(self.item_1_0,     "Note 1_0_1")
        self.item_1_0_2     = self.create_note_and_append(self.item_1_0,     "Note 1_0_2")
        self.item_1_0_2_0   = self.create_note_and_append(self.item_1_0_2,   "Note 1_0_2_0")
        self.item_1_0_2_0_0 = self.create_note_and_append(self.item_1_0_2_0, "Note 1_0_2_0_0")
        self.item_1_0_3     = self.create_note_and_append(self.item_1_0,     "Note 1_0_3")
        self.item_1_1       = self.create_note_and_append(self.item_1,       "Note 1_1")
        self.item_1_1_0     = self.create_note_and_append(self.item_1_1,     "Note 1_1_0")
        self.item_2         = self.create_note_and_append(root_item,         "Note 2")
        self.item_2_0       = self.create_note_and_append(self.item_2,       "Note 2_0")
        self.item_3         = self.create_note_and_append(root_item,         "Note 3")

    def test_all_items_should_iterate_over_all_model_items_inorder(self):
        self.prepare_tree()

        expected_order = [
            item_to_note(self.item_0),
            item_to_note(self.item_0_0),
            item_to_note(self.item_0_0_0),
            item_to_note(self.item_0_0_0_0),
            item_to_note(self.item_1),
            item_to_note(self.item_1_0),
            item_to_note(self.item_1_0_0),
            item_to_note(self.item_1_0_1),
            item_to_note(self.item_1_0_2),
            item_to_note(self.item_1_0_2_0),
            item_to_note(self.item_1_0_2_0_0),
            item_to_note(self.item_1_0_3),
            item_to_note(self.item_1_1),
            item_to_note(self.item_1_1_0),
            item_to_note(self.item_2),
            item_to_note(self.item_2_0),
            item_to_note(self.item_3)
        ]

        result = []
        for note in all_notes(self.model):
            result.append(note)

        self.assertEqual(result, expected_order)

    def test_assign_note_ids_should_put_unique_integer_id_in_each_note(self):
        self.prepare_tree()
        assert all(note.id == None for note in all_notes(self.model))

        assign_note_ids(self.model)

        ids = [note.id for note in all_notes(self.model)]
        self.assertEqual(len(set(ids)), len(ids))
        self.assertEqual(min(ids), 1)
        self.assertEqual(max(ids), len(ids))

    def test_assign_note_ids_should_not_crash_if_given_empty_model(self):
        empty_model = QStandardItemModel()

        assign_note_ids(empty_model)

        self.assertEqual(empty_model.rowCount(), 0)

    def test_assign_note_ids_should_not_modify_ids_in_model_that_already_has_ids(self):
        self.prepare_tree()
        assert all(note.id == None for note in all_notes(self.model))

        next_id = 1
        for note in all_notes(self.model):
            note.id = next_id
            next_id += 1

        ids_before = list(range(1, next_id))

        assign_note_ids(self.model)

        ids_after = [note.id for note in all_notes(self.model)]
        self.assertEqual(ids_after, ids_before)

    def test_assign_note_ids_should_assign_ids_only_to_notes_that_do_not_already_have_them(self):
        self.prepare_tree()
        assert all(note.id == None for note in all_notes(self.model))

        next_id = 0
        for note in all_notes(self.model):
            if next_id % 2 == 0:
                note.id = next_id
            next_id += 1

        ids_before = [note.id for note in all_notes(self.model)]
        assert all(id == None for id in ids_before[1::2])

        assign_note_ids(self.model)

        ids_after = [note.id for note in all_notes(self.model)]
        self.assertEqual(ids_after[::2], ids_before[::2])
        self.assertTrue(all(id != None for id in ids_after[1::2]))

    def test_assign_note_ids_should_assign_ids_not_colliding_with_already_assigned_ones(self):
        self.prepare_tree()
        assert all(note.id == None for note in all_notes(self.model))

        next_id = 0
        for note in all_notes(self.model):
            if next_id % 2 == 0:
                note.id = next_id
            next_id += 1

        ids_before = [note.id for note in all_notes(self.model)]
        assert all(id == None for id in ids_before[1::2])

        assign_note_ids(self.model)

        ids_after = [note.id for note in all_notes(self.model)]
        self.assertEqual(set(ids_after) & set(ids_before[1::2]), set())

    def test_dump_notes_should_serialize_note_tree_into_a_list_of_dicts_of_primitives(self):
        self.prepare_tree()
        notes = list(all_notes(self.model))
        assign_note_ids(self.model)
        assert all(note.id != None for note in notes)

        serialized_notes = dump_notes(self.model)

        self.assertEqual(len(serialized_notes), len(notes))
        for key in ['body', 'tags', 'created_at', 'modified_at', 'id', 'parent_id', 'prev_sibling_id']:
            self.assertTrue(all(key in note_dict for note_dict in serialized_notes))

        for key in ['body', 'created_at', 'modified_at']:
            self.assertTrue(all(isinstance(note_dict[key], str) for note_dict in serialized_notes))

        for key in ['id', 'parent_id', 'prev_sibling_id']:
            self.assertTrue((note_dict[key] == None or all(isinstance(note_dict[key], int)) for note_dict in serialized_notes))

        self.assertTrue(all(all(isinstance(tag, str) for tag in note_dict['tags']) for note_dict in serialized_notes))

    def test_dump_notes_should_serialize_tree_structure_correctly(self):
        self.prepare_tree()
        assign_note_ids(self.model)

        items = list(all_items(self.model))
        assert all(item_to_id(item) != None for item in items)

        expected_tree = {
            item_to_id(self.item_0):         (None,              None),
            item_to_id(self.item_0_0):       (self.item_0,       None),
            item_to_id(self.item_0_0_0):     (self.item_0_0,     None),
            item_to_id(self.item_0_0_0_0):   (self.item_0_0_0,   None),
            item_to_id(self.item_1):         (None,              self.item_0),
            item_to_id(self.item_1_0):       (self.item_1,       None),
            item_to_id(self.item_1_0_0):     (self.item_1_0,     None),
            item_to_id(self.item_1_0_1):     (self.item_1_0,     self.item_1_0_0),
            item_to_id(self.item_1_0_2):     (self.item_1_0,     self.item_1_0_1),
            item_to_id(self.item_1_0_2_0):   (self.item_1_0_2,   None),
            item_to_id(self.item_1_0_2_0_0): (self.item_1_0_2_0, None),
            item_to_id(self.item_1_0_3):     (self.item_1_0,     self.item_1_0_2),
            item_to_id(self.item_1_1):       (self.item_1,       self.item_1_0),
            item_to_id(self.item_1_1_0):     (self.item_1_1,     None),
            item_to_id(self.item_2):         (None,              self.item_1),
            item_to_id(self.item_2_0):       (self.item_2,       None),
            item_to_id(self.item_3):         (None,              self.item_2)
        }

        serialized_notes = dump_notes(self.model)

        serialized_id_set = set(note_dict['id']  for note_dict in serialized_notes)
        note_id_set       = set(item_to_id(item) for item      in items)

        self.assertEqual(serialized_id_set, note_id_set)

        for note_dict in serialized_notes:
            expected_node            = expected_tree[note_dict['id']]
            expected_parent_id       = item_to_id(expected_node[0]) if expected_node[0] != None else None
            expected_prev_sibling_id = item_to_id(expected_node[1]) if expected_node[1] != None else None

            self.assertEqual(note_dict['parent_id'],       expected_parent_id)
            self.assertEqual(note_dict['prev_sibling_id'], expected_prev_sibling_id)

    def test_dump_notes_should_handle_empty_model(self):
        empty_model = QStandardItemModel()

        serialized_notes = dump_notes(empty_model)

        self.assertEqual(serialized_notes, [])

    def test_load_notes_should_deserialize_tree_structure_correctly(self):
        self.prepare_tree()
        assign_note_ids(self.model)
        serialized_notes_before = dump_notes(self.model)
        assert all(note_dict['id'] != None for note_dict in serialized_notes_before)

        new_model = load_notes(serialized_notes_before)

        serialized_notes_after = dump_notes(new_model)

        note_id = lambda note_dict: note_dict['id']
        self.assertEqual(sorted(serialized_notes_after, key = note_id), sorted(serialized_notes_before, key = note_id))

    def test_load_notes_should_raise_error_if_tree_contains_sibling_cycle(self):
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(2, 1,    4),
            self.sample_note_dict(3, 1,    2),
            self.sample_note_dict(4, 1,    3)
        ]

        with self.assertRaises(SiblingCycle):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_tree_contains_sibling_cycle_that_does_not_include_all_siblings(self):
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(5, 1,    None),
            self.sample_note_dict(6, 1,    5),
            self.sample_note_dict(7, 1,    6),
            self.sample_note_dict(2, 1,    4),
            self.sample_note_dict(3, 1,    2),
            self.sample_note_dict(4, 1,    3)
        ]

        with self.assertRaises(SiblingCycle):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_tree_contains_an_element_which_is_its_own_prev_sibling(self):
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(2, 1,    None),
            self.sample_note_dict(3, 1,    2),
            self.sample_note_dict(4, 1,    4)
        ]

        with self.assertRaises(SiblingCycle):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_tree_contains_parent_cycle(self):
        serialized_notes = [
            self.sample_note_dict(1, 4, None),
            self.sample_note_dict(2, 1, None),
            self.sample_note_dict(3, 2, None),
            self.sample_note_dict(4, 3, None)
        ]

        with self.assertRaises(ParentCycle):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_tree_contains_parent_cycle_that_does_not_reach_top_level(self):
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(2, 1,    None),
            self.sample_note_dict(3, 2,    None),
            self.sample_note_dict(4, 3,    None),
            self.sample_note_dict(5, 8,    None),
            self.sample_note_dict(6, 5,    None),
            self.sample_note_dict(7, 6,    None),
            self.sample_note_dict(8, 7,    None),
            self.sample_note_dict(9, 8,    5)
        ]

        with self.assertRaises(ParentCycle):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_tree_contains_an_element_which_is_its_own_parent(self):
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(2, 1,    None),
            self.sample_note_dict(3, 2,    None),
            self.sample_note_dict(4, 4,    None)
        ]

        with self.assertRaises(ParentCycle):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_tree_siblings_with_the_same_prev_sibling_id(self):
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(2, 1,    None),
            self.sample_note_dict(3, 1,    2),
            self.sample_note_dict(4, 1,    2),
            self.sample_note_dict(5, 1,    4)
        ]

        with self.assertRaises(ConflictingSiblingIds):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_tree_siblings_with_the_same_prev_sibling_id_being_none(self):
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(2, 1,    None),
            self.sample_note_dict(3, 1,    None),
            self.sample_note_dict(4, 1,    2),
            self.sample_note_dict(5, 1,    4)
        ]

        with self.assertRaises(ConflictingSiblingIds):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_tree_contains_note_with_empty_id(self):
        serialized_notes = [
            self.sample_note_dict(1,    None, None),
            self.sample_note_dict(2,    1,    None),
            self.sample_note_dict(3,    1,    2),
            self.sample_note_dict(4,    1,    3),
            self.sample_note_dict(None, 1,    4)
        ]

        with self.assertRaises(EmptyNoteId):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_tree_contains_note_without_parent_id_attribute(self):
        # NOTE: It's about the attribute missing from the dict, not being None
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(2, 1,    None),
            self.sample_note_dict(3, 1,    2),
            self.sample_note_dict(4, 1,    3),
            self.sample_note_dict(5, 1,    4)
        ]

        del serialized_notes[-1]['parent_id']

        with self.assertRaises(MissingParentId):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_tree_contains_note_without_prev_sibling_id_attribute(self):
        # NOTE: It's about the attribute missing from the dict, not being None
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(2, 1,    None),
            self.sample_note_dict(3, 1,    2),
            self.sample_note_dict(4, 1,    3),
            self.sample_note_dict(5, 1,    4)
        ]

        del serialized_notes[-1]['prev_sibling_id']

        with self.assertRaises(MissingPrevSiblingId):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_prev_sibling_id_does_not_exist_in_tree(self):
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(2, 1,    None),
            self.sample_note_dict(3, 1,    2),
            self.sample_note_dict(4, 1,    666),
            self.sample_note_dict(5, 1,    4)
        ]

        with self.assertRaises(MissingNote):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_parent_id_does_not_exist_in_tree(self):
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(2, 1,    None),
            self.sample_note_dict(3, 1,    2),
            self.sample_note_dict(4, 666,  3),
            self.sample_note_dict(5, 1,    4)
        ]

        with self.assertRaises(MissingNote):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_prev_sibling_has_different_parent(self):
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(2, 1,    None),
            self.sample_note_dict(3, 1,    2),
            self.sample_note_dict(4, 5,    3),
            self.sample_note_dict(5, None, 4)
        ]

        with self.assertRaises(InconsistentParentIds):
            load_notes(serialized_notes)

    def test_load_notes_should_raise_error_if_prev_sibling_at_a_different_level(self):
        # This can also be classified as siblings having different parents but
        # the structure here is a bit different so the example is included for completeness.
        serialized_notes = [
            self.sample_note_dict(1, None, None),
            self.sample_note_dict(2, 1,    None),
            self.sample_note_dict(3, 2,    None),
            self.sample_note_dict(4, 2,    3),
            self.sample_note_dict(5, 1,    4)
        ]

        with self.assertRaises(InconsistentParentIds):
            load_notes(serialized_notes)

    def test_load_notes_should_correctly_handle_notes_not_in_the_final_order(self):
        # This means note's prev sibling and/or parent coming after the note
        serialized_notes_before = [
            self.sample_note_dict(15, 7,    14),
            self.sample_note_dict(7,  5,    6),
            self.sample_note_dict(2,  1,    None),
            self.sample_note_dict(14, 7,    10),
            self.sample_note_dict(4,  1,    3),
            self.sample_note_dict(17, 5,    7),
            self.sample_note_dict(18, 5,    17),
            self.sample_note_dict(10, 7,    9),
            self.sample_note_dict(11, 10,   None),
            self.sample_note_dict(3,  1,    2),
            self.sample_note_dict(12, 10,   11),
            self.sample_note_dict(9,  7,    8),
            self.sample_note_dict(8,  7,    None),
            self.sample_note_dict(16, 15,   None),
            self.sample_note_dict(13, 10,   12),
            self.sample_note_dict(6,  5,    None),
            self.sample_note_dict(20, 19,   None),
            self.sample_note_dict(19, None, 5),
            self.sample_note_dict(5,  None, 1),
            self.sample_note_dict(1,  None, None)
        ]

        new_model = load_notes(serialized_notes_before)

        serialized_notes_after = dump_notes(new_model)

        note_id = lambda note_dict: note_dict['id']
        self.assertEqual(sorted(serialized_notes_after, key = note_id), sorted(serialized_notes_before, key = note_id))

    def test_load_notes_should_detect_wrong_attribute_types(self):
        note_dict = {
            'body':            "Y",
            'tags':            ["a", "b", "c"],
            'created_at':      "2013-06-16T00:00:00.000000",
            'modified_at':     "2013-07-16T00:00:00.000000",
            'id':              1,
            'parent_id':       None,
            'prev_sibling_id': None
        }

        # ASSUMPTION: This does not raise exceptions
        load_notes([note_dict])

        wrong_type_samples = [
            ('body',            1),
            ('tags',            ("a", "b", "c")),
            ('tags',            ()),
            ('tags',            {}),
            ('tags',            set()),
            ('tags',            deque(["a", "b", "c"])),
            ('tags',            [1, 2, 3]),
            ('created_at',      1234567890),
            ('created_at',      datetime(2013, 1, 1)),
            ('modified_at',     1234567890),
            ('modified_at',     datetime(2013, 1, 1)),
            ('id',              "10"),
            ('id',              []),
            ('parent_id',       "10"),
            ('parent_id',       []),
            ('prev_sibling_id', "10"),
            ('prev_sibling_id', [])
        ]

        for tested_attribute, wrong_value in wrong_type_samples:
            filtered_note_dict = {attribute: note_dict[attribute] if attribute != tested_attribute else wrong_value for attribute in note_dict}

            with self.assertRaises(WrongAttributeType):
                load_notes([filtered_note_dict])
    new_path = get_path(new_selection_indexes[0])

    print(old_path, " -> ", new_path)


if __name__ == '__main__':
    app = QApplication(sys.argv)

    tree_view = QTreeView()

    ###

    model = QStandardItemModel(None)

    rootItem = model.invisibleRootItem()

    # Defining a couple of items
    americaItem = QStandardItem("America")
    canadaItem = QStandardItem("Canada")
    europeItem = QStandardItem("Europe")
    franceItem = QStandardItem("France")
    brittanyItem = QStandardItem("Brittany")

    # Building up the hierarchy
    rootItem.appendRow(americaItem)
    rootItem.appendRow(europeItem)
    americaItem.appendRow(canadaItem)
    europeItem.appendRow(franceItem)
    franceItem.appendRow(brittanyItem)
예제 #38
0
class FittingAdvancedDlg(QDialog, Ui_Dialog):
    '''
    The tree should provide any fittable parameter of any layers
    layer 1                                                     value               *what to change*            
        - thickness                                                                 layer.thickness
        - srough_thickness (if model is on)                                  if layer.srough: layer.sroughThickness
        - haze reflection (if model is on)                                     if layer.srough: layer.sroughHazeR
        - haze transmission (if model is on)                                 if layer.srough: layer.sroughHazeT
        - constant n (if source is constant)                                if layer.criSource=='constant': layer.criConstant[0] 
        - constant k (if source is constant)                                if layer.criSource=='constant': layer.criConstant[1] 
        - grading (constant) (if source is constant)                     if layer.criSource=='graded' && layer.criGrading['mode']=='constant':  layer.criGrading['value']
        + dielectric function (if source)                                       if layer.criSource=='dielectric function'
            - e0                                                                        layer.dielectricFunction['e0']
            + oscillator 0                                                          for each oscillator: layer.dielectricFunction['oscillators'][#of Osci]['name'] : [{'name': 'Lorentz', 'values': [1, 3, 0.2], 'active': True}], 
                - value 1                                                           layer.dielectricFunction['oscillators'][#of Osci]['value'][0]
                - value 2 ...
            + oscillator 1
                - value 1 ..
        - collection function (constant) (if selected)                     if layer.collection['source'] == 'from collection function' && layer.collection['mode'] == 'constant': layer.collection['value']
        + diff length model                                                       if layer.collection['source'] == 'from diffusion length'
            - space charge region width                                      layer.collection['SCRwidth']
            - diff length                                                           layer.collection['diffLength']
            - surface rec. velocity                                             layer.collection['recVel']
    layer 2
        ...

    '''
    def __init__(self, stack, references, stackname, settings, getcri, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget
        @type QWidget
        """
        super().__init__(parent)
        self.setupUi(self)        
        self.setAttribute(Qt.WA_DeleteOnClose)
        
        self.originalStack = stack
        self.stack = copy.deepcopy(stack)
        self.references = references
        self.StackName = stackname
        self.settings = settings
        self.getCRI = getcri
        
        self.referenceDataSelected = {}
        self.referenceList = []
        for key, value in self.references.items():
            if value[0]:
                self.referenceList.append([key, False]) # name and selection for fitting 
        self.referenceListModel = QStandardItemModel()
        self.referenceListModel.itemChanged.connect(self.updateReferences)
        self.referenceListView.setModel(self.referenceListModel)
        self.fillReferences()
        
        self.parameterModel = QStandardItemModel() #TreeOfParametersModel()
        self.parameterTreeView.setModel(self.parameterModel)
        self.parameterModel.setHorizontalHeaderLabels(['Parameter', 'Value'])
        self.root = self.parameterModel.invisibleRootItem()
        self.fillParameterTree()
        

        
        # configurations
        self.noOfFitIterations = 100
        methods = ['Nelder-Mead', 'Powell', 'CG', 'BFGS', 'L-BFGS-B', 'TNC', 'COBYLA', 'SLSQP']
        self.tolerance = 1e-3
         # with Jacobian necessary: 'Newton-CG', 'dogleg',  'trust-ncg'
        self.configuration = dict([
                        ('method', methods[0]),
                        ('noOfIterations', self.noOfFitIterations), 
                        ('tolerance', self.tolerance), 
                        ('plotInBetween',  True)
                        ])
        self.methodCB.addItems(methods)
        self.noOfIterationsSB.setValue(self.noOfFitIterations) 
        self.toleranceSB.setValue(self.tolerance)
        
        try:
            self.runOptics()
        except:
            self.done(0)
            QMessageBox.warning(self, "error", 'Error - could not calculate current stack.\nPlease check stack definition until simple simulation is running.',
                QMessageBox.StandardButtons(QMessageBox.Close))
            
            
    def fillReferences(self):
        
        for value in self.referenceList:                   
            item = QStandardItem(value[0])
            check = Qt.Checked if value[1] else Qt.Unchecked
            item.setCheckState(check)
            item.setCheckable(True)
            self.referenceListModel.appendRow(item)
    
    def updateReferences(self):
        self.referenceDataSelected = {}
        for row in range(self.referenceListModel.rowCount()):
            item = self.referenceListModel.item(row)                  
            if item.checkState() == Qt.Checked:
                self.referenceList[row][1] = True
                self.referenceDataSelected[item.text()] = self.referenceData[item.text()]
            else:
                self.referenceList[row][1] = False
        self.updatePlot()
        #print(len(self.referenceDataSelected))
            #print('{} {}'.format(row, self.references[row]))
        
    def updatePlot(self):
        plotDict = {}
        for ref in self.referenceList:
            if ref[1]:
                if ref[0] == 'R reference':
                    plotDict['R reference'] = self.referenceData['R reference']
                    plotDict['R'] = self.optics.RspectrumSystem
                if ref[0] == 'T reference':                    
                    plotDict['T reference'] = self.referenceData['T reference']
                    plotDict['T'] = self.optics.TspectrumSystem
                if ref[0] == 'EQE reference':
                    plotDict['EQE reference'] = self.referenceData['EQE reference']
                    plotDict['EQE'] = self.optics.EQE
                if ref[0] == 'psi reference':
                    plotDict['psi reference'] = self.referenceData['psi reference']
                    plotDict['psi'] = self.optics.psi
                if ref[0] == 'delta reference':
                    plotDict['delta reference'] = self.referenceData['delta reference']
                    plotDict['delta'] = self.optics.delta
        x = self.optics.wavelength
        if plotDict:
            self.plotView.showCurves(x, plotDict, 'wavelength (nm)', 'value [a.u.]')
        else:
            self.plotView.ax.clear()
            self.plotView.canvas.draw()
        
    def fillParameterTree(self):
        rows = self.parameterModel.rowCount()
        if rows:
            while self.parameterModel.rowCount() > 0:
                self.parameterModel.removeRow(0)
        self.parameterList = []
        parameterStr = 'self.stack['
        
        for i, layer in enumerate(self.stack):
            parameterStr += '{}].'.format(i)
            layerBranch = QStandardItem(layer.name)
            self.root.appendRow(layerBranch)
            self.addTreeEntry(layerBranch, 'thickness (nm)',  layer.thickness, self.changeThickness)
            if layer.srough:
                self.addTreeEntry(layerBranch, 'thickness roughness layer (nm)', layer.sroughThickness, self.changeSroughThickness)
                self.addTreeEntry(layerBranch, 'Haze R', layer.sroughHazeR, self.changeSroughHazeR)
                self.addTreeEntry(layerBranch, 'Haze T', layer.sroughHazeT, self.changeSroughHazeT)
            if layer.criSource=='constant':
                self.addTreeEntry(layerBranch, 'constant n', layer.criConstant[0], self.changeConstantn)
                self.addTreeEntry(layerBranch, 'constant k', layer.criConstant[1], self.changeConstantk)
            if layer.criSource=='graded' and layer.criGrading['mode']=='constant':
                self.addTreeEntry(layerBranch, 'constant grading', layer.criGrading['value'], self.changeConstantGrading)
            if layer.criSource=='dielectric function':
                criBranch = QStandardItem('dielectric function parameters')
                layerBranch.appendRow(criBranch)
                self.addTreeEntry(criBranch, 'e0', layer.dielectricFunction['e0'],  self.changeConstante, level = 2)
                for idx, oscillator in enumerate(layer.dielectricFunction['oscillators']):
                    osciBranch = QStandardItem('{} {}'.format(idx, oscillator['name']))
                    criBranch.appendRow(osciBranch)
                    parameterNames = MODELS[oscillator['name']]['parameter']
                    for i, value in enumerate(oscillator['values']):
                        self.addTreeEntry(osciBranch, parameterNames[i], value, self.changeOscillator, level = 3)
            if layer.collection['source'] == 'from collection function' and layer.collection['mode'] == 'constant':
                self.addTreeEntry(layerBranch, 'constant collection efficiency', layer.collection['value'], self.changeConstantCollection)
            if layer.collection['source'] == 'from diffusion length':
                collectionBranch = QStandardItem('collection model')
                layerBranch.appendRow(collectionBranch)
                self.addTreeEntry(collectionBranch, 'space charge region width (nm)', layer.collection['SCRwidth'],  self.changeSCR, level = 2)
                self.addTreeEntry(collectionBranch, 'diffusion length (nm)', layer.collection['diffLength'], self.changeDiffL, level = 2)
                self.addTreeEntry(collectionBranch, 'recombination velocity (cm/s)', layer.collection['recVel'], self.changerecVel, level = 2)
        
        self.parameterTreeView.setColumnWidth(1, 80)
        self.parameterTreeView.header().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.parameterTreeView.expandAll()

    def addTreeEntry(self, parent, name, parameter, func, level = 1):
        child = QStandardItem(name)
        child.setCheckable(True)
        value = QStandardItem(str(parameter))
        parent.appendRow([child, value])
        
        if level == 3:
            osciNum = parent.parent().rowCount() - 2
            itemNum = parent.rowCount() - 1
            self.parameterList.append([parameter, func, osciNum, itemNum])
        else:
            self.parameterList.append([parameter, func])
            
            
    def getSelectedValues(self):
        selected = [] # name, layer number, initial value, function to change
        i = 0
        for row in range(self.parameterModel.rowCount()):
            layer = self.parameterModel.item(row)
            for row1 in range(layer.rowCount()):
                child1 = layer.child(row1)
                if not child1.hasChildren():
                    if child1.checkState() == Qt.Checked:
                        selected.append([child1.text(), row, self.parameterList[i][0], self.parameterList[i][1]])
                    i += 1
                else:
                    for row2 in range(child1.rowCount()):
                        child2 = child1.child(row2)
                        if not child2.hasChildren():
                            if child2.checkState() == Qt.Checked:
                                selected.append([child2.text(), row, self.parameterList[i][0], self.parameterList[i][1]])
                            i += 1
                        else:
                            for row3 in range(child2.rowCount()):
                                child3 = child2.child(row3)
                                if child3.checkState() == Qt.Checked:
                                    selected.append([child3.text(), row, self.parameterList[i][0], self.parameterList[i][1], self.parameterList[i][2], self.parameterList[i][3]])
                                i += 1
        return selected
    
    @pyqtSlot()
    def on_testPB_clicked(self):
        selected = self.getSelectedValues()
        str = ''
        #print(selected)
        for item in selected:
            str += '{} {}\n'.format(item[0], item[1]) 
            self.resultTextEdit.setText(str)
        self.plot()
        if selected:
            layer = selected[0][1]
            func = selected[0][2]
            value = 250
            func(layer, value)
            #print(self.parameterList)
            #self.parameterList[0][0] = 300
            #print('stack {}'.format(self.stack[0].thickness))
            
            
    def runOptics(self):
        input = LayerStack(self.StackName, self.stack, self.settings, self.getCRI)
        self.optics = Optics(self.StackName, input, self.references, self.settings)
        self.optics.calcStack()
        self.optics.createReferenceCurves()
        self.optics.calcFieldIntensity()
        self.optics.calcAbsorption()
        self.optics.calcQE()
        self.optics.calcEllipsometry()
        #get reference data
        self.referenceData = {}
        
        for ref in self.referenceList:
            if ref[0] == 'R reference':
                self.referenceData['R reference'] = self.optics.R_reference
            elif ref[0] == 'T reference':
                self.referenceData['T reference'] = self.optics.T_reference
            elif ref[0] == 'EQE reference':
                 self.referenceData['EQE reference'] = self.optics.EQE_reference
            elif ref[0] == 'psi reference':
                self.referenceData['psi reference'] = self.optics.psi_reference
            elif ref[0] == 'delta reference':
                self.referenceData['delta reference'] = self.optics.delta_reference

        
    @pyqtSlot()
    def on_startFittingPB_clicked(self):
        if not self.referenceDataSelected:
            QMessageBox.warning(self, "error", 'Error - no reference curve selected!\n',
                QMessageBox.StandardButtons(QMessageBox.Close))
            return
            
        parameterList = self.getSelectedValues()
        if not parameterList:
            QMessageBox.warning(self, "error", 'Error - no fitting parameter selected!\n',
                QMessageBox.StandardButtons(QMessageBox.Close))
            return
        self.resultTextEdit.setPlainText("")
               
        start_time = time.time()

        #get initial deviation
            
        #get initial values
        parameters = []
        for item in parameterList:
            parameters.append(item[2])
        # run fitting
        try:
            self.resultTextEdit.setText("busy fitting ...")
            minResult = minimize(self.minimizeFunction, parameters, args = (parameterList),
                                    method= self.configuration['method'], tol=self.configuration['tolerance'], 
                                    options = {'maxiter' : self.configuration['noOfIterations']}) #, tol=1e-6
        except RuntimeError as e:
            QMessageBox.warning(self, "fitting error", 'Error - curve fitting failed!\n{}'.format(e.args[0]),
                QMessageBox.StandardButtons(QMessageBox.Close))
            return
        
        # run all optics to get other curves when references are changed
        self.runOptics()
        # to make sure at least the last result is plotted
        self.updatePlot()
        
        duration = time.time() - start_time
        message = "The optimized parameters are:\n"
        for i, item in enumerate(parameterList):
            message += "{} of {} --> {}\n".format(item[0], self.stack[item[1]].name, minResult.x[i])
        message += "Details: {}\nNumber of Iterations: {}\nNumber of function calls: {}\nChi-square: {:7.4f}\nFitting time: {:7.2f} seconds".format(
                            minResult.message, minResult.nit, minResult.nfev, minResult.fun, duration)
        self.resultTextEdit.setText(message)
        self.fillParameterTree()
        #logging.info('\n' + 50 * '#' + '\n' + message + '\n do final calculation ...\n' + 50 * '#')

    def minimizeFunction(self, values, parameterList):
        #set the parameters
        for i, value in enumerate(values):
            layer = parameterList[i][1]
            func = parameterList[i][3]
            if func == self.changeOscillator:
                osciNum = parameterList[i][4]
                itemNum = parameterList[i][5]
                func(layer, osciNum, itemNum, value)
            else:
                func(layer, value)
        input = LayerStack(self.StackName, self.stack, self.settings, self.getCRI)
        self.optics = Optics(self.StackName, input, self.references, self.settings)
        self.optics.calcStack()
        #print(len(self.referenceDataSelected))
        errorArray = np.zeros(len(self.optics.wavelength))
        for key, exp in self.referenceDataSelected.items():
            if key == 'R reference':
                model = self.optics.RspectrumSystem
                errorArray += ((model - exp)/exp)**2
            elif key == 'T reference':
                model = self.optics.TspectrumSystem
                errorArray += ((model - exp)/exp)**2
            elif key == 'EQE reference':
                self.optics.calcFieldIntensity()
                self.optics.calcAbsorption()
                self.optics.calcQE()
                model = self.optics.EQE
                errorArray += ((model - exp)/exp)**2
            elif key == 'psi reference':
                self.optics.calcEllipsometry()
                model = self.optics.psi
                errorArray += ((model - exp)/exp)**2
            elif key == 'delta reference':
                self.optics.calcEllipsometry()
                model = self.optics.delta
                errorArray += ((model - exp)/exp)**2
        #N = len(errorArray)
        #M = len(parameterList)
        if self.configuration['plotInBetween']:
            self.updatePlot()
        return np.sum(errorArray) # chi² or MSE = 1/(2N-M) * chi² 
        
    @pyqtSlot(str)
    def on_methodCB_currentIndexChanged(self, p0):
       self.configuration['method'] = p0
       
    @pyqtSlot(int)
    def on_noOfIterationsSB_valueChanged(self, p0):
        self.configuration['noOfIterations'] = p0

    def changeThickness(self, layer, value):
        self.stack[layer].thickness = int(value)
        
    def changeSroughThickness(self, layer, value):
        self.stack[layer].sroughThickness = int(value)
        
    def changeSroughHazeR(self, layer, value):
        self.stack[layer].sroughHazeR = value
        
    def changeSroughHazeT(self, layer, value):
        self.stack[layer].sroughHazeT = value
        
    def changeConstantn(self, layer, value):
        self.stack[layer].criConstant[0] = value
        
    def changeConstantk(self, layer, value):
        self.stack[layer].criConstant[1] = value
        
    def changeConstantGrading(self, layer, value):
         self.stack[layer].criGrading['value'] = value
         
    def changeConstante(self, layer, value):
        self.stack[layer].dielectricFunction['e0'] = value
        e1, e2, self.stack[layer].dielectricFunction, eV = calcOsciFunction(self.stack[layer].dielectricFunction)
        
    def changeConstantCollection(self, layer, value):
         self.stack[layer].collection['value'] = value
         self.stack[layer].makeXcollection()
         
    def changeSCR(self, layer, value):
        self.stack[layer].collection['SCRwidth'] = int(value)
        self.stack[layer].makeXcollection()
        
    def changeDiffL(self, layer, value):
        self.stack[layer].collection['diffLength'] = int(value)
        self.stack[layer].makeXcollection()
        
    def changerecVel(self, layer, value):
        self.stack[layer].collection['recVel'] = value
        self.stack[layer].makeXcollection()
        
    def changeOscillator(self, layer, osciNum, itemNum, value):
        self.stack[layer].dielectricFunction['oscillators'][osciNum]['values'][itemNum] = value
        e1, e2, self.stack[layer].dielectricFunction, eV = calcOsciFunction(self.stack[layer].dielectricFunction)
    
    @pyqtSlot()
    def on_reloadPB_clicked(self):
        self.stack = self.originalStack
        self.fillParameterTree()
    
    @pyqtSlot(float)
    def on_toleranceSB_valueChanged(self, p0):
        self.configuration['tolerance'] = p0
    
    @pyqtSlot(bool)
    def on_plotInBetweenCB_toggled(self, checked):
        self.configuration['plotInBetween'] = checked
예제 #39
0
class ProgramInfoFiles(QWidget, Ui_ProgramInfoFiles):
    def __init__(self, context, update_main_ui_state, set_widget_enabled, is_alive, show_upload_files_wizard, show_download_wizard):
        QWidget.__init__(self)

        self.setupUi(self)

        self.session                 = context.session
        self.script_manager          = context.script_manager
        self.program                 = context.program
        self.update_main_ui_state    = update_main_ui_state
        self.set_widget_enabled      = set_widget_enabled
        self.is_alive                = is_alive
        self.show_download_wizard    = show_download_wizard
        self.bin_directory           = posixpath.join(self.program.root_directory, 'bin')
        self.refresh_in_progress     = False
        self.any_refresh_in_progress = False # set from ProgramInfoMain.update_ui_state
        self.available_files         = []
        self.available_directories   = []
        self.folder_icon             = QIcon(load_pixmap('folder-icon.png'))
        self.file_icon               = QIcon(load_pixmap('file-icon.png'))
        self.tree_files_model        = QStandardItemModel(self)
        self.tree_files_model_header = ['Name', 'Size', 'Last Modified']
        self.tree_files_proxy_model  = FilesProxyModel(self)
        self.last_download_directory = get_home_path()

        self.tree_files_model.setHorizontalHeaderLabels(self.tree_files_model_header)
        self.tree_files_proxy_model.setSourceModel(self.tree_files_model)
        self.tree_files.setModel(self.tree_files_model)
        self.tree_files.setModel(self.tree_files_proxy_model)
        self.tree_files.setColumnWidth(0, 210)
        self.tree_files.setColumnWidth(1, 85)

        self.tree_files.selectionModel().selectionChanged.connect(self.update_ui_state)
        self.tree_files.activated.connect(self.rename_activated_file)
        self.button_upload_files.clicked.connect(show_upload_files_wizard)
        self.button_download_files.clicked.connect(self.download_selected_files)
        self.button_rename_file.clicked.connect(self.rename_selected_file)
        self.button_change_file_permissions.clicked.connect(self.change_permissions_of_selected_file)
        self.button_delete_files.clicked.connect(self.delete_selected_files)

        self.label_error.setVisible(False)

    def update_ui_state(self):
        selection_count = len(self.tree_files.selectionModel().selectedRows())

        self.set_widget_enabled(self.button_upload_files, not self.any_refresh_in_progress)
        self.set_widget_enabled(self.button_download_files, not self.any_refresh_in_progress and selection_count > 0)
        self.set_widget_enabled(self.button_rename_file, not self.any_refresh_in_progress and selection_count == 1)
        self.set_widget_enabled(self.button_change_file_permissions, not self.any_refresh_in_progress and selection_count == 1)
        self.set_widget_enabled(self.button_delete_files, not self.any_refresh_in_progress and selection_count > 0)

    def close_all_dialogs(self):
        pass

    def refresh_files_done(self):
        self.refresh_in_progress = False
        self.update_main_ui_state()

    def refresh_files(self):
        def cb_walk(result):
            okay, message = check_script_result(result, decode_stderr=True)

            if not okay:
                self.label_error.setText('<b>Error:</b> ' + html.escape(message))
                self.label_error.setVisible(True)
                self.refresh_files_done()
                return

            self.label_error.setVisible(False)

            def expand_async(data):
                try:
                    walk = json.loads(zlib.decompress(memoryview(data)).decode('utf-8'))
                except:
                    walk = None

                if walk == None or not isinstance(walk, dict):
                    available_files       = []
                    available_directories = []
                    walk                  = None
                else:
                    available_files, available_directories = expand_walk_to_lists(walk)

                return walk, available_files, available_directories

            def cb_expand_success(result):
                walk, available_files, available_directories = result

                self.available_files       = available_files
                self.available_directories = available_directories

                if walk != None:
                    expand_walk_to_model(walk, self.tree_files_model, self.folder_icon, self.file_icon)
                else:
                    self.label_error.setText('<b>Error:</b> Received invalid data')
                    self.label_error.setVisible(True)

                self.tree_files.header().setSortIndicator(0, Qt.AscendingOrder)
                self.refresh_files_done()

            def cb_expand_error():
                self.label_error.setText('<b>Error:</b> Internal async error')
                self.label_error.setVisible(True)
                self.refresh_files_done()

            async_call(expand_async, result.stdout, cb_expand_success, cb_expand_error)

        self.refresh_in_progress = True
        self.update_main_ui_state()

        width1 = self.tree_files.columnWidth(0)
        width2 = self.tree_files.columnWidth(1)

        self.tree_files_model.clear()
        self.tree_files_model.setHorizontalHeaderLabels(self.tree_files_model_header)
        self.tree_files.setColumnWidth(0, width1)
        self.tree_files.setColumnWidth(1, width2)

        self.script_manager.execute_script('walk', cb_walk,
                                           [self.bin_directory], max_length=1024*1024,
                                           decode_output_as_utf8=False)

    def get_directly_selected_name_items(self):
        selected_indexes    = self.tree_files.selectedIndexes()
        selected_name_items = []

        for selected_index in selected_indexes:
            if selected_index.column() == 0:
                mapped_index = self.tree_files_proxy_model.mapToSource(selected_index)
                selected_name_items.append(self.tree_files_model.itemFromIndex(mapped_index))

        return selected_name_items

    def download_selected_files(self):
        selected_name_items = self.get_directly_selected_name_items()

        if len(selected_name_items) == 0:
            return

        downloads = []

        def expand(name_item):
            item_type = name_item.data(USER_ROLE_ITEM_TYPE)

            if item_type == ITEM_TYPE_DIRECTORY:
                for i in range(name_item.rowCount()):
                    expand(name_item.child(i, 0))
            elif item_type == ITEM_TYPE_FILE:
                filename = get_full_item_path(name_item)

                downloads.append(Download(filename, QDir.toNativeSeparators(filename)))

        for selected_name_item in selected_name_items:
            expand(selected_name_item)

        if len(downloads) == 0:
            return

        download_directory = get_existing_directory(get_main_window(), 'Download Files',
                                                    self.last_download_directory)

        if len(download_directory) == 0:
            return

        self.last_download_directory = download_directory

        self.show_download_wizard('files', download_directory, downloads)

    def rename_activated_file(self, index):
        if index.column() == 0 and not self.any_refresh_in_progress:
            mapped_index = self.tree_files_proxy_model.mapToSource(index)
            name_item    = self.tree_files_model.itemFromIndex(mapped_index)
            item_type    = name_item.data(USER_ROLE_ITEM_TYPE)

            # only rename files via activation, because directories are expanded
            if item_type == ITEM_TYPE_FILE:
                self.rename_item(name_item)

    def rename_selected_file(self):
        selection_count = len(self.tree_files.selectionModel().selectedRows())

        if selection_count != 1:
            return

        selected_name_items = self.get_directly_selected_name_items()

        if len(selected_name_items) != 1:
            return

        self.rename_item(selected_name_items[0])

    def rename_item(self, name_item):
        item_type = name_item.data(USER_ROLE_ITEM_TYPE)

        if item_type == ITEM_TYPE_FILE:
            title     = 'Rename File'
            type_name = 'file'
        else:
            title     = 'Rename Directory'
            type_name = 'directory'

        old_name = name_item.text()

        # get new name
        dialog = ExpandingInputDialog(get_main_window())
        dialog.setModal(True)
        dialog.setWindowTitle(title)
        dialog.setLabelText('Enter new {0} name:'.format(type_name))
        dialog.setInputMode(QInputDialog.TextInput)
        dialog.setTextValue(old_name)
        dialog.setOkButtonText('Rename')

        if dialog.exec_() != QDialog.Accepted:
            return

        new_name = dialog.textValue()

        if new_name == old_name:
            return

        # check that new name is valid
        if len(new_name) == 0 or new_name == '.' or new_name == '..' or '/' in new_name:
            QMessageBox.critical(get_main_window(), title + ' Error',
                                 'A {0} name cannot be empty, cannot be one dot [.], cannot be two dots [..] and cannot contain a forward slash [/].'
                                 .format(type_name))
            return

        # check that new name is not already in use
        name_item_parent = name_item.parent()

        if name_item_parent == None:
            name_item_parent = self.tree_files_model.invisibleRootItem()

        for i in range(name_item_parent.rowCount()):
            if new_name == name_item_parent.child(i).text():
                QMessageBox.critical(get_main_window(), title + ' Error',
                                     'The new {0} name is already in use.'.format(type_name))
                return

        absolute_old_name = posixpath.join(self.bin_directory, get_full_item_path(name_item))
        absolute_new_name = posixpath.join(posixpath.split(absolute_old_name)[0], new_name)

        def cb_rename(result):
            if not report_script_result(result, title + ' Error', 'Could not rename {0}'.format(type_name)):
                return

            name_item.setText(new_name)

            if self.tree_files.header().sortIndicatorSection() == 0:
                self.tree_files.header().setSortIndicator(0, self.tree_files.header().sortIndicatorOrder())

        self.script_manager.execute_script('rename', cb_rename,
                                           [absolute_old_name, absolute_new_name])

    def change_permissions_of_selected_file(self):
        selection_count = len(self.tree_files.selectionModel().selectedRows())

        if selection_count != 1:
            return

        selected_name_items = self.get_directly_selected_name_items()

        if len(selected_name_items) != 1:
            return

        name_item = selected_name_items[0]
        item_type = name_item.data(USER_ROLE_ITEM_TYPE)
        old_permissions = name_item.data(USER_ROLE_PERMISSIONS)

        if item_type == ITEM_TYPE_FILE:
            title     = 'Change File Permissions'
            type_name = 'file'
        else:
            title     = 'Change Directory Permissions'
            type_name = 'directory'

        dialog = ProgramInfoFilesPermissions(get_main_window(), title, old_permissions)

        if dialog.exec_() != QDialog.Accepted:
            return

        new_permissions = dialog.get_permissions()

        if new_permissions == (old_permissions & 0o777):
            return

        absolute_name = posixpath.join(self.bin_directory, get_full_item_path(name_item))

        def cb_change_permissions(result):
            if not report_script_result(result, title + ' Error', 'Could change {0} permissions'.format(type_name)):
                return

            name_item.setData(new_permissions, USER_ROLE_PERMISSIONS)

        self.script_manager.execute_script('change_permissions', cb_change_permissions,
                                           [absolute_name, str(new_permissions)])

    def delete_selected_files(self):
        button = QMessageBox.question(get_main_window(), 'Delete Files',
                                      'Irreversibly deleting selected files and directories.',
                                      QMessageBox.Ok, QMessageBox.Cancel)

        if not self.is_alive() or button != QMessageBox.Ok:
            return

        selected_name_items = self.get_directly_selected_name_items()

        if len(selected_name_items) == 0:
            return

        script_instance_ref = [None]

        def progress_canceled():
            script_instance = script_instance_ref[0]

            if script_instance == None:
                return

            self.script_manager.abort_script(script_instance)

        progress = ExpandingProgressDialog(self)
        progress.set_progress_text_visible(False)
        progress.setModal(True)
        progress.setWindowTitle('Delete Files')
        progress.setLabelText('Collecting files and directories to delete')
        progress.setRange(0, 0)
        progress.canceled.connect(progress_canceled)
        progress.show()

        files_to_delete = []
        dirs_to_delete  = []
        all_done        = False

        while not all_done:
            all_done = True

            for selected_name_item in list(selected_name_items):
                item_done = False
                parent = selected_name_item.parent()

                while not item_done and parent != None:
                    if parent in selected_name_items:
                        selected_name_items.remove(selected_name_item)
                        item_done = True
                    else:
                        parent = parent.parent()

                if item_done:
                    all_done = False
                    break

        for selected_name_item in selected_name_items:
            path      = get_full_item_path(selected_name_item)
            item_type = selected_name_item.data(USER_ROLE_ITEM_TYPE)

            if item_type == ITEM_TYPE_DIRECTORY:
                dirs_to_delete.append(posixpath.join(self.bin_directory, path))
            else:
                files_to_delete.append(posixpath.join(self.bin_directory, path))

        message = 'Deleting '

        if len(files_to_delete) == 1:
            message += '1 file '
        elif len(files_to_delete) > 1:
            message += '{0} files '.format(len(files_to_delete))

        if len(dirs_to_delete) == 1:
            if len(files_to_delete) > 0:
                message += 'and '

            message += '1 directory'
        elif len(dirs_to_delete) > 1:
            if len(files_to_delete) > 0:
                message += 'and '

            message += '{0} directories'.format(len(dirs_to_delete))

        progress.setLabelText(message)

        def cb_delete(result):
            script_instance = script_instance_ref[0]

            if script_instance != None:
                aborted = script_instance.abort
            else:
                aborted = False

            script_instance_ref[0] = None

            progress.cancel()
            self.refresh_files()

            if aborted:
                QMessageBox.information(get_main_window(), 'Delete Files',
                                        'Delete operation was aborted.')
                return

            report_script_result(result, 'Delete Files Error', 'Could not delete selected files/directories:')

        script_instance_ref[0] = self.script_manager.execute_script('delete', cb_delete,
                                                                    [json.dumps(files_to_delete), json.dumps(dirs_to_delete)],
                                                                    execute_as_user=True)
예제 #40
0
class SetupDialog(QDialog, Ui_SetupDialog):
    """
        Function and Event handling class for the Ui_SetupDialog.
    """

    def __init__(self, parent, host_infos):
        QDialog.__init__(self, parent, get_modeless_dialog_flags())

        self._gui_logger = GUILogger("GUILogger", logging.INFO)
        self._gui_job = None
        EventLogger.add_logger(self._gui_logger)

        self.data_logger_thread = None
        self.tab_debug_warning = False
        self.device_dialog = None
        self.last_host_index = -1

        self.setupUi(self)

        self.model_data = QStandardItemModel(self)
        self.model_data.setHorizontalHeaderLabels(['Time', 'Name', 'UID', 'Var', 'Raw', 'Unit'])
        self.table_data.setModel(self.model_data)
        self.table_data.setColumnWidth(0, 160)
        self.table_data.setColumnWidth(1, 170)
        self.table_data.setColumnWidth(2, 50)
        self.table_data.setColumnWidth(3, 110)
        self.table_data.setColumnWidth(4, 70)
        self.table_data.setColumnWidth(5, 100)

        self.model_devices = QStandardItemModel(self)
        self.model_devices.setHorizontalHeaderLabels(['Device', 'Value'])
        self.tree_devices.setModel(self.model_devices)
        self.tree_devices.setColumnWidth(0, 300)

        self.signal_initialization()

        self.check_authentication.stateChanged.connect(self.authentication_state_changed)
        self.label_secret.hide()
        self.edit_secret.hide()
        self.edit_secret.setEchoMode(QLineEdit.Password)
        self.check_secret_show.hide()
        self.check_secret_show.stateChanged.connect(self.secret_show_state_changed)

        self.btn_start_logging.setIcon(QIcon(load_pixmap('data_logger/start-icon.png')))

        self.example_timestamp = time.time()

        self.edit_csv_file_name.setText(os.path.join(get_home_path(), 'logger_data_{0}.csv'.format(int(self.example_timestamp))))
        self.edit_log_file_name.setText(os.path.join(get_home_path(), 'logger_debug_{0}.log'.format(int(self.example_timestamp))))

        self.combo_data_time_format.addItem(utils.timestamp_to_de(self.example_timestamp) + ' (DD.MM.YYYY HH:MM:SS)', 'de')
        self.combo_data_time_format.addItem(utils.timestamp_to_de_msec(self.example_timestamp) + ' (DD.MM.YYYY HH:MM:SS,000)', 'de-msec')
        self.combo_data_time_format.insertSeparator(self.combo_data_time_format.count())
        self.combo_data_time_format.addItem(utils.timestamp_to_us(self.example_timestamp) + ' (MM/DD/YYYY HH:MM:SS)', 'us')
        self.combo_data_time_format.addItem(utils.timestamp_to_us_msec(self.example_timestamp) + ' (MM/DD/YYYY HH:MM:SS.000)', 'us-msec')
        self.combo_data_time_format.insertSeparator(self.combo_data_time_format.count())
        self.combo_data_time_format.addItem(utils.timestamp_to_iso(self.example_timestamp) + ' (ISO 8601)', 'iso')
        self.combo_data_time_format.addItem(utils.timestamp_to_iso_msec(self.example_timestamp) + ' (ISO 8601 + Milliseconds)', 'iso-msec')
        self.combo_data_time_format.insertSeparator(self.combo_data_time_format.count())
        self.combo_data_time_format.addItem(utils.timestamp_to_unix(self.example_timestamp) + ' (Unix)', 'unix')
        self.combo_data_time_format.addItem(utils.timestamp_to_unix_msec(self.example_timestamp) + ' (Unix + Milliseconds)', 'unix-msec')
        self.combo_data_time_format.insertSeparator(self.combo_data_time_format.count())

        t = utils.timestamp_to_strftime(self.example_timestamp, self.edit_data_time_format_strftime.text())
        if len(t) == 0:
            t = '<empty>'

        self.combo_data_time_format.addItem((t + ' (strftime)'), 'strftime')

        self.combo_debug_time_format.addItem(utils.timestamp_to_de(self.example_timestamp) + ' (DD.MM.YYYY HH:MM:SS)', 'de')
        self.combo_debug_time_format.addItem(utils.timestamp_to_us(self.example_timestamp) + ' (MM/DD/YYYY HH:MM:SS)', 'us')
        self.combo_debug_time_format.addItem(utils.timestamp_to_iso(self.example_timestamp) + ' (ISO 8601)', 'iso')
        self.combo_debug_time_format.addItem(utils.timestamp_to_unix(self.example_timestamp) + ' (Unix)', 'unix')

        self.combo_log_level.addItem('Debug', 'debug')
        self.combo_log_level.addItem('Info', 'info')
        self.combo_log_level.addItem('Warning', 'warning')
        self.combo_log_level.addItem('Error', 'error')
        self.combo_log_level.addItem('Critical', 'critical')
        self.combo_log_level.setCurrentIndex(0) # debug

        self.combo_debug_level.addItem('Debug', logging.DEBUG)
        self.combo_debug_level.addItem('Info', logging.INFO)
        self.combo_debug_level.addItem('Warning', logging.WARNING)
        self.combo_debug_level.addItem('Error', logging.ERROR)
        self.combo_debug_level.addItem('Critical', logging.CRITICAL)
        self.combo_debug_level.setCurrentIndex(1) # info

        for host_info in host_infos:
            self.combo_host.addItem(host_info.host, (host_info.port, host_info.use_authentication, host_info.secret))

        self._host_index_changed(0)

        self.update_ui_state()

    def update_ui_state(self):
        index = self.combo_data_time_format.currentIndex()

        if index > 0:
            time_format = self.combo_data_time_format.itemData(index)
        else:
            time_format = 'unknown'

        data_to_csv_file = self.check_data_to_csv_file.isChecked()
        debug_to_log_file = self.check_debug_to_log_file.isChecked()

        self.edit_data_time_format_strftime.setVisible(time_format == 'strftime')
        self.label_data_time_format_strftime_help.setVisible(time_format == 'strftime')

        self.label_csv_file_name.setVisible(data_to_csv_file)
        self.edit_csv_file_name.setVisible(data_to_csv_file)
        self.btn_browse_csv_file_name.setVisible(data_to_csv_file)

        self.label_log_file_name.setVisible(debug_to_log_file)
        self.edit_log_file_name.setVisible(debug_to_log_file)
        self.btn_browse_log_file_name.setVisible(debug_to_log_file)
        self.label_log_level.setVisible(debug_to_log_file)
        self.combo_log_level.setVisible(debug_to_log_file)

    def signal_initialization(self):
        """
            Init of all important Signals and connections.
        """
        # Buttons
        self.btn_start_logging.clicked.connect(self.btn_start_logging_clicked)
        self.btn_save_config.clicked.connect(self.btn_save_config_clicked)
        self.btn_load_config.clicked.connect(self.btn_load_config_clicked)
        self.combo_data_time_format.currentIndexChanged.connect(self.update_ui_state)
        self.edit_data_time_format_strftime.textChanged.connect(self.edit_data_time_format_strftime_changed)
        self.check_data_to_csv_file.stateChanged.connect(self.update_ui_state)
        self.check_debug_to_log_file.stateChanged.connect(self.update_ui_state)
        self.btn_browse_csv_file_name.clicked.connect(self.btn_browse_csv_file_name_clicked)
        self.btn_browse_log_file_name.clicked.connect(self.btn_browse_log_file_name_clicked)
        self.btn_clear_debug.clicked.connect(self.btn_clear_debug_clicked)
        self.combo_debug_level.currentIndexChanged.connect(self.combo_debug_level_changed)
        self.btn_add_device.clicked.connect(self.btn_add_device_clicked)
        self.btn_remove_device.clicked.connect(self.btn_remove_device_clicked)
        self.btn_remove_all_devices.clicked.connect(self.btn_remove_all_devices_clicked)

        self.tab_widget.currentChanged.connect(self.tab_reset_warning)
        self.btn_clear_data.clicked.connect(self.btn_clear_data_clicked)

        self._gui_logger.newEventMessage.connect(self.add_debug_message)
        self._gui_logger.newEventTabHighlight.connect(self.highlight_debug_tab)

        self.combo_host.currentIndexChanged.connect(self._host_index_changed)

    def btn_start_logging_clicked(self):
        """
            Start/Stop of the logging process
        """
        if (self.data_logger_thread is not None) and (not self.data_logger_thread.stopped):
            self.btn_start_logging.clicked.disconnect()

            self.data_logger_thread.stop()
            self._reset_stop()

        elif self.data_logger_thread is None:
            from brickv.data_logger import main

            self._gui_job = GuiDataJob(name="GuiData-Writer")

            self._gui_job.signalNewData.connect(self.table_add_row)

            self.data_logger_thread = main.main(None, GuiConfigHandler.create_config(self), self._gui_job, None, None, None)

            if self.data_logger_thread is not None:
                self.btn_start_logging.setText("Stop Logging")
                self.btn_start_logging.setIcon(QIcon(load_pixmap('data_logger/stop-icon.png')))
                self.tab_devices.setEnabled(False)
                self.tab_setup.setEnabled(False)
                self.tab_widget.setCurrentIndex(self.tab_widget.indexOf(self.tab_data))
                self.tab_reset_warning()

    def _reset_stop(self):
        self.tab_devices.setEnabled(True)
        self.tab_setup.setEnabled(True)
        self.btn_start_logging.setText("Start Logging")
        self.btn_start_logging.setIcon(QIcon(load_pixmap('data_logger/start-icon.png')))


        self._gui_job.signalNewData.disconnect(self.table_add_row)
        self.data_logger_thread = None
        self._gui_job = None

        self.btn_start_logging.clicked.connect(self.btn_start_logging_clicked)

    def authentication_state_changed(self, state):
        visible = state == Qt.Checked

        self.label_secret.setVisible(visible)
        self.edit_secret.setVisible(visible)
        self.check_secret_show.setVisible(visible)

    def secret_show_state_changed(self, state):
        if state == Qt.Checked:
            self.edit_secret.setEchoMode(QLineEdit.Normal)
        else:
            self.edit_secret.setEchoMode(QLineEdit.Password)

    def edit_data_time_format_strftime_changed(self):
        index = self.combo_data_time_format.findData('strftime')

        if index < 0:
            return

        t = utils.timestamp_to_strftime(self.example_timestamp, self.edit_data_time_format_strftime.text())
        if len(t) == 0:
            t = '<empty>'

        self.combo_data_time_format.setItemText(index, (t + ' (strftime)'))

        if self.edit_data_time_format_strftime.isVisible():
            self.edit_data_time_format_strftime.setFocus()

    def btn_save_config_clicked(self):
        filename = get_save_file_name(self, 'Save Config',
                                      get_home_path(), 'JSON Files (*.json)')

        if len(filename) == 0:
            return

        if not filename.lower().endswith('.json'):
            filename += '.json'

        config = GuiConfigHandler.create_config(self)

        if not save_config(config, filename):
            QMessageBox.warning(self, 'Save Config',
                                'Could not save config to file! See Debug tab for details.',
                                QMessageBox.Ok)

    def btn_load_config_clicked(self):
        filename = get_open_file_name(self, 'Load Config',
                                      get_home_path(), 'JSON Files (*.json)')

        if len(filename) == 0:
            return

        config = load_and_validate_config(filename)

        if config == None:
            QMessageBox.warning(self, 'Load Config',
                                'Could not load config from file! See Debug tab for details.',
                                QMessageBox.Ok)
            return

        self.update_setup_tab(config)
        self.update_devices_tab(config)

    def btn_browse_csv_file_name_clicked(self):
        if len(self.edit_csv_file_name.text()) > 0:
            last_dir = os.path.dirname(os.path.realpath(self.edit_csv_file_name.text()))
        else:
            last_dir = get_home_path()

        filename = get_save_file_name(self, 'Choose CSV File',
                                      last_dir, "CSV Files (*.csv)")

        if len(filename) > 0:
            if not filename.lower().endswith('.csv'):
                filename += '.csv'

            self.edit_csv_file_name.setText(filename)

    def btn_browse_log_file_name_clicked(self):
        if len(self.edit_log_file_name.text()) > 0:
            last_dir = os.path.dirname(os.path.realpath(self.edit_log_file_name.text()))
        else:
            last_dir = get_home_path()

        filename = get_save_file_name(self, 'Choose Log File',
                                      last_dir, "Log Files (*.log)")

        if len(filename) > 0:
            if not filename.lower().endswith('.log'):
                filename += '.log'

            self.edit_log_file_name.setText(filename)

    def btn_add_device_clicked(self):
        """
            Opens the DeviceDialog in Add-Mode.
        """
        if self.device_dialog is None:
            self.device_dialog = DeviceDialog(self)

        self.device_dialog.btn_refresh_clicked()
        self.device_dialog.show()

    def btn_remove_device_clicked(self):
        selection = self.tree_devices.selectionModel().selectedIndexes()

        while len(selection) > 0:
            index = selection[0]

            while index.parent() != self.model_devices.invisibleRootItem().index():
                index = index.parent()

            self.model_devices.removeRows(index.row(), 1)

            # get new selection, because row removal might invalid indices
            selection = self.tree_devices.selectionModel().selectedIndexes()

    def btn_remove_all_devices_clicked(self):
        self.model_devices.removeRows(0, self.model_devices.rowCount())

    def btn_clear_data_clicked(self):
        self.model_data.removeRows(0, self.model_data.rowCount())

    def tab_reset_warning(self):
        """
            Resets the Warning @ the debug tab.
        """
        if not self.tab_debug_warning or self.tab_widget.currentIndex() != self.tab_widget.indexOf(self.tab_debug):
            return

        self.tab_debug_warning = False

        self.tab_set(self.tab_widget.indexOf(self.tab_debug), self.palette().color(QPalette.WindowText), None)

    def combo_debug_level_changed(self):
        """
            Changes the log level dynamically.
        """
        self._gui_logger.level = self.combo_debug_level.itemData(self.combo_debug_level.currentIndex())

    def tab_set(self, tab_index, color, icon=None):
        """
            Sets the font Color and an icon, if given, at a specific tab.
        """
        self.tab_widget.tabBar().setTabTextColor(tab_index, color)
        if icon is not None:
            self.tab_widget.setTabIcon(tab_index, QIcon(icon))
        else:
            self.tab_widget.setTabIcon(tab_index, QIcon())

    def _host_index_changed(self, i):
        if self.last_host_index >= 0:
            self.combo_host.setItemData(self.last_host_index,
                                        (self.spin_port.value(),
                                         self.check_authentication.isChecked(),
                                         self.edit_secret.text()))

        self.last_host_index = i

        if i < 0:
            return

        host_info = self.combo_host.itemData(i)

        self.spin_port.setValue(host_info[0])
        self.check_authentication.setChecked(host_info[1])
        self.edit_secret.setText(host_info[2])

    def update_setup_tab(self, config):
        EventLogger.debug('Updating setup tab from config')

        name = config['hosts']['default']['name']
        port = config['hosts']['default']['port']
        secret = config['hosts']['default']['secret']

        i = self.combo_host.findText(name)
        if i >= 0:
            self.combo_host.setCurrentIndex(i)
        else:
            self.combo_host.insertItem(0, name, (port, secret != None, secret))
            self.combo_host.setCurrentIndex(0)

        self.spin_port.setValue(port)

        self.check_authentication.setChecked(secret != None)
        self.edit_secret.setText(secret if secret != None else '')

        self.combo_data_time_format.setCurrentIndex(max(self.combo_data_time_format.findData(config['data']['time_format']), 0))
        self.edit_data_time_format_strftime.setText(config['data']['time_format_strftime'])
        self.check_data_to_csv_file.setChecked(config['data']['csv']['enabled'])
        self.edit_csv_file_name.setText(config['data']['csv']['file_name'])

        self.combo_debug_time_format.setCurrentIndex(max(self.combo_debug_time_format.findData(config['debug']['time_format']), 0))
        self.check_debug_to_log_file.setChecked(config['debug']['log']['enabled'])
        self.edit_log_file_name.setText(config['debug']['log']['file_name'])
        self.combo_log_level.setCurrentIndex(max(self.combo_debug_time_format.findData(config['debug']['log']['level']), 0))

    def update_devices_tab(self, config):
        EventLogger.debug('Updating devices tab from config')

        self.model_devices.removeRows(0, self.model_data.rowCount())

        for device in config['devices']:
            self.add_device_to_tree(device)

    def add_device_to_tree(self, device):
        # check if device is already added
        if len(device['uid']) > 0:
            for row in range(self.model_devices.rowCount()):
                existing_name = self.model_devices.item(row, 0).text()
                exisitng_uid = self.tree_devices.indexWidget(self.model_devices.item(row, 1).index()).text()

                if device['name'] == existing_name and device['uid'] == exisitng_uid:
                    EventLogger.info('Ignoring duplicate device "{0}" with UID "{1}"'
                                     .format(device['name'], device['uid']))
                    return

        # add device
        name_item = QStandardItem(device['name'])
        uid_item = QStandardItem('')

        self.model_devices.appendRow([name_item, uid_item])

        edit_uid = QLineEdit()
        edit_uid.setPlaceholderText('Enter UID')
        edit_uid.setValidator(QRegExpValidator(QRegExp('^[{0}]{{1,6}}$'.format(BASE58)))) # FIXME: use stricter logic
        edit_uid.setText(device['uid'])

        self.tree_devices.setIndexWidget(uid_item.index(), edit_uid)

        value_specs = device_specs[device['name']]['values']
        parent_item = QStandardItem('Values')

        name_item.appendRow([parent_item, QStandardItem('')])
        self.tree_devices.expand(parent_item.index())

        # add values
        for value_spec in value_specs:
            value_name_item = QStandardItem(value_spec['name'])
            value_interval_item = QStandardItem('')

            parent_item.appendRow([value_name_item, value_interval_item])

            spinbox_interval = IntervalWidget()
            spinbox_interval.set_interval(device['values'][value_spec['name']]['interval'])

            self.tree_devices.setIndexWidget(value_interval_item.index(), spinbox_interval)

            if value_spec['subvalues'] != None:
                for subvalue_name in value_spec['subvalues']:
                    subvalue_name_item = QStandardItem(subvalue_name)
                    subvalue_check_item = QStandardItem('')

                    value_name_item.appendRow([subvalue_name_item, subvalue_check_item])

                    check_subvalue = QCheckBox()
                    check_subvalue.setChecked(device['values'][value_spec['name']]['subvalues'][subvalue_name])

                    self.tree_devices.setIndexWidget(subvalue_check_item.index(), check_subvalue)

        self.tree_devices.expand(name_item.index())

        # add options
        option_specs = device_specs[device['name']]['options']

        if option_specs != None:
            parent_item = QStandardItem('Options')

            name_item.appendRow([parent_item, QStandardItem('')])

            for option_spec in option_specs:
                option_name_item = QStandardItem(option_spec['name'])
                option_widget_item = QStandardItem('')

                parent_item.appendRow([option_name_item, option_widget_item])

                if option_spec['type'] == 'choice':
                    widget_option_value = QComboBox()

                    for option_value_spec in option_spec['values']:
                        widget_option_value.addItem(option_value_spec[0], option_value_spec[1])

                    widget_option_value.setCurrentIndex(widget_option_value.findText(device['options'][option_spec['name']]['value']))
                elif option_spec['type'] == 'int':
                    widget_option_value = QSpinBox()
                    widget_option_value.setRange(option_spec['minimum'], option_spec['maximum'])
                    widget_option_value.setSuffix(option_spec['suffix'])
                    widget_option_value.setValue(device['options'][option_spec['name']]['value'])
                elif option_spec['type'] == 'bool':
                    widget_option_value = QCheckBox()
                    widget_option_value.setChecked(device['options'][option_spec['name']]['value'])

                self.tree_devices.setIndexWidget(option_widget_item.index(), widget_option_value)

    def add_debug_message(self, message):
        self.text_debug.append(message)

        while self.text_debug.document().blockCount() > 1000:
            cursor = QTextCursor(self.text_debug.document().begin())
            cursor.select(QTextCursor.BlockUnderCursor)
            cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor)
            cursor.removeSelectedText()

        if self.checkbox_debug_auto_scroll.isChecked():
            self.text_debug.verticalScrollBar().setValue(self.text_debug.verticalScrollBar().maximum())

    def btn_clear_debug_clicked(self):
        self.text_debug.clear()

    def highlight_debug_tab(self):
        """
            SIGNAL function:
            Highlight the debug tab when an error occurs.
        """
        if not self.tab_debug_warning and self.tab_widget.currentIndex() != self.tab_widget.indexOf(self.tab_debug):
            self.tab_debug_warning = True
            self.tab_set(self.tab_widget.indexOf(self.tab_debug), QColor(255, 0, 0),
                         get_resources_path("warning-icon-16.png"))

    def table_add_row(self, csv_data):
        """
            SIGNAL function:
            Adds new CSV Data into the Table.
        """
        rows = self.model_data.rowCount()

        while rows >= 1000:
            self.model_data.removeRow(0)
            rows = self.model_data.rowCount()

        row_number = None

        if rows > 0:
            try:
                row_number = int(self.model_data.headerData(rows - 1, Qt.Vertical))
            except ValueError:
                pass

        self.model_data.appendRow([QStandardItem(csv_data.timestamp),
                                   QStandardItem(csv_data.name),
                                   QStandardItem(csv_data.uid),
                                   QStandardItem(csv_data.var_name),
                                   QStandardItem(str(csv_data.raw_data)),
                                   QStandardItem(csv_data.var_unit)])

        if row_number != None:
            self.model_data.setHeaderData(rows, Qt.Vertical, str(row_number + 1))

        if self.checkbox_data_auto_scroll.isChecked():
            self.table_data.scrollToBottom()