init
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# 基于编辑器的 HTTP 客户端请求
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
10
.idea/AugmentWebviewStateStore.xml
generated
Normal file
14
.idea/MetaCore.iml
generated
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.13 (MetaCore-startup)" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="PyDocumentationSettings">
|
||||||
|
<option name="format" value="PLAIN" />
|
||||||
|
<option name="myDocStringFormat" value="Plain" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PyStubPackagesAdvertiser" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredPackages">
|
||||||
|
<list>
|
||||||
|
<option value="PyQt5-stubs==5.15.6.0" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
7
.idea/misc.xml
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.12" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (MetaCore-startup)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/MetaCore.iml" filepath="$PROJECT_DIR$/.idea/MetaCore.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
224
CROSS_PLATFORM_OPTIMIZATION.md
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
# 跨平台路径处理优化报告
|
||||||
|
|
||||||
|
## 优化概述
|
||||||
|
|
||||||
|
本次优化主要针对 MetaCore 项目中的跨平台兼容性和路径处理问题,使用现代 Python 标准库 `pathlib` 替代传统的 `os.path`,并创建了专门的工具类来处理跨平台差异。
|
||||||
|
|
||||||
|
## 主要问题
|
||||||
|
|
||||||
|
### 1. 路径处理问题
|
||||||
|
- **混合使用路径分隔符**:代码中存在大量 `replace('\\', '/')` 操作,这是不规范且不可靠的做法
|
||||||
|
- **硬编码路径**:存在平台特定的硬编码路径,如Linux下的 `/home/tiger/下载/pycharm-2025.2.0.1/bin/pycharm.sh`
|
||||||
|
- **不一致的路径API**:混合使用 `os.path.join` 和字符串拼接
|
||||||
|
|
||||||
|
### 2. 跨平台兼容性问题
|
||||||
|
- **平台检测重复**:多处重复的平台类型检测代码
|
||||||
|
- **可执行文件查找**:没有统一的可执行文件查找机制
|
||||||
|
- **路径规范化不统一**:不同地方使用不同的路径规范化方法
|
||||||
|
|
||||||
|
## 优化方案
|
||||||
|
|
||||||
|
### 1. 创建工具类
|
||||||
|
|
||||||
|
#### PathUtils 类
|
||||||
|
```python
|
||||||
|
class PathUtils:
|
||||||
|
"""跨平台路径处理工具类"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def normalize_path(path_str: str) -> Path:
|
||||||
|
"""规范化路径为Path对象"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def ensure_path_exists(path: Path, is_file: bool = False) -> bool:
|
||||||
|
"""确保路径存在"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def safe_path_join(*parts) -> Path:
|
||||||
|
"""安全地连接路径部分"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_valid_path(path_str: str) -> bool:
|
||||||
|
"""检查路径字符串是否有效"""
|
||||||
|
```
|
||||||
|
|
||||||
|
#### PlatformUtils 类
|
||||||
|
```python
|
||||||
|
class PlatformUtils:
|
||||||
|
"""跨平台工具类"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_system_type() -> str:
|
||||||
|
"""获取系统类型"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_executable_extension() -> str:
|
||||||
|
"""获取可执行文件扩展名"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_python_executable(venv_path: Path) -> Path:
|
||||||
|
"""获取虚拟环境中的Python可执行文件路径"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_pycharm_paths() -> List[Path]:
|
||||||
|
"""获取各平台PyCharm可能的安装路径"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def find_executable(paths: List[Path]) -> Optional[Path]:
|
||||||
|
"""在指定路径列表中查找可执行文件"""
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 优化的文件
|
||||||
|
|
||||||
|
#### MetaCore/data/project_manager.py
|
||||||
|
- **完全重构**:使用 `pathlib.Path` 替代所有 `os.path` 操作
|
||||||
|
- **统一路径处理**:所有路径操作都通过 `PathUtils` 进行
|
||||||
|
- **移除硬编码路径**:使用动态路径查找替代硬编码路径
|
||||||
|
- **改进的PyCharm集成**:使用统一的可执行文件查找机制
|
||||||
|
|
||||||
|
#### MetaCore/ui/project_card.py
|
||||||
|
- **优化 show_in_explorer 方法**:使用 `pathlib` 处理路径
|
||||||
|
- **改进错误处理**:更好的异常处理和用户提示
|
||||||
|
- **跨平台文件管理器支持**:统一的文件管理器打开逻辑
|
||||||
|
|
||||||
|
### 3. 主要改进
|
||||||
|
|
||||||
|
#### 路径处理改进
|
||||||
|
- ✅ 使用 `pathlib.Path` 替代 `os.path`
|
||||||
|
- ✅ 统一的路径规范化方法
|
||||||
|
- ✅ 自动处理不同操作系统的路径格式
|
||||||
|
- ✅ 移除手动的路径分隔符替换
|
||||||
|
|
||||||
|
#### 跨平台兼容性改进
|
||||||
|
- ✅ 统一的平台检测机制
|
||||||
|
- ✅ 动态的可执行文件查找
|
||||||
|
- ✅ 平台特定的配置统一管理
|
||||||
|
- ✅ 改进的错误处理和回退机制
|
||||||
|
|
||||||
|
#### 代码质量改进
|
||||||
|
- ✅ 减少代码重复
|
||||||
|
- ✅ 更好的类型提示
|
||||||
|
- ✅ 统一的异常处理
|
||||||
|
- ✅ 改进的文档和注释
|
||||||
|
|
||||||
|
## 具体优化案例
|
||||||
|
|
||||||
|
### 1. 路径连接优化
|
||||||
|
|
||||||
|
**优化前:**
|
||||||
|
```python
|
||||||
|
project_dir = os.path.join(path, title).replace('\\', '/')
|
||||||
|
full_path = os.path.normpath(os.path.join(project_dir, filename))
|
||||||
|
```
|
||||||
|
|
||||||
|
**优化后:**
|
||||||
|
```python
|
||||||
|
path_obj = PathUtils.normalize_path(path)
|
||||||
|
project_dir = path_obj / title
|
||||||
|
full_path = project_dir / filename
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. PyCharm路径查找优化
|
||||||
|
|
||||||
|
**优化前:**
|
||||||
|
```python
|
||||||
|
if system == "linux":
|
||||||
|
return [
|
||||||
|
"pycharm",
|
||||||
|
"pycharm.sh",
|
||||||
|
"/opt/pycharm*/bin/pycharm.sh",
|
||||||
|
"/usr/local/bin/pycharm",
|
||||||
|
"/usr/bin/pycharm",
|
||||||
|
"/home/tiger/下载/pycharm-2025.2.0.1/bin/pycharm.sh", # 硬编码路径
|
||||||
|
os.path.expanduser("~/.local/share/JetBrains/Toolbox/apps/PyCharm-P/ch-*/bin/pycharm.sh")
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
**优化后:**
|
||||||
|
```python
|
||||||
|
else: # Linux
|
||||||
|
return [
|
||||||
|
Path("pycharm"),
|
||||||
|
Path("pycharm.sh"),
|
||||||
|
*Path("/opt").glob("pycharm*/bin/pycharm.sh"),
|
||||||
|
Path("/usr/local/bin/pycharm"),
|
||||||
|
Path("/usr/bin/pycharm"),
|
||||||
|
*home.glob(".local/share/JetBrains/Toolbox/apps/PyCharm-P/ch-*/bin/pycharm.sh")
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 虚拟环境Python可执行文件查找优化
|
||||||
|
|
||||||
|
**优化前:**
|
||||||
|
```python
|
||||||
|
if os.name == 'nt': # Windows
|
||||||
|
python_executable = Path(venv_path) / 'Scripts' / 'python.exe'
|
||||||
|
else: # Unix-like systems
|
||||||
|
python_executable = Path(venv_path) / 'bin' / 'python'
|
||||||
|
```
|
||||||
|
|
||||||
|
**优化后:**
|
||||||
|
```python
|
||||||
|
python_executable = PlatformUtils.get_python_executable(venv_path_obj)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 测试建议
|
||||||
|
|
||||||
|
### 1. 跨平台测试
|
||||||
|
- Windows 10/11
|
||||||
|
- macOS (Intel & Apple Silicon)
|
||||||
|
- Ubuntu/Debian Linux
|
||||||
|
- CentOS/RHEL Linux
|
||||||
|
|
||||||
|
### 2. 路径测试
|
||||||
|
- 包含中文字符的路径
|
||||||
|
- 包含空格的路径
|
||||||
|
- 超长路径
|
||||||
|
- 网络路径 (Windows UNC)
|
||||||
|
- 符号链接
|
||||||
|
|
||||||
|
### 3. 功能测试
|
||||||
|
- 项目创建和导入
|
||||||
|
- 文件管理器打开
|
||||||
|
- PyCharm集成
|
||||||
|
- 虚拟环境处理
|
||||||
|
|
||||||
|
## 后续优化建议
|
||||||
|
|
||||||
|
### 1. 配置文件优化
|
||||||
|
- 使用 `pathlib` 优化配置文件路径处理
|
||||||
|
- 统一配置文件格式和位置
|
||||||
|
|
||||||
|
### 2. 资源文件处理
|
||||||
|
- 优化图标和资源文件的路径处理
|
||||||
|
- 支持相对路径和绝对路径
|
||||||
|
|
||||||
|
### 3. 日志系统
|
||||||
|
- 添加路径相关的详细日志
|
||||||
|
- 改进错误报告机制
|
||||||
|
|
||||||
|
### 4. 单元测试
|
||||||
|
- 为路径处理工具类添加单元测试
|
||||||
|
- 添加跨平台兼容性测试
|
||||||
|
|
||||||
|
## 性能影响
|
||||||
|
|
||||||
|
### 正面影响
|
||||||
|
- ✅ **更少的路径转换操作**:减少字符串替换操作
|
||||||
|
- ✅ **更好的缓存利用**:Path对象的内置缓存机制
|
||||||
|
- ✅ **减少重复代码**:统一的工具函数
|
||||||
|
|
||||||
|
### 注意事项
|
||||||
|
- ⚠️ **Path对象创建开销**:虽然很小,但比字符串操作略重
|
||||||
|
- ⚠️ **兼容性**:确保所有Path对象在需要时正确转换为字符串
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
本次优化显著改善了 MetaCore 项目的跨平台兼容性和代码质量:
|
||||||
|
|
||||||
|
1. **统一性**:所有路径操作现在使用统一的API
|
||||||
|
2. **可靠性**:减少了平台特定的bug和问题
|
||||||
|
3. **可维护性**:代码更清晰,更容易维护和扩展
|
||||||
|
4. **现代化**:使用现代Python最佳实践
|
||||||
|
|
||||||
|
这些改进为项目的长期维护和跨平台部署奠定了坚实的基础。
|
||||||
80
Doc/README.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# MetaCore 项目文档中心
|
||||||
|
|
||||||
|
欢迎来到MetaCore项目文档中心!这里包含了项目的所有说明文档,按类别整理便于查阅。
|
||||||
|
|
||||||
|
## 📚 文档分类
|
||||||
|
|
||||||
|
### 🚀 快速开始
|
||||||
|
- **[快速开始.md](快速开始.md)** - 新用户必读,快速上手指南
|
||||||
|
- **[安装PyQt5指南.md](安装PyQt5指南.md)** - PyQt5安装详细步骤
|
||||||
|
|
||||||
|
### 📖 详细说明
|
||||||
|
- **[README_PyQt5.md](README_PyQt5.md)** - PyQt5版本完整功能说明
|
||||||
|
- **[项目总览.md](项目总览.md)** - 整个项目的全面概述
|
||||||
|
- **[功能对比说明.md](功能对比说明.md)** - Web版本与PyQt5版本对比
|
||||||
|
|
||||||
|
### 🔧 环境配置
|
||||||
|
- **[虚拟环境完整指南.md](虚拟环境完整指南.md)** - 虚拟环境完整指南
|
||||||
|
|
||||||
|
## 🎯 推荐阅读顺序
|
||||||
|
|
||||||
|
### 新用户
|
||||||
|
1. [快速开始.md](快速开始.md) - 了解如何快速启动
|
||||||
|
2. [安装PyQt5指南.md](安装PyQt5指南.md) - 解决安装问题
|
||||||
|
3. [README_PyQt5.md](README_PyQt5.md) - 了解完整功能
|
||||||
|
|
||||||
|
### 开发者
|
||||||
|
1. [项目总览.md](项目总览.md) - 了解项目整体架构
|
||||||
|
2. [功能对比说明.md](功能对比说明.md) - 理解两个版本的差异
|
||||||
|
3. [虚拟环境完整指南.md](虚拟环境完整指南.md) - 配置开发环境
|
||||||
|
|
||||||
|
### 系统管理员
|
||||||
|
1. [虚拟环境完整指南.md](虚拟环境完整指南.md) - 环境部署
|
||||||
|
2. [安装PyQt5指南.md](安装PyQt5指南.md) - 依赖安装
|
||||||
|
3. [项目总览.md](项目总览.md) - 了解项目状态
|
||||||
|
|
||||||
|
## 🔍 快速查找
|
||||||
|
|
||||||
|
### 按问题类型查找
|
||||||
|
|
||||||
|
#### 安装问题
|
||||||
|
- PyQt5安装失败 → [安装PyQt5指南.md](安装PyQt5指南.md)
|
||||||
|
- 虚拟环境配置 → [虚拟环境完整指南.md](虚拟环境完整指南.md)
|
||||||
|
|
||||||
|
#### 使用问题
|
||||||
|
- 如何启动应用 → [快速开始.md](快速开始.md)
|
||||||
|
- 功能说明 → [README_PyQt5.md](README_PyQt5.md)
|
||||||
|
- 版本选择 → [功能对比说明.md](功能对比说明.md)
|
||||||
|
|
||||||
|
#### 开发问题
|
||||||
|
- 项目架构 → [项目总览.md](项目总览.md)
|
||||||
|
- 功能对比 → [功能对比说明.md](功能对比说明.md)
|
||||||
|
|
||||||
|
## 📱 文档更新
|
||||||
|
|
||||||
|
### 最新更新
|
||||||
|
- **2024年** - 完成PyQt5版本开发
|
||||||
|
- **最近** - 整理文档到Doc目录
|
||||||
|
|
||||||
|
### 维护说明
|
||||||
|
- 所有文档统一存放在Doc目录
|
||||||
|
- 按功能和用途分类
|
||||||
|
- 定期更新和维护
|
||||||
|
|
||||||
|
## 🎯 使用建议
|
||||||
|
|
||||||
|
### 查阅文档
|
||||||
|
1. **从README.md开始** - 本文档提供了完整的导航
|
||||||
|
2. **按需查阅** - 根据具体问题选择相应文档
|
||||||
|
3. **顺序阅读** - 新用户建议按推荐顺序阅读
|
||||||
|
|
||||||
|
### 贡献文档
|
||||||
|
1. **保持结构** - 新文档应放在Doc目录
|
||||||
|
2. **更新索引** - 添加新文档时更新本README
|
||||||
|
3. **统一格式** - 遵循现有文档的格式规范
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
💡 **提示:** 如果您是第一次使用MetaCore,建议从 [快速开始.md](快速开始.md) 开始阅读!
|
||||||
|
|
||||||
|
🎉 **欢迎使用MetaCore项目管理平台!**
|
||||||
210
Doc/README_PyQt5.md
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
# MetaCore - PyQt5版本
|
||||||
|
|
||||||
|
这是基于PyQt5重写的MetaCore项目管理平台,完全复制了原始Web版本的界面和功能。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
### 🎯 主要功能
|
||||||
|
- ✅ **项目管理**:创建、导入、删除、重命名项目
|
||||||
|
- ✅ **项目卡片**:三段式布局(标题+菜单、图片+类型标签、时间)
|
||||||
|
- ✅ **收藏功能**:项目收藏/取消收藏
|
||||||
|
- ✅ **搜索过滤**:按名称搜索、按类型过滤
|
||||||
|
- ✅ **视图模式**:网格视图和列表视图
|
||||||
|
- ✅ **右键菜单**:完整的项目操作菜单
|
||||||
|
|
||||||
|
### 🎨 界面特性
|
||||||
|
- ✅ **深色主题**:现代化的深色界面设计
|
||||||
|
- ✅ **响应式布局**:自适应窗口大小
|
||||||
|
- ✅ **侧边栏导航**:可展开/收起的导航菜单
|
||||||
|
- ✅ **模态对话框**:创建项目和导入项目对话框
|
||||||
|
- ✅ **拖拽支持**:文件拖拽导入功能
|
||||||
|
|
||||||
|
## 安装和运行
|
||||||
|
|
||||||
|
### 1. 环境要求
|
||||||
|
- Python 3.7+
|
||||||
|
- PyQt5 5.15.0+
|
||||||
|
|
||||||
|
### 2. 安装依赖
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 运行应用
|
||||||
|
```bash
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
MetaCore/
|
||||||
|
├── main.py # 主程序入口
|
||||||
|
├── requirements.txt # 依赖包列表
|
||||||
|
├── README_PyQt5.md # 说明文档
|
||||||
|
├── data/ # 数据模块
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ ├── project_manager.py # 项目数据管理器
|
||||||
|
│ └── projects.json # 项目数据文件(自动生成)
|
||||||
|
└── ui/ # 界面模块
|
||||||
|
├── __init__.py
|
||||||
|
├── main_window.py # 主窗口
|
||||||
|
├── sidebar.py # 侧边栏组件
|
||||||
|
├── project_area.py # 项目显示区域
|
||||||
|
├── project_card.py # 项目卡片组件
|
||||||
|
├── create_project_dialog.py # 创建项目对话框
|
||||||
|
├── import_project_dialog.py # 导入项目对话框
|
||||||
|
└── styles.py # 样式表定义
|
||||||
|
```
|
||||||
|
|
||||||
|
## 主要组件说明
|
||||||
|
|
||||||
|
### 1. 主窗口 (MainWindow)
|
||||||
|
- 整体布局管理
|
||||||
|
- 菜单栏和状态栏
|
||||||
|
- 组件间信号连接
|
||||||
|
- 窗口事件处理
|
||||||
|
|
||||||
|
### 2. 侧边栏 (Sidebar)
|
||||||
|
- Logo区域
|
||||||
|
- 快速操作按钮
|
||||||
|
- 可展开的导航菜单
|
||||||
|
- 用户信息显示
|
||||||
|
|
||||||
|
### 3. 项目区域 (ProjectArea)
|
||||||
|
- 工具栏和搜索区域
|
||||||
|
- 网格/列表视图切换
|
||||||
|
- 项目卡片容器
|
||||||
|
- 空状态显示
|
||||||
|
|
||||||
|
### 4. 项目卡片 (ProjectCard)
|
||||||
|
- 三段式布局设计
|
||||||
|
- 悬停效果
|
||||||
|
- 右键菜单
|
||||||
|
- 收藏状态显示
|
||||||
|
|
||||||
|
### 5. 创建项目对话框 (CreateProjectDialog)
|
||||||
|
- 2:1布局比例
|
||||||
|
- 模板选择网格
|
||||||
|
- 项目信息表单
|
||||||
|
- 文件夹选择功能
|
||||||
|
|
||||||
|
### 6. 导入项目对话框 (ImportProjectDialog)
|
||||||
|
- 文件拖拽上传
|
||||||
|
- 导入选项配置
|
||||||
|
- 文件列表显示
|
||||||
|
- 进度反馈
|
||||||
|
|
||||||
|
## 数据管理
|
||||||
|
|
||||||
|
### 项目数据结构
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"title": "项目名称",
|
||||||
|
"date": "2024-06-08 15:56:35",
|
||||||
|
"type": "industrial",
|
||||||
|
"image": "🏭",
|
||||||
|
"favorite": true,
|
||||||
|
"path": "/path/to/project"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 支持的项目类型
|
||||||
|
- `industrial` - 工业项目 🏭
|
||||||
|
- `smart` - 智能项目 💧
|
||||||
|
- `vr` - VR项目 🥽
|
||||||
|
- `game` - 游戏项目 🎮
|
||||||
|
- `design` - 设计项目 🎨
|
||||||
|
- `empty` - 空白项目 📁
|
||||||
|
|
||||||
|
## 样式系统
|
||||||
|
|
||||||
|
### 主题色彩
|
||||||
|
- **主色调**:深灰色 (#1a1a1a, #2a2a2a)
|
||||||
|
- **边框色**:中灰色 (#3a3a3a, #4a4a4a)
|
||||||
|
- **强调色**:紫色 (#8b5cf6, #7c3aed)
|
||||||
|
- **文字色**:白色/灰色 (#ffffff, #cccccc, #888888)
|
||||||
|
|
||||||
|
### 组件样式
|
||||||
|
- 所有组件都有对应的ObjectName用于样式选择器
|
||||||
|
- 支持悬停状态和选中状态
|
||||||
|
- 统一的圆角和间距设计
|
||||||
|
- 平滑的过渡动画效果
|
||||||
|
|
||||||
|
## 信号和槽机制
|
||||||
|
|
||||||
|
### 主要信号
|
||||||
|
- `projects_changed` - 项目列表变化
|
||||||
|
- `project_added` - 项目添加
|
||||||
|
- `project_removed` - 项目删除
|
||||||
|
- `project_updated` - 项目更新
|
||||||
|
- `filter_changed` - 过滤条件变化
|
||||||
|
- `search_changed` - 搜索内容变化
|
||||||
|
|
||||||
|
### 事件处理
|
||||||
|
- 鼠标点击事件
|
||||||
|
- 键盘快捷键
|
||||||
|
- 拖拽事件
|
||||||
|
- 窗口事件
|
||||||
|
|
||||||
|
## 扩展功能
|
||||||
|
|
||||||
|
### 可以添加的功能
|
||||||
|
1. **项目模板系统**:真实的项目模板创建和应用
|
||||||
|
2. **文件管理**:项目内文件的管理和预览
|
||||||
|
3. **版本控制**:Git集成和版本管理
|
||||||
|
4. **协作功能**:多用户协作和权限管理
|
||||||
|
5. **插件系统**:支持第三方插件扩展
|
||||||
|
6. **云同步**:项目数据云端同步
|
||||||
|
7. **导出功能**:项目打包和分享
|
||||||
|
|
||||||
|
### 性能优化
|
||||||
|
1. **虚拟滚动**:大量项目时的性能优化
|
||||||
|
2. **缓存机制**:图片和数据缓存
|
||||||
|
3. **异步加载**:大文件异步处理
|
||||||
|
4. **内存管理**:及时释放不用的资源
|
||||||
|
|
||||||
|
## 开发说明
|
||||||
|
|
||||||
|
### 添加新组件
|
||||||
|
1. 在`ui/`目录下创建新的组件文件
|
||||||
|
2. 继承适当的PyQt5基类
|
||||||
|
3. 实现`init_ui()`方法
|
||||||
|
4. 添加必要的信号定义
|
||||||
|
5. 在样式表中添加对应样式
|
||||||
|
|
||||||
|
### 修改样式
|
||||||
|
1. 在`ui/styles.py`中修改样式定义
|
||||||
|
2. 使用ObjectName作为选择器
|
||||||
|
3. 支持状态选择器(:hover, :checked等)
|
||||||
|
4. 遵循现有的颜色和间距规范
|
||||||
|
|
||||||
|
### 数据持久化
|
||||||
|
- 项目数据自动保存到`data/projects.json`
|
||||||
|
- 应用关闭时自动保存
|
||||||
|
- 启动时自动加载历史数据
|
||||||
|
- 支持数据备份和恢复
|
||||||
|
|
||||||
|
## 与Web版本对比
|
||||||
|
|
||||||
|
### 相同功能
|
||||||
|
- ✅ 完全相同的界面布局
|
||||||
|
- ✅ 相同的项目管理功能
|
||||||
|
- ✅ 相同的视觉设计风格
|
||||||
|
- ✅ 相同的用户交互逻辑
|
||||||
|
|
||||||
|
### PyQt5版本优势
|
||||||
|
- ✅ 原生桌面应用体验
|
||||||
|
- ✅ 更好的性能表现
|
||||||
|
- ✅ 系统集成度更高
|
||||||
|
- ✅ 离线使用支持
|
||||||
|
- ✅ 文件系统直接访问
|
||||||
|
|
||||||
|
### 技术差异
|
||||||
|
- **Web版本**:HTML + CSS + JavaScript
|
||||||
|
- **PyQt5版本**:Python + PyQt5 + 自定义样式表
|
||||||
|
- **数据存储**:JSON文件 vs 浏览器存储
|
||||||
|
- **文件操作**:系统API vs Web API限制
|
||||||
|
|
||||||
|
这个PyQt5版本完全复制了Web版本的功能和外观,同时提供了更好的桌面应用体验。
|
||||||
208
Doc/功能对比说明.md
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
# MetaCore Web版本 vs PyQt5版本功能对比
|
||||||
|
|
||||||
|
## 🎯 完整功能映射
|
||||||
|
|
||||||
|
### 1. 整体布局结构
|
||||||
|
|
||||||
|
| Web版本 | PyQt5版本 | 说明 |
|
||||||
|
|---------|-----------|------|
|
||||||
|
| `<div class="sidebar">` | `Sidebar(QWidget)` | 左侧导航栏 |
|
||||||
|
| `<div class="main-content">` | `ProjectArea(QWidget)` | 主内容区域 |
|
||||||
|
| CSS Grid布局 | QGridLayout | 项目卡片网格布局 |
|
||||||
|
| CSS Flexbox | QHBoxLayout/QVBoxLayout | 弹性布局 |
|
||||||
|
|
||||||
|
### 2. 侧边栏功能
|
||||||
|
|
||||||
|
| Web版本功能 | PyQt5实现 | 对应文件 |
|
||||||
|
|-------------|-----------|----------|
|
||||||
|
| Logo区域 | `create_logo_section()` | `ui/sidebar.py` |
|
||||||
|
| 创建项目按钮 | `QPushButton("➕ 创建新项目")` | `ui/sidebar.py` |
|
||||||
|
| 导入项目按钮 | `QPushButton("📤 导入项目")` | `ui/sidebar.py` |
|
||||||
|
| 导航菜单 | `create_navigation_menu()` | `ui/sidebar.py` |
|
||||||
|
| 可展开分组 | `create_nav_section()` | `ui/sidebar.py` |
|
||||||
|
| 用户信息 | `create_user_info()` | `ui/sidebar.py` |
|
||||||
|
|
||||||
|
### 3. 项目卡片功能
|
||||||
|
|
||||||
|
| Web版本 | PyQt5版本 | 实现细节 |
|
||||||
|
|---------|-----------|----------|
|
||||||
|
| 三段式布局 | `create_grid_layout()` | 头部+图片+底部 |
|
||||||
|
| 项目标题 | `QLabel(project.title)` | 支持文字省略 |
|
||||||
|
| 三点菜单 | `QPushButton("⋮")` | 右键菜单触发 |
|
||||||
|
| 项目图标 | `QLabel(project.image)` | Emoji图标显示 |
|
||||||
|
| 类型标签 | `QLabel(type_label)` | 紫色背景标签 |
|
||||||
|
| 收藏星星 | `QLabel("⭐")` | 条件显示 |
|
||||||
|
| 项目时间 | `QLabel(project.date)` | 底部居中显示 |
|
||||||
|
| 悬停效果 | `enterEvent/leaveEvent` | 边框高亮效果 |
|
||||||
|
|
||||||
|
### 4. 右键菜单功能
|
||||||
|
|
||||||
|
| Web版本菜单项 | PyQt5实现 | 功能说明 |
|
||||||
|
|---------------|-----------|----------|
|
||||||
|
| 📁 打开项目 | `open_action` | 项目打开功能 |
|
||||||
|
| ✏️ 重命名 | `rename_action` | 项目重命名 |
|
||||||
|
| 📋 复制项目 | `duplicate_action` | 项目复制 |
|
||||||
|
| 📤 导出项目 | `export_action` | 项目导出 |
|
||||||
|
| ⭐ 收藏/取消收藏 | `favorite_action` | 收藏状态切换 |
|
||||||
|
| 🗑️ 删除项目 | `delete_action` | 项目删除确认 |
|
||||||
|
|
||||||
|
### 5. 创建项目对话框
|
||||||
|
|
||||||
|
| Web版本元素 | PyQt5组件 | 布局比例 |
|
||||||
|
|-------------|-----------|----------|
|
||||||
|
| 模板选择区域 | `create_template_section()` | 2/3宽度 |
|
||||||
|
| 项目信息区域 | `create_project_info_section()` | 1/3宽度 |
|
||||||
|
| 模板网格 | `QGridLayout(2列)` | 2列模板布局 |
|
||||||
|
| 项目名称输入 | `QLineEdit` | 表单输入 |
|
||||||
|
| 项目描述输入 | `QTextEdit` | 多行文本 |
|
||||||
|
| 位置选择 | `QFileDialog.getExistingDirectory()` | 系统文件夹选择 |
|
||||||
|
| 浏览按钮 | `QPushButton("📁")` | 文件夹图标 |
|
||||||
|
|
||||||
|
### 6. 搜索和过滤功能
|
||||||
|
|
||||||
|
| Web版本 | PyQt5版本 | 实现方式 |
|
||||||
|
|---------|-----------|----------|
|
||||||
|
| 搜索框 | `QLineEdit` | 实时搜索 |
|
||||||
|
| 视图切换 | `QPushButton` (网格/列表) | 可选择按钮组 |
|
||||||
|
| 类型过滤 | `QComboBox` | 下拉选择 |
|
||||||
|
| 排序选项 | `QComboBox` | 排序方式选择 |
|
||||||
|
|
||||||
|
## 🎨 样式系统对比
|
||||||
|
|
||||||
|
### CSS vs PyQt5样式表
|
||||||
|
|
||||||
|
| Web版本CSS | PyQt5样式表 | 效果 |
|
||||||
|
|------------|-------------|------|
|
||||||
|
| `.project-card` | `#projectCard` | 项目卡片样式 |
|
||||||
|
| `.project-card:hover` | `#projectCard[hover="true"]` | 悬停效果 |
|
||||||
|
| `background: #2a2a2a` | `background-color: #2a2a2a` | 背景色 |
|
||||||
|
| `border-radius: 12px` | `border-radius: 12px` | 圆角 |
|
||||||
|
| `transition: all 0.2s` | 通过事件处理实现 | 过渡动画 |
|
||||||
|
|
||||||
|
### 颜色主题完全一致
|
||||||
|
|
||||||
|
| 颜色用途 | 颜色值 | Web版本 | PyQt5版本 |
|
||||||
|
|----------|--------|---------|-----------|
|
||||||
|
| 主背景 | #1a1a1a | ✅ | ✅ |
|
||||||
|
| 卡片背景 | #2a2a2a | ✅ | ✅ |
|
||||||
|
| 边框色 | #3a3a3a | ✅ | ✅ |
|
||||||
|
| 强调色 | #8b5cf6 | ✅ | ✅ |
|
||||||
|
| 文字色 | #ffffff | ✅ | ✅ |
|
||||||
|
|
||||||
|
## 🔧 技术实现对比
|
||||||
|
|
||||||
|
### 1. 数据管理
|
||||||
|
|
||||||
|
| 方面 | Web版本 | PyQt5版本 |
|
||||||
|
|------|---------|-----------|
|
||||||
|
| 数据存储 | JavaScript数组 | Python列表 + JSON文件 |
|
||||||
|
| 数据持久化 | localStorage | 文件系统 |
|
||||||
|
| 数据结构 | JavaScript对象 | Python类 |
|
||||||
|
| 状态管理 | 直接操作DOM | 信号槽机制 |
|
||||||
|
|
||||||
|
### 2. 事件处理
|
||||||
|
|
||||||
|
| 事件类型 | Web版本 | PyQt5版本 |
|
||||||
|
|----------|---------|-----------|
|
||||||
|
| 点击事件 | `addEventListener('click')` | `clicked.connect()` |
|
||||||
|
| 悬停事件 | CSS `:hover` | `enterEvent/leaveEvent` |
|
||||||
|
| 键盘事件 | `keydown/keyup` | `keyPressEvent` |
|
||||||
|
| 拖拽事件 | HTML5 Drag API | `dragEnterEvent/dropEvent` |
|
||||||
|
|
||||||
|
### 3. 布局系统
|
||||||
|
|
||||||
|
| 布局方式 | Web版本 | PyQt5版本 |
|
||||||
|
|----------|---------|-----------|
|
||||||
|
| 弹性布局 | CSS Flexbox | QHBoxLayout/QVBoxLayout |
|
||||||
|
| 网格布局 | CSS Grid | QGridLayout |
|
||||||
|
| 绝对定位 | CSS position | setGeometry() |
|
||||||
|
| 响应式 | CSS媒体查询 | 布局管理器自适应 |
|
||||||
|
|
||||||
|
## 🚀 功能增强
|
||||||
|
|
||||||
|
### PyQt5版本独有优势
|
||||||
|
|
||||||
|
1. **系统集成**
|
||||||
|
- 原生文件对话框
|
||||||
|
- 系统通知支持
|
||||||
|
- 任务栏集成
|
||||||
|
- 系统托盘支持
|
||||||
|
|
||||||
|
2. **性能优化**
|
||||||
|
- 原生渲染性能
|
||||||
|
- 内存管理更好
|
||||||
|
- 大量数据处理能力
|
||||||
|
- 多线程支持
|
||||||
|
|
||||||
|
3. **桌面特性**
|
||||||
|
- 快捷键支持
|
||||||
|
- 窗口管理
|
||||||
|
- 多显示器支持
|
||||||
|
- 离线使用
|
||||||
|
|
||||||
|
### 可扩展功能
|
||||||
|
|
||||||
|
1. **文件系统集成**
|
||||||
|
```python
|
||||||
|
# 直接操作文件系统
|
||||||
|
import os, shutil
|
||||||
|
def copy_project_files(src, dst):
|
||||||
|
shutil.copytree(src, dst)
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **数据库支持**
|
||||||
|
```python
|
||||||
|
# 可以集成SQLite等数据库
|
||||||
|
import sqlite3
|
||||||
|
def save_to_database(project):
|
||||||
|
# 数据库操作
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **插件系统**
|
||||||
|
```python
|
||||||
|
# 动态加载插件
|
||||||
|
import importlib
|
||||||
|
def load_plugin(plugin_name):
|
||||||
|
return importlib.import_module(f'plugins.{plugin_name}')
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📱 使用体验对比
|
||||||
|
|
||||||
|
### 启动和运行
|
||||||
|
|
||||||
|
| 方面 | Web版本 | PyQt5版本 |
|
||||||
|
|------|---------|-----------|
|
||||||
|
| 启动方式 | 浏览器打开HTML | 运行Python脚本 |
|
||||||
|
| 依赖环境 | 现代浏览器 | Python + PyQt5 |
|
||||||
|
| 安装过程 | 无需安装 | pip install PyQt5 |
|
||||||
|
| 更新方式 | 刷新页面 | 重新运行程序 |
|
||||||
|
|
||||||
|
### 用户交互
|
||||||
|
|
||||||
|
| 交互方式 | Web版本 | PyQt5版本 |
|
||||||
|
|----------|---------|-----------|
|
||||||
|
| 响应速度 | 依赖浏览器 | 原生应用速度 |
|
||||||
|
| 动画效果 | CSS动画 | Qt动画系统 |
|
||||||
|
| 拖拽操作 | HTML5 API | Qt拖拽系统 |
|
||||||
|
| 右键菜单 | 自定义实现 | 原生菜单 |
|
||||||
|
|
||||||
|
## 🎯 总结
|
||||||
|
|
||||||
|
PyQt5版本完全复制了Web版本的所有功能和视觉效果,同时提供了更好的桌面应用体验:
|
||||||
|
|
||||||
|
### ✅ 完全实现的功能
|
||||||
|
- 所有UI组件和布局
|
||||||
|
- 所有交互功能
|
||||||
|
- 完整的样式主题
|
||||||
|
- 数据管理和持久化
|
||||||
|
- 搜索和过滤功能
|
||||||
|
- 项目CRUD操作
|
||||||
|
|
||||||
|
### 🚀 额外优势
|
||||||
|
- 原生桌面应用性能
|
||||||
|
- 系统级文件操作
|
||||||
|
- 更好的用户体验
|
||||||
|
- 扩展性更强
|
||||||
|
|
||||||
|
这个PyQt5版本不仅是Web版本的完美移植,更是一个功能更强大的桌面应用程序。
|
||||||
190
Doc/安装PyQt5指南.md
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
# PyQt5安装指南
|
||||||
|
|
||||||
|
## 🔧 Windows系统安装PyQt5
|
||||||
|
|
||||||
|
### 方法1:使用pip安装(推荐)
|
||||||
|
|
||||||
|
#### 1. 检查Python是否已安装
|
||||||
|
```cmd
|
||||||
|
python --version
|
||||||
|
```
|
||||||
|
如果显示版本号,说明Python已安装。如果提示命令不存在,需要先安装Python。
|
||||||
|
|
||||||
|
#### 2. 安装Python(如果未安装)
|
||||||
|
1. 访问 https://www.python.org/downloads/
|
||||||
|
2. 下载最新版本的Python
|
||||||
|
3. 安装时勾选"Add Python to PATH"
|
||||||
|
|
||||||
|
#### 3. 安装PyQt5
|
||||||
|
```cmd
|
||||||
|
pip install PyQt5
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. 验证安装
|
||||||
|
```cmd
|
||||||
|
python -c "import PyQt5; print('PyQt5安装成功')"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方法2:使用conda安装
|
||||||
|
|
||||||
|
#### 1. 安装Anaconda或Miniconda
|
||||||
|
- 下载地址:https://www.anaconda.com/products/distribution
|
||||||
|
|
||||||
|
#### 2. 安装PyQt5
|
||||||
|
```cmd
|
||||||
|
conda install pyqt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方法3:离线安装
|
||||||
|
|
||||||
|
#### 1. 下载PyQt5安装包
|
||||||
|
访问 https://pypi.org/project/PyQt5/#files 下载对应的.whl文件
|
||||||
|
|
||||||
|
#### 2. 离线安装
|
||||||
|
```cmd
|
||||||
|
pip install PyQt5-5.15.7-cp39-cp39-win_amd64.whl
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 运行MetaCore应用
|
||||||
|
|
||||||
|
### 1. 确认PyQt5已安装
|
||||||
|
```cmd
|
||||||
|
python -c "from PyQt5.QtWidgets import QApplication; print('PyQt5可用')"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 运行应用
|
||||||
|
```cmd
|
||||||
|
cd MetaCore目录
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 如果遇到错误
|
||||||
|
|
||||||
|
#### 错误1:ModuleNotFoundError: No module named 'PyQt5'
|
||||||
|
**解决方案:**
|
||||||
|
```cmd
|
||||||
|
pip install PyQt5
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 错误2:ImportError: DLL load failed
|
||||||
|
**解决方案:**
|
||||||
|
```cmd
|
||||||
|
pip uninstall PyQt5
|
||||||
|
pip install PyQt5
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 错误3:Python命令不存在
|
||||||
|
**解决方案:**
|
||||||
|
1. 重新安装Python并勾选"Add to PATH"
|
||||||
|
2. 或者使用完整路径:
|
||||||
|
```cmd
|
||||||
|
C:\Python39\python.exe main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📋 系统要求
|
||||||
|
|
||||||
|
### 最低要求
|
||||||
|
- Windows 7 SP1 或更高版本
|
||||||
|
- Python 3.6 或更高版本
|
||||||
|
- 2GB RAM
|
||||||
|
- 100MB 可用磁盘空间
|
||||||
|
|
||||||
|
### 推荐配置
|
||||||
|
- Windows 10 或更高版本
|
||||||
|
- Python 3.8 或更高版本
|
||||||
|
- 4GB RAM
|
||||||
|
- SSD硬盘
|
||||||
|
|
||||||
|
## 🔍 故障排除
|
||||||
|
|
||||||
|
### 1. 检查Python版本
|
||||||
|
```cmd
|
||||||
|
python --version
|
||||||
|
```
|
||||||
|
确保版本为3.6或更高。
|
||||||
|
|
||||||
|
### 2. 检查pip版本
|
||||||
|
```cmd
|
||||||
|
pip --version
|
||||||
|
```
|
||||||
|
如果pip不可用,可以重新安装Python。
|
||||||
|
|
||||||
|
### 3. 更新pip
|
||||||
|
```cmd
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 清理缓存
|
||||||
|
```cmd
|
||||||
|
pip cache purge
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 使用国内镜像源(如果下载慢)
|
||||||
|
```cmd
|
||||||
|
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple PyQt5
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 验证安装成功
|
||||||
|
|
||||||
|
### 运行测试脚本
|
||||||
|
创建一个测试文件 `test_pyqt5.py`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import sys
|
||||||
|
from PyQt5.QtWidgets import QApplication, QLabel, QWidget
|
||||||
|
|
||||||
|
def test_pyqt5():
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
|
||||||
|
window = QWidget()
|
||||||
|
window.setWindowTitle('PyQt5测试')
|
||||||
|
window.setGeometry(100, 100, 300, 200)
|
||||||
|
|
||||||
|
label = QLabel('PyQt5安装成功!', window)
|
||||||
|
label.move(100, 80)
|
||||||
|
|
||||||
|
window.show()
|
||||||
|
|
||||||
|
print("PyQt5测试窗口已显示,关闭窗口退出测试")
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_pyqt5()
|
||||||
|
```
|
||||||
|
|
||||||
|
运行测试:
|
||||||
|
```cmd
|
||||||
|
python test_pyqt5.py
|
||||||
|
```
|
||||||
|
|
||||||
|
如果出现一个窗口显示"PyQt5安装成功!",说明安装正确。
|
||||||
|
|
||||||
|
## 📞 获取帮助
|
||||||
|
|
||||||
|
如果仍然遇到问题:
|
||||||
|
|
||||||
|
1. **检查Python环境**
|
||||||
|
```cmd
|
||||||
|
where python
|
||||||
|
python -m site
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **重新安装Python**
|
||||||
|
- 卸载现有Python
|
||||||
|
- 重新下载安装,确保勾选"Add to PATH"
|
||||||
|
|
||||||
|
3. **使用虚拟环境**
|
||||||
|
```cmd
|
||||||
|
python -m venv metacore_env
|
||||||
|
metacore_env\Scripts\activate
|
||||||
|
pip install PyQt5
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **联系技术支持**
|
||||||
|
- 提供错误信息截图
|
||||||
|
- 说明操作系统版本
|
||||||
|
- 提供Python版本信息
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
安装完成后,就可以运行MetaCore PyQt5版本了!🎉
|
||||||
209
Doc/快速开始.md
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
# MetaCore PyQt5版本 - 快速开始指南
|
||||||
|
|
||||||
|
## 🚀 一键启动
|
||||||
|
|
||||||
|
### 方法1:直接运行
|
||||||
|
```bash
|
||||||
|
# 1. 安装依赖
|
||||||
|
pip install PyQt5
|
||||||
|
|
||||||
|
# 2. 运行应用
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方法2:使用启动脚本
|
||||||
|
```bash
|
||||||
|
python run_app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📋 系统要求
|
||||||
|
|
||||||
|
- **Python版本**:3.7 或更高
|
||||||
|
- **操作系统**:Windows 10/11, macOS 10.14+, Linux
|
||||||
|
- **内存要求**:最少 512MB RAM
|
||||||
|
- **磁盘空间**:约 100MB
|
||||||
|
|
||||||
|
## 🔧 安装步骤
|
||||||
|
|
||||||
|
### Windows用户
|
||||||
|
```cmd
|
||||||
|
# 1. 检查Python版本
|
||||||
|
python --version
|
||||||
|
|
||||||
|
# 2. 安装PyQt5
|
||||||
|
pip install PyQt5
|
||||||
|
|
||||||
|
# 3. 运行应用
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### macOS用户
|
||||||
|
```bash
|
||||||
|
# 1. 确保有Python3
|
||||||
|
python3 --version
|
||||||
|
|
||||||
|
# 2. 安装PyQt5
|
||||||
|
pip3 install PyQt5
|
||||||
|
|
||||||
|
# 3. 运行应用
|
||||||
|
python3 main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux用户
|
||||||
|
```bash
|
||||||
|
# Ubuntu/Debian
|
||||||
|
sudo apt-get install python3-pyqt5
|
||||||
|
|
||||||
|
# 或使用pip
|
||||||
|
pip3 install PyQt5
|
||||||
|
|
||||||
|
# 运行应用
|
||||||
|
python3 main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 首次使用
|
||||||
|
|
||||||
|
### 1. 启动应用
|
||||||
|
运行后会看到MetaCore主界面:
|
||||||
|
- 左侧:导航侧边栏
|
||||||
|
- 右侧:项目展示区域
|
||||||
|
- 底部:状态栏
|
||||||
|
|
||||||
|
### 2. 创建第一个项目
|
||||||
|
1. 点击侧边栏的"➕ 创建新项目"按钮
|
||||||
|
2. 选择项目模板(工业、VR、智能等)
|
||||||
|
3. 填写项目名称和描述
|
||||||
|
4. 选择项目保存位置
|
||||||
|
5. 点击"创建项目"
|
||||||
|
|
||||||
|
### 3. 管理项目
|
||||||
|
- **查看项目**:点击项目卡片
|
||||||
|
- **右键菜单**:右键点击项目卡片或点击"⋮"按钮
|
||||||
|
- **搜索项目**:使用顶部搜索框
|
||||||
|
- **切换视图**:点击网格/列表视图按钮
|
||||||
|
|
||||||
|
## 📁 文件结构说明
|
||||||
|
|
||||||
|
```
|
||||||
|
MetaCore/
|
||||||
|
├── main.py # 🚀 主程序入口
|
||||||
|
├── run_app.py # 🎯 启动脚本
|
||||||
|
├── requirements.txt # 📦 依赖列表
|
||||||
|
├── data/ # 💾 数据目录
|
||||||
|
│ ├── project_manager.py # 项目管理器
|
||||||
|
│ └── projects.json # 项目数据(自动生成)
|
||||||
|
└── ui/ # 🎨 界面组件
|
||||||
|
├── main_window.py # 主窗口
|
||||||
|
├── sidebar.py # 侧边栏
|
||||||
|
├── project_area.py # 项目区域
|
||||||
|
├── project_card.py # 项目卡片
|
||||||
|
├── create_project_dialog.py # 创建项目对话框
|
||||||
|
├── import_project_dialog.py # 导入项目对话框
|
||||||
|
└── styles.py # 样式表
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎨 界面预览
|
||||||
|
|
||||||
|
### 主界面布局
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ MetaCore - 项目管理平台 🔔 👤 ➕创建 │
|
||||||
|
├─────────────┬───────────────────────────────────────────┤
|
||||||
|
│ 🧊 MetaCore │ 全部项目 ⊞ ☰ 🔽 🔍 │
|
||||||
|
│ ├───────────────────────────────────────────┤
|
||||||
|
│ ➕ 创建新项目│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
|
||||||
|
│ 📤 导入项目 │ │ 🏭 │ │ 💧 │ │ 🏗️ │ │ 📊 │ │
|
||||||
|
│ │ │智慧工厂│ │智慧水务│ │数字工厂│ │智慧监控│ │
|
||||||
|
│ 📁 项目概览 │ │ ⭐⋮ │ │ ⋮ │ │ ⋮ │ │ ⭐⋮ │ │
|
||||||
|
│ ⭐ 收藏项目 │ └─────┘ └─────┘ └─────┘ └─────┘ │
|
||||||
|
│ 🕒 最近项目 │ │
|
||||||
|
│ 🏭 工业项目 │ │
|
||||||
|
│ 💧 智能项目 │ │
|
||||||
|
│ │ │
|
||||||
|
│ 👤 Admin ▼ │ │
|
||||||
|
└─────────────┴───────────────────────────────────────────┤
|
||||||
|
│ 项目总数: 5 当前用户: Admin │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 创建项目对话框
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ 创建新的项目 ✕ │
|
||||||
|
├─────────────────────────────────────────────────────────┤
|
||||||
|
│ 选择项目模板 │ 项目信息 │
|
||||||
|
│ │ │
|
||||||
|
│ ┌─────┐ ┌─────┐ │ 选择一个项目模板来快速 │
|
||||||
|
│ │ 📁 │ │ 🏭 │ │ 开始,或者创建一个空白 │
|
||||||
|
│ │空白项目│ │工业项目│ │ 项目来从头开始。 │
|
||||||
|
│ └─────┘ └─────┘ │ │
|
||||||
|
│ ┌─────┐ ┌─────┐ │ 项目名称 │
|
||||||
|
│ │ 🥽 │ │ 💧 │ │ ┌─────────────────┐ │
|
||||||
|
│ │VR项目│ │智能项目│ │ │ │ │
|
||||||
|
│ └─────┘ └─────┘ │ └─────────────────┘ │
|
||||||
|
│ ┌─────┐ ┌─────┐ │ │
|
||||||
|
│ │ 🎮 │ │ 🎨 │ │ 项目描述 │
|
||||||
|
│ │游戏项目│ │设计项目│ │ ┌─────────────────┐ │
|
||||||
|
│ └─────┘ └─────┘ │ │ │ │
|
||||||
|
│ │ └─────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ │ 项目位置 │
|
||||||
|
│ │ ┌───────────────┐ 📁 │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ │ └───────────────┘ │
|
||||||
|
├─────────────────────────────────────────────────────────┤
|
||||||
|
│ 取消 创建项目 │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚡ 快捷键
|
||||||
|
|
||||||
|
| 功能 | 快捷键 | 说明 |
|
||||||
|
|------|--------|------|
|
||||||
|
| 新建项目 | Ctrl+N | 打开创建项目对话框 |
|
||||||
|
| 导入项目 | Ctrl+I | 打开导入项目对话框 |
|
||||||
|
| 搜索项目 | Ctrl+F | 聚焦搜索框 |
|
||||||
|
| 退出应用 | Ctrl+Q | 关闭应用程序 |
|
||||||
|
|
||||||
|
## 🔧 常见问题
|
||||||
|
|
||||||
|
### Q: 提示"No module named 'PyQt5'"
|
||||||
|
**A:** 需要安装PyQt5依赖包
|
||||||
|
```bash
|
||||||
|
pip install PyQt5
|
||||||
|
```
|
||||||
|
|
||||||
|
### Q: 在macOS上运行出错
|
||||||
|
**A:** 可能需要使用python3命令
|
||||||
|
```bash
|
||||||
|
python3 main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Q: 项目数据保存在哪里?
|
||||||
|
**A:** 项目数据保存在`data/projects.json`文件中,应用关闭时自动保存。
|
||||||
|
|
||||||
|
### Q: 如何备份项目数据?
|
||||||
|
**A:** 复制`data/projects.json`文件即可备份所有项目信息。
|
||||||
|
|
||||||
|
### Q: 可以修改界面主题吗?
|
||||||
|
**A:** 可以在`ui/styles.py`文件中修改颜色和样式定义。
|
||||||
|
|
||||||
|
## 🎯 下一步
|
||||||
|
|
||||||
|
1. **探索功能**:尝试创建不同类型的项目
|
||||||
|
2. **自定义设置**:根据需要调整界面和功能
|
||||||
|
3. **数据管理**:定期备份项目数据
|
||||||
|
4. **功能扩展**:根据需要添加新功能
|
||||||
|
|
||||||
|
## 📞 技术支持
|
||||||
|
|
||||||
|
如果遇到问题,可以:
|
||||||
|
1. 查看`README_PyQt5.md`详细文档
|
||||||
|
2. 检查`功能对比说明.md`了解功能对应关系
|
||||||
|
3. 查看源代码中的注释和文档字符串
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
🎉 **恭喜!** 您已经成功运行了MetaCore PyQt5版本!
|
||||||
|
|
||||||
|
这个桌面应用完全复制了Web版本的所有功能,同时提供了更好的性能和用户体验。开始创建您的第一个项目吧!
|
||||||
261
Doc/虚拟环境完整指南.md
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
# MetaCore虚拟环境完整指南
|
||||||
|
|
||||||
|
## 🎯 概述
|
||||||
|
|
||||||
|
为MetaCore PyQt5版本创建独立的Python虚拟环境,确保项目依赖不会与系统其他Python项目冲突。
|
||||||
|
|
||||||
|
## 📁 已创建的文件
|
||||||
|
|
||||||
|
### 自动化脚本
|
||||||
|
- `setup_and_run.bat` - Windows一键启动脚本
|
||||||
|
- `setup_and_run.sh` - macOS/Linux一键启动脚本
|
||||||
|
- `test_environment.py` - 环境测试脚本
|
||||||
|
|
||||||
|
### 配置文件
|
||||||
|
- `requirements.txt` - 项目依赖列表
|
||||||
|
- `虚拟环境设置指南.md` - 详细设置说明
|
||||||
|
- `虚拟环境快速参考.md` - 快速参考卡
|
||||||
|
|
||||||
|
## 🚀 快速开始
|
||||||
|
|
||||||
|
### 方法1:一键启动(推荐)
|
||||||
|
|
||||||
|
#### Windows用户
|
||||||
|
```cmd
|
||||||
|
# 双击运行或命令行执行
|
||||||
|
setup_and_run.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
#### macOS/Linux用户
|
||||||
|
```bash
|
||||||
|
# 首次运行需要给权限
|
||||||
|
chmod +x setup_and_run.sh
|
||||||
|
|
||||||
|
# 运行脚本
|
||||||
|
./setup_and_run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方法2:手动设置
|
||||||
|
|
||||||
|
#### 1. 创建虚拟环境
|
||||||
|
```cmd
|
||||||
|
# Windows
|
||||||
|
python -m venv metacore_env
|
||||||
|
|
||||||
|
# macOS/Linux
|
||||||
|
python3 -m venv metacore_env
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. 激活虚拟环境
|
||||||
|
```cmd
|
||||||
|
# Windows
|
||||||
|
metacore_env\Scripts\activate
|
||||||
|
|
||||||
|
# macOS/Linux
|
||||||
|
source metacore_env/bin/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. 安装依赖
|
||||||
|
```cmd
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. 运行应用
|
||||||
|
```cmd
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5. 退出虚拟环境
|
||||||
|
```cmd
|
||||||
|
deactivate
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 环境测试
|
||||||
|
|
||||||
|
运行环境测试脚本检查配置:
|
||||||
|
```cmd
|
||||||
|
python test_environment.py
|
||||||
|
```
|
||||||
|
|
||||||
|
测试内容包括:
|
||||||
|
- ✅ Python版本检查
|
||||||
|
- ✅ PyQt5安装验证
|
||||||
|
- ✅ 项目文件完整性
|
||||||
|
- ✅ 模块导入测试
|
||||||
|
- ✅ 虚拟环境状态
|
||||||
|
|
||||||
|
## 📋 依赖包说明
|
||||||
|
|
||||||
|
### 必需依赖
|
||||||
|
- **PyQt5 >= 5.15.0** - GUI框架
|
||||||
|
|
||||||
|
### 可选依赖
|
||||||
|
- **Pillow >= 8.0.0** - 图像处理(如需要更好的图标支持)
|
||||||
|
- **psutil >= 5.8.0** - 系统信息(如需要系统集成功能)
|
||||||
|
|
||||||
|
## 🎯 使用场景
|
||||||
|
|
||||||
|
### 开发环境
|
||||||
|
```cmd
|
||||||
|
# 激活环境
|
||||||
|
metacore_env\Scripts\activate
|
||||||
|
|
||||||
|
# 开发调试
|
||||||
|
python main.py
|
||||||
|
|
||||||
|
# 安装新依赖
|
||||||
|
pip install package_name
|
||||||
|
|
||||||
|
# 更新依赖列表
|
||||||
|
pip freeze > requirements.txt
|
||||||
|
|
||||||
|
# 退出环境
|
||||||
|
deactivate
|
||||||
|
```
|
||||||
|
|
||||||
|
### 生产环境
|
||||||
|
```cmd
|
||||||
|
# 创建干净环境
|
||||||
|
python -m venv production_env
|
||||||
|
|
||||||
|
# 激活环境
|
||||||
|
production_env\Scripts\activate
|
||||||
|
|
||||||
|
# 安装指定依赖
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# 运行应用
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔍 故障排除
|
||||||
|
|
||||||
|
### 常见问题及解决方案
|
||||||
|
|
||||||
|
#### 1. Python命令不存在
|
||||||
|
**症状:** `'python' 不是内部或外部命令`
|
||||||
|
**解决:**
|
||||||
|
- 重新安装Python并勾选"Add to PATH"
|
||||||
|
- 或使用完整路径:`C:\Python39\python.exe`
|
||||||
|
|
||||||
|
#### 2. venv模块不存在
|
||||||
|
**症状:** `No module named venv`
|
||||||
|
**解决:**
|
||||||
|
```cmd
|
||||||
|
pip install virtualenv
|
||||||
|
virtualenv metacore_env
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. PyQt5安装失败
|
||||||
|
**症状:** 网络错误或编译错误
|
||||||
|
**解决:**
|
||||||
|
```cmd
|
||||||
|
# 使用国内镜像
|
||||||
|
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple PyQt5
|
||||||
|
|
||||||
|
# 或使用conda
|
||||||
|
conda install pyqt
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. 权限错误
|
||||||
|
**症状:** `Permission denied`
|
||||||
|
**解决:**
|
||||||
|
- Windows:以管理员身份运行
|
||||||
|
- macOS/Linux:检查目录权限 `chmod 755 /path/to/MetaCore`
|
||||||
|
|
||||||
|
#### 5. 虚拟环境激活失败
|
||||||
|
**症状:** 激活脚本不存在
|
||||||
|
**解决:**
|
||||||
|
```cmd
|
||||||
|
# 删除并重新创建
|
||||||
|
rm -rf metacore_env
|
||||||
|
python -m venv metacore_env
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 环境管理最佳实践
|
||||||
|
|
||||||
|
### 1. 项目隔离
|
||||||
|
- 每个项目使用独立的虚拟环境
|
||||||
|
- 避免在系统Python中安装项目依赖
|
||||||
|
|
||||||
|
### 2. 依赖管理
|
||||||
|
- 使用requirements.txt记录依赖
|
||||||
|
- 定期更新依赖包版本
|
||||||
|
- 区分开发依赖和生产依赖
|
||||||
|
|
||||||
|
### 3. 版本控制
|
||||||
|
- 将虚拟环境目录添加到.gitignore
|
||||||
|
- 只提交requirements.txt文件
|
||||||
|
- 在不同环境中重新创建虚拟环境
|
||||||
|
|
||||||
|
### 4. 文档维护
|
||||||
|
- 记录环境创建步骤
|
||||||
|
- 说明特殊依赖的安装方法
|
||||||
|
- 提供故障排除指南
|
||||||
|
|
||||||
|
## 🎨 目录结构
|
||||||
|
|
||||||
|
完整的项目目录结构:
|
||||||
|
```
|
||||||
|
MetaCore/
|
||||||
|
├── metacore_env/ # 虚拟环境(不提交到版本控制)
|
||||||
|
│ ├── Scripts/ # Windows
|
||||||
|
│ ├── bin/ # macOS/Linux
|
||||||
|
│ ├── lib/
|
||||||
|
│ └── pyvenv.cfg
|
||||||
|
├── data/ # 数据模块
|
||||||
|
├── ui/ # 界面模块
|
||||||
|
├── main.py # 主程序
|
||||||
|
├── requirements.txt # 依赖列表
|
||||||
|
├── setup_and_run.bat # Windows启动脚本
|
||||||
|
├── setup_and_run.sh # macOS/Linux启动脚本
|
||||||
|
├── test_environment.py # 环境测试脚本
|
||||||
|
├── 虚拟环境设置指南.md # 详细指南
|
||||||
|
├── 虚拟环境快速参考.md # 快速参考
|
||||||
|
└── 虚拟环境完整指南.md # 本文档
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 部署建议
|
||||||
|
|
||||||
|
### 开发部署
|
||||||
|
1. 克隆项目代码
|
||||||
|
2. 创建虚拟环境
|
||||||
|
3. 安装依赖包
|
||||||
|
4. 运行测试脚本
|
||||||
|
5. 启动应用
|
||||||
|
|
||||||
|
### 生产部署
|
||||||
|
1. 使用干净的Python环境
|
||||||
|
2. 创建专用虚拟环境
|
||||||
|
3. 安装精确版本的依赖
|
||||||
|
4. 配置系统服务
|
||||||
|
5. 设置日志和监控
|
||||||
|
|
||||||
|
## 📞 获取帮助
|
||||||
|
|
||||||
|
### 自助诊断
|
||||||
|
1. 运行 `python test_environment.py` 检查环境
|
||||||
|
2. 查看 `虚拟环境快速参考.md` 获取常用命令
|
||||||
|
3. 参考 `虚拟环境设置指南.md` 获取详细说明
|
||||||
|
|
||||||
|
### 常用检查命令
|
||||||
|
```cmd
|
||||||
|
# 检查Python版本
|
||||||
|
python --version
|
||||||
|
|
||||||
|
# 检查虚拟环境状态
|
||||||
|
echo $VIRTUAL_ENV # Linux/macOS
|
||||||
|
echo %VIRTUAL_ENV% # Windows
|
||||||
|
|
||||||
|
# 检查已安装包
|
||||||
|
pip list
|
||||||
|
|
||||||
|
# 检查PyQt5
|
||||||
|
python -c "import PyQt5; print('PyQt5可用')"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
🎉 **虚拟环境配置完成!**
|
||||||
|
|
||||||
|
现在您可以在独立的环境中安全地运行MetaCore PyQt5版本,不用担心依赖冲突问题。选择最适合您的启动方式,开始使用吧!
|
||||||
234
Doc/项目总览.md
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
# MetaCore 项目总览
|
||||||
|
|
||||||
|
## 🎯 项目简介
|
||||||
|
|
||||||
|
MetaCore是一个现代化的项目管理平台,现在提供两个版本:
|
||||||
|
- **Web版本**:基于HTML/CSS/JavaScript的浏览器应用
|
||||||
|
- **PyQt5版本**:基于Python PyQt5的桌面应用
|
||||||
|
|
||||||
|
两个版本功能完全一致,界面设计完全相同,为用户提供了不同平台的选择。
|
||||||
|
|
||||||
|
## 📁 完整项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
MetaCore/
|
||||||
|
├── 📄 Web版本文件
|
||||||
|
│ ├── index.html # 主页面
|
||||||
|
│ ├── script.js # JavaScript逻辑
|
||||||
|
│ ├── styles.css # 样式表
|
||||||
|
│ └── test-cards.html # 测试页面
|
||||||
|
│
|
||||||
|
├── 🐍 PyQt5版本文件
|
||||||
|
│ ├── main.py # 主程序入口
|
||||||
|
│ ├── run_app.py # 启动脚本
|
||||||
|
│ ├── requirements.txt # 依赖包
|
||||||
|
│ ├── data/ # 数据模块
|
||||||
|
│ │ ├── __init__.py
|
||||||
|
│ │ ├── project_manager.py # 项目管理器
|
||||||
|
│ │ └── projects.json # 数据文件(自动生成)
|
||||||
|
│ └── ui/ # 界面模块
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ ├── main_window.py # 主窗口
|
||||||
|
│ ├── sidebar.py # 侧边栏
|
||||||
|
│ ├── project_area.py # 项目区域
|
||||||
|
│ ├── project_card.py # 项目卡片
|
||||||
|
│ ├── create_project_dialog.py # 创建对话框
|
||||||
|
│ ├── import_project_dialog.py # 导入对话框
|
||||||
|
│ └── styles.py # 样式定义
|
||||||
|
│
|
||||||
|
└── 📚 文档文件
|
||||||
|
├── README_PyQt5.md # PyQt5版本说明
|
||||||
|
├── 快速开始.md # 快速开始指南
|
||||||
|
├── 安装PyQt5指南.md # 安装指南
|
||||||
|
├── 功能对比说明.md # 版本对比
|
||||||
|
├── PyQt5版本完成总结.md # 完成总结
|
||||||
|
├── 创建项目1-3布局说明.md # 布局优化说明
|
||||||
|
├── 创建项目布局优化说明.md # 布局说明
|
||||||
|
├── 项目卡片更新说明.md # 卡片更新说明
|
||||||
|
├── 功能演示.md # 功能演示
|
||||||
|
└── 项目总览.md # 本文档
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 快速开始
|
||||||
|
|
||||||
|
### Web版本
|
||||||
|
```bash
|
||||||
|
# 直接在浏览器中打开
|
||||||
|
open index.html
|
||||||
|
```
|
||||||
|
|
||||||
|
### PyQt5版本
|
||||||
|
```bash
|
||||||
|
# 1. 安装依赖
|
||||||
|
pip install PyQt5
|
||||||
|
|
||||||
|
# 2. 运行应用
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## ✨ 核心功能
|
||||||
|
|
||||||
|
### 🎨 界面特性
|
||||||
|
- ✅ **现代化设计**:深色主题,简洁美观
|
||||||
|
- ✅ **响应式布局**:自适应不同屏幕尺寸
|
||||||
|
- ✅ **三段式卡片**:标题+图片+时间的经典布局
|
||||||
|
- ✅ **2:1对话框**:创建项目的黄金比例布局
|
||||||
|
- ✅ **悬停效果**:丰富的交互反馈
|
||||||
|
|
||||||
|
### 📊 项目管理
|
||||||
|
- ✅ **项目创建**:多种模板选择
|
||||||
|
- ✅ **项目导入**:支持文件拖拽
|
||||||
|
- ✅ **项目编辑**:重命名、描述修改
|
||||||
|
- ✅ **项目删除**:安全删除确认
|
||||||
|
- ✅ **收藏功能**:快速标记重要项目
|
||||||
|
|
||||||
|
### 🔍 搜索过滤
|
||||||
|
- ✅ **实时搜索**:按项目名称搜索
|
||||||
|
- ✅ **类型过滤**:按项目类型筛选
|
||||||
|
- ✅ **收藏过滤**:查看收藏的项目
|
||||||
|
- ✅ **时间排序**:按创建时间排序
|
||||||
|
|
||||||
|
### 👁️ 视图模式
|
||||||
|
- ✅ **网格视图**:卡片式展示
|
||||||
|
- ✅ **列表视图**:紧凑式展示
|
||||||
|
- ✅ **视图切换**:一键切换显示模式
|
||||||
|
|
||||||
|
## 🎯 版本对比
|
||||||
|
|
||||||
|
| 特性 | Web版本 | PyQt5版本 |
|
||||||
|
|------|---------|-----------|
|
||||||
|
| 运行环境 | 浏览器 | 桌面应用 |
|
||||||
|
| 安装要求 | 无 | Python + PyQt5 |
|
||||||
|
| 性能表现 | 依赖浏览器 | 原生性能 |
|
||||||
|
| 文件操作 | 受限 | 完全访问 |
|
||||||
|
| 离线使用 | 支持 | 完全支持 |
|
||||||
|
| 系统集成 | 有限 | 完全集成 |
|
||||||
|
| 更新方式 | 刷新页面 | 重启应用 |
|
||||||
|
|
||||||
|
## 🛠️ 技术栈
|
||||||
|
|
||||||
|
### Web版本
|
||||||
|
- **前端**:HTML5 + CSS3 + JavaScript ES6
|
||||||
|
- **样式**:CSS Grid + Flexbox
|
||||||
|
- **图标**:Font Awesome + Emoji
|
||||||
|
- **存储**:localStorage
|
||||||
|
|
||||||
|
### PyQt5版本
|
||||||
|
- **框架**:Python 3.7+ + PyQt5
|
||||||
|
- **架构**:MVC模式 + 信号槽机制
|
||||||
|
- **界面**:Qt样式表 + 自定义组件
|
||||||
|
- **存储**:JSON文件
|
||||||
|
|
||||||
|
## 📈 开发历程
|
||||||
|
|
||||||
|
### 第一阶段:Web版本开发
|
||||||
|
1. ✅ 基础界面搭建
|
||||||
|
2. ✅ 项目卡片设计
|
||||||
|
3. ✅ 侧边栏导航
|
||||||
|
4. ✅ 创建项目功能
|
||||||
|
5. ✅ 搜索过滤功能
|
||||||
|
|
||||||
|
### 第二阶段:界面优化
|
||||||
|
1. ✅ 三段式卡片布局
|
||||||
|
2. ✅ 1/3布局对话框
|
||||||
|
3. ✅ 悬停效果优化
|
||||||
|
4. ✅ 响应式设计
|
||||||
|
5. ✅ 文件选择集成
|
||||||
|
|
||||||
|
### 第三阶段:PyQt5移植
|
||||||
|
1. ✅ 架构设计
|
||||||
|
2. ✅ 组件开发
|
||||||
|
3. ✅ 样式移植
|
||||||
|
4. ✅ 功能实现
|
||||||
|
5. ✅ 测试优化
|
||||||
|
|
||||||
|
## 🎨 设计亮点
|
||||||
|
|
||||||
|
### 1. 三段式项目卡片
|
||||||
|
```
|
||||||
|
┌─────────────────┐
|
||||||
|
│ 标题 ⋮ │ ← 头部:项目名称 + 菜单
|
||||||
|
├─────────────────┤
|
||||||
|
│ 🏭 │ ← 中部:项目图标 + 类型
|
||||||
|
│ 工业项目 │
|
||||||
|
├─────────────────┤
|
||||||
|
│ 2024-06-08 15:56│ ← 底部:创建时间
|
||||||
|
└─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 2:1创建对话框
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ 创建新的项目 ✕ │
|
||||||
|
├─────────────────────────────────────┤
|
||||||
|
│ 模板选择 (2/3) │ 项目信息 (1/3) │
|
||||||
|
│ ┌─────┐ ┌─────┐ │ 项目名称 │
|
||||||
|
│ │ 📁 │ │ 🏭 │ │ ┌─────────────┐ │
|
||||||
|
│ │空白 │ │工业 │ │ │ │ │
|
||||||
|
│ └─────┘ └─────┘ │ └─────────────┘ │
|
||||||
|
│ ┌─────┐ ┌─────┐ │ 项目描述 │
|
||||||
|
│ │ 🥽 │ │ 💧 │ │ ┌─────────────┐ │
|
||||||
|
│ │VR │ │智能 │ │ │ │ │
|
||||||
|
│ └─────┘ └─────┘ │ └─────────────┘ │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 深色主题配色
|
||||||
|
- **主背景**:#1a1a1a(深黑)
|
||||||
|
- **卡片背景**:#2a2a2a(深灰)
|
||||||
|
- **边框色**:#3a3a3a(中灰)
|
||||||
|
- **强调色**:#8b5cf6(紫色)
|
||||||
|
- **文字色**:#ffffff(白色)
|
||||||
|
|
||||||
|
## 🔮 未来规划
|
||||||
|
|
||||||
|
### 短期目标
|
||||||
|
- [ ] 添加项目模板管理
|
||||||
|
- [ ] 实现真实的文件操作
|
||||||
|
- [ ] 添加项目统计功能
|
||||||
|
- [ ] 支持主题切换
|
||||||
|
|
||||||
|
### 中期目标
|
||||||
|
- [ ] 集成版本控制系统
|
||||||
|
- [ ] 添加协作功能
|
||||||
|
- [ ] 实现云同步
|
||||||
|
- [ ] 开发移动端版本
|
||||||
|
|
||||||
|
### 长期目标
|
||||||
|
- [ ] 构建插件生态
|
||||||
|
- [ ] 企业级功能
|
||||||
|
- [ ] AI辅助功能
|
||||||
|
- [ ] 跨平台统一
|
||||||
|
|
||||||
|
## 📞 技术支持
|
||||||
|
|
||||||
|
### 文档资源
|
||||||
|
- 📖 **详细说明**:README_PyQt5.md
|
||||||
|
- 🚀 **快速开始**:快速开始.md
|
||||||
|
- 🔧 **安装指南**:安装PyQt5指南.md
|
||||||
|
- 📊 **功能对比**:功能对比说明.md
|
||||||
|
|
||||||
|
### 常见问题
|
||||||
|
1. **PyQt5安装问题**:参考安装PyQt5指南.md
|
||||||
|
2. **功能使用问题**:参考快速开始.md
|
||||||
|
3. **版本选择问题**:参考功能对比说明.md
|
||||||
|
|
||||||
|
## 🏆 项目成就
|
||||||
|
|
||||||
|
### ✅ 完成的里程碑
|
||||||
|
1. **完整功能实现**:100%复制Web版本功能
|
||||||
|
2. **视觉效果还原**:像素级还原界面设计
|
||||||
|
3. **性能优化**:提供更好的桌面体验
|
||||||
|
4. **文档完善**:提供完整的使用文档
|
||||||
|
|
||||||
|
### 🎯 技术价值
|
||||||
|
- 展示了Web到桌面的完整转换过程
|
||||||
|
- 提供了PyQt5开发的最佳实践
|
||||||
|
- 建立了可复用的组件架构
|
||||||
|
- 创建了完整的文档体系
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
🎉 **MetaCore项目现在提供了Web和桌面两种完整的解决方案!**
|
||||||
|
|
||||||
|
无论您喜欢在浏览器中使用还是作为桌面应用运行,都能获得完全相同的功能和体验。选择最适合您的版本,开始管理您的项目吧!
|
||||||
39
MetaCore.spec
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
a = Analysis(
|
||||||
|
['MetaCore\\main.py'],
|
||||||
|
pathex=['.'],
|
||||||
|
binaries=[],
|
||||||
|
datas=[('MetaCore/Resources', 'MetaCore/Resources'), ('data', 'data')],
|
||||||
|
hiddenimports=[],
|
||||||
|
hookspath=[],
|
||||||
|
hooksconfig={},
|
||||||
|
runtime_hooks=[],
|
||||||
|
excludes=[],
|
||||||
|
noarchive=False,
|
||||||
|
optimize=0,
|
||||||
|
)
|
||||||
|
pyz = PYZ(a.pure)
|
||||||
|
|
||||||
|
exe = EXE(
|
||||||
|
pyz,
|
||||||
|
a.scripts,
|
||||||
|
a.binaries,
|
||||||
|
a.datas,
|
||||||
|
[],
|
||||||
|
name='MetaCore',
|
||||||
|
debug=False,
|
||||||
|
bootloader_ignore_signals=False,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
runtime_tmpdir=None,
|
||||||
|
console=False,
|
||||||
|
disable_windowed_traceback=False,
|
||||||
|
argv_emulation=False,
|
||||||
|
target_arch=None,
|
||||||
|
codesign_identity=None,
|
||||||
|
entitlements_file=None,
|
||||||
|
icon=['MetaCore\\Resources\\Icons\\app_icon.png'],
|
||||||
|
)
|
||||||
5
MetaCore/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# 基于编辑器的 HTTP 客户端请求
|
||||||
|
/httpRequests/
|
||||||
12
MetaCore/.idea/MetaCore.iml
generated
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="PyDocumentationSettings">
|
||||||
|
<option name="format" value="PLAIN" />
|
||||||
|
<option name="myDocStringFormat" value="Plain" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
MetaCore/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
8
MetaCore/.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/MetaCore.iml" filepath="$PROJECT_DIR$/.idea/MetaCore.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 89 KiB |
210
MetaCore/README.md
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
# MetaCore - PyQt5版本
|
||||||
|
|
||||||
|
这是基于PyQt5重写的MetaCore项目管理平台,完全复制了原始Web版本的界面和功能。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
### 🎯 主要功能
|
||||||
|
- ✅ **项目管理**:创建、导入、删除、重命名项目
|
||||||
|
- ✅ **项目卡片**:三段式布局(标题+菜单、图片+类型标签、时间)
|
||||||
|
- ✅ **收藏功能**:项目收藏/取消收藏
|
||||||
|
- ✅ **搜索过滤**:按名称搜索、按类型过滤
|
||||||
|
- ✅ **视图模式**:网格视图和列表视图
|
||||||
|
- ✅ **右键菜单**:完整的项目操作菜单
|
||||||
|
|
||||||
|
### 🎨 界面特性
|
||||||
|
- ✅ **深色主题**:现代化的深色界面设计
|
||||||
|
- ✅ **响应式布局**:自适应窗口大小
|
||||||
|
- ✅ **侧边栏导航**:可展开/收起的导航菜单
|
||||||
|
- ✅ **模态对话框**:创建项目和导入项目对话框
|
||||||
|
- ✅ **拖拽支持**:文件拖拽导入功能
|
||||||
|
|
||||||
|
## 安装和运行
|
||||||
|
|
||||||
|
### 1. 环境要求
|
||||||
|
- Python 3.7+
|
||||||
|
- PyQt5 5.15.0+
|
||||||
|
|
||||||
|
### 2. 安装依赖
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 运行应用
|
||||||
|
```bash
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
MetaCore/
|
||||||
|
├── main.py # 主程序入口
|
||||||
|
├── requirements.txt # 依赖包列表
|
||||||
|
├── README_PyQt5.md # 说明文档
|
||||||
|
├── data/ # 数据模块
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ ├── project_manager.py # 项目数据管理器
|
||||||
|
│ └── projects.json # 项目数据文件(自动生成)
|
||||||
|
└── ui/ # 界面模块
|
||||||
|
├── __init__.py
|
||||||
|
├── main_window.py # 主窗口
|
||||||
|
├── sidebar.py # 侧边栏组件
|
||||||
|
├── project_area.py # 项目显示区域
|
||||||
|
├── project_card.py # 项目卡片组件
|
||||||
|
├── create_project_dialog.py # 创建项目对话框
|
||||||
|
├── import_project_dialog.py # 导入项目对话框
|
||||||
|
└── styles.py # 样式表定义
|
||||||
|
```
|
||||||
|
|
||||||
|
## 主要组件说明
|
||||||
|
|
||||||
|
### 1. 主窗口 (MainWindow)
|
||||||
|
- 整体布局管理
|
||||||
|
- 菜单栏和状态栏
|
||||||
|
- 组件间信号连接
|
||||||
|
- 窗口事件处理
|
||||||
|
|
||||||
|
### 2. 侧边栏 (Sidebar)
|
||||||
|
- Logo区域
|
||||||
|
- 快速操作按钮
|
||||||
|
- 可展开的导航菜单
|
||||||
|
- 用户信息显示
|
||||||
|
|
||||||
|
### 3. 项目区域 (ProjectArea)
|
||||||
|
- 工具栏和搜索区域
|
||||||
|
- 网格/列表视图切换
|
||||||
|
- 项目卡片容器
|
||||||
|
- 空状态显示
|
||||||
|
|
||||||
|
### 4. 项目卡片 (ProjectCard)
|
||||||
|
- 三段式布局设计
|
||||||
|
- 悬停效果
|
||||||
|
- 右键菜单
|
||||||
|
- 收藏状态显示
|
||||||
|
|
||||||
|
### 5. 创建项目对话框 (CreateProjectDialog)
|
||||||
|
- 2:1布局比例
|
||||||
|
- 模板选择网格
|
||||||
|
- 项目信息表单
|
||||||
|
- 文件夹选择功能
|
||||||
|
|
||||||
|
### 6. 导入项目对话框 (ImportProjectDialog)
|
||||||
|
- 文件拖拽上传
|
||||||
|
- 导入选项配置
|
||||||
|
- 文件列表显示
|
||||||
|
- 进度反馈
|
||||||
|
|
||||||
|
## 数据管理
|
||||||
|
|
||||||
|
### 项目数据结构
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"title": "项目名称",
|
||||||
|
"date": "2024-06-08 15:56:35",
|
||||||
|
"type": "industrial",
|
||||||
|
"image": "🏭",
|
||||||
|
"favorite": true,
|
||||||
|
"path": "/path/to/project"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 支持的项目类型
|
||||||
|
- `industrial` - 工业项目 🏭
|
||||||
|
- `smart` - 智能项目 💧
|
||||||
|
- `vr` - VR项目 🥽
|
||||||
|
- `game` - 游戏项目 🎮
|
||||||
|
- `design` - 设计项目 🎨
|
||||||
|
- `empty` - 空白项目 📁
|
||||||
|
|
||||||
|
## 样式系统
|
||||||
|
|
||||||
|
### 主题色彩
|
||||||
|
- **主色调**:深灰色 (#1a1a1a, #2a2a2a)
|
||||||
|
- **边框色**:中灰色 (#3a3a3a, #4a4a4a)
|
||||||
|
- **强调色**:紫色 (#8b5cf6, #7c3aed)
|
||||||
|
- **文字色**:白色/灰色 (#ffffff, #cccccc, #888888)
|
||||||
|
|
||||||
|
### 组件样式
|
||||||
|
- 所有组件都有对应的ObjectName用于样式选择器
|
||||||
|
- 支持悬停状态和选中状态
|
||||||
|
- 统一的圆角和间距设计
|
||||||
|
- 平滑的过渡动画效果
|
||||||
|
|
||||||
|
## 信号和槽机制
|
||||||
|
|
||||||
|
### 主要信号
|
||||||
|
- `projects_changed` - 项目列表变化
|
||||||
|
- `project_added` - 项目添加
|
||||||
|
- `project_removed` - 项目删除
|
||||||
|
- `project_updated` - 项目更新
|
||||||
|
- `filter_changed` - 过滤条件变化
|
||||||
|
- `search_changed` - 搜索内容变化
|
||||||
|
|
||||||
|
### 事件处理
|
||||||
|
- 鼠标点击事件
|
||||||
|
- 键盘快捷键
|
||||||
|
- 拖拽事件
|
||||||
|
- 窗口事件
|
||||||
|
|
||||||
|
## 扩展功能
|
||||||
|
|
||||||
|
### 可以添加的功能
|
||||||
|
1. **项目模板系统**:真实的项目模板创建和应用
|
||||||
|
2. **文件管理**:项目内文件的管理和预览
|
||||||
|
3. **版本控制**:Git集成和版本管理
|
||||||
|
4. **协作功能**:多用户协作和权限管理
|
||||||
|
5. **插件系统**:支持第三方插件扩展
|
||||||
|
6. **云同步**:项目数据云端同步
|
||||||
|
7. **导出功能**:项目打包和分享
|
||||||
|
|
||||||
|
### 性能优化
|
||||||
|
1. **虚拟滚动**:大量项目时的性能优化
|
||||||
|
2. **缓存机制**:图片和数据缓存
|
||||||
|
3. **异步加载**:大文件异步处理
|
||||||
|
4. **内存管理**:及时释放不用的资源
|
||||||
|
|
||||||
|
## 开发说明
|
||||||
|
|
||||||
|
### 添加新组件
|
||||||
|
1. 在`ui/`目录下创建新的组件文件
|
||||||
|
2. 继承适当的PyQt5基类
|
||||||
|
3. 实现`init_ui()`方法
|
||||||
|
4. 添加必要的信号定义
|
||||||
|
5. 在样式表中添加对应样式
|
||||||
|
|
||||||
|
### 修改样式
|
||||||
|
1. 在`ui/styles.py`中修改样式定义
|
||||||
|
2. 使用ObjectName作为选择器
|
||||||
|
3. 支持状态选择器(:hover, :checked等)
|
||||||
|
4. 遵循现有的颜色和间距规范
|
||||||
|
|
||||||
|
### 数据持久化
|
||||||
|
- 项目数据自动保存到`data/projects.json`
|
||||||
|
- 应用关闭时自动保存
|
||||||
|
- 启动时自动加载历史数据
|
||||||
|
- 支持数据备份和恢复
|
||||||
|
|
||||||
|
## 与Web版本对比
|
||||||
|
|
||||||
|
### 相同功能
|
||||||
|
- ✅ 完全相同的界面布局
|
||||||
|
- ✅ 相同的项目管理功能
|
||||||
|
- ✅ 相同的视觉设计风格
|
||||||
|
- ✅ 相同的用户交互逻辑
|
||||||
|
|
||||||
|
### PyQt5版本优势
|
||||||
|
- ✅ 原生桌面应用体验
|
||||||
|
- ✅ 更好的性能表现
|
||||||
|
- ✅ 系统集成度更高
|
||||||
|
- ✅ 离线使用支持
|
||||||
|
- ✅ 文件系统直接访问
|
||||||
|
|
||||||
|
### 技术差异
|
||||||
|
- **Web版本**:HTML + CSS + JavaScript
|
||||||
|
- **PyQt5版本**:Python + PyQt5 + 自定义样式表
|
||||||
|
- **数据存储**:JSON文件 vs 浏览器存储
|
||||||
|
- **文件操作**:系统API vs Web API限制
|
||||||
|
|
||||||
|
这个PyQt5版本完全复制了Web版本的功能和外观,同时提供了更好的桌面应用体验。
|
||||||
BIN
MetaCore/Resources/Icons/Refresh.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
MetaCore/Resources/Icons/app_icon.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
MetaCore/Resources/Icons/category.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
MetaCore/Resources/Icons/create.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
MetaCore/Resources/Icons/delete.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
MetaCore/Resources/Icons/down.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
MetaCore/Resources/Icons/folder.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
MetaCore/Resources/Icons/grid_view.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
MetaCore/Resources/Icons/import.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
MetaCore/Resources/Icons/list_view.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
MetaCore/Resources/Icons/logo.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
MetaCore/Resources/Icons/management.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
MetaCore/Resources/Icons/overview.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
MetaCore/Resources/Icons/resource.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
MetaCore/Resources/Icons/right.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
MetaCore/Resources/Icons/settings.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
MetaCore/Resources/Icons/system_settings.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
1
MetaCore/data/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# 数据模块
|
||||||
BIN
MetaCore/data/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
MetaCore/data/__pycache__/project_manager.cpython-313.pyc
Normal file
1271
MetaCore/data/project_manager.py
Normal file
13
MetaCore/data/projects.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"title": "XNWX",
|
||||||
|
"date": "2025-09-28 10:48:15",
|
||||||
|
"type": "imported",
|
||||||
|
"image": "C:\\Users\\29381\\Desktop\\XNWX\\XNWX.png",
|
||||||
|
"path": "C:\\Users\\29381\\Desktop",
|
||||||
|
"project_dir": "C:\\Users\\29381\\Desktop\\XNWX",
|
||||||
|
"description": "从文件夹 XNWX 导入",
|
||||||
|
"status": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
67
MetaCore/main.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
MetaCore - 项目管理平台 (PyQt5版本)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
|
||||||
|
# 导入自定义组件
|
||||||
|
from MetaCore.ui.main_window import MainWindow
|
||||||
|
from MetaCore.ui.styles import StyleSheet
|
||||||
|
|
||||||
|
from MetaCore.data.project_manager import ProjectManager
|
||||||
|
|
||||||
|
class MetaCoreApp(QApplication):
|
||||||
|
"""MetaCore应用程序主类"""
|
||||||
|
|
||||||
|
def __init__(self, argv):
|
||||||
|
super().__init__(argv)
|
||||||
|
|
||||||
|
# 设置应用程序信息
|
||||||
|
self.setApplicationName("MetaCore")
|
||||||
|
self.setApplicationVersion("1.0.0")
|
||||||
|
self.setOrganizationName("MetaCore Team")
|
||||||
|
|
||||||
|
# 设置应用程序图标(如果图标文件存在)
|
||||||
|
icon_path = "resources/icons/app_icon.png"
|
||||||
|
if os.path.exists(icon_path):
|
||||||
|
self.setWindowIcon(QIcon(icon_path))
|
||||||
|
|
||||||
|
# 初始化数据管理器
|
||||||
|
self.project_manager = ProjectManager()
|
||||||
|
|
||||||
|
# 创建主窗口
|
||||||
|
self.main_window = MainWindow(self.project_manager)
|
||||||
|
|
||||||
|
# 应用样式表
|
||||||
|
self.setStyleSheet(StyleSheet.get_main_style())
|
||||||
|
|
||||||
|
# 显示主窗口
|
||||||
|
self.main_window.show()
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
"""应用程序关闭事件"""
|
||||||
|
# 保存项目数据
|
||||||
|
self.project_manager.save_projects()
|
||||||
|
event.accept()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数"""
|
||||||
|
app = MetaCoreApp(sys.argv)
|
||||||
|
|
||||||
|
# 设置高DPI支持
|
||||||
|
app.setAttribute(Qt.AA_EnableHighDpiScaling, True)
|
||||||
|
app.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
|
||||||
|
|
||||||
|
# 运行应用程序
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
24
MetaCore/requirements.txt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# MetaCore PyQt5版本依赖包
|
||||||
|
# ================================
|
||||||
|
|
||||||
|
# 必需依赖 - 核心GUI框架
|
||||||
|
PyQt5>=5.15.0
|
||||||
|
|
||||||
|
# 必需依赖 - 打包工具(用于构建可执行文件)
|
||||||
|
PyInstaller>=5.0.0
|
||||||
|
|
||||||
|
# 推荐依赖 - 图像处理(更好的图标和图片支持)
|
||||||
|
Pillow>=8.0.0
|
||||||
|
|
||||||
|
# 可选依赖 - 系统信息(系统集成功能)
|
||||||
|
psutil>=5.8.0
|
||||||
|
|
||||||
|
# 开发依赖 - 类型检查(开发时使用)
|
||||||
|
# typing-extensions>=4.0.0 # Python 3.7兼容性
|
||||||
|
|
||||||
|
# 注意:以下是Python标准库,无需安装
|
||||||
|
# - sys, os, json, datetime (系统和文件操作)
|
||||||
|
# - pathlib (路径处理)
|
||||||
|
# - subprocess (进程管理)
|
||||||
|
# - platform (平台信息)
|
||||||
|
# - typing (类型提示)
|
||||||
47
MetaCore/scripts/example_script.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
示例脚本 - 演示如何编写脚本
|
||||||
|
"""
|
||||||
|
|
||||||
|
from core.script_system import ScriptBase
|
||||||
|
|
||||||
|
class ExampleScript(ScriptBase):
|
||||||
|
"""示例脚本类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.counter = 0
|
||||||
|
self.rotation_speed = 30.0 # 度/秒
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""脚本开始时调用"""
|
||||||
|
self.log("示例脚本开始运行!")
|
||||||
|
self.log(f"挂载到对象: {self.gameObject.getName()}")
|
||||||
|
|
||||||
|
def update(self, dt):
|
||||||
|
"""每帧更新"""
|
||||||
|
self.counter += 1
|
||||||
|
|
||||||
|
# 每60帧输出一次信息
|
||||||
|
if self.counter % 60 == 0:
|
||||||
|
self.log(f"运行了 {self.counter} 帧")
|
||||||
|
|
||||||
|
# 让对象旋转
|
||||||
|
if self.transform:
|
||||||
|
current_h = self.transform.getH()
|
||||||
|
new_h = current_h + self.rotation_speed * dt
|
||||||
|
self.transform.setH(new_h)
|
||||||
|
|
||||||
|
def on_destroy(self):
|
||||||
|
"""脚本销毁时调用"""
|
||||||
|
self.log("示例脚本被销毁")
|
||||||
|
|
||||||
|
def on_enable(self):
|
||||||
|
"""脚本启用时调用"""
|
||||||
|
self.log("示例脚本被启用")
|
||||||
|
|
||||||
|
def on_disable(self):
|
||||||
|
"""脚本禁用时调用"""
|
||||||
|
self.log("示例脚本被禁用")
|
||||||
225
MetaCore/test_open.py
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def run_cmd_command(command, cwd=None, shell=True, timeout=30):
|
||||||
|
"""
|
||||||
|
执行CMD命令的通用方法
|
||||||
|
|
||||||
|
Args:
|
||||||
|
command (str or list): 要执行的命令
|
||||||
|
cwd (str, optional): 工作目录
|
||||||
|
shell (bool): 是否使用shell执行命令
|
||||||
|
timeout (int): 超时时间(秒)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (return_code, stdout, stderr)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 执行命令
|
||||||
|
result = subprocess.run(
|
||||||
|
command,
|
||||||
|
cwd=cwd,
|
||||||
|
shell=shell,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=timeout,
|
||||||
|
encoding='utf-8'
|
||||||
|
)
|
||||||
|
|
||||||
|
return result.returncode, result.stdout, result.stderr
|
||||||
|
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
return -1, "", "命令执行超时"
|
||||||
|
except Exception as e:
|
||||||
|
return -2, "", f"执行命令时出错: {str(e)}"
|
||||||
|
|
||||||
|
|
||||||
|
def run_cmd_with_venv(venv_path, command, cwd=None, timeout=30):
|
||||||
|
"""
|
||||||
|
在指定虚拟环境中执行CMD命令
|
||||||
|
|
||||||
|
Args:
|
||||||
|
venv_path (str): 虚拟环境路径
|
||||||
|
command (str): 要执行的命令
|
||||||
|
cwd (str, optional): 工作目录
|
||||||
|
timeout (int): 超时时间(秒)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (return_code, stdout, stderr)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 激活虚拟环境并执行命令
|
||||||
|
if os.name == 'nt': # Windows
|
||||||
|
activate_script = Path(venv_path) / 'Scripts' / 'activate.bat'
|
||||||
|
full_command = f'"{activate_script}" && {command}'
|
||||||
|
else: # Unix-like systems
|
||||||
|
activate_script = Path(venv_path) / 'bin' / 'activate'
|
||||||
|
full_command = f'source "{activate_script}" && {command}'
|
||||||
|
|
||||||
|
return run_cmd_command(full_command, cwd=cwd, timeout=timeout)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return -2, "", f"在虚拟环境中执行命令时出错: {str(e)}"
|
||||||
|
|
||||||
|
|
||||||
|
def run_python_in_venv(venv_path, script_path, args=None, cwd=None, timeout=30):
|
||||||
|
"""
|
||||||
|
在指定虚拟环境中运行Python脚本
|
||||||
|
|
||||||
|
Args:
|
||||||
|
venv_path (str): 虚拟环境路径
|
||||||
|
script_path (str): Python脚本路径
|
||||||
|
args (list, optional): 脚本参数
|
||||||
|
cwd (str, optional): 工作目录
|
||||||
|
timeout (int): 超时时间(秒)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (return_code, stdout, stderr)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 获取虚拟环境中的Python解释器
|
||||||
|
if os.name == 'nt': # Windows
|
||||||
|
python_executable = Path(venv_path) / 'Scripts' / 'python.exe'
|
||||||
|
else: # Unix-like systems
|
||||||
|
python_executable = Path(venv_path) / 'bin' / 'python'
|
||||||
|
|
||||||
|
# 构建命令
|
||||||
|
cmd = [str(python_executable), str(script_path)]
|
||||||
|
if args:
|
||||||
|
cmd.extend(args)
|
||||||
|
|
||||||
|
# 设置环境变量
|
||||||
|
env = os.environ.copy()
|
||||||
|
env['VIRTUAL_ENV'] = str(venv_path)
|
||||||
|
if os.name == 'nt': # Windows
|
||||||
|
env['PATH'] = str(Path(venv_path) / 'Scripts') + os.pathsep + env['PATH']
|
||||||
|
else: # Unix-like
|
||||||
|
env['PATH'] = str(Path(venv_path) / 'bin') + os.pathsep + env['PATH']
|
||||||
|
|
||||||
|
# 执行命令
|
||||||
|
result = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
cwd=cwd,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=timeout,
|
||||||
|
encoding='utf-8',
|
||||||
|
env=env
|
||||||
|
)
|
||||||
|
|
||||||
|
return result.returncode, result.stdout, result.stderr
|
||||||
|
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
return -1, "", "命令执行超时"
|
||||||
|
except Exception as e:
|
||||||
|
return -2, "", f"在虚拟环境中运行Python脚本时出错: {str(e)}"
|
||||||
|
|
||||||
|
|
||||||
|
def execute_commands_sequentially(commands, cwd=None, timeout=30):
|
||||||
|
"""
|
||||||
|
顺序执行多个命令
|
||||||
|
|
||||||
|
Args:
|
||||||
|
commands (list): 命令列表
|
||||||
|
cwd (str, optional): 工作目录
|
||||||
|
timeout (int): 超时时间(秒)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: 每个命令的执行结果列表
|
||||||
|
"""
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for i, command in enumerate(commands):
|
||||||
|
print(f"执行命令 {i + 1}/{len(commands)}: {command}")
|
||||||
|
return_code, stdout, stderr = run_cmd_command(command, cwd=cwd, timeout=timeout)
|
||||||
|
results.append({
|
||||||
|
'command': command,
|
||||||
|
'return_code': return_code,
|
||||||
|
'stdout': stdout,
|
||||||
|
'stderr': stderr
|
||||||
|
})
|
||||||
|
|
||||||
|
# 如果命令执行失败,停止执行后续命令
|
||||||
|
if return_code != 0:
|
||||||
|
print(f"命令执行失败,停止执行后续命令: {command}")
|
||||||
|
break
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def run_text():
|
||||||
|
# 示例1: 执行简单命令
|
||||||
|
print("=== 示例1: 执行简单命令 ===")
|
||||||
|
return_code, stdout, stderr = run_cmd_command("dir" if os.name == 'nt' else "ls -la")
|
||||||
|
print(f"返回码: {return_code}")
|
||||||
|
print(f"输出: {stdout}")
|
||||||
|
if stderr:
|
||||||
|
print(f"错误: {stderr}")
|
||||||
|
|
||||||
|
# 示例2: 在虚拟环境中执行命令
|
||||||
|
print("\n=== 示例2: 在虚拟环境中执行命令 ===")
|
||||||
|
# return_code, stdout, stderr = run_cmd_with_venv(
|
||||||
|
# r"C:\path\to\your\venv",
|
||||||
|
# "pip list"
|
||||||
|
# )
|
||||||
|
# print(f"返回码: {return_code}")
|
||||||
|
# print(f"输出: {stdout}")
|
||||||
|
|
||||||
|
# 示例3: 在虚拟环境中运行Python脚本
|
||||||
|
print("\n=== 示例3: 在虚拟环境中运行Python脚本 ===")
|
||||||
|
# return_code, stdout, stderr = run_python_in_venv(
|
||||||
|
# r"C:\path\to\your\venv",
|
||||||
|
# r"C:\path\to\your\script.py",
|
||||||
|
# args=["arg1", "arg2"]
|
||||||
|
# )
|
||||||
|
# print(f"返回码: {return_code}")
|
||||||
|
# print(f"输出: {stdout}")
|
||||||
|
|
||||||
|
# 示例4: 顺序执行多个命令
|
||||||
|
print("\n=== 示例4: 顺序执行多个命令 ===")
|
||||||
|
commands = [
|
||||||
|
"echo Hello",
|
||||||
|
"echo World",
|
||||||
|
"python --version"
|
||||||
|
]
|
||||||
|
results = execute_commands_sequentially(commands)
|
||||||
|
for result in results:
|
||||||
|
print(f"命令: {result['command']}")
|
||||||
|
print(f"返回码: {result['return_code']}")
|
||||||
|
print(f"输出: {result['stdout']}")
|
||||||
|
if result['stderr']:
|
||||||
|
print(f"错误: {result['stderr']}")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
|
||||||
|
# 使用示例
|
||||||
|
if __name__ == "__main__":
|
||||||
|
venv_path = r"d:\PythonProject\CH_EG\EG\.venv"
|
||||||
|
script_path = r"d:\PythonProject\CH_EG\EG\Start_Run.py"
|
||||||
|
|
||||||
|
print(f"虚拟环境路径: {venv_path}")
|
||||||
|
print(f"脚本路径: {script_path}")
|
||||||
|
|
||||||
|
# 检查路径是否存在
|
||||||
|
if not os.path.exists(venv_path):
|
||||||
|
print(f"错误: 虚拟环境路径不存在: {venv_path}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not os.path.exists(script_path):
|
||||||
|
print(f"错误: 脚本文件不存在: {script_path}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# 在虚拟环境中运行Python脚本
|
||||||
|
return_code, stdout, stderr = run_python_in_venv(venv_path, script_path)
|
||||||
|
|
||||||
|
print(f"返回码: {return_code}")
|
||||||
|
print(f"标准输出: {stdout}")
|
||||||
|
print(f"错误输出: {stderr}")
|
||||||
|
|
||||||
|
if return_code == 0:
|
||||||
|
print("脚本执行成功!")
|
||||||
|
else:
|
||||||
|
print("脚本执行失败!")
|
||||||
1
MetaCore/ui/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# UI模块
|
||||||
BIN
MetaCore/ui/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
MetaCore/ui/__pycache__/create_project_dialog.cpython-313.pyc
Normal file
BIN
MetaCore/ui/__pycache__/icon_manager.cpython-313.pyc
Normal file
BIN
MetaCore/ui/__pycache__/import_project_dialog.cpython-313.pyc
Normal file
BIN
MetaCore/ui/__pycache__/main_window.cpython-313.pyc
Normal file
BIN
MetaCore/ui/__pycache__/project_area.cpython-313.pyc
Normal file
BIN
MetaCore/ui/__pycache__/project_card.cpython-313.pyc
Normal file
BIN
MetaCore/ui/__pycache__/project_settings_page.cpython-313.pyc
Normal file
BIN
MetaCore/ui/__pycache__/sidebar.cpython-313.pyc
Normal file
BIN
MetaCore/ui/__pycache__/styles.cpython-313.pyc
Normal file
460
MetaCore/ui/create_project_dialog.py
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
创建项目对话框
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
|
||||||
|
from MetaCore.data.project_manager import ProjectManager
|
||||||
|
|
||||||
|
class CreateProjectDialog(QDialog):
|
||||||
|
"""创建项目对话框"""
|
||||||
|
|
||||||
|
def __init__(self, project_manager: ProjectManager, project_settings_page=None, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.project_manager = project_manager
|
||||||
|
self.project_settings_page = project_settings_page
|
||||||
|
self.selected_template = "empty"
|
||||||
|
self.selected_path = ""
|
||||||
|
|
||||||
|
self.init_ui()
|
||||||
|
self.connect_signals()
|
||||||
|
|
||||||
|
# 设置对话框属性
|
||||||
|
self.setWindowTitle("创建新的项目")
|
||||||
|
self.setModal(True)
|
||||||
|
self.setMinimumSize(1000, 725)
|
||||||
|
self.resize(1000, 725) # 设置默认尺寸
|
||||||
|
|
||||||
|
# 设置默认项目位置
|
||||||
|
self.set_default_location_from_settings()
|
||||||
|
|
||||||
|
# 居中显示
|
||||||
|
self.center_dialog()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
"""初始化UI"""
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.setSpacing(0)
|
||||||
|
|
||||||
|
# 标题栏 - 使用默认系统标题栏
|
||||||
|
# self.create_title_bar(layout)
|
||||||
|
|
||||||
|
# 主要内容区域
|
||||||
|
self.create_main_content(layout)
|
||||||
|
|
||||||
|
# 底部按钮
|
||||||
|
self.create_button_area(layout)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def create_main_content(self, layout):
|
||||||
|
"""创建主要内容"""
|
||||||
|
content_widget = QWidget()
|
||||||
|
content_layout = QHBoxLayout(content_widget)
|
||||||
|
content_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
content_layout.setSpacing(0)
|
||||||
|
|
||||||
|
# 左侧模板选择区域 (2/3)
|
||||||
|
self.create_template_section(content_layout)
|
||||||
|
|
||||||
|
# 右侧项目信息区域 (1/3)
|
||||||
|
self.create_project_info_section(content_layout)
|
||||||
|
|
||||||
|
layout.addWidget(content_widget)
|
||||||
|
|
||||||
|
def create_template_section(self, layout):
|
||||||
|
"""创建模板选择区域"""
|
||||||
|
template_widget = QWidget()
|
||||||
|
template_widget.setObjectName("templateSection")
|
||||||
|
template_layout = QVBoxLayout(template_widget)
|
||||||
|
template_layout.setContentsMargins(30, 30, 20, 30)
|
||||||
|
|
||||||
|
# 标题
|
||||||
|
title_label = QLabel("选择项目模板")
|
||||||
|
title_label.setObjectName("sectionTitle")
|
||||||
|
template_layout.addWidget(title_label)
|
||||||
|
|
||||||
|
# 模板网格
|
||||||
|
self.create_template_grid(template_layout)
|
||||||
|
|
||||||
|
# 设置固定比例 (2/3)
|
||||||
|
template_widget.setMinimumWidth(600)
|
||||||
|
layout.addWidget(template_widget, 2)
|
||||||
|
|
||||||
|
def create_template_grid(self, layout):
|
||||||
|
"""创建模板网格"""
|
||||||
|
# 滚动区域
|
||||||
|
scroll_area = QScrollArea()
|
||||||
|
scroll_area.setObjectName("templateScrollArea")
|
||||||
|
scroll_area.setWidgetResizable(True)
|
||||||
|
scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
|
scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||||
|
|
||||||
|
# 模板容器
|
||||||
|
templates_widget = QWidget()
|
||||||
|
templates_widget.setObjectName("templatesContainer")
|
||||||
|
templates_layout = QGridLayout(templates_widget)
|
||||||
|
templates_layout.setSpacing(20) # 增加间距,适配固定尺寸按钮
|
||||||
|
templates_layout.setContentsMargins(10, 10, 10, 10) # 添加容器边距
|
||||||
|
templates_layout.setAlignment(Qt.AlignTop | Qt.AlignLeft) # 左上对齐
|
||||||
|
|
||||||
|
# 模板数据 - 当前只有空白项目模板,后续可以添加更多模板
|
||||||
|
templates = [
|
||||||
|
("empty", "📄", "空白项目模板"),
|
||||||
|
# 后续可以添加的模板示例:
|
||||||
|
# ("web", "🌐", "Web应用模板"),
|
||||||
|
# ("mobile", "📱", "移动应用模板"),
|
||||||
|
# ("desktop", "🖥️", "桌面应用模板"),
|
||||||
|
# ("api", "🔌", "API服务模板"),
|
||||||
|
# ("data", "📊", "数据分析模板"),
|
||||||
|
# ("game", "🎮", "游戏开发模板"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# 创建模板项
|
||||||
|
self.template_buttons = []
|
||||||
|
for i, (template_id, icon, name) in enumerate(templates):
|
||||||
|
row = i // 3 # 每行最多3个模板,为后续扩展做准备
|
||||||
|
col = i % 3
|
||||||
|
|
||||||
|
template_btn = self.create_template_item(template_id, icon, name)
|
||||||
|
templates_layout.addWidget(template_btn, row, col)
|
||||||
|
self.template_buttons.append(template_btn)
|
||||||
|
|
||||||
|
# 添加弹性空间,确保模板按钮不会被拉伸
|
||||||
|
templates_layout.setRowStretch(templates_layout.rowCount(), 1)
|
||||||
|
templates_layout.setColumnStretch(templates_layout.columnCount(), 1)
|
||||||
|
|
||||||
|
scroll_area.setWidget(templates_widget)
|
||||||
|
layout.addWidget(scroll_area)
|
||||||
|
|
||||||
|
def create_template_item(self, template_id, icon, name):
|
||||||
|
"""创建模板项"""
|
||||||
|
template_btn = QPushButton()
|
||||||
|
template_btn.setObjectName("templateItem")
|
||||||
|
template_btn.setCheckable(True)
|
||||||
|
# 设置固定尺寸,确保所有模板按钮大小一致,便于后续添加多个模板
|
||||||
|
template_btn.setFixedSize(180, 140)
|
||||||
|
|
||||||
|
# 设置默认选中
|
||||||
|
if template_id == "empty":
|
||||||
|
template_btn.setChecked(True)
|
||||||
|
|
||||||
|
# 布局
|
||||||
|
btn_layout = QVBoxLayout(template_btn)
|
||||||
|
btn_layout.setAlignment(Qt.AlignCenter)
|
||||||
|
btn_layout.setSpacing(12)
|
||||||
|
btn_layout.setContentsMargins(20, 24, 20, 24)
|
||||||
|
|
||||||
|
# 图标
|
||||||
|
icon_label = QLabel(icon)
|
||||||
|
icon_label.setObjectName("templateIcon")
|
||||||
|
icon_label.setAlignment(Qt.AlignCenter)
|
||||||
|
btn_layout.addWidget(icon_label)
|
||||||
|
|
||||||
|
# 名称
|
||||||
|
name_label = QLabel(name)
|
||||||
|
name_label.setObjectName("templateName")
|
||||||
|
name_label.setAlignment(Qt.AlignCenter)
|
||||||
|
name_label.setWordWrap(True)
|
||||||
|
btn_layout.addWidget(name_label)
|
||||||
|
|
||||||
|
# 点击事件
|
||||||
|
def on_clicked():
|
||||||
|
# 取消其他按钮的选中状态
|
||||||
|
for btn in self.template_buttons:
|
||||||
|
if btn != template_btn:
|
||||||
|
btn.setChecked(False)
|
||||||
|
|
||||||
|
template_btn.setChecked(True)
|
||||||
|
self.selected_template = template_id
|
||||||
|
self.update_template_description(template_id)
|
||||||
|
|
||||||
|
template_btn.clicked.connect(on_clicked)
|
||||||
|
return template_btn
|
||||||
|
|
||||||
|
def create_project_info_section(self, layout):
|
||||||
|
"""创建项目信息区域"""
|
||||||
|
info_widget = QWidget()
|
||||||
|
info_widget.setObjectName("projectInfoSection")
|
||||||
|
info_layout = QVBoxLayout(info_widget)
|
||||||
|
info_layout.setContentsMargins(20, 30, 30, 30)
|
||||||
|
|
||||||
|
# 标题
|
||||||
|
title_label = QLabel("项目信息")
|
||||||
|
title_label.setObjectName("sectionTitle")
|
||||||
|
info_layout.addWidget(title_label)
|
||||||
|
|
||||||
|
# 模板描述
|
||||||
|
self.description_label = QLabel("创建一个空白项目,您可以从头开始构建您的应用程序。包含基础的项目结构和配置文件,适用于任何类型的项目开发。")
|
||||||
|
self.description_label.setObjectName("templateDescription")
|
||||||
|
self.description_label.setWordWrap(True)
|
||||||
|
info_layout.addWidget(self.description_label)
|
||||||
|
|
||||||
|
# 表单
|
||||||
|
self.create_project_form(info_layout)
|
||||||
|
|
||||||
|
info_layout.addStretch()
|
||||||
|
|
||||||
|
# 设置固定比例 (1/3),增加最大宽度以容纳更长的错误信息
|
||||||
|
info_widget.setMaximumWidth(350) # 从300增加到350
|
||||||
|
layout.addWidget(info_widget, 1)
|
||||||
|
|
||||||
|
def create_project_form(self, layout):
|
||||||
|
"""创建项目表单"""
|
||||||
|
form_layout = QVBoxLayout()
|
||||||
|
form_layout.setSpacing(18)
|
||||||
|
|
||||||
|
# 项目名称
|
||||||
|
name_group = QVBoxLayout()
|
||||||
|
name_group.setSpacing(4) # 减小间距,让错误提示更紧贴
|
||||||
|
|
||||||
|
name_label = QLabel("项目名称")
|
||||||
|
name_label.setObjectName("formLabel")
|
||||||
|
name_group.addWidget(name_label)
|
||||||
|
|
||||||
|
self.name_input = QLineEdit()
|
||||||
|
self.name_input.setObjectName("formInput")
|
||||||
|
self.name_input.setPlaceholderText("输入项目名称")
|
||||||
|
name_group.addWidget(self.name_input)
|
||||||
|
|
||||||
|
# 错误提示标签 - 紧贴在输入框下方的小红字
|
||||||
|
self.name_error_label = QLabel("")
|
||||||
|
self.name_error_label.setObjectName("errorLabel")
|
||||||
|
self.name_error_label.setWordWrap(False) # 不换行,保持一行显示
|
||||||
|
self.name_error_label.setFixedHeight(18) # 固定高度,一行小字
|
||||||
|
self.name_error_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||||
|
self.name_error_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
|
||||||
|
self.name_error_label.hide() # 初始隐藏
|
||||||
|
|
||||||
|
name_group.addWidget(self.name_error_label)
|
||||||
|
|
||||||
|
form_layout.addLayout(name_group)
|
||||||
|
|
||||||
|
# 项目描述
|
||||||
|
desc_group = QVBoxLayout()
|
||||||
|
desc_label = QLabel("项目描述")
|
||||||
|
desc_label.setObjectName("formLabel")
|
||||||
|
desc_group.addWidget(desc_label)
|
||||||
|
|
||||||
|
self.desc_input = QTextEdit()
|
||||||
|
self.desc_input.setObjectName("formTextArea")
|
||||||
|
self.desc_input.setPlaceholderText("输入项目描述(可选)")
|
||||||
|
self.desc_input.setMaximumHeight(70)
|
||||||
|
desc_group.addWidget(self.desc_input)
|
||||||
|
|
||||||
|
form_layout.addLayout(desc_group)
|
||||||
|
|
||||||
|
# 项目位置
|
||||||
|
location_group = QVBoxLayout()
|
||||||
|
location_label = QLabel("项目位置")
|
||||||
|
location_label.setObjectName("formLabel")
|
||||||
|
location_group.addWidget(location_label)
|
||||||
|
|
||||||
|
location_layout = QHBoxLayout()
|
||||||
|
self.location_input = QLineEdit()
|
||||||
|
self.location_input.setObjectName("formInput")
|
||||||
|
self.location_input.setPlaceholderText("点击浏览选择位置")
|
||||||
|
self.location_input.setReadOnly(True)
|
||||||
|
location_layout.addWidget(self.location_input)
|
||||||
|
|
||||||
|
browse_btn = QPushButton("📁")
|
||||||
|
browse_btn.setObjectName("browseBtn")
|
||||||
|
browse_btn.setFixedSize(32, 32) # 减小尺寸:40x32 -> 32x32
|
||||||
|
browse_btn.setToolTip("选择项目保存位置")
|
||||||
|
browse_btn.clicked.connect(self.browse_location)
|
||||||
|
location_layout.addWidget(browse_btn)
|
||||||
|
|
||||||
|
location_group.addLayout(location_layout)
|
||||||
|
form_layout.addLayout(location_group)
|
||||||
|
|
||||||
|
layout.addLayout(form_layout)
|
||||||
|
|
||||||
|
def create_button_area(self, layout):
|
||||||
|
"""创建按钮区域"""
|
||||||
|
button_widget = QWidget()
|
||||||
|
button_widget.setObjectName("buttonArea")
|
||||||
|
button_layout = QHBoxLayout(button_widget)
|
||||||
|
button_layout.setContentsMargins(30, 20, 30, 30)
|
||||||
|
button_layout.setSpacing(10) # 设置按钮间距
|
||||||
|
|
||||||
|
button_layout.addStretch()
|
||||||
|
|
||||||
|
# 取消按钮
|
||||||
|
cancel_btn = QPushButton("取消")
|
||||||
|
cancel_btn.setObjectName("secondaryBtn")
|
||||||
|
cancel_btn.clicked.connect(self.reject)
|
||||||
|
button_layout.addWidget(cancel_btn)
|
||||||
|
|
||||||
|
# 创建按钮
|
||||||
|
self.create_btn = QPushButton("创建项目")
|
||||||
|
self.create_btn.setObjectName("primaryBtn")
|
||||||
|
self.create_btn.clicked.connect(self.create_project)
|
||||||
|
button_layout.addWidget(self.create_btn)
|
||||||
|
|
||||||
|
layout.addWidget(button_widget)
|
||||||
|
|
||||||
|
def update_template_description(self, template_id):
|
||||||
|
"""更新模板描述"""
|
||||||
|
descriptions = {
|
||||||
|
"empty": "创建一个空白项目,您可以从头开始构建您的应用程序。包含基础的项目结构和配置文件,适用于任何类型的项目开发。",
|
||||||
|
}
|
||||||
|
|
||||||
|
description = descriptions.get(template_id, "项目模板描述")
|
||||||
|
self.description_label.setText(description)
|
||||||
|
|
||||||
|
def browse_location(self):
|
||||||
|
"""浏览项目位置"""
|
||||||
|
# 使用项目设置中的默认位置作为起始目录
|
||||||
|
if self.project_settings_page:
|
||||||
|
start_dir = self.project_settings_page.get_default_project_location()
|
||||||
|
else:
|
||||||
|
start_dir = os.path.expanduser("~/Documents")
|
||||||
|
|
||||||
|
folder = QFileDialog.getExistingDirectory(self, "选择项目保存位置", start_dir)
|
||||||
|
if folder:
|
||||||
|
self.selected_path = folder
|
||||||
|
self.location_input.setText(folder)
|
||||||
|
# 触发验证
|
||||||
|
self.validate_input()
|
||||||
|
|
||||||
|
def create_project(self):
|
||||||
|
"""创建项目"""
|
||||||
|
# 验证输入
|
||||||
|
name = self.name_input.text().strip()
|
||||||
|
if not name:
|
||||||
|
QMessageBox.warning(self, "输入错误", "请输入项目名称")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.selected_path:
|
||||||
|
QMessageBox.warning(self, "输入错误", "请选择项目保存位置")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 使用项目管理器的验证方法进行全面检查
|
||||||
|
is_valid, error_message = self.project_manager.validate_project_creation(name, self.selected_path)
|
||||||
|
if not is_valid:
|
||||||
|
QMessageBox.warning(self, "创建失败", error_message)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 创建项目
|
||||||
|
description = self.desc_input.toPlainText().strip()
|
||||||
|
try:
|
||||||
|
project = self.project_manager.add_project(
|
||||||
|
name, description, self.selected_template, self.selected_path
|
||||||
|
)
|
||||||
|
|
||||||
|
# 显示详细的成功信息
|
||||||
|
success_msg = f"""项目创建成功!
|
||||||
|
|
||||||
|
项目名称: {name}
|
||||||
|
项目目录: {project.project_dir}
|
||||||
|
|
||||||
|
项目文件结构已创建完成,包含:
|
||||||
|
• models/ - 模型文件夹
|
||||||
|
• textures/ - 贴图文件夹
|
||||||
|
• scenes/ - 场景文件夹
|
||||||
|
• project.json - 项目配置文件
|
||||||
|
|
||||||
|
您可以开始在此基础上开发您的应用程序。"""
|
||||||
|
|
||||||
|
QMessageBox.information(self, "创建成功", success_msg)
|
||||||
|
self.accept()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "创建失败", f"项目创建失败:{str(e)}")
|
||||||
|
|
||||||
|
def get_template_name(self, template_id):
|
||||||
|
"""获取模板名称"""
|
||||||
|
template_names = {
|
||||||
|
"empty": "空白项目模板",
|
||||||
|
}
|
||||||
|
return template_names.get(template_id, "空白项目模板")
|
||||||
|
|
||||||
|
def connect_signals(self):
|
||||||
|
"""连接信号"""
|
||||||
|
# 连接项目名称输入框的文本变化信号
|
||||||
|
self.name_input.textChanged.connect(self.validate_input)
|
||||||
|
# 连接路径选择的变化
|
||||||
|
self.location_input.textChanged.connect(self.validate_input)
|
||||||
|
|
||||||
|
def validate_input(self):
|
||||||
|
"""实时验证输入"""
|
||||||
|
name = self.name_input.text().strip()
|
||||||
|
path = self.selected_path
|
||||||
|
|
||||||
|
# 重置样式属性
|
||||||
|
self.name_input.setProperty("error", False)
|
||||||
|
self.name_input.setProperty("valid", False)
|
||||||
|
self.create_btn.setEnabled(True)
|
||||||
|
|
||||||
|
# 如果名称为空,清空错误提示(用户可能还在输入)
|
||||||
|
if not name:
|
||||||
|
self.name_error_label.hide()
|
||||||
|
self.name_input.style().polish(self.name_input)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 如果路径未选择,不进行完整验证
|
||||||
|
if not path:
|
||||||
|
self.name_error_label.hide()
|
||||||
|
self.name_input.style().polish(self.name_input)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 进行验证
|
||||||
|
is_valid, error_message = self.project_manager.validate_project_creation(name, path)
|
||||||
|
|
||||||
|
if not is_valid:
|
||||||
|
# 设置错误状态
|
||||||
|
self.name_input.setProperty("error", True)
|
||||||
|
self.name_input.setProperty("valid", False)
|
||||||
|
# 禁用创建按钮
|
||||||
|
self.create_btn.setEnabled(False)
|
||||||
|
# 显示错误信息 - 一行小红字
|
||||||
|
self.name_error_label.setText(error_message)
|
||||||
|
self.name_error_label.show()
|
||||||
|
else:
|
||||||
|
# 设置成功状态
|
||||||
|
self.name_input.setProperty("error", False)
|
||||||
|
self.name_input.setProperty("valid", True)
|
||||||
|
# 隐藏错误信息
|
||||||
|
self.name_error_label.hide()
|
||||||
|
|
||||||
|
# 刷新样式
|
||||||
|
self.name_input.style().polish(self.name_input)
|
||||||
|
|
||||||
|
def set_default_location(self, location: str):
|
||||||
|
"""设置默认项目位置"""
|
||||||
|
if location and os.path.exists(location):
|
||||||
|
self.selected_path = location
|
||||||
|
self.location_input.setText(location)
|
||||||
|
# 触发验证
|
||||||
|
self.validate_input()
|
||||||
|
|
||||||
|
def set_default_location_from_settings(self):
|
||||||
|
"""从项目设置中设置默认项目位置"""
|
||||||
|
if self.project_settings_page:
|
||||||
|
default_location = self.project_settings_page.get_default_project_location()
|
||||||
|
if default_location:
|
||||||
|
self.set_default_location(default_location)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def center_dialog(self):
|
||||||
|
"""对话框居中"""
|
||||||
|
if self.parent():
|
||||||
|
parent_rect = self.parent().geometry()
|
||||||
|
x = parent_rect.x() + (parent_rect.width() - self.width()) // 2
|
||||||
|
y = parent_rect.y() + (parent_rect.height() - self.height()) // 2
|
||||||
|
self.move(x, y)
|
||||||
|
else:
|
||||||
|
# 如果没有父窗口,则在屏幕中央显示
|
||||||
|
screen = QApplication.desktop().screenGeometry()
|
||||||
|
x = (screen.width() - self.width()) // 2
|
||||||
|
y = (screen.height() - self.height()) // 2
|
||||||
|
self.move(x, y)
|
||||||
238
MetaCore/ui/file_watcher.py
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
文件系统监控器
|
||||||
|
实时监测目录和文件的变化
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from PyQt5.QtCore import QObject, QFileSystemWatcher, pyqtSignal, QTimer
|
||||||
|
from PyQt5.QtWidgets import QMessageBox
|
||||||
|
|
||||||
|
class FileWatcher(QObject):
|
||||||
|
"""文件系统监控器"""
|
||||||
|
|
||||||
|
# 信号定义
|
||||||
|
directory_changed = pyqtSignal(str) # 目录变化信号
|
||||||
|
file_changed = pyqtSignal(str) # 文件变化信号
|
||||||
|
project_added = pyqtSignal(str) # 项目添加信号
|
||||||
|
project_removed = pyqtSignal(str) # 项目删除信号
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
# 创建文件系统监控器
|
||||||
|
self.watcher = QFileSystemWatcher()
|
||||||
|
|
||||||
|
# 连接信号
|
||||||
|
self.watcher.directoryChanged.connect(self.on_directory_changed)
|
||||||
|
self.watcher.fileChanged.connect(self.on_file_changed)
|
||||||
|
|
||||||
|
# 监控的路径列表
|
||||||
|
self.watched_directories = set()
|
||||||
|
self.watched_files = set()
|
||||||
|
|
||||||
|
# 目录内容缓存(用于检测具体变化)
|
||||||
|
self.directory_contents = {}
|
||||||
|
|
||||||
|
# 延迟处理定时器(避免频繁触发)
|
||||||
|
self.change_timer = QTimer()
|
||||||
|
self.change_timer.setSingleShot(True)
|
||||||
|
self.change_timer.timeout.connect(self.process_pending_changes)
|
||||||
|
self.pending_changes = set()
|
||||||
|
|
||||||
|
def add_directory(self, directory_path):
|
||||||
|
"""
|
||||||
|
添加目录监控
|
||||||
|
|
||||||
|
Args:
|
||||||
|
directory_path (str): 要监控的目录路径
|
||||||
|
"""
|
||||||
|
if not os.path.exists(directory_path):
|
||||||
|
print(f"警告: 目录不存在 - {directory_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not os.path.isdir(directory_path):
|
||||||
|
print(f"警告: 路径不是目录 - {directory_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 规范化路径
|
||||||
|
directory_path = os.path.abspath(directory_path)
|
||||||
|
|
||||||
|
if directory_path not in self.watched_directories:
|
||||||
|
# 添加到监控列表
|
||||||
|
self.watcher.addPath(directory_path)
|
||||||
|
self.watched_directories.add(directory_path)
|
||||||
|
|
||||||
|
# 缓存目录内容
|
||||||
|
self.cache_directory_contents(directory_path)
|
||||||
|
|
||||||
|
print(f"开始监控目录: {directory_path}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"目录已在监控中: {directory_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def remove_directory(self, directory_path):
|
||||||
|
"""
|
||||||
|
移除目录监控
|
||||||
|
|
||||||
|
Args:
|
||||||
|
directory_path (str): 要移除监控的目录路径
|
||||||
|
"""
|
||||||
|
directory_path = os.path.abspath(directory_path)
|
||||||
|
|
||||||
|
if directory_path in self.watched_directories:
|
||||||
|
self.watcher.removePath(directory_path)
|
||||||
|
self.watched_directories.remove(directory_path)
|
||||||
|
|
||||||
|
# 清除缓存
|
||||||
|
if directory_path in self.directory_contents:
|
||||||
|
del self.directory_contents[directory_path]
|
||||||
|
|
||||||
|
print(f"停止监控目录: {directory_path}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"目录未在监控中: {directory_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def add_file(self, file_path):
|
||||||
|
"""
|
||||||
|
添加文件监控
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path (str): 要监控的文件路径
|
||||||
|
"""
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
print(f"警告: 文件不存在 - {file_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not os.path.isfile(file_path):
|
||||||
|
print(f"警告: 路径不是文件 - {file_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
file_path = os.path.abspath(file_path)
|
||||||
|
|
||||||
|
if file_path not in self.watched_files:
|
||||||
|
self.watcher.addPath(file_path)
|
||||||
|
self.watched_files.add(file_path)
|
||||||
|
print(f"开始监控文件: {file_path}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"文件已在监控中: {file_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def remove_file(self, file_path):
|
||||||
|
"""
|
||||||
|
移除文件监控
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path (str): 要移除监控的文件路径
|
||||||
|
"""
|
||||||
|
file_path = os.path.abspath(file_path)
|
||||||
|
|
||||||
|
if file_path in self.watched_files:
|
||||||
|
self.watcher.removePath(file_path)
|
||||||
|
self.watched_files.remove(file_path)
|
||||||
|
print(f"停止监控文件: {file_path}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"文件未在监控中: {file_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def cache_directory_contents(self, directory_path):
|
||||||
|
"""缓存目录内容"""
|
||||||
|
try:
|
||||||
|
contents = set(os.listdir(directory_path))
|
||||||
|
self.directory_contents[directory_path] = contents
|
||||||
|
except OSError as e:
|
||||||
|
print(f"无法读取目录内容: {directory_path} - {e}")
|
||||||
|
|
||||||
|
def on_directory_changed(self, directory_path):
|
||||||
|
"""目录变化处理"""
|
||||||
|
print(f"检测到目录变化: {directory_path}")
|
||||||
|
|
||||||
|
# 添加到待处理变化列表
|
||||||
|
self.pending_changes.add(directory_path)
|
||||||
|
|
||||||
|
# 启动延迟处理定时器
|
||||||
|
self.change_timer.start(500) # 500ms延迟
|
||||||
|
|
||||||
|
def on_file_changed(self, file_path):
|
||||||
|
"""文件变化处理"""
|
||||||
|
print(f"检测到文件变化: {file_path}")
|
||||||
|
|
||||||
|
# 立即发出文件变化信号
|
||||||
|
self.file_changed.emit(file_path)
|
||||||
|
|
||||||
|
def process_pending_changes(self):
|
||||||
|
"""处理待处理的目录变化"""
|
||||||
|
for directory_path in self.pending_changes:
|
||||||
|
self.analyze_directory_changes(directory_path)
|
||||||
|
|
||||||
|
self.pending_changes.clear()
|
||||||
|
|
||||||
|
def analyze_directory_changes(self, directory_path):
|
||||||
|
"""分析目录具体变化"""
|
||||||
|
if not os.path.exists(directory_path):
|
||||||
|
print(f"目录已被删除: {directory_path}")
|
||||||
|
self.directory_changed.emit(directory_path)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 获取当前目录内容
|
||||||
|
current_contents = set(os.listdir(directory_path))
|
||||||
|
|
||||||
|
# 获取之前缓存的内容
|
||||||
|
previous_contents = self.directory_contents.get(directory_path, set())
|
||||||
|
|
||||||
|
# 检测新增的项目
|
||||||
|
added_items = current_contents - previous_contents
|
||||||
|
for item in added_items:
|
||||||
|
item_path = os.path.join(directory_path, item)
|
||||||
|
if os.path.isdir(item_path):
|
||||||
|
print(f"检测到新增目录: {item_path}")
|
||||||
|
self.project_added.emit(item_path)
|
||||||
|
else:
|
||||||
|
print(f"检测到新增文件: {item_path}")
|
||||||
|
|
||||||
|
# 检测删除的项目
|
||||||
|
removed_items = previous_contents - current_contents
|
||||||
|
for item in removed_items:
|
||||||
|
item_path = os.path.join(directory_path, item)
|
||||||
|
print(f"检测到删除项目: {item_path}")
|
||||||
|
self.project_removed.emit(item_path)
|
||||||
|
|
||||||
|
# 更新缓存
|
||||||
|
self.directory_contents[directory_path] = current_contents
|
||||||
|
|
||||||
|
# 发出目录变化信号
|
||||||
|
if added_items or removed_items:
|
||||||
|
self.directory_changed.emit(directory_path)
|
||||||
|
|
||||||
|
except OSError as e:
|
||||||
|
print(f"分析目录变化失败: {directory_path} - {e}")
|
||||||
|
|
||||||
|
def get_watched_directories(self):
|
||||||
|
"""获取所有监控的目录"""
|
||||||
|
return list(self.watched_directories)
|
||||||
|
|
||||||
|
def get_watched_files(self):
|
||||||
|
"""获取所有监控的文件"""
|
||||||
|
return list(self.watched_files)
|
||||||
|
|
||||||
|
def clear_all_watches(self):
|
||||||
|
"""清除所有监控"""
|
||||||
|
# 移除所有路径
|
||||||
|
for path in list(self.watched_directories):
|
||||||
|
self.remove_directory(path)
|
||||||
|
|
||||||
|
for path in list(self.watched_files):
|
||||||
|
self.remove_file(path)
|
||||||
|
|
||||||
|
print("已清除所有文件监控")
|
||||||
|
|
||||||
|
def is_watching(self, path):
|
||||||
|
"""检查是否正在监控指定路径"""
|
||||||
|
path = os.path.abspath(path)
|
||||||
|
return path in self.watched_directories or path in self.watched_files
|
||||||
197
MetaCore/ui/icon_manager.py
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
图标管理器
|
||||||
|
统一管理应用程序中使用的所有图标
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from PyQt5.QtGui import QIcon, QPixmap
|
||||||
|
from PyQt5.QtCore import QSize
|
||||||
|
|
||||||
|
class IconManager:
|
||||||
|
"""图标管理器"""
|
||||||
|
|
||||||
|
# 图标目录路径
|
||||||
|
ICONS_DIR = "Resources/Icons"
|
||||||
|
|
||||||
|
# 图标文件映射
|
||||||
|
ICON_FILES = {
|
||||||
|
# 应用程序图标
|
||||||
|
'app': 'app_icon.png',
|
||||||
|
'logo': 'logo.png',
|
||||||
|
|
||||||
|
# 操作图标
|
||||||
|
'create': 'create.png',
|
||||||
|
'import': 'import.png',
|
||||||
|
'folder': 'folder.png',
|
||||||
|
'delete': 'delete.png',
|
||||||
|
'Refresh': 'Refresh.png',
|
||||||
|
|
||||||
|
# 视图图标
|
||||||
|
'grid_view': 'grid_view.png',
|
||||||
|
'list_view': 'list_view.png',
|
||||||
|
|
||||||
|
# 导航图标
|
||||||
|
'overview': 'overview.png',
|
||||||
|
'management': 'management.png',
|
||||||
|
'resource_category': 'category.png',
|
||||||
|
'resource_management': 'resource.png',
|
||||||
|
'project_settings': 'settings.png',
|
||||||
|
'system_settings': 'system.png',
|
||||||
|
|
||||||
|
# 树箭头
|
||||||
|
'down': 'down.png',
|
||||||
|
'right': 'right.png',
|
||||||
|
}
|
||||||
|
|
||||||
|
# 图标缓存
|
||||||
|
_icon_cache = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_icon(cls, icon_name: str, size: QSize = None) -> QIcon:
|
||||||
|
"""
|
||||||
|
获取图标
|
||||||
|
|
||||||
|
Args:
|
||||||
|
icon_name (str): 图标名称
|
||||||
|
size (QSize, optional): 图标尺寸
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
QIcon: 图标对象,如果文件不存在则返回空图标
|
||||||
|
"""
|
||||||
|
# 检查缓存
|
||||||
|
cache_key = f"{icon_name}_{size.width() if size else 'default'}_{size.height() if size else 'default'}"
|
||||||
|
if cache_key in cls._icon_cache:
|
||||||
|
return cls._icon_cache[cache_key]
|
||||||
|
|
||||||
|
# 获取图标文件路径
|
||||||
|
icon_path = cls.get_icon_path(icon_name)
|
||||||
|
|
||||||
|
if not icon_path or not os.path.exists(icon_path):
|
||||||
|
# 如果图标文件不存在,返回空图标
|
||||||
|
icon = QIcon()
|
||||||
|
else:
|
||||||
|
# 创建图标
|
||||||
|
if size:
|
||||||
|
pixmap = QPixmap(icon_path).scaled(size, aspectRatioMode=1, transformMode=1)
|
||||||
|
icon = QIcon(pixmap)
|
||||||
|
else:
|
||||||
|
icon = QIcon(icon_path)
|
||||||
|
|
||||||
|
# 缓存图标
|
||||||
|
cls._icon_cache[cache_key] = icon
|
||||||
|
return icon
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_icon_path(cls, icon_name: str) -> str:
|
||||||
|
"""
|
||||||
|
获取图标文件路径
|
||||||
|
|
||||||
|
Args:
|
||||||
|
icon_name (str): 图标名称
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 图标文件的完整路径,如果不存在则返回空字符串
|
||||||
|
"""
|
||||||
|
if icon_name not in cls.ICON_FILES:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
icon_file = cls.ICON_FILES[icon_name]
|
||||||
|
icon_path = os.path.join(cls.ICONS_DIR, icon_file)
|
||||||
|
|
||||||
|
return icon_path
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_pixmap(cls, icon_name: str, size: QSize = None) -> QPixmap:
|
||||||
|
"""
|
||||||
|
获取图标的 QPixmap 对象
|
||||||
|
|
||||||
|
Args:
|
||||||
|
icon_name (str): 图标名称
|
||||||
|
size (QSize, optional): 图标尺寸
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
QPixmap: 图标的 QPixmap 对象
|
||||||
|
"""
|
||||||
|
icon_path = cls.get_icon_path(icon_name)
|
||||||
|
|
||||||
|
if not icon_path or not os.path.exists(icon_path):
|
||||||
|
return QPixmap()
|
||||||
|
|
||||||
|
pixmap = QPixmap(icon_path)
|
||||||
|
if size:
|
||||||
|
pixmap = pixmap.scaled(size, aspectRatioMode=1, transformMode=1)
|
||||||
|
|
||||||
|
return pixmap
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def icon_exists(cls, icon_name: str) -> bool:
|
||||||
|
"""
|
||||||
|
检查图标是否存在
|
||||||
|
|
||||||
|
Args:
|
||||||
|
icon_name (str): 图标名称
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 图标文件是否存在
|
||||||
|
"""
|
||||||
|
icon_path = cls.get_icon_path(icon_name)
|
||||||
|
return icon_path and os.path.exists(icon_path)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_project_type_icon(cls, project_type: str) -> QIcon:
|
||||||
|
"""
|
||||||
|
根据项目类型获取对应图标
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_type (str): 项目类型
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
QIcon: 项目类型对应的图标
|
||||||
|
"""
|
||||||
|
icon_name = f"project_{project_type}"
|
||||||
|
if icon_name in cls.ICON_FILES:
|
||||||
|
return cls.get_icon(icon_name)
|
||||||
|
else:
|
||||||
|
# 如果没有对应的项目类型图标,返回默认项目图标
|
||||||
|
return cls.get_icon('project_empty')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clear_cache(cls):
|
||||||
|
"""清空图标缓存"""
|
||||||
|
cls._icon_cache.clear()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def ensure_icons_directory(cls):
|
||||||
|
"""确保图标目录存在"""
|
||||||
|
if not os.path.exists(cls.ICONS_DIR):
|
||||||
|
os.makedirs(cls.ICONS_DIR, exist_ok=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_available_icons(cls) -> list:
|
||||||
|
"""
|
||||||
|
获取所有可用的图标列表
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: 可用图标名称列表
|
||||||
|
"""
|
||||||
|
available_icons = []
|
||||||
|
for icon_name in cls.ICON_FILES:
|
||||||
|
if cls.icon_exists(icon_name):
|
||||||
|
available_icons.append(icon_name)
|
||||||
|
return available_icons
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_missing_icons(cls) -> list:
|
||||||
|
"""
|
||||||
|
获取缺失的图标列表
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: 缺失图标名称列表
|
||||||
|
"""
|
||||||
|
missing_icons = []
|
||||||
|
for icon_name in cls.ICON_FILES:
|
||||||
|
if not cls.icon_exists(icon_name):
|
||||||
|
missing_icons.append(icon_name)
|
||||||
|
return missing_icons
|
||||||
468
MetaCore/ui/import_project_dialog.py
Normal file
@ -0,0 +1,468 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
导入项目对话框
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
|
||||||
|
from MetaCore.data.project_manager import ProjectManager
|
||||||
|
|
||||||
|
class ImportProjectDialog(QDialog):
|
||||||
|
"""导入项目对话框"""
|
||||||
|
|
||||||
|
def __init__(self, project_manager: ProjectManager, project_settings_page=None, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.project_manager = project_manager
|
||||||
|
self.project_settings_page = project_settings_page
|
||||||
|
self.selected_files = []
|
||||||
|
|
||||||
|
self.init_ui()
|
||||||
|
self.connect_signals()
|
||||||
|
|
||||||
|
# 设置对话框属性
|
||||||
|
self.setWindowTitle("导入文件夹")
|
||||||
|
self.setModal(True)
|
||||||
|
self.setMinimumSize(1000, 725)
|
||||||
|
self.resize(1000, 725) # 设置默认尺寸
|
||||||
|
|
||||||
|
# 居中显示
|
||||||
|
self.center_dialog()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
"""初始化UI"""
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.setSpacing(0)
|
||||||
|
|
||||||
|
# 标题栏
|
||||||
|
# self.create_title_bar(layout)
|
||||||
|
|
||||||
|
# 主要内容区域
|
||||||
|
self.create_main_content(layout)
|
||||||
|
|
||||||
|
# 底部按钮
|
||||||
|
self.create_button_area(layout)
|
||||||
|
|
||||||
|
def create_title_bar(self, layout):
|
||||||
|
"""创建标题栏"""
|
||||||
|
title_widget = QWidget()
|
||||||
|
title_widget.setObjectName("dialogTitle")
|
||||||
|
title_layout = QHBoxLayout(title_widget)
|
||||||
|
title_layout.setContentsMargins(30, 20, 30, 20)
|
||||||
|
|
||||||
|
# 标题
|
||||||
|
title_label = QLabel("导入项目文件")
|
||||||
|
title_label.setObjectName("titleLabel")
|
||||||
|
title_layout.addWidget(title_label)
|
||||||
|
|
||||||
|
title_layout.addStretch()
|
||||||
|
|
||||||
|
# 关闭按钮
|
||||||
|
close_btn = QPushButton("✕")
|
||||||
|
close_btn.setObjectName("closeBtn")
|
||||||
|
close_btn.setFixedSize(32, 32)
|
||||||
|
close_btn.clicked.connect(self.reject)
|
||||||
|
title_layout.addWidget(close_btn)
|
||||||
|
|
||||||
|
layout.addWidget(title_widget)
|
||||||
|
|
||||||
|
def create_main_content(self, layout):
|
||||||
|
"""创建主要内容"""
|
||||||
|
content_widget = QWidget()
|
||||||
|
content_layout = QVBoxLayout(content_widget)
|
||||||
|
content_layout.setContentsMargins(30, 30, 30, 30)
|
||||||
|
content_layout.setSpacing(20)
|
||||||
|
|
||||||
|
# 导入区域
|
||||||
|
self.create_import_area(content_layout)
|
||||||
|
|
||||||
|
# 导入选项
|
||||||
|
self.create_import_options(content_layout)
|
||||||
|
|
||||||
|
layout.addWidget(content_widget)
|
||||||
|
|
||||||
|
def create_import_area(self, layout):
|
||||||
|
"""创建导入区域"""
|
||||||
|
import_group = QGroupBox("选择文件夹")
|
||||||
|
import_group.setObjectName("importGroup")
|
||||||
|
import_layout = QVBoxLayout(import_group)
|
||||||
|
import_layout.setSpacing(15)
|
||||||
|
|
||||||
|
# 拖拽上传区域
|
||||||
|
self.upload_area = UploadArea()
|
||||||
|
self.upload_area.files_dropped.connect(self.on_files_dropped)
|
||||||
|
self.upload_area.select_files_requested.connect(self.select_files)
|
||||||
|
import_layout.addWidget(self.upload_area)
|
||||||
|
|
||||||
|
# 或者选择文件
|
||||||
|
file_layout = QHBoxLayout()
|
||||||
|
file_layout.addWidget(QLabel("或者"))
|
||||||
|
|
||||||
|
select_btn = QPushButton("点击选择文件夹")
|
||||||
|
select_btn.setObjectName("selectBtn")
|
||||||
|
select_btn.clicked.connect(self.select_files)
|
||||||
|
file_layout.addWidget(select_btn)
|
||||||
|
|
||||||
|
file_layout.addStretch()
|
||||||
|
import_layout.addLayout(file_layout)
|
||||||
|
|
||||||
|
# 文件列表
|
||||||
|
self.file_list = QListWidget()
|
||||||
|
self.file_list.setObjectName("fileList")
|
||||||
|
self.file_list.setMaximumHeight(150)
|
||||||
|
import_layout.addWidget(self.file_list)
|
||||||
|
|
||||||
|
layout.addWidget(import_group)
|
||||||
|
|
||||||
|
def create_import_options(self, layout):
|
||||||
|
"""创建导入选项"""
|
||||||
|
options_widget = QWidget()
|
||||||
|
options_widget.setObjectName("optionsGroup")
|
||||||
|
options_layout = QHBoxLayout(options_widget)
|
||||||
|
|
||||||
|
# 导入选项
|
||||||
|
self.extract_checkbox = QCheckBox("导入后打开项目")
|
||||||
|
self.extract_checkbox.setChecked(True)
|
||||||
|
options_layout.addWidget(self.extract_checkbox)
|
||||||
|
|
||||||
|
options_layout.addStretch()
|
||||||
|
|
||||||
|
self.overwrite_checkbox = QCheckBox("还原动态数据源")
|
||||||
|
options_layout.addWidget(self.overwrite_checkbox)
|
||||||
|
|
||||||
|
layout.addWidget(options_widget)
|
||||||
|
|
||||||
|
# def create_import_options(self, layout):
|
||||||
|
# """创建导入选项"""
|
||||||
|
# options_group = QGroupBox("导入选项")
|
||||||
|
# options_group.setObjectName("optionsGroup")
|
||||||
|
# options_layout = QVBoxLayout(options_group)
|
||||||
|
# options_layout.setSpacing(10)
|
||||||
|
#
|
||||||
|
# # 项目名称
|
||||||
|
# name_layout = QHBoxLayout()
|
||||||
|
# name_layout.addWidget(QLabel("项目名称:"))
|
||||||
|
#
|
||||||
|
# self.name_input = QLineEdit()
|
||||||
|
# self.name_input.setObjectName("nameInput")
|
||||||
|
# self.name_input.setPlaceholderText("自动从文件名提取")
|
||||||
|
# name_layout.addWidget(self.name_input)
|
||||||
|
#
|
||||||
|
# options_layout.addLayout(name_layout)
|
||||||
|
#
|
||||||
|
# # 导入位置
|
||||||
|
# location_layout = QHBoxLayout()
|
||||||
|
# location_layout.addWidget(QLabel("导入位置:"))
|
||||||
|
#
|
||||||
|
# self.location_input = QLineEdit()
|
||||||
|
# self.location_input.setObjectName("locationInput")
|
||||||
|
# self.location_input.setPlaceholderText("选择导入位置")
|
||||||
|
# self.location_input.setReadOnly(True)
|
||||||
|
# location_layout.addWidget(self.location_input)
|
||||||
|
#
|
||||||
|
# browse_btn = QPushButton("浏览")
|
||||||
|
# browse_btn.setObjectName("browseBtn")
|
||||||
|
# browse_btn.clicked.connect(self.browse_location)
|
||||||
|
# location_layout.addWidget(browse_btn)
|
||||||
|
#
|
||||||
|
# options_layout.addLayout(location_layout)
|
||||||
|
#
|
||||||
|
# # 导入选项
|
||||||
|
# self.extract_checkbox = QCheckBox("解压缩文件")
|
||||||
|
# self.extract_checkbox.setChecked(True)
|
||||||
|
# options_layout.addWidget(self.extract_checkbox)
|
||||||
|
#
|
||||||
|
# self.overwrite_checkbox = QCheckBox("覆盖已存在的文件")
|
||||||
|
# options_layout.addWidget(self.overwrite_checkbox)
|
||||||
|
#
|
||||||
|
# layout.addWidget(options_group)
|
||||||
|
|
||||||
|
def create_button_area(self, layout):
|
||||||
|
"""创建按钮区域"""
|
||||||
|
button_widget = QWidget()
|
||||||
|
button_widget.setObjectName("buttonArea")
|
||||||
|
button_layout = QHBoxLayout(button_widget)
|
||||||
|
button_layout.setContentsMargins(30, 20, 30, 30)
|
||||||
|
button_layout.setSpacing(10) # 与创建项目对话框保持一致
|
||||||
|
|
||||||
|
button_layout.addStretch()
|
||||||
|
|
||||||
|
# 取消按钮
|
||||||
|
self.cancel_btn = QPushButton("取消")
|
||||||
|
self.cancel_btn.setObjectName("secondaryBtn")
|
||||||
|
self.cancel_btn.clicked.connect(self.reject)
|
||||||
|
button_layout.addWidget(self.cancel_btn)
|
||||||
|
|
||||||
|
# 导入按钮
|
||||||
|
self.import_btn = QPushButton("导入项目")
|
||||||
|
self.import_btn.setObjectName("primaryBtn")
|
||||||
|
self.import_btn.setEnabled(False)
|
||||||
|
self.import_btn.clicked.connect(self.import_project)
|
||||||
|
button_layout.addWidget(self.import_btn)
|
||||||
|
|
||||||
|
layout.addWidget(button_widget)
|
||||||
|
|
||||||
|
def select_files(self):
|
||||||
|
"""选择文件夹"""
|
||||||
|
# 使用项目设置中的默认位置作为起始目录
|
||||||
|
if self.project_settings_page:
|
||||||
|
start_dir = self.project_settings_page.get_default_project_location()
|
||||||
|
else:
|
||||||
|
start_dir = os.path.expanduser("~/Documents")
|
||||||
|
|
||||||
|
folder = QFileDialog.getExistingDirectory(
|
||||||
|
self, "选择文件夹",
|
||||||
|
start_dir
|
||||||
|
)
|
||||||
|
|
||||||
|
if folder:
|
||||||
|
self.selected_files = [folder]
|
||||||
|
self.update_file_list()
|
||||||
|
self.update_project_name()
|
||||||
|
|
||||||
|
def browse_location(self):
|
||||||
|
"""浏览导入位置"""
|
||||||
|
# 当前UI简化版本不需要此功能
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_files_dropped(self, files):
|
||||||
|
"""文件夹拖拽事件"""
|
||||||
|
# 只接受文件夹
|
||||||
|
folders = [f for f in files if os.path.isdir(f)]
|
||||||
|
if folders:
|
||||||
|
self.selected_files = folders
|
||||||
|
self.update_file_list()
|
||||||
|
self.update_project_name()
|
||||||
|
else:
|
||||||
|
QMessageBox.warning(self, "提示", "请拖拽文件夹,不支持单个文件")
|
||||||
|
|
||||||
|
def update_file_list(self):
|
||||||
|
"""更新文件夹列表"""
|
||||||
|
self.file_list.clear()
|
||||||
|
|
||||||
|
for folder_path in self.selected_files:
|
||||||
|
folder_name = os.path.basename(folder_path)
|
||||||
|
|
||||||
|
# 计算文件夹大小和文件数量
|
||||||
|
try:
|
||||||
|
total_size = 0
|
||||||
|
file_count = 0
|
||||||
|
for root, dirs, files in os.walk(folder_path):
|
||||||
|
for file in files:
|
||||||
|
file_path = os.path.join(root, file)
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
total_size += os.path.getsize(file_path)
|
||||||
|
file_count += 1
|
||||||
|
|
||||||
|
size_str = self.format_file_size(total_size)
|
||||||
|
item_text = f"📁 {folder_name} ({file_count} 个文件, {size_str})"
|
||||||
|
except Exception:
|
||||||
|
item_text = f"📁 {folder_name} (无法计算大小)"
|
||||||
|
|
||||||
|
self.file_list.addItem(item_text)
|
||||||
|
|
||||||
|
# 按钮状态由 update_project_name 方法中的验证逻辑控制
|
||||||
|
|
||||||
|
def update_project_name(self):
|
||||||
|
"""更新项目名称并验证"""
|
||||||
|
if not self.selected_files:
|
||||||
|
self.import_btn.setEnabled(False)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 从第一个文件夹名自动提取项目名称
|
||||||
|
folder_path = self.selected_files[0]
|
||||||
|
folder_name = os.path.basename(folder_path)
|
||||||
|
|
||||||
|
# 进行验证
|
||||||
|
is_valid, error_message = self.project_manager.validate_project_import(folder_name, folder_path)
|
||||||
|
|
||||||
|
if is_valid:
|
||||||
|
# 验证通过,启用导入按钮
|
||||||
|
self.import_btn.setEnabled(True)
|
||||||
|
self.import_btn.setToolTip("")
|
||||||
|
else:
|
||||||
|
# 验证失败,禁用导入按钮并显示错误信息
|
||||||
|
self.import_btn.setEnabled(False)
|
||||||
|
self.import_btn.setToolTip(f"无法导入: {error_message}")
|
||||||
|
|
||||||
|
def format_file_size(self, size):
|
||||||
|
"""格式化文件大小"""
|
||||||
|
for unit in ['B', 'KB', 'MB', 'GB']:
|
||||||
|
if size < 1024.0:
|
||||||
|
return f"{size:.1f} {unit}"
|
||||||
|
size /= 1024.0
|
||||||
|
return f"{size:.1f} TB"
|
||||||
|
|
||||||
|
def import_project(self):
|
||||||
|
"""导入项目"""
|
||||||
|
# 防止重复点击
|
||||||
|
if not self.import_btn.isEnabled():
|
||||||
|
return
|
||||||
|
|
||||||
|
# 立即禁用按钮,防止重复点击
|
||||||
|
self.import_btn.setEnabled(False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 验证输入
|
||||||
|
if not self.selected_files:
|
||||||
|
QMessageBox.warning(self, "输入错误", "请选择要导入的文件夹")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 从第一个文件夹名自动提取项目名称
|
||||||
|
folder_path = self.selected_files[0]
|
||||||
|
folder_name = os.path.basename(folder_path)
|
||||||
|
name = folder_name
|
||||||
|
|
||||||
|
# 使用项目管理器的验证方法进行全面检查
|
||||||
|
is_valid, error_message = self.project_manager.validate_project_import(name, folder_path)
|
||||||
|
if not is_valid:
|
||||||
|
QMessageBox.warning(self, "导入失败", error_message)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 导入项目 - 直接使用现有文件夹作为项目目录
|
||||||
|
project = self.project_manager.import_project(
|
||||||
|
name, # 项目名称
|
||||||
|
f"从文件夹 {folder_name} 导入", # 项目描述
|
||||||
|
"imported", # 项目类型
|
||||||
|
folder_path # 直接使用原文件夹路径作为项目目录
|
||||||
|
)
|
||||||
|
|
||||||
|
# 处理导入选项
|
||||||
|
if self.overwrite_checkbox.isChecked():
|
||||||
|
self.restore_dynamic_data_sources(project)
|
||||||
|
|
||||||
|
QMessageBox.information(self, "导入成功", f"项目 \"{name}\" 导入成功!\n文件夹位置: {folder_path}")
|
||||||
|
|
||||||
|
# 如果勾选了导入后打开项目,则打开项目
|
||||||
|
if self.extract_checkbox.isChecked():
|
||||||
|
self.open_imported_project(project)
|
||||||
|
|
||||||
|
self.accept()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "导入失败", f"项目导入失败:{str(e)}")
|
||||||
|
finally:
|
||||||
|
# 确保在任何情况下都重新启用按钮(如果对话框没有关闭)
|
||||||
|
if self.isVisible():
|
||||||
|
self.import_btn.setEnabled(True)
|
||||||
|
|
||||||
|
def open_imported_project(self, project):
|
||||||
|
"""打开导入的项目"""
|
||||||
|
try:
|
||||||
|
# 使用项目管理器的验证方法检查项目是否可以打开
|
||||||
|
is_valid, error_message = self.project_manager.validate_project_open(project.project_dir)
|
||||||
|
if not is_valid:
|
||||||
|
QMessageBox.warning(self, "无法打开项目", f"项目无法打开: {error_message}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 验证通过,显示成功信息
|
||||||
|
QMessageBox.information(self, "打开项目", f"正在打开项目: {project.title}")
|
||||||
|
|
||||||
|
# TODO: 在这里添加实际的项目打开逻辑
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "错误", f"打开项目时发生错误:\n{str(e)}")
|
||||||
|
|
||||||
|
def restore_dynamic_data_sources(self, project):
|
||||||
|
"""还原动态数据源"""
|
||||||
|
try:
|
||||||
|
# TODO: 在这里添加还原动态数据源的逻辑
|
||||||
|
print(f"还原项目 {project.title} 的动态数据源")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.warning(self, "警告", f"还原动态数据源时发生错误:\n{str(e)}")
|
||||||
|
|
||||||
|
def connect_signals(self):
|
||||||
|
"""连接信号"""
|
||||||
|
# 连接按钮信号
|
||||||
|
self.cancel_btn.clicked.connect(self.reject)
|
||||||
|
self.import_btn.clicked.connect(self.import_project)
|
||||||
|
|
||||||
|
# 连接文件选择按钮信号
|
||||||
|
# self.select_files_btn.clicked.connect(self.select_files)
|
||||||
|
# self.select_folder_btn.clicked.connect(self.select_folder)
|
||||||
|
|
||||||
|
def center_dialog(self):
|
||||||
|
"""对话框居中"""
|
||||||
|
if self.parent():
|
||||||
|
parent_rect = self.parent().geometry()
|
||||||
|
x = parent_rect.x() + (parent_rect.width() - self.width()) // 2
|
||||||
|
y = parent_rect.y() + (parent_rect.height() - self.height()) // 2
|
||||||
|
self.move(x, y)
|
||||||
|
|
||||||
|
|
||||||
|
class UploadArea(QWidget):
|
||||||
|
"""文件上传区域"""
|
||||||
|
|
||||||
|
files_dropped = pyqtSignal(list)
|
||||||
|
select_files_requested = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.setAcceptDrops(True)
|
||||||
|
self.init_ui()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
"""初始化UI"""
|
||||||
|
self.setObjectName("uploadArea")
|
||||||
|
self.setMinimumHeight(150)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.setSpacing(10)
|
||||||
|
|
||||||
|
# 上传图标
|
||||||
|
icon_label = QLabel("📁")
|
||||||
|
icon_label.setStyleSheet("font-size: 32px; color: #666666;")
|
||||||
|
icon_label.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.addWidget(icon_label)
|
||||||
|
|
||||||
|
# 提示文字
|
||||||
|
text_label = QLabel("拖拽文件夹到这里,或者")
|
||||||
|
text_label.setStyleSheet("color: #888888; font-size: 14px;")
|
||||||
|
text_label.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.addWidget(text_label)
|
||||||
|
|
||||||
|
# 选择按钮
|
||||||
|
select_btn = QPushButton("点击选择")
|
||||||
|
select_btn.setObjectName("uploadBtn")
|
||||||
|
select_btn.clicked.connect(self.select_files_requested.emit)
|
||||||
|
layout.addWidget(select_btn)
|
||||||
|
|
||||||
|
# 支持格式提示
|
||||||
|
format_label = QLabel("支持任意文件夹")
|
||||||
|
format_label.setStyleSheet("color: #666666; font-size: 12px;")
|
||||||
|
format_label.setAlignment(Qt.AlignCenter)
|
||||||
|
layout.addWidget(format_label)
|
||||||
|
|
||||||
|
def dragEnterEvent(self, event):
|
||||||
|
"""拖拽进入事件"""
|
||||||
|
if event.mimeData().hasUrls():
|
||||||
|
event.acceptProposedAction()
|
||||||
|
self.setProperty("dragOver", True)
|
||||||
|
self.style().unpolish(self)
|
||||||
|
self.style().polish(self)
|
||||||
|
|
||||||
|
def dragLeaveEvent(self, event):
|
||||||
|
"""拖拽离开事件"""
|
||||||
|
self.setProperty("dragOver", False)
|
||||||
|
self.style().unpolish(self)
|
||||||
|
self.style().polish(self)
|
||||||
|
|
||||||
|
def dropEvent(self, event):
|
||||||
|
"""拖拽放下事件"""
|
||||||
|
files = []
|
||||||
|
for url in event.mimeData().urls():
|
||||||
|
if url.isLocalFile():
|
||||||
|
files.append(url.toLocalFile())
|
||||||
|
|
||||||
|
if files:
|
||||||
|
self.files_dropped.emit(files)
|
||||||
|
|
||||||
|
self.setProperty("dragOver", False)
|
||||||
|
self.style().unpolish(self)
|
||||||
|
self.style().polish(self)
|
||||||
303
MetaCore/ui/main_window.py
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
主窗口类
|
||||||
|
"""
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
|
||||||
|
from MetaCore.ui.sidebar import Sidebar
|
||||||
|
from MetaCore.ui.project_area import ProjectArea
|
||||||
|
from MetaCore.ui.create_project_dialog import CreateProjectDialog
|
||||||
|
from MetaCore.ui.import_project_dialog import ImportProjectDialog
|
||||||
|
from MetaCore.ui.project_settings_page import ProjectSettingsPage
|
||||||
|
from MetaCore.data.project_manager import ProjectManager
|
||||||
|
from MetaCore.ui.icon_manager import IconManager
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow):
|
||||||
|
"""主窗口类"""
|
||||||
|
|
||||||
|
def __init__(self, project_manager: ProjectManager):
|
||||||
|
super().__init__()
|
||||||
|
self.project_manager = project_manager
|
||||||
|
self.current_filter = "overview"
|
||||||
|
self.current_search = ""
|
||||||
|
|
||||||
|
self.init_ui()
|
||||||
|
self.connect_signals()
|
||||||
|
|
||||||
|
# 设置窗口属性
|
||||||
|
self.setWindowTitle("MetaCore - 项目管理平台")
|
||||||
|
self.setWindowIcon(IconManager.get_icon('app'))
|
||||||
|
self.setMinimumSize(1000, 700)
|
||||||
|
self.resize(1400, 900)
|
||||||
|
|
||||||
|
# 响应式布局标志
|
||||||
|
self.is_compact_mode = False
|
||||||
|
|
||||||
|
# 居中显示
|
||||||
|
self.center_window()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
"""初始化UI"""
|
||||||
|
# 创建中央部件
|
||||||
|
central_widget = QWidget()
|
||||||
|
self.setCentralWidget(central_widget)
|
||||||
|
|
||||||
|
# 创建主布局
|
||||||
|
main_layout = QHBoxLayout(central_widget)
|
||||||
|
# 设置部件内容周围的边距大小分别为左、上、右和下。
|
||||||
|
# 边距由布局系统使用,并且子类可能使用边距来指定绘制区域(例如,不包括框架)。
|
||||||
|
# 更改页边距会触发一个 resizeEvent() 事件。
|
||||||
|
main_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
main_layout.setSpacing(0)
|
||||||
|
|
||||||
|
# 创建侧边栏
|
||||||
|
self.sidebar = Sidebar(self.project_manager)
|
||||||
|
main_layout.addWidget(self.sidebar)
|
||||||
|
|
||||||
|
# 创建项目区域
|
||||||
|
self.project_area = ProjectArea(self.project_manager)
|
||||||
|
|
||||||
|
# 创建项目设置页面
|
||||||
|
self.project_settings_page = ProjectSettingsPage()
|
||||||
|
|
||||||
|
# 创建堆叠窗口部件来管理不同页面
|
||||||
|
self.stacked_widget = QStackedWidget()
|
||||||
|
self.stacked_widget.addWidget(self.project_area) # 索引 0: 项目区域
|
||||||
|
self.stacked_widget.addWidget(self.project_settings_page) # 索引 1: 项目设置页面
|
||||||
|
|
||||||
|
main_layout.addWidget(self.stacked_widget)
|
||||||
|
|
||||||
|
# 设置布局比例
|
||||||
|
main_layout.setStretch(0, 0) # 侧边栏固定宽度
|
||||||
|
main_layout.setStretch(1, 1) # 堆叠窗口部件自适应
|
||||||
|
|
||||||
|
# 创建状态栏
|
||||||
|
# self.create_status_bar()
|
||||||
|
|
||||||
|
# 创建菜单栏
|
||||||
|
# self.create_menu_bar()
|
||||||
|
|
||||||
|
def create_status_bar(self):
|
||||||
|
"""创建状态栏"""
|
||||||
|
self.status_bar = self.statusBar()
|
||||||
|
|
||||||
|
# 项目数量标签
|
||||||
|
self.project_count_label = QLabel()
|
||||||
|
self.status_bar.addWidget(self.project_count_label)
|
||||||
|
|
||||||
|
# 分隔符
|
||||||
|
self.status_bar.addPermanentWidget(QLabel("|"))
|
||||||
|
|
||||||
|
# 当前用户标签
|
||||||
|
user_label = QLabel("当前用户: Admin")
|
||||||
|
self.status_bar.addPermanentWidget(user_label)
|
||||||
|
|
||||||
|
# 更新项目数量
|
||||||
|
self.update_project_count()
|
||||||
|
|
||||||
|
def create_menu_bar(self):
|
||||||
|
"""创建菜单栏"""
|
||||||
|
menubar = self.menuBar()
|
||||||
|
|
||||||
|
# 文件菜单
|
||||||
|
file_menu = menubar.addMenu('文件(&F)')
|
||||||
|
|
||||||
|
# 新建项目
|
||||||
|
new_action = QAction('新建项目(&N)', self)
|
||||||
|
new_action.setShortcut('Ctrl+N')
|
||||||
|
new_action.setStatusTip('创建新项目')
|
||||||
|
new_action.triggered.connect(self.show_create_project_dialog)
|
||||||
|
file_menu.addAction(new_action)
|
||||||
|
|
||||||
|
# 导入项目
|
||||||
|
import_action = QAction('导入项目(&I)', self)
|
||||||
|
import_action.setShortcut('Ctrl+I')
|
||||||
|
import_action.setStatusTip('导入现有项目')
|
||||||
|
import_action.triggered.connect(self.show_import_project_dialog)
|
||||||
|
file_menu.addAction(import_action)
|
||||||
|
|
||||||
|
file_menu.addSeparator()
|
||||||
|
|
||||||
|
# 退出
|
||||||
|
exit_action = QAction('退出(&X)', self)
|
||||||
|
exit_action.setShortcut('Ctrl+Q')
|
||||||
|
exit_action.setStatusTip('退出应用程序')
|
||||||
|
exit_action.triggered.connect(self.close)
|
||||||
|
file_menu.addAction(exit_action)
|
||||||
|
|
||||||
|
# 编辑菜单
|
||||||
|
edit_menu = menubar.addMenu('编辑(&E)')
|
||||||
|
|
||||||
|
# 搜索
|
||||||
|
search_action = QAction('搜索项目(&S)', self)
|
||||||
|
search_action.setShortcut('Ctrl+F')
|
||||||
|
search_action.setStatusTip('搜索项目')
|
||||||
|
search_action.triggered.connect(self.focus_search)
|
||||||
|
edit_menu.addAction(search_action)
|
||||||
|
|
||||||
|
# 视图菜单
|
||||||
|
view_menu = menubar.addMenu('视图(&V)')
|
||||||
|
|
||||||
|
# 网格视图
|
||||||
|
grid_action = QAction('网格视图(&G)', self)
|
||||||
|
grid_action.setCheckable(True)
|
||||||
|
grid_action.setChecked(True)
|
||||||
|
grid_action.triggered.connect(lambda: self.project_area.set_view_mode('grid'))
|
||||||
|
view_menu.addAction(grid_action)
|
||||||
|
|
||||||
|
# 列表视图
|
||||||
|
list_action = QAction('列表视图(&L)', self)
|
||||||
|
list_action.setCheckable(True)
|
||||||
|
list_action.triggered.connect(lambda: self.project_area.set_view_mode('list'))
|
||||||
|
view_menu.addAction(list_action)
|
||||||
|
|
||||||
|
# 创建视图模式组
|
||||||
|
view_group = QActionGroup(self)
|
||||||
|
view_group.addAction(grid_action)
|
||||||
|
view_group.addAction(list_action)
|
||||||
|
|
||||||
|
# 帮助菜单
|
||||||
|
help_menu = menubar.addMenu('帮助(&H)')
|
||||||
|
|
||||||
|
# 关于
|
||||||
|
about_action = QAction('关于(&A)', self)
|
||||||
|
about_action.triggered.connect(self.show_about)
|
||||||
|
help_menu.addAction(about_action)
|
||||||
|
|
||||||
|
def connect_signals(self):
|
||||||
|
"""连接信号"""
|
||||||
|
# 侧边栏信号
|
||||||
|
self.sidebar.filter_changed.connect(self.on_filter_changed)
|
||||||
|
self.sidebar.navigation_changed.connect(self.on_navigation_changed) # 新增导航变化信号
|
||||||
|
self.sidebar.create_project_requested.connect(self.show_create_project_dialog)
|
||||||
|
self.sidebar.import_project_requested.connect(self.show_import_project_dialog)
|
||||||
|
|
||||||
|
# 项目区域信号
|
||||||
|
self.project_area.search_changed.connect(self.on_search_changed)
|
||||||
|
self.project_area.create_project_requested.connect(self.show_create_project_dialog)
|
||||||
|
self.project_area.import_project_requested.connect(self.show_import_project_dialog)
|
||||||
|
|
||||||
|
# 项目设置页面信号
|
||||||
|
self.project_settings_page.settings_changed.connect(self.on_project_settings_changed)
|
||||||
|
|
||||||
|
# 项目管理器信号
|
||||||
|
self.project_manager.projects_changed.connect(self.update_project_count)
|
||||||
|
self.project_manager.projects_changed.connect(self.refresh_projects)
|
||||||
|
|
||||||
|
def center_window(self):
|
||||||
|
"""窗口居中"""
|
||||||
|
screen = QApplication.desktop().screenGeometry()
|
||||||
|
size = self.geometry()
|
||||||
|
self.move(
|
||||||
|
(screen.width() - size.width()) // 2,
|
||||||
|
(screen.height() - size.height()) // 2
|
||||||
|
)
|
||||||
|
|
||||||
|
def resizeEvent(self, event):
|
||||||
|
"""窗口大小变化事件"""
|
||||||
|
super().resizeEvent(event)
|
||||||
|
|
||||||
|
# 检查是否需要切换到紧凑模式
|
||||||
|
width = event.size().width()
|
||||||
|
should_be_compact = width < 1200
|
||||||
|
|
||||||
|
if should_be_compact != self.is_compact_mode:
|
||||||
|
self.is_compact_mode = should_be_compact
|
||||||
|
self.update_layout_mode()
|
||||||
|
|
||||||
|
def update_layout_mode(self):
|
||||||
|
"""更新布局模式"""
|
||||||
|
if self.is_compact_mode:
|
||||||
|
# 紧凑模式:缩小侧边栏
|
||||||
|
self.sidebar.setFixedWidth(240)
|
||||||
|
else:
|
||||||
|
# 正常模式:标准侧边栏宽度
|
||||||
|
self.sidebar.setFixedWidth(280)
|
||||||
|
|
||||||
|
def on_filter_changed(self, filter_type: str):
|
||||||
|
"""过滤器改变"""
|
||||||
|
self.current_filter = filter_type
|
||||||
|
self.refresh_projects()
|
||||||
|
|
||||||
|
def on_navigation_changed(self, section: str, item_name: str, filter_type: str):
|
||||||
|
"""导航变化处理"""
|
||||||
|
# 根据filter_type决定显示哪个页面
|
||||||
|
if filter_type == "project_settings":
|
||||||
|
# 切换到项目设置页面
|
||||||
|
self.stacked_widget.setCurrentIndex(1)
|
||||||
|
else:
|
||||||
|
# 切换到项目区域
|
||||||
|
self.stacked_widget.setCurrentIndex(0)
|
||||||
|
# 更新项目区域的面包屑导航和标题
|
||||||
|
self.project_area.update_navigation(section, item_name)
|
||||||
|
|
||||||
|
def on_search_changed(self, search_text: str):
|
||||||
|
"""搜索改变"""
|
||||||
|
self.current_search = search_text
|
||||||
|
self.refresh_projects()
|
||||||
|
|
||||||
|
def on_project_settings_changed(self):
|
||||||
|
"""项目设置变化处理"""
|
||||||
|
# 设置已更改,可以在这里处理相关逻辑
|
||||||
|
# 例如:更新创建项目对话框的默认位置
|
||||||
|
print("项目设置已更新")
|
||||||
|
|
||||||
|
def refresh_projects(self):
|
||||||
|
"""刷新项目显示"""
|
||||||
|
if self.current_search:
|
||||||
|
projects = self.project_manager.search_projects(self.current_search)
|
||||||
|
else:
|
||||||
|
projects = self.project_manager.get_projects_by_type(self.current_filter)
|
||||||
|
|
||||||
|
self.project_area.update_projects(projects)
|
||||||
|
|
||||||
|
def update_project_count(self):
|
||||||
|
"""更新项目数量"""
|
||||||
|
count = len(self.project_manager.get_all_projects())
|
||||||
|
# 如果状态栏存在,更新项目数量显示
|
||||||
|
if hasattr(self, 'project_count_label'):
|
||||||
|
self.project_count_label.setText(f"项目总数: {count}")
|
||||||
|
# 可以在这里添加其他更新逻辑,比如更新窗口标题
|
||||||
|
self.setWindowTitle(f"MetaCore - 项目管理平台 ({count} 个项目)")
|
||||||
|
|
||||||
|
def show_create_project_dialog(self):
|
||||||
|
"""显示创建项目对话框"""
|
||||||
|
dialog = CreateProjectDialog(self.project_manager, self.project_settings_page, self)
|
||||||
|
if dialog.exec_() == QDialog.Accepted:
|
||||||
|
self.refresh_projects()
|
||||||
|
|
||||||
|
def show_import_project_dialog(self):
|
||||||
|
"""显示导入项目对话框"""
|
||||||
|
dialog = ImportProjectDialog(self.project_manager, self.project_settings_page, self)
|
||||||
|
if dialog.exec_() == QDialog.Accepted:
|
||||||
|
self.refresh_projects()
|
||||||
|
|
||||||
|
def focus_search(self):
|
||||||
|
"""聚焦搜索框"""
|
||||||
|
self.project_area.focus_search()
|
||||||
|
|
||||||
|
def show_about(self):
|
||||||
|
"""显示关于对话框"""
|
||||||
|
QMessageBox.about(self, "关于 MetaCore",
|
||||||
|
"MetaCore 项目管理平台\n\n"
|
||||||
|
"版本: 1.0.0\n"
|
||||||
|
"基于 PyQt5 开发\n\n"
|
||||||
|
"© 2024 MetaCore Team")
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
"""关闭事件"""
|
||||||
|
reply = QMessageBox.question(self, '确认退出',
|
||||||
|
'确定要退出 MetaCore 吗?',
|
||||||
|
QMessageBox.Yes | QMessageBox.No,
|
||||||
|
QMessageBox.No)
|
||||||
|
|
||||||
|
if reply == QMessageBox.Yes:
|
||||||
|
# 保存数据
|
||||||
|
self.project_manager.save_projects()
|
||||||
|
event.accept()
|
||||||
|
else:
|
||||||
|
event.ignore()
|
||||||
441
MetaCore/ui/project_area.py
Normal file
@ -0,0 +1,441 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
项目区域组件
|
||||||
|
"""
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from MetaCore.data.project_manager import ProjectManager, Project
|
||||||
|
from MetaCore.ui.icon_manager import IconManager
|
||||||
|
from MetaCore.ui.project_card import ProjectCard
|
||||||
|
|
||||||
|
class ProjectArea(QWidget):
|
||||||
|
"""项目区域组件"""
|
||||||
|
|
||||||
|
# 信号定义
|
||||||
|
search_changed = pyqtSignal(str)
|
||||||
|
create_project_requested = pyqtSignal()
|
||||||
|
import_project_requested = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, project_manager: ProjectManager):
|
||||||
|
super().__init__()
|
||||||
|
self.project_manager = project_manager
|
||||||
|
self.view_mode = "grid" # grid 或 list
|
||||||
|
self.projects = []
|
||||||
|
|
||||||
|
self.init_ui()
|
||||||
|
self.connect_signals()
|
||||||
|
|
||||||
|
# 初始加载项目
|
||||||
|
self.update_projects(self.project_manager.get_all_projects())
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
"""初始化UI"""
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.setSpacing(0)
|
||||||
|
|
||||||
|
# 顶部工具栏
|
||||||
|
self.create_toolbar(layout)
|
||||||
|
|
||||||
|
# 搜索和过滤区域
|
||||||
|
self.create_search_filter_area(layout)
|
||||||
|
|
||||||
|
# 项目显示区域
|
||||||
|
self.create_project_display_area(layout)
|
||||||
|
|
||||||
|
def create_toolbar(self, layout):
|
||||||
|
"""创建顶部工具栏"""
|
||||||
|
toolbar_widget = QWidget()
|
||||||
|
toolbar_widget.setObjectName("toolbar")
|
||||||
|
toolbar_layout = QHBoxLayout(toolbar_widget)
|
||||||
|
toolbar_layout.setContentsMargins(30, 20, 30, 10)
|
||||||
|
|
||||||
|
# 面包屑导航容器
|
||||||
|
breadcrumb_container = QWidget()
|
||||||
|
breadcrumb_container.setObjectName("breadcrumbContainer")
|
||||||
|
breadcrumb_layout = QHBoxLayout(breadcrumb_container)
|
||||||
|
breadcrumb_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
breadcrumb_layout.setSpacing(0)
|
||||||
|
|
||||||
|
self.home_label = QLabel("我的项目")
|
||||||
|
self.home_label.setObjectName("breadcrumbItem")
|
||||||
|
breadcrumb_layout.addWidget(self.home_label)
|
||||||
|
|
||||||
|
self.separator_label = QLabel("/")
|
||||||
|
self.separator_label.setObjectName("breadcrumbSeparator")
|
||||||
|
breadcrumb_layout.addWidget(self.separator_label)
|
||||||
|
|
||||||
|
self.current_label = QLabel("项目概述")
|
||||||
|
self.current_label.setObjectName("breadcrumbCurrent")
|
||||||
|
breadcrumb_layout.addWidget(self.current_label)
|
||||||
|
|
||||||
|
breadcrumb_layout.addStretch()
|
||||||
|
|
||||||
|
toolbar_layout.addWidget(breadcrumb_container)
|
||||||
|
|
||||||
|
# 右侧操作按钮
|
||||||
|
actions_layout = QHBoxLayout()
|
||||||
|
|
||||||
|
# 导入项目按钮
|
||||||
|
self.import_project_btn = QPushButton("导入项目")
|
||||||
|
if IconManager.icon_exists('import'):
|
||||||
|
self.import_project_btn.setIcon(IconManager.get_icon('import'))
|
||||||
|
else:
|
||||||
|
self.import_project_btn = QPushButton("↑ 导入项目")
|
||||||
|
self.import_project_btn.setObjectName("importBtn")
|
||||||
|
self.import_project_btn.clicked.connect(self.import_project_requested.emit)
|
||||||
|
actions_layout.addWidget(self.import_project_btn)
|
||||||
|
|
||||||
|
# 创建项目按钮
|
||||||
|
self.create_project_btn = QPushButton("创建")
|
||||||
|
if IconManager.icon_exists('create'):
|
||||||
|
self.create_project_btn.setIcon(IconManager.get_icon('create'))
|
||||||
|
else:
|
||||||
|
self.create_project_btn = QPushButton("+ 创建")
|
||||||
|
self.create_project_btn.setObjectName("primaryBtn")
|
||||||
|
self.create_project_btn.clicked.connect(self.create_project_requested.emit)
|
||||||
|
actions_layout.addWidget(self.create_project_btn)
|
||||||
|
|
||||||
|
toolbar_layout.addLayout(actions_layout)
|
||||||
|
layout.addWidget(toolbar_widget)
|
||||||
|
|
||||||
|
def create_search_filter_area(self, layout):
|
||||||
|
"""创建搜索和过滤区域"""
|
||||||
|
# 内容头部 - 调整高度更紧凑
|
||||||
|
content_header = QWidget()
|
||||||
|
content_header.setObjectName("contentHeader")
|
||||||
|
header_layout = QHBoxLayout(content_header)
|
||||||
|
header_layout.setContentsMargins(30, 12, 30, 12) # 减少上下边距:20->12
|
||||||
|
|
||||||
|
# 标题
|
||||||
|
self.title_label = QLabel("项目概述")
|
||||||
|
self.title_label.setObjectName("contentTitle")
|
||||||
|
header_layout.addWidget(self.title_label)
|
||||||
|
|
||||||
|
header_layout.addStretch()
|
||||||
|
|
||||||
|
# 搜索输入框
|
||||||
|
self.search_input = QLineEdit()
|
||||||
|
self.search_input.setObjectName("searchInput")
|
||||||
|
self.search_input.setPlaceholderText("搜索项目...")
|
||||||
|
self.search_input.textChanged.connect(self.search_changed.emit)
|
||||||
|
self.search_input.setMaximumWidth(250) # 限制最大宽度
|
||||||
|
header_layout.addWidget(self.search_input)
|
||||||
|
|
||||||
|
# 视图控制按钮
|
||||||
|
view_controls = QHBoxLayout()
|
||||||
|
|
||||||
|
# 网格视图按钮
|
||||||
|
self.grid_view_btn = QPushButton()
|
||||||
|
if IconManager.icon_exists('grid_view'):
|
||||||
|
self.grid_view_btn.setIcon(IconManager.get_icon('grid_view', QSize(16, 16)))
|
||||||
|
self.grid_view_btn.setIconSize(QSize(16, 16))
|
||||||
|
else:
|
||||||
|
self.grid_view_btn.setText("⊞")
|
||||||
|
self.grid_view_btn.setObjectName("viewBtn")
|
||||||
|
self.grid_view_btn.setCheckable(True)
|
||||||
|
self.grid_view_btn.setChecked(True)
|
||||||
|
self.grid_view_btn.setToolTip("网格视图")
|
||||||
|
self.grid_view_btn.clicked.connect(lambda: self.set_view_mode("grid"))
|
||||||
|
view_controls.addWidget(self.grid_view_btn)
|
||||||
|
|
||||||
|
# 列表视图按钮
|
||||||
|
self.list_view_btn = QPushButton()
|
||||||
|
if IconManager.icon_exists('list_view'):
|
||||||
|
self.list_view_btn.setIcon(IconManager.get_icon('list_view', QSize(16, 16)))
|
||||||
|
self.list_view_btn.setIconSize(QSize(16, 16))
|
||||||
|
else:
|
||||||
|
self.list_view_btn.setText("☰")
|
||||||
|
self.list_view_btn.setObjectName("viewBtn")
|
||||||
|
self.list_view_btn.setCheckable(True)
|
||||||
|
self.list_view_btn.setToolTip("列表视图")
|
||||||
|
self.list_view_btn.clicked.connect(lambda: self.set_view_mode("list"))
|
||||||
|
view_controls.addWidget(self.list_view_btn)
|
||||||
|
|
||||||
|
# # 过滤按钮
|
||||||
|
# filter_btn = QPushButton("▼")
|
||||||
|
# filter_btn.setObjectName("viewBtn")
|
||||||
|
# filter_btn.setToolTip("过滤选项")
|
||||||
|
# view_controls.addWidget(filter_btn)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
header_layout.addLayout(view_controls)
|
||||||
|
layout.addWidget(content_header)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def create_project_display_area(self, layout):
|
||||||
|
"""创建项目显示区域"""
|
||||||
|
# 滚动区域
|
||||||
|
self.scroll_area = QScrollArea()
|
||||||
|
self.scroll_area.setWidgetResizable(True)
|
||||||
|
self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
|
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||||
|
|
||||||
|
# 项目容器
|
||||||
|
self.projects_container = QWidget()
|
||||||
|
self.projects_container.setObjectName("projectsContainer")
|
||||||
|
|
||||||
|
# 网格布局
|
||||||
|
self.projects_layout = QGridLayout(self.projects_container)
|
||||||
|
self.projects_layout.setContentsMargins(30, 20, 30, 30)
|
||||||
|
self.projects_layout.setSpacing(20)
|
||||||
|
self.projects_layout.setAlignment(Qt.AlignTop) # 设置顶部对齐
|
||||||
|
|
||||||
|
# 响应式列数
|
||||||
|
self.grid_columns = 4 # 默认列数
|
||||||
|
self.update_grid_columns()
|
||||||
|
|
||||||
|
self.scroll_area.setWidget(self.projects_container)
|
||||||
|
layout.addWidget(self.scroll_area)
|
||||||
|
|
||||||
|
def connect_signals(self):
|
||||||
|
"""连接信号"""
|
||||||
|
# 项目管理器信号
|
||||||
|
self.project_manager.project_added.connect(self.on_project_added)
|
||||||
|
self.project_manager.project_removed.connect(self.on_project_removed)
|
||||||
|
self.project_manager.project_updated.connect(self.on_project_updated)
|
||||||
|
|
||||||
|
def update_projects(self, projects: List[Project]):
|
||||||
|
"""更新项目显示"""
|
||||||
|
self.projects = projects
|
||||||
|
self.refresh_project_display()
|
||||||
|
|
||||||
|
def update_navigation(self, section: str, item_name: str):
|
||||||
|
"""更新导航显示"""
|
||||||
|
# 更新面包屑导航
|
||||||
|
self.home_label.setText(section)
|
||||||
|
self.current_label.setText(item_name)
|
||||||
|
|
||||||
|
# 更新主标题
|
||||||
|
# 根据不同的导航项设置不同的标题
|
||||||
|
title_mapping = {
|
||||||
|
"项目概述": "项目概述",
|
||||||
|
"项目管理": "项目管理",
|
||||||
|
"资源分类": "资源分类管理",
|
||||||
|
"资源管理": "资源管理",
|
||||||
|
"系统设置": "系统设置",
|
||||||
|
}
|
||||||
|
|
||||||
|
display_title = title_mapping.get(item_name, item_name)
|
||||||
|
self.title_label.setText(display_title)
|
||||||
|
|
||||||
|
def refresh_project_display(self):
|
||||||
|
"""刷新项目显示"""
|
||||||
|
# 清除现有项目卡片
|
||||||
|
for i in reversed(range(self.projects_layout.count())):
|
||||||
|
child = self.projects_layout.itemAt(i).widget()
|
||||||
|
if child:
|
||||||
|
child.setParent(None)
|
||||||
|
|
||||||
|
if not self.projects:
|
||||||
|
# 显示空状态
|
||||||
|
self.show_empty_state()
|
||||||
|
else:
|
||||||
|
# 添加项目卡片
|
||||||
|
if self.view_mode == "grid":
|
||||||
|
self.show_grid_view()
|
||||||
|
else:
|
||||||
|
self.show_list_view()
|
||||||
|
|
||||||
|
# 强制更新布局和几何信息
|
||||||
|
self._update_layout_geometry()
|
||||||
|
|
||||||
|
def show_grid_view(self):
|
||||||
|
"""显示网格视图"""
|
||||||
|
# 使用响应式列数
|
||||||
|
columns = self.grid_columns
|
||||||
|
|
||||||
|
for i, project in enumerate(self.projects):
|
||||||
|
row = i // columns
|
||||||
|
col = i % columns
|
||||||
|
|
||||||
|
project_card = ProjectCard(project, self.project_manager)
|
||||||
|
self.projects_layout.addWidget(project_card, row, col, Qt.AlignTop) # 顶部对齐
|
||||||
|
|
||||||
|
def show_list_view(self):
|
||||||
|
"""显示列表视图"""
|
||||||
|
for i, project in enumerate(self.projects):
|
||||||
|
project_card = ProjectCard(project, self.project_manager, view_mode="list")
|
||||||
|
self.projects_layout.addWidget(project_card, i, 0, Qt.AlignTop) # 顶部对齐
|
||||||
|
|
||||||
|
def show_empty_state(self):
|
||||||
|
"""显示空状态"""
|
||||||
|
empty_widget = QWidget()
|
||||||
|
empty_layout = QVBoxLayout(empty_widget)
|
||||||
|
empty_layout.setAlignment(Qt.AlignCenter)
|
||||||
|
|
||||||
|
# 空状态图标
|
||||||
|
empty_icon = QLabel("📁")
|
||||||
|
empty_icon.setStyleSheet("font-size: 48px; color: #666666;")
|
||||||
|
empty_icon.setAlignment(Qt.AlignCenter)
|
||||||
|
empty_layout.addWidget(empty_icon)
|
||||||
|
|
||||||
|
# 空状态文字
|
||||||
|
empty_text = QLabel("没有找到匹配的项目")
|
||||||
|
empty_text.setStyleSheet("font-size: 16px; color: #888888; margin-top: 10px;")
|
||||||
|
empty_text.setAlignment(Qt.AlignCenter)
|
||||||
|
empty_layout.addWidget(empty_text)
|
||||||
|
|
||||||
|
self.projects_layout.addWidget(empty_widget, 0, 0, 1, 4)
|
||||||
|
|
||||||
|
def set_view_mode(self, mode: str):
|
||||||
|
"""设置视图模式"""
|
||||||
|
self.view_mode = mode
|
||||||
|
|
||||||
|
# 更新按钮状态
|
||||||
|
self.grid_view_btn.setChecked(mode == "grid")
|
||||||
|
self.list_view_btn.setChecked(mode == "list")
|
||||||
|
|
||||||
|
# 刷新显示
|
||||||
|
self.refresh_project_display()
|
||||||
|
|
||||||
|
def focus_search(self):
|
||||||
|
"""聚焦搜索框"""
|
||||||
|
self.search_input.setFocus()
|
||||||
|
|
||||||
|
def on_project_added(self, project: Project):
|
||||||
|
"""项目添加事件"""
|
||||||
|
# 如果当前显示的是项目概述或项目管理,则添加新项目
|
||||||
|
if hasattr(self, 'current_filter') and self.current_filter in ["overview", "management"]:
|
||||||
|
self.projects.insert(0, project)
|
||||||
|
self.refresh_project_display()
|
||||||
|
|
||||||
|
def on_project_removed(self, project_id: int):
|
||||||
|
"""项目删除事件"""
|
||||||
|
self.projects = [p for p in self.projects if p.id != project_id]
|
||||||
|
self.refresh_project_display()
|
||||||
|
|
||||||
|
def on_project_updated(self, project: Project):
|
||||||
|
"""项目更新事件"""
|
||||||
|
for i, p in enumerate(self.projects):
|
||||||
|
if p.id == project.id:
|
||||||
|
self.projects[i] = project
|
||||||
|
break
|
||||||
|
self.refresh_project_display()
|
||||||
|
|
||||||
|
def update_grid_columns(self):
|
||||||
|
"""更新网格列数 - 针对固定大小卡片优化"""
|
||||||
|
# 获取可用宽度,尝试多种方式确保准确性
|
||||||
|
width = 0
|
||||||
|
if hasattr(self, 'scroll_area') and self.scroll_area.width() > 0:
|
||||||
|
# 优先使用滚动区域的宽度
|
||||||
|
width = self.scroll_area.viewport().width()
|
||||||
|
elif hasattr(self, 'projects_container') and self.projects_container.width() > 0:
|
||||||
|
# 备选:使用项目容器的宽度
|
||||||
|
width = self.projects_container.width()
|
||||||
|
elif hasattr(self, 'scroll_area'):
|
||||||
|
# 最后备选:使用滚动区域的宽度
|
||||||
|
width = self.scroll_area.width()
|
||||||
|
|
||||||
|
# 确保宽度有效
|
||||||
|
if width <= 0:
|
||||||
|
# 如果仍然无效,使用默认列数
|
||||||
|
if not hasattr(self, 'grid_columns'):
|
||||||
|
self.grid_columns = 1
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 固定卡片大小的计算(280px宽度,20px间距)
|
||||||
|
available_width = width - 60 # 减去左右边距
|
||||||
|
|
||||||
|
# 确保可用宽度为正数
|
||||||
|
if available_width <= 0:
|
||||||
|
available_width = width - 20 # 使用更小的边距
|
||||||
|
|
||||||
|
# 固定卡片宽度和间距
|
||||||
|
card_width = 280 # 固定卡片宽度
|
||||||
|
spacing = 20 # 卡片间距
|
||||||
|
|
||||||
|
# 计算能容纳的列数
|
||||||
|
if available_width < card_width:
|
||||||
|
columns = 1
|
||||||
|
else:
|
||||||
|
# 计算能容纳的列数:(可用宽度 + 间距) / (卡片宽度 + 间距)
|
||||||
|
columns = (available_width + spacing) // (card_width + spacing)
|
||||||
|
columns = max(1, columns)
|
||||||
|
|
||||||
|
# 限制最大列数,避免过多列
|
||||||
|
columns = min(columns, 6)
|
||||||
|
|
||||||
|
# 检查列数是否发生变化
|
||||||
|
old_columns = getattr(self, 'grid_columns', 4)
|
||||||
|
if old_columns != columns:
|
||||||
|
self.grid_columns = columns
|
||||||
|
return True # 返回True表示列数发生了变化
|
||||||
|
else:
|
||||||
|
self.grid_columns = columns
|
||||||
|
return False
|
||||||
|
|
||||||
|
def resizeEvent(self, event):
|
||||||
|
"""窗口大小变化事件"""
|
||||||
|
super().resizeEvent(event)
|
||||||
|
|
||||||
|
# 立即处理缩小情况,延迟处理放大情况
|
||||||
|
if hasattr(self, '_last_width'):
|
||||||
|
current_width = event.size().width()
|
||||||
|
is_shrinking = current_width < self._last_width
|
||||||
|
|
||||||
|
if is_shrinking:
|
||||||
|
# 缩小时立即处理,确保响应性
|
||||||
|
self._handle_resize()
|
||||||
|
self._last_width = current_width
|
||||||
|
return
|
||||||
|
|
||||||
|
# 延迟处理,避免频繁调用(主要用于放大情况)
|
||||||
|
if hasattr(self, '_resize_timer'):
|
||||||
|
self._resize_timer.stop()
|
||||||
|
|
||||||
|
self._resize_timer = QTimer()
|
||||||
|
self._resize_timer.setSingleShot(True)
|
||||||
|
self._resize_timer.timeout.connect(self._handle_resize)
|
||||||
|
self._resize_timer.start(50) # 减少延迟:100ms->50ms
|
||||||
|
|
||||||
|
# 记录当前宽度
|
||||||
|
self._last_width = event.size().width()
|
||||||
|
|
||||||
|
def _handle_resize(self):
|
||||||
|
"""处理窗口大小变化"""
|
||||||
|
if hasattr(self, 'projects') and self.view_mode == "grid":
|
||||||
|
# 强制更新滚动区域几何信息
|
||||||
|
if hasattr(self, 'scroll_area'):
|
||||||
|
self.scroll_area.updateGeometry()
|
||||||
|
QApplication.processEvents()
|
||||||
|
|
||||||
|
# 更新列数
|
||||||
|
columns_changed = self.update_grid_columns()
|
||||||
|
|
||||||
|
if columns_changed:
|
||||||
|
# 列数变化,完全重新布局
|
||||||
|
self.refresh_project_display()
|
||||||
|
else:
|
||||||
|
# 列数没变,但仍需要更新布局以适应新的宽度
|
||||||
|
self._update_layout_geometry()
|
||||||
|
# 强制重新计算卡片大小
|
||||||
|
self._update_card_sizes()
|
||||||
|
|
||||||
|
def _update_layout_geometry(self):
|
||||||
|
"""更新布局几何信息"""
|
||||||
|
if hasattr(self, 'projects_container'):
|
||||||
|
# 强制更新布局
|
||||||
|
self.projects_container.updateGeometry()
|
||||||
|
self.projects_layout.update()
|
||||||
|
|
||||||
|
# 确保滚动区域正确更新
|
||||||
|
if hasattr(self, 'scroll_area'):
|
||||||
|
self.scroll_area.updateGeometry()
|
||||||
|
|
||||||
|
# 强制重新计算滚动区域大小
|
||||||
|
QApplication.processEvents()
|
||||||
|
self.scroll_area.ensureVisible(0, 0)
|
||||||
|
|
||||||
|
def _update_card_sizes(self):
|
||||||
|
"""更新项目卡片大小 - 固定大小卡片无需动态调整"""
|
||||||
|
# 由于卡片现在是固定大小(280x240),不再需要动态调整
|
||||||
|
# 这个方法保留为空,以保持接口兼容性
|
||||||
|
pass
|
||||||
974
MetaCore/ui/project_card.py
Normal file
@ -0,0 +1,974 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
项目卡片组件
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import platform
|
||||||
|
from pathlib import Path
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
|
||||||
|
from MetaCore.data.project_manager import ProjectManager, Project
|
||||||
|
from MetaCore.ui.icon_manager import IconManager
|
||||||
|
from MetaCore.ui.project_settings_page import ProjectSettingsPage
|
||||||
|
class ImageDisplayWidget(QWidget):
|
||||||
|
"""
|
||||||
|
一个专门用于显示带圆角图片的控件。
|
||||||
|
它会自动将图片按比例缩放以覆盖整个区域,并进行圆角裁剪。
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.pixmap = QPixmap()
|
||||||
|
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
|
|
||||||
|
def setPixmap(self, pixmap):
|
||||||
|
self.pixmap = pixmap
|
||||||
|
self.update() # 触发重绘
|
||||||
|
|
||||||
|
# 这是在 ImageDisplayWidget 类内部的方法
|
||||||
|
def paintEvent(self, event):
|
||||||
|
if self.pixmap.isNull():
|
||||||
|
return
|
||||||
|
|
||||||
|
# 导入 QSize 以便创建新的尺寸对象
|
||||||
|
from PyQt5.QtCore import QSize
|
||||||
|
import math
|
||||||
|
|
||||||
|
target_rect = self.rect()
|
||||||
|
radius = 12.0
|
||||||
|
|
||||||
|
# “过缩放”逻辑保持不变,我们仍然需要一张比控件大的图片
|
||||||
|
overscale_factor = 1.05
|
||||||
|
original_size = target_rect.size()
|
||||||
|
larger_width = math.ceil(original_size.width() * overscale_factor)
|
||||||
|
larger_height = math.ceil(original_size.height() * overscale_factor)
|
||||||
|
larger_target_size = QSize(larger_width, larger_height)
|
||||||
|
|
||||||
|
scaled_pixmap = self.pixmap.scaled(larger_target_size, Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation)
|
||||||
|
|
||||||
|
# --- 核心修正点在这里 ---
|
||||||
|
|
||||||
|
# 1. 计算绘制的起始坐标(x, y),以使 scaled_pixmap 的中心与控件中心对齐
|
||||||
|
# 由于 scaled_pixmap 比控件大,所以 x 和 y 通常是负数,这是正确的
|
||||||
|
draw_x = (target_rect.width() - scaled_pixmap.width()) / 2
|
||||||
|
draw_y = (target_rect.height() - scaled_pixmap.height()) / 2
|
||||||
|
|
||||||
|
# 2. 使用QPainter进行绘制
|
||||||
|
painter = QPainter(self)
|
||||||
|
painter.setRenderHint(QPainter.Antialiasing)
|
||||||
|
|
||||||
|
# 3. 创建并设置圆角裁剪路径 (逻辑不变)
|
||||||
|
path = QPainterPath()
|
||||||
|
path.addRoundedRect(QRectF(target_rect), radius, radius)
|
||||||
|
painter.setClipPath(path)
|
||||||
|
|
||||||
|
# 4. 使用最简单的 drawPixmap 版本,直接在计算好的坐标点绘制
|
||||||
|
# 这个版本不会进行任何额外的缩放,完美解决了偏移问题
|
||||||
|
painter.drawPixmap(int(draw_x), int(draw_y), scaled_pixmap)
|
||||||
|
|
||||||
|
# -----------------------
|
||||||
|
class ProjectCard(QWidget):
|
||||||
|
"""项目卡片组件"""
|
||||||
|
|
||||||
|
def __init__(self, project: Project, project_manager: ProjectManager, view_mode: str = "grid"):
|
||||||
|
super().__init__()
|
||||||
|
self.project = project
|
||||||
|
self.project_manager = project_manager
|
||||||
|
self.view_mode = view_mode
|
||||||
|
self.project_settings_page = ProjectSettingsPage()
|
||||||
|
|
||||||
|
# 设置卡片对象名称和属性
|
||||||
|
self.setObjectName("projectCard")
|
||||||
|
self.setProperty("status", project.status)
|
||||||
|
self.setAttribute(Qt.WA_StyledBackground) # 关键:启用样式背景继承
|
||||||
|
|
||||||
|
# 设置尺寸和策略
|
||||||
|
if view_mode == "grid":
|
||||||
|
self.setFixedSize(280, 240)
|
||||||
|
else:
|
||||||
|
self.setFixedHeight(80)
|
||||||
|
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
|
||||||
|
|
||||||
|
self.init_ui()
|
||||||
|
self.connect_signals()
|
||||||
|
|
||||||
|
# 确保样式正确应用
|
||||||
|
self.update_style()
|
||||||
|
|
||||||
|
def update_style(self):
|
||||||
|
"""强制刷新样式"""
|
||||||
|
self.style().unpolish(self)
|
||||||
|
self.style().polish(self)
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
"""初始化UI"""
|
||||||
|
if self.view_mode == "grid":
|
||||||
|
self.create_grid_layout()
|
||||||
|
else:
|
||||||
|
self.create_list_layout()
|
||||||
|
|
||||||
|
def create_grid_layout(self):
|
||||||
|
"""创建网格布局"""
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.setSpacing(0)
|
||||||
|
|
||||||
|
# 项目头部
|
||||||
|
self.create_project_header(layout)
|
||||||
|
|
||||||
|
# 项目图片
|
||||||
|
self.create_project_image(layout)
|
||||||
|
|
||||||
|
# 项目底部
|
||||||
|
self.create_project_footer(layout)
|
||||||
|
|
||||||
|
def create_list_layout(self):
|
||||||
|
"""创建列表布局"""
|
||||||
|
layout = QHBoxLayout(self)
|
||||||
|
layout.setContentsMargins(16, 12, 16, 12)
|
||||||
|
layout.setSpacing(16)
|
||||||
|
|
||||||
|
# 项目图标 - 使用优化的图标显示
|
||||||
|
self.create_list_project_icon(layout)
|
||||||
|
|
||||||
|
# 项目信息
|
||||||
|
info_layout = QVBoxLayout()
|
||||||
|
info_layout.setSpacing(4)
|
||||||
|
|
||||||
|
# 项目名称
|
||||||
|
title_layout = QHBoxLayout()
|
||||||
|
title_label = QLabel(self.project.title)
|
||||||
|
title_label.setObjectName("projectTitle")
|
||||||
|
title_layout.addWidget(title_label)
|
||||||
|
|
||||||
|
title_layout.addStretch()
|
||||||
|
info_layout.addLayout(title_layout)
|
||||||
|
|
||||||
|
# 项目日期
|
||||||
|
date_label = QLabel(self.project.date)
|
||||||
|
date_label.setObjectName("projectDate")
|
||||||
|
info_layout.addWidget(date_label)
|
||||||
|
|
||||||
|
layout.addLayout(info_layout)
|
||||||
|
layout.addStretch()
|
||||||
|
|
||||||
|
# 菜单按钮
|
||||||
|
self.create_menu_button(layout)
|
||||||
|
|
||||||
|
def create_project_header(self, layout):
|
||||||
|
"""创建项目头部"""
|
||||||
|
header_widget = QWidget()
|
||||||
|
header_widget.setObjectName("projectHeader")
|
||||||
|
header_layout = QHBoxLayout(header_widget)
|
||||||
|
header_layout.setContentsMargins(16, 16, 16, 8)
|
||||||
|
header_layout.setSpacing(8)
|
||||||
|
|
||||||
|
# 项目标题
|
||||||
|
title_label = QLabel(self.project.title)
|
||||||
|
title_label.setObjectName("projectTitle")
|
||||||
|
title_label.setWordWrap(True)
|
||||||
|
header_layout.addWidget(title_label, 1) # 添加拉伸因子
|
||||||
|
|
||||||
|
# 右侧操作区
|
||||||
|
actions_layout = QHBoxLayout()
|
||||||
|
actions_layout.setSpacing(4)
|
||||||
|
|
||||||
|
# 根据项目状态显示不同的按钮
|
||||||
|
if self.project.status == 'pending_delete':
|
||||||
|
self.menu_btn = QPushButton("✕")
|
||||||
|
self.menu_btn.setObjectName("deleteBtn")
|
||||||
|
self.menu_btn.setFixedSize(24, 24)
|
||||||
|
self.menu_btn.clicked.connect(self.confirm_delete_project)
|
||||||
|
self.menu_btn.setToolTip("确认删除项目")
|
||||||
|
else:
|
||||||
|
self.menu_btn = QPushButton("⋯")
|
||||||
|
self.menu_btn.setObjectName("menuBtn")
|
||||||
|
self.menu_btn.setFixedSize(24, 24)
|
||||||
|
self.menu_btn.clicked.connect(self.show_context_menu)
|
||||||
|
self.menu_btn.setToolTip("项目操作菜单")
|
||||||
|
|
||||||
|
actions_layout.addWidget(self.menu_btn)
|
||||||
|
header_layout.addLayout(actions_layout)
|
||||||
|
layout.addWidget(header_widget)
|
||||||
|
|
||||||
|
def create_project_image(self, layout):
|
||||||
|
"""创建项目图片区域 - 最终版"""
|
||||||
|
import os
|
||||||
|
from PyQt5.QtWidgets import QStackedLayout # 导入 QStackedLayout
|
||||||
|
|
||||||
|
# image_container 是最外层的容器
|
||||||
|
image_container = QWidget()
|
||||||
|
image_container.setObjectName("projectImageContainer")
|
||||||
|
image_container.setContentsMargins(16, 0, 16, 0)
|
||||||
|
|
||||||
|
# image_widget 现在是堆叠布局的容器,它拥有灰色背景和圆角
|
||||||
|
image_widget = QWidget()
|
||||||
|
image_widget.setObjectName("projectImage")
|
||||||
|
|
||||||
|
# --- 使用 QStackedLayout 来切换两种状态 ---
|
||||||
|
stacked_layout = QStackedLayout(image_widget)
|
||||||
|
stacked_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
|
# 状态一:显示图片 (使用我们自定义的控件)
|
||||||
|
image_display = ImageDisplayWidget()
|
||||||
|
# 注意:这里不需要给 image_display 设置 objectName 或样式,因为它只是一个“画布”
|
||||||
|
|
||||||
|
# 状态二:显示默认图标 (使用一个标准的 QLabel)
|
||||||
|
default_icon_label = QLabel("📁")
|
||||||
|
default_icon_label.setObjectName("projectIcon") # QSS 会应用到这里
|
||||||
|
default_icon_label.setAlignment(Qt.AlignCenter)
|
||||||
|
|
||||||
|
# 将两个状态控件添加到堆叠布局中
|
||||||
|
stacked_layout.addWidget(image_display) # 索引 0
|
||||||
|
stacked_layout.addWidget(default_icon_label) # 索引 1
|
||||||
|
|
||||||
|
# --- 根据条件切换显示 ---
|
||||||
|
if hasattr(self.project, 'image') and os.path.exists(self.project.image) and os.path.isfile(self.project.image):
|
||||||
|
# 如果图片存在...
|
||||||
|
pixmap = QPixmap(self.project.image)
|
||||||
|
image_display.setPixmap(pixmap)
|
||||||
|
stacked_layout.setCurrentIndex(0) # 显示图片控件
|
||||||
|
else:
|
||||||
|
# 如果图片不存在...
|
||||||
|
stacked_layout.setCurrentIndex(1) # 显示默认图标控件
|
||||||
|
|
||||||
|
# --- 最终布局 ---
|
||||||
|
# 我们只需要一个简单的 QVBoxLayout 来容纳 image_widget
|
||||||
|
container_layout = QVBoxLayout(image_container)
|
||||||
|
container_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
container_layout.addWidget(image_widget)
|
||||||
|
|
||||||
|
layout.addWidget(image_container, 1)
|
||||||
|
|
||||||
|
def create_project_footer(self, layout):
|
||||||
|
"""创建项目底部"""
|
||||||
|
footer_widget = QWidget()
|
||||||
|
footer_widget.setObjectName("projectFooter")
|
||||||
|
footer_layout = QVBoxLayout(footer_widget)
|
||||||
|
footer_layout.setContentsMargins(16, 0, 16, 16) # 减少顶部边距
|
||||||
|
|
||||||
|
# 项目日期
|
||||||
|
date_label = QLabel(self.project.date)
|
||||||
|
date_label.setObjectName("projectDate")
|
||||||
|
date_label.setAlignment(Qt.AlignCenter)
|
||||||
|
footer_layout.addWidget(date_label)
|
||||||
|
|
||||||
|
layout.addWidget(footer_widget)
|
||||||
|
|
||||||
|
def create_menu_button(self, layout):
|
||||||
|
"""创建菜单按钮(用于列表视图)"""
|
||||||
|
self.menu_btn = QPushButton("⋮")
|
||||||
|
self.menu_btn.setObjectName("menuBtn")
|
||||||
|
self.menu_btn.setFixedSize(32, 32)
|
||||||
|
self.menu_btn.clicked.connect(self.show_context_menu)
|
||||||
|
layout.addWidget(self.menu_btn)
|
||||||
|
|
||||||
|
def create_list_project_icon(self, layout):
|
||||||
|
"""创建列表视图中的项目图标"""
|
||||||
|
import os
|
||||||
|
from PyQt5.QtWidgets import QStackedLayout
|
||||||
|
|
||||||
|
# 图标容器
|
||||||
|
icon_container = QWidget()
|
||||||
|
icon_container.setObjectName("listProjectIconContainer")
|
||||||
|
icon_container.setFixedSize(48, 48) # 列表视图中使用较小的图标
|
||||||
|
|
||||||
|
# 图标控件 - 带圆角背景
|
||||||
|
icon_widget = QWidget()
|
||||||
|
icon_widget.setObjectName("listProjectIcon")
|
||||||
|
icon_widget.setProperty("status", self.project.status) # 设置状态属性
|
||||||
|
|
||||||
|
# 使用堆叠布局来切换图片和默认图标
|
||||||
|
stacked_layout = QStackedLayout(icon_widget)
|
||||||
|
stacked_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
|
# 状态一:显示图片 (使用自定义的圆角图片控件)
|
||||||
|
image_display = ListImageDisplayWidget()
|
||||||
|
|
||||||
|
# 状态二:显示默认图标
|
||||||
|
default_icon_label = QLabel("📁")
|
||||||
|
default_icon_label.setObjectName("listProjectDefaultIcon")
|
||||||
|
default_icon_label.setAlignment(Qt.AlignCenter)
|
||||||
|
|
||||||
|
# 添加到堆叠布局
|
||||||
|
stacked_layout.addWidget(image_display) # 索引 0
|
||||||
|
stacked_layout.addWidget(default_icon_label) # 索引 1
|
||||||
|
|
||||||
|
# 根据条件切换显示
|
||||||
|
if hasattr(self.project, 'image') and self.project.image and os.path.exists(self.project.image) and os.path.isfile(self.project.image):
|
||||||
|
# 如果图片存在,显示图片
|
||||||
|
pixmap = QPixmap(self.project.image)
|
||||||
|
if not pixmap.isNull():
|
||||||
|
image_display.setPixmap(pixmap)
|
||||||
|
stacked_layout.setCurrentIndex(0)
|
||||||
|
else:
|
||||||
|
stacked_layout.setCurrentIndex(1)
|
||||||
|
else:
|
||||||
|
# 如果图片不存在,显示默认图标
|
||||||
|
stacked_layout.setCurrentIndex(1)
|
||||||
|
|
||||||
|
# 容器布局
|
||||||
|
container_layout = QVBoxLayout(icon_container)
|
||||||
|
container_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
container_layout.addWidget(icon_widget)
|
||||||
|
|
||||||
|
layout.addWidget(icon_container)
|
||||||
|
|
||||||
|
def get_type_label(self):
|
||||||
|
"""获取项目类型标签"""
|
||||||
|
type_labels = {
|
||||||
|
'industrial': '工业',
|
||||||
|
'smart': '智能',
|
||||||
|
'vr': 'VR',
|
||||||
|
'game': '游戏',
|
||||||
|
'design': '设计'
|
||||||
|
}
|
||||||
|
return type_labels.get(self.project.type, '其他')
|
||||||
|
|
||||||
|
def show_context_menu(self):
|
||||||
|
"""显示右键菜单"""
|
||||||
|
menu = QMenu(self)
|
||||||
|
|
||||||
|
# 刷新预览图
|
||||||
|
if IconManager.icon_exists("Refresh"):
|
||||||
|
refresh_action = menu.addAction(IconManager.get_icon('Refresh'), "刷新预览图")
|
||||||
|
else:
|
||||||
|
refresh_action = menu.addAction("🔄 刷新预览图")
|
||||||
|
refresh_action.triggered.connect(self.refresh_preview_image)
|
||||||
|
|
||||||
|
menu.addSeparator()
|
||||||
|
|
||||||
|
# 在资源管理器显示
|
||||||
|
if IconManager.icon_exists('folder'):
|
||||||
|
show_in_explorer_action = menu.addAction(IconManager.get_icon('folder'), "在资源管理器显示")
|
||||||
|
else:
|
||||||
|
show_in_explorer_action = menu.addAction("📁 在资源管理器显示")
|
||||||
|
show_in_explorer_action.triggered.connect(self.show_in_explorer)
|
||||||
|
|
||||||
|
menu.addSeparator()
|
||||||
|
|
||||||
|
# 删除项目
|
||||||
|
if IconManager.icon_exists('delete'):
|
||||||
|
delete_action = menu.addAction(IconManager.get_icon('delete'), "移除项目")
|
||||||
|
else:
|
||||||
|
delete_action = menu.addAction("🗑️ 移除项目")
|
||||||
|
delete_action.triggered.connect(self.delete_project)
|
||||||
|
|
||||||
|
# 显示菜单
|
||||||
|
menu.exec_(self.menu_btn.mapToGlobal(self.menu_btn.rect().bottomLeft()))
|
||||||
|
|
||||||
|
def open_project(self):
|
||||||
|
"""打开项目"""
|
||||||
|
try:
|
||||||
|
# 优先使用项目目录路径,如果不存在则使用基础路径
|
||||||
|
project_path = self.project.project_dir if self.project.project_dir else self.project.path
|
||||||
|
|
||||||
|
# 使用项目管理器的验证方法进行全面检查
|
||||||
|
is_valid, error_message = self.project_manager.validate_project_open(project_path)
|
||||||
|
if not is_valid:
|
||||||
|
QMessageBox.warning(self, "无法打开项目", f"项目无法打开: {error_message}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 验证通过,显示成功信息
|
||||||
|
# QMessageBox.information(self, "打开项目", f"正在打开项目: {self.project.title}")
|
||||||
|
# 使用question对话框提供明确的确认选项
|
||||||
|
reply = QMessageBox.question(self, "打开项目",
|
||||||
|
f"确定要打开项目: {self.project.title}?",
|
||||||
|
QMessageBox.Yes | QMessageBox.No,
|
||||||
|
QMessageBox.Yes)
|
||||||
|
|
||||||
|
if reply == QMessageBox.Yes:
|
||||||
|
# 用户确认打开项目,继续执行打开逻辑
|
||||||
|
# TODO: 在这里添加实际的项目打开逻辑
|
||||||
|
print(f"正在打开项目路径: {project_path},正在启动应用程序: {self.project.title}")
|
||||||
|
|
||||||
|
# 连接信号
|
||||||
|
self.project_manager.pycharm_started.connect(self.on_pycharm_started)
|
||||||
|
self.project_manager.project_method_called.connect(self.on_project_method_called)
|
||||||
|
|
||||||
|
# # 启动PyCharm并调用项目方法
|
||||||
|
# # 修正参数顺序:
|
||||||
|
# # 第一个参数:要在PyCharm中打开的项目路径(EG项目)
|
||||||
|
# # 第二个参数:要传递给项目方法的目标项目路径(当前项目)
|
||||||
|
success = self.project_manager.run_project_command(
|
||||||
|
self.project_settings_page.get_default_open_location(),
|
||||||
|
# "/home/tiger/文档/EG", # project_path - 要在PyCharm中打开的项目
|
||||||
|
project_path # target_project_path - 要传递给项目方法的目标项目路径
|
||||||
|
)
|
||||||
|
|
||||||
|
if not success:
|
||||||
|
QMessageBox.warning(
|
||||||
|
self,
|
||||||
|
"启动失败",
|
||||||
|
"无法启动,请检查打开项目路径。"
|
||||||
|
)
|
||||||
|
# if success:
|
||||||
|
# QMessageBox.information(
|
||||||
|
# self,
|
||||||
|
# "启动PyCharm",
|
||||||
|
# f"正在启动PyCharm并准备调用项目方法...\n目标项目: {project_path}"
|
||||||
|
# )
|
||||||
|
# else:
|
||||||
|
# QMessageBox.warning(
|
||||||
|
# self,
|
||||||
|
# "启动失败",
|
||||||
|
# "无法启动PyCharm,请检查PyCharm安装。"
|
||||||
|
# )
|
||||||
|
else:
|
||||||
|
# 用户取消操作,直接返回
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
# success = self.project_manager.launch_pycharm_and_open_project(
|
||||||
|
# "/home/tiger/文档/EG", # project_path - 要在PyCharm中打开的项目
|
||||||
|
# project_path # target_project_path - 要传递给项目方法的目标项目路径
|
||||||
|
# )
|
||||||
|
# if success:
|
||||||
|
# QMessageBox.information(
|
||||||
|
# self,
|
||||||
|
# "启动PyCharm",
|
||||||
|
# f"正在启动PyCharm并准备调用项目方法...\n目标项目: {project_path}"
|
||||||
|
# )
|
||||||
|
# else:
|
||||||
|
# QMessageBox.warning(
|
||||||
|
# self,
|
||||||
|
# "启动失败",
|
||||||
|
# "无法启动PyCharm,请检查PyCharm安装。"
|
||||||
|
# )
|
||||||
|
|
||||||
|
# self.project_manager.open_app_if_not_running(f'{project_path}/project.json', "project.json")
|
||||||
|
# self.project_manager.open_project_in_pycharm(project_path)
|
||||||
|
|
||||||
|
# except Exception as e:
|
||||||
|
# QMessageBox.critical(self, "错误", f"打开项目时发生错误:\n{str(e)}")
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "错误", f"启动PyCharm时发生错误:\n{str(e)}")
|
||||||
|
|
||||||
|
def on_pycharm_started(self):
|
||||||
|
"""PyCharm启动完成回调"""
|
||||||
|
print("PyCharm has started and is ready")
|
||||||
|
|
||||||
|
def on_project_method_called(self, target_project_path):
|
||||||
|
"""项目方法调用完成回调"""
|
||||||
|
QMessageBox.information(
|
||||||
|
self,
|
||||||
|
"操作完成",
|
||||||
|
f"已成功在PyCharm中打开项目: {target_project_path}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def show_in_explorer(self):
|
||||||
|
"""在资源管理器中显示项目目录"""
|
||||||
|
try:
|
||||||
|
# 获取项目路径并规范化
|
||||||
|
project_path_str = self.project.project_dir if self.project.project_dir else self.project.path
|
||||||
|
|
||||||
|
if not project_path_str:
|
||||||
|
QMessageBox.warning(self, "路径不存在", "项目路径为空,请检查项目配置。")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 使用pathlib处理路径
|
||||||
|
project_path = Path(project_path_str).resolve()
|
||||||
|
|
||||||
|
print(f"项目ID: {self.project.id}")
|
||||||
|
print(f"项目标题: {self.project.title}")
|
||||||
|
print(f"最终使用的路径: '{project_path}'")
|
||||||
|
print(f"路径是否存在: {project_path.exists()}")
|
||||||
|
print(f"是否为目录: {project_path.is_dir()}")
|
||||||
|
|
||||||
|
# 检查项目路径是否存在
|
||||||
|
if not project_path.exists():
|
||||||
|
QMessageBox.warning(self, "路径不存在",
|
||||||
|
f"项目路径不存在或无效:\n{project_path}\n\n请检查项目是否已被移动或删除。")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 获取操作系统类型
|
||||||
|
system = platform.system().lower()
|
||||||
|
|
||||||
|
if system == "windows":
|
||||||
|
try:
|
||||||
|
# Windows使用os.startfile,会自动使用系统默认的文件管理器
|
||||||
|
os.startfile(str(project_path))
|
||||||
|
except OSError as e:
|
||||||
|
QMessageBox.critical(self, "打开失败", f"无法打开资源管理器:\n{str(e)}")
|
||||||
|
|
||||||
|
elif system == "darwin": # macOS
|
||||||
|
if project_path.is_file():
|
||||||
|
# 如果是文件,选中该文件
|
||||||
|
subprocess.run(['open', '-R', str(project_path)], check=True)
|
||||||
|
else:
|
||||||
|
# 如果是目录,直接打开
|
||||||
|
subprocess.run(['open', str(project_path)], check=True)
|
||||||
|
|
||||||
|
else: # Linux和其他Unix系统
|
||||||
|
try:
|
||||||
|
# 首先尝试使用nautilus(GNOME文件管理器)
|
||||||
|
subprocess.run(['nautilus', str(project_path)], check=True)
|
||||||
|
except (FileNotFoundError, subprocess.CalledProcessError):
|
||||||
|
try:
|
||||||
|
# 尝试使用dolphin (KDE)
|
||||||
|
subprocess.run(['dolphin', str(project_path)], check=True)
|
||||||
|
except (FileNotFoundError, subprocess.CalledProcessError):
|
||||||
|
try:
|
||||||
|
# 尝试使用thunar (XFCE)
|
||||||
|
subprocess.run(['thunar', str(project_path)], check=True)
|
||||||
|
except (FileNotFoundError, subprocess.CalledProcessError):
|
||||||
|
try:
|
||||||
|
# 最后尝试使用xdg-open
|
||||||
|
subprocess.run(['xdg-open', str(project_path)], check=True)
|
||||||
|
except (FileNotFoundError, subprocess.CalledProcessError):
|
||||||
|
QMessageBox.warning(self, "无法打开文件管理器",
|
||||||
|
"系统中没有找到合适的文件管理器。\n"
|
||||||
|
f"请手动打开路径: {project_path}")
|
||||||
|
|
||||||
|
print(f"成功在资源管理器中打开: {project_path}")
|
||||||
|
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
QMessageBox.critical(self, "打开失败",
|
||||||
|
f"无法打开资源管理器:\n{str(e)}")
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "错误",
|
||||||
|
f"打开资源管理器时发生错误:\n{str(e)}")
|
||||||
|
|
||||||
|
def delete_project(self):
|
||||||
|
"""删除项目"""
|
||||||
|
reply = QMessageBox.question(self, "确认移除",
|
||||||
|
f"确定要移除项目 \"{self.project.title}\" 吗?\n此操作不可撤销。",
|
||||||
|
QMessageBox.Yes | QMessageBox.No,
|
||||||
|
QMessageBox.No)
|
||||||
|
|
||||||
|
if reply == QMessageBox.Yes:
|
||||||
|
self.project_manager.remove_project(self.project.id)
|
||||||
|
|
||||||
|
def confirm_delete_project(self):
|
||||||
|
"""确认删除待删除状态的项目"""
|
||||||
|
reply = QMessageBox.question(self, "确认删除项目",
|
||||||
|
f"确定要永久删除项目 \"{self.project.title}\" 吗?\n"
|
||||||
|
f"此操作不可撤销。\n\n"
|
||||||
|
f"提示:如果项目目录已恢复,您可以点击项目卡片来恢复项目。",
|
||||||
|
QMessageBox.Yes | QMessageBox.No,
|
||||||
|
QMessageBox.No)
|
||||||
|
|
||||||
|
if reply == QMessageBox.Yes:
|
||||||
|
self.project_manager.confirm_delete_project(self.project.id)
|
||||||
|
|
||||||
|
def update_display(self):
|
||||||
|
"""更新显示"""
|
||||||
|
# 更新项目状态属性
|
||||||
|
self.setProperty("status", self.project.status)
|
||||||
|
|
||||||
|
# 重新创建UI以反映更改
|
||||||
|
for i in reversed(range(self.layout().count())):
|
||||||
|
child = self.layout().itemAt(i).widget()
|
||||||
|
if child:
|
||||||
|
child.setParent(None)
|
||||||
|
|
||||||
|
self.init_ui()
|
||||||
|
|
||||||
|
# 强制刷新样式
|
||||||
|
self.style().unpolish(self)
|
||||||
|
self.style().polish(self)
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def apply_fallback_styles(self):
|
||||||
|
"""应用备用样式,确保卡片有正确的外观"""
|
||||||
|
# 直接设置卡片的内联样式
|
||||||
|
card_style = """
|
||||||
|
QWidget#projectCard {
|
||||||
|
background-color: #4a4a5a;
|
||||||
|
border: 1px solid #5a5a6a;
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
QWidget#projectCard:hover {
|
||||||
|
background-color: #5a5a6a;
|
||||||
|
border-color: #6a6a7a;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
self.setStyleSheet(card_style)
|
||||||
|
|
||||||
|
def connect_signals(self):
|
||||||
|
"""连接信号"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def mousePressEvent(self, event):
|
||||||
|
"""鼠标点击事件"""
|
||||||
|
if event.button() == Qt.LeftButton:
|
||||||
|
# 检查是否点击了菜单按钮
|
||||||
|
if not self.menu_btn.geometry().contains(event.pos()):
|
||||||
|
if self.project.status == 'pending_delete':
|
||||||
|
# 待删除状态的项目,尝试恢复
|
||||||
|
self.try_restore_project()
|
||||||
|
else:
|
||||||
|
# 正常状态的项目,打开项目
|
||||||
|
self.open_project()
|
||||||
|
super().mousePressEvent(event)
|
||||||
|
|
||||||
|
def try_restore_project(self):
|
||||||
|
"""尝试恢复待删除状态的项目"""
|
||||||
|
if self.project_manager.restore_project(self.project.id):
|
||||||
|
QMessageBox.information(self, "项目已恢复",
|
||||||
|
f"项目 \"{self.project.title}\" 已成功恢复!")
|
||||||
|
else:
|
||||||
|
QMessageBox.information(self, "项目目录不存在",
|
||||||
|
f"项目 \"{self.project.title}\" 的目录仍然不存在:\n{self.project.project_dir}\n\n"
|
||||||
|
f"提示:当您恢复项目目录后,系统会自动检测并恢复项目状态,无需手动操作。")
|
||||||
|
|
||||||
|
def enterEvent(self, event):
|
||||||
|
"""鼠标进入事件"""
|
||||||
|
self.setProperty("hover", True)
|
||||||
|
self.style().unpolish(self)
|
||||||
|
self.style().polish(self)
|
||||||
|
# 强制重绘以确保悬停效果立即生效
|
||||||
|
self.update()
|
||||||
|
super().enterEvent(event)
|
||||||
|
|
||||||
|
def leaveEvent(self, event):
|
||||||
|
"""鼠标离开事件"""
|
||||||
|
self.setProperty("hover", False)
|
||||||
|
self.style().unpolish(self)
|
||||||
|
self.style().polish(self)
|
||||||
|
# 强制重绘以确保悬停效果立即消失
|
||||||
|
self.update()
|
||||||
|
super().leaveEvent(event)
|
||||||
|
|
||||||
|
def show_success_tooltip(self, message):
|
||||||
|
"""显示成功提示工具提示"""
|
||||||
|
# 临时改变菜单按钮的工具提示来显示成功状态
|
||||||
|
original_tooltip = self.menu_btn.toolTip()
|
||||||
|
|
||||||
|
self.menu_btn.setToolTip(f"✅ {message}")
|
||||||
|
|
||||||
|
# 使用定时器恢复原状态
|
||||||
|
QTimer.singleShot(3000, lambda: self.restore_button_state(original_tooltip))
|
||||||
|
|
||||||
|
def restore_button_state(self, original_tooltip):
|
||||||
|
"""恢复按钮原始状态"""
|
||||||
|
self.menu_btn.setToolTip(original_tooltip)
|
||||||
|
|
||||||
|
def refresh_preview_image(self):
|
||||||
|
"""刷新预览图"""
|
||||||
|
try:
|
||||||
|
# 获取项目路径
|
||||||
|
project_path = self.project.project_dir if self.project.project_dir else self.project.path
|
||||||
|
if not project_path or not Path(project_path).exists():
|
||||||
|
QMessageBox.warning(self, "路径不存在", "项目路径不存在,无法生成预览图。")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 显示进度提示
|
||||||
|
original_tooltip = self.menu_btn.toolTip()
|
||||||
|
self.menu_btn.setEnabled(False)
|
||||||
|
self.menu_btn.setToolTip("⏳ 正在生成预览图...")
|
||||||
|
QApplication.processEvents()
|
||||||
|
|
||||||
|
# 生成新的预览图
|
||||||
|
preview_path = self.generate_project_preview(project_path)
|
||||||
|
|
||||||
|
if preview_path and Path(preview_path).exists():
|
||||||
|
# 清理旧的预览图
|
||||||
|
self.project_manager.cleanup_old_preview_images(self.project.id)
|
||||||
|
|
||||||
|
# 更新项目的图片路径
|
||||||
|
old_image = self.project.image
|
||||||
|
self.project.image = preview_path
|
||||||
|
self.project_manager.update_project(self.project)
|
||||||
|
|
||||||
|
# 刷新显示
|
||||||
|
self.refresh_image_display()
|
||||||
|
|
||||||
|
# 显示成功提示(不使用阻塞对话框)
|
||||||
|
self.show_success_tooltip("预览图已刷新!")
|
||||||
|
|
||||||
|
# 如果有旧图片且不同于新图片,尝试删除
|
||||||
|
if old_image and old_image != preview_path and Path(old_image).exists():
|
||||||
|
try:
|
||||||
|
# 检查是否是我们生成的预览图
|
||||||
|
if "ProjectPreviews" in old_image:
|
||||||
|
Path(old_image).unlink()
|
||||||
|
except Exception:
|
||||||
|
pass # 忽略删除失败
|
||||||
|
else:
|
||||||
|
QMessageBox.warning(self, "生成失败",
|
||||||
|
"无法生成预览图。\n\n可能原因:\n"
|
||||||
|
"• 项目目录中没有图片文件\n"
|
||||||
|
"• 图片文件格式不支持\n"
|
||||||
|
"• 权限不足")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "错误", f"刷新预览图时发生错误:\n{str(e)}")
|
||||||
|
finally:
|
||||||
|
# 恢复按钮状态
|
||||||
|
self.menu_btn.setEnabled(True)
|
||||||
|
self.menu_btn.setToolTip(original_tooltip)
|
||||||
|
|
||||||
|
def generate_project_preview(self, project_path):
|
||||||
|
"""生成项目预览图"""
|
||||||
|
try:
|
||||||
|
project_path = Path(project_path)
|
||||||
|
|
||||||
|
# 查找项目中的图片文件
|
||||||
|
image_extensions = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.tiff', '.webp']
|
||||||
|
found_images = []
|
||||||
|
|
||||||
|
# 搜索常见的图片目录
|
||||||
|
search_dirs = [
|
||||||
|
project_path,
|
||||||
|
project_path / 'images',
|
||||||
|
project_path / 'img',
|
||||||
|
project_path / 'assets',
|
||||||
|
project_path / 'static',
|
||||||
|
project_path / 'resources',
|
||||||
|
project_path / 'media',
|
||||||
|
project_path / 'screenshots',
|
||||||
|
project_path / 'preview'
|
||||||
|
]
|
||||||
|
|
||||||
|
for search_dir in search_dirs:
|
||||||
|
if search_dir.exists() and search_dir.is_dir():
|
||||||
|
for ext in image_extensions:
|
||||||
|
found_images.extend(search_dir.glob(f'*{ext}'))
|
||||||
|
found_images.extend(search_dir.glob(f'*{ext.upper()}'))
|
||||||
|
# 递归搜索子目录(限制深度)
|
||||||
|
found_images.extend(search_dir.glob(f'*/*{ext}'))
|
||||||
|
found_images.extend(search_dir.glob(f'*/*{ext.upper()}'))
|
||||||
|
|
||||||
|
if not found_images:
|
||||||
|
return self.create_default_preview(project_path)
|
||||||
|
|
||||||
|
# 优先选择特定名称的图片
|
||||||
|
priority_names = ['preview', 'screenshot', 'main', 'cover', 'thumbnail', 'icon']
|
||||||
|
selected_image = None
|
||||||
|
|
||||||
|
for priority_name in priority_names:
|
||||||
|
for img_path in found_images:
|
||||||
|
if priority_name in img_path.stem.lower():
|
||||||
|
selected_image = img_path
|
||||||
|
break
|
||||||
|
if selected_image:
|
||||||
|
break
|
||||||
|
|
||||||
|
# 如果没有找到优先图片,选择第一个
|
||||||
|
if not selected_image:
|
||||||
|
selected_image = found_images[0]
|
||||||
|
|
||||||
|
# 创建预览图存储目录
|
||||||
|
preview_dir = Path.cwd() / 'MetaCore' / 'Resources' / 'ProjectPreviews'
|
||||||
|
preview_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# 生成预览图文件名
|
||||||
|
preview_filename = f"preview_{self.project.id}_{int(QDateTime.currentMSecsSinceEpoch())}.png"
|
||||||
|
preview_path = preview_dir / preview_filename
|
||||||
|
|
||||||
|
# 处理图片并保存预览图
|
||||||
|
original_pixmap = QPixmap(str(selected_image))
|
||||||
|
if not original_pixmap.isNull():
|
||||||
|
# 缩放到合适的预览尺寸
|
||||||
|
preview_size = QSize(400, 300)
|
||||||
|
scaled_pixmap = original_pixmap.scaled(
|
||||||
|
preview_size,
|
||||||
|
Qt.KeepAspectRatioByExpanding,
|
||||||
|
Qt.SmoothTransformation
|
||||||
|
)
|
||||||
|
|
||||||
|
# 裁剪到目标尺寸
|
||||||
|
if scaled_pixmap.size() != preview_size:
|
||||||
|
x = (scaled_pixmap.width() - preview_size.width()) // 2
|
||||||
|
y = (scaled_pixmap.height() - preview_size.height()) // 2
|
||||||
|
scaled_pixmap = scaled_pixmap.copy(x, y, preview_size.width(), preview_size.height())
|
||||||
|
|
||||||
|
# 保存预览图
|
||||||
|
if scaled_pixmap.save(str(preview_path), 'PNG'):
|
||||||
|
return str(preview_path)
|
||||||
|
|
||||||
|
return self.create_default_preview(project_path)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"生成预览图时发生错误: {e}")
|
||||||
|
return self.create_default_preview(project_path)
|
||||||
|
|
||||||
|
def create_default_preview(self, project_path):
|
||||||
|
"""创建默认预览图"""
|
||||||
|
try:
|
||||||
|
# 创建预览图存储目录
|
||||||
|
preview_dir = Path.cwd() / 'MetaCore' / 'Resources' / 'ProjectPreviews'
|
||||||
|
preview_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# 生成默认预览图文件名
|
||||||
|
preview_filename = f"default_preview_{self.project.id}.png"
|
||||||
|
preview_path = preview_dir / preview_filename
|
||||||
|
|
||||||
|
# 创建一个带有项目信息的默认预览图
|
||||||
|
pixmap = QPixmap(400, 300)
|
||||||
|
pixmap.fill(QColor(70, 70, 80)) # 深灰色背景
|
||||||
|
|
||||||
|
painter = QPainter(pixmap)
|
||||||
|
painter.setRenderHint(QPainter.Antialiasing)
|
||||||
|
|
||||||
|
# 设置字体
|
||||||
|
font = QFont("微软雅黑", 16, QFont.Bold)
|
||||||
|
painter.setFont(font)
|
||||||
|
painter.setPen(QColor(255, 255, 255))
|
||||||
|
|
||||||
|
# 绘制项目名称
|
||||||
|
title_rect = QRect(20, 100, 360, 40)
|
||||||
|
painter.drawText(title_rect, Qt.AlignCenter | Qt.TextWordWrap, self.project.title)
|
||||||
|
|
||||||
|
# 绘制项目类型
|
||||||
|
type_font = QFont("微软雅黑", 12)
|
||||||
|
painter.setFont(type_font)
|
||||||
|
painter.setPen(QColor(200, 200, 200))
|
||||||
|
type_rect = QRect(20, 150, 360, 30)
|
||||||
|
type_text = self.get_type_label()
|
||||||
|
painter.drawText(type_rect, Qt.AlignCenter, f"项目类型: {type_text}")
|
||||||
|
|
||||||
|
# 绘制创建日期
|
||||||
|
date_rect = QRect(20, 180, 360, 30)
|
||||||
|
painter.drawText(date_rect, Qt.AlignCenter, f"创建时间: {self.project.date}")
|
||||||
|
|
||||||
|
# 绘制文件夹图标
|
||||||
|
icon_font = QFont("Segoe UI Emoji", 48)
|
||||||
|
painter.setFont(icon_font)
|
||||||
|
painter.setPen(QColor(150, 150, 150))
|
||||||
|
icon_rect = QRect(20, 30, 360, 60)
|
||||||
|
painter.drawText(icon_rect, Qt.AlignCenter, "📁")
|
||||||
|
|
||||||
|
painter.end()
|
||||||
|
|
||||||
|
# 保存预览图
|
||||||
|
if pixmap.save(str(preview_path), 'PNG'):
|
||||||
|
return str(preview_path)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"创建默认预览图时发生错误: {e}")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def refresh_image_display(self):
|
||||||
|
"""刷新图片显示"""
|
||||||
|
try:
|
||||||
|
# 更新网格视图中的图片显示
|
||||||
|
if self.view_mode == "grid":
|
||||||
|
self.update_grid_image_display()
|
||||||
|
else:
|
||||||
|
self.update_list_image_display()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"刷新图片显示时发生错误: {e}")
|
||||||
|
|
||||||
|
def update_grid_image_display(self):
|
||||||
|
"""更新网格视图中的图片显示"""
|
||||||
|
# 找到图片容器
|
||||||
|
for i in range(self.layout().count()):
|
||||||
|
widget = self.layout().itemAt(i).widget()
|
||||||
|
if widget and widget.objectName() == "projectImageContainer":
|
||||||
|
# 找到内部的堆叠布局
|
||||||
|
for j in range(widget.layout().count()):
|
||||||
|
image_widget = widget.layout().itemAt(j).widget()
|
||||||
|
if image_widget and image_widget.objectName() == "projectImage":
|
||||||
|
stacked_layout = image_widget.layout()
|
||||||
|
if isinstance(stacked_layout, QStackedLayout):
|
||||||
|
# 获取图片显示控件
|
||||||
|
image_display = stacked_layout.widget(0)
|
||||||
|
if isinstance(image_display, ImageDisplayWidget):
|
||||||
|
# 检查是否有新的图片文件
|
||||||
|
if (hasattr(self.project, 'image') and
|
||||||
|
self.project.image and
|
||||||
|
os.path.exists(self.project.image) and
|
||||||
|
os.path.isfile(self.project.image)):
|
||||||
|
# 重新加载图片
|
||||||
|
pixmap = QPixmap(self.project.image)
|
||||||
|
if not pixmap.isNull():
|
||||||
|
image_display.setPixmap(pixmap)
|
||||||
|
stacked_layout.setCurrentIndex(0)
|
||||||
|
else:
|
||||||
|
stacked_layout.setCurrentIndex(1)
|
||||||
|
else:
|
||||||
|
stacked_layout.setCurrentIndex(1)
|
||||||
|
break
|
||||||
|
|
||||||
|
def update_list_image_display(self):
|
||||||
|
"""更新列表视图中的图片显示"""
|
||||||
|
# 在列表视图中查找并更新图片显示
|
||||||
|
for i in range(self.layout().count()):
|
||||||
|
widget = self.layout().itemAt(i).widget()
|
||||||
|
if widget and widget.objectName() == "listProjectIconContainer":
|
||||||
|
# 找到内部的堆叠布局
|
||||||
|
for j in range(widget.layout().count()):
|
||||||
|
icon_widget = widget.layout().itemAt(j).widget()
|
||||||
|
if icon_widget and icon_widget.objectName() == "listProjectIcon":
|
||||||
|
stacked_layout = icon_widget.layout()
|
||||||
|
if isinstance(stacked_layout, QStackedLayout):
|
||||||
|
# 获取图片显示控件
|
||||||
|
image_display = stacked_layout.widget(0)
|
||||||
|
if isinstance(image_display, ListImageDisplayWidget):
|
||||||
|
# 检查是否有新的图片文件
|
||||||
|
if (hasattr(self.project, 'image') and
|
||||||
|
self.project.image and
|
||||||
|
os.path.exists(self.project.image) and
|
||||||
|
os.path.isfile(self.project.image)):
|
||||||
|
# 重新加载图片
|
||||||
|
pixmap = QPixmap(self.project.image)
|
||||||
|
if not pixmap.isNull():
|
||||||
|
image_display.setPixmap(pixmap)
|
||||||
|
stacked_layout.setCurrentIndex(0)
|
||||||
|
else:
|
||||||
|
stacked_layout.setCurrentIndex(1)
|
||||||
|
else:
|
||||||
|
stacked_layout.setCurrentIndex(1)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
class ListImageDisplayWidget(QWidget):
|
||||||
|
"""
|
||||||
|
专门用于列表视图的圆角图片显示控件
|
||||||
|
尺寸较小,适合列表视图
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.pixmap = QPixmap()
|
||||||
|
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
|
|
||||||
|
def setPixmap(self, pixmap):
|
||||||
|
self.pixmap = pixmap
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def paintEvent(self, event):
|
||||||
|
if self.pixmap.isNull():
|
||||||
|
return
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QSize
|
||||||
|
import math
|
||||||
|
|
||||||
|
target_rect = self.rect()
|
||||||
|
radius = 8.0 # 列表视图使用较小的圆角
|
||||||
|
|
||||||
|
# 过缩放因子
|
||||||
|
overscale_factor = 1.05
|
||||||
|
original_size = target_rect.size()
|
||||||
|
larger_width = math.ceil(original_size.width() * overscale_factor)
|
||||||
|
larger_height = math.ceil(original_size.height() * overscale_factor)
|
||||||
|
larger_target_size = QSize(larger_width, larger_height)
|
||||||
|
|
||||||
|
scaled_pixmap = self.pixmap.scaled(larger_target_size, Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation)
|
||||||
|
|
||||||
|
# 计算绘制的起始坐标,使图片居中
|
||||||
|
draw_x = (target_rect.width() - scaled_pixmap.width()) / 2
|
||||||
|
draw_y = (target_rect.height() - scaled_pixmap.height()) / 2
|
||||||
|
|
||||||
|
# 绘制
|
||||||
|
painter = QPainter(self)
|
||||||
|
painter.setRenderHint(QPainter.Antialiasing)
|
||||||
|
|
||||||
|
# # 创建圆角裁剪路径
|
||||||
|
# path = QPainterPath()
|
||||||
|
# path.addRoundedRect(QRectF(target_rect), radius, radius)
|
||||||
|
# painter.setClipPath(path)
|
||||||
|
|
||||||
|
# 绘制图片
|
||||||
|
painter.drawPixmap(int(draw_x), int(draw_y), scaled_pixmap)
|
||||||
|
|
||||||
328
MetaCore/ui/project_settings_page.py
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
项目设置页面组件
|
||||||
|
|
||||||
|
这个页面允许用户配置项目相关的设置,包括:
|
||||||
|
- 默认项目创建位置
|
||||||
|
- 项目模板设置
|
||||||
|
- 项目命名规则
|
||||||
|
- 其他项目相关配置
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectSettingsPage(QWidget):
|
||||||
|
"""
|
||||||
|
项目设置页面
|
||||||
|
|
||||||
|
提供项目相关的配置选项,主要包括默认项目位置的设置。
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 信号定义
|
||||||
|
settings_changed = pyqtSignal() # 设置发生变化时发出
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.settings = QSettings("MetaCore", "ProjectManager") # 用于保存设置
|
||||||
|
self.init_ui()
|
||||||
|
self.load_settings()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
"""初始化用户界面"""
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(30, 30, 30, 30)
|
||||||
|
layout.setSpacing(20)
|
||||||
|
|
||||||
|
# 页面标题
|
||||||
|
self.create_page_header(layout)
|
||||||
|
|
||||||
|
# 默认项目位置设置
|
||||||
|
self.create_default_location_section(layout)
|
||||||
|
|
||||||
|
self.create_open_location_section(layout)
|
||||||
|
|
||||||
|
# 项目创建设置
|
||||||
|
# self.create_project_creation_section(layout)
|
||||||
|
|
||||||
|
# 按钮区域
|
||||||
|
self.create_button_section(layout)
|
||||||
|
|
||||||
|
# 添加弹性空间
|
||||||
|
layout.addStretch()
|
||||||
|
|
||||||
|
def create_page_header(self, layout):
|
||||||
|
"""创建页面标题"""
|
||||||
|
header_widget = QWidget()
|
||||||
|
header_layout = QVBoxLayout(header_widget)
|
||||||
|
header_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
header_layout.setSpacing(8)
|
||||||
|
|
||||||
|
# 主标题
|
||||||
|
title_label = QLabel("项目设置")
|
||||||
|
title_label.setObjectName("pageTitle")
|
||||||
|
header_layout.addWidget(title_label)
|
||||||
|
|
||||||
|
# 副标题
|
||||||
|
subtitle_label = QLabel("配置项目创建和管理的相关设置")
|
||||||
|
subtitle_label.setObjectName("pageSubtitle")
|
||||||
|
header_layout.addWidget(subtitle_label)
|
||||||
|
|
||||||
|
layout.addWidget(header_widget)
|
||||||
|
|
||||||
|
def create_default_location_section(self, layout):
|
||||||
|
"""创建默认项目位置设置区域"""
|
||||||
|
# 分组框
|
||||||
|
group_box = QGroupBox("默认项目位置")
|
||||||
|
group_box.setObjectName("settingsGroup")
|
||||||
|
group_layout = QVBoxLayout(group_box)
|
||||||
|
group_layout.setSpacing(15)
|
||||||
|
|
||||||
|
# 说明文字
|
||||||
|
desc_label = QLabel("设置新项目的默认创建位置。")
|
||||||
|
desc_label.setObjectName("settingsDescription")
|
||||||
|
desc_label.setWordWrap(True)
|
||||||
|
group_layout.addWidget(desc_label)
|
||||||
|
|
||||||
|
# 当前路径显示和选择
|
||||||
|
path_widget = QWidget()
|
||||||
|
path_layout = QHBoxLayout(path_widget)
|
||||||
|
path_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
path_layout.setSpacing(10)
|
||||||
|
|
||||||
|
# 路径输入框
|
||||||
|
self.path_input = QLineEdit()
|
||||||
|
self.path_input.setObjectName("pathInput")
|
||||||
|
self.path_input.setPlaceholderText("选择默认项目创建位置...")
|
||||||
|
self.path_input.setReadOnly(True) # 只读,通过按钮选择
|
||||||
|
path_layout.addWidget(self.path_input)
|
||||||
|
|
||||||
|
# 浏览按钮
|
||||||
|
self.browse_btn = QPushButton("浏览...")
|
||||||
|
self.browse_btn.setObjectName("browseBtn")
|
||||||
|
self.browse_btn.clicked.connect(self.browse_default_location)
|
||||||
|
path_layout.addWidget(self.browse_btn)
|
||||||
|
|
||||||
|
# 重置按钮
|
||||||
|
self.reset_btn = QPushButton("重置")
|
||||||
|
self.reset_btn.setObjectName("resetBtn")
|
||||||
|
self.reset_btn.clicked.connect(self.reset_default_location)
|
||||||
|
path_layout.addWidget(self.reset_btn)
|
||||||
|
|
||||||
|
group_layout.addWidget(path_widget)
|
||||||
|
|
||||||
|
layout.addWidget(group_box)
|
||||||
|
|
||||||
|
def create_open_location_section(self, layout):
|
||||||
|
"""创建打开位置设置区域"""
|
||||||
|
# 分组框
|
||||||
|
group_box = QGroupBox("打开位置")
|
||||||
|
group_box.setObjectName("settingsGroup")
|
||||||
|
group_layout = QVBoxLayout(group_box)
|
||||||
|
group_layout.setSpacing(15)
|
||||||
|
|
||||||
|
# 说明文字
|
||||||
|
desc_label = QLabel("设置项目文件的默认打开位置。")
|
||||||
|
desc_label.setObjectName("settingsDescription")
|
||||||
|
desc_label.setWordWrap(True)
|
||||||
|
group_layout.addWidget(desc_label)
|
||||||
|
|
||||||
|
# 当前路径显示和选择
|
||||||
|
path_widget = QWidget()
|
||||||
|
path_layout = QHBoxLayout(path_widget)
|
||||||
|
path_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
path_layout.setSpacing(10)
|
||||||
|
|
||||||
|
# 路径输入框
|
||||||
|
self.open_path_input = QLineEdit()
|
||||||
|
self.open_path_input.setObjectName("pathInput")
|
||||||
|
self.open_path_input.setPlaceholderText("选择默认项目打开位置...")
|
||||||
|
self.open_path_input.setReadOnly(True) # 只读,通过按钮选择
|
||||||
|
path_layout.addWidget(self.open_path_input)
|
||||||
|
|
||||||
|
# 浏览按钮
|
||||||
|
self.open_browse_btn = QPushButton("浏览...")
|
||||||
|
self.open_browse_btn.setObjectName("browseBtn")
|
||||||
|
self.open_browse_btn.clicked.connect(self.browse_open_location)
|
||||||
|
path_layout.addWidget(self.open_browse_btn)
|
||||||
|
|
||||||
|
# 重置按钮
|
||||||
|
self.open_reset_btn = QPushButton("重置")
|
||||||
|
self.open_reset_btn.setObjectName("resetBtn")
|
||||||
|
self.open_reset_btn.clicked.connect(self.reset_open_location)
|
||||||
|
path_layout.addWidget(self.open_reset_btn)
|
||||||
|
|
||||||
|
group_layout.addWidget(path_widget)
|
||||||
|
|
||||||
|
layout.addWidget(group_box)
|
||||||
|
|
||||||
|
def browse_open_location(self):
|
||||||
|
"""浏览选择打开位置"""
|
||||||
|
current_path = self.open_path_input.text() or self.get_default_projects_path()
|
||||||
|
|
||||||
|
folder = QFileDialog.getExistingDirectory(
|
||||||
|
self,
|
||||||
|
"选择默认项目打开位置",
|
||||||
|
current_path
|
||||||
|
)
|
||||||
|
|
||||||
|
if folder:
|
||||||
|
self.open_path_input.setText(folder)
|
||||||
|
# 可以根据需要添加保存逻辑
|
||||||
|
self.save_settings_immediately("default_open_location", self.open_path_input.text())
|
||||||
|
|
||||||
|
def reset_open_location(self):
|
||||||
|
"""重置为默认打开位置"""
|
||||||
|
default_path = self.get_default_projects_path()
|
||||||
|
self.open_path_input.setText(default_path)
|
||||||
|
|
||||||
|
def create_project_creation_section(self, layout):
|
||||||
|
"""创建项目创建设置区域"""
|
||||||
|
# 分组框
|
||||||
|
group_box = QGroupBox("项目创建设置")
|
||||||
|
group_box.setObjectName("settingsGroup")
|
||||||
|
group_layout = QVBoxLayout(group_box)
|
||||||
|
group_layout.setSpacing(15)
|
||||||
|
|
||||||
|
# 自动打开项目文件夹选项
|
||||||
|
self.auto_open_checkbox = QCheckBox("创建项目后自动打开项目文件夹")
|
||||||
|
self.auto_open_checkbox.setObjectName("settingsCheckbox")
|
||||||
|
group_layout.addWidget(self.auto_open_checkbox)
|
||||||
|
|
||||||
|
# 创建README文件选项
|
||||||
|
self.create_readme_checkbox = QCheckBox("自动创建 README.md 文件")
|
||||||
|
self.create_readme_checkbox.setObjectName("settingsCheckbox")
|
||||||
|
self.create_readme_checkbox.setChecked(True) # 默认选中
|
||||||
|
group_layout.addWidget(self.create_readme_checkbox)
|
||||||
|
|
||||||
|
# 创建.gitignore文件选项
|
||||||
|
self.create_gitignore_checkbox = QCheckBox("自动创建 .gitignore 文件")
|
||||||
|
self.create_gitignore_checkbox.setObjectName("settingsCheckbox")
|
||||||
|
group_layout.addWidget(self.create_gitignore_checkbox)
|
||||||
|
|
||||||
|
layout.addWidget(group_box)
|
||||||
|
|
||||||
|
def create_button_section(self, layout):
|
||||||
|
"""创建按钮区域(已移除,路径选择后自动保存)"""
|
||||||
|
# 不再需要按钮区域,路径选择后自动保存
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_default_projects_path(self):
|
||||||
|
"""获取默认项目目录路径"""
|
||||||
|
# 获取当前文件所在目录的上级目录(项目根目录)
|
||||||
|
# current_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
# return os.path.join(current_dir, "MetaCore_Projects")
|
||||||
|
current_dir = ''
|
||||||
|
return current_dir
|
||||||
|
|
||||||
|
def browse_default_location(self):
|
||||||
|
"""浏览选择默认位置"""
|
||||||
|
current_path = self.path_input.text() or self.get_default_projects_path()
|
||||||
|
|
||||||
|
folder = QFileDialog.getExistingDirectory(
|
||||||
|
self,
|
||||||
|
"选择默认项目创建位置",
|
||||||
|
current_path
|
||||||
|
)
|
||||||
|
|
||||||
|
if folder:
|
||||||
|
self.path_input.setText(folder)
|
||||||
|
# 路径选择后立即保存设置
|
||||||
|
self.save_settings_immediately("default_project_location", self.path_input.text())
|
||||||
|
|
||||||
|
def reset_default_location(self):
|
||||||
|
"""重置为默认位置"""
|
||||||
|
default_path = self.get_default_projects_path()
|
||||||
|
self.path_input.setText(default_path)
|
||||||
|
|
||||||
|
def load_settings(self):
|
||||||
|
"""加载保存的设置"""
|
||||||
|
# 加载默认项目位置
|
||||||
|
default_path = self.settings.value(
|
||||||
|
"default_project_location",
|
||||||
|
self.get_default_projects_path()
|
||||||
|
)
|
||||||
|
self.path_input.setText(default_path)
|
||||||
|
|
||||||
|
default_open_path = self.settings.value(
|
||||||
|
"default_open_location",
|
||||||
|
self.get_default_projects_path()
|
||||||
|
)
|
||||||
|
self.open_path_input.setText(default_open_path)
|
||||||
|
|
||||||
|
# 加载其他设置
|
||||||
|
# self.auto_open_checkbox.setChecked(
|
||||||
|
# self.settings.value("auto_open_folder", False, type=bool)
|
||||||
|
# )
|
||||||
|
# self.create_readme_checkbox.setChecked(
|
||||||
|
# self.settings.value("create_readme", True, type=bool)
|
||||||
|
# )
|
||||||
|
# self.create_gitignore_checkbox.setChecked(
|
||||||
|
# self.settings.value("create_gitignore", False, type=bool)
|
||||||
|
# )
|
||||||
|
|
||||||
|
def save_settings_immediately(self, key, value):
|
||||||
|
"""立即保存设置(路径选择后自动调用)"""
|
||||||
|
# 保存默认项目位置
|
||||||
|
self.settings.setValue(key, value)
|
||||||
|
|
||||||
|
# 确保设置被保存
|
||||||
|
self.settings.sync()
|
||||||
|
|
||||||
|
# 发出设置变化信号
|
||||||
|
self.settings_changed.emit()
|
||||||
|
|
||||||
|
# 显示简短的成功提示(可选)
|
||||||
|
# QMessageBox.information(self, "设置已保存", "默认项目位置已更新!")
|
||||||
|
|
||||||
|
# def apply_settings(self):
|
||||||
|
# """应用设置(保留方法以防其他地方调用)"""
|
||||||
|
# self.save_settings_immediately()
|
||||||
|
#
|
||||||
|
# # 显示成功消息
|
||||||
|
# QMessageBox.information(self, "设置已保存", "项目设置已成功保存!")
|
||||||
|
#
|
||||||
|
# def restore_defaults(self):
|
||||||
|
# """恢复默认设置(已移除按钮,保留方法以防其他地方调用)"""
|
||||||
|
# reply = QMessageBox.question(
|
||||||
|
# self,
|
||||||
|
# "恢复默认设置",
|
||||||
|
# "确定要恢复所有设置为默认值吗?",
|
||||||
|
# QMessageBox.Yes | QMessageBox.No,
|
||||||
|
# QMessageBox.No
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# if reply == QMessageBox.Yes:
|
||||||
|
# # 恢复默认值
|
||||||
|
# self.path_input.setText(self.get_default_projects_path())
|
||||||
|
#
|
||||||
|
# # 立即保存恢复的设置
|
||||||
|
# self.save_settings_immediately()
|
||||||
|
#
|
||||||
|
# QMessageBox.information(self, "恢复完成", "已恢复默认设置!")
|
||||||
|
|
||||||
|
def get_default_project_location(self):
|
||||||
|
"""获取默认项目位置"""
|
||||||
|
return self.settings.value(
|
||||||
|
"default_project_location",
|
||||||
|
self.get_default_projects_path()
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_default_open_location(self):
|
||||||
|
"""获取默认项目位置"""
|
||||||
|
return self.settings.value(
|
||||||
|
"default_open_location",
|
||||||
|
self.get_default_projects_path()
|
||||||
|
)
|
||||||
|
|
||||||
|
# def get_project_creation_settings(self):
|
||||||
|
# """获取项目创建设置"""
|
||||||
|
# return {
|
||||||
|
# 'auto_open_folder': self.settings.value("auto_open_folder", False, type=bool),
|
||||||
|
# 'create_readme': self.settings.value("create_readme", True, type=bool),
|
||||||
|
# 'create_gitignore': self.settings.value("create_gitignore", False, type=bool),
|
||||||
|
# }
|
||||||
283
MetaCore/ui/sidebar.py
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
侧边栏组件
|
||||||
|
"""
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
from PyQt5.QtCore import *
|
||||||
|
from PyQt5.QtGui import *
|
||||||
|
|
||||||
|
from MetaCore.data.project_manager import ProjectManager
|
||||||
|
from MetaCore.ui.icon_manager import IconManager
|
||||||
|
|
||||||
|
class Sidebar(QWidget):
|
||||||
|
"""侧边栏组件"""
|
||||||
|
|
||||||
|
# 信号定义
|
||||||
|
filter_changed = pyqtSignal(str)
|
||||||
|
navigation_changed = pyqtSignal(str, str, str) # 新增信号:(section, item_name, filter_type)
|
||||||
|
create_project_requested = pyqtSignal()
|
||||||
|
import_project_requested = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, project_manager: ProjectManager):
|
||||||
|
super().__init__()
|
||||||
|
self.project_manager = project_manager
|
||||||
|
self.current_filter = "overview"
|
||||||
|
|
||||||
|
# 导航项映射:filter_type -> (section, item_name)
|
||||||
|
self.nav_mapping = {
|
||||||
|
"overview": ("我的项目", "项目概述"),
|
||||||
|
"management": ("我的项目", "项目管理"),
|
||||||
|
"resource_category": ("资源管理", "资源分类"),
|
||||||
|
"resource_management": ("资源管理", "资源管理"),
|
||||||
|
"project_settings": ("设置中心", "项目设置"),
|
||||||
|
"system_settings": ("设置中心", "系统设置"),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.init_ui()
|
||||||
|
self.connect_signals()
|
||||||
|
|
||||||
|
# 设置固定宽度
|
||||||
|
self.setFixedWidth(280)
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
"""初始化UI"""
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.setSpacing(0)
|
||||||
|
|
||||||
|
# Logo区域
|
||||||
|
self.create_logo_section(layout)
|
||||||
|
|
||||||
|
# 快速操作区域
|
||||||
|
self.create_quick_actions(layout)
|
||||||
|
|
||||||
|
# 导航菜单
|
||||||
|
self.create_navigation_menu(layout)
|
||||||
|
|
||||||
|
# 底部用户信息
|
||||||
|
# layout.addStretch()
|
||||||
|
# self.create_user_info(layout)
|
||||||
|
|
||||||
|
def create_logo_section(self, layout):
|
||||||
|
"""创建Logo区域"""
|
||||||
|
logo_widget = QWidget()
|
||||||
|
logo_widget.setObjectName("logoWidget")
|
||||||
|
logo_layout = QHBoxLayout(logo_widget)
|
||||||
|
logo_layout.setContentsMargins(20, 20, 20, 20)
|
||||||
|
|
||||||
|
# Logo图标 - 使用更专业的图标
|
||||||
|
logo_icon = QLabel()
|
||||||
|
if IconManager.icon_exists('logo'):
|
||||||
|
logo_icon.setPixmap(IconManager.get_pixmap('logo', QSize(24, 24)))
|
||||||
|
else:
|
||||||
|
logo_icon.setText("⬛") # 备选文字图标
|
||||||
|
logo_icon.setObjectName("logoIcon")
|
||||||
|
logo_layout.addWidget(logo_icon)
|
||||||
|
|
||||||
|
# Logo文字
|
||||||
|
logo_text = QLabel("MetaCore")
|
||||||
|
logo_text.setObjectName("logoText")
|
||||||
|
logo_layout.addWidget(logo_text)
|
||||||
|
|
||||||
|
logo_layout.addStretch()
|
||||||
|
layout.addWidget(logo_widget)
|
||||||
|
|
||||||
|
def create_quick_actions(self, layout):
|
||||||
|
"""创建快速操作区域"""
|
||||||
|
actions_widget = QWidget()
|
||||||
|
actions_widget.setObjectName("quickActions")
|
||||||
|
actions_layout = QVBoxLayout(actions_widget)
|
||||||
|
actions_layout.setContentsMargins(20, 10, 20, 20)
|
||||||
|
actions_layout.setSpacing(10)
|
||||||
|
|
||||||
|
# 创建新项目按钮
|
||||||
|
self.create_btn = QPushButton("创建新项目")
|
||||||
|
if IconManager.icon_exists('create'):
|
||||||
|
self.create_btn.setIcon(IconManager.get_icon('create'))
|
||||||
|
else:
|
||||||
|
self.create_btn = QPushButton("+ 创建新项目")
|
||||||
|
self.create_btn.setObjectName("createBtn")
|
||||||
|
self.create_btn.clicked.connect(self.create_project_requested.emit)
|
||||||
|
actions_layout.addWidget(self.create_btn)
|
||||||
|
|
||||||
|
# 导入项目按钮
|
||||||
|
self.import_btn = QPushButton("导入项目")
|
||||||
|
if IconManager.icon_exists('import'):
|
||||||
|
self.import_btn.setIcon(IconManager.get_icon('import'))
|
||||||
|
else:
|
||||||
|
self.import_btn = QPushButton("↑ 导入项目")
|
||||||
|
self.import_btn.setObjectName("sidebarImportBtn")
|
||||||
|
self.import_btn.clicked.connect(self.import_project_requested.emit)
|
||||||
|
actions_layout.addWidget(self.import_btn)
|
||||||
|
|
||||||
|
layout.addWidget(actions_widget)
|
||||||
|
|
||||||
|
def create_navigation_menu(self, layout):
|
||||||
|
"""创建导航菜单"""
|
||||||
|
# 滚动区域
|
||||||
|
scroll_area = QScrollArea()
|
||||||
|
scroll_area.setObjectName("navScrollArea") # 设置对象名称
|
||||||
|
scroll_area.setWidgetResizable(True) # 自适应内容大小
|
||||||
|
scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 水平滚动条
|
||||||
|
scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # 垂直滚动条
|
||||||
|
|
||||||
|
# 导航内容
|
||||||
|
nav_widget = QWidget()
|
||||||
|
nav_widget.setObjectName("navWidget")
|
||||||
|
nav_layout = QVBoxLayout(nav_widget)
|
||||||
|
nav_layout.setContentsMargins(0, 0, 0, 0) # 边距
|
||||||
|
nav_layout.setSpacing(0) # 间距
|
||||||
|
|
||||||
|
# 我的项目分组
|
||||||
|
self.create_nav_section(nav_layout, "我的项目", [
|
||||||
|
("📊", "项目概述", "overview"),
|
||||||
|
("📋", "项目管理", "management"),
|
||||||
|
])
|
||||||
|
|
||||||
|
# 资源管理分组
|
||||||
|
self.create_nav_section(nav_layout, "资源管理", [
|
||||||
|
("🏷", "资源分类", "resource_category"),
|
||||||
|
("📦", "资源管理", "resource_management"),
|
||||||
|
])
|
||||||
|
|
||||||
|
# 设置中心分组
|
||||||
|
self.create_nav_section(nav_layout, "设置中心", [
|
||||||
|
("📁", "项目设置", "project_settings"),
|
||||||
|
("⚙", "系统设置", "system_settings"),
|
||||||
|
])
|
||||||
|
|
||||||
|
nav_layout.addStretch()
|
||||||
|
scroll_area.setWidget(nav_widget)
|
||||||
|
layout.addWidget(scroll_area)
|
||||||
|
|
||||||
|
def create_nav_section(self, layout, title, items):
|
||||||
|
"""创建导航分组"""
|
||||||
|
# 分组标题
|
||||||
|
section_widget = QWidget()
|
||||||
|
section_widget.setObjectName("navSection")
|
||||||
|
section_layout = QVBoxLayout(section_widget)
|
||||||
|
section_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
section_layout.setSpacing(0)
|
||||||
|
|
||||||
|
# 标题按钮(可展开/收起)
|
||||||
|
title_btn = QPushButton(f"{title}")
|
||||||
|
if IconManager.icon_exists('down'):
|
||||||
|
title_btn.setIcon(IconManager.get_icon('down'))
|
||||||
|
else:
|
||||||
|
title_btn = QPushButton(f"▼ {title}")
|
||||||
|
|
||||||
|
title_btn.setObjectName("navSectionTitle")
|
||||||
|
title_btn.setCheckable(True)
|
||||||
|
title_btn.setChecked(True)
|
||||||
|
section_layout.addWidget(title_btn)
|
||||||
|
|
||||||
|
# 子项容器
|
||||||
|
items_widget = QWidget()
|
||||||
|
items_widget.setObjectName("navItems")
|
||||||
|
items_layout = QVBoxLayout(items_widget)
|
||||||
|
items_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
items_layout.setSpacing(0)
|
||||||
|
|
||||||
|
# 创建导航项
|
||||||
|
for icon, text, filter_type in items:
|
||||||
|
nav_item = self.create_nav_item(icon, text, filter_type)
|
||||||
|
items_layout.addWidget(nav_item)
|
||||||
|
|
||||||
|
section_layout.addWidget(items_widget)
|
||||||
|
|
||||||
|
# 展开/收起功能
|
||||||
|
def toggle_section():
|
||||||
|
is_expanded = title_btn.isChecked()
|
||||||
|
items_widget.setVisible(is_expanded)
|
||||||
|
if is_expanded:
|
||||||
|
if IconManager.icon_exists('down'):
|
||||||
|
title_btn.setIcon(IconManager.get_icon('down'))
|
||||||
|
title_btn.setText(f" {title}")
|
||||||
|
else:
|
||||||
|
title_btn.setText(f"▼ {title}")
|
||||||
|
else:
|
||||||
|
if IconManager.icon_exists('right'):
|
||||||
|
title_btn.setIcon(IconManager.get_icon('right'))
|
||||||
|
title_btn.setText(f" {title}")
|
||||||
|
else:
|
||||||
|
title_btn.setText(f"▶ {title}")
|
||||||
|
|
||||||
|
title_btn.clicked.connect(toggle_section)
|
||||||
|
layout.addWidget(section_widget)
|
||||||
|
|
||||||
|
def create_nav_item(self, icon, text, filter_type):
|
||||||
|
"""创建导航项"""
|
||||||
|
item_btn = QPushButton(f" {text}") # 移除文字图标,只保留空格用于间距
|
||||||
|
|
||||||
|
# 设置真实图标
|
||||||
|
if IconManager.icon_exists(filter_type):
|
||||||
|
item_btn.setIcon(IconManager.get_icon(filter_type, QSize(16, 16)))
|
||||||
|
item_btn.setIconSize(QSize(16, 16))
|
||||||
|
else:
|
||||||
|
# 如果图标不存在,使用原来的文字图标
|
||||||
|
item_btn.setText(f"{icon} {text}")
|
||||||
|
|
||||||
|
item_btn.setObjectName("navItem")
|
||||||
|
item_btn.setCheckable(True)
|
||||||
|
|
||||||
|
# 设置默认选中
|
||||||
|
if filter_type == "overview":
|
||||||
|
item_btn.setChecked(True)
|
||||||
|
# 发送初始导航信号
|
||||||
|
if filter_type in self.nav_mapping:
|
||||||
|
section, item_name = self.nav_mapping[filter_type]
|
||||||
|
# 使用 QTimer.singleShot 确保在UI完全初始化后发送信号
|
||||||
|
QTimer.singleShot(0, lambda: self.navigation_changed.emit(section, item_name, filter_type))
|
||||||
|
|
||||||
|
# 点击事件
|
||||||
|
def on_clicked():
|
||||||
|
# 取消其他按钮的选中状态
|
||||||
|
for btn in self.findChildren(QPushButton):
|
||||||
|
if btn.objectName() == "navItem" and btn != item_btn:
|
||||||
|
btn.setChecked(False)
|
||||||
|
|
||||||
|
item_btn.setChecked(True)
|
||||||
|
self.current_filter = filter_type
|
||||||
|
self.filter_changed.emit(filter_type)
|
||||||
|
|
||||||
|
# 发送导航变化信号
|
||||||
|
if filter_type in self.nav_mapping:
|
||||||
|
section, item_name = self.nav_mapping[filter_type]
|
||||||
|
self.navigation_changed.emit(section, item_name, filter_type)
|
||||||
|
|
||||||
|
item_btn.clicked.connect(on_clicked)
|
||||||
|
return item_btn
|
||||||
|
|
||||||
|
def create_user_info(self, layout):
|
||||||
|
"""创建用户信息区域"""
|
||||||
|
user_widget = QWidget()
|
||||||
|
user_widget.setObjectName("userInfo")
|
||||||
|
user_layout = QHBoxLayout(user_widget)
|
||||||
|
user_layout.setContentsMargins(20, 15, 20, 20)
|
||||||
|
|
||||||
|
# 用户头像 - 创建圆形头像
|
||||||
|
avatar_label = QLabel("U")
|
||||||
|
avatar_label.setObjectName("userAvatar")
|
||||||
|
avatar_label.setAlignment(Qt.AlignCenter)
|
||||||
|
avatar_label.setFixedSize(32, 32)
|
||||||
|
user_layout.addWidget(avatar_label)
|
||||||
|
|
||||||
|
# 用户名
|
||||||
|
username_label = QLabel("Admin")
|
||||||
|
username_label.setObjectName("userName")
|
||||||
|
user_layout.addWidget(username_label)
|
||||||
|
|
||||||
|
user_layout.addStretch()
|
||||||
|
|
||||||
|
# 下拉箭头
|
||||||
|
dropdown_label = QLabel("▼")
|
||||||
|
dropdown_label.setObjectName("userDropdown")
|
||||||
|
user_layout.addWidget(dropdown_label)
|
||||||
|
|
||||||
|
layout.addWidget(user_widget)
|
||||||
|
|
||||||
|
def connect_signals(self):
|
||||||
|
"""连接信号"""
|
||||||
|
pass
|
||||||
1705
MetaCore/ui/styles.py
Normal file
45
MetaCore/启动应用.bat
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
@echo off
|
||||||
|
echo ========================================
|
||||||
|
echo MetaCore PyQt5 项目管理平台
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM 检查Python是否可用
|
||||||
|
python --version >nul 2>&1
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [错误] Python未找到,请确保Python已正确安装并添加到PATH
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [信息] Python环境正常
|
||||||
|
python --version
|
||||||
|
|
||||||
|
REM 检查PyQt5是否已安装
|
||||||
|
python -c "import PyQt5" >nul 2>&1
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [警告] PyQt5未安装,正在安装...
|
||||||
|
python -m pip install PyQt5
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [错误] PyQt5安装失败
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
echo [成功] PyQt5安装完成
|
||||||
|
) else (
|
||||||
|
echo [信息] PyQt5已安装
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo [信息] 正在启动MetaCore应用...
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM 启动应用
|
||||||
|
python main.py
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ========================================
|
||||||
|
echo [信息] MetaCore应用已退出
|
||||||
|
echo 感谢使用!
|
||||||
|
pause
|
||||||
78
MetaCore/验证安装.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
验证MetaCore安装是否正确
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("=" * 50)
|
||||||
|
print("🧪 MetaCore安装验证")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
# 检查Python版本
|
||||||
|
print(f"🐍 Python版本: {sys.version}")
|
||||||
|
print(f"📁 Python路径: {sys.executable}")
|
||||||
|
|
||||||
|
# 检查PyQt5
|
||||||
|
try:
|
||||||
|
import PyQt5
|
||||||
|
from PyQt5.QtWidgets import QApplication
|
||||||
|
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR
|
||||||
|
print(f"✅ PyQt5版本: {PYQT_VERSION_STR}")
|
||||||
|
print(f"✅ Qt版本: {QT_VERSION_STR}")
|
||||||
|
|
||||||
|
# 测试创建应用
|
||||||
|
app = QApplication([])
|
||||||
|
print("✅ PyQt5可以正常创建应用程序")
|
||||||
|
app.quit()
|
||||||
|
|
||||||
|
except ImportError as e:
|
||||||
|
print(f"❌ PyQt5导入失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 检查项目文件
|
||||||
|
required_files = [
|
||||||
|
'main.py',
|
||||||
|
'ui/main_window.py',
|
||||||
|
'data/project_manager.py'
|
||||||
|
]
|
||||||
|
|
||||||
|
print("\n📁 检查项目文件:")
|
||||||
|
for file_path in required_files:
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
print(f"✅ {file_path}")
|
||||||
|
else:
|
||||||
|
print(f"❌ {file_path} (缺失)")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 测试模块导入
|
||||||
|
print("\n📦 测试模块导入:")
|
||||||
|
try:
|
||||||
|
sys.path.insert(0, os.getcwd())
|
||||||
|
from ui.main_window import MainWindow
|
||||||
|
from data.project_manager import ProjectManager
|
||||||
|
print("✅ 所有模块导入成功")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 模块导入失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("\n" + "=" * 50)
|
||||||
|
print("🎉 验证完成!")
|
||||||
|
print("✅ MetaCore安装正确,可以正常运行")
|
||||||
|
print("\n🚀 启动命令:")
|
||||||
|
print(" python main.py")
|
||||||
|
print(" 或双击: 启动MetaCore.bat")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
success = main()
|
||||||
|
if not success:
|
||||||
|
print("\n❌ 验证失败,请检查安装")
|
||||||
|
input("按Enter键退出...")
|
||||||
|
else:
|
||||||
|
input("按Enter键退出...")
|
||||||
139
README.md
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
# MetaCore 项目管理平台
|
||||||
|
|
||||||
|
现代化的项目管理平台,提供Web版本和PyQt5桌面版本。
|
||||||
|
|
||||||
|
## 🚀 快速开始
|
||||||
|
|
||||||
|
### PyQt5桌面版本(推荐)
|
||||||
|
```cmd
|
||||||
|
# 一键启动
|
||||||
|
启动MetaCore.bat
|
||||||
|
|
||||||
|
# 或进入目录启动
|
||||||
|
cd MetaCore
|
||||||
|
启动应用.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
### Web版本
|
||||||
|
```cmd
|
||||||
|
# 浏览器打开
|
||||||
|
web/index.html
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📁 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
MetaCore/
|
||||||
|
├── 🌐 Web版本
|
||||||
|
│ └── web/ # Web版本目录
|
||||||
|
│ ├── index.html # Web版本主页面
|
||||||
|
│ ├── script.js # JavaScript逻辑
|
||||||
|
│ ├── styles.css # 样式表
|
||||||
|
│ └── test-cards.html # 测试页面
|
||||||
|
│
|
||||||
|
├── 🖥️ PyQt5桌面版本
|
||||||
|
│ └── MetaCore/ # 桌面版本目录
|
||||||
|
│ ├── main.py # 主程序入口
|
||||||
|
│ ├── 启动应用.bat # 一键启动
|
||||||
|
│ ├── data/ # 数据模块
|
||||||
|
│ ├── ui/ # 界面模块
|
||||||
|
│ └── 验证安装.py # 环境验证工具
|
||||||
|
│
|
||||||
|
├── 📚 文档中心
|
||||||
|
│ └── Doc/ # 所有文档
|
||||||
|
│ ├── README.md # 文档索引
|
||||||
|
│ ├── 快速开始.md # 快速开始指南
|
||||||
|
│ ├── README_PyQt5.md # PyQt5详细说明
|
||||||
|
│ ├── 项目总览.md # 项目全面概述
|
||||||
|
│ ├── 功能对比说明.md # Web vs PyQt5对比
|
||||||
|
│ ├── 安装PyQt5指南.md # 安装问题解决
|
||||||
|
│ └── 虚拟环境完整指南.md # 环境配置指南
|
||||||
|
│
|
||||||
|
├── 🧪 测试文件
|
||||||
|
│ └── tests/ # 测试目录
|
||||||
|
│ ├── test_*.py # 各种测试文件
|
||||||
|
│ └── verify_button_fix.py # 验证修复文件
|
||||||
|
│
|
||||||
|
├── 🔧 开发工具
|
||||||
|
│ └── tools/ # 工具目录
|
||||||
|
│ ├── build.bat # 构建脚本
|
||||||
|
│ ├── build_config.py # 构建配置
|
||||||
|
│ ├── README_打包.md # 打包说明
|
||||||
|
│ └── 打包指南.md # 打包指南
|
||||||
|
│
|
||||||
|
├── 🚀 快速启动
|
||||||
|
│ └── 启动MetaCore.bat # 从根目录启动桌面版
|
||||||
|
│
|
||||||
|
└── 🔧 项目配置
|
||||||
|
├── .gitignore # Git忽略文件
|
||||||
|
├── data/ # 共享数据目录
|
||||||
|
└── 项目整理完成报告.md # 项目整理记录
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📚 文档导航
|
||||||
|
|
||||||
|
### 🎯 新用户必读
|
||||||
|
- **[Doc/快速开始.md](Doc/快速开始.md)** - 快速上手指南
|
||||||
|
- **[Doc/安装PyQt5指南.md](Doc/安装PyQt5指南.md)** - 安装问题解决
|
||||||
|
|
||||||
|
### 📖 详细文档
|
||||||
|
- **[Doc/README.md](Doc/README.md)** - 📚 **文档中心索引**
|
||||||
|
- **[Doc/README_PyQt5.md](Doc/README_PyQt5.md)** - PyQt5版本完整说明
|
||||||
|
- **[Doc/项目总览.md](Doc/项目总览.md)** - 项目全面概述
|
||||||
|
|
||||||
|
### 🔧 技术文档
|
||||||
|
- **[Doc/功能对比说明.md](Doc/功能对比说明.md)** - Web vs PyQt5对比
|
||||||
|
- **[Doc/虚拟环境完整指南.md](Doc/虚拟环境完整指南.md)** - 环境配置指南
|
||||||
|
|
||||||
|
## ✨ 功能特性
|
||||||
|
|
||||||
|
### 项目管理
|
||||||
|
- ✅ 创建项目(6种模板)
|
||||||
|
- ✅ 导入项目(拖拽支持)
|
||||||
|
- ✅ 项目搜索和过滤
|
||||||
|
- ✅ 收藏和管理
|
||||||
|
|
||||||
|
### 界面设计
|
||||||
|
- ✅ 现代化深色主题
|
||||||
|
- ✅ 三段式项目卡片
|
||||||
|
- ✅ 2:1创建对话框
|
||||||
|
- ✅ 响应式布局
|
||||||
|
|
||||||
|
### 技术特点
|
||||||
|
- ✅ Web版本:HTML/CSS/JavaScript
|
||||||
|
- ✅ 桌面版本:Python + PyQt5
|
||||||
|
- ✅ 跨平台支持
|
||||||
|
- ✅ 数据持久化
|
||||||
|
|
||||||
|
## 🔧 系统要求
|
||||||
|
|
||||||
|
### PyQt5桌面版本
|
||||||
|
- Python 3.7+
|
||||||
|
- PyQt5 5.15.0+
|
||||||
|
- Windows/macOS/Linux
|
||||||
|
|
||||||
|
### Web版本
|
||||||
|
- 现代浏览器
|
||||||
|
- 支持HTML5/CSS3
|
||||||
|
|
||||||
|
## 🆘 获取帮助
|
||||||
|
|
||||||
|
### 常见问题
|
||||||
|
1. **PyQt5安装问题** → [Doc/安装PyQt5指南.md](Doc/安装PyQt5指南.md)
|
||||||
|
2. **使用方法** → [Doc/快速开始.md](Doc/快速开始.md)
|
||||||
|
3. **功能说明** → [Doc/README_PyQt5.md](Doc/README_PyQt5.md)
|
||||||
|
|
||||||
|
### 环境验证
|
||||||
|
```cmd
|
||||||
|
cd MetaCore
|
||||||
|
python 验证安装.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 完整文档
|
||||||
|
📚 **[Doc/README.md](Doc/README.md)** - 查看完整文档索引
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
🎉 **开始使用MetaCore管理您的项目吧!**
|
||||||
|
|
||||||
|
💡 **提示:** 推荐使用桌面版本,性能更好,功能更完整。
|
||||||
1343
build/main/Analysis-00.toc
Normal file
570
build/main/EXE-00.toc
Normal file
@ -0,0 +1,570 @@
|
|||||||
|
('C:\\Users\\29381\\Desktop\\MetaCore-startup\\dist\\main.exe',
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\bootloader\\images\\icon-console.ico',
|
||||||
|
None,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<assembly xmlns='
|
||||||
|
b'"urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\n <trustInfo x'
|
||||||
|
b'mlns="urn:schemas-microsoft-com:asm.v3">\n <security>\n <requested'
|
||||||
|
b'Privileges>\n <requestedExecutionLevel level="asInvoker" uiAccess='
|
||||||
|
b'"false"/>\n </requestedPrivileges>\n </security>\n </trustInfo>\n '
|
||||||
|
b'<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">\n <'
|
||||||
|
b'application>\n <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f'
|
||||||
|
b'0}"/>\n <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>\n '
|
||||||
|
b' <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>\n <s'
|
||||||
|
b'upportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>\n <supporte'
|
||||||
|
b'dOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>\n </application>\n <'
|
||||||
|
b'/compatibility>\n <application xmlns="urn:schemas-microsoft-com:asm.v3">'
|
||||||
|
b'\n <windowsSettings>\n <longPathAware xmlns="http://schemas.micros'
|
||||||
|
b'oft.com/SMI/2016/WindowsSettings">true</longPathAware>\n </windowsSett'
|
||||||
|
b'ings>\n </application>\n <dependency>\n <dependentAssembly>\n <ass'
|
||||||
|
b'emblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version='
|
||||||
|
b'"6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" langua'
|
||||||
|
b'ge="*"/>\n </dependentAssembly>\n </dependency>\n</assembly>',
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\main.pkg',
|
||||||
|
[('pyi-contents-directory _internal', '', 'OPTION'),
|
||||||
|
('PYZ-00.pyz',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\PYZ-00.pyz',
|
||||||
|
'PYZ'),
|
||||||
|
('struct',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\struct.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod01_archive',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod01_archive.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod02_importers',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod02_importers.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod03_ctypes',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod03_ctypes.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod04_pywin32',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod04_pywin32.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyiboot01_bootstrap',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('pyi_rth_inspect',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('pyi_rth_pyqt5',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pyqt5.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('pyi_rth_pkgutil',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('main',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\MetaCore\\main.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('python313.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Scripts\\python313.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qjpeg.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qjpeg.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qtga.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qtga.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qtiff.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qtiff.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\platformthemes\\qxdgdesktopportal.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platformthemes\\qxdgdesktopportal.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\generic\\qtuiotouchplugin.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\generic\\qtuiotouchplugin.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\iconengines\\qsvgicon.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\iconengines\\qsvgicon.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\platforms\\qwebgl.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qwebgl.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qwebp.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qwebp.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qico.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qico.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qicns.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qicns.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\platforms\\qoffscreen.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qoffscreen.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qgif.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qgif.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\platforms\\qwindows.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qwindows.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qwbmp.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qwbmp.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qsvg.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qsvg.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\platforms\\qminimal.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qminimal.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\d3dcompiler_47.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\d3dcompiler_47.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\opengl32sw.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\opengl32sw.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\libEGL.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\libEGL.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\libGLESv2.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\libGLESv2.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\styles\\qwindowsvistastyle.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\styles\\qwindowsvistastyle.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('_decimal.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_decimal.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_hashlib.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_hashlib.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_lzma.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_lzma.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_bz2.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_bz2.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('select.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\select.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_socket.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_socket.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('unicodedata.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\unicodedata.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('PyQt5\\QtGui.pyd',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\QtGui.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('PyQt5\\sip.cp313-win_amd64.pyd',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\sip.cp313-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('PyQt5\\QtCore.pyd',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\QtCore.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('PyQt5\\QtWidgets.pyd',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\QtWidgets.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('VCRUNTIME140.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Scripts\\VCRUNTIME140.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-stdio-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-stdio-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-convert-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-convert-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-heap-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-heap-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-process-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-process-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-time-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-time-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-conio-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-conio-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-locale-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-locale-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-environment-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-environment-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-string-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-string-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-runtime-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-runtime-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-math-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-math-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Gui.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Gui.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Core.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Core.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-utility-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-utility-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5DBus.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5DBus.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Network.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Network.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Svg.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Svg.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5WebSockets.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5WebSockets.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\MSVCP140.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\MSVCP140.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Quick.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Quick.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('VCRUNTIME140_1.dll',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\VCRUNTIME140.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\VCRUNTIME140.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\VCRUNTIME140_1.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\VCRUNTIME140_1.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Widgets.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Widgets.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('libcrypto-3.dll',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('python3.dll',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\python3.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('ucrtbase.dll', 'C:\\Windows\\system32\\ucrtbase.dll', 'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\MSVCP140_1.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\MSVCP140_1.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5QmlModels.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5QmlModels.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Qml.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Qml.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-memory-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-memory-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-console-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-console-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-util-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-util-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-processthreads-l1-1-1.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-processthreads-l1-1-1.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-synch-l1-2-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-synch-l1-2-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-string-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-string-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-file-l2-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-file-l2-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-profile-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-profile-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-localization-l1-2-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-localization-l1-2-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-processenvironment-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-processenvironment-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-debug-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-debug-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-synch-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-synch-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-processthreads-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-processthreads-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-handle-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-handle-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-interlocked-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-interlocked-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-file-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-file-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-heap-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-heap-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-datetime-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-datetime-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-file-l1-2-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-file-l1-2-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-timezone-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-timezone-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_ja.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ja.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_bg.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_bg.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_gl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_gl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_bg.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_bg.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_de.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_de.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_he.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_he.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_ko.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ko.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_es.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_es.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_cs.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_cs.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_zh_TW.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_zh_TW.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_cs.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_cs.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_gd.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_gd.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_fr.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_fr.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_ko.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ko.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_uk.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_uk.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_zh_TW.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_zh_TW.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_gd.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_gd.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_da.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_da.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_ca.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ca.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_sk.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_sk.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_uk.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_uk.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_zh_TW.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_zh_TW.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_ar.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ar.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_da.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_da.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_pt.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_pt.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_ca.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ca.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_ar.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ar.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_tr.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_tr.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_it.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_it.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_uk.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_uk.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_it.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_it.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_it.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_it.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_ko.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ko.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_sk.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_sk.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_hu.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_hu.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_da.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_da.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_ja.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ja.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_ru.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ru.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_ja.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ja.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_tr.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_tr.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_tr.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_tr.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_fi.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_fi.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_zh_CN.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_zh_CN.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_hu.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_hu.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_es.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_es.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_fa.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_fa.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_en.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_en.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_cs.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_cs.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_en.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_en.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_bg.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_bg.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_fi.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_fi.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_en.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_en.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_gl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_gl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_ar.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ar.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_pl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_pl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_ru.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ru.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_de.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_de.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_zh_CN.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_zh_CN.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_pl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_pl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_fr.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_fr.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_sk.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_sk.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_pl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_pl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_es.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_es.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_lt.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_lt.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_sl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_sl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_he.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_he.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_hu.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_hu.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_sl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_sl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_fr.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_fr.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_sv.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_sv.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_de.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_de.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_lv.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_lv.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_lv.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_lv.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_ca.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ca.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_ru.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ru.qm',
|
||||||
|
'DATA'),
|
||||||
|
('base_library.zip',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\base_library.zip',
|
||||||
|
'DATA')],
|
||||||
|
[],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
1758880462,
|
||||||
|
[('run.exe',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
|
||||||
|
'EXECUTABLE')],
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Scripts\\python313.dll')
|
||||||
548
build/main/PKG-00.toc
Normal file
@ -0,0 +1,548 @@
|
|||||||
|
('C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\main.pkg',
|
||||||
|
{'BINARY': True,
|
||||||
|
'DATA': True,
|
||||||
|
'EXECUTABLE': True,
|
||||||
|
'EXTENSION': True,
|
||||||
|
'PYMODULE': True,
|
||||||
|
'PYSOURCE': True,
|
||||||
|
'PYZ': False,
|
||||||
|
'SPLASH': True,
|
||||||
|
'SYMLINK': False},
|
||||||
|
[('pyi-contents-directory _internal', '', 'OPTION'),
|
||||||
|
('PYZ-00.pyz',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\PYZ-00.pyz',
|
||||||
|
'PYZ'),
|
||||||
|
('struct',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\struct.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod01_archive',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod01_archive.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod02_importers',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod02_importers.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod03_ctypes',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod03_ctypes.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod04_pywin32',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod04_pywin32.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyiboot01_bootstrap',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('pyi_rth_inspect',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('pyi_rth_pyqt5',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pyqt5.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('pyi_rth_pkgutil',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('main',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\MetaCore\\main.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('python313.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Scripts\\python313.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qjpeg.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qjpeg.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qtga.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qtga.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qtiff.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qtiff.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\platformthemes\\qxdgdesktopportal.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platformthemes\\qxdgdesktopportal.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\generic\\qtuiotouchplugin.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\generic\\qtuiotouchplugin.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\iconengines\\qsvgicon.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\iconengines\\qsvgicon.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\platforms\\qwebgl.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qwebgl.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qwebp.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qwebp.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qico.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qico.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qicns.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qicns.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\platforms\\qoffscreen.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qoffscreen.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qgif.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qgif.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\platforms\\qwindows.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qwindows.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qwbmp.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qwbmp.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\imageformats\\qsvg.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qsvg.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\platforms\\qminimal.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qminimal.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\d3dcompiler_47.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\d3dcompiler_47.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\opengl32sw.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\opengl32sw.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\libEGL.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\libEGL.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\libGLESv2.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\libGLESv2.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\plugins\\styles\\qwindowsvistastyle.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\styles\\qwindowsvistastyle.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('_decimal.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_decimal.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_hashlib.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_hashlib.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_lzma.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_lzma.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_bz2.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_bz2.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('select.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\select.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_socket.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_socket.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('unicodedata.pyd',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\unicodedata.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('PyQt5\\QtGui.pyd',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\QtGui.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('PyQt5\\sip.cp313-win_amd64.pyd',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\sip.cp313-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('PyQt5\\QtCore.pyd',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\QtCore.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('PyQt5\\QtWidgets.pyd',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\QtWidgets.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('VCRUNTIME140.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Scripts\\VCRUNTIME140.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-stdio-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-stdio-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-convert-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-convert-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-heap-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-heap-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-process-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-process-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-time-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-time-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-conio-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-conio-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-locale-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-locale-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-environment-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-environment-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-string-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-string-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-runtime-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-runtime-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-math-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-math-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Gui.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Gui.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Core.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Core.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-utility-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-crt-utility-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5DBus.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5DBus.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Network.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Network.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Svg.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Svg.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5WebSockets.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5WebSockets.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\MSVCP140.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\MSVCP140.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Quick.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Quick.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('VCRUNTIME140_1.dll',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\VCRUNTIME140.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\VCRUNTIME140.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\VCRUNTIME140_1.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\VCRUNTIME140_1.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Widgets.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Widgets.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('libcrypto-3.dll',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('python3.dll',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\python3.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('ucrtbase.dll', 'C:\\Windows\\system32\\ucrtbase.dll', 'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\MSVCP140_1.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\MSVCP140_1.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5QmlModels.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5QmlModels.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\bin\\Qt5Qml.dll',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Qml.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-memory-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-memory-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-console-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-console-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-util-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-util-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-processthreads-l1-1-1.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-processthreads-l1-1-1.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-synch-l1-2-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-synch-l1-2-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-string-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-string-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-file-l2-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-file-l2-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-profile-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-profile-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-localization-l1-2-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-localization-l1-2-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-processenvironment-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-processenvironment-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-debug-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-debug-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-synch-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-synch-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-processthreads-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-processthreads-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-handle-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-handle-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-interlocked-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-interlocked-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-file-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-file-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-heap-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-heap-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-datetime-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-datetime-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-file-l1-2-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-file-l1-2-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-timezone-l1-1-0.dll',
|
||||||
|
'C:\\Windows\\system32\\api-ms-win-core-timezone-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_ja.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ja.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_bg.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_bg.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_gl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_gl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_bg.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_bg.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_de.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_de.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_he.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_he.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_ko.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ko.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_es.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_es.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_cs.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_cs.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_zh_TW.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_zh_TW.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_cs.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_cs.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_gd.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_gd.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_fr.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_fr.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_ko.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ko.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_uk.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_uk.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_zh_TW.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_zh_TW.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_gd.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_gd.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_da.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_da.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_ca.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ca.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_sk.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_sk.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_uk.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_uk.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_zh_TW.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_zh_TW.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_ar.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ar.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_da.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_da.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_pt.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_pt.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_ca.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ca.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_ar.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ar.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_tr.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_tr.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_it.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_it.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_uk.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_uk.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_it.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_it.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_it.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_it.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_ko.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ko.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_sk.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_sk.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_hu.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_hu.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_da.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_da.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_ja.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ja.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_ru.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ru.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_ja.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ja.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_tr.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_tr.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_tr.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_tr.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_fi.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_fi.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_zh_CN.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_zh_CN.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_hu.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_hu.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_es.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_es.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_fa.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_fa.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_en.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_en.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_cs.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_cs.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_en.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_en.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_bg.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_bg.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_fi.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_fi.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_en.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_en.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_gl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_gl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_ar.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ar.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_pl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_pl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_ru.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ru.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_de.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_de.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_zh_CN.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_zh_CN.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_pl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_pl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_fr.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_fr.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_sk.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_sk.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_pl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_pl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_es.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_es.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_lt.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_lt.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_sl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_sl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_he.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_he.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_hu.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_hu.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_sl.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_sl.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_fr.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_fr.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_sv.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_sv.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_de.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_de.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_lv.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_lv.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_lv.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_lv.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qt_help_ca.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ca.qm',
|
||||||
|
'DATA'),
|
||||||
|
('PyQt5\\Qt5\\translations\\qtbase_ru.qm',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ru.qm',
|
||||||
|
'DATA'),
|
||||||
|
('base_library.zip',
|
||||||
|
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\base_library.zip',
|
||||||
|
'DATA')],
|
||||||
|
'python313.dll',
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None)
|
||||||
BIN
build/main/PYZ-00.pyz
Normal file
352
build/main/PYZ-00.toc
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
('C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\PYZ-00.pyz',
|
||||||
|
[('PyQt5',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('__future__',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\__future__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_colorize',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_colorize.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_compat_pickle',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_compat_pickle.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_compression',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_compression.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_opcode_metadata',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_opcode_metadata.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_py_abc',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_py_abc.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_pydatetime',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_pydatetime.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_pydecimal',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_pydecimal.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_pyi_rth_utils',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\fake-modules\\_pyi_rth_utils\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_pyi_rth_utils.qt',
|
||||||
|
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\fake-modules\\_pyi_rth_utils\\qt.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_strptime',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_strptime.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('_threading_local',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_threading_local.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('argparse',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\argparse.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('ast',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\ast.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('base64',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\base64.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('bisect',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\bisect.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('bz2',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\bz2.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('calendar',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\calendar.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('contextlib',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\contextlib.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('contextvars',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\contextvars.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('copy',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\copy.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('csv',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\csv.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('dataclasses',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\dataclasses.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('datetime',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\datetime.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('decimal',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\decimal.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('dis',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\dis.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email._encoded_words',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\_encoded_words.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email._header_value_parser',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\_header_value_parser.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email._parseaddr',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\_parseaddr.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email._policybase',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\_policybase.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.base64mime',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\base64mime.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.charset',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\charset.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.contentmanager',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\contentmanager.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.encoders',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\encoders.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.errors',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\errors.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.feedparser',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\feedparser.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.generator',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\generator.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.header',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\header.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.headerregistry',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\headerregistry.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.iterators',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\iterators.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.message',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\message.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.parser',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\parser.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.policy',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\policy.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.quoprimime',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\quoprimime.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('email.utils',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\utils.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('fnmatch',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\fnmatch.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('fractions',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\fractions.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('getopt',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\getopt.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('gettext',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\gettext.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('glob',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\glob.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('gzip',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\gzip.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('hashlib',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\hashlib.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib._abc',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\_abc.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib._bootstrap',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\_bootstrap.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib._bootstrap_external',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\_bootstrap_external.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.abc',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\abc.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.machinery',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\machinery.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.metadata',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.metadata._adapters',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_adapters.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.metadata._collections',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_collections.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.metadata._functools',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_functools.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.metadata._itertools',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_itertools.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.metadata._meta',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_meta.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.metadata._text',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_text.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.readers',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\readers.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.resources',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.resources._adapters',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\_adapters.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.resources._common',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\_common.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.resources._functional',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\_functional.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.resources._itertools',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\_itertools.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.resources.abc',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\abc.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.resources.readers',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\readers.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('importlib.util',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\util.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('inspect',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\inspect.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('ipaddress',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\ipaddress.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('json',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('json.decoder',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\decoder.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('json.encoder',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\encoder.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('json.scanner',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\scanner.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('logging',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\logging\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('lzma',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\lzma.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('numbers',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\numbers.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('opcode',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\opcode.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pathlib',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pathlib\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pathlib._abc',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pathlib\\_abc.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pathlib._local',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pathlib\\_local.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pickle',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pickle.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pkgutil',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pkgutil.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pprint',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pprint.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('py_compile',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\py_compile.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('quopri',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\quopri.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('random',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\random.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('selectors',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\selectors.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('shutil',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\shutil.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('signal',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\signal.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('socket',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\socket.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('statistics',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\statistics.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('string',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\string.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('stringprep',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\stringprep.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('subprocess',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\subprocess.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('tarfile',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tarfile.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('tempfile',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tempfile.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('textwrap',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\textwrap.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('threading',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\threading.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('token',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\token.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('tokenize',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tokenize.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('tracemalloc',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tracemalloc.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('typing',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\typing.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('urllib',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\urllib\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('urllib.parse',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\urllib\\parse.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('zipfile',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\zipfile\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('zipfile._path',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\zipfile\\_path\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('zipfile._path.glob',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\zipfile\\_path\\glob.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('zipimport',
|
||||||
|
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\zipimport.py',
|
||||||
|
'PYMODULE')])
|
||||||
BIN
build/main/base_library.zip
Normal file
BIN
build/main/localpycs/pyimod01_archive.pyc
Normal file
BIN
build/main/localpycs/pyimod02_importers.pyc
Normal file
BIN
build/main/localpycs/pyimod03_ctypes.pyc
Normal file
BIN
build/main/localpycs/pyimod04_pywin32.pyc
Normal file
BIN
build/main/localpycs/struct.pyc
Normal file
BIN
build/main/main.pkg
Normal file
28
build/main/warn-main.txt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
This file lists modules PyInstaller was not able to find. This does not
|
||||||
|
necessarily mean this module is required for running your program. Python and
|
||||||
|
Python 3rd-party packages include a lot of conditional or optional modules. For
|
||||||
|
example the module 'ntpath' only exists on Windows, whereas the module
|
||||||
|
'posixpath' only exists on Posix systems.
|
||||||
|
|
||||||
|
Types if import:
|
||||||
|
* top-level: imported at the top-level - look at these first
|
||||||
|
* conditional: imported within an if-statement
|
||||||
|
* delayed: imported within a function
|
||||||
|
* optional: imported within a try-except-statement
|
||||||
|
|
||||||
|
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||||
|
tracking down the missing module yourself. Thanks!
|
||||||
|
|
||||||
|
missing module named pyimod02_importers - imported by D:\PythonProject\MetaCore-startup\.venv\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||||
|
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional)
|
||||||
|
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional)
|
||||||
|
missing module named posix - imported by posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), os (conditional, optional)
|
||||||
|
missing module named resource - imported by posix (top-level)
|
||||||
|
missing module named 'collections.abc' - imported by tracemalloc (top-level), traceback (top-level), typing (top-level), inspect (top-level), logging (top-level), importlib.resources.readers (top-level), selectors (top-level)
|
||||||
|
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||||
|
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||||
|
missing module named 'MetaCore.data' - imported by C:\Users\29381\Desktop\MetaCore-startup\MetaCore\main.py (top-level)
|
||||||
|
missing module named 'MetaCore.ui' - imported by C:\Users\29381\Desktop\MetaCore-startup\MetaCore\main.py (top-level)
|
||||||
|
missing module named _posixsubprocess - imported by subprocess (conditional)
|
||||||
|
missing module named fcntl - imported by subprocess (optional)
|
||||||
7773
build/main/xref-main.html
Normal file
203
build_app.py
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
MetaCore 应用程序打包脚本
|
||||||
|
|
||||||
|
这个脚本用于自动化打包 MetaCore 应用程序为可执行文件。
|
||||||
|
它会:
|
||||||
|
1. 清理之前的构建文件
|
||||||
|
2. 创建必要的资源目录
|
||||||
|
3. 使用优化的配置进行打包
|
||||||
|
4. 验证打包结果
|
||||||
|
|
||||||
|
使用方法:
|
||||||
|
python build_app.py
|
||||||
|
|
||||||
|
作者: MetaCore Team
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def clean_build_dirs():
|
||||||
|
"""清理构建目录"""
|
||||||
|
print("🧹 清理构建目录...")
|
||||||
|
|
||||||
|
dirs_to_clean = ['build', 'dist', '__pycache__']
|
||||||
|
for dir_name in dirs_to_clean:
|
||||||
|
dir_path = Path(dir_name)
|
||||||
|
if dir_path.exists():
|
||||||
|
print(f" 删除: {dir_path}")
|
||||||
|
shutil.rmtree(dir_path)
|
||||||
|
|
||||||
|
# 清理 .pyc 文件
|
||||||
|
for pyc_file in Path('.').rglob('*.pyc'):
|
||||||
|
pyc_file.unlink()
|
||||||
|
|
||||||
|
print("✅ 清理完成")
|
||||||
|
|
||||||
|
def ensure_resources():
|
||||||
|
"""确保必要的资源目录存在"""
|
||||||
|
print("📁 检查资源目录...")
|
||||||
|
|
||||||
|
resource_dirs = [
|
||||||
|
Path('MetaCore/Resources/Icons'),
|
||||||
|
Path('MetaCore/Resources/ProjectPreviews'),
|
||||||
|
Path('data')
|
||||||
|
]
|
||||||
|
|
||||||
|
for dir_path in resource_dirs:
|
||||||
|
if not dir_path.exists():
|
||||||
|
print(f" 创建目录: {dir_path}")
|
||||||
|
dir_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
else:
|
||||||
|
print(f" ✓ 存在: {dir_path}")
|
||||||
|
|
||||||
|
print("✅ 资源目录检查完成")
|
||||||
|
|
||||||
|
def check_dependencies():
|
||||||
|
"""检查依赖"""
|
||||||
|
print("🔍 检查依赖...")
|
||||||
|
|
||||||
|
required_packages = ['PyQt5', 'pyinstaller']
|
||||||
|
missing = []
|
||||||
|
|
||||||
|
for package in required_packages:
|
||||||
|
try:
|
||||||
|
# 使用pip show来检查包是否安装
|
||||||
|
result = subprocess.run([sys.executable, '-m', 'pip', 'show', package],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(f" ✓ {package}")
|
||||||
|
else:
|
||||||
|
missing.append(package)
|
||||||
|
print(f" ✗ {package} - 缺失")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ⚠️ {package} - 检查失败: {e}")
|
||||||
|
# 如果pip检查失败,尝试直接导入
|
||||||
|
try:
|
||||||
|
if package == 'PyQt5':
|
||||||
|
import PyQt5.QtCore
|
||||||
|
elif package == 'pyinstaller':
|
||||||
|
import PyInstaller
|
||||||
|
print(f" ✓ {package} (通过导入验证)")
|
||||||
|
except ImportError:
|
||||||
|
missing.append(package)
|
||||||
|
print(f" ✗ {package} - 确实缺失")
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
print(f"❌ 缺少依赖: {', '.join(missing)}")
|
||||||
|
print("请运行: pip install " + ' '.join(missing))
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("✅ 依赖检查完成")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def build_app():
|
||||||
|
"""构建应用程序"""
|
||||||
|
print("🔨 开始构建应用程序...")
|
||||||
|
|
||||||
|
# 使用自定义的spec文件
|
||||||
|
spec_file = 'MetaCore.spec'
|
||||||
|
if not Path(spec_file).exists():
|
||||||
|
print(f"❌ 找不到 {spec_file} 文件")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 运行PyInstaller
|
||||||
|
cmd = [sys.executable, '-m', 'PyInstaller', spec_file, '--clean']
|
||||||
|
print(f"执行命令: {' '.join(cmd)}")
|
||||||
|
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
print("✅ 构建成功!")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print("❌ 构建失败:")
|
||||||
|
print(result.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 构建过程中发生错误: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def verify_build():
|
||||||
|
"""验证构建结果"""
|
||||||
|
print("🔍 验证构建结果...")
|
||||||
|
|
||||||
|
exe_path = Path('dist/MetaCore.exe')
|
||||||
|
if exe_path.exists():
|
||||||
|
size_mb = exe_path.stat().st_size / (1024 * 1024)
|
||||||
|
print(f"✅ 找到可执行文件: {exe_path}")
|
||||||
|
print(f"📊 文件大小: {size_mb:.1f} MB")
|
||||||
|
|
||||||
|
# 检查资源文件是否被正确包含
|
||||||
|
# 这里可以添加更多的验证逻辑
|
||||||
|
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print("❌ 未找到可执行文件")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def show_results():
|
||||||
|
"""显示构建结果"""
|
||||||
|
print("\n" + "="*50)
|
||||||
|
print("🎉 构建完成!")
|
||||||
|
print("="*50)
|
||||||
|
|
||||||
|
dist_path = Path('dist')
|
||||||
|
if dist_path.exists():
|
||||||
|
print(f"📦 输出目录: {dist_path.absolute()}")
|
||||||
|
|
||||||
|
for file in dist_path.glob('*'):
|
||||||
|
if file.is_file():
|
||||||
|
size_mb = file.stat().st_size / (1024 * 1024)
|
||||||
|
print(f" 📄 {file.name} ({size_mb:.1f} MB)")
|
||||||
|
|
||||||
|
print("\n💡 使用提示:")
|
||||||
|
print("1. 双击 MetaCore.exe 运行应用程序")
|
||||||
|
print("2. 可以将 exe 文件分发给其他用户")
|
||||||
|
print("3. 首次运行可能会慢一些(解压时间)")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数"""
|
||||||
|
print("🚀 MetaCore 应用程序打包工具")
|
||||||
|
print("="*50)
|
||||||
|
|
||||||
|
# 检查是否在项目根目录
|
||||||
|
if not Path('MetaCore/main.py').exists():
|
||||||
|
print("❌ 请在项目根目录运行此脚本")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# 执行构建步骤
|
||||||
|
try:
|
||||||
|
clean_build_dirs()
|
||||||
|
ensure_resources()
|
||||||
|
|
||||||
|
# 跳过依赖检查,直接尝试构建
|
||||||
|
# if not check_dependencies():
|
||||||
|
# return 1
|
||||||
|
print("⚠️ 跳过依赖检查,直接尝试构建...")
|
||||||
|
|
||||||
|
if not build_app():
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if not verify_build():
|
||||||
|
return 1
|
||||||
|
|
||||||
|
show_results()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n⚠️ 用户中断构建")
|
||||||
|
return 1
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n❌ 构建过程中发生未预期的错误: {e}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
57
data/projects.json
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"title": "智慧工厂",
|
||||||
|
"date": "2024-06-08 15:56:35",
|
||||||
|
"type": "industrial",
|
||||||
|
"image": "🏭",
|
||||||
|
"path": "",
|
||||||
|
"project_dir": "",
|
||||||
|
"description": "",
|
||||||
|
"status": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"title": "智慧水务",
|
||||||
|
"date": "2023-01-10 12:09:04",
|
||||||
|
"type": "smart",
|
||||||
|
"image": "💧",
|
||||||
|
"path": "",
|
||||||
|
"project_dir": "",
|
||||||
|
"description": "",
|
||||||
|
"status": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"title": "数字工厂",
|
||||||
|
"date": "2024-06-07 06:57:46",
|
||||||
|
"type": "industrial",
|
||||||
|
"image": "🏗️",
|
||||||
|
"path": "",
|
||||||
|
"project_dir": "",
|
||||||
|
"description": "",
|
||||||
|
"status": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"title": "智慧监控",
|
||||||
|
"date": "2024-07-28 17:38:02",
|
||||||
|
"type": "smart",
|
||||||
|
"image": "📊",
|
||||||
|
"path": "",
|
||||||
|
"project_dir": "",
|
||||||
|
"description": "",
|
||||||
|
"status": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"title": "工业设计平台",
|
||||||
|
"date": "2025-02-28 18:00:05",
|
||||||
|
"type": "design",
|
||||||
|
"image": "🎨",
|
||||||
|
"path": "",
|
||||||
|
"project_dir": "",
|
||||||
|
"description": "",
|
||||||
|
"status": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
BIN
dist/MetaCore.exe
vendored
Normal file
BIN
dist/Resources/Icons/Refresh.png
vendored
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
dist/Resources/Icons/app_icon.png
vendored
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
dist/Resources/Icons/category.png
vendored
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
dist/Resources/Icons/create.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
dist/Resources/Icons/delete.png
vendored
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
dist/Resources/Icons/down.png
vendored
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
dist/Resources/Icons/folder.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
dist/Resources/Icons/grid_view.png
vendored
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
dist/Resources/Icons/import.png
vendored
Normal file
|
After Width: | Height: | Size: 2.7 KiB |