diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b321710 --- /dev/null +++ b/.gitignore @@ -0,0 +1,231 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# VS Code +.vscode/ + +# macOS +.DS_Store +.AppleDouble +.LSOverride +Icon? +._* +.Spotlight-V100 +.Trashes +AppleDskTp + +# Windows +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ +Windows/Temp/ +*.cab +*.msi +*.msp +*.tmp + +# Logs +logs/ +*.log + +# Temp files +tmp/ +temp/ + +# Backup files +*.bak +*.backup +*.old +*.orig + +# Project specific +*.pyc +*.pyo +*.pyd +*.py.class +*.pyc.orig +*.pyc~* + +# Application data +/resources/user_data/ +/resources/cache/ + +# Test reports +htmlcov/ +.coverage +.coverage.* +nosetests.xml +coverage.xml +*.cover +*.py,cover + +# Virtual environments +venv/ +env/ +.venv/ +.env/ + +# IDE +.idea/ + +# Local configuration +config/local_settings.json \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 35410ca..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# 默认忽略的文件 -/shelf/ -/workspace.xml -# 基于编辑器的 HTTP 客户端请求 -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index b8cca46..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -constants.py \ No newline at end of file diff --git a/.idea/Curriculum_Design.iml b/.idea/Curriculum_Design.iml deleted file mode 100644 index 27487ca..0000000 --- a/.idea/Curriculum_Design.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index ce3e966..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 657dff4..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 8306744..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index d3eeb76..96c661b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,8 @@ -python-docx>=0.8.11 +python-docx>=0.8.10 PyPDF2>=1.26.0 ebooklib>=0.17.1 -<<<<<<< HEAD PyQt5>=5.15.0 -======= -PyQt5>=5.15 ->>>>>>> main -requests>=2.28.0 +requests>=2.25.1 beautifulsoup4>=4.11.0 -pillow>=9.0.0 \ No newline at end of file +pillow>=9.0.0 +chardet>=4.0.0 \ No newline at end of file diff --git a/resources/config/app_settings.json b/resources/config/app_settings.json new file mode 100644 index 0000000..53d89fe --- /dev/null +++ b/resources/config/app_settings.json @@ -0,0 +1,42 @@ +{ + "application": { + "name": "MagicWord", + "version": "1.0.0", + "author": "MagicWord Team", + "description": "隐私学习软件" + }, + "window": { + "default_size": { + "width": 800, + "height": 600 + }, + "minimum_size": { + "width": 600, + "height": 400 + }, + "title": "MagicWord - 隐私学习软件" + }, + "typing": { + "default_time_limit": 300, + "show_progress_bar": true, + "highlight_current_line": true, + "auto_save_progress": true + }, + "files": { + "supported_formats": [".txt", ".docx"], + "auto_backup_enabled": true, + "backup_interval_minutes": 30 + }, + "network": { + "weather_api_key": "YOUR_WEATHER_API_KEY", + "quote_api_url": "https://api.quotable.io/random", + "timeout_seconds": 10 + }, + "appearance": { + "theme": "light", + "font_family": "Arial", + "font_size": 12, + "text_color": "#000000", + "background_color": "#FFFFFF" + } +} \ No newline at end of file diff --git a/rescources/资源文件.txt b/resources/资源文件.txt similarity index 100% rename from rescources/资源文件.txt rename to resources/资源文件.txt diff --git a/src/constants.py b/src/constants.py index e0bdc52..210e6c3 100644 --- a/src/constants.py +++ b/src/constants.py @@ -1,7 +1,20 @@ -""" -需要定义的常量: -SUPPORTED_FORMATS = ['.txt', '.docx'] +# constants.py +from PyQt5.QtGui import QColor + +# 支持的文件格式 +SUPPORTED_FORMATS = ['.txt', '.docx', '.pdf'] + +# 默认窗口大小 DEFAULT_WINDOW_SIZE = (800, 600) -COLOR_CORRECT = QColor('green') -COLOR_WRONG = QColor('red') -""" \ No newline at end of file + +# 颜色定义 +COLOR_CORRECT = QColor('lightgreen') +COLOR_WRONG = QColor('lightcoral') +COLOR_HIGHLIGHT = QColor('yellow') + +# API配置 +WEATHER_API_KEY = "your_weather_api_key" +QUOTE_API_URL = "https://api.quotable.io/random" + +# 其他常量 +MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB \ No newline at end of file diff --git a/src/file_manager/file_operations.py b/src/file_manager/file_operations.py new file mode 100644 index 0000000..603cb8e --- /dev/null +++ b/src/file_manager/file_operations.py @@ -0,0 +1,151 @@ +# file_manager/file_operations.py +import os +import shutil +from typing import List, Optional, Dict, Any +from pathlib import Path + +class FileManager: + def __init__(self): + """ + 初始化文件管理器 + - 设置工作目录 + - 初始化文件缓存 + """ + # TODO: 实现构造函数逻辑 + # 1. 设置默认工作目录 + # 2. 初始化文件缓存 + # 3. 创建必要的目录结构 + pass + + def list_files(self, directory: str, extensions: Optional[List[str]] = None) -> List[str]: + """ + 列出目录中的文件 + - 遍历指定目录 + - 根据扩展名过滤文件(如果提供) + - 返回文件路径列表 + """ + # TODO: 实现文件列表逻辑 + # 1. 检查目录是否存在 + # 2. 遍历目录中的所有文件 + # 3. 根据扩展名过滤文件(如果提供) + # 4. 返回文件路径列表 + pass + + def copy_file(self, source: str, destination: str) -> bool: + """ + 复制文件 + - 将文件从源路径复制到目标路径 + - 返回操作结果 + """ + # TODO: 实现文件复制逻辑 + # 1. 检查源文件是否存在 + # 2. 创建目标目录(如果不存在) + # 3. 执行文件复制操作 + # 4. 处理异常情况 + # 5. 返回操作结果 + pass + + def move_file(self, source: str, destination: str) -> bool: + """ + 移动文件 + - 将文件从源路径移动到目标路径 + - 返回操作结果 + """ + # TODO: 实现文件移动逻辑 + # 1. 检查源文件是否存在 + # 2. 创建目标目录(如果不存在) + # 3. 执行文件移动操作 + # 4. 处理异常情况 + # 5. 返回操作结果 + pass + + def delete_file(self, file_path: str) -> bool: + """ + 删除文件 + - 删除指定路径的文件 + - 返回操作结果 + """ + # TODO: 实现文件删除逻辑 + # 1. 检查文件是否存在 + # 2. 执行文件删除操作 + # 3. 处理异常情况(如权限不足) + # 4. 返回操作结果 + pass + + def get_file_info(self, file_path: str) -> Optional[Dict[str, Any]]: + """ + 获取文件信息 + - 获取文件大小、修改时间等信息 + - 返回信息字典 + """ + # TODO: 实现文件信息获取逻辑 + # 1. 检查文件是否存在 + # 2. 获取文件基本信息(大小、修改时间等) + # 3. 获取文件扩展名和类型 + # 4. 返回信息字典 + pass + +class DocumentOrganizer: + def __init__(self): + """ + 初始化文档整理器 + - 设置分类规则 + - 初始化标签系统 + """ + # TODO: 实现构造函数逻辑 + # 1. 设置默认分类规则 + # 2. 初始化标签系统 + # 3. 创建必要的目录结构 + pass + + def categorize_documents(self, directory: str) -> Dict[str, List[str]]: + """ + 分类文档 + - 根据预设规则对文档进行分类 + - 返回分类结果字典 + """ + # TODO: 实现文档分类逻辑 + # 1. 遍历目录中的所有文件 + # 2. 根据文件类型或内容特征进行分类 + # 3. 返回分类结果字典 {类别: [文件列表]} + pass + + def add_tag_to_file(self, file_path: str, tag: str) -> bool: + """ + 为文件添加标签 + - 在文件元数据中添加标签信息 + - 返回操作结果 + """ + # TODO: 实现标签添加逻辑 + # 1. 检查文件是否存在 + # 2. 读取文件元数据 + # 3. 添加新标签 + # 4. 保存更新后的元数据 + # 5. 返回操作结果 + pass + + def search_files_by_tag(self, tag: str) -> List[str]: + """ + 根据标签搜索文件 + - 查找具有指定标签的所有文件 + - 返回文件路径列表 + """ + # TODO: 实现标签搜索逻辑 + # 1. 遍历文件数据库或目录 + # 2. 查找包含指定标签的文件 + # 3. 返回文件路径列表 + pass + + def backup_documents(self, source_dir: str, backup_dir: str) -> bool: + """ + 备份文档 + - 将源目录中的文档备份到备份目录 + - 返回操作结果 + """ + # TODO: 实现文档备份逻辑 + # 1. 创建备份目录(如果不存在) + # 2. 遍历源目录中的所有文件 + # 3. 复制文件到备份目录 + # 4. 处理异常情况 + # 5. 返回操作结果 + pass \ No newline at end of file diff --git a/src/file_parser.py b/src/file_parser.py index 3bd3cc7..84b3c04 100644 --- a/src/file_parser.py +++ b/src/file_parser.py @@ -1,34 +1,57 @@ -""" -1. parse_file(file_path) -输入:file_path:字符串,文件路径 -输出:字符串(文件内容)或抛出异常 -功能:主解析函数,根据文件扩展名路由到具体解析器 -需要包含: -调用validate_file_path(file_path)验证路径 -根据扩展名调用对应解析函数 -统一异常处理 -2. parse_txt(file_path) -输入:file_path:字符串,txt文件路径 -输出:字符串(文件内容) -功能:解析纯文本文件 -需要包含: -自动检测编码(utf-8, gbk等) -处理不同换行符 -返回纯文本内容 -3. parse_docx(file_path) -输入:file_path:字符串,docx文件路径 -输出:字符串(文档文本内容) -功能:解析Word文档 -需要包含: -提取所有段落文本 -保留基本格式(换行) -忽略图片、表格等非文本元素 -4. validate_file_path(file_path) -输入:file_path:字符串,文件路径 -输出:布尔值(是否有效) -功能:验证文件路径的有效性 -需要包含: -检查文件是否存在 -检查文件是否可读 -检查文件大小是否合理 -""" \ No newline at end of file +import os +from typing import Union + +class FileParser: + @staticmethod + def parse_file(file_path: str) -> str: + """ + 主解析函数,根据文件扩展名路由到具体解析器 + - 调用validate_file_path(file_path)验证路径 + - 根据扩展名调用对应解析函数 + - 统一异常处理 + """ + # TODO: 实现主解析函数逻辑 + pass + + @staticmethod + def parse_txt(file_path: str) -> str: + """ + 解析纯文本文件 + - 自动检测编码(utf-8, gbk等) + - 处理不同换行符 + - 返回纯文本内容 + """ + # TODO: 实现实现txt文件解析逻辑 + pass + + @staticmethod + def parse_docx(file_path: str) -> str: + """ + 解析Word文档 + - 提取所有段落文本 + - 保留基本格式(换行) + - 忽略图片、表格等非文本元素 + """ + # TODO: 实现docx文件解析逻辑 + pass + + @staticmethod + def parse_pdf(file_path: str) -> str: + """ + 解析PDF文档 + - 提取文本内容 + - 保留基本格式(换行) + """ + # TODO: 实现PDF文件解析逻辑 + pass + + @staticmethod + def validate_file_path(file_path: str) -> bool: + """ + 验证文件路径的有效性 + - 检查文件是否存在 + - 检查文件是否可读 + - 检查文件大小是否合理 + """ + # TODO: 实现文件路径验证逻辑 + pass \ No newline at end of file diff --git a/src/input_handler/input_processor.py b/src/input_handler/input_processor.py new file mode 100644 index 0000000..d60790a --- /dev/null +++ b/src/input_handler/input_processor.py @@ -0,0 +1,119 @@ +# input_handler/input_processor.py +from PyQt5.QtCore import QObject, pyqtSignal +from typing import Optional + +class InputProcessor(QObject): + # 定义信号 + text_changed = pyqtSignal(str) # 文本变化信号 + key_pressed = pyqtSignal(str) # 按键按下信号 + input_completed = pyqtSignal() # 输入完成信号 + + def __init__(self): + """ + 初始化输入处理器 + - 设置初始状态 + - 初始化输入缓冲区 + """ + super().__init__() + # TODO: 实现构造函数逻辑 + # 1. 初始化输入缓冲区 + # 2. 设置初始状态 + # 3. 初始化相关属性 + pass + + def process_key_event(self, key: str) -> bool: + """ + 处理按键事件 + - 检查按键有效性 + - 更新输入缓冲区 + - 发送相关信号 + - 返回处理结果 + """ + # TODO: 实现按键事件处理逻辑 + # 1. 检查按键是否有效 + # 2. 根据按键类型处理(字符、功能键等) + # 3. 更新输入缓冲区 + # 4. 发送text_changed信号 + # 5. 检查是否完成输入,如是则发送input_completed信号 + # 6. 返回处理结果 + pass + + def get_current_input(self) -> str: + """ + 获取当前输入 + - 返回输入缓冲区内容 + """ + # TODO: 实现获取当前输入逻辑 + # 1. 返回输入缓冲区内容 + pass + + def reset_input(self): + """ + 重置输入 + - 清空输入缓冲区 + - 重置相关状态 + """ + # TODO: 实现输入重置逻辑 + # 1. 清空输入缓冲区 + # 2. 重置相关状态变量 + # 3. 发送重置信号(如需要) + pass + + def set_expected_text(self, text: str): + """ + 设置期望文本 + - 用于后续输入验证 + """ + # TODO: 实现设置期望文本逻辑 + # 1. 保存期望文本 + # 2. 初始化匹配相关状态 + pass + +class InputValidator: + def __init__(self): + """ + 初始化输入验证器 + - 设置验证规则 + """ + # TODO: 实现构造函数逻辑 + # 1. 初始化验证规则 + # 2. 设置默认验证参数 + pass + + def validate_character(self, input_char: str, expected_char: str) -> bool: + """ + 验证字符输入 + - 比较输入字符与期望字符 + - 返回验证结果 + """ + # TODO: 实现字符验证逻辑 + # 1. 比较输入字符与期望字符 + # 2. 考虑大小写敏感性设置 + # 3. 返回验证结果 + pass + + def validate_word(self, input_word: str, expected_word: str) -> dict: + """ + 验证单词输入 + - 比较输入单词与期望单词 + - 返回详细验证结果(正确字符数、错误字符数等) + """ + # TODO: 实现单词验证逻辑 + # 1. 逐字符比较输入单词与期望单词 + # 2. 统计正确/错误字符数 + # 3. 计算准确率 + # 4. 返回验证结果字典 + pass + + def calculate_accuracy(self, input_text: str, expected_text: str) -> float: + """ + 计算输入准确率 + - 比较输入文本与期望文本 + - 返回准确率百分比 + """ + # TODO: 实现准确率计算逻辑 + # 1. 比较输入文本与期望文本 + # 2. 统计正确字符数 + # 3. 计算准确率百分比 + # 4. 返回准确率 + pass \ No newline at end of file diff --git a/src/main.py b/src/main.py index 88bad02..40e96f8 100644 --- a/src/main.py +++ b/src/main.py @@ -1,12 +1,22 @@ -""" -1. main() -输入:无(命令行参数通过sys.argv获取) -输出:整数(程序退出码) -功能:应用程序主入口点 -需要包含: -创建QApplication实例 -创建MainWindow实例 -显示窗口 -启动事件循环 -返回退出码 -""" \ No newline at end of file +# main.py +import sys +from PyQt5.QtWidgets import QApplication +from src.main_window import MainWindow + +def main(): + """ + 应用程序主入口点 + - 创建QApplication实例 + - 创建MainWindow实例 + - 显示窗口 + - 启动事件循环 + - 返回退出码 + """ + # TODO: 实现主函数逻辑 + app = QApplication(sys.argv) + window = MainWindow() + window.show() + sys.exit(app.exec_()) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/main_window.py b/src/main_window.py index 4ec4913..2459aa2 100644 --- a/src/main_window.py +++ b/src/main_window.py @@ -1,70 +1,88 @@ -""" -1. __init__(self) -输入:无 -输出:无(构造函数) -功能:初始化主窗口,设置基本属性,调用UI初始化方法 -需要包含: -窗口标题设置为"隐私学习软件 - 仿Word" -窗口大小设置为800x600 -初始化学习内容存储变量self.learning_content = "" -初始化当前输入位置self.current_index = 0 -调用self.initUI() -2. initUI(self) -输入:无 -输出:无 -功能:创建和布局所有UI组件 -需要包含: -创建中央文本编辑区域QTextEdit -调用self.createMenuBar()创建菜单 -创建状态栏并显示"就绪" -连接文本变化信号到self.onTextChanged -3. createMenuBar(self) -输入:无 -输出:无 -功能:创建菜单栏和所有菜单项 -需要包含: -文件菜单:打开(Ctrl+O)、保存(Ctrl+S)、退出(Ctrl+Q) -帮助菜单:关于 -为每个菜单项连接对应的槽函数 -4. openFile(self) -输入:无(通过文件对话框获取路径) -输出:无 -功能:打开文件选择对话框并加载选中的文件 -需要包含: -显示文件选择对话框,过滤条件:*.txt, *.docx -如果用户选择了文件,调用FileParser.parse_file(file_path) -成功时:将内容显示在文本区域,重置打字状态 -失败时:显示错误消息框 -5. saveFile(self) -输入:无(通过文件对话框获取路径) -输出:布尔值(成功/失败) -功能:保存当前内容到文件 -需要包含: -显示保存文件对话框 -将文本区域内容写入选定文件 -返回操作结果 -6. showAbout(self) -输入:无 -输出:无 -功能:显示关于对话框 -需要包含: -显示消息框,包含软件名称、版本、描述 -7. onTextChanged(self) -输入:无(通过信号自动触发) -输出:无 -功能:处理文本变化事件,实现打字逻辑 -需要包含: -获取当前文本内容 -调用打字逻辑检查输入正确性 -更新高亮显示和状态栏 -8. highlightText(self, position, color) -输入: -position:整数,要高亮到的字符位置 -color:QColor对象,高亮颜色 -输出:无 -功能:高亮显示从开始到指定位置的文本 -需要包含: -使用QTextCursor选择文本范围 -应用背景颜色格式 -恢复光标位置 -""" +import sys +from PyQt5.QtWidgets import (QApplication, QMainWindow, QTextEdit, QAction, + QFileDialog, QVBoxLayout, QWidget, QLabel, QStatusBar) +from PyQt5.QtGui import QFont, QTextCharFormat, QColor +from PyQt5.QtCore import Qt + +class MainWindow(QMainWindow): + def __init__(self): + """ + 初始化主窗口 + - 设置窗口标题为"隐私学习软件 - 仿Word" + - 设置窗口大小为800x600 + - 初始化学习内容存储变量 + - 初始化当前输入位置 + - 调用initUI()方法 + """ + # TODO: 实现构造函数逻辑 + pass + + def initUI(self): + """ + 创建和布局所有UI组件 + - 创建中央文本编辑区域QTextEdit + - 调用createMenuBar()创建菜单 + - 创建状态栏并显示"就绪" + - 连接文本变化信号到onTextChanged + """ + # TODO: 实现UI初始化逻辑 + pass + + def createMenuBar(self): + """ + 创建菜单栏和所有菜单项 + - 文件菜单:打开(Ctrl+O)、保存(Ctrl+S)、退出(Ctrl+Q) + - 帮助菜单:关于 + - 为每个菜单项连接对应的槽函数 + """ + # TODO: 实现菜单栏创建逻辑 + pass + + def openFile(self): + """ + 打开文件选择对话框并加载选中的文件 + - 显示文件选择对话框,过滤条件:*.txt, *.docx + - 如果用户选择了文件,调用FileParser.parse_file(file_path) + - 成功时:将内容显示在文本区域,重置打字状态 + - 失败时:显示错误消息框 + """ + # TODO: 实现打开文件逻辑 + pass + + def saveFile(self): + """ + 保存当前内容到文件 + - 显示保存文件对话框 + - 将文本区域内容写入选定文件 + - 返回操作结果 + """ + # TODO: 实现保存文件逻辑 + pass + + def showAbout(self): + """ + 显示关于对话框 + - 显示消息框,包含软件名称、版本、描述 + """ + # TODO: 实现关于对话框逻辑 + pass + + def onTextChanged(self): + """ + 处理文本变化事件,实现打字逻辑 + - 获取当前文本内容 + - 调用打字逻辑检查输入正确性 + - 更新高亮显示和状态栏 + """ + # TODO: 实现文本变化处理逻辑 + pass + + def highlightText(self, position, color): + """ + 高亮显示从开始到指定位置的文本 + - 使用QTextCursor选择文本范围 + - 应用背景颜色格式 + - 恢复光标位置 + """ + # TODO: 实现文本高亮逻辑 + pass \ No newline at end of file diff --git a/src/services/network_service.py b/src/services/network_service.py new file mode 100644 index 0000000..76095ea --- /dev/null +++ b/src/services/network_service.py @@ -0,0 +1,87 @@ +# services/network_service.py +import requests +import json +from typing import Optional, Dict, Any + +class NetworkService: + def __init__(self): + """ + 初始化网络服务 + - 设置API密钥 + - 初始化缓存 + """ + # TODO: 实现构造函数逻辑 + pass + + def get_weather_info(self) -> Optional[Dict[str, Any]]: + """ + 获取天气信息 + - 调用天气API + - 解析返回数据 + - 返回格式化的天气信息 + """ + # TODO: 实现天气信息获取逻辑 + # 1. 获取用户IP地址 + # 2. 根据IP获取地理位置 + # 3. 调用天气API获取天气数据 + # 4. 解析并格式化数据 + # 5. 返回天气信息字典 + pass + + def get_daily_quote(self) -> Optional[str]: + """ + 获取每日一句 + - 调用名言API + - 返回格式化的名言 + """ + # TODO: 实现每日一句获取逻辑 + # 1. 调用名言API + # 2. 解析返回的名言数据 + # 3. 格式化名言文本 + # 4. 返回名言字符串 + pass + + def download_image(self, url: str) -> Optional[bytes]: + """ + 下载图片 + - 从指定URL下载图片 + - 返回图片二进制数据 + """ + # TODO: 实现图片下载逻辑 + # 1. 发送HTTP GET请求获取图片 + # 2. 检查响应状态码 + # 3. 返回图片二进制数据 + pass + +class ImageService: + def __init__(self): + """ + 初始化图片服务 + """ + # TODO: 实现构造函数逻辑 + pass + + def extract_images_from_document(self, file_path: str) -> list: + """ + 从文档中提取图片 + - 解析文档中的图片 + - 返回图片列表 + """ + # TODO: 实现图片提取逻辑 + # 1. 根据文件类型选择解析方法 + # 2. 提取文档中的图片数据 + # 3. 返回图片信息列表 + pass + + def display_image_at_position(self, image_data: bytes, position: int) -> bool: + """ + 在指定位置显示图片 + - 将图片插入到文本中的指定位置 + - 返回操作结果 + """ + # TODO: 实现图片显示逻辑 + # 1. 创建图片对象 + # 2. 在指定位置插入图片 + # 3. 更新UI显示 + # 4. 返回操作结果 + pass \ No newline at end of file diff --git a/src/settings/settings_manager.py b/src/settings/settings_manager.py new file mode 100644 index 0000000..e5fdd76 --- /dev/null +++ b/src/settings/settings_manager.py @@ -0,0 +1,50 @@ +# settings/settings_manager.py +import json +import os +from typing import Any, Dict + +class SettingsManager: + def __init__(self, config_file: str = "config.json"): + """ + 初始化设置管理器 + - 指定配置文件路径 + - 加载现有配置或创建默认配置 + """ + # TODO: 实现构造函数逻辑 + pass + + def load_settings(self) -> Dict[str, Any]: + """ + 加载设置 + - 从配置文件读取设置 + - 返回设置字典 + """ + # TODO: 实现设置加载逻辑 + pass + + def save_settings(self, settings: Dict[str, Any]) -> bool: + """ + 保存设置 + - 将设置保存到配置文件 + - 返回保存结果 + """ + # TODO: 实现设置保存逻辑 + pass + + def get_setting(self, key: str, default: Any = None) -> Any: + """ + 获取特定设置项 + - 根据键名获取设置值 + - 如果不存在返回默认值 + """ + # TODO: 实现获取设置项逻辑 + pass + + def set_setting(self, key: str, value: Any) -> bool: + """ + 设置特定设置项 + - 设置指定键的值 + - 保存到配置文件 + """ + # TODO: 实现设置设置项逻辑 + pass \ No newline at end of file diff --git a/src/typing_logic.py b/src/typing_logic.py index c2e1fee..6bf0a83 100644 --- a/src/typing_logic.py +++ b/src/typing_logic.py @@ -1,54 +1,67 @@ -""" -1. __init__(self, learning_content) -输入:learning_content:字符串,学习材料 -输出:无(构造函数) -功能:初始化打字逻辑状态 -需要包含: -存储学习材料 -初始化当前索引为0 -初始化错误计数为0 -2. check_input(self, user_text) -输入:user_text:字符串,用户输入的文本 -输出:字典,包含检查结果 -correct:布尔值,当前输入是否正确 -expected:字符串,当前期望的字符 -position:整数,当前位置 -completed:布尔值,是否完成 -accuracy:浮点数,准确率 -功能:检查用户输入与学习材料的匹配情况 -需要包含: -逐字符比较逻辑 -进度跟踪 -准确率计算 -3. get_expected_text(self) -输入:无 -输出:字符串(当前期望输入的文本部分) -功能:获取用户接下来应该输入的内容 -需要包含: -返回从当前位置开始的一定长度文本(如10个字符) -处理文本结束情况 -4. get_progress(self) -输入:无 -输出:字典,包含进度信息 -current:整数,当前位置 -total:整数,总长度 -percentage:浮点数,完成百分比 -remaining:整数,剩余字符数 -功能:获取当前学习进度统计 -5. reset(self, new_content=None) -输入:new_content:字符串(可选),新的学习材料 -输出:无 -功能:重置打字状态 -需要包含: -重置当前索引为0 -重置错误计数 -如果提供了新内容,更新学习材料 -6. get_statistics(self) -输入:无 -输出:字典,包含统计信息 -total_chars:整数,总字符数 -typed_chars:整数,已输入字符数 -error_count:整数,错误次数 -accuracy_rate:浮点数,准确率 -功能:获取打字统计信息 -""" \ No newline at end of file +class TypingLogic: + def __init__(self, learning_content: str): + """ + 初始化打字逻辑状态 + - 存储学习材料 + - 初始化当前索引为0 + - 初始化错误计数为0 + """ + # TODO: 实现构造函数逻辑 + pass + + def check_input(self, user_text: str) -> dict: + """ + 检查用户输入与学习材料的匹配情况 + - 逐字符比较逻辑 + - 进度跟踪 + - 准确率计算 + - 返回字典包含: + * correct: 布尔值,当前输入是否正确 + * expected: 字符串,当前期望的字符 + * position: 整数,当前位置 + * completed: 布尔值,是否完成 + * accuracy: 浮点数,准确率 + """ + # TODO: 实现输入检查逻辑 + pass + + def get_expected_text(self) -> str: + """ + 获取用户接下来应该输入的内容 + - 返回从当前位置开始的一定长度文本(如10个字符) + - 处理文本结束情况 + """ + # TODO: 实现期望文本获取逻辑 + pass + + def get_progress(self) -> dict: + """ + 获取当前学习进度统计 + - current: 整数,当前位置 + - total: 整数,总长度 + - percentage: 浮点数,完成百分比 + - remaining: 整数,剩余字符数 + """ + # TODO: 实现进度获取逻辑 + pass + + def reset(self, new_content: str = None): + """ + 重置打字状态 + - 重置当前索引为0 + - 重置错误计数 + - 如果提供了新内容,更新学习材料 + """ + # TODO: 实现重置逻辑 + pass + + def get_statistics(self) -> dict: + """ + 获取打字统计信息 + - total_chars: 整数,总字符数 + - typed_chars: 整数,已输入字符数 + - error_count: 整数,错误次数 + - accuracy_rate: 浮点数,准确率 + """ + # TODO: 实现统计信息获取逻辑 + pass \ No newline at end of file diff --git a/src/ui/components.py b/src/ui/components.py new file mode 100644 index 0000000..2763f93 --- /dev/null +++ b/src/ui/components.py @@ -0,0 +1,148 @@ +# ui/components.py +from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QVBoxLayout, QHBoxLayout +from PyQt5.QtCore import Qt + +class CustomTitleBar(QWidget): + def __init__(self, parent=None): + """ + 自定义标题栏 + - 创建标题栏UI元素 + - 添加窗口控制按钮 + """ + super().__init__(parent) + # TODO: 实现标题栏UI + # 1. 创建标题标签 + # 2. 创建最小化、最大化、关闭按钮 + # 3. 设置布局和样式 + # 4. 连接按钮事件 + pass + + def setup_ui(self): + """ + 设置标题栏UI + - 初始化所有UI组件 + - 设置组件属性和样式 + """ + # TODO: 实现UI设置逻辑 + # 1. 创建水平布局 + # 2. 添加标题标签和控制按钮 + # 3. 设置组件样式 + pass + + def minimize_window(self): + """ + 最小化窗口 + - 触发窗口最小化事件 + """ + # TODO: 实现窗口最小化逻辑 + # 1. 获取父窗口 + # 2. 调用窗口最小化方法 + pass + + def maximize_window(self): + """ + 最大化窗口 + - 切换窗口最大化状态 + """ + # TODO: 实现窗口最大化逻辑 + # 1. 获取父窗口 + # 2. 检查当前窗口状态 + # 3. 切换最大化/还原状态 + pass + + def close_window(self): + """ + 关闭窗口 + - 触发窗口关闭事件 + """ + # TODO: 实现窗口关闭逻辑 + # 1. 获取父窗口 + # 2. 调用窗口关闭方法 + pass + +class ProgressBarWidget(QWidget): + def __init__(self, parent=None): + """ + 进度条组件 + - 显示打字练习进度 + - 显示统计信息 + """ + super().__init__(parent) + # TODO: 实现进度条组件初始化 + # 1. 创建进度条UI元素 + # 2. 创建统计信息标签 + # 3. 设置布局 + pass + + def update_progress(self, progress: float): + """ + 更新进度条 + - 设置进度值 + - 更新显示 + """ + # TODO: 实现进度更新逻辑 + # 1. 更新进度条数值 + # 2. 刷新UI显示 + pass + + def update_stats(self, wpm: int, accuracy: float, time_elapsed: int): + """ + 更新统计信息 + - 显示WPM、准确率、用时等信息 + """ + # TODO: 实现统计信息更新逻辑 + # 1. 更新WPM标签 + # 2. 更新准确率标签 + # 3. 更新用时标签 + pass + +class TextDisplayWidget(QWidget): + def __init__(self, parent=None): + """ + 文本显示组件 + - 显示待练习文本 + - 高亮当前字符 + - 显示用户输入 + """ + super().__init__(parent) + # TODO: 实现文本显示组件初始化 + # 1. 创建文本显示区域 + # 2. 设置文本样式 + # 3. 初始化高亮相关属性 + pass + + def set_text(self, text: str): + """ + 设置显示文本 + - 更新显示内容 + - 重置高亮状态 + """ + # TODO: 实现文本设置逻辑 + # 1. 更新内部文本内容 + # 2. 重置高亮位置 + # 3. 刷新UI显示 + pass + + def highlight_character(self, position: int): + """ + 高亮指定位置字符 + - 更新高亮位置 + - 刷新显示 + """ + # TODO: 实现字符高亮逻辑 + # 1. 计算高亮范围 + # 2. 应用高亮样式 + # 3. 滚动到高亮位置 + pass + + def show_user_input(self, input_text: str): + """ + 显示用户输入 + - 在文本下方显示用户输入 + - 高亮正确/错误字符 + """ + # TODO: 实现用户输入显示逻辑 + # 1. 对比用户输入与原文 + # 2. 分别高亮正确和错误字符 + # 3. 更新输入显示区域 + pass \ No newline at end of file diff --git a/src/utils/helper_functions.py b/src/utils/helper_functions.py new file mode 100644 index 0000000..af3cb2f --- /dev/null +++ b/src/utils/helper_functions.py @@ -0,0 +1,35 @@ +# utils/helper_functions.py +import os +import hashlib +from typing import Optional + +class Utils: + @staticmethod + def detect_encoding(file_path: str) -> str: + """ + 检测文件编码 + - 尝试多种编码格式 + - 返回最可能的编码 + """ + # TODO: 实现编码检测逻辑 + pass + + @staticmethod + def format_file_size(size_bytes: int) -> str: + """ + 格式化文件大小 + - 将字节数转换为可读格式 + - 返回格式化字符串 + """ + # TODO: 实现文件大小格式化逻辑 + pass + + @staticmethod + def calculate_file_hash(file_path: str) -> str: + """ + 计算文件哈希值 + - 使用SHA256算法 + - 返回哈希字符串 + """ + # TODO: 实现文件哈希计算逻辑 + pass \ No newline at end of file diff --git a/tests/test_file_operations.py b/tests/test_file_operations.py new file mode 100644 index 0000000..61fe3a3 --- /dev/null +++ b/tests/test_file_operations.py @@ -0,0 +1,88 @@ +# tests/test_file_operations.py +import sys +import os +import unittest +import tempfile +import shutil +from pathlib import Path + +# 添加src目录到Python路径 +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) + +class TestFileManager(unittest.TestCase): + def setUp(self): + """ + 测试前准备 + - 创建临时目录和测试文件 + """ + # TODO: 实现测试环境初始化逻辑 + # 1. 创建临时测试目录 + # 2. 创建测试文件 + # 3. 导入文件管理模块 + # 4. 创建文件管理器实例 + pass + + def tearDown(self): + """ + 测试后清理 + - 删除临时目录和文件 + """ + # TODO: 实现测试环境清理逻辑 + # 1. 删除临时测试目录 + # 2. 清理文件管理器状态 + pass + + def test_list_files(self): + """ + 测试文件列表功能 + - 验证文件列表准确性 + - 检查扩展名过滤功能 + """ + # TODO: 实现文件列表测试逻辑 + # 1. 在临时目录中创建不同类型文件 + # 2. 调用list_files方法 + # 3. 验证返回文件列表 + # 4. 测试扩展名过滤功能 + pass + + def test_copy_file(self): + """ + 测试文件复制功能 + - 验证文件复制正确性 + - 检查异常处理 + """ + # TODO: 实现文件复制测试逻辑 + # 1. 准备源文件 + # 2. 调用copy_file方法 + # 3. 验证目标文件是否存在且内容正确 + # 4. 测试异常情况(源文件不存在等) + pass + + def test_move_file(self): + """ + 测试文件移动功能 + - 验证文件移动正确性 + - 检查源文件是否被删除 + """ + # TODO: 实现文件移动测试逻辑 + # 1. 准备源文件 + # 2. 调用move_file方法 + # 3. 验证目标文件是否存在且内容正确 + # 4. 验证源文件是否已被删除 + pass + + def test_delete_file(self): + """ + 测试文件删除功能 + - 验证文件删除成功性 + - 检查异常处理 + """ + # TODO: 实现文件删除测试逻辑 + # 1. 准备测试文件 + # 2. 调用delete_file方法 + # 3. 验证文件是否已被删除 + # 4. 测试异常情况(文件不存在等) + pass + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/tests/test_input_processor.py b/tests/test_input_processor.py new file mode 100644 index 0000000..b53154b --- /dev/null +++ b/tests/test_input_processor.py @@ -0,0 +1,71 @@ +# tests/test_input_processor.py +import sys +import os +import unittest +from PyQt5.QtCore import QEvent, Qt +from PyQt5.QtGui import QKeyEvent + +# 添加src目录到Python路径 +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) + +class TestInputProcessor(unittest.TestCase): + def setUp(self): + """ + 测试前准备 + """ + # TODO: 实现测试环境初始化逻辑 + # 1. 导入输入处理模块 + # 2. 创建输入处理器实例 + # 3. 初始化测试变量 + pass + + def tearDown(self): + """ + 测试后清理 + """ + # TODO: 实现测试环境清理逻辑 + # 1. 重置输入处理器状态 + # 2. 清理测试数据 + pass + + def test_process_key_event(self): + """ + 测试按键事件处理 + - 验证不同按键的处理结果 + - 检查信号发送 + """ + # TODO: 实现按键事件处理测试逻辑 + # 1. 创建不同类型的按键事件 + # 2. 调用process_key_event方法 + # 3. 验证返回结果 + # 4. 检查信号是否正确发送 + pass + + def test_input_validation(self): + """ + 测试输入验证功能 + - 验证字符验证准确性 + - 检查单词验证结果 + """ + # TODO: 实现输入验证测试逻辑 + # 1. 准备测试输入和期望文本 + # 2. 调用验证方法 + # 3. 验证验证结果 + # 4. 检查边界情况处理 + pass + + def test_accuracy_calculation(self): + """ + 测试准确率计算 + - 验证准确率计算正确性 + - 检查特殊输入情况 + """ + # TODO: 实现准确率计算测试逻辑 + # 1. 准备测试输入和期望文本 + # 2. 调用准确率计算方法 + # 3. 验证计算结果 + # 4. 检查边界情况(空输入、完全错误等) + pass + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 0000000..d087221 --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,60 @@ +# tests/test_main.py +import sys +import os +import unittest + +# 添加src目录到Python路径 +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) + +class TestMagicWordApplication(unittest.TestCase): + def setUp(self): + """ + 测试前准备 + - 初始化测试环境 + - 创建测试数据 + """ + # TODO: 实现测试环境初始化逻辑 + # 1. 创建临时测试目录 + # 2. 准备测试文件 + # 3. 初始化被测试对象 + pass + + def tearDown(self): + """ + 测试后清理 + - 清理测试数据 + - 恢复环境状态 + """ + # TODO: 实现测试环境清理逻辑 + # 1. 删除临时测试文件 + # 2. 清理测试目录 + # 3. 重置全局状态 + pass + + def test_application_startup(self): + """ + 测试应用启动 + - 验证应用能够正常启动 + - 检查初始状态 + """ + # TODO: 实现应用启动测试逻辑 + # 1. 导入主应用模块 + # 2. 创建应用实例 + # 3. 验证应用初始化状态 + # 4. 检查必要组件是否加载 + pass + + def test_file_operations(self): + """ + 测试文件操作 + - 验证文件打开、保存等功能 + """ + # TODO: 实现文件操作测试逻辑 + # 1. 准备测试文件 + # 2. 测试文件打开功能 + # 3. 测试文件保存功能 + # 4. 验证文件内容正确性 + pass + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/tests/test_network_service.py b/tests/test_network_service.py new file mode 100644 index 0000000..dbcbcd6 --- /dev/null +++ b/tests/test_network_service.py @@ -0,0 +1,73 @@ +# tests/test_network_service.py +import sys +import os +import unittest +from unittest.mock import patch, Mock + +# 添加src目录到Python路径 +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) + +class TestNetworkService(unittest.TestCase): + def setUp(self): + """ + 测试前准备 + """ + # TODO: 实现测试环境初始化逻辑 + # 1. 导入网络服务模块 + # 2. 创建网络服务实例 + # 3. 准备测试数据 + pass + + def tearDown(self): + """ + 测试后清理 + """ + # TODO: 实现测试环境清理逻辑 + # 1. 重置网络服务状态 + # 2. 清理模拟对象 + pass + + @patch('requests.get') + def test_get_weather_info(self, mock_get): + """ + 测试获取天气信息功能 + - 模拟网络请求 + - 验证返回数据格式 + """ + # TODO: 实现天气信息获取测试逻辑 + # 1. 准备模拟响应数据 + # 2. 设置mock对象返回值 + # 3. 调用被测试方法 + # 4. 验证返回数据格式和内容 + pass + + @patch('requests.get') + def test_get_daily_quote(self, mock_get): + """ + 测试获取每日一句功能 + - 模拟网络请求 + - 验证返回数据 + """ + # TODO: 实现每日一句获取测试逻辑 + # 1. 准备模拟响应数据 + # 2. 设置mock对象返回值 + # 3. 调用被测试方法 + # 4. 验证返回数据 + pass + + @patch('requests.get') + def test_download_image(self, mock_get): + """ + 测试图片下载功能 + - 模拟网络请求 + - 验证返回的图片数据 + """ + # TODO: 实现图片下载测试逻辑 + # 1. 准备模拟响应数据(图片二进制数据) + # 2. 设置mock对象返回值 + # 3. 调用被测试方法 + # 4. 验证返回的图片数据 + pass + +if __name__ == '__main__': + unittest.main() \ No newline at end of file