upd
This commit is contained in:
@@ -268,6 +268,12 @@ class PreviewTextBox(MessageBoxBase):
|
||||
self._id = _id
|
||||
self.isChanged = False
|
||||
|
||||
# 初始化关键变量
|
||||
self.isContentSaved = False # 明确初始化保存状态
|
||||
self.httpd = None # 服务器实例引用
|
||||
self.server_thread = None # 服务器线程引用
|
||||
self.tempFilePath = None # 临时文件路径
|
||||
|
||||
# 设置编辑器HTML文件路径 - 修正为项目根目录的_internal文件夹
|
||||
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
self.editor_index = os.path.join(project_root, "_internal/editor_main/index.html")
|
||||
@@ -348,7 +354,10 @@ class PreviewTextBox(MessageBoxBase):
|
||||
)
|
||||
# 隐藏进度条
|
||||
self.saveProgressBar.hide()
|
||||
QTimer.singleShot(700, self.accept)
|
||||
|
||||
# 直接调用accept()关闭窗口,不再使用定时器延迟
|
||||
# 确保窗口立即关闭并返回成功结果
|
||||
self.accept()
|
||||
|
||||
def _errorSave(self, msg):
|
||||
logger.error(f"文本文件保存失败,文件ID: {self._id}, 错误: {msg}")
|
||||
@@ -432,14 +441,9 @@ class PreviewTextBox(MessageBoxBase):
|
||||
|
||||
def setTextContent(self, content):
|
||||
"""设置文本内容并在外部浏览器中打开"""
|
||||
# 检查内容是否已保存,如果已保存则不允许再次编辑
|
||||
if hasattr(self, 'isContentSaved') and self.isContentSaved:
|
||||
logger.warning("内容已保存,不允许再次编辑")
|
||||
self.placeholderLabel.setText('''<div style='text-align:center; padding:20px;'>
|
||||
<h3>已经保存</h3>
|
||||
<p>该内容已经保存,不再允许编辑</p>
|
||||
</div>''')
|
||||
return
|
||||
# 每次打开文件时都重置isContentSaved状态为False,允许重新编辑
|
||||
self.isContentSaved = False
|
||||
logger.info(f"重置isContentSaved为False,文件ID: {self._id}")
|
||||
|
||||
logger.info(f"文本文件加载成功,原始内容长度: {len(content)}字符")
|
||||
|
||||
@@ -563,10 +567,10 @@ class PreviewTextBox(MessageBoxBase):
|
||||
attempts = 0
|
||||
while attempts < max_attempts:
|
||||
try:
|
||||
# 设置处理器的实例引用
|
||||
EditorHTTPRequestHandler.preview_box_instance = self
|
||||
# 使用自定义处理器创建服务器
|
||||
self.httpd = ReuseTCPServer(("127.0.0.1", port), EditorHTTPRequestHandler)
|
||||
# 保存当前实例的引用,以便处理器可以访问
|
||||
self.httpd.RequestHandlerClass.preview_box_instance = self
|
||||
logger.info(f"Web服务器成功在端口 {port} 启动")
|
||||
break
|
||||
except OSError as e:
|
||||
@@ -616,87 +620,44 @@ class PreviewTextBox(MessageBoxBase):
|
||||
self.pollingTimer.start()
|
||||
|
||||
def _checkBrowserContent(self):
|
||||
"""检查浏览器是否已保存内容"""
|
||||
# 首先尝试从localStorage读取
|
||||
try:
|
||||
import json
|
||||
import os
|
||||
import base64
|
||||
|
||||
# 尝试获取localStorage数据
|
||||
# 在Windows上,localStorage通常存储在用户的AppData目录中
|
||||
# 由于直接访问localStorage有困难,我们使用一个更可靠的方法:
|
||||
# 1. 首先检查临时文件
|
||||
if self.tempFilePath and os.path.exists(self.tempFilePath):
|
||||
try:
|
||||
with open(self.tempFilePath, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
if data.get('saved', False):
|
||||
logger.info("检测到浏览器已保存内容(通过临时文件)")
|
||||
self._processSavedContent(data)
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"读取临时文件失败: {e}")
|
||||
|
||||
# 2. 作为备用方案,检查是否有特定的保存文件
|
||||
# 这个文件可以由浏览器通过特定的方法创建
|
||||
import tempfile
|
||||
app_data_dir = os.path.join(tempfile.gettempdir(), 'LeonPan')
|
||||
os.makedirs(app_data_dir, exist_ok=True)
|
||||
save_file_path = os.path.join(app_data_dir, 'editor_content.json')
|
||||
|
||||
if os.path.exists(save_file_path):
|
||||
try:
|
||||
with open(save_file_path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
if data.get('saved', False):
|
||||
logger.info("检测到浏览器已保存内容(通过备用文件)")
|
||||
self._processSavedContent(data)
|
||||
# 删除备用文件
|
||||
os.unlink(save_file_path)
|
||||
except Exception as e:
|
||||
logger.error(f"读取备用保存文件失败: {e}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"检查浏览器内容时出错: {e}")
|
||||
"""检查浏览器是否已保存内容 - 现在仅作为备用方案"""
|
||||
# 由于我们使用POST请求直接传递内容,这里不再需要轮询检查文件
|
||||
# 轮询可以保留作为备用方案,但主要保存机制是通过POST请求
|
||||
pass
|
||||
|
||||
def _processSavedContent(self, data):
|
||||
"""处理已保存的内容"""
|
||||
# 停止轮询
|
||||
self.pollingTimer.stop()
|
||||
logger.info(f"开始处理保存的内容,文件ID: {self._id}")
|
||||
|
||||
# 更新内容
|
||||
import base64
|
||||
encoded_content = data.get('content', '')
|
||||
try:
|
||||
self.editorContent = base64.b64decode(encoded_content).decode('utf-8')
|
||||
logger.info(f"内容解码成功,长度: {len(self.editorContent)}字符")
|
||||
except Exception as e:
|
||||
logger.error(f"解码内容失败: {e}")
|
||||
return
|
||||
|
||||
# 标记内容已保存
|
||||
self.isContentSaved = True
|
||||
# 不再标记为已保存,让_saveContent方法处理保存逻辑
|
||||
# 直接调用_saveContent方法保存内容到服务器,不再重置状态
|
||||
logger.info(f"调用_saveContent方法保存内容到服务器,文件ID: {self._id}")
|
||||
self._saveContent(self.editorContent)
|
||||
|
||||
# 更新占位符文本,显示已保存信息
|
||||
# 这里不再显示成功信息,因为_saveContent会通过_successSave方法显示
|
||||
# 也不再设置定时器重置状态,因为成功保存后窗口会直接关闭
|
||||
|
||||
def _resetSaveState(self):
|
||||
"""重置保存状态,允许再次编辑和保存"""
|
||||
self.isContentSaved = False
|
||||
logger.info(f"已重置保存状态,允许再次编辑和保存,文件ID: {self._id}")
|
||||
# 恢复默认的占位符文本
|
||||
self.placeholderLabel.setText('''<div style='text-align:center; padding:20px;'>
|
||||
<h3>已经保存</h3>
|
||||
<p>内容已从浏览器同步到应用并已保存</p>
|
||||
<p>该内容将不再允许编辑</p>
|
||||
<h3>文本编辑已在外部浏览器中打开</h3>
|
||||
<p><strong>重要提示:</strong>完成编辑后,请点击浏览器中的"保存并返回"按钮</p>
|
||||
<p>应用正在自动检测...</p>
|
||||
</div>''')
|
||||
|
||||
# 禁用保存按钮
|
||||
self.saveButton.setEnabled(False)
|
||||
|
||||
# 清理临时文件
|
||||
if self.tempFilePath and os.path.exists(self.tempFilePath):
|
||||
try:
|
||||
os.unlink(self.tempFilePath)
|
||||
self.tempFilePath = None
|
||||
except Exception as e:
|
||||
logger.error(f"删除临时文件失败: {e}")
|
||||
|
||||
|
||||
|
||||
def handleError(self, error_msg):
|
||||
@@ -741,15 +702,10 @@ class PreviewTextBox(MessageBoxBase):
|
||||
<script>
|
||||
let editor;
|
||||
|
||||
require.config({{ paths: {{ 'vs': './vs' }} }});
|
||||
require.config({ paths: { 'vs': './vs' } });
|
||||
require(['vs/editor/editor.main'], function() {{
|
||||
editor = monaco.editor.create(document.getElementById('container'), {{
|
||||
value: `{content.replace('`', '\\`')}`,
|
||||
}});
|
||||
// 重新获取编辑器实例以确保正确初始化
|
||||
setTimeout(() => {{
|
||||
editor = monaco.editor.getModels()[0] ? monaco.editor.getModels()[0].getContainerInfo().domNode.monacoEditor : null;
|
||||
}}, 100);'\\`'}}`,
|
||||
language: '{language}',
|
||||
theme: 'vs-dark',
|
||||
automaticLayout: true,
|
||||
@@ -760,7 +716,11 @@ class PreviewTextBox(MessageBoxBase):
|
||||
lineNumbers: 'on',
|
||||
readOnly: false,
|
||||
fontFamily: 'Consolas, "Microsoft YaHei", monospace'
|
||||
}});
|
||||
}});
|
||||
// 重新获取编辑器实例以确保正确初始化
|
||||
setTimeout(() => {{
|
||||
editor = monaco.editor.getModels()[0] ? monaco.editor.getModels()[0].getContainerInfo().domNode.monacoEditor : null;
|
||||
}}, 100);
|
||||
|
||||
// 添加内容变化监听器
|
||||
editor.onDidChangeModelContent(function() {{
|
||||
@@ -833,9 +793,40 @@ class PreviewTextBox(MessageBoxBase):
|
||||
|
||||
# JavaScript执行完成的处理已移除
|
||||
|
||||
def __del__(self):
|
||||
"""析构函数,确保清理资源"""
|
||||
# 停止轮询定时器
|
||||
self.pollingTimer.stop()
|
||||
|
||||
# 停止HTTP服务器
|
||||
if hasattr(self, 'httpd'):
|
||||
try:
|
||||
self.httpd.shutdown()
|
||||
self.httpd.server_close()
|
||||
logger.info("Web服务器已停止")
|
||||
except Exception as e:
|
||||
logger.warning(f"停止Web服务器时出错: {e}")
|
||||
|
||||
# 删除临时文件
|
||||
if hasattr(self, 'tempFilePath') and self.tempFilePath and os.path.exists(self.tempFilePath):
|
||||
try:
|
||||
os.unlink(self.tempFilePath)
|
||||
logger.info(f"临时文件已删除: {self.tempFilePath}")
|
||||
except Exception as e:
|
||||
logger.warning(f"删除临时文件失败: {e}")
|
||||
|
||||
def _saveContent(self, content):
|
||||
"""保存编辑器内容并提交修改"""
|
||||
logger.info(f"保存文本文件修改,文件ID: {self._id}")
|
||||
# 确保断开之前可能存在的连接,避免多次连接
|
||||
if hasattr(self, 'saveTextThread') and self.saveTextThread:
|
||||
try:
|
||||
self.saveTextThread.successUpdated.disconnect()
|
||||
self.saveTextThread.errorUpdated.disconnect()
|
||||
except:
|
||||
pass
|
||||
|
||||
# 创建新的保存线程
|
||||
self.saveTextThread = UpdateFileContentThread(
|
||||
self._id,
|
||||
content,
|
||||
|
||||
Reference in New Issue
Block a user