# coding: utf-8
# Python conversion of ViewState.java by Andrew Davison, ad@fivedots.coe.psu.ac.th
# See Also: https:#fivedots.coe.psu.ac.th/~ad/jlop/
from __future__ import annotations
from enum import IntEnum
from ooodev.office import calc as mCalc
from ooodev.loader import lo as mLo
[docs]class ViewState:
"""
For moving the pane focus
See Also:
:ref:`ch23_view_states_top_pane`
"""
[docs] class PaneEnum(IntEnum):
MOVE_UP = 0
MOVE_DOWN = 1
MOVE_LEFT = 2
MOVE_RIGHT = 3
[docs] def __init__(self, state: str) -> None:
"""
Constructor
Args:
state (str): State in format of '0/4998/0/1/0/218/2/0/0/4988/4998'
Raises:
ValueError: if state does not contains 10 '/' (11 parts)
"""
# The state string has the format:
# 0/4998/0/1/0/218/2/0/0/4988/4998
self._cursor_column: int = 0
self._cursor_row: int = 0
self._col_split_mode: int = 0
self._col_split_mode: int = 0
self._row_split_mode: int = 0
self._row_split_mode: int = 0
self._vertical_split: int = 0
self._horizontal_split: int = 0
self._pane_focus_num: int = 0
self._column_left_pane: int = 0
self._column_right_pane: int = 0
self._row_upper_pane: int = 0
self._row_lower_pane: int = 0
states = state.split("/")
if len(states) != 11:
raise ValueError(f"Incorrect number of states, Expected 11 got {len(states)}")
self._cursor_column = ViewState.parse_int(states[0]) # 0: cursor position column
self._cursor_row = ViewState.parse_int(states[1]) # 1: cursor position row
self._col_split_mode = ViewState.parse_int(states[2]) # 2: column split mode
self._row_split_mode = ViewState.parse_int(states[3]) # 3: row split mode
self._vertical_split = ViewState.parse_int(states[4]) # 4: vertical split position
self._horizontal_split = ViewState.parse_int(states[5]) # 5: horizontal split position
self._pane_focus_num = ViewState.parse_int(states[6]) # 6: focused pane number
self._column_left_pane = ViewState.parse_int(states[7]) # 7: left column index of left pane
self._column_right_pane = ViewState.parse_int(states[8]) # 8: left column index of right pane
self._row_upper_pane = ViewState.parse_int(states[9]) # 9: top row index of upper pane
self._row_lower_pane = ViewState.parse_int(states[10]) # 10: top row index of lower pane
[docs] @staticmethod
def parse_int(s: str) -> int:
"""
Parses int
Args:
s (str): string value that contains int
Returns:
int: string value converted to int on success; Otherwise, 0
"""
if not s:
return 0
try:
return int(s)
except ValueError:
mLo.Lo.print(f"'{s}' could not be parsed as an int; using 0")
return 0
@property
def cursor_column(self) -> int:
"""Gets/Sets cursor position column"""
return self._cursor_column
@cursor_column.setter
def cursor_column(self, value: int) -> None:
if value < 0:
raise ValueError("Column position must be positive")
self._cursor_column = value
@property
def cursor_row(self) -> int:
"""Gets/Sets cursor position row"""
return self._cursor_row
@cursor_row.setter
def cursor_row(self, value: int) -> None:
if value < 0:
raise ValueError("Row position must be positive")
self._cursor_row = value
@property
def column_split_mode(self) -> int:
"""Gets/Sets column split mode"""
return self._col_split_mode
@column_split_mode.setter
def column_split_mode(self, value: bool | int) -> None:
self._col_split_mode = int(value)
if self._col_split_mode == 0: # no column splitting
self._vertical_split = 0
if self._pane_focus_num in (1, 3):
self._pane_focus_num -= 1 # move focus to left
@property
def row_split_mode(self) -> int:
"""Gets/Sets row split mode"""
return self._row_split_mode
@row_split_mode.setter
def row_split_mode(self, value: bool | int) -> None:
self._row_split_mode = int(value)
if self._row_split_mode == 0: # no row splitting
self._horizontal_split = 0
if self._pane_focus_num in (2, 3):
self._pane_focus_num -= 2 # move focus up
@property
def vertical_split(self) -> int:
"""Gets/Sets vertical split position"""
return self._vertical_split
@vertical_split.setter
def vertical_split(self, value: int) -> None:
if value < 0:
raise ValueError("Position must be positive")
self._vertical_split = value
@property
def horizontal_split(self) -> int:
"""Gets/Sets horizontal split position"""
return self._horizontal_split
@horizontal_split.setter
def horizontal_split(self, value: int) -> None:
if value < 0:
raise ValueError("Position must be positive")
self._horizontal_split = value
@property
def pane_focus_num(self) -> int:
"""Gets/Sets focused pane number"""
return self._pane_focus_num
@pane_focus_num.setter
def pane_focus_num(self, value: int) -> None:
if value < 0 or value > 3:
raise ValueError("Focus number is out of range 0-3")
if self._horizontal_split == 0 and value in {1, 3}:
raise ValueError("No horizontal split, so focus number must be 0 or 2")
if self._vertical_split == 0 and value in {2, 3}:
raise ValueError("No vertical split, so focus number must be 0 or 1")
self._pane_focus_num = value
[docs] def move_pane_focus(self, dir: int | ViewState.PaneEnum) -> bool:
"""
Moves pane focus
Args:
dir (int | PaneEnum): Direction to move
Raises:
ValueError: If dir is unknown
Returns:
bool: True if move is successful; Otherwise False
Note:
The 4 possible view panes are numbered like so
::
0 | 1
-------
2 | 3
If there's no horizontal split then the panes are numbered 0 and 2.
If there's no vertical split then the panes are numbered 0 and 1.
"""
try:
d = ViewState.PaneEnum(dir)
except Exception as e:
raise ValueError("Unknown move direction") from e
if d == ViewState.PaneEnum.MOVE_UP:
if self._pane_focus_num == 3:
self._pane_focus_num = 1
elif self._pane_focus_num == 2:
self._pane_focus_num = 0
else:
mLo.Lo.print("cannot move up")
return False
elif d == ViewState.PaneEnum.MOVE_DOWN:
if self._pane_focus_num == 1:
self._pane_focus_num = 3
elif self._pane_focus_num == 0:
self._pane_focus_num = 2
else:
mLo.Lo.print("cannot move down")
return False
elif d == ViewState.PaneEnum.MOVE_LEFT:
if self._pane_focus_num == 1:
self._pane_focus_num = 0
elif self._pane_focus_num == 3:
self._pane_focus_num = 2
else:
mLo.Lo.print("cannot move left")
return False
elif d == ViewState.PaneEnum.MOVE_RIGHT:
if self._pane_focus_num == 0:
self._pane_focus_num = 1
elif self._pane_focus_num == 2:
self._pane_focus_num = 3
else:
mLo.Lo.print("cannot move right")
return False
return True
@property
def column_left_pane(self) -> int:
"""Gets/Sets left column index of left pane"""
return self._column_left_pane
@column_left_pane.setter
def column_left_pane(self, value: int) -> None:
if value < 0:
raise IndexError("value must be positive")
self._column_left_pane = value
@property
def column_right_pane(self) -> int:
"""Gets/Sets left column index of right pane"""
return self._column_right_pane
@column_right_pane.setter
def column_right_pane(self, value: int) -> None:
if value < 0:
raise IndexError("value must be positive")
self._column_right_pane = value
@property
def row_upper_pane(self) -> int:
"""Gets/Sets top row index of upper pane"""
return self._row_upper_pane
@row_upper_pane.setter
def row_upper_pane(self, value: int) -> None:
if value < 0:
raise IndexError("value must be positive")
self._row_upper_pane = value
@property
def row_lower_pane(self) -> int:
"""Gets/Sets top row index of lower pane"""
return self._row_lower_pane
@row_lower_pane.setter
def row_lower_pane(self, value: int) -> None:
if value < 0:
raise IndexError("value must be positive")
self._row_lower_pane = value
[docs] def report(self) -> None:
"""
Prints a report to console
"""
print("Sheet View State")
print(
f" Cursor pos (column, row): ({self.cursor_column}, {self.cursor_row}) or '{mCalc.Calc.get_cell_str(col=self.cursor_column, row=self.cursor_row)}'"
)
if self.column_split_mode == 1 and self.row_split_mode == 1:
print(f" Sheet is split vertically and horizontally at {self.vertical_split} / {self.horizontal_split}")
elif self.column_split_mode == 1:
print(f" Sheet is split vertically at {self.vertical_split}")
elif self.row_split_mode == 1:
print(f" Sheet is split horizontally at {self.horizontal_split}")
else:
print(" Sheet is not split")
print(f" Number of focused pane: {self.pane_focus_num}")
print(f" Left column indices of left/right panes: {self.column_left_pane} / {self.column_right_pane}")
print(f" Top row indices of upper/lower panes: {self.row_upper_pane} / {self.row_lower_pane}")
print()
[docs] def to_string(self) -> str:
"""
Gets string Representation of object.
String representation can also be used to create a new instance of this class.
same as ``str(instance)``
"""
lst = [
self.cursor_column,
self.cursor_row,
self.column_split_mode,
self.row_split_mode,
self.vertical_split,
self.horizontal_split,
self.pane_focus_num,
self.column_left_pane,
self.column_right_pane,
self.row_upper_pane,
self.row_lower_pane,
]
return "/".join([str(val) for val in lst])
def __str__(self) -> str:
return self.to_string()