cadquery-freecad-module/CadQuery/Libs/pyqode/core/widgets/outline.py
2015-10-26 16:25:38 -04:00

181 lines
6.2 KiB
Python

"""
This document contains the tree widget used to display the editor document
outline.
"""
from pyqode.core import icons
from pyqode.core.panels import FoldingPanel
from pyqode.core.modes.outline import OutlineMode
from pyqode.qt import QtCore, QtGui, QtWidgets
from pyqode.core.api import TextBlockHelper, TextBlockUserData, TextHelper
class OutlineTreeWidget(QtWidgets.QTreeWidget):
"""
Displays the outline of a CodeEdit.
To use this widget:
1. add an OutlineMode to CodeEdit
2. call set_editor with a CodeEdit instance to show it's outline.
"""
def __init__(self, parent=None):
super(OutlineTreeWidget, self).__init__(parent)
self._editor = None
self._outline_mode = None
self._folding_panel = None
self._expanded_items = []
self.setHeaderHidden(True)
self.itemClicked.connect(self._on_item_clicked)
self.itemCollapsed.connect(self._on_item_state_changed)
self.itemExpanded.connect(self._on_item_state_changed)
self._updating = True
def set_editor(self, editor):
"""
Sets the current editor. The widget display the structure of that
editor.
:param editor: CodeEdit
"""
if self._outline_mode:
try:
self._outline_mode.document_changed.disconnect(
self._on_changed)
except (TypeError, RuntimeError):
pass
if self._folding_panel:
try:
self._folding_panel.trigger_state_changed.disconnect(
self._on_block_state_changed)
except (TypeError, RuntimeError):
pass
self._editor = editor
if self._editor is not None:
try:
self._folding_panel = editor.panels.get(FoldingPanel)
except KeyError:
pass
else:
self._folding_panel.trigger_state_changed.connect(
self._on_block_state_changed)
try:
analyser = editor.modes.get(OutlineMode)
except KeyError:
self._outline_mode = None
else:
self._outline_mode = analyser
analyser.document_changed.connect(self._on_changed)
self._on_changed()
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 _on_block_state_changed(self, block, state):
if self._updating:
return
data = block.userData()
if data is not None:
try:
item_state = not data.tree_item.isExpanded()
if item_state != state:
if state:
self.collapseItem(data.tree_item)
else:
self.expandItem(data.tree_item)
except AttributeError:
# a block that is not represented in the tree view has
# folded/unfolded, just ignore it
pass
def _on_changed(self):
"""
Update the tree items
"""
self._updating = True
to_collapse = []
self.clear()
if self._editor and self._outline_mode and self._folding_panel:
items, to_collapse = self.to_tree_widget_items(
self._outline_mode.definitions, to_collapse=to_collapse)
if len(items):
self.addTopLevelItems(items)
self.expandAll()
for item in reversed(to_collapse):
self.collapseItem(item)
self._updating = False
return
# no data
root = QtWidgets.QTreeWidgetItem()
root.setText(0, 'No data')
root.setIcon(0, icons.icon(
'dialog-information', ':/pyqode-icons/rc/dialog-info.png',
'fa.info-circle'))
self.addTopLevelItem(root)
self._updating = False
def _on_item_clicked(self, item):
"""
Go to the item position in the editor.
"""
if item:
name = item.data(0, QtCore.Qt.UserRole)
if name:
go = name.block.blockNumber()
helper = TextHelper(self._editor)
if helper.current_line_nbr() != go:
helper.goto_line(go, column=name.column)
self._editor.setFocus()
def to_tree_widget_items(self, definitions, to_collapse=None):
"""
Converts the list of top level definitions to a list of top level
tree items.
"""
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
items = []
for d in definitions:
value, to_collapse = convert(d, self._editor, to_collapse)
items.append(value)
if to_collapse is not None:
return items, to_collapse
return items