From b835ed6cb357a02463543a9cf821e09935b7d626 Mon Sep 17 00:00:00 2001 From: zzs Date: Thu, 27 Mar 2025 15:16:04 +0800 Subject: [PATCH] feat: replace with control --- BookmarkOP.py | 265 +++++++++++++++++++++++++++++--------------------- 1 file changed, 152 insertions(+), 113 deletions(-) diff --git a/BookmarkOP.py b/BookmarkOP.py index d50d52f..ee127bd 100644 --- a/BookmarkOP.py +++ b/BookmarkOP.py @@ -1,5 +1,6 @@ import json + def Replace(bookmark_name_value_map): """ 替换所有书签 @@ -16,6 +17,21 @@ def Replace(bookmark_name_value_map): 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): """ 替换所有书签 @@ -27,22 +43,6 @@ def ReplaceWithJSON(json_str): Replace(bookmark_name_value_map) -def DebugCallReplace(): - """ - 调试调用 - """ - - Replace({"合同编号_A": "11111", "合同名称_A": "11111"}) - - -def DebugCallReplaceList(): - """ - 调试调用,替换list - """ - - Replace({"list": "1\r2\r3\r4"}) - - def QueryAll(): """ 查询所有书签,表格中的书签获取对应表格index @@ -78,39 +78,61 @@ def QueryAll(): def QueryAllWithJSON(): return returnWithJSON(QueryAll()) - 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() - row_count = table.getRows().getCount() + for j in range(max_cols): + cell = table.getCellByPosition(j, i) + cell_text = cell.getText() - 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, + if cell_text == x_text: + result[bookmark_name] = { + 'tableIndex': t, + 'row': i, + 'col': j } + break + else: + continue + break + else: + continue + break - return bookmark_position + return result 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: 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) @@ -178,7 +197,6 @@ def InsertRow(location_bookmark_name, data, start_row_index=-1): except Exception as e: raise RuntimeError(f"err: {str(e)}") - def BatchInsertRowWithContentControl(data_array): """ 批量插入行 @@ -210,8 +228,8 @@ def BatchInsertRowWithContentControl(data_array): if not data or len(data) == 0: return - if any(len(row) != col_count for row in data): - raise ValueError(f"数据列数不匹配,表格有 {col_count} 列") + # if any(len(row) != col_count for row in data): + # raise ValueError(f"数据列数不匹配,表格有 {col_count} 列") try: row_count = handle_table.getRows().getCount() @@ -233,28 +251,28 @@ def BatchInsertRowWithContentControl(data_array): for col_idx, cell_value in enumerate(row_data): cell = handle_table.getCellByPosition(col_idx, target_row) cell_text = cell.getText() - + # === 清空单元格 === 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() cell_text.insertTextContent(cursor, content_control, False) - + # === 设置控件内容 === cc_text = content_control.getText() cc_cursor = cc_text.createTextCursor() cc_cursor.setString(str(cell_value)) - - + except Exception as e: raise RuntimeError(f"插入行时发生错误: {str(e)}") - def BatchInsertRow(data_array): """ 批量插入行 @@ -314,6 +332,7 @@ def BatchInsertRow(data_array): except Exception as e: raise RuntimeError(f"插入行时发生错误: {str(e)}") + def DeleteRowWithJSON(json_str): """ 删除行 @@ -360,6 +379,7 @@ def DeleteRow(location_bookmark_name, start_row_index, delete_row_count=-1): except Exception as e: raise RuntimeError(f"err: {str(e)}") + def LocateBookmark(bookmark_name): """ 定位书签并选中内容 @@ -479,6 +499,7 @@ def DeleteBookmark(bookmark_name): except Exception as e: pass + def CreateTable(location_bookmark_name, data): """ 创建表格 @@ -499,8 +520,8 @@ def ReplaceTextAndInsertTableRow(json_str): def ReplaceTextAndInsertTableRowWithContentControl(json_str): data = json.loads(json_str) + # BatchInsertRowWithContentControl(data["table"]) ReplaceBookmarksWithControls(data["text"]) - BatchInsertRowWithContentControl(data["table"]) def returnWithJSON(data): @@ -525,53 +546,58 @@ def SaveDocument(): return False -def DebugCallReplaceBookmarksWithControls(): - ReplaceBookmarksWithControls({"合同编号_A": "11111", "合同名称_A": "22222"}) - - def ReplaceBookmarksWithControls(bookmark_name_value_map={}): + # 获取文档对象 doc = XSCRIPTCONTEXT.getDocument() bookmarks = doc.getBookmarks() - for i in reversed(range(bookmarks.getCount())): - bookmark = bookmarks.getByIndex(i) - name = bookmark.getName() - anchor = bookmark.getAnchor() - if not anchor: - continue + # 过滤包含下划线前缀的书签 + bookmark_names = [name for name in bookmarks.getElementNames() if not name.startswith("_")] + + # 遍历所有需要处理的书签 + for name in bookmark_names: + 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() - 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) - - # === 第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) + except Exception as e: + print(f"处理书签 '{name}' 时出错: {e}") def NextEditableZone(current_index): """ - 根据索引定位可编辑的内容控件(支持循环) + 根据索引定位名称包含'permission'的书签(支持循环) Args: current_index (int/str): 从 0 开始的索引,支持字符串或整数类型 """ @@ -586,33 +612,49 @@ def NextEditableZone(current_index): controller = doc.getCurrentController() view_cursor = controller.getViewCursor() - # 收集所有内容控件的锚点 - text_content = doc.getText().createEnumeration() - 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 + bookmarks = doc.getBookmarks() + bookmark_names = bookmarks.getElementNames() - # 无控件时直接返回 + # 过滤包含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: - print("文档中未找到内容控件") return # 计算有效索引(循环逻辑) total = len(editable_anchors) effective_index = current_index % total # 自动处理越界 - # 定位到目标控件 + # 定位到目标书签 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 = ( @@ -625,11 +667,8 @@ g_exportedScripts = ( DeleteRow, DeleteRowWithJSON, ReplaceTextAndInsertTableRow, - DebugCallReplace, - DebugCallReplaceList, ReplaceBookmarksWithControls, ReplaceTextAndInsertTableRowWithContentControl, - DebugCallReplaceBookmarksWithControls, SaveDocument, NextEditableZone, )