1# Copyright (c) 2023, Pubpub-ZZ 
    2# 
    3# All rights reserved. 
    4# 
    5# Redistribution and use in source and binary forms, with or without 
    6# modification, are permitted provided that the following conditions are 
    7# met: 
    8# 
    9# * Redistributions of source code must retain the above copyright notice, 
    10# this list of conditions and the following disclaimer. 
    11# * Redistributions in binary form must reproduce the above copyright notice, 
    12# this list of conditions and the following disclaimer in the documentation 
    13# and/or other materials provided with the distribution. 
    14# * The name of the author may not be used to endorse or promote products 
    15# derived from this software without specific prior written permission. 
    16# 
    17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
    18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
    19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
    20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
    21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
    22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
    23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
    24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
    25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
    26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
    27# POSSIBILITY OF SUCH DAMAGE. 
    28 
    29from typing import ( 
    30    Any, 
    31    Optional, 
    32) 
    33 
    34from ._base import BooleanObject, NameObject, NumberObject, is_null_or_none 
    35from ._data_structures import ArrayObject, DictionaryObject 
    36 
    37f_obj = BooleanObject(False) 
    38 
    39 
    40class ViewerPreferences(DictionaryObject): 
    41    def __init__(self, obj: Optional[DictionaryObject] = None) -> None: 
    42        super().__init__(self) 
    43        if not is_null_or_none(obj): 
    44            self.update(obj.items())  # type: ignore 
    45        try: 
    46            self.indirect_reference = obj.indirect_reference  # type: ignore 
    47        except AttributeError: 
    48            pass 
    49 
    50    def _get_bool(self, key: str, default: Optional[BooleanObject]) -> Optional[BooleanObject]: 
    51        return self.get(key, default) 
    52 
    53    def _set_bool(self, key: str, v: bool) -> None: 
    54        self[NameObject(key)] = BooleanObject(v is True) 
    55 
    56    def _get_name(self, key: str, default: Optional[NameObject]) -> Optional[NameObject]: 
    57        return self.get(key, default) 
    58 
    59    def _set_name(self, key: str, lst: list[str], v: NameObject) -> None: 
    60        if v[0] != "/": 
    61            raise ValueError(f"{v} does not start with '/'") 
    62        if lst != [] and v not in lst: 
    63            raise ValueError(f"{v} is an unacceptable value") 
    64        self[NameObject(key)] = NameObject(v) 
    65 
    66    def _get_arr(self, key: str, default: Optional[list[Any]]) -> Optional[ArrayObject]: 
    67        return self.get(key, None if default is None else ArrayObject(default)) 
    68 
    69    def _set_arr(self, key: str, v: Optional[ArrayObject]) -> None: 
    70        if v is None: 
    71            try: 
    72                del self[NameObject(key)] 
    73            except KeyError: 
    74                pass 
    75            return 
    76        if not isinstance(v, ArrayObject): 
    77            raise ValueError("ArrayObject is expected") 
    78        self[NameObject(key)] = v 
    79 
    80    def _get_int(self, key: str, default: Optional[NumberObject]) -> Optional[NumberObject]: 
    81        return self.get(key, default) 
    82 
    83    def _set_int(self, key: str, v: int) -> None: 
    84        self[NameObject(key)] = NumberObject(v) 
    85 
    86    @property 
    87    def PRINT_SCALING(self) -> NameObject: 
    88        return NameObject("/PrintScaling") 
    89 
    90    def __new__(cls: Any, value: Any = None) -> "ViewerPreferences": 
    91        def _add_prop_bool(key: str, default: Optional[BooleanObject]) -> property: 
    92            return property( 
    93                lambda self: self._get_bool(key, default), 
    94                lambda self, v: self._set_bool(key, v), 
    95                None, 
    96                f""" 
    97            Returns/Modify the status of {key}, Returns {default} if not defined 
    98            """, 
    99            ) 
    100 
    101        def _add_prop_name( 
    102            key: str, lst: list[str], default: Optional[NameObject] 
    103        ) -> property: 
    104            return property( 
    105                lambda self: self._get_name(key, default), 
    106                lambda self, v: self._set_name(key, lst, v), 
    107                None, 
    108                f""" 
    109            Returns/Modify the status of {key}, Returns {default} if not defined. 
    110            Acceptable values: {lst} 
    111            """, 
    112            ) 
    113 
    114        def _add_prop_arr(key: str, default: Optional[ArrayObject]) -> property: 
    115            return property( 
    116                lambda self: self._get_arr(key, default), 
    117                lambda self, v: self._set_arr(key, v), 
    118                None, 
    119                f""" 
    120            Returns/Modify the status of {key}, Returns {default} if not defined 
    121            """, 
    122            ) 
    123 
    124        def _add_prop_int(key: str, default: Optional[int]) -> property: 
    125            return property( 
    126                lambda self: self._get_int(key, default), 
    127                lambda self, v: self._set_int(key, v), 
    128                None, 
    129                f""" 
    130            Returns/Modify the status of {key}, Returns {default} if not defined 
    131            """, 
    132            ) 
    133 
    134        cls.hide_toolbar = _add_prop_bool("/HideToolbar", f_obj) 
    135        cls.hide_menubar = _add_prop_bool("/HideMenubar", f_obj) 
    136        cls.hide_windowui = _add_prop_bool("/HideWindowUI", f_obj) 
    137        cls.fit_window = _add_prop_bool("/FitWindow", f_obj) 
    138        cls.center_window = _add_prop_bool("/CenterWindow", f_obj) 
    139        cls.display_doctitle = _add_prop_bool("/DisplayDocTitle", f_obj) 
    140 
    141        cls.non_fullscreen_pagemode = _add_prop_name( 
    142            "/NonFullScreenPageMode", 
    143            ["/UseNone", "/UseOutlines", "/UseThumbs", "/UseOC"], 
    144            NameObject("/UseNone"), 
    145        ) 
    146        cls.direction = _add_prop_name( 
    147            "/Direction", ["/L2R", "/R2L"], NameObject("/L2R") 
    148        ) 
    149        cls.view_area = _add_prop_name("/ViewArea", [], None) 
    150        cls.view_clip = _add_prop_name("/ViewClip", [], None) 
    151        cls.print_area = _add_prop_name("/PrintArea", [], None) 
    152        cls.print_clip = _add_prop_name("/PrintClip", [], None) 
    153        cls.print_scaling = _add_prop_name("/PrintScaling", [], None) 
    154        cls.duplex = _add_prop_name( 
    155            "/Duplex", ["/Simplex", "/DuplexFlipShortEdge", "/DuplexFlipLongEdge"], None 
    156        ) 
    157        cls.pick_tray_by_pdfsize = _add_prop_bool("/PickTrayByPDFSize", None) 
    158        cls.print_pagerange = _add_prop_arr("/PrintPageRange", None) 
    159        cls.num_copies = _add_prop_int("/NumCopies", None) 
    160 
    161        cls.enforce = _add_prop_arr("/Enforce", ArrayObject()) 
    162 
    163        return DictionaryObject.__new__(cls)