|
|
|
|
@ -83,6 +83,9 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
self.unified_document_content = "" # 统一文档内容
|
|
|
|
|
self.last_edit_mode = "typing" # 上次编辑模式
|
|
|
|
|
|
|
|
|
|
# 临时文件管理
|
|
|
|
|
self.temp_files = [] # 跟踪创建的临时文件
|
|
|
|
|
|
|
|
|
|
# 初始化网络服务和WeatherAPI
|
|
|
|
|
self.network_service = NetworkService()
|
|
|
|
|
self.weather_api = WeatherAPI()
|
|
|
|
|
@ -155,16 +158,8 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
weather_data = self.weather_api.get_weather_data(city)
|
|
|
|
|
if weather_data:
|
|
|
|
|
print(f"获取到天气数据: {weather_data}")
|
|
|
|
|
# 格式化数据以匹配状态栏期望的格式
|
|
|
|
|
formatted_data = {
|
|
|
|
|
'city': weather_data['city'],
|
|
|
|
|
'temperature': weather_data['current']['temp'],
|
|
|
|
|
'description': weather_data['current']['weather'],
|
|
|
|
|
'humidity': weather_data['current']['humidity'],
|
|
|
|
|
'wind_scale': weather_data['current']['wind_scale']
|
|
|
|
|
}
|
|
|
|
|
print(f"格式化后的数据: {formatted_data}")
|
|
|
|
|
self.update_weather_display(formatted_data)
|
|
|
|
|
# 直接传递原始数据,update_weather_display会处理嵌套结构
|
|
|
|
|
self.update_weather_display(weather_data)
|
|
|
|
|
else:
|
|
|
|
|
print(f"无法获取城市 {city} 的天气数据")
|
|
|
|
|
|
|
|
|
|
@ -202,7 +197,8 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
'temperature': weather_data['current']['temp'],
|
|
|
|
|
'description': weather_data['current']['weather'],
|
|
|
|
|
'humidity': weather_data['current']['humidity'],
|
|
|
|
|
'wind_scale': weather_data['current']['wind_scale']
|
|
|
|
|
'wind_scale': weather_data['current']['wind_scale'],
|
|
|
|
|
'life_tips': weather_data.get('life_tips', [])
|
|
|
|
|
}
|
|
|
|
|
print(f"格式化后的数据: {formatted_data}")
|
|
|
|
|
self.update_weather_display(formatted_data)
|
|
|
|
|
@ -282,10 +278,10 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
new_action.triggered.connect(self.new_document)
|
|
|
|
|
file_menu.addAction(new_action)
|
|
|
|
|
|
|
|
|
|
# 打开
|
|
|
|
|
open_action = QAction('打开(O)...', self)
|
|
|
|
|
# 导入文件 - 改为导入功能
|
|
|
|
|
open_action = QAction('导入文件(I)...', self)
|
|
|
|
|
open_action.setShortcut('Ctrl+O')
|
|
|
|
|
open_action.triggered.connect(self.open_file)
|
|
|
|
|
open_action.triggered.connect(self.import_file)
|
|
|
|
|
file_menu.addAction(open_action)
|
|
|
|
|
|
|
|
|
|
# 保存
|
|
|
|
|
@ -587,6 +583,11 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
# 保存当前学习进度,以便在模式切换时恢复
|
|
|
|
|
self.learning_progress = self.displayed_chars
|
|
|
|
|
|
|
|
|
|
# 更新打字逻辑中的进度信息
|
|
|
|
|
if self.typing_logic:
|
|
|
|
|
self.typing_logic.typed_chars = self.displayed_chars
|
|
|
|
|
self.typing_logic.current_index = self.displayed_chars
|
|
|
|
|
|
|
|
|
|
# 获取应该显示的文本部分(从上次中断处继续)
|
|
|
|
|
display_text = self.imported_content[:self.displayed_chars]
|
|
|
|
|
|
|
|
|
|
@ -742,6 +743,10 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
|
|
|
|
|
# 保存打字内容到文档A
|
|
|
|
|
self.typing_mode_content = current_text
|
|
|
|
|
|
|
|
|
|
# 更新学习进度(用于打字模式显示)
|
|
|
|
|
if hasattr(self, 'learning_progress'):
|
|
|
|
|
self.learning_progress = len(current_text)
|
|
|
|
|
|
|
|
|
|
def on_text_changed_original(self):
|
|
|
|
|
"""文本变化处理 - 支持逐步显示模式和自由打字模式"""
|
|
|
|
|
@ -791,6 +796,7 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
self.text_edit.setTextCursor(cursor)
|
|
|
|
|
|
|
|
|
|
# 在文本中插入图片(如果有的话)
|
|
|
|
|
# 注意:必须在更新文本后调用,且要处理图片插入对文本长度的影响
|
|
|
|
|
self.insert_images_in_text()
|
|
|
|
|
|
|
|
|
|
# 重新连接文本变化信号
|
|
|
|
|
@ -814,6 +820,9 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
# 检查当前位置是否有图片
|
|
|
|
|
self.check_and_show_image_at_position(self.displayed_chars)
|
|
|
|
|
|
|
|
|
|
# 在文本中插入图片(如果有的话)
|
|
|
|
|
self.insert_images_in_text()
|
|
|
|
|
|
|
|
|
|
# 检查是否完成
|
|
|
|
|
if self.displayed_chars >= len(self.imported_content):
|
|
|
|
|
self.on_lesson_complete()
|
|
|
|
|
@ -913,25 +922,34 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
|
|
|
|
|
def update_weather_display(self, weather_data):
|
|
|
|
|
"""更新天气显示"""
|
|
|
|
|
print(f"接收到天气数据: {weather_data}")
|
|
|
|
|
if 'error' in weather_data:
|
|
|
|
|
print(f"天气显示错误: {weather_data['error']}")
|
|
|
|
|
self.status_bar.showMessage(f"天气数据获取失败: {weather_data['error']}", 3000)
|
|
|
|
|
else:
|
|
|
|
|
# 处理嵌套的天气数据结构
|
|
|
|
|
city = weather_data.get('city', '未知城市')
|
|
|
|
|
temp = weather_data.get('temperature', 'N/A')
|
|
|
|
|
desc = weather_data.get('description', 'N/A')
|
|
|
|
|
humidity = weather_data.get('humidity', 'N/A')
|
|
|
|
|
wind_scale = weather_data.get('wind_scale', 'N/A')
|
|
|
|
|
|
|
|
|
|
# 从current字段获取温度和天气状况
|
|
|
|
|
current_data = weather_data.get('current', {})
|
|
|
|
|
temp = current_data.get('temp', 'N/A')
|
|
|
|
|
desc = current_data.get('weather', 'N/A')
|
|
|
|
|
|
|
|
|
|
# 获取温度范围信息
|
|
|
|
|
temp_range = ""
|
|
|
|
|
if 'forecast' in weather_data and weather_data['forecast']:
|
|
|
|
|
forecast_data = weather_data['forecast'][0] # 今天的预报
|
|
|
|
|
if isinstance(forecast_data, dict):
|
|
|
|
|
temp_max = forecast_data.get('temp_max', 'N/A')
|
|
|
|
|
temp_min = forecast_data.get('temp_min', 'N/A')
|
|
|
|
|
if temp_max != 'N/A' and temp_min != 'N/A':
|
|
|
|
|
temp_range = f" ({temp_min}°C~{temp_max}°C)"
|
|
|
|
|
|
|
|
|
|
# 在状态栏显示简要天气信息
|
|
|
|
|
weather_message = f"{city}: {desc}, {temp}°C, 湿度{humidity}%, 风力{wind_scale}级"
|
|
|
|
|
print(f"显示天气信息: {weather_message}")
|
|
|
|
|
weather_message = f"{city}: {desc}, {temp}°C{temp_range}"
|
|
|
|
|
self.status_bar.showMessage(weather_message, 5000)
|
|
|
|
|
|
|
|
|
|
# 存储天气数据供其他功能使用
|
|
|
|
|
# 存储天气数据供其他功能使用(确保包含生活提示)
|
|
|
|
|
self.current_weather_data = weather_data
|
|
|
|
|
print("天气数据已存储")
|
|
|
|
|
print(f"update_weather_display - 存储的current_weather_data包含life_tips: {self.current_weather_data.get('life_tips', [])}")
|
|
|
|
|
|
|
|
|
|
def refresh_weather(self):
|
|
|
|
|
"""手动刷新天气信息"""
|
|
|
|
|
@ -948,15 +966,15 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
weather_data = self.weather_api.get_weather_data(current_city)
|
|
|
|
|
|
|
|
|
|
if weather_data:
|
|
|
|
|
# 格式化天气数据
|
|
|
|
|
# 格式化天气数据为扁平结构,便于update_weather_display使用
|
|
|
|
|
formatted_data = {
|
|
|
|
|
'city': weather_data['city'],
|
|
|
|
|
'temperature': weather_data['current']['temp'],
|
|
|
|
|
'description': weather_data['current']['weather'],
|
|
|
|
|
'humidity': weather_data['current']['humidity'],
|
|
|
|
|
'wind_scale': weather_data['current']['wind_scale'],
|
|
|
|
|
'forecast': weather_data['forecast']
|
|
|
|
|
'current': weather_data['current'],
|
|
|
|
|
'forecast': weather_data['forecast'],
|
|
|
|
|
'life_tips': weather_data.get('life_tips', [])
|
|
|
|
|
}
|
|
|
|
|
print(f"refresh_weather - 原始数据包含life_tips: {weather_data.get('life_tips', [])}")
|
|
|
|
|
print(f"refresh_weather - formatted_data包含life_tips: {formatted_data.get('life_tips', [])}")
|
|
|
|
|
self.update_weather_display(formatted_data)
|
|
|
|
|
self.status_bar.showMessage("天气数据已刷新", 2000)
|
|
|
|
|
else:
|
|
|
|
|
@ -974,6 +992,7 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
weather_data = self.current_weather_data
|
|
|
|
|
print(f"详细天气对话框 - 天气数据: {weather_data}")
|
|
|
|
|
|
|
|
|
|
# 创建对话框
|
|
|
|
|
dialog = QDialog(self)
|
|
|
|
|
@ -990,11 +1009,26 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
current_layout = QVBoxLayout()
|
|
|
|
|
current_layout.addWidget(QLabel("<b>当前天气:</b>"))
|
|
|
|
|
|
|
|
|
|
# 获取温度信息,支持嵌套结构
|
|
|
|
|
current_data = weather_data.get('current', {})
|
|
|
|
|
temp = current_data.get('temp', 'N/A')
|
|
|
|
|
if temp != 'N/A' and isinstance(temp, str):
|
|
|
|
|
temp = float(temp) if temp.replace('.', '').isdigit() else temp
|
|
|
|
|
|
|
|
|
|
# 从预报数据中获取最高和最低气温
|
|
|
|
|
temp_max = 'N/A'
|
|
|
|
|
temp_min = 'N/A'
|
|
|
|
|
if 'forecast' in weather_data and weather_data['forecast']:
|
|
|
|
|
forecast_data = weather_data['forecast'][0] # 今天的预报
|
|
|
|
|
if isinstance(forecast_data, dict):
|
|
|
|
|
temp_max = forecast_data.get('temp_max', 'N/A')
|
|
|
|
|
temp_min = forecast_data.get('temp_min', 'N/A')
|
|
|
|
|
|
|
|
|
|
current_info = f"""
|
|
|
|
|
温度: {weather_data.get('temperature', 'N/A')}°C
|
|
|
|
|
天气状况: {weather_data.get('description', 'N/A')}
|
|
|
|
|
湿度: {weather_data.get('humidity', 'N/A')}%
|
|
|
|
|
风力: {weather_data.get('wind_scale', 'N/A')}级
|
|
|
|
|
当前温度: {temp}°C
|
|
|
|
|
最高气温: {temp_max}°C
|
|
|
|
|
最低气温: {temp_min}°C
|
|
|
|
|
天气状况: {current_data.get('weather', 'N/A')}
|
|
|
|
|
"""
|
|
|
|
|
current_text = QTextEdit()
|
|
|
|
|
current_text.setPlainText(current_info.strip())
|
|
|
|
|
@ -1003,22 +1037,23 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
|
|
|
|
|
layout.addLayout(current_layout)
|
|
|
|
|
|
|
|
|
|
# 天气预报信息
|
|
|
|
|
if 'forecast' in weather_data and weather_data['forecast']:
|
|
|
|
|
forecast_layout = QVBoxLayout()
|
|
|
|
|
forecast_layout.addWidget(QLabel("<b>天气预报:</b>"))
|
|
|
|
|
# 生活提示信息(替换原来的天气预报)
|
|
|
|
|
life_tips = weather_data.get('life_tips', [])
|
|
|
|
|
print(f"详细天气对话框 - 生活提示: {life_tips}")
|
|
|
|
|
print(f"详细天气对话框 - 完整天气数据: {weather_data}")
|
|
|
|
|
if life_tips:
|
|
|
|
|
tips_layout = QVBoxLayout()
|
|
|
|
|
tips_layout.addWidget(QLabel("<b>生活提示:</b>"))
|
|
|
|
|
|
|
|
|
|
forecast_text = QTextEdit()
|
|
|
|
|
forecast_info = ""
|
|
|
|
|
for i, day in enumerate(weather_data['forecast'][:3]): # 显示最近3天的预报
|
|
|
|
|
if i < len(weather_data['forecast']):
|
|
|
|
|
day_data = weather_data['forecast'][i]
|
|
|
|
|
forecast_info += f"第{i+1}天: {day_data.get('fxDate', 'N/A')} - {day_data.get('textDay', 'N/A')}, {day_data.get('tempMin', 'N/A')}~{day_data.get('tempMax', 'N/A')}°C\n"
|
|
|
|
|
tips_text = QTextEdit()
|
|
|
|
|
tips_info = ""
|
|
|
|
|
for tip in life_tips:
|
|
|
|
|
tips_info += f"• {tip}\n"
|
|
|
|
|
|
|
|
|
|
forecast_text.setPlainText(forecast_info.strip())
|
|
|
|
|
forecast_text.setReadOnly(True)
|
|
|
|
|
forecast_layout.addWidget(forecast_text)
|
|
|
|
|
layout.addLayout(forecast_layout)
|
|
|
|
|
tips_text.setPlainText(tips_info.strip())
|
|
|
|
|
tips_text.setReadOnly(True)
|
|
|
|
|
tips_layout.addWidget(tips_text)
|
|
|
|
|
layout.addLayout(tips_layout)
|
|
|
|
|
|
|
|
|
|
# 按钮
|
|
|
|
|
button_layout = QHBoxLayout()
|
|
|
|
|
@ -1154,59 +1189,181 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
self.is_modified = False
|
|
|
|
|
self.update_window_title()
|
|
|
|
|
|
|
|
|
|
# 重置导入内容和进度
|
|
|
|
|
self.imported_content = ""
|
|
|
|
|
self.displayed_chars = 0
|
|
|
|
|
if hasattr(self, 'learning_progress'):
|
|
|
|
|
delattr(self, 'learning_progress')
|
|
|
|
|
|
|
|
|
|
# 根据当前模式重置打字逻辑
|
|
|
|
|
if self.typing_logic:
|
|
|
|
|
if self.view_mode == "learning":
|
|
|
|
|
# 学习模式:重置为默认内容
|
|
|
|
|
self.typing_logic.reset("欢迎使用MagicWord隐私学习软件!\n\n这是一个仿Microsoft Word界面的学习工具。")
|
|
|
|
|
self.imported_content = ""
|
|
|
|
|
self.displayed_chars = 0
|
|
|
|
|
# 学习模式:重置为默认内容,需要导入文件
|
|
|
|
|
self.typing_logic.reset("欢迎使用MagicWord隐私学习软件!\n\n请先导入文件开始打字学习。")
|
|
|
|
|
self.status_bar.showMessage("新建文档 - 学习模式,请先导入文件开始打字学习", 3000)
|
|
|
|
|
elif self.view_mode == "typing":
|
|
|
|
|
# 打字模式:重置为默认内容,允许自由打字
|
|
|
|
|
self.typing_logic.reset("欢迎使用MagicWord隐私学习软件!\n\n这是一个仿Microsoft Word界面的学习工具。")
|
|
|
|
|
self.imported_content = ""
|
|
|
|
|
self.displayed_chars = 0
|
|
|
|
|
self.status_bar.showMessage("新建文档 - 打字模式,可以自由开始打字", 3000)
|
|
|
|
|
|
|
|
|
|
def open_file(self):
|
|
|
|
|
"""打开文件 - 创建空白副本并在学习模式下显示导入内容"""
|
|
|
|
|
def import_file(self):
|
|
|
|
|
"""导入文件 - 仅在导入时存储内容,不立即显示"""
|
|
|
|
|
file_path, _ = QFileDialog.getOpenFileName(
|
|
|
|
|
self, "打开文件", "",
|
|
|
|
|
self, "导入文件", "",
|
|
|
|
|
"文档文件 (*.docx *.txt *.pdf);;所有文件 (*.*)"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if file_path:
|
|
|
|
|
try:
|
|
|
|
|
# 解析文件
|
|
|
|
|
# 使用新的转换方法,将文件转换为txt格式
|
|
|
|
|
parser = FileParser()
|
|
|
|
|
content = parser.parse_file(file_path)
|
|
|
|
|
result = parser.parse_and_convert_to_txt(file_path)
|
|
|
|
|
|
|
|
|
|
if content:
|
|
|
|
|
# 设置文件加载标志
|
|
|
|
|
self.is_loading_file = True
|
|
|
|
|
if result['success']:
|
|
|
|
|
content = result['content']
|
|
|
|
|
txt_path = result['txt_path']
|
|
|
|
|
images = result['images']
|
|
|
|
|
|
|
|
|
|
# 如果是临时文件,添加到跟踪列表
|
|
|
|
|
if result.get('is_temp_file', False):
|
|
|
|
|
self.temp_files.append(txt_path)
|
|
|
|
|
|
|
|
|
|
# 存储完整内容但不立即显示
|
|
|
|
|
self.imported_content = content
|
|
|
|
|
self.displayed_chars = 0
|
|
|
|
|
|
|
|
|
|
# 创建空白副本 - 清空文本编辑器
|
|
|
|
|
# 如果有提取的图片,设置到打字逻辑中
|
|
|
|
|
if images:
|
|
|
|
|
image_data_dict = {}
|
|
|
|
|
for filename, image_data in images:
|
|
|
|
|
image_data_dict[filename] = image_data
|
|
|
|
|
|
|
|
|
|
# 创建图片位置信息(简化处理,将图片放在文本末尾)
|
|
|
|
|
image_positions = []
|
|
|
|
|
current_pos = len(content)
|
|
|
|
|
for i, (filename, _) in enumerate(images):
|
|
|
|
|
# 在文本末尾添加图片标记
|
|
|
|
|
content += f"\n\n[图片: {filename}]\n"
|
|
|
|
|
image_positions.append({
|
|
|
|
|
'start_pos': current_pos,
|
|
|
|
|
'end_pos': current_pos + len(f"[图片: {filename}]"),
|
|
|
|
|
'filename': filename
|
|
|
|
|
})
|
|
|
|
|
current_pos += len(f"\n\n[图片: {filename}]\n")
|
|
|
|
|
|
|
|
|
|
# 更新导入的内容
|
|
|
|
|
self.imported_content = content
|
|
|
|
|
|
|
|
|
|
# 设置图片数据到打字逻辑
|
|
|
|
|
if self.typing_logic:
|
|
|
|
|
self.typing_logic.set_image_data(image_data_dict)
|
|
|
|
|
self.typing_logic.set_image_positions(image_positions)
|
|
|
|
|
|
|
|
|
|
# 清空文本编辑器
|
|
|
|
|
self.text_edit.clear()
|
|
|
|
|
|
|
|
|
|
# 根据当前模式进行处理
|
|
|
|
|
if self.view_mode == "learning":
|
|
|
|
|
# 学习模式:设置学习内容到打字逻辑
|
|
|
|
|
# 学习模式:重置打字逻辑并准备显示导入内容
|
|
|
|
|
if self.typing_logic:
|
|
|
|
|
self.typing_logic.reset(content) # 重置打字状态并设置新内容
|
|
|
|
|
|
|
|
|
|
self.status_bar.showMessage(f"已打开学习文件: {os.path.basename(file_path)},开始打字逐步显示学习内容!", 5000)
|
|
|
|
|
self.status_bar.showMessage(f"已导入: {os.path.basename(txt_path)},开始打字逐步显示学习内容!", 5000)
|
|
|
|
|
else:
|
|
|
|
|
# 打字模式:不显示导入内容,保持当前内容
|
|
|
|
|
self.status_bar.showMessage(f"已导入: {os.path.basename(txt_path)},切换到学习模式查看内容", 5000)
|
|
|
|
|
|
|
|
|
|
elif self.view_mode == "typing":
|
|
|
|
|
# 打字模式:也设置内容,但允许自由打字
|
|
|
|
|
if self.typing_logic:
|
|
|
|
|
self.typing_logic.reset("") # 重置打字状态,但内容为空,允许自由打字
|
|
|
|
|
# 提取并显示图片(如果有)
|
|
|
|
|
if images:
|
|
|
|
|
self.extract_and_display_images(content, images)
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
# 转换失败,显示错误信息
|
|
|
|
|
raise Exception(result['error'])
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
# 如果新转换方法失败,回退到原来的解析方法
|
|
|
|
|
try:
|
|
|
|
|
parser = FileParser()
|
|
|
|
|
content = parser.parse_file(file_path)
|
|
|
|
|
|
|
|
|
|
if content:
|
|
|
|
|
# 存储完整内容但不立即显示
|
|
|
|
|
self.imported_content = content
|
|
|
|
|
self.displayed_chars = 0
|
|
|
|
|
|
|
|
|
|
# 清空文本编辑器
|
|
|
|
|
self.text_edit.clear()
|
|
|
|
|
|
|
|
|
|
# 根据当前模式进行处理
|
|
|
|
|
if self.view_mode == "learning":
|
|
|
|
|
# 学习模式:重置打字逻辑并准备显示导入内容
|
|
|
|
|
if self.typing_logic:
|
|
|
|
|
self.typing_logic.reset(content) # 重置打字状态并设置新内容
|
|
|
|
|
|
|
|
|
|
self.status_bar.showMessage(f"已导入: {os.path.basename(file_path)},开始打字逐步显示学习内容!", 5000)
|
|
|
|
|
else:
|
|
|
|
|
# 打字模式:不显示导入内容,保持当前内容
|
|
|
|
|
self.status_bar.showMessage(f"已导入: {os.path.basename(file_path)},切换到学习模式查看内容", 5000)
|
|
|
|
|
|
|
|
|
|
except Exception as fallback_e:
|
|
|
|
|
QMessageBox.critical(self, "错误", f"无法导入文件:\n{str(e)}\n\n回退方法也失败:\n{str(fallback_e)}")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 设置当前文件路径(仅作为参考,不用于保存)
|
|
|
|
|
self.current_file_path = txt_path if 'txt_path' in locals() else file_path
|
|
|
|
|
self.is_modified = False
|
|
|
|
|
self.update_window_title()
|
|
|
|
|
|
|
|
|
|
# 更新字数统计
|
|
|
|
|
if hasattr(self.status_bar, 'words_label'):
|
|
|
|
|
self.status_bar.words_label.setText(f"总字数: {len(content)}")
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
# 如果新转换方法失败,回退到原来的解析方法
|
|
|
|
|
try:
|
|
|
|
|
parser = FileParser()
|
|
|
|
|
content = parser.parse_file(file_path)
|
|
|
|
|
|
|
|
|
|
if content:
|
|
|
|
|
# 设置文件加载标志
|
|
|
|
|
self.is_loading_file = True
|
|
|
|
|
|
|
|
|
|
self.status_bar.showMessage(f"已创建空白副本,可以自由打字", 5000)
|
|
|
|
|
# 存储完整内容但不立即显示
|
|
|
|
|
self.imported_content = content
|
|
|
|
|
self.displayed_chars = 0
|
|
|
|
|
|
|
|
|
|
# 创建空白副本 - 清空文本编辑器
|
|
|
|
|
self.text_edit.clear()
|
|
|
|
|
|
|
|
|
|
# 根据当前模式进行处理
|
|
|
|
|
if self.view_mode == "learning":
|
|
|
|
|
# 学习模式:设置学习内容到打字逻辑
|
|
|
|
|
if self.typing_logic:
|
|
|
|
|
self.typing_logic.reset(content) # 重置打字状态并设置新内容
|
|
|
|
|
|
|
|
|
|
self.status_bar.showMessage(f"已打开学习文件: {os.path.basename(file_path)},开始打字逐步显示学习内容!", 5000)
|
|
|
|
|
else:
|
|
|
|
|
# 打字模式:直接显示完整内容
|
|
|
|
|
self.text_edit.setPlainText(content)
|
|
|
|
|
self.status_bar.showMessage(f"已打开: {os.path.basename(file_path)}", 5000)
|
|
|
|
|
|
|
|
|
|
# 清除文件加载标志
|
|
|
|
|
self.is_loading_file = False
|
|
|
|
|
|
|
|
|
|
# 设置当前文件路径
|
|
|
|
|
self.current_file_path = file_path
|
|
|
|
|
self.is_modified = False
|
|
|
|
|
self.update_window_title()
|
|
|
|
|
|
|
|
|
|
# 更新字数统计
|
|
|
|
|
if hasattr(self.status_bar, 'words_label'):
|
|
|
|
|
self.status_bar.words_label.setText(f"总字数: {len(content)}")
|
|
|
|
|
|
|
|
|
|
except Exception as fallback_e:
|
|
|
|
|
# 确保在异常情况下也清除标志
|
|
|
|
|
self.is_loading_file = False
|
|
|
|
|
QMessageBox.critical(self, "错误", f"无法打开文件:\n{str(e)}\n\n回退方法也失败:\n{str(fallback_e)}")
|
|
|
|
|
|
|
|
|
|
# 清除文件加载标志
|
|
|
|
|
self.is_loading_file = False
|
|
|
|
|
@ -1351,13 +1508,18 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
if mode == "typing":
|
|
|
|
|
# 打字模式:显示文档A的内容
|
|
|
|
|
self.status_bar.showMessage("切换到打字模式 - 显示文档A内容", 3000)
|
|
|
|
|
# 打字模式:显示学习模式下已输入的内容(文档A)
|
|
|
|
|
self.status_bar.showMessage("切换到打字模式 - 显示已输入的内容", 3000)
|
|
|
|
|
|
|
|
|
|
# 设置文档A的内容
|
|
|
|
|
# 设置文档A的内容(学习模式下已输入的内容)
|
|
|
|
|
self.text_edit.clear()
|
|
|
|
|
if self.typing_mode_content:
|
|
|
|
|
self.text_edit.setPlainText(self.typing_mode_content)
|
|
|
|
|
if hasattr(self, 'learning_progress') and self.learning_progress > 0:
|
|
|
|
|
# 显示学习模式下已输入的内容
|
|
|
|
|
display_text = self.imported_content[:self.learning_progress]
|
|
|
|
|
self.text_edit.setPlainText(display_text)
|
|
|
|
|
else:
|
|
|
|
|
# 如果没有学习进度,显示默认提示
|
|
|
|
|
self.text_edit.setPlainText("请先在学习模式下输入内容")
|
|
|
|
|
|
|
|
|
|
# 设置光标位置到文档末尾
|
|
|
|
|
cursor = self.text_edit.textCursor()
|
|
|
|
|
@ -1366,7 +1528,14 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
|
|
|
|
|
# 重置打字逻辑,准备接受新的输入
|
|
|
|
|
if self.typing_logic:
|
|
|
|
|
self.typing_logic.reset("")
|
|
|
|
|
if hasattr(self, 'learning_progress') and self.learning_progress > 0:
|
|
|
|
|
# 使用已输入的内容作为打字逻辑的基础
|
|
|
|
|
self.typing_logic.reset(self.imported_content)
|
|
|
|
|
# 设置当前位置到已输入的末尾
|
|
|
|
|
self.typing_logic.current_index = self.learning_progress
|
|
|
|
|
self.typing_logic.typed_chars = self.learning_progress
|
|
|
|
|
else:
|
|
|
|
|
self.typing_logic.reset("")
|
|
|
|
|
|
|
|
|
|
# 重置显示字符计数
|
|
|
|
|
self.displayed_chars = 0
|
|
|
|
|
@ -1859,6 +2028,11 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
print("打字逻辑或图片位置信息不存在")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 添加调试信息
|
|
|
|
|
print(f"当前显示字符数: {self.displayed_chars}")
|
|
|
|
|
print(f"图片位置信息数量: {len(self.typing_logic.image_positions)}")
|
|
|
|
|
print(f"图片数据数量: {len(self.typing_logic.image_data) if hasattr(self.typing_logic, 'image_data') else 0}")
|
|
|
|
|
|
|
|
|
|
# 检查是否已经插入过图片(避免重复插入)
|
|
|
|
|
if not hasattr(self, 'inserted_images'):
|
|
|
|
|
self.inserted_images = set()
|
|
|
|
|
@ -1867,65 +2041,83 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
current_text = self.text_edit.toPlainText()
|
|
|
|
|
current_length = len(current_text)
|
|
|
|
|
|
|
|
|
|
# 获取需要显示的图片列表
|
|
|
|
|
images_to_display = self.typing_logic.get_images_to_display(self.displayed_chars)
|
|
|
|
|
|
|
|
|
|
# 添加调试信息
|
|
|
|
|
print(f"需要显示的图片数量: {len(images_to_display)}")
|
|
|
|
|
if images_to_display:
|
|
|
|
|
for img in images_to_display:
|
|
|
|
|
print(f"图片信息: {img.get('filename', 'unknown')} at pos {img.get('start_pos', -1)}-{img.get('end_pos', -1)}")
|
|
|
|
|
|
|
|
|
|
# 检查当前显示位置是否有图片需要插入
|
|
|
|
|
for image_info in self.typing_logic.image_positions:
|
|
|
|
|
for image_info in images_to_display:
|
|
|
|
|
image_key = f"{image_info['start_pos']}_{image_info['filename']}"
|
|
|
|
|
|
|
|
|
|
# 跳过已经插入过的图片
|
|
|
|
|
if image_key in self.inserted_images:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
# 当打字进度达到图片位置时插入图片
|
|
|
|
|
if self.displayed_chars >= image_info['start_pos'] and current_length >= image_info['start_pos']:
|
|
|
|
|
# 当打字进度达到图片位置时插入图片 - 修复条件,确保图片能显示
|
|
|
|
|
if (self.displayed_chars >= image_info['start_pos'] or
|
|
|
|
|
(self.displayed_chars >= max(1, image_info['start_pos'] - 20) and self.displayed_chars > 0)):
|
|
|
|
|
# 在图片位置插入图片
|
|
|
|
|
cursor = self.text_edit.textCursor()
|
|
|
|
|
|
|
|
|
|
# 计算图片应该插入的位置(相对于当前文本)
|
|
|
|
|
insert_position = min(image_info['start_pos'], current_length)
|
|
|
|
|
# 计算图片应该插入的位置(基于原始内容位置)
|
|
|
|
|
insert_position = image_info['start_pos']
|
|
|
|
|
|
|
|
|
|
# 确保插入位置有效
|
|
|
|
|
# 确保插入位置有效(不能超过当前显示内容长度)
|
|
|
|
|
if insert_position >= 0 and insert_position <= current_length:
|
|
|
|
|
cursor.setPosition(insert_position)
|
|
|
|
|
|
|
|
|
|
# 创建图片格式
|
|
|
|
|
image_format = QTextImageFormat()
|
|
|
|
|
|
|
|
|
|
# 加载图片数据
|
|
|
|
|
pixmap = QPixmap()
|
|
|
|
|
if pixmap.loadFromData(image_info['data']):
|
|
|
|
|
# 调整图片大小
|
|
|
|
|
scaled_pixmap = pixmap.scaled(200, 150, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
|
|
|
|
|
|
|
|
|
# 将图片保存到临时文件(使用更稳定的路径)
|
|
|
|
|
import tempfile
|
|
|
|
|
import os
|
|
|
|
|
temp_dir = tempfile.gettempdir()
|
|
|
|
|
|
|
|
|
|
# 确保文件名安全
|
|
|
|
|
safe_filename = "".join(c for c in image_info['filename'] if c.isalnum() or c in ('.', '_', '-'))
|
|
|
|
|
temp_file = os.path.join(temp_dir, safe_filename)
|
|
|
|
|
|
|
|
|
|
if scaled_pixmap.save(temp_file):
|
|
|
|
|
# 设置图片格式
|
|
|
|
|
image_format.setName(temp_file)
|
|
|
|
|
image_format.setWidth(200)
|
|
|
|
|
image_format.setHeight(150)
|
|
|
|
|
|
|
|
|
|
# 在光标位置插入图片
|
|
|
|
|
cursor.insertImage(image_format)
|
|
|
|
|
# 获取图片数据(优先使用typing_logic中的数据)
|
|
|
|
|
image_data = None
|
|
|
|
|
if hasattr(self.typing_logic, 'image_data') and image_info['filename'] in self.typing_logic.image_data:
|
|
|
|
|
image_data = self.typing_logic.image_data[image_info['filename']]
|
|
|
|
|
else:
|
|
|
|
|
image_data = image_info.get('data')
|
|
|
|
|
|
|
|
|
|
if image_data:
|
|
|
|
|
# 加载图片数据
|
|
|
|
|
pixmap = QPixmap()
|
|
|
|
|
if pixmap.loadFromData(image_data):
|
|
|
|
|
# 调整图片大小
|
|
|
|
|
scaled_pixmap = pixmap.scaled(200, 150, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
|
|
|
|
|
|
|
|
|
# 在图片后插入一个空格,让文字继续
|
|
|
|
|
cursor.insertText(" ")
|
|
|
|
|
# 将图片保存到临时文件(使用更稳定的路径)
|
|
|
|
|
import tempfile
|
|
|
|
|
import os
|
|
|
|
|
temp_dir = tempfile.gettempdir()
|
|
|
|
|
|
|
|
|
|
# 标记这张图片已经插入过
|
|
|
|
|
self.inserted_images.add(image_key)
|
|
|
|
|
# 确保文件名安全
|
|
|
|
|
safe_filename = "".join(c for c in image_info['filename'] if c.isalnum() or c in ('.', '_', '-'))
|
|
|
|
|
temp_file = os.path.join(temp_dir, safe_filename)
|
|
|
|
|
|
|
|
|
|
# 记录插入成功
|
|
|
|
|
print(f"图片 {image_info['filename']} 已在位置 {insert_position} 插入")
|
|
|
|
|
if scaled_pixmap.save(temp_file):
|
|
|
|
|
# 设置图片格式
|
|
|
|
|
image_format.setName(temp_file)
|
|
|
|
|
image_format.setWidth(200)
|
|
|
|
|
image_format.setHeight(150)
|
|
|
|
|
|
|
|
|
|
# 在光标位置插入图片
|
|
|
|
|
cursor.insertImage(image_format)
|
|
|
|
|
|
|
|
|
|
# 在图片后插入一个空格,让文字继续
|
|
|
|
|
cursor.insertText(" ")
|
|
|
|
|
|
|
|
|
|
# 标记这张图片已经插入过
|
|
|
|
|
self.inserted_images.add(image_key)
|
|
|
|
|
|
|
|
|
|
# 记录插入成功
|
|
|
|
|
print(f"图片 {image_info['filename']} 已在位置 {insert_position} 插入")
|
|
|
|
|
else:
|
|
|
|
|
print(f"保存临时图片文件失败: {temp_file}")
|
|
|
|
|
else:
|
|
|
|
|
print(f"保存临时图片文件失败: {temp_file}")
|
|
|
|
|
else:
|
|
|
|
|
print(f"加载图片数据失败: {image_info['filename']}")
|
|
|
|
|
print(f"加载图片数据失败: {image_info['filename']}")
|
|
|
|
|
|
|
|
|
|
# 重新设置光标到文本末尾
|
|
|
|
|
cursor.movePosition(cursor.End)
|
|
|
|
|
@ -1948,6 +2140,9 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
|
|
|
|
|
def closeEvent(self, event):
|
|
|
|
|
"""关闭事件处理"""
|
|
|
|
|
# 清理临时文件
|
|
|
|
|
self.cleanup_temp_files()
|
|
|
|
|
|
|
|
|
|
if self.is_modified:
|
|
|
|
|
reply = QMessageBox.question(
|
|
|
|
|
self, "确认退出",
|
|
|
|
|
@ -1965,6 +2160,18 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
else:
|
|
|
|
|
event.accept()
|
|
|
|
|
|
|
|
|
|
def cleanup_temp_files(self):
|
|
|
|
|
"""清理临时文件"""
|
|
|
|
|
import os
|
|
|
|
|
for temp_file in self.temp_files:
|
|
|
|
|
try:
|
|
|
|
|
if os.path.exists(temp_file):
|
|
|
|
|
os.remove(temp_file)
|
|
|
|
|
print(f"已删除临时文件: {temp_file}")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"删除临时文件失败 {temp_file}: {str(e)}")
|
|
|
|
|
self.temp_files.clear()
|
|
|
|
|
|
|
|
|
|
def extract_and_display_images(self, file_path):
|
|
|
|
|
"""提取并显示Word文档中的图片 - 修复图片位置计算"""
|
|
|
|
|
try:
|
|
|
|
|
@ -2009,15 +2216,33 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
item.setData(Qt.UserRole, filename)
|
|
|
|
|
self.image_list_widget.addItem(item)
|
|
|
|
|
|
|
|
|
|
# 为每张图片创建位置信息 - 更合理的分布
|
|
|
|
|
# 为每张图片创建位置信息 - 修复位置计算,确保早期显示
|
|
|
|
|
content_length = len(self.imported_content)
|
|
|
|
|
if content_length == 0:
|
|
|
|
|
content_length = len(content) if 'content' in locals() else 1000 # 备用长度
|
|
|
|
|
|
|
|
|
|
# 修复图片位置计算,确保图片能在用户早期打字时显示
|
|
|
|
|
if len(images) == 1:
|
|
|
|
|
# 只有一张图片,放在文档中间
|
|
|
|
|
start_pos = len(self.imported_content) // 2
|
|
|
|
|
# 只有一张图片,放在文档开始位置附近(前10%),确保用户能快速看到
|
|
|
|
|
start_pos = max(10, content_length // 10)
|
|
|
|
|
else:
|
|
|
|
|
# 多张图片,均匀分布
|
|
|
|
|
start_pos = (len(self.imported_content) * (index + 1)) // (len(images) + 1)
|
|
|
|
|
# 多张图片:前几张放在较前位置,确保用户能看到
|
|
|
|
|
if index < 3:
|
|
|
|
|
# 前3张图片放在文档前30%
|
|
|
|
|
segment = content_length // 3
|
|
|
|
|
start_pos = max(10, segment * (index + 1) // 4)
|
|
|
|
|
else:
|
|
|
|
|
# 其余图片均匀分布
|
|
|
|
|
remaining_start = content_length // 2
|
|
|
|
|
remaining_index = index - 3
|
|
|
|
|
remaining_count = len(images) - 3
|
|
|
|
|
if remaining_count > 0:
|
|
|
|
|
segment = (content_length - remaining_start) // (remaining_count + 1)
|
|
|
|
|
start_pos = remaining_start + segment * (remaining_index + 1)
|
|
|
|
|
else:
|
|
|
|
|
start_pos = content_length // 2
|
|
|
|
|
|
|
|
|
|
end_pos = min(start_pos + 50, len(self.imported_content))
|
|
|
|
|
end_pos = min(start_pos + 50, content_length)
|
|
|
|
|
|
|
|
|
|
image_positions.append({
|
|
|
|
|
'start_pos': start_pos,
|
|
|
|
|
@ -2029,6 +2254,15 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
# 设置图片位置信息到打字逻辑
|
|
|
|
|
if self.typing_logic:
|
|
|
|
|
self.typing_logic.set_image_positions(image_positions)
|
|
|
|
|
|
|
|
|
|
# 设置图片数据到打字逻辑
|
|
|
|
|
image_data_dict = {}
|
|
|
|
|
for filename, image_data in images:
|
|
|
|
|
image_data_dict[filename] = image_data
|
|
|
|
|
self.typing_logic.set_image_data(image_data_dict)
|
|
|
|
|
|
|
|
|
|
# 添加调试信息
|
|
|
|
|
print(f"已设置 {len(image_positions)} 个图片位置和 {len(image_data_dict)} 个图片数据到打字逻辑")
|
|
|
|
|
|
|
|
|
|
# 更新状态栏
|
|
|
|
|
self.status_bar.showMessage(f"已提取 {len(images)} 张图片,双击查看大图", 5000)
|
|
|
|
|
|