libreoffice-python-script/BookmarkOP.py

815 lines
27 KiB
Python
Raw Permalink Normal View History

2025-03-24 11:49:58 +08:00
import json
import base64
import io
from com.sun.star.beans import PropertyValue
2025-03-28 11:54:53 +08:00
import tempfile
import os
from com.sun.star.beans import PropertyValue
from uno import ByteSequence, systemPathToFileUrl
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER, AT_PARAGRAPH
2025-03-27 15:16:04 +08:00
2025-03-24 11:49:58 +08:00
def Replace(bookmark_name_value_map):
"""
替换所有书签
Args:
bookmark_name_value_map: 书签名称和新值的映射
"""
doc = XSCRIPTCONTEXT.getDocument()
bookmarks = doc.getBookmarks()
2025-03-27 10:13:08 +08:00
for bookmark_name, new_value in bookmark_name_value_map.items():
if bookmarks.hasByName(bookmark_name):
bookmark = bookmarks.getByName(bookmark_name)
anchor = bookmark.getAnchor()
anchor.setString(new_value)
2025-03-24 11:49:58 +08:00
2025-03-27 15:16:04 +08:00
def ReplaceOne(bookmark_obj_collection, bookmark_name, new_value):
2025-03-24 11:49:58 +08:00
"""
2025-03-27 15:16:04 +08:00
替换一个书签
2025-03-24 11:49:58 +08:00
Args:
2025-03-27 15:16:04 +08:00
bookmark_obj_collection: 书签对象集合
bookmark_name: 书签名称
new_value: 新值
2025-03-24 11:49:58 +08:00
"""
2025-03-27 15:16:04 +08:00
if bookmark_obj_collection.hasByName(bookmark_name):
bookmark = bookmark_obj_collection.getByName(bookmark_name)
anchor = bookmark.getAnchor()
anchor.setString(new_value)
2025-03-24 11:49:58 +08:00
2025-03-27 15:16:04 +08:00
def ReplaceWithJSON(json_str):
2025-03-24 11:49:58 +08:00
"""
2025-03-27 15:16:04 +08:00
替换所有书签
Args:
json_str: 书签名称和新值的映射的JSON字符串
2025-03-24 11:49:58 +08:00
"""
2025-03-27 15:16:04 +08:00
bookmark_name_value_map = json.loads(json_str)
Replace(bookmark_name_value_map)
2025-03-24 11:49:58 +08:00
2025-03-27 10:13:08 +08:00
2025-03-24 11:49:58 +08:00
def QueryAll():
"""
查询所有书签表格中的书签获取对应表格index
返回结果格式:
{
"text": [],
"table": [
{
"tableIndex": 表格索引,
"bookmark": [书签名称列表]
}
]
}
"""
doc = XSCRIPTCONTEXT.getDocument()
bookmarks = doc.getBookmarks()
bookmark_names = bookmarks.getElementNames()
2025-03-27 10:13:08 +08:00
filtered_bookmarks = [
bk_name
for bk_name in bookmark_names
if not bk_name.startswith("_") and ":" not in bk_name
]
2025-03-24 11:49:58 +08:00
result = {"text": [], "table": []}
for bk_name in filtered_bookmarks:
2025-03-24 18:23:13 +08:00
result["text"].append(bk_name)
2025-03-24 11:49:58 +08:00
return result
def QueryAllWithJSON():
return returnWithJSON(QueryAll())
def QueryBookmarkPositionInTable(tables, bookmarks):
"""
2025-03-27 15:16:04 +08:00
查询书签在表格中的位置
参数:
tables: 表格集合 (XIndexAccess)
bookmarks: 书签集合 (XIndexAccess)
返回:
一个字典格式为 {'书签名': {'tableIndex': 表格索引, 'row': 行号}}
"""
result = {}
# 遍历所有书签
for b in range(bookmarks.getCount()):
bookmark = bookmarks.getByIndex(b)
bookmark_name = bookmark.getName()
x_range = bookmark.getAnchor() # 获取书签的锚点
x_text = x_range.getText() # 获取书签所在的文本对象
# 遍历所有表格
for t in range(tables.getCount()):
table = tables.getByIndex(t)
# 遍历表格中的每一行
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
for j in range(max_cols):
cell = table.getCellByPosition(j, i)
cell_text = cell.getText()
if cell_text == x_text:
result[bookmark_name] = {
'tableIndex': t,
'row': i,
'col': j
2025-03-24 11:49:58 +08:00
}
2025-03-27 15:16:04 +08:00
break
else:
continue
break
else:
continue
break
2025-03-24 11:49:58 +08:00
2025-03-27 15:16:04 +08:00
return result
2025-03-24 11:49:58 +08:00
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} 对应的表格")
2025-03-27 10:13:08 +08:00
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
try:
2025-03-24 15:55:55 +08:00
row_count = handle_table.getRows().getCount()
rows_to_insert = len(data)
2025-03-27 10:13:08 +08:00
2025-03-24 15:55:55 +08:00
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 # 插入到表格末尾
2025-03-27 10:13:08 +08:00
2025-03-24 15:55:55 +08:00
# 批量插入所有新行
handle_table.getRows().insertByIndex(insert_pos, rows_to_insert)
2025-03-27 10:13:08 +08:00
2025-03-24 15:55:55 +08:00
# 填充数据到新插入的行
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-27 10:13:08 +08:00
2025-03-24 11:49:58 +08:00
except Exception as e:
2025-03-27 10:13:08 +08:00
raise RuntimeError(f"err: {str(e)}")
2025-03-26 11:09:42 +08:00
def BatchInsertRowWithContentControl(data_array):
"""
批量插入行
"""
doc = XSCRIPTCONTEXT.getDocument()
tables = doc.getTextTables()
bookmarks = doc.getBookmarks()
bookmark_in_table_position = QueryBookmarkPositionInTable(tables, bookmarks)
for arr_obj in data_array:
2025-03-27 10:13:08 +08:00
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
2025-03-26 11:09:42 +08:00
if location_bookmark_name not in bookmark_in_table_position:
raise ValueError(f"未找到书签 {location_bookmark_name} 对应的表格")
2025-03-27 10:13:08 +08:00
handle_table_index = bookmark_in_table_position[location_bookmark_name][
"tableIndex"
]
2025-03-26 11:09:42 +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
2025-03-27 15:16:04 +08:00
# if any(len(row) != col_count for row in data):
# raise ValueError(f"数据列数不匹配,表格有 {col_count} 列")
2025-03-26 11:09:42 +08:00
try:
row_count = handle_table.getRows().getCount()
rows_to_insert = len(data)
2025-03-27 10:13:08 +08:00
2025-03-26 11:09:42 +08:00
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 # 插入到表格末尾
2025-03-27 10:13:08 +08:00
2025-03-26 11:09:42 +08:00
# 批量插入所有新行
handle_table.getRows().insertByIndex(insert_pos, rows_to_insert)
2025-03-27 10:13:08 +08:00
2025-03-26 11:09:42 +08:00
# 填充数据到新插入的行
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_text = cell.getText()
2025-03-27 15:16:04 +08:00
2025-03-27 10:13:08 +08:00
# === 清空单元格 ===
cell_text.setString("")
2025-03-27 15:16:04 +08:00
2025-03-27 10:13:08 +08:00
# === 创建内容控件 ===
2025-03-27 15:16:04 +08:00
content_control = doc.createInstance(
"com.sun.star.text.ContentControl"
)
2025-03-27 10:13:08 +08:00
# === 插入控件到单元格 ===
2025-03-26 11:09:42 +08:00
cursor = cell_text.createTextCursor()
2025-03-27 10:13:08 +08:00
cell_text.insertTextContent(cursor, content_control, False)
2025-03-27 15:16:04 +08:00
2025-03-27 10:13:08 +08:00
# === 设置控件内容 ===
cc_text = content_control.getText()
cc_cursor = cc_text.createTextCursor()
cc_cursor.setString(str(cell_value))
2025-03-27 15:16:04 +08:00
2025-03-26 11:09:42 +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:
2025-03-27 10:13:08 +08:00
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} 对应的表格")
2025-03-27 10:13:08 +08:00
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
2025-03-28 11:54:53 +08:00
# 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)
2025-03-27 10:13:08 +08:00
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 # 插入到表格末尾
2025-03-27 10:13:08 +08:00
# 批量插入所有新行
handle_table.getRows().insertByIndex(insert_pos, rows_to_insert)
2025-03-27 10:13:08 +08:00
# 填充数据到新插入的行
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-27 10:13:08 +08:00
except Exception as e:
raise RuntimeError(f"插入行时发生错误: {str(e)}")
2025-03-27 15:16:04 +08:00
2025-03-24 14:51:09 +08:00
def DeleteRowWithJSON(json_str):
"""
删除行
"""
data = json.loads(json_str)
2025-03-27 10:13:08 +08:00
DeleteRow(
data["location_bookmark_name"],
data["start_row_index"],
data["delete_row_count"],
)
2025-03-24 14:51:09 +08:00
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: 删除的行数
"""
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} 对应的表格")
2025-03-27 10:13:08 +08:00
handle_table_index = bookmark_in_table_position[location_bookmark_name][
"tableIndex"
]
2025-03-25 10:33:49 +08:00
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:
2025-03-27 10:13:08 +08:00
raise RuntimeError(f"err: {str(e)}")
2025-03-24 11:49:58 +08:00
2025-03-27 15:16:04 +08:00
2025-03-24 11:49:58 +08:00
def LocateBookmark(bookmark_name):
"""
定位书签并选中内容
Args:
bookmark_name: 要定位的书签名称
"""
doc = XSCRIPTCONTEXT.getDocument()
if False == doc.getBookmarks().hasByName(bookmark_name):
2025-03-27 10:13:08 +08:00
return
2025-03-24 11:49:58 +08:00
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 InsertBookmark(bookmark_name):
"""
选中内容插入书签如果没有选中任何内容插入点书签
Args:
bookmark_name: 要插入的书签名称
"""
doc = XSCRIPTCONTEXT.getDocument()
controller = doc.getCurrentController()
2025-03-27 10:13:08 +08:00
2025-03-24 11:49:58 +08:00
# 获取当前选区
selection = controller.getSelection()
2025-03-27 10:13:08 +08:00
2025-03-24 11:49:58 +08:00
# 检查是否已存在同名书签,如果存在则先删除
bookmarks = doc.getBookmarks()
if bookmarks.hasByName(bookmark_name):
bookmarks.getByName(bookmark_name).dispose()
2025-03-27 10:13:08 +08:00
2025-03-24 11:49:58 +08:00
try:
# 创建书签
if selection.getCount() > 0:
# 尝试获取选区的第一个元素
range_to_bookmark = selection.getByIndex(0)
2025-03-27 10:13:08 +08:00
2025-03-24 11:49:58 +08:00
# 创建书签并附加到选区
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)
2025-03-27 10:13:08 +08:00
2025-03-24 11:49:58 +08:00
# 创建书签并附加到光标位置
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 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 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
2025-03-27 15:16:04 +08:00
2025-03-24 11:49:58 +08:00
def CreateTable(location_bookmark_name, data):
"""
创建表格
Args:
location_bookmark_name: 用于定位表格的书签
data: 二维数组用于填充表格数据
"""
2025-03-27 10:13:08 +08:00
def ReplaceTextAndInsertTableRow(json_str):
"""
替换文本和表格
"""
data = json.loads(json_str)
Replace(data["text"])
BatchInsertRow(data["table"])
2025-03-28 11:54:53 +08:00
ReplaceBookmarkWithImage(data["image"])
2025-03-27 10:13:08 +08:00
2025-03-26 11:09:42 +08:00
def ReplaceTextAndInsertTableRowWithContentControl(json_str):
data = json.loads(json_str)
Replace(data["text"])
2025-03-28 11:54:53 +08:00
ReplaceBookmarkWithImage(data["image"])
BatchInsertRowWithContentControl(data["table"])
2025-03-28 11:54:53 +08:00
ReplaceBookmarksWithControls({}, ExtractBookmarkNames(data))
2025-03-25 16:43:02 +08:00
2025-03-27 10:13:08 +08:00
2025-03-24 11:49:58 +08:00
def returnWithJSON(data):
return json.dumps(data, ensure_ascii=False)
2025-03-27 10:13:08 +08:00
2025-03-25 16:43:02 +08:00
def SaveDocument():
# 获取当前文档对象
model = XSCRIPTCONTEXT.getDocument()
2025-03-27 10:13:08 +08:00
2025-03-25 16:43:02 +08:00
try:
# 检查文档是否支持保存XStorable 接口)
from com.sun.star.frame import XStorable
2025-03-27 10:13:08 +08:00
2025-03-25 16:43:02 +08:00
xstorable = model.uno_getAdapter(XStorable)
2025-03-27 10:13:08 +08:00
2025-03-25 16:43:02 +08:00
# 调用保存方法(覆盖原文件)
xstorable.store()
return True
except Exception as e:
2025-03-26 11:09:42 +08:00
print("err:", e)
2025-03-25 16:43:02 +08:00
return False
2025-03-28 11:54:53 +08:00
def ReplaceBookmarksWithControls(bookmark_name_value_map={}, exclude_bookmark_names=[]):
2025-03-27 15:16:04 +08:00
# 获取文档对象
2025-03-25 16:43:02 +08:00
doc = XSCRIPTCONTEXT.getDocument()
bookmarks = doc.getBookmarks()
2025-03-26 11:09:42 +08:00
2025-03-27 15:16:04 +08:00
# 过滤包含下划线前缀的书签
bookmark_names = [name for name in bookmarks.getElementNames() if not name.startswith("_")]
# 遍历所有需要处理的书签
for name in bookmark_names:
try:
2025-03-28 11:54:53 +08:00
# 检查是否需要排除
if name in exclude_bookmark_names:
continue
2025-03-27 15:16:04 +08:00
# 检查书签是否存在
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)
2025-03-27 10:13:08 +08:00
2025-03-27 15:16:04 +08:00
except Exception as e:
print(f"处理书签 '{name}' 时出错: {e}")
2025-03-26 11:09:42 +08:00
def NextEditableZone(current_index):
"""
2025-03-27 15:16:04 +08:00
根据索引定位名称包含'permission'的书签支持循环
2025-03-26 11:09:42 +08:00
Args:
current_index (int/str): 0 开始的索引支持字符串或整数类型
"""
# 强制转换为整数 -----------------------------
try:
current_index = int(current_index)
except (ValueError, TypeError):
2025-03-27 10:13:08 +08:00
print(f"错误:无法将 {current_index} 转换为整数")
2025-03-26 11:09:42 +08:00
return
doc = XSCRIPTCONTEXT.getDocument()
controller = doc.getCurrentController()
view_cursor = controller.getViewCursor()
2025-03-27 15:16:04 +08:00
bookmarks = doc.getBookmarks()
bookmark_names = bookmarks.getElementNames()
# 过滤包含permission的书签不区分大小写
permission_bookmarks = [name for name in bookmark_names if not name.startswith("_")]
2025-03-26 11:09:42 +08:00
editable_anchors = []
2025-03-27 15:16:04 +08:00
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
2025-03-26 11:09:42 +08:00
2025-03-27 15:16:04 +08:00
# 无匹配书签时直接返回
2025-03-26 11:09:42 +08:00
if not editable_anchors:
return
# 计算有效索引(循环逻辑)
total = len(editable_anchors)
2025-03-27 10:13:08 +08:00
effective_index = current_index % total # 自动处理越界
2025-03-26 11:09:42 +08:00
2025-03-27 15:16:04 +08:00
# 定位到目标书签
2025-03-26 11:09:42 +08:00
target_anchor = editable_anchors[effective_index]
2025-03-27 15:16:04 +08:00
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
2025-03-25 16:43:02 +08:00
def ReplaceBookmarkWithImage(data_array):
2025-03-28 11:54:53 +08:00
"""
替换书签为图片同时保留书签
参数:
data_array: 包含书签和图片信息的字典数组
"""
# 获取当前文档和相关服务
doc = XSCRIPTCONTEXT.getDocument()
bookmarks = doc.getBookmarks()
smgr = XSCRIPTCONTEXT.getComponentContext().getServiceManager()
graphic_provider = smgr.createInstanceWithContext("com.sun.star.graphic.GraphicProvider", XSCRIPTCONTEXT.getComponentContext())
2025-03-28 11:54:53 +08:00
if not graphic_provider:
raise RuntimeError("无法初始化 GraphicProvider 服务")
for data in data_array:
bookmark_name = data["bookmarkName"]
image_data = data["imageData"]
width = data["width"]
height = data["height"]
file_type = data["fileType"]
2025-03-28 11:54:53 +08:00
# 检查书签是否存在
if bookmark_name not in bookmarks:
print(f"错误: 书签 '{bookmark_name}' 不存在")
continue
try:
# 解码 Base64 数据
image_bytes = base64.b64decode(image_data)
if not image_bytes:
raise ValueError("Base64 数据为空或无效")
# 获取书签的文本范围和光标
bookmark = bookmarks[bookmark_name]
text_range = bookmark.getAnchor()
text_cursor = text_range.getText().createTextCursorByRange(text_range)
2025-03-28 11:54:53 +08:00
# 记录书签位置并删除书签内容
text = text_range.getText()
text_cursor.setString("") # 删除书签范围内的文本
# 使用临时文件方式插入图片
temp_file_path = None
try:
with tempfile.NamedTemporaryFile(delete=False, suffix=f".{file_type}") as temp_file:
temp_file.write(image_bytes)
temp_file_path = temp_file.name
file_url = systemPathToFileUrl(temp_file_path)
url_prop = PropertyValue()
url_prop.Name = "URL"
url_prop.Value = file_url
2025-03-28 11:54:53 +08:00
graphic_properties = (url_prop,)
graphic = graphic_provider.queryGraphic(graphic_properties)
2025-03-28 11:54:53 +08:00
if not graphic:
raise RuntimeError(f"无法为书签 '{bookmark_name}' 生成图形对象")
2025-03-28 11:54:53 +08:00
# 创建图形对象
graphic_object = doc.createInstance("com.sun.star.text.TextGraphicObject")
graphic_object.Graphic = graphic
graphic_object.Width = width
graphic_object.Height = height
2025-03-28 11:54:53 +08:00
# 设置锚定方式
graphic_object.AnchorType = AS_CHARACTER # 锚定为字符
2025-03-28 11:54:53 +08:00
# 插入图片
text.insertTextContent(text_cursor, graphic_object, False)
if bookmark_name not in doc.getBookmarks():
# 重新创建书签以覆盖图片位置
bookmark_range = text.createTextCursorByRange(text_range)
new_bookmark = doc.createInstance("com.sun.star.text.Bookmark")
new_bookmark.Name = bookmark_name
text.insertTextContent(bookmark_range, new_bookmark, False)
finally:
# 清理临时文件
if temp_file_path and os.path.exists(temp_file_path):
os.unlink(temp_file_path)
except Exception as e:
continue
def ExtractBookmarkNames(data):
"""
data["image"] 数组中提取所有 bookmarkName组成一个字符串数组
参数:
data: 包含 "image" 键的字典其值为图片对象数组
返回:
list: 包含所有 bookmarkName 的字符串数组
"""
if "image" not in data or not isinstance(data["image"], list):
return []
2025-03-28 11:54:53 +08:00
# 使用列表推导式提取 bookmarkName
bookmark_names = [item["bookmarkName"] for item in data["image"] if "bookmarkName" in item]
return bookmark_names
def GetBookmarksInLists():
"""
返回文档中所有位于列表中的书签
Returns:
list: 位于列表中的书签名称列表
"""
doc = XSCRIPTCONTEXT.getDocument()
bookmarks = doc.getBookmarks()
bookmarks_in_lists = []
# 遍历所有书签
for bookmark in bookmarks:
bookmark_name = bookmark.getName()
anchor = bookmark.getAnchor()
# 判断书签的锚点是否在列表中
if anchor.supportsService("com.sun.star.text.Paragraph"):
paragraph = anchor
if paragraph.getPropertySetInfo().hasPropertyByName("NumberingStyleName"):
numbering_style = paragraph.getPropertyValue("NumberingStyleName")
if numbering_style:
bookmarks_in_lists.append(bookmark_name)
return bookmarks_in_lists
2025-03-25 16:43:02 +08:00
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-26 11:09:42 +08:00
ReplaceBookmarksWithControls,
ReplaceTextAndInsertTableRowWithContentControl,
SaveDocument,
2025-03-27 10:13:08 +08:00
NextEditableZone,
GetBookmarksInLists,
2025-03-24 11:49:58 +08:00
)