Browse Source

修改叶子节点的选中事件前

master
hejl 2 months ago
parent
commit
d29d8e8033
  1. 81
      win_text_editor/lib/modules/template_parser/controllers/template_parser_controller.dart
  2. 58
      win_text_editor/lib/modules/template_parser/models/template_node.dart
  3. 26
      win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart

81
win_text_editor/lib/modules/template_parser/controllers/template_parser_controller.dart

@ -37,32 +37,9 @@ class TemplateParserController extends BaseContentController { @@ -37,32 +37,9 @@ class TemplateParserController extends BaseContentController {
void selectTreeNode(TemplateNode node) {
_selectedNode = node;
_templateItems = _generateTemplateItems(node);
notifyListeners();
}
List<TemplateItem> _generateTemplateItems(TemplateNode node) {
// XML解析真实数据
return [
if (node.attributes != null)
...node.attributes!.entries.map(
(e) => TemplateItem(
id: e.key.hashCode,
content: '${node.name}.${e.key}',
xPath: '${node.name}@${e.key}',
value: e.value,
),
),
if (node.text != null && node.text!.trim().isNotEmpty)
TemplateItem(
id: node.text.hashCode,
content: node.text!,
xPath: '${node.name}/text()',
value: node.text!,
),
];
}
Future<void> _loadTemplateData() async {
try {
_errorMessage = null;
@ -85,36 +62,62 @@ class TemplateParserController extends BaseContentController { @@ -85,36 +62,62 @@ class TemplateParserController extends BaseContentController {
Future<void> _parseXmlContent(String xmlContent) async {
final document = xml.XmlDocument.parse(xmlContent);
Logger().debug('开始解析XML,根元素: ${document.rootElement.name}');
_treeNodes = _buildTreeNodes(document.rootElement, depth: 0);
Logger().debug('解析完成,共生成 ${_treeNodes.length} 个顶级节点');
notifyListeners();
}
List<TemplateNode> _buildTreeNodes(xml.XmlElement element, {required int depth}) {
List<TemplateNode> _buildTreeNodes(
xml.XmlElement element, {
required int depth,
int repreatCount = 1,
}) {
final node = TemplateNode(
name: element.name.local,
children: [],
attributes:
element.attributes.isNotEmpty
? {for (var attr in element.attributes) attr.name.local: attr.value}
: null,
text: element.text.trim().isNotEmpty ? element.text : null,
depth: depth,
isExpanded: depth < 1, //
);
//
node.children.addAll(
element.children.whereType<xml.XmlElement>().map(
(e) => _buildTreeNodes(e, depth: depth + 1).first,
),
isExpanded: depth < 5, //
isRepeated: repreatCount > 1,
repreatCount: repreatCount,
);
//
//
if (element.attributes.isNotEmpty) {
node.children.addAll(
element.attributes.map((attr) => TemplateNode.attribute(attr.name.local, attr.value)),
element.attributes.map(
(attr) => TemplateNode(
name: '@${attr.name.local}',
children: [],
depth: depth + 1,
isAttribute: true,
),
),
);
}
//
final childElements = element.children.whereType<xml.XmlElement>();
final groupedChildren = <String, List<xml.XmlElement>>{};
//
for (var child in childElements) {
groupedChildren.putIfAbsent(child.name.local, () => []).add(child);
}
//
groupedChildren.forEach((name, elements) {
if (elements.length == 1) {
//
node.children.addAll(_buildTreeNodes(elements.first, depth: depth + 1));
} else {
//
node.children.addAll(
_buildTreeNodes(elements.first, depth: depth + 1, repreatCount: elements.length),
);
}
});
return [node];
}

58
win_text_editor/lib/modules/template_parser/models/template_node.dart

@ -2,57 +2,33 @@ import 'package:flutter/material.dart'; @@ -2,57 +2,33 @@ import 'package:flutter/material.dart';
import 'package:win_text_editor/shared/components/tree_view.dart';
class TemplateNode implements TreeNode {
@override
final String id; // 使ID
@override
final String name;
@override
final List<TemplateNode> children;
final Map<String, String>? attributes;
final String? text;
@override
final int depth; //
@override
bool isExpanded; //
bool isRepeated; //
@override
bool get isDirectory => children.isNotEmpty; //
@override
IconData? get iconData {
if (name.startsWith('@')) return Icons.code; //
return isDirectory ? Icons.folder : Icons.insert_drive_file; //
}
final int depth;
bool isExpanded;
bool isRepeated;
bool isAttribute;
int repreatCount;
TemplateNode({
required this.name,
required this.children,
this.attributes,
this.text,
this.depth = 0,
required this.depth,
this.isExpanded = false,
this.isRepeated = false,
String? id,
}) : id = id ?? '${depth}_${name}'; // ID生成逻辑
this.isAttribute = false,
this.repreatCount = 1,
});
// TreeNode接口
@override
String get id => '$name-$depth';
//
TemplateNode.attribute(String name, String value)
: this(name: '@$name', children: const [], attributes: {name: value}, depth: 1);
@override
bool get isDirectory => children.isNotEmpty;
//
TemplateNode copyWith({int? depth, bool? isExpanded}) {
return TemplateNode(
name: name,
children: children,
attributes: attributes,
text: text,
depth: depth ?? this.depth,
isExpanded: isExpanded ?? this.isExpanded,
id: id,
);
}
@override
IconData? get iconData => isAttribute ? Icons.code : Icons.label_outline;
}
class TemplateItem {

26
win_text_editor/lib/modules/template_parser/widgets/template_parser_view.dart

@ -111,32 +111,17 @@ class _TemplateParserViewState extends State<TemplateParserView> { @@ -111,32 +111,17 @@ class _TemplateParserViewState extends State<TemplateParserView> {
}
List<TreeNode> _processXmlNodes(List<TemplateNode> nodes) {
final uniqueNodes = <String, TemplateNode>{};
final result = <TreeNode>[];
for (final node in nodes) {
// +
final signature = '${node.name}:${node.attributes?.keys.join(',') ?? ''}';
if (!uniqueNodes.containsKey(signature)) {
uniqueNodes[signature] = node;
result.add(node);
} else {
//
uniqueNodes[signature]!.isRepeated = true;
}
}
return result.cast<TreeNode>();
return nodes.cast<TreeNode>();
}
Widget _buildCustomNode(TreeNode node) {
final templateNode = node as TemplateNode;
final isAttribute = node.depth > 0 && node.name.startsWith('@');
final isAttribute = node.isAttribute;
return Consumer<TemplateParserController>(
builder: (context, controller, _) {
return Padding(
padding: EdgeInsets.only(left: 12.0 * node.depth), //
padding: EdgeInsets.only(left: 12.0 * node.depth),
child: ListTile(
dense: true,
leading:
@ -152,7 +137,10 @@ class _TemplateParserViewState extends State<TemplateParserView> { @@ -152,7 +137,10 @@ class _TemplateParserViewState extends State<TemplateParserView> {
),
trailing:
templateNode.isRepeated
? const Text("(repeated)", style: TextStyle(color: Colors.grey))
? Text(
"(${templateNode.repreatCount.toString()})",
style: const TextStyle(color: Colors.grey),
)
: null,
onTap: () => controller.selectTreeNode(templateNode),
),

Loading…
Cancel
Save