/
OS-Worldaa05f6c
import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
class CalcTools:
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
@classmethod
def close_other_window(cls):
"""关闭除当前文档外的所有文档"""
# 获取所有打开的文档
components = cls.desktop.getComponents().createEnumeration()
current_url = cls.doc.getURL()
while components.hasMoreElements():
doc = components.nextElement()
if doc.getURL() != current_url: # 如果不是当前文档
doc.close(True) # True 表示保存更改
@classmethod
def maximize_window(cls):
"""
将窗口设置为工作区最大尺寸
使用工作区域大小(考虑任务栏等)
"""
window = cls.doc.getCurrentController().getFrame().getContainerWindow()
toolkit = window.getToolkit()
device = toolkit.createScreenCompatibleDevice(0, 0)
# 获取工作区域(排除任务栏等)
workarea = toolkit.getWorkArea()
# 设置窗口位置和大小为工作区域
window.setPosSize(workarea.X, workarea.Y, workarea.Width, workarea.Height, 15)
@classmethod
def print_result(cls):
print(cls.ret)
@classmethod
def save(cls):
"""
Save the current workbook to its current location
Returns:
bool: True if save successful, False otherwise
"""
try:
# Just save the document
cls.doc.store()
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def _get_column_index(cls, column_name, sheet=None):
"""
Get the index of a column by its name (A, B, C, ...)
Args:
column_name (str): Name of the column
Returns:
int: Index of the column
"""
try:
return ord(column_name[0]) - ord("A")
except ValueError:
return None
@classmethod
def _get_last_used_column(cls):
"""
Get the last used column index
Args:
None
Returns:
int: Index of the last used column
"""
cursor = cls.sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
return cursor.RangeAddress.EndColumn
@classmethod
def _get_last_used_row(cls):
"""
Get the last used row index
Args:
None
Returns:
int: Index of the last used row
"""
cursor = cls.sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
return cursor.RangeAddress.EndRow
@classmethod
def _column_name_to_index(cls, column_name):
"""
将列名转换为列索引
Args:
column_name (str): 列名,如 'A', 'AB'
Returns:
int: 列索引(从0开始)
"""
column_name = column_name.upper()
result = 0
for char in column_name:
result = result * 26 + (ord(char) - ord("A") + 1)
return result - 1
@classmethod
def get_workbook_info(cls):
"""
Get workbook information
Args:
None
Returns:
dict: Workbook information, including file path, file name, sheets and active sheet
"""
try:
info = {
"file_path": cls.doc.getLocation(),
"file_title": cls.doc.getTitle(),
"sheets": [],
"active_sheet": cls.sheet.Name,
}
# Get sheets information
sheets = cls.doc.getSheets()
info["sheet_count"] = sheets.getCount()
# Get all sheet names and info
for i in range(sheets.getCount()):
sheet = sheets.getByIndex(i)
cursor = sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
end_col = cursor.getRangeAddress().EndColumn
end_row = cursor.getRangeAddress().EndRow
sheet_info = {
"name": sheet.getName(),
"index": i,
"visible": sheet.IsVisible,
"row_count": end_row + 1,
"column_count": end_col + 1,
}
info["sheets"].append(sheet_info)
# Check if this is the active sheet
if sheet == cls.sheet:
info["active_sheet"] = sheet_info
cls.ret = json.dumps(info, ensure_ascii=False)
return info
except Exception as e:
cls.ret = f"Error: {e}"
@classmethod
def env_info(cls, sheet_name=None):
"""
Get content of the specified or active sheet
Args:
sheet_name (str, optional): Name of the sheet to read. If None, uses active sheet
Returns:
dict: Sheet information including name, headers and data
"""
try:
# Get the target sheet
if sheet_name is not None:
sheet = cls.doc.getSheets().getByName(sheet_name)
else:
sheet = cls.sheet
# Create cursor to find used range
cursor = sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
end_col = cursor.getRangeAddress().EndColumn
end_row = cursor.getRangeAddress().EndRow
# Generate column headers (A, B, C, ...)
col_headers = [chr(65 + i) for i in range(end_col + 1)]
# Get displayed values from cells
data_array = []
for row in range(end_row + 1):
row_data = []
for col in range(end_col + 1):
cell = sheet.getCellByPosition(col, row)
row_data.append(cell.getString())
data_array.append(row_data)
# Calculate maximum width for each column
col_widths = [len(header) for header in col_headers] # Initialize with header lengths
for row in data_array:
for i, cell in enumerate(row):
col_widths[i] = max(col_widths[i], len(str(cell)))
# Format the header row
header_row = " | " + " | ".join(f"{h:<{w}}" for h, w in zip(col_headers, col_widths)) + " |"
separator = "--|-" + "-|-".join("-" * w for w in col_widths) + "-|"
# Format data rows with row numbers
formatted_rows = []
for row_idx, row in enumerate(data_array, 1):
row_str = f"{row_idx:<2}| " + " | ".join(f"{cell:<{w}}" for cell, w in zip(row, col_widths)) + " |"
formatted_rows.append(row_str)
# Combine all parts
formated_data = header_row + "\n" + separator + "\n" + "\n".join(formatted_rows)
# Get sheet properties
sheet_info = {
"name": sheet.getName(),
"data": formated_data,
"row_count": end_row + 1,
"column_count": end_col + 1,
}
cls.ret = json.dumps(sheet_info, ensure_ascii=False)
return sheet_info
except Exception as e:
cls.ret = f"Error: {e}"
@classmethod
def get_column_data(cls, column_name):
"""
Get data from the specified column
Args:
column_name (str): Name of the column to read
Returns:
list: List of values in the specified column
"""
column_index = cls._get_column_index(column_name)
if column_index is None:
return "Column not found"
last_row = cls._get_last_used_row()
_range = cls.sheet.getCellRangeByPosition(column_index, 0, column_index, last_row)
# 获取数据数组并展平
cls.ret = json.dumps([row[0] for row in _range.getDataArray()], ensure_ascii=False)
return [row[0] for row in _range.getDataArray()]
@classmethod
def switch_active_sheet(cls, sheet_name):
"""
Switch to the specified sheet and make it active, create if not exist
Args:
sheet_name (str): Name of the sheet to switch to or create
Returns:
bool: True if successful, False otherwise
"""
try:
# 获取所有工作表
sheets = cls.doc.getSheets()
# 检查工作表是否存在
if not sheets.hasByName(sheet_name):
# 创建新工作表
new_sheet = cls.doc.createInstance("com.sun.star.sheet.Spreadsheet")
sheets.insertByName(sheet_name, new_sheet)
# 获取目标工作表
sheet = sheets.getByName(sheet_name)
# 切换到目标工作表
cls.doc.getCurrentController().setActiveSheet(sheet)
# 更新当前工作表引用
cls.sheet = sheet
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def set_column_values(cls, column_name, data, start_index=2):
"""
Set data to the specified column
Args:
column_name (str): Name of the column to write
data (list): List of values to write to the column
start_index (int): The index of the first row to write to, default is 2 (skip the first row)
Returns:
bool: True if successful, False otherwise
"""
# 获取列的索引
column_index = cls._get_column_index(column_name)
if column_index is None:
cls.ret = "Column not found"
return False
for i, value in enumerate(data):
cell = cls.sheet.getCellByPosition(column_index, i + start_index - 1)
if type(value) == float and value.is_integer():
cell.setNumber(int(value))
else:
cell.setString(str(value))
cls.ret = "Success"
return True
@classmethod
def highlight_range(cls, range_str, color=0xFF0000):
"""
highlight the specified range with the specified color
Args:
range_str (str): Range to highlight, in the format of "A1:B10"
color (str): Color to highlight with, default is '0xFF0000' (red)
Returns:
bool: True if successful, False otherwise
"""
try:
_range = cls.sheet.getCellRangeByName(range_str)
_range.CellBackColor = color
cls.ret = "Success"
return True
except:
cls.ret = "False"
return False
@classmethod
def transpose_range(cls, source_range, target_cell):
"""
Transpose the specified range and paste it to the target cell
Args:
source_range (str): Range to transpose, in the format of "A1:B10"
target_cell (str): Target cell to paste the transposed data, in the format of "A1"
Returns:
bool: True if successful, False otherwise
"""
try:
source = cls.sheet.getCellRangeByName(source_range)
target = cls.sheet.getCellRangeByName(target_cell)
data = source.getDataArray()
# 转置数据
transposed_data = list(map(list, zip(*data)))
# 设置转置后的数据
target_range = cls.sheet.getCellRangeByPosition(
target.CellAddress.Column,
target.CellAddress.Row,
target.CellAddress.Column + len(transposed_data[0]) - 1,
target.CellAddress.Row + len(transposed_data) - 1,
)
target_range.setDataArray(transposed_data)
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def export_to_csv(cls):
"""
Export the current document to a CSV file
Args:
None
Returns:
bool: True if successful, False otherwise
"""
try:
# 获取当前文档的URL
doc_url = cls.doc.getURL()
if not doc_url:
raise ValueError("Document must be saved first")
# 构造CSV文件路径
if doc_url.startswith("file://"):
base_path = doc_url[7:] # 移除 'file://' 前缀
else:
base_path = doc_url
# 获取基本路径和文件名
csv_path = os.path.splitext(base_path)[0] + ".csv"
# 确保路径是绝对路径
csv_path = os.path.abspath(csv_path)
# 转换为 LibreOffice URL 格式
csv_url = uno.systemPathToFileUrl(csv_path)
# 设置CSV导出选项
props = (
PropertyValue(Name="FilterName", Value="Text - txt - csv (StarCalc)"),
PropertyValue(
Name="FilterOptions", Value="44,0,76,0"
), # 44=comma, 34=quote, 76=UTF-8, 1=first row as header
)
# 导出文件
cls.doc.storeToURL(csv_url, props)
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def sort_column(cls, column_name, ascending=True, start_index=2):
"""
Sorts the data in the specified column in ascending or descending order
Args:
column_name (str): The name of the column to sort (e.g. 'A') or the title
ascending (bool): Whether to sort in ascending order (default True)
start_index (int): The index of the first row to sort, default is 1
Returns:
bool: True if successful, False otherwise
"""
try:
column_data = cls.get_column_data(column_name)[start_index - 1 :]
column_data = sorted(column_data, key=lambda x: float(x), reverse=not ascending)
except:
cls.ret = "Error: Invalid column name or data type"
return False
return cls.set_column_values(column_name, column_data, start_index)
@classmethod
def set_validation_list(cls, column_name, values):
"""
Set a validation list for the specified column
Args:
column_name (str): The name of the column to set the validation list for
values (list): The list of values to use for the validation list
Returns:
None
"""
try:
column_index = cls._get_column_index(column_name)
last_row = cls._get_last_used_row()
cell_range = cls.sheet.getCellRangeByPosition(column_index, 1, column_index, last_row)
# 获取现有的验证对象
validation = cell_range.getPropertyValue("Validation")
# 设置基本验证类型
validation.Type = uno.Enum("com.sun.star.sheet.ValidationType", "LIST")
validation.Operator = uno.Enum("com.sun.star.sheet.ConditionOperator", "EQUAL")
# 设置下拉列表
validation.ShowList = True
values_str = ";".join(str(val) for val in values)
validation.Formula1 = values_str
# 应用验证设置回单元格范围
cell_range.setPropertyValue("Validation", validation)
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def hide_row_data(cls, value="N/A"):
"""
Hide rows that contain the specified value
Args:
value (str): The value to hide rows for, default is 'N/A'
Returns:
None
"""
last_row = cls._get_last_used_row()
last_col = cls._get_last_used_column()
for row in range(1, last_row + 1):
has_value = False
for col in range(last_col + 1):
cell = cls.sheet.getCellByPosition(col, row)
if cell.getString() == value:
has_value = True
break
row_range = cls.sheet.getRows().getByIndex(row)
row_range.IsVisible = not has_value
cls.ret = "Success"
return True
@classmethod
def reorder_columns(cls, column_order):
"""
Reorder the columns in the sheet according to the specified order
Args:
column_order (list): A list of column names in the desired order
Returns:
bool: True if successful, False otherwise
"""
try:
# 获取新的列索引
new_indices = [cls._get_column_index(col) for col in column_order]
# 创建新的列顺序
for new_index, old_index in enumerate(new_indices):
if new_index != old_index:
cls.sheet.Columns.insertByIndex(new_index, 1)
source = cls.sheet.Columns[old_index + (old_index > new_index)]
target = cls.sheet.Columns[new_index]
target.setDataArray(source.getDataArray())
cls.sheet.Columns.removeByIndex(old_index + (old_index > new_index), 1)
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def create_pivot_table(
cls,
source_sheet,
table_name,
row_fields=None,
col_fields=None,
value_fields=None,
aggregation_function="sum",
target_cell="A1",
):
"""
Create a pivot table in the active worksheet based on data from the active sheet.
"""
try:
source = cls.doc.getSheets().getByName(source_sheet)
# 获取数据范围
cursor = source.createCursor()
cursor.gotoEndOfUsedArea(False)
end_col = cursor.getRangeAddress().EndColumn
end_row = cursor.getRangeAddress().EndRow
# 获取完整的数据范围
source_range = source.getCellRangeByPosition(0, 0, end_col, end_row)
# 获取数据透视表集合
dp_tables = cls.sheet.getDataPilotTables()
# 创建数据透视表描述符
dp_descriptor = dp_tables.createDataPilotDescriptor()
# 设置数据源
dp_descriptor.setSourceRange(source_range.getRangeAddress())
# 设置行字段
if row_fields:
for field in row_fields:
field_index = cls._get_column_index(field)
dimension = dp_descriptor.getDataPilotFields().getByIndex(field_index)
dimension.Orientation = uno.Enum("com.sun.star.sheet.DataPilotFieldOrientation", "ROW")
# 设置列字段
if col_fields:
for field in col_fields:
field_index = cls._get_column_index(field)
dimension = dp_descriptor.getDataPilotFields().getByIndex(field_index)
dimension.Orientation = uno.Enum("com.sun.star.sheet.DataPilotFieldOrientation", "COLUMN")
# 设置数据字段
for field in value_fields:
field_index = cls._get_column_index(field)
dimension = dp_descriptor.getDataPilotFields().getByIndex(field_index)
dimension.Orientation = uno.Enum("com.sun.star.sheet.DataPilotFieldOrientation", "DATA")
# 设置聚合函数
function_map = {"Count": "COUNT", "Sum": "SUM", "Average": "AVERAGE", "Min": "MIN", "Max": "MAX"}
if aggregation_function in function_map:
dimension.Function = uno.Enum(
"com.sun.star.sheet.GeneralFunction", function_map[aggregation_function]
)
# 在当前工作表中创建数据透视表
dp_tables.insertNewByName(
table_name, # 透视表名称
cls.sheet.getCellRangeByName(target_cell).CellAddress, # 目标位置
dp_descriptor, # 描述符
)
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def merge_cells(cls, range_str):
"""
合并活动工作表中指定范围的单元格
Args:
range_str (str): 要合并的单元格范围,格式为'A1:B10'
Returns:
bool: 成功返回True,失败返回False
"""
try:
# 获取当前活动工作表
sheet = cls.sheet
# 获取单元格范围
cell_range = sheet.getCellRangeByName(range_str)
# 获取单元格范围的属性
range_props = cell_range.getIsMerged()
# 如果单元格范围尚未合并,则进行合并
if not range_props:
cell_range.merge(True)
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def set_cell_value(cls, cell, value):
"""
Set a value to a specific cell in the active worksheet.
Args:
cell (str): Cell reference (e.g., 'A1')
value (str): Value to set in the cell
Returns:
bool: True if successful, False otherwise
"""
try:
# 获取单元格对象
cell_obj = cls.sheet.getCellRangeByName(cell)
if isinstance(value, str) and value.startswith("="):
# 设置公式
cell_obj.Formula = value
cls.ret = "Success"
return True
# 尝试将值转换为数字
try:
# 尝试转换为整数
int_value = int(value)
cell_obj.Value = int_value
except ValueError:
try:
# 尝试转换为浮点数
float_value = float(value)
cell_obj.Value = float_value
except ValueError:
# 如果不是数字,则设置为字符串
cell_obj.String = value
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def format_range(cls, range_str, background_color=None, font_color=None, bold=None, alignment=None):
"""
Apply formatting to the specified range in the active worksheet
Args:
range_str (str): Range to format, in the format of 'A1:B10'
background_color (str, optional): Background color in hex format (e.g., '#0000ff')
font_color (str, optional): Font color in hex format (e.g., '#ffffff')
bold (bool, optional): Whether to make the text bold
italic (bool, optional): Whether to make the text italic
alignment (str, optional): Text alignment (left, center, right)
Returns:
bool: True if successful, False otherwise
"""
try:
# 获取指定范围
cell_range = cls.sheet.getCellRangeByName(range_str)
# 设置背景颜色
if background_color:
# 将十六进制颜色转换为整数
bg_color_int = int(background_color.replace("#", ""), 16)
cell_range.CellBackColor = bg_color_int
# 设置字体颜色
if font_color:
# 将十六进制颜色转换为整数
font_color_int = int(font_color.replace("#", ""), 16)
cell_range.CharColor = font_color_int
# 设置粗体
if bold is not None:
cell_range.CharWeight = 150.0 if bold else 100.0 # 150.0 是粗体,100.0 是正常
# 设置对齐方式
if alignment:
# 设置水平对齐方式
struct = cell_range.getPropertyValue("HoriJustify")
if alignment == "left":
struct.value = "LEFT"
elif alignment == "center":
struct.value = "CENTER"
elif alignment == "right":
struct.value = "RIGHT"
cell_range.setPropertyValue("HoriJustify", struct)
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def create_chart(cls, chart_type, data_range, title=None, x_axis_title=None, y_axis_title=None):
"""
Create a chart in the active worksheet based on the specified data range.
Args:
chart_type (str): Type of chart to create (bar, column, line, pie, scatter, area)
data_range (str): Range containing the data for the chart, in the format of 'A1:B10'
title (str, optional): Title for the chart
x_axis_title (str, optional): Title for the X axis
y_axis_title (str, optional): Title for the Y axis
Returns:
bool: True if successful, False otherwise
"""
# 将图表类型映射到LibreOffice的图表类型常量
try:
chart_type_map = {
"bar": "com.sun.star.chart.BarDiagram",
"column": "com.sun.star.chart.ColumnDiagram",
"line": "com.sun.star.chart.LineDiagram",
"pie": "com.sun.star.chart.PieDiagram",
"scatter": "com.sun.star.chart.ScatterDiagram",
"area": "com.sun.star.chart.AreaDiagram",
}
# 获取数据范围
cell_range_address = cls.sheet.getCellRangeByName(data_range).getRangeAddress()
# 创建图表
charts = cls.sheet.getCharts()
rect = uno.createUnoStruct("com.sun.star.awt.Rectangle")
rect.Width = 10000 # 默认宽度
rect.Height = 7000 # 默认高度
# 添加图表到工作表
charts.addNewByName("MyChart", rect, (cell_range_address,), False, False)
# 获取图表
chart = charts.getByName("MyChart")
chart_doc = chart.getEmbeddedObject()
# 设置图表类型
diagram = chart_doc.createInstance(chart_type_map[chart_type])
chart_doc.setDiagram(diagram)
# 设置图表标题
if title:
chart_doc.Title.String = title
# 设置X轴标题
if x_axis_title:
chart_doc.Diagram.XAxis.AxisTitle.String = x_axis_title
# 设置Y轴标题
if y_axis_title:
chart_doc.Diagram.YAxis.AxisTitle.String = y_axis_title
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def freeze_panes(cls, rows=0, columns=0):
"""
冻结活动工作表中的行和/或列
Args:
rows (int): 从顶部开始冻结的行数
columns (int): 从左侧开始冻结的列数
Returns:
bool: 成功返回True,失败返回False
"""
try:
# 获取当前视图
view = cls.doc.getCurrentController()
# 设置冻结窗格
view.freezeAtPosition(columns, rows)
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def rename_sheet(cls, old_name, new_name):
"""
重命名工作表
Args:
old_name (str): 要重命名的工作表的当前名称
new_name (str): 工作表的新名称
Returns:
bool: 成功返回True,失败返回False
"""
try:
# 获取所有工作表
sheets = cls.doc.getSheets()
# 检查原工作表是否存在
if not sheets.hasByName(old_name):
return False
# 检查新名称是否已存在
if sheets.hasByName(new_name):
return False
# 获取要重命名的工作表
sheet = sheets.getByName(old_name)
# 重命名工作表
sheet.setName(new_name)
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def copy_sheet(cls, source_sheet, new_sheet_name=None):
"""
创建工作簿中现有工作表的副本
Args:
source_sheet (str): 要复制的工作表名称
new_sheet_name (str, optional): 新工作表副本的名称,如果不提供则自动生成
Returns:
str: 新创建的工作表名称,如果失败则返回None
"""
try:
# 获取所有工作表
sheets = cls.doc.getSheets()
# 检查源工作表是否存在
if not sheets.hasByName(source_sheet):
return None
# 如果没有提供新名称,则生成一个
if not new_sheet_name:
# 生成类似 "Sheet1 (2)" 的名称
base_name = source_sheet
counter = 1
new_sheet_name = f"{base_name} ({counter})"
# 确保名称不重复
while sheets.hasByName(new_sheet_name):
counter += 1
new_sheet_name = f"{base_name} ({counter})"
# 检查新名称是否已存在
if sheets.hasByName(new_sheet_name):
return None # 名称已存在,无法创建
# 获取源工作表的索引
source_index = -1
for i in range(sheets.getCount()):
if sheets.getByIndex(i).getName() == source_sheet:
source_index = i
break
if source_index == -1:
return None
# 复制工作表
sheets.copyByName(source_sheet, new_sheet_name, source_index + 1)
cls.ret = f"New sheet created: {new_sheet_name}"
return new_sheet_name
except Exception as e:
cls.ret = f"Error: {e}"
return None
@classmethod
def reorder_sheets(cls, sheet_name, position):
"""
重新排序工作表在工作簿中的位置
Args:
sheet_name (str): 要移动的工作表名称
position (int): 要移动到的位置(基于0的索引)
Returns:
bool: 成功返回True,失败返回False
"""
try:
# 获取所有工作表
sheets = cls.doc.getSheets()
# 检查工作表是否存在
if not sheets.hasByName(sheet_name):
return False
# 获取工作表总数
sheet_count = sheets.getCount()
# 检查位置是否有效
if position < 0 or position >= sheet_count:
return False
# 获取要移动的工作表
sheet = sheets.getByName(sheet_name)
# 获取工作表当前索引
current_index = -1
for i in range(sheet_count):
if sheets.getByIndex(i).Name == sheet_name:
current_index = i
break
if current_index == -1:
return False
# 移动工作表到指定位置
sheets.moveByName(sheet_name, position)
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def set_chart_legend_position(cls, position):
"""
Set the position of the legend in a chart in the active worksheet.
Args:
position (str): Position of the legend ('top', 'bottom', 'left', 'right', 'none')
Returns:
bool: True if successful, False otherwise
"""
try:
# 获取当前工作表中的所有图表
charts = cls.sheet.getCharts()
if charts.getCount() == 0:
return False
# 获取第一个图表(假设我们要修改的是第一个图表)
chart = charts.getByIndex(0)
chart_obj = chart.getEmbeddedObject()
# 获取图表的图例
diagram = chart_obj.getDiagram()
legend = chart_obj.getLegend()
# 根据指定的位置设置图例位置
if position == "none":
# 如果选择"none",则隐藏图例
chart_obj.HasLegend = False
else:
# 确保图例可见
chart_obj.HasLegend = True
import inspect
print(inspect.getmembers(legend))
# 设置图例位置
if position == "top":
pos = uno.Enum("com.sun.star.chart.ChartLegendPosition", "TOP")
elif position == "bottom":
pos = uno.Enum("com.sun.star.chart.ChartLegendPosition", "BOTTOM")
elif position == "left":
pos = uno.Enum("com.sun.star.chart.ChartLegendPosition", "LEFT")
elif position == "right":
pos = uno.Enum("com.sun.star.chart.ChartLegendPosition", "RIGHT")
legend.Alignment = pos
cls.ret = "Success"
return True
except Exception:
cls.ret = "Error"
return False
@classmethod
def set_number_format(cls, range_str, format_type, decimal_places=None):
"""
Apply a specific number format to a range of cells in the active worksheet.
Args:
range_str (str): Range to format, in the format of 'A1:B10'
format_type (str): Type of number format to apply
decimal_places (int, optional): Number of decimal places to display
Returns:
bool: True if successful, False otherwise
"""
try:
# 获取单元格范围
cell_range = cls.sheet.getCellRangeByName(range_str)
# 获取数字格式化服务
number_formats = cls.doc.NumberFormats
locale = cls.doc.CharLocale
# 根据格式类型设置格式字符串
format_string = ""
if format_type == "general":
format_string = "General"
elif format_type == "number":
if decimal_places is not None:
format_string = f"0{('.' + '0' * decimal_places) if decimal_places > 0 else ''}"
else:
format_string = "0"
elif format_type == "currency":
if decimal_places is not None:
format_string = f"[$¥-804]#,##0{('.' + '0' * decimal_places) if decimal_places > 0 else ''}"
else:
format_string = "[$¥-804]#,##0.00"
elif format_type == "accounting":
if decimal_places is not None:
format_string = f"_-[$¥-804]* #,##0{('.' + '0' * decimal_places) if decimal_places > 0 else ''}_-;-[$¥-804]* #,##0{('.' + '0' * decimal_places) if decimal_places > 0 else ''}_-;_-[$¥-804]* \"-\"_-;_-@_-"
else:
format_string = '_-[$¥-804]* #,##0.00_-;-[$¥-804]* #,##0.00_-;_-[$¥-804]* "-"??_-;_-@_-'
elif format_type == "date":
format_string = "YYYY/MM/DD"
elif format_type == "time":
format_string = "HH:MM:SS"
elif format_type == "percentage":
if decimal_places is not None:
format_string = f"0{('.' + '0' * decimal_places) if decimal_places > 0 else ''}%"
else:
format_string = "0.00%"
elif format_type == "fraction":
format_string = "# ?/?"
elif format_type == "scientific":
if decimal_places is not None:
format_string = f"0{('.' + '0' * decimal_places) if decimal_places > 0 else ''}E+00"
else:
format_string = "0.00E+00"
elif format_type == "text":
format_string = "@"
# 获取格式键
format_key = number_formats.queryKey(format_string, locale, True)
# 如果格式不存在,则添加
if format_key == -1:
format_key = number_formats.addNew(format_string, locale)
# 应用格式
cell_range.NumberFormat = format_key
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def adjust_column_width(cls, columns, width=None, autofit=False):
"""
调整活动工作表中指定列的宽度
Args:
columns (str): 要调整的列范围,例如 'A:C' 表示从A列到C列
width (float, optional): 要设置的宽度(以字符为单位)
autofit (bool, optional): 是否自动调整列宽以适应内容
Returns:
bool: 成功返回True,失败返回False
"""
try:
# 解析列范围
col_range = columns.split(":")
start_col = cls._column_name_to_index(col_range[0])
if len(col_range) > 1:
end_col = cls._column_name_to_index(col_range[1])
else:
end_col = start_col
# 获取列对象
columns_obj = cls.sheet.getColumns()
# 遍历指定的列范围
for col_idx in range(start_col, end_col + 1):
column = columns_obj.getByIndex(col_idx)
if autofit:
# 自动调整列宽
column.OptimalWidth = True
elif width is not None:
# 设置指定宽度(转换为1/100毫米)
# 大约一个字符宽度为256 (1/100 mm)
column.Width = int(width * 256)
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def adjust_row_height(cls, rows, height=None, autofit=False):
"""
调整活动工作表中指定行的高度
Args:
rows (str): 要调整的行范围,例如 '1:10' 表示第1行到第10行
height (float, optional): 要设置的高度(以点为单位)
autofit (bool, optional): 是否自动调整行高以适应内容
Returns:
bool: 操作成功返回True,否则返回False
"""
try:
# 解析行范围
row_range = rows.split(":")
start_row = int(row_range[0])
end_row = int(row_range[1]) if len(row_range) > 1 else start_row
# 获取行对象
for row_index in range(start_row, end_row + 1):
row = cls.sheet.getRows().getByIndex(row_index - 1) # 索引从0开始
if autofit:
# 自动调整行高以适应内容
row.OptimalHeight = True
elif height is not None:
# 设置指定高度(将点转换为1/100毫米,LibreOffice使用的单位)
# 1点 ≈ 35.28 1/100毫米
row.Height = int(height * 35.28)
row.OptimalHeight = False
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def export_to_pdf(cls, file_path=None, sheets=None, open_after_export=False):
"""
将当前文档或指定工作表导出为PDF文件
Args:
file_path (str, optional): PDF文件保存路径,如果不指定则使用当前文档路径
sheets (list, optional): 要包含在PDF中的工作表名称列表,如果不指定则包含所有工作表
open_after_export (bool, optional): 导出后是否打开PDF文件
Returns:
bool: 成功返回True,失败返回False
"""
try:
# 如果未指定文件路径,则使用当前文档路径并更改扩展名为.pdf
if not file_path:
if cls.doc.hasLocation():
url = cls.doc.getLocation()
file_path = uno.fileUrlToSystemPath(url)
file_path = os.path.splitext(file_path)[0] + ".pdf"
else:
# 如果文档尚未保存,则在用户桌面创建临时文件
desktop_path = os.path.join(os.path.expanduser("~"), "Desktop")
file_path = os.path.join(desktop_path, "LibreOffice_Export.pdf")
# 确保文件路径是系统路径,然后转换为URL
pdf_url = uno.systemPathToFileUrl(os.path.abspath(file_path))
# 创建导出属性
export_props = []
# 设置过滤器名称
export_props.append(PropertyValue(Name="FilterName", Value="calc_pdf_Export"))
# 如果指定了特定工作表,则只导出这些工作表
if sheets and isinstance(sheets, list) and len(sheets) > 0:
# 获取所有工作表
all_sheets = cls.doc.getSheets()
selection = []
# 查找指定的工作表
for sheet_name in sheets:
if all_sheets.hasByName(sheet_name):
sheet = all_sheets.getByName(sheet_name)
selection.append(sheet)
# 如果找到了指定的工作表,则设置导出选择
if selection:
export_props.append(PropertyValue(Name="Selection", Value=tuple(selection)))
# 导出PDF
cls.doc.storeToURL(pdf_url, tuple(export_props))
# 如果需要,导出后打开PDF
if open_after_export:
if sys.platform.startswith("darwin"): # macOS
subprocess.call(("open", file_path))
elif os.name == "nt": # Windows
os.startfile(file_path)
elif os.name == "posix": # Linux
subprocess.call(("xdg-open", file_path))
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
@classmethod
def set_zoom_level(cls, zoom_percentage):
"""
调整当前工作表的缩放级别,使单元格看起来更大或更小
Args:
zoom_percentage (int): 缩放级别的百分比(例如,75表示75%,100表示正常大小,150表示放大)。
有效范围通常为10-400。
Returns:
bool: 成功返回True,失败返回False
"""
try:
# 获取当前控制器
controller = cls.doc.getCurrentController()
# 设置缩放值
# 确保缩放值在合理范围内
if zoom_percentage < 10:
zoom_percentage = 10
elif zoom_percentage > 400:
zoom_percentage = 400
# 应用缩放值
controller.ZoomValue = zoom_percentage
cls.ret = "Success"
return True
except Exception as e:
cls.ret = f"Error: {e}"
return False
if __name__ == "__main__":
print(CalcTools._get_column_index("A"))
print(CalcTools.get_workbook_info())
print(CalcTools.get_content())
CalcTools.switch_active_sheet("Sheet2")
# helper.set_column_values('A', [1, 2, 3, 4, 5])
# helper.highlight_range('A1:A3', 'Red')
# helper.transpose_range('A1:D5', 'B8')
print(CalcTools.get_column_data("A"))
CalcTools.sort_column("A", True)
CalcTools.hide_row_data("N/A")
CalcTools.reorder_columns(["B", "A", "C"])
CalcTools.freeze_panes(1, 1)
# helper.set_validation_list('C', ['Pass', 'Fail', 'Held'])
CalcTools.export_to_csv()