def __set_name(self, index: int): """Load the parameters of the link.""" if not self.name_box.isEnabled(): return if len(self.vlinks) > index: vlink = self.vlinks[index] self.name_edit.setText(vlink.name) color_text = vlink.colorSTR color_index = self.color_box.findText(color_text) if color_index > -1: self.color_box.setCurrentIndex(color_index) else: self.color_box.addItem(color_icon(color_text), color_text) self.color_box.setCurrentIndex(self.color_box.count() - 1) self.noSelected.clear() self.selected.clear() for p in vlink.points: self.selected.addItem( QListWidgetItem(self.point_icon, f'Point{p}')) for p in range(len(self.vpoints)): if p in vlink.points: continue self.noSelected.addItem( QListWidgetItem(self.point_icon, f'Point{p}')) not_ground = index > 0 for widget in (self.name_edit, self.color_box, self.color_pick_button): widget.setEnabled(not_ground)
def on_collection_list_currentItemChanged(self, item, p0): """Show the data of collection. Save the layout position to keep the graphs will be in same appearance. """ has_item = bool(item) self.delete_button.setEnabled(has_item) self.grounded_button.setEnabled(has_item) self.triangle_button.setEnabled(has_item) if not item: return self.selection_window.clear() item_ = QListWidgetItem(item.text()) row = self.collection_list.row(item) G = self.collections[row] self.ground_engine = self.collections_layouts[row] item_.setIcon( graph(G, self.selection_window.iconSize().width(), self.ground_engine)) self.selection_window.addItem(item_) self.Expression_edges.setText(str(list(G.edges))) self.NL.setText(str(len(G.nodes))) self.NJ.setText(str(len(G.edges))) self.DOF.setText( str(3 * (int(self.NL.text()) - 1) - 2 * int(self.NJ.text())))
def __set_name(self, index: int): """Load the parameters of the point.""" if not len(self.vpoints) > index: return vpoint = self.vpoints[index] self.x_box.setValue(vpoint.x) self.y_box.setValue(vpoint.y) color_text = vpoint.color_str color_index = self.color_box.findText(color_text) if color_index > -1: self.color_box.setCurrentIndex(color_index) else: self.color_box.addItem(color_icon(color_text), color_text) self.color_box.setCurrentIndex(self.color_box.count() - 1) self.type_box.setCurrentIndex(vpoint.type) self.angle_box.setValue(vpoint.angle) self.noSelected.clear() self.selected.clear() for linkName in vpoint.links: self.selected.addItem(QListWidgetItem(self.link_icon, linkName)) for vlink in self.vlinks: if vlink.name in vpoint.links: continue self.noSelected.addItem(QListWidgetItem(self.link_icon, vlink.name))
def addSolution(self, point: str, expr: Tuple[str]): """Add a solution.""" item = QListWidgetItem() self.Expression_list.addItem(item) item.setText("{}[{},{},{},{}]({})".format(*expr)) self.PreviewWindow.setStatus(point, True) self.hasSolution() self.setWarning(self.Expression_list_label, not self.PreviewWindow.isAllLock())
def __add_solution(self, *expr: str): """Add a solution.""" item = QListWidgetItem() self.expression_list.addItem(item) item.setText(f"{expr[0]}[{','.join(expr[1:-1])}]({expr[-1]})") self.PreviewWindow.setStatus(expr[-1], True) self.__set_parm_bind() self.__has_solution() _set_warning(self.expression_list_label, not self.PreviewWindow.isAllLock())
def __addSolution(self, *expr: Tuple[str]): """Add a solution.""" item = QListWidgetItem() self.expression_list.addItem(item) item.setText("{}[{}]({})".format(expr[0], ','.join(expr[1:-1]), expr[-1])) self.PreviewWindow.setStatus(expr[-1], True) self.__setParmBind() self.__hasSolution() self.__setWarning(self.expression_list_label, not self.PreviewWindow.isAllLock())
def __grounded(self): """Grounded combinations.""" current_item = self.collection_list.currentItem() self.collections_grounded.clear() self.grounded_list.clear() g = self.collections[self.collection_list.row(current_item)] item = QListWidgetItem("Released") icon = to_graph(g, self.grounded_list.iconSize().width(), self.ground_engine, self.graph_link_as_node.isChecked(), self.graph_show_label.isChecked(), self.is_monochrome()) item.setIcon(icon) self.collections_grounded.append(g) self.grounded_list.addItem(item) for node, graph_ in labeled_enumerate(g): item = QListWidgetItem(f"link_{node}") icon = to_graph(g, self.grounded_list.iconSize().width(), self.ground_engine, self.graph_link_as_node.isChecked(), self.graph_show_label.isChecked(), self.is_monochrome(), except_node=node) item.setIcon(icon) self.collections_grounded.append(graph_) self.grounded_list.addItem(item)
def on_grounded_button_clicked(self): """Grounded combinations.""" current_item = self.collection_list.currentItem() self.collections_grounded.clear() self.grounded_list.clear() G = self.collections[self.collection_list.row(current_item)] item = QListWidgetItem("Released") try: icon = graph(G, self.grounded_list.iconSize().width(), self.ground_engine) except EngineError as e: self.engineErrorMsg(e) return item.setIcon(icon) self.collections_grounded.append(G) self.grounded_list.addItem(item) for node in G.nodes: G_ = Graph(G) G_.remove_node(node) error = False for H in self.collections_grounded: if is_isomorphic(G_, H): error = True if error: continue item = QListWidgetItem("link_{} constrainted".format(node)) icon = graph(G, self.grounded_list.iconSize().width(), self.ground_engine, except_node=node) item.setIcon(icon) self.collections_grounded.append(G_) self.grounded_list.addItem(item) self.grounded_merge.setEnabled(bool(self.grounded_list.count()))
def on_load_button_clicked(self): """Show up the dialog to load structure data.""" dlg = CollectionsDialog(self) dlg.show() if not dlg.exec_(): return self.profile_name = dlg.name_loaded params = dlg.mechanismParams mapping = params['name_dict'] #Add customize joints. G = Graph(params['Graph']) self.setGraph(G, params['pos']) self.PreviewWindow.cus = params['cus'] self.PreviewWindow.same = params['same'] #Grounded setting. Driver = [mapping[e] for e in params['Driver']] Follower = [mapping[e] for e in params['Follower']] for row, link in enumerate(G.nodes): points = set('P{}'.format(n) for n, edge in edges_view(G) if link in edge) if set(Driver + Follower) <= points: self.grounded_list.setCurrentRow(row) break #Driver, Follower, Target for row in reversed(range(self.Follower_list.count())): if self.Follower_list.item(row).text() in Driver: self.Follower_list.setCurrentRow(row) self.Driver_add.click() self.Target_list.addItems([mapping[e] for e in params['Target']]) self.setWarning(self.Target_label, not self.Target_list.count() > 0) #Constraints self.constraint_list.addItems( [", ".join(mapping[e] for e in c) for c in params['constraint']]) #Expression for expr in params['Expression'].split(';'): params = get_from_parenthesis(expr, '[', ']').split(',') target = get_from_parenthesis(expr, '(', ')') params.append(target) for p in params: try: #Try to avoid replace function name. expr = mapping[p].join(expr.rsplit(p, 1)) except KeyError: continue item = QListWidgetItem() self.Expression_list.addItem(item) item.setText(expr) self.PreviewWindow.setStatus(mapping[target], True) self.setWarning(self.Expression_list_label, not self.PreviewWindow.isAllLock())
class AddVariable(QUndoCommand): """Add a variable to list widget.""" def __init__(self, text: str, widget: QListWidget): super(AddVariable, self).__init__() self.item = QListWidgetItem(text) self.item.setToolTip(text) self.widget = widget def redo(self): """Add to widget.""" self.widget.addItem(self.item) def undo(self): """Take out the item.""" self.widget.takeItem(self.widget.row(self.item))
def __path_dlg(self, item: QListWidgetItem): """View path data.""" name = item.text().split(":")[0] try: data = self.__path_data[name] except KeyError: return points_text = ", ".join(f"Point{i}" for i in range(len(data))) if QMessageBox.question( self, "Path data", f"This path data including {points_text}.", (QMessageBox.Save | QMessageBox.Close), QMessageBox.Close ) != QMessageBox.Save: return file_name = self.output_to( "path data", ["Comma-Separated Values (*.csv)", "Text file (*.txt)"] ) if not file_name: return with open(file_name, 'w', encoding='utf-8', newline='') as stream: writer = csv.writer(stream) for point in data: for coordinate in point: writer.writerow(coordinate) writer.writerow(()) logger.info(f"Output path data: {file_name}")
def find_in_nodes(node: QTreeWidgetItem, last_name: str = ''): """Find the word in all nodes.""" last_name += node.text(0) if node.childCount(): last_name += '->' code = int(node.text(2)) doc = self.data[code] pattern = re.compile(text.encode('utf-8'), flags) for m in pattern.finditer(doc.encode('utf-8')): start, end = m.span() item = QListWidgetItem(last_name) item.setToolTip(f"{code}:{start}:{end}") self.find_list_node[code] = node self.find_list.addItem(item) for i in range(node.childCount()): find_in_nodes(node.child(i), last_name)
def __init__(self, points: List[VPoint], links: List[VLink], pos: bool = False, parent=None): super(EditPointDialog, self).__init__(parent) self.setupUi(self) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) icon = self.windowIcon() self.LinkIcon = QIcon(QPixmap(":/icons/link.png")) self.points = points self.links = links for i, e in enumerate(colorName): self.Color.insertItem(i, colorIcons(e), e) for vlink in links: self.noSelected.addItem(QListWidgetItem(self.LinkIcon, vlink.name)) if pos is False: self.Point.addItem(icon, 'Point{}'.format(len(points))) self.Point.setEnabled(False) self.Color.setCurrentIndex(self.Color.findText('Green')) else: for i in range(len(points)): self.Point.insertItem(i, icon, 'Point{}'.format(i)) self.Point.setCurrentIndex(pos)
def __init__( self, vpoints: List[VPoint], vlinks: List[VLink], pos: bool, parent: QWidget, ): """Input data reference from main window. + Needs VPoints and VLinks information. + If row is false: Create action. """ super(EditPointDialog, self).__init__(parent) self.setupUi(self) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) icon = self.windowIcon() self.link_icon = QIcon(QPixmap(":/icons/link.png")) self.vpoints = vpoints self.vlinks = vlinks vpoints_count = len(vpoints) for i, e in enumerate(color_names): self.color_box.insertItem(i, color_icon(e), e) for vlink in vlinks: self.noSelected.addItem(QListWidgetItem(self.link_icon, vlink.name)) if pos is False: self.name_box.addItem(icon, f'Point{vpoints_count}') self.name_box.setEnabled(False) self.color_box.setCurrentIndex(self.color_box.findText('Green')) else: for i in range(vpoints_count): self.name_box.insertItem(i, icon, f'Point{i}') self.name_box.setCurrentIndex(pos)
def __init__(self, vpoints: List[VPoint], vlinks: List[VLink], row: Union[int, bool], parent: QWidget): """Input data reference from main window. + Needs VPoints and VLinks information. + If row is false: Create action. """ super(EditLinkDialog, self).__init__(parent) self.setupUi(self) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) self.vpoints = vpoints self.vlinks = vlinks icon = self.windowIcon() self.point_icon = QIcon(QPixmap(":/icons/bearing.png")) for i, e in enumerate(colorNames): self.color_box.insertItem(i, color_icon(e), e) for i in range(len(self.vpoints)): self.noSelected.addItem( QListWidgetItem(self.point_icon, f'Point{i}')) if row is False: self.name_box.addItem(icon, "New link") self.name_box.setEnabled(False) self.color_box.setCurrentIndex(self.color_box.findText('Blue')) else: for i, vlink in enumerate(self.vlinks): self.name_box.insertItem(i, icon, vlink.name) self.name_box.setCurrentIndex(row) self.name_edit.textChanged.connect(self.__is_ok) self.__is_ok()
def __addResult(self, result: Dict[str, Any]): """Add result items, except add to the list.""" item = QListWidgetItem(result['Algorithm']) interrupt = result['interrupted'] if interrupt == 'False': item.setIcon(QIcon(QPixmap(":/icons/task-completed.png"))) elif interrupt == 'N/A': item.setIcon(QIcon(QPixmap(":/icons/question-mark.png"))) else: item.setIcon(QIcon(QPixmap(":/icons/interrupted.png"))) text = "{} ({})".format( result['Algorithm'], "No interrupt." if interrupt == 'False' else "Interrupt at {}".format(interrupt)) if interrupt == 'N/A': text += "\n※Completeness is not clear." item.setToolTip(text) self.Result_list.addItem(item)
def __l_a_synthesis(self) -> List[Tuple[int, ...]]: """Synthesis of link assortments.""" self.l_a_list.clear() self.c_l_a_list.clear() try: results = number_synthesis(self.NL_input.value(), self.NJ_input.value()) except Exception as e: item = QListWidgetItem(str(e)) self.l_a_list.addItem(item) return [] else: for result in results: self.l_a_list.addItem( QListWidgetItem(", ".join(f"NL{i + 2} = {result[i]}" for i in range(len(result))))) self.l_a_list.setCurrentRow(0) return results
def on_Link_currentIndexChanged(self, index): """Load the parameters of the link.""" if len(self.links) > index: vlink = self.links[index] self.name_edit.setText(vlink.name) self.Color.setCurrentIndex(self.Color.findText(vlink.colorSTR)) self.noSelected.clear() self.selected.clear() for point in vlink.points: self.selected.addItem( QListWidgetItem(self.PointIcon, 'Point{}'.format(point))) for point in range(len(self.points)): if point in vlink.points: continue self.noSelected.addItem( QListWidgetItem(self.PointIcon, 'Point{}'.format(point))) self.name_edit.setEnabled(index > 0) self.Color.setEnabled(index > 0)
def on_Point_currentIndexChanged(self, index): """Load the parameters of the point.""" if not len(self.points) > index: return vpoint = self.points[index] self.X_coordinate.setValue(vpoint.x) self.Y_coordinate.setValue(vpoint.y) self.Color.setCurrentIndex(self.Color.findText(vpoint.colorSTR)) self.Type.setCurrentIndex(vpoint.type) self.Angle.setValue(vpoint.angle) self.noSelected.clear() self.selected.clear() for linkName in vpoint.links: self.selected.addItem(QListWidgetItem(self.LinkIcon, linkName)) for vlink in self.links: if vlink.name in vpoint.links: continue self.noSelected.addItem(QListWidgetItem(self.LinkIcon, vlink.name))
def __set_selection(self, row: int): """Show the data of collection. Save the layout position to keep the graphs will be in same appearance. """ item: Optional[QListWidgetItem] = self.collection_list.item(row) has_item = item is not None self.delete_button.setEnabled(has_item) self.configure_button.setEnabled(has_item) self.selection_window.clear() if item is None: return # Preview item. link_is_node = self.graph_link_as_node.isChecked() item_preview = QListWidgetItem(item.text()) row = self.collection_list.row(item) g = self.collections[row] self.ground_engine = self.collections_layouts[row] item_preview.setIcon( to_graph(g, self.selection_window.iconSize().width(), self.ground_engine, link_is_node, self.graph_show_label.isChecked(), self.is_monochrome())) self.selection_window.addItem(item_preview) # Set attributes. self.edges_text.setText(str(list(g.edges))) self.nl_label.setText(str(len(g.nodes))) self.nj_label.setText(str(len(g.edges))) self.dof_label.setText(str(g.dof())) self.is_degenerate_label.setText(str(g.is_degenerate())) self.link_assortment_label.setText(str(l_a(g))) self.contracted_link_assortment_label.setText(str(c_l_a(g))) # "Link as node" layout cannot do these action. self.configure_button.setEnabled(not link_is_node) self.grounded_merge.setEnabled(not link_is_node) # Automatic ground. self.__grounded()
def __c_l_a_synthesis(self, index: int = 0) -> List[Tuple[int, ...]]: """Synthesis of contracted link assortments.""" self.c_l_a_list.clear() item = self.l_a_list.item(index) if item is None: return [] results = contracted_link(_link_assortments(item.text())) for c_j in results: self.c_l_a_list.addItem( QListWidgetItem(", ".join(f"Nc{i + 1} = {c_j[i]}" for i in range(len(c_j))))) self.c_l_a_list.setCurrentRow(0) return results
def __find_results(self, item: QListWidgetItem, _: Optional[QListWidgetItem] = None): """Switch to target node.""" if item is None: return tool_tips = item.toolTip().split(':') code = int(tool_tips[0]) start = int(tool_tips[1]) end = int(tool_tips[2]) self.tree_main.setCurrentItem(self.find_list_node[code]) self.text_editor.setSelection(start, end)
def __draw_atlas(self, i: int, g: Graph) -> bool: """Draw atlas and return True if done.""" item = QListWidgetItem(f"No. {i + 1}") item.setIcon( to_graph(g, self.structure_list.iconSize().width(), self.graph_engine.currentText(), self.graph_link_as_node.isChecked())) item.setToolTip(f"Edge Set: {list(g.edges)}\n" f"Link Assortments: {l_a(g)}\n" f"Contracted Link Assortments: {c_l_a(g)}") self.structure_list.addItem(item) return True
def on_mechanism_storage_restore_clicked(self, item: QListWidgetItem = None): """Restore the storage data.""" if item is None: item = self.mechanism_storage.currentItem() if not item: return reply = QMessageBox.question( self, "Storage", "Restore mechanism will overwrite the canvas." + "\nDo you want to continue?") if reply != QMessageBox.Yes: return name = item.text() self.CommandStack.beginMacro("Restore from {{Mechanism: {}}}".format(name)) _clearStorage(self) self.parseExpression(item.expr) self.CommandStack.push( DeleteStorage(self.mechanism_storage.row(item), self.mechanism_storage)) self.CommandStack.push( AddStorageName(name, self.mechanism_storage_name_tag)) self.CommandStack.endMacro()
def on_Combine_number_clicked(self): """Show number of links with different number of joints.""" self.Expression_number.clear() NS_result = NumberSynthesis(self.NL_input.value(), self.NJ_input.value()) if type(NS_result) == str: item = QListWidgetItem(NS_result) item.links = None self.Expression_number.addItem(item) else: for result in NS_result: item = QListWidgetItem(", ".join( "NL{} = {}".format(i+2, result[i]) for i in range(len(result)) )) item.links = result self.Expression_number.addItem(item) self.Expression_number.setCurrentRow(0)
def __drawAtlas(self, i: int, G: Graph) -> bool: """Draw atlas and return True if done.""" item = QListWidgetItem("No. {}".format(i + 1)) try: item.setIcon( graph(G, self.Topologic_result.iconSize().width(), self.engine, self.graph_link_as_node.isChecked())) except EngineError as e: QMessageBox.warning( self, str(e), "Please install and make sure Graphviz is working.") return False else: item.setToolTip(str(G.edges)) self.Topologic_result.addItem(item) return True
def __init__(self, Points, Links, pos=False, parent=None): super(edit_link_show, self).__init__(parent) self.setupUi(self) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) self.Points = Points self.Links = Links icon = self.windowIcon() self.PointIcon = QIcon(QPixmap(":/icons/bearing.png")) for i, e in enumerate(colorName()): self.Color.insertItem(i, colorIcons(e), e) for i in range(len(self.Points)): self.noSelected.addItem( QListWidgetItem(self.PointIcon, 'Point{}'.format(i))) if pos is False: self.Link.addItem(icon, "New link") self.Link.setEnabled(False) self.Color.setCurrentIndex(self.Color.findText('Blue')) else: for vlink in self.Links: self.Link.insertItem(i, icon, vlink.name) self.Link.setCurrentIndex(pos) self.name_edit.textChanged.connect(self.isOk) self.isOk()
def __add_result(self, result: Dict[str, Any]): """Add result items, except add to the list.""" item = QListWidgetItem(result['Algorithm']) interrupt = result['interrupted'] if interrupt == 'False': interrupt_icon = "task_completed.png" elif interrupt == 'N/A': interrupt_icon = "question.png" else: interrupt_icon = "interrupted.png" item.setIcon(QIcon(QPixmap(f":/icons/{interrupt_icon}"))) if interrupt == 'False': interrupt_text = "No interrupt." else: interrupt_text = f"Interrupt at: {interrupt}" text = f"{result['Algorithm']} ({interrupt_text})" if interrupt == 'N/A': text += "\n※Completeness is unknown." item.setToolTip(text) self.result_list.addItem(item)
def __reload_atlas(self): """Reload atlas with the engine.""" current_pos = self.collection_list.currentRow() self.collections_layouts.clear() self.collection_list.clear() self.__clear_selection() if not self.collections: return progress_dlg = QProgressDialog("Drawing atlas...", "Cancel", 0, len(self.collections), self) progress_dlg.setAttribute(Qt.WA_DeleteOnClose, True) progress_dlg.setWindowTitle("Type synthesis") progress_dlg.resize(400, progress_dlg.height()) progress_dlg.setModal(True) progress_dlg.show() engine_str = self.graph_engine.currentText() for i, g in enumerate(self.collections): QCoreApplication.processEvents() if progress_dlg.wasCanceled(): progress_dlg.deleteLater() return item = QListWidgetItem(f"No. {i + 1}") engine = engine_picker(g, engine_str, self.graph_link_as_node.isChecked()) item.setIcon( to_graph(g, self.collection_list.iconSize().width(), engine, self.graph_link_as_node.isChecked(), self.graph_show_label.isChecked(), self.is_monochrome())) self.collections_layouts.append(engine) item.setToolTip(f"{g.edges}") self.collection_list.addItem(item) progress_dlg.setValue(i + 1) progress_dlg.deleteLater() self.collection_list.setCurrentRow(current_pos)
def on_reload_atlas_clicked(self, p0=None): """Reload atlas with the engine.""" if not self.collections: return self.collections_layouts.clear() self.collection_list.clear() self.selection_window.clear() self.Expression_edges.clear() self.NL.setText('0') self.NJ.setText('0') self.DOF.setText('0') self.grounded_list.clear() progdlg = QProgressDialog("Drawing atlas...", "Cancel", 0, len(self.collections), self) progdlg.setAttribute(Qt.WA_DeleteOnClose, True) progdlg.setWindowTitle("Type synthesis") progdlg.resize(400, progdlg.height()) progdlg.setModal(True) progdlg.show() engineSTR = self.graph_engine.currentText().split(" - ")[1] for i, G in enumerate(self.collections): QCoreApplication.processEvents() if progdlg.wasCanceled(): return item = QListWidgetItem("No. {}".format(i + 1)) try: engine = engine_picker(G, engineSTR) item.setIcon( graph(G, self.collection_list.iconSize().width(), engine)) except EngineError as e: progdlg.setValue(progdlg.maximum()) self.engineErrorMsg(e) break else: self.collections_layouts.append(engine) item.setToolTip( "{}\nUse the right-click menu to operate.".format(G.edges)) self.collection_list.addItem(item) progdlg.setValue(i + 1)