diff --git a/documents/PB UFT模块迁移方案.docx b/documents/PB UFT模块迁移方案.docx index e378b76..d11e08f 100644 Binary files a/documents/PB UFT模块迁移方案.docx and b/documents/PB UFT模块迁移方案.docx differ diff --git a/win_text_editor/lib/menus/app_menu.dart b/win_text_editor/lib/menus/app_menu.dart index 09480bb..fdacc98 100644 --- a/win_text_editor/lib/menus/app_menu.dart +++ b/win_text_editor/lib/menus/app_menu.dart @@ -27,7 +27,10 @@ class AppMenu extends StatelessWidget { return [ const PopupMenuItem(value: MenuConstants.templateParser, child: Text('XML解析')), const PopupMenuItem(value: MenuConstants.contentSearch, child: Text('内容搜索')), - const PopupMenuItem(value: MenuConstants.dataFormat, child: Text('格式化')), + const PopupMenuItem(value: MenuConstants.dataCompare, child: Text('数据对比')), + const PopupMenuItem(value: MenuConstants.dataFormat, child: Text('数据格式化')), + const PopupMenuDivider(), + const PopupMenuItem(value: MenuConstants.demo, child: Text('Demo')), ]; } diff --git a/win_text_editor/lib/menus/menu_actions.dart b/win_text_editor/lib/menus/menu_actions.dart index 817cbb4..f4e7b84 100644 --- a/win_text_editor/lib/menus/menu_actions.dart +++ b/win_text_editor/lib/menus/menu_actions.dart @@ -10,96 +10,95 @@ import 'dart:io'; import 'package:win_text_editor/modules/module_router.dart'; class MenuActions { + static final Map _actionHandlers = { + MenuConstants.openFolder: _openFolder, + MenuConstants.contentSearch: _openContentSearch, + MenuConstants.templateParser: _openTemplateParser, + MenuConstants.dataFormat: _dataFormat, + MenuConstants.dataCompare: _dataCompare, + MenuConstants.demo: _demo, + MenuConstants.exit: _exitApplication, + }; + static Future handleMenuAction(String value, BuildContext context) async { - switch (value) { - case MenuConstants.openFolder: - await _openFolder(context); - break; - case MenuConstants.contentSearch: // 新增内容搜索菜单项 - await _openContentSearch(context); - break; - case MenuConstants.templateParser: - await _openTemplateParser(context); - break; - case MenuConstants.dataFormat: - await _dataFormat(context); - break; - case MenuConstants.exit: - _exitApplication(); - break; - // 其他菜单项可以在这里添加处理逻辑 + final handler = _actionHandlers[value]; + if (handler != null) { + await handler(context); } } static Future _openFolder(BuildContext context) async { - final fileProvider = Provider.of(context, listen: false); - final String? selectedDirectory = await FilePicker.platform.getDirectoryPath(); - - if (selectedDirectory != null) { - await fileProvider.loadDirectory(selectedDirectory); + try { + final fileProvider = Provider.of(context, listen: false); + final String? selectedDirectory = await FilePicker.platform.getDirectoryPath(); + if (selectedDirectory != null) { + await fileProvider.loadDirectory(selectedDirectory); + } + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('打开文件夹失败: $e'))); } } static Future _openContentSearch(BuildContext context) async { - final tabManager = Provider.of(context, listen: false); - - // Create new tab with unique ID - final tabId = DateTime.now().millisecondsSinceEpoch.toString(); - - await tabManager.addTab( - tabId, - title: "内容搜索", - type: RouterKey.contentSearch, - icon: Icons.search, - content: "", - ); + await _openOrActivateTab(context, "内容搜索", RouterKey.contentSearch, Icons.search); } static Future _openTemplateParser(BuildContext context) async { - final tabManager = Provider.of(context, listen: false); + await _openOrActivateTab(context, "XML解析", RouterKey.templateParser, Icons.auto_awesome_mosaic); + } - // 使用 firstWhereOrNull 查找选项卡 - final existingTab = tabManager.tabs.firstWhereOrNull( - (tab) => tab.type == RouterKey.templateParser, - ); + static Future _dataFormat(BuildContext context) async { + await _openOrActivateTab(context, "数据格式化", RouterKey.dataFormat, Icons.date_range); + } - if (existingTab != null) { - // 如果存在,激活该选项卡 - tabManager.setActiveTab(existingTab.id); - } else { - final tabId = DateTime.now().millisecondsSinceEpoch.toString(); - await tabManager.addTab( - tabId, - title: "XML解析", - type: RouterKey.templateParser, - icon: Icons.auto_awesome_mosaic, - content: "", - ); - } + static Future _dataCompare(BuildContext context) async { + await _openOrActivateTab(context, "数据对比", RouterKey.dataCompare, Icons.compare); } - static Future _dataFormat(BuildContext context) async { - final tabManager = Provider.of(context, listen: false); + static Future _demo(BuildContext context) async { + await _openOrActivateTab(context, "Demo", RouterKey.demo, Icons.code); + } - // 使用 firstWhereOrNull 查找选项卡 - final existingTab = tabManager.tabs.firstWhereOrNull((tab) => tab.type == RouterKey.dataFormat); + static Future _openOrActivateTab( + BuildContext context, + String title, + String type, + IconData icon, + ) async { + try { + final tabManager = Provider.of(context, listen: false); + final existingTab = tabManager.tabs.firstWhereOrNull((tab) => tab.type == type); - if (existingTab != null) { - // 如果存在,激活该选项卡 - tabManager.setActiveTab(existingTab.id); - } else { - final tabId = DateTime.now().millisecondsSinceEpoch.toString(); - await tabManager.addTab( - tabId, - title: "数据格式化", - type: RouterKey.dataFormat, - icon: Icons.date_range, - content: "", - ); + if (existingTab != null) { + tabManager.setActiveTab(existingTab.id); + } else { + final tabId = DateTime.now().millisecondsSinceEpoch.toString(); + await tabManager.addTab(tabId, title: title, type: type, icon: icon, content: ""); + } + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('打开标签页失败: $e'))); } } - static void _exitApplication() { - exit(0); + static Future _exitApplication(BuildContext context) async { + final shouldExit = await showDialog( + context: context, + builder: + (context) => AlertDialog( + title: const Text('退出应用'), + content: const Text('确定要退出吗?未保存的内容可能会丢失。'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text('取消'), + ), + TextButton(onPressed: () => Navigator.of(context).pop(true), child: const Text('退出')), + ], + ), + ); + + if (shouldExit ?? false) { + exit(0); + } } } diff --git a/win_text_editor/lib/menus/menu_constants.dart b/win_text_editor/lib/menus/menu_constants.dart index a2ef800..6d2ff66 100644 --- a/win_text_editor/lib/menus/menu_constants.dart +++ b/win_text_editor/lib/menus/menu_constants.dart @@ -16,6 +16,8 @@ class MenuConstants { static const String contentSearch = "content_search"; static const String templateParser = 'template_parser'; static const String dataFormat = 'data_format'; + static const String dataCompare = 'data_compare'; + static const String demo = 'demo'; // 编辑菜单项 static const String undo = 'undo'; diff --git a/win_text_editor/lib/modules/content_search/controllers/content_search_controller.dart b/win_text_editor/lib/modules/content_search/controllers/content_search_controller.dart index 34f3ff5..dcedae1 100644 --- a/win_text_editor/lib/modules/content_search/controllers/content_search_controller.dart +++ b/win_text_editor/lib/modules/content_search/controllers/content_search_controller.dart @@ -4,7 +4,6 @@ import 'dart:async'; import 'dart:io'; import 'package:file_picker/file_picker.dart'; -import 'package:flutter/material.dart'; import 'package:win_text_editor/framework/controllers/logger.dart'; import 'package:win_text_editor/modules/content_search/models/search_mode.dart'; import 'package:win_text_editor/modules/content_search/models/search_result.dart'; diff --git a/win_text_editor/lib/modules/data_compare/controllers/data_compare_controller.dart b/win_text_editor/lib/modules/data_compare/controllers/data_compare_controller.dart new file mode 100644 index 0000000..b313900 --- /dev/null +++ b/win_text_editor/lib/modules/data_compare/controllers/data_compare_controller.dart @@ -0,0 +1,13 @@ +import 'package:win_text_editor/shared/base/base_content_controller.dart'; + +class DataCompareController extends BaseContentController { + @override + void onOpenFile(String filePath) { + // TODO: implement onOpenFile + } + + @override + void onOpenFolder(String folderPath) { + // TODO: implement onOpenFolder + } +} diff --git a/win_text_editor/lib/modules/data_compare/widgets/data_compare_view.dart b/win_text_editor/lib/modules/data_compare/widgets/data_compare_view.dart new file mode 100644 index 0000000..b5fa5c0 --- /dev/null +++ b/win_text_editor/lib/modules/data_compare/widgets/data_compare_view.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:win_text_editor/framework/controllers/tab_items_controller.dart'; +import 'package:win_text_editor/modules/data_compare/controllers/data_compare_controller.dart'; + +class DataCompareView extends StatefulWidget { + final String tabId; + const DataCompareView({super.key, required this.tabId}); + + @override + State createState() => _DataCompareViewState(); +} + +class _DataCompareViewState extends State { + late final DataCompareController _controller; + + get tabManager => Provider.of(context, listen: false); + + @override + void initState() { + super.initState(); + _controller = tabManager.getController(widget.tabId) ?? DataCompareController(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider.value( + value: _controller, + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Column(children: [Expanded(flex: 1, child: Text("空白"))]), + ), + ); + } +} diff --git a/win_text_editor/lib/modules/demo/controllers/demo_controller.dart b/win_text_editor/lib/modules/demo/controllers/demo_controller.dart new file mode 100644 index 0000000..c7a3623 --- /dev/null +++ b/win_text_editor/lib/modules/demo/controllers/demo_controller.dart @@ -0,0 +1,13 @@ +import 'package:win_text_editor/shared/base/base_content_controller.dart'; + +class DemoController extends BaseContentController { + @override + void onOpenFile(String filePath) { + // TODO: implement onOpenFile + } + + @override + void onOpenFolder(String folderPath) { + // TODO: implement onOpenFolder + } +} diff --git a/win_text_editor/lib/modules/demo/widgets/demo_view.dart b/win_text_editor/lib/modules/demo/widgets/demo_view.dart new file mode 100644 index 0000000..dc706cc --- /dev/null +++ b/win_text_editor/lib/modules/demo/widgets/demo_view.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:win_text_editor/framework/controllers/tab_items_controller.dart'; +import 'package:win_text_editor/modules/demo/controllers/demo_controller.dart'; + +class DemoView extends StatefulWidget { + final String tabId; + const DemoView({super.key, required this.tabId}); + + @override + State createState() => _DemoViewState(); +} + +class _DemoViewState extends State { + late final DemoController _controller; + + get tabManager => Provider.of(context, listen: false); + + @override + void initState() { + super.initState(); + _controller = tabManager.getController(widget.tabId) ?? DemoController(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider.value( + value: _controller, + child: const Padding( + padding: EdgeInsets.all(8.0), + child: Column(children: [Expanded(flex: 1, child: Text("Demo,就是一个空窗体,用于新增菜单时快速初始化(拷贝)。"))]), + ), + ); + } +} diff --git a/win_text_editor/lib/modules/module_router.dart b/win_text_editor/lib/modules/module_router.dart index 1304d7c..38e86ec 100644 --- a/win_text_editor/lib/modules/module_router.dart +++ b/win_text_editor/lib/modules/module_router.dart @@ -1,8 +1,12 @@ // modules/tab_content_registry.dart import 'package:flutter/material.dart'; import 'package:win_text_editor/framework/models/tab_model.dart'; +import 'package:win_text_editor/modules/data_compare/controllers/data_compare_controller.dart'; +import 'package:win_text_editor/modules/data_compare/widgets/data_compare_view.dart'; import 'package:win_text_editor/modules/data_format/controllers/data_format_controller.dart'; import 'package:win_text_editor/modules/data_format/widgets/data_format_view.dart'; +import 'package:win_text_editor/modules/demo/controllers/demo_controller.dart'; +import 'package:win_text_editor/modules/demo/widgets/demo_view.dart'; import 'package:win_text_editor/shared/base/base_content_controller.dart'; import 'package:win_text_editor/modules/content_search/controllers/content_search_controller.dart'; import 'package:win_text_editor/modules/template_parser/controllers/template_parser_controller.dart'; @@ -14,6 +18,8 @@ class RouterKey { static const String templateParser = 'template_parser'; static const String dataFormat = 'data_format'; static const String textEditor = 'text_editor'; + static const String dataCompare = 'data_compare'; + static const String demo = 'demo'; } class ModuleRouter { @@ -22,6 +28,8 @@ class ModuleRouter { RouterKey.contentSearch: (tab) => ContentSearchController(), RouterKey.templateParser: (tab) => TemplateParserController(), RouterKey.dataFormat: (tab) => DataFormatController(), + RouterKey.dataCompare: (tab) => DataCompareController(), + RouterKey.demo: (tab) => DemoController(), }; // 映射UI组件 @@ -29,6 +37,8 @@ class ModuleRouter { RouterKey.contentSearch: (tab, controller) => ContentSearchView(tabId: tab.id), RouterKey.templateParser: (tab, controller) => TemplateParserView(tabId: tab.id), RouterKey.dataFormat: (tab, controller) => DataFormatView(tabId: tab.id), + RouterKey.dataCompare: (tab, controller) => DataCompareView(tabId: tab.id), + RouterKey.demo: (tab, controller) => DemoView(tabId: tab.id), }; static BaseContentController? createControllerForTab(AppTab tab) {