feat: replace with control

This commit is contained in:
zzs 2025-03-27 15:16:04 +08:00
parent ca9bb2771c
commit b835ed6cb3

View File

@ -1,5 +1,6 @@
import json import json
def Replace(bookmark_name_value_map): def Replace(bookmark_name_value_map):
""" """
替换所有书签 替换所有书签
@ -16,6 +17,21 @@ def Replace(bookmark_name_value_map):
anchor.setString(new_value) anchor.setString(new_value)
def ReplaceOne(bookmark_obj_collection, bookmark_name, new_value):
"""
替换一个书签
Args:
bookmark_obj_collection: 书签对象集合
bookmark_name: 书签名称
new_value: 新值
"""
if bookmark_obj_collection.hasByName(bookmark_name):
bookmark = bookmark_obj_collection.getByName(bookmark_name)
anchor = bookmark.getAnchor()
anchor.setString(new_value)
def ReplaceWithJSON(json_str): def ReplaceWithJSON(json_str):
""" """
替换所有书签 替换所有书签
@ -27,22 +43,6 @@ def ReplaceWithJSON(json_str):
Replace(bookmark_name_value_map) Replace(bookmark_name_value_map)
def DebugCallReplace():
"""
调试调用
"""
Replace({"合同编号_A": "11111", "合同名称_A": "11111"})
def DebugCallReplaceList():
"""
调试调用替换list
"""
Replace({"list": "1\r2\r3\r4"})
def QueryAll(): def QueryAll():
""" """
查询所有书签表格中的书签获取对应表格index 查询所有书签表格中的书签获取对应表格index
@ -78,39 +78,61 @@ def QueryAll():
def QueryAllWithJSON(): def QueryAllWithJSON():
return returnWithJSON(QueryAll()) return returnWithJSON(QueryAll())
def QueryBookmarkPositionInTable(tables, bookmarks): def QueryBookmarkPositionInTable(tables, bookmarks):
""" """
查询书签在表格中的位置 查询书签在表格中的位置
{'bk1': {'tableIndex': 0, 'row': 0, 'col': 0}, 'bk2': {'tableIndex': 0, 'row': 0, 'col': 2}}
参数:
tables: 表格集合 (XIndexAccess)
bookmarks: 书签集合 (XIndexAccess)
返回:
一个字典格式为 {'书签名': {'tableIndex': 表格索引, 'row': 行号}}
""" """
result = {}
bookmark_names = bookmarks.getElementNames() # 遍历所有书签
for b in range(bookmarks.getCount()):
bookmark = bookmarks.getByIndex(b)
bookmark_name = bookmark.getName()
x_range = bookmark.getAnchor() # 获取书签的锚点
x_text = x_range.getText() # 获取书签所在的文本对象
bookmark_position = {} # 遍历所有表格
for t in range(tables.getCount()):
table = tables.getByIndex(t)
for table_index in range(tables.getCount()): # 遍历表格中的每一行
table = tables.getByIndex(table_index) rows = table.getRows().getCount()
for i in range(rows):
# 动态确定当前行的最大列数
max_cols = 0
while True:
try:
cell = table.getCellByPosition(max_cols, i)
max_cols += 1
except Exception:
break
col_count = table.getColumns().getCount() for j in range(max_cols):
row_count = table.getRows().getCount() cell = table.getCellByPosition(j, i)
cell_text = cell.getText()
for row in range(row_count): if cell_text == x_text:
for col in range(col_count): result[bookmark_name] = {
cell = table.getCellByPosition(col, row) 'tableIndex': t,
cell_text_obj = cell.getText() 'row': i,
'col': j
for bk_name in bookmark_names:
bookmark_obj = bookmarks.getByName(bk_name)
bookmark_text_obj = bookmark_obj.getAnchor().getText()
if cell_text_obj == bookmark_text_obj:
bookmark_position[bk_name] = {
"tableIndex": table_index,
"col": col,
"row": row,
} }
break
else:
continue
break
else:
continue
break
return bookmark_position return result
def InsertRowWithJSON(json_str): def InsertRowWithJSON(json_str):
""" """
@ -151,9 +173,6 @@ def InsertRow(location_bookmark_name, data, start_row_index=-1):
if not data or len(data) == 0: if not data or len(data) == 0:
return return
if any(len(row) != col_count for row in data):
raise ValueError(f"数据列数不匹配,表格有 {col_count}")
try: try:
row_count = handle_table.getRows().getCount() row_count = handle_table.getRows().getCount()
rows_to_insert = len(data) rows_to_insert = len(data)
@ -178,7 +197,6 @@ def InsertRow(location_bookmark_name, data, start_row_index=-1):
except Exception as e: except Exception as e:
raise RuntimeError(f"err: {str(e)}") raise RuntimeError(f"err: {str(e)}")
def BatchInsertRowWithContentControl(data_array): def BatchInsertRowWithContentControl(data_array):
""" """
批量插入行 批量插入行
@ -210,8 +228,8 @@ def BatchInsertRowWithContentControl(data_array):
if not data or len(data) == 0: if not data or len(data) == 0:
return return
if any(len(row) != col_count for row in data): # if any(len(row) != col_count for row in data):
raise ValueError(f"数据列数不匹配,表格有 {col_count}") # raise ValueError(f"数据列数不匹配,表格有 {col_count} 列")
try: try:
row_count = handle_table.getRows().getCount() row_count = handle_table.getRows().getCount()
@ -233,28 +251,28 @@ def BatchInsertRowWithContentControl(data_array):
for col_idx, cell_value in enumerate(row_data): for col_idx, cell_value in enumerate(row_data):
cell = handle_table.getCellByPosition(col_idx, target_row) cell = handle_table.getCellByPosition(col_idx, target_row)
cell_text = cell.getText() cell_text = cell.getText()
# === 清空单元格 === # === 清空单元格 ===
cell_text.setString("") cell_text.setString("")
# === 创建内容控件 === # === 创建内容控件 ===
content_control = doc.createInstance("com.sun.star.text.ContentControl") content_control = doc.createInstance(
"com.sun.star.text.ContentControl"
)
# === 插入控件到单元格 === # === 插入控件到单元格 ===
cursor = cell_text.createTextCursor() cursor = cell_text.createTextCursor()
cell_text.insertTextContent(cursor, content_control, False) cell_text.insertTextContent(cursor, content_control, False)
# === 设置控件内容 === # === 设置控件内容 ===
cc_text = content_control.getText() cc_text = content_control.getText()
cc_cursor = cc_text.createTextCursor() cc_cursor = cc_text.createTextCursor()
cc_cursor.setString(str(cell_value)) cc_cursor.setString(str(cell_value))
except Exception as e: except Exception as e:
raise RuntimeError(f"插入行时发生错误: {str(e)}") raise RuntimeError(f"插入行时发生错误: {str(e)}")
def BatchInsertRow(data_array): def BatchInsertRow(data_array):
""" """
批量插入行 批量插入行
@ -314,6 +332,7 @@ def BatchInsertRow(data_array):
except Exception as e: except Exception as e:
raise RuntimeError(f"插入行时发生错误: {str(e)}") raise RuntimeError(f"插入行时发生错误: {str(e)}")
def DeleteRowWithJSON(json_str): def DeleteRowWithJSON(json_str):
""" """
删除行 删除行
@ -360,6 +379,7 @@ def DeleteRow(location_bookmark_name, start_row_index, delete_row_count=-1):
except Exception as e: except Exception as e:
raise RuntimeError(f"err: {str(e)}") raise RuntimeError(f"err: {str(e)}")
def LocateBookmark(bookmark_name): def LocateBookmark(bookmark_name):
""" """
定位书签并选中内容 定位书签并选中内容
@ -479,6 +499,7 @@ def DeleteBookmark(bookmark_name):
except Exception as e: except Exception as e:
pass pass
def CreateTable(location_bookmark_name, data): def CreateTable(location_bookmark_name, data):
""" """
创建表格 创建表格
@ -499,8 +520,8 @@ def ReplaceTextAndInsertTableRow(json_str):
def ReplaceTextAndInsertTableRowWithContentControl(json_str): def ReplaceTextAndInsertTableRowWithContentControl(json_str):
data = json.loads(json_str) data = json.loads(json_str)
# BatchInsertRowWithContentControl(data["table"])
ReplaceBookmarksWithControls(data["text"]) ReplaceBookmarksWithControls(data["text"])
BatchInsertRowWithContentControl(data["table"])
def returnWithJSON(data): def returnWithJSON(data):
@ -525,53 +546,58 @@ def SaveDocument():
return False return False
def DebugCallReplaceBookmarksWithControls():
ReplaceBookmarksWithControls({"合同编号_A": "11111", "合同名称_A": "22222"})
def ReplaceBookmarksWithControls(bookmark_name_value_map={}): def ReplaceBookmarksWithControls(bookmark_name_value_map={}):
# 获取文档对象
doc = XSCRIPTCONTEXT.getDocument() doc = XSCRIPTCONTEXT.getDocument()
bookmarks = doc.getBookmarks() bookmarks = doc.getBookmarks()
for i in reversed(range(bookmarks.getCount())): # 过滤包含下划线前缀的书签
bookmark = bookmarks.getByIndex(i) bookmark_names = [name for name in bookmarks.getElementNames() if not name.startswith("_")]
name = bookmark.getName()
anchor = bookmark.getAnchor() # 遍历所有需要处理的书签
if not anchor: for name in bookmark_names:
continue try:
# 检查书签是否存在
if not bookmarks.hasByName(name):
continue
# 获取书签对象及其锚点
bookmark = bookmarks.getByName(name)
anchor = bookmark.getAnchor()
# 获取书签的原始内容
original_text = anchor.getString()
replace_value = bookmark_name_value_map.get(name, original_text)
# === 第1步创建内容控件 ===
content_control = doc.createInstance("com.sun.star.text.ContentControl")
# 获取书签所在文本对象并清空原内容
text = anchor.getText()
anchor.setString("")
# 插入内容控件
text.insertTextContent(anchor, content_control, True)
# 设置控件内容
cc_cursor = content_control.getText().createTextCursor()
cc_cursor.setString(replace_value)
# === 第2步清理旧书签 ===
bookmark.dispose()
# === 第3步创建新书签 ===
cc_anchor = content_control.getText().getAnchor()
new_bookmark = doc.createInstance("com.sun.star.text.Bookmark")
new_bookmark.setName(name)
new_bookmark.attach(cc_anchor)
original_text = anchor.getString() except Exception as e:
replace_value = bookmark_name_value_map.get(name, original_text) print(f"处理书签 '{name}' 时出错: {e}")
# === 第1步创建内容控件 ===
content_control = doc.createInstance("com.sun.star.text.ContentControl")
# 获取书签所在文本对象
text = anchor.getText()
anchor.setString("")
# # 创建游标并清空原内容
# 插入内容控件
text.insertTextContent(anchor, content_control, True)
# 设置控件内容
cc_cursor = content_control.getText().createTextCursor()
cc_cursor.setString(replace_value)
# === 第1步清理旧书签 ===
bookmark.dispose()
# === 第2步创建新书签 ===
# 获取控件实际范围
cc_anchor = content_control.getText().getAnchor()
new_bookmark = doc.createInstance("com.sun.star.text.Bookmark")
new_bookmark.setName(name)
new_bookmark.attach(cc_anchor)
def NextEditableZone(current_index): def NextEditableZone(current_index):
""" """
根据索引定位可编辑的内容控件支持循环 根据索引定位名称包含'permission'的书签支持循环
Args: Args:
current_index (int/str): 0 开始的索引支持字符串或整数类型 current_index (int/str): 0 开始的索引支持字符串或整数类型
""" """
@ -586,33 +612,49 @@ def NextEditableZone(current_index):
controller = doc.getCurrentController() controller = doc.getCurrentController()
view_cursor = controller.getViewCursor() view_cursor = controller.getViewCursor()
# 收集所有内容控件的锚点 bookmarks = doc.getBookmarks()
text_content = doc.getText().createEnumeration() bookmark_names = bookmarks.getElementNames()
editable_anchors = []
while text_content.hasMoreElements():
element = text_content.nextElement()
# 关键修改点:检查内容控件服务
if element.supportsService("com.sun.star.text.ContentControl"):
try:
anchor = element.getAnchor()
editable_anchors.append(anchor)
except Exception:
continue
# 无控件时直接返回 # 过滤包含permission的书签不区分大小写
permission_bookmarks = [name for name in bookmark_names if not name.startswith("_")]
editable_anchors = []
for bm_name in permission_bookmarks:
try:
bookmark = bookmarks.getByName(bm_name)
anchor = bookmark.getAnchor()
editable_anchors.append(anchor)
except Exception as e:
print(f"err '{bm_name}' e: {e}")
continue
# 无匹配书签时直接返回
if not editable_anchors: if not editable_anchors:
print("文档中未找到内容控件")
return return
# 计算有效索引(循环逻辑) # 计算有效索引(循环逻辑)
total = len(editable_anchors) total = len(editable_anchors)
effective_index = current_index % total # 自动处理越界 effective_index = current_index % total # 自动处理越界
# 定位到目标控件 # 定位到目标书签
target_anchor = editable_anchors[effective_index] target_anchor = editable_anchors[effective_index]
view_cursor.gotoRange(target_anchor.getStart(), False) # 跳转到控件起始位置
controller.select(target_anchor) # 选中整个控件范围
try:
# 跳转到书签起始位置
view_cursor.gotoRange(target_anchor, False)
# 选中整个书签范围
controller.select(target_anchor)
# 窗口可见性处理
try:
window = controller.getFrame().getContainerWindow()
window.setVisible(True)
window.toFront()
except Exception:
pass
except Exception as e:
raise RuntimeError(f"err: {str(e)}") from e
g_exportedScripts = ( g_exportedScripts = (
@ -625,11 +667,8 @@ g_exportedScripts = (
DeleteRow, DeleteRow,
DeleteRowWithJSON, DeleteRowWithJSON,
ReplaceTextAndInsertTableRow, ReplaceTextAndInsertTableRow,
DebugCallReplace,
DebugCallReplaceList,
ReplaceBookmarksWithControls, ReplaceBookmarksWithControls,
ReplaceTextAndInsertTableRowWithContentControl, ReplaceTextAndInsertTableRowWithContentControl,
DebugCallReplaceBookmarksWithControls,
SaveDocument, SaveDocument,
NextEditableZone, NextEditableZone,
) )