def _on_key_pressed(self, event): """ Override key press to select the current scope if the user wants to deleted a folded scope (without selecting it). """ delete_request = event.key() in [QtCore.Qt.Key_Backspace, QtCore.Qt.Key_Delete] if event.text() or delete_request: cursor = self.editor.textCursor() if cursor.hasSelection(): # change selection to encompass the whole scope. positions_to_check = cursor.selectionStart(), cursor.selectionEnd() else: positions_to_check = (cursor.position(), ) for pos in positions_to_check: block = self.editor.document().findBlock(pos) th = TextBlockHelper() if th.is_fold_trigger(block) and th.is_collapsed(block): self.toggle_fold_trigger(block) if delete_request and cursor.hasSelection(): scope = FoldScope(self.find_parent_scope(block)) tc = TextHelper(self.editor).select_lines(*scope.get_range()) if tc.selectionStart() > cursor.selectionStart(): start = cursor.selectionStart() else: start = tc.selectionStart() if tc.selectionEnd() < cursor.selectionEnd(): end = cursor.selectionEnd() else: end = tc.selectionEnd() tc.setPosition(start) tc.setPosition(end, tc.KeepAnchor) self.editor.setTextCursor(tc)
def convert(name, editor, to_collapse): ti = QtWidgets.QTreeWidgetItem() ti.setText(0, name.name) if isinstance(name.icon, list): icon = QtGui.QIcon.fromTheme(name.icon[0], QtGui.QIcon(name.icon[1])) else: icon = QtGui.QIcon(name.icon) ti.setIcon(0, icon) name.block = editor.document().findBlockByNumber(name.line) ti.setData(0, QtCore.Qt.UserRole, name) ti.setToolTip(0, name.description) name.tree_item = ti block_data = name.block.userData() if block_data is None: block_data = TextBlockUserData() name.block.setUserData(block_data) block_data.tree_item = ti if to_collapse is not None and \ TextBlockHelper.is_collapsed(name.block): to_collapse.append(ti) for ch in name.children: ti_ch, to_collapse = convert(ch, editor, to_collapse) if ti_ch: ti.addChild(ti_ch) return ti, to_collapse
def convert(name, editor, to_collapse): ti = QtWidgets.QTreeWidgetItem() ti.setText(0, name.name) if isinstance(name.icon, list): icon = QtGui.QIcon.fromTheme( name.icon[0], QtGui.QIcon(name.icon[1])) else: icon = QtGui.QIcon(name.icon) ti.setIcon(0, icon) name.block = editor.document().findBlockByNumber(name.line) ti.setData(0, QtCore.Qt.UserRole, name) ti.setToolTip(0, name.description) block_data = name.block.userData() if block_data is None: block_data = TextBlockUserData() name.block.setUserData(block_data) block_data.tree_item = ti if to_collapse is not None and \ TextBlockHelper.is_collapsed(name.block): to_collapse.append(ti) for ch in name.children: ti_ch, to_collapse = convert(ch, editor, to_collapse) if ti_ch: ti.addChild(ti_ch) return ti, to_collapse
def _on_item_state_changed(self, item): if self._updating: return block = item.data(0, QtCore.Qt.UserRole).block assert isinstance(item, QtWidgets.QTreeWidgetItem) item_state = not item.isExpanded() block_state = TextBlockHelper.is_collapsed(block) if item_state != block_state: self._updating = True self._folding_panel.toggle_fold_trigger(block) self._updating = False
def test_expand_all(editor): panel = get_panel(editor) QTest.qWait(1000) panel.collapse_all() QTest.qWait(1000) panel.expand_all() block = editor.document().firstBlock() while block.blockNumber() < editor.document().blockCount() - 1: assert block.isVisible() if TextBlockHelper.is_fold_trigger(block): assert TextBlockHelper.is_collapsed(block) is False block = block.next()
def test_mouse_press(editor): panel = get_panel(editor) panel.highlight_caret_scope = False # fold child block toggle_fold_trigger(editor, 15, panel) block = editor.document().findBlockByNumber(14) assert TextBlockHelper.is_fold_trigger(block) is True assert TextBlockHelper.is_collapsed(block) is True block = block.next() while block.blockNumber() < 21: assert block.isVisible() is False block = block.next() # fold top level block toggle_fold_trigger(editor, 9, panel) block = editor.document().findBlockByNumber(8) assert TextBlockHelper.is_fold_trigger(block) block = block.next() while block.blockNumber() < 27: if block.blockNumber() == 14: assert TextBlockHelper.is_fold_trigger(block) is True assert TextBlockHelper.is_collapsed(block) is True assert block.isVisible() is False block = block.next() # unfold it top level block toggle_fold_trigger(editor, 9, panel) block = editor.document().findBlockByNumber(8) assert TextBlockHelper.is_fold_trigger(block) block = block.next() while block.blockNumber() < 27: if 14 < block.blockNumber() < 22: assert block.isVisible() is False else: assert block.isVisible() is True block = block.next() # cleanup QTest.mouseMove(panel, QtCore.QPoint(0, 0)) panel.leaveEvent(None) editor.setFocus() panel.highlight_caret_scope = True
def _highlight_surrounding_scopes(self, block): """ Highlights the scopes surrounding the current fold scope. :param block: Block that starts the current fold scope. """ scope = FoldScope(block) if (self._current_scope is None or self._current_scope.get_range() != scope.get_range()): self._current_scope = scope self._clear_scope_decos() # highlight surrounding parent scopes with a darker color start, end = scope.get_range() if not TextBlockHelper.is_collapsed(block): self._add_scope_decorations(block, start, end)
def test_collapse_all(editor): panel = get_panel(editor) QTest.qWait(1000) panel.collapse_all() QTest.qWait(1000) block = editor.document().firstBlock() while block.blockNumber() < editor.document().blockCount() - 1: blank_line = len(block.text().strip()) == 0 if TextBlockHelper.get_fold_lvl(block) > 0: if not blank_line: assert block.isVisible() is False else: assert block.isVisible() is True if TextBlockHelper.is_fold_trigger(block): assert TextBlockHelper.is_collapsed(block) is True block = block.next()
def paintEvent(self, event): # Paints the fold indicators and the possible fold region background # on the folding panel. super(FoldingPanel, self).paintEvent(event) painter = QtGui.QPainter(self) # Draw background over the selected non collapsed fold region if self._mouse_over_line is not None: block = self.editor.document().findBlockByNumber( self._mouse_over_line) try: self._draw_fold_region_background(block, painter) except ValueError: pass # Draw fold triggers for top_position, line_number, block in self.editor.visible_blocks: if TextBlockHelper.is_fold_trigger(block): collapsed = TextBlockHelper.is_collapsed(block) mouse_over = self._mouse_over_line == line_number self._draw_fold_indicator( top_position, mouse_over, collapsed, painter) if collapsed: # check if the block already has a decoration, it might # have been folded by the parent editor/document in the # case of cloned editor for deco in self._block_decos: if deco.block == block: # no need to add a deco, just go to the next block break else: self._add_fold_decoration(block, FoldScope(block)) else: for deco in self._block_decos: # check if the block decoration has been removed, it # might have been unfolded by the parent # editor/document in the case of cloned editor if deco.block == block: # remove it and self._block_decos.remove(deco) self.editor.decorations.remove(deco) del deco break
def paintEvent(self, event): # Paints the fold indicators and the possible fold region background # on the folding panel. super(FoldingPanel, self).paintEvent(event) painter = QtGui.QPainter(self) # Draw background over the selected non collapsed fold region if self._mouse_over_line is not None: block = self.editor.document().findBlockByNumber( self._mouse_over_line) try: self._draw_fold_region_background(block, painter) except ValueError: pass # Draw fold triggers for top_position, line_number, block in self.editor.visible_blocks: if TextBlockHelper.is_fold_trigger(block): collapsed = TextBlockHelper.is_collapsed(block) mouse_over = self._mouse_over_line == line_number self._draw_fold_indicator(top_position, mouse_over, collapsed, painter) if collapsed: # check if the block already has a decoration, it might # have been folded by the parent editor/document in the # case of cloned editor for deco in self._block_decos: if deco.block == block: # no need to add a deco, just go to the next block break else: self._add_fold_decoration(block, FoldScope(block)) else: for deco in self._block_decos: # check if the block decoration has been removed, it # might have been unfolded by the parent # editor/document in the case of cloned editor if deco.block == block: # remove it and self._block_decos.remove(deco) self.editor.decorations.remove(deco) del deco break