libreoffice-python-script/BookmarkOP.py

603 lines
18 KiB
Python
Raw Normal View History

2025-03-24 11:49:58 +08:00
import json
import time
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 ReplaceAll(bookmark_obj_collection, bookmark_name_value_map):
"""
替换所有书签
Args:
bookmark_obj_collection: 书签对象集合
bookmark_name_value_map: 书签名称和新值的映射
"""
for bookmark_name, new_value in bookmark_name_value_map.items():
ReplaceOne(bookmark_obj_collection, bookmark_name, new_value)
def Replace(bookmark_name_value_map):
"""
替换所有书签
Args:
bookmark_name_value_map: 书签名称和新值的映射
"""
doc = XSCRIPTCONTEXT.getDocument()
bookmarks = doc.getBookmarks()
ReplaceAll(bookmarks, bookmark_name_value_map)
def ReplaceWithJSON(json_str):
"""
替换所有书签
Args:
json_str: 书签名称和新值的映射的JSON字符串
"""
bookmark_name_value_map = json.loads(json_str)
Replace(bookmark_name_value_map)
def DebugCallReplace():
"""
调试调用
"""
2025-03-25 16:43:02 +08:00
Replace({"bb1": "P1", "bb2": "P2", "bb3": "P3", "bb4": "P4"})
2025-03-24 11:49:58 +08:00
def DebugCallReplaceList():
"""
调试调用替换list
"""
Replace({"list": "1\r2\r3\r4"})
def QueryAll():
"""
查询所有书签表格中的书签获取对应表格index
返回结果格式:
{
"text": [],
"table": [
{
"tableIndex": 表格索引,
"bookmark": [书签名称列表]
}
]
}
"""
doc = XSCRIPTCONTEXT.getDocument()
bookmarks = doc.getBookmarks()
bookmark_names = bookmarks.getElementNames()
filtered_bookmarks = [bk_name for bk_name in bookmark_names if '_' not in bk_name and ':' not in bk_name]
result = {"text": [], "table": []}
2025-03-24 18:23:13 +08:00
# tables = doc.getTextTables()
# bookmark_in_table_position = QueryBookmarkPositionInTable(tables, bookmarks)
2025-03-24 11:49:58 +08:00
existing_table_indices = {}
for bk_name in filtered_bookmarks:
2025-03-24 18:23:13 +08:00
# if bk_name in bookmark_in_table_position:
# table_index = bookmark_in_table_position[bk_name]["tableIndex"]
# if table_index in existing_table_indices:
# index = existing_table_indices[table_index]
# result["table"][index]["bookmark"].append(bk_name)
# else:
# new_entry = {"tableIndex": table_index, "bookmark": [bk_name]}
# result["table"].append(new_entry)
# existing_table_indices[table_index] = (
# len(result["table"]) - 1
# ) # 更新索引记录
# else:
result["text"].append(bk_name)
2025-03-24 11:49:58 +08:00
return result
def QueryAllWithJSON():
return returnWithJSON(QueryAll())
def QueryBookmarkPositionInTable(tables, bookmarks):
"""
查询书签在表格中的位置
{'bk1': {'tableIndex': 0, 'row': 0, 'col': 0}, 'bk2': {'tableIndex': 0, 'row': 0, 'col': 2}}
"""
bookmark_names = bookmarks.getElementNames()
bookmark_position = {}
for table_index in range(tables.getCount()):
table = tables.getByIndex(table_index)
col_count = table.getColumns().getCount()
row_count = table.getRows().getCount()
for row in range(row_count):
for col in range(col_count):
cell = table.getCellByPosition(col, row)
cell_text_obj = cell.getText()
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,
}
return bookmark_position
def CreateRow(table, row_count):
"""
创建表格行
"""
table.getRows().insertByIndex(table.getRows().getCount(), row_count)
def FindTableIndex(table_bookmarks, location_bookmark_name):
"""
找到表格索引
"""
handle_table_index = -1
for table_info in table_bookmarks:
if location_bookmark_name in table_info["bookmark"]:
handle_table_index = table_info["tableIndex"]
break
if handle_table_index == -1:
raise ValueError(f"未找到书签 {location_bookmark_name} 对应的表格")
return handle_table_index
2025-03-24 14:51:09 +08:00
def InsertRowWithJSON(json_str):
"""
插入行
"""
data = json.loads(json_str)
InsertRow(data["location_bookmark_name"], data["data"], data["start_row_index"])
2025-03-24 11:49:58 +08:00
def InsertRow(location_bookmark_name, data, start_row_index=-1):
"""
表格插入行
Args:
location_bookmark_name: 用于定位表格的书签
data: 二维数组用于填充表格数据
start_row_index: 起始行位置默认为-1即在表格末尾插入
"""
doc = XSCRIPTCONTEXT.getDocument()
tables = doc.getTextTables()
2025-03-25 10:33:49 +08:00
bookmarks = doc.getBookmarks()
bookmark_in_table_position = QueryBookmarkPositionInTable(tables, bookmarks)
if location_bookmark_name not in bookmark_in_table_position:
raise ValueError(f"未找到书签 {location_bookmark_name} 对应的表格")
handle_table_index = bookmark_in_table_position[location_bookmark_name]["tableIndex"]
2025-03-24 11:49:58 +08:00
try:
handle_table = tables.getByIndex(handle_table_index)
except IndexError:
raise IndexError(f"表格索引 {handle_table_index} 超出范围")
col_count = handle_table.getColumns().getCount()
row_count = handle_table.getRows().getCount()
if not data or len(data) == 0:
return
if any(len(row) != col_count for row in data):
raise ValueError(f"数据列数不匹配,表格有 {col_count}")
try:
2025-03-24 15:55:55 +08:00
row_count = handle_table.getRows().getCount()
rows_to_insert = len(data)
if rows_to_insert > 0:
# 确定插入位置
if start_row_index != -1 and 0 <= start_row_index < row_count:
insert_pos = start_row_index + 1 # 在指定行下方插入
2025-03-24 11:49:58 +08:00
else:
2025-03-24 15:55:55 +08:00
insert_pos = row_count # 插入到表格末尾
# 批量插入所有新行
handle_table.getRows().insertByIndex(insert_pos, rows_to_insert)
# 填充数据到新插入的行
for data_row_idx, row_data in enumerate(data):
target_row = insert_pos + data_row_idx # 计算目标行索引
for col_idx, cell_value in enumerate(row_data):
cell = handle_table.getCellByPosition(col_idx, target_row)
cell.setString(str(cell_value))
2025-03-24 11:49:58 +08:00
except Exception as e:
raise RuntimeError(f"插入行时发生错误: {str(e)}")
def BatchInsertRow(data_array):
"""
批量插入行
"""
doc = XSCRIPTCONTEXT.getDocument()
tables = doc.getTextTables()
bookmarks = doc.getBookmarks()
bookmark_in_table_position = QueryBookmarkPositionInTable(tables, bookmarks)
for arr_obj in data_array:
location_bookmark_name = arr_obj.get('location_bookmark_name')
data = arr_obj.get('data')
start_row_index = arr_obj.get('start_row_index', -1) # 默认值为 -1
if location_bookmark_name not in bookmark_in_table_position:
raise ValueError(f"未找到书签 {location_bookmark_name} 对应的表格")
handle_table_index = bookmark_in_table_position[location_bookmark_name]["tableIndex"]
try:
handle_table = tables.getByIndex(handle_table_index)
except IndexError:
raise IndexError(f"表格索引 {handle_table_index} 超出范围")
col_count = handle_table.getColumns().getCount()
row_count = handle_table.getRows().getCount()
if not data or len(data) == 0:
return
if any(len(row) != col_count for row in data):
raise ValueError(f"数据列数不匹配,表格有 {col_count}")
try:
row_count = handle_table.getRows().getCount()
rows_to_insert = len(data)
if rows_to_insert > 0:
# 确定插入位置
if start_row_index != -1 and 0 <= start_row_index < row_count:
insert_pos = start_row_index + 1 # 在指定行下方插入
else:
insert_pos = row_count # 插入到表格末尾
# 批量插入所有新行
handle_table.getRows().insertByIndex(insert_pos, rows_to_insert)
# 填充数据到新插入的行
for data_row_idx, row_data in enumerate(data):
target_row = insert_pos + data_row_idx # 计算目标行索引
for col_idx, cell_value in enumerate(row_data):
cell = handle_table.getCellByPosition(col_idx, target_row)
cell.setString(str(cell_value))
except Exception as e:
raise RuntimeError(f"插入行时发生错误: {str(e)}")
2025-03-24 11:49:58 +08:00
2025-03-24 18:23:13 +08:00
def InsertRowWithJSONDefineCol(json_str):
"""
插入行
"""
2025-03-24 11:49:58 +08:00
def DebugCallInsertRow():
"""
调试调用
"""
2025-03-25 10:33:49 +08:00
InsertRow("t1", [["1", "2"], ["4", "5"]], 0)
2025-03-24 11:49:58 +08:00
2025-03-24 14:51:09 +08:00
def DeleteRowWithJSON(json_str):
"""
删除行
"""
data = json.loads(json_str)
DeleteRow(data["location_bookmark_name"], data["start_row_index"], data["delete_row_count"])
def DeleteRow(location_bookmark_name, start_row_index, delete_row_count=-1):
2025-03-24 11:49:58 +08:00
"""
删除表格行
Args:
location_bookmark_name: 用于定位表格的书签
start_row_index: 起始行位置(删除行包含本行)
delete_row_count: 删除的行数
"""
2025-03-25 10:33:49 +08:00
# bookmark_info = QueryAll()
# table_bookmarks = bookmark_info["table"]
# handle_table_index = FindTableIndex(table_bookmarks, location_bookmark_name)
2025-03-24 11:49:58 +08:00
doc = XSCRIPTCONTEXT.getDocument()
tables = doc.getTextTables()
2025-03-25 10:33:49 +08:00
bookmarks = doc.getBookmarks()
bookmark_in_table_position = QueryBookmarkPositionInTable(tables, bookmarks)
if location_bookmark_name not in bookmark_in_table_position:
raise ValueError(f"未找到书签 {location_bookmark_name} 对应的表格")
handle_table_index = bookmark_in_table_position[location_bookmark_name]["tableIndex"]
2025-03-24 11:49:58 +08:00
handle_table = tables.getByIndex(handle_table_index)
row_count = handle_table.getRows().getCount()
if start_row_index < 0 or start_row_index >= row_count:
raise ValueError(f"起始行索引 {start_row_index} 超出范围")
2025-03-24 14:51:09 +08:00
# 如果未指定删除行数或超出范围,则删除剩余所有行
if start_row_index + delete_row_count > row_count or delete_row_count == -1:
delete_row_count = row_count - start_row_index
2025-03-24 11:49:58 +08:00
try:
handle_table.getRows().removeByIndex(start_row_index, delete_row_count)
except Exception as e:
raise RuntimeError(f"删除行时发生错误: {str(e)}")
def DebugCallDeleteRow():
"""
调试调用
"""
DeleteRow("h1", 1, 2)
def LocateBookmark(bookmark_name):
"""
定位书签并选中内容
Args:
bookmark_name: 要定位的书签名称
"""
doc = XSCRIPTCONTEXT.getDocument()
if False == doc.getBookmarks().hasByName(bookmark_name):
return
bookmark = doc.getBookmarks().getByName(bookmark_name)
try:
# 获取书签的文本范围锚点
anchor = bookmark.getAnchor()
# 获取文档控制器
controller = doc.getCurrentController()
# 将视图光标移动到书签位置并选中
view_cursor = controller.getViewCursor()
view_cursor.gotoRange(anchor, False) # False表示不扩展选区
# 如果需要高亮显示(可选)
controller.select(anchor)
# 确保窗口可见(针对隐藏窗口的情况)
try:
window = controller.getFrame().getContainerWindow()
window.setVisible(True)
window.toFront()
except Exception:
pass
except Exception as e:
raise RuntimeError(f"定位书签失败: {str(e)}") from e
def DebugCallLocateBookmarkLo1():
LocateBookmark("lo1")
def DebugCallLocateBookmarkLo2():
LocateBookmark("lo2")
def InsertBookmark(bookmark_name):
"""
选中内容插入书签如果没有选中任何内容插入点书签
Args:
bookmark_name: 要插入的书签名称
"""
doc = XSCRIPTCONTEXT.getDocument()
controller = doc.getCurrentController()
# 获取当前选区
selection = controller.getSelection()
# 检查是否已存在同名书签,如果存在则先删除
bookmarks = doc.getBookmarks()
if bookmarks.hasByName(bookmark_name):
bookmarks.getByName(bookmark_name).dispose()
try:
# 创建书签
if selection.getCount() > 0:
# 尝试获取选区的第一个元素
range_to_bookmark = selection.getByIndex(0)
# 创建书签并附加到选区
bookmark = doc.createInstance("com.sun.star.text.Bookmark")
bookmark.attach(range_to_bookmark)
bookmark.setName(bookmark_name)
else:
# 没有选中内容,创建点书签
cursor = controller.getViewCursor()
text_cursor = cursor.getText().createTextCursorByRange(cursor)
# 创建书签并附加到光标位置
bookmark = doc.createInstance("com.sun.star.text.Bookmark")
bookmark.attach(text_cursor)
bookmark.setName(bookmark_name)
except Exception as e:
raise RuntimeError(f"插入书签失败: {str(e)}") from e
def DebugCallInsertBookmark():
"""
调试调用
"""
InsertBookmark("bookmark_" + str(time.time()))
def UpdateBookmark(bookmark_name, new_value):
"""
修改书签名称通过删除旧书签 + 插入新书签实现
Args:
bookmark_name: 原书签名称
new_value: 新书签名称
"""
doc = XSCRIPTCONTEXT.getDocument()
bookmarks = doc.getBookmarks()
if not bookmarks.hasByName(bookmark_name):
raise ValueError(f"书签 '{bookmark_name}' 不存在")
if bookmarks.hasByName(new_value):
raise ValueError(f"书签 '{new_value}' 已存在")
# 获取旧书签的锚点位置
old_bookmark = bookmarks.getByName(bookmark_name)
old_bookmark.setName(new_value)
def DebugCallUpdateBookmark():
"""
调试调用
"""
UpdateBookmark("ole_bookmark", "new_bookmark")
def DeleteBookmark(bookmark_name):
"""
删除书签但保留内容通过断开书签与锚点的关联
"""
doc = XSCRIPTCONTEXT.getDocument()
bookmarks = doc.getBookmarks()
if not bookmarks.hasByName(bookmark_name):
return
bookmark = bookmarks.getByName(bookmark_name)
if hasattr(bookmark, "Anchor"):
try:
anchor = bookmark.Anchor
anchor.getText().removeTextContent(bookmark)
except Exception as e:
pass
def DebugCallDeleteBookmark():
"""
调试调用
"""
DeleteBookmark("remove_me")
def CreateTable(location_bookmark_name, data):
"""
创建表格
Args:
location_bookmark_name: 用于定位表格的书签
data: 二维数组用于填充表格数据
"""
def ReplaceTextAndInsertTableRow(json_str):
"""
替换文本和表格
"""
data = json.loads(json_str)
Replace(data["text"])
BatchInsertRow(data["table"])
2025-03-25 16:43:02 +08:00
model = XSCRIPTCONTEXT.getDocument()
controller = model.getCurrentController()
controller.refresh()
2025-03-24 11:49:58 +08:00
def returnWithJSON(data):
return json.dumps(data, ensure_ascii=False)
2025-03-25 16:43:02 +08:00
def SaveDocument():
# 获取当前文档对象
model = XSCRIPTCONTEXT.getDocument()
try:
# 检查文档是否支持保存XStorable 接口)
from com.sun.star.frame import XStorable
xstorable = model.uno_getAdapter(XStorable)
# 调用保存方法(覆盖原文件)
xstorable.store()
return True
except Exception as e:
print("保存失败:", e)
return False
def replace_bookmarks_with_controls():
doc = XSCRIPTCONTEXT.getDocument()
bookmarks = doc.getBookmarks()
controller = doc.getCurrentController()
for name in reversed([bm.getName() for bm in bookmarks]):
try:
bookmark = bookmarks.getByName(name)
anchor = bookmark.getAnchor()
# 获取书签内容
cursor = anchor.getText().createTextCursorByRange(anchor)
original_text = cursor.getString()
# 创建文本控件并设置内容
text_control = doc.createInstance("com.sun.star.text.TextField.Input")
text_control.setPropertyValue("Content", original_text)
# text_control.setPropertyValue("BookmarkName", name) # 正确属性名
# 替换原书签内容为控件
cursor.setString("")
anchor.getText().insertTextContent(cursor, text_control, False)
# 重新插入原书签到控件后
new_cursor = cursor.getText().createTextCursorByRange(cursor)
new_cursor.goRight(1, False)
doc.getBookmarks().addNew(name, new_cursor)
except Exception as e:
print(f"错误:{str(e)}")
2025-03-24 11:49:58 +08:00
g_exportedScripts = (
Replace,
ReplaceWithJSON,
QueryAll,
QueryAllWithJSON,
InsertRow,
2025-03-24 14:51:09 +08:00
InsertRowWithJSON,
2025-03-24 11:49:58 +08:00
DeleteRow,
2025-03-24 14:51:09 +08:00
DeleteRowWithJSON,
ReplaceTextAndInsertTableRow,
2025-03-24 11:49:58 +08:00
DebugCallReplace,
DebugCallReplaceList,
DebugCallInsertRow,
DebugCallDeleteRow,
DebugCallLocateBookmarkLo1,
DebugCallLocateBookmarkLo2,
DebugCallInsertBookmark,
DebugCallUpdateBookmark,
2025-03-25 16:43:02 +08:00
DebugCallDeleteBookmark,
replace_bookmarks_with_controls,
SaveDocument
2025-03-24 11:49:58 +08:00
)