"""Clipboard management."""
from __future__ import annotations
from pyramid.config import Configurator
from pyramid.registry import Registry
from pyramid.request import Request
from ..lib.i18n import _
from ..lib.navigation import NavPanel
from ..lib.panel import PANEL_ITEM_PREFIX, Panel
from ..models.dbsettings import SETTINGS_DEFAULTS
CLIPBOARD_LABEL_MAX_LENGTH = 96
CLIPBOARD_LABEL_MAX_ITEMS = 8
# =============================================================================
[docs]
def includeme(configurator: Configurator):
"""Function to include the clipboard.
:type configurator: pyramid.config.Configurator
:param configurator:
Object used to do configuration declaration within the application.
"""
if isinstance(configurator, Configurator):
if 'panels' not in configurator.registry:
configurator.registry['panels'] = {}
if 'clipboard' not in configurator.registry['panels']:
Clipboard.register(configurator.registry, Clipboard)
# =============================================================================
[docs]
class NavClipboard(NavPanel):
"""Entry for clipboard."""
# -------------------------------------------------------------------------
# =============================================================================
[docs]
class Clipboard(Panel):
"""Class to manage clipboard and clipboard panel.
See: :class:`.lib.panel.Panel`
"""
uid = 'clipboard'
label = _('Clipboard')
nav_location = ('user', 1)
nav_button_class = 'cioNavClipboard'
nav_entry = NavClipboard
icon = '/images/panel_clipboard.png'
template = 'chrysalio:Templates/panel_clipboard.pt'
need_form = True
# -------------------------------------------------------------------------
# DEPRECATED: remove in version 2
[docs]
@classmethod
def register(
cls,
registry: Registry,
panel_class,
area: tuple[str, ...] | None = None) -> Panel | None:
"""Method to register the panel and possibly add it to a navigation
menu.
See: :meth:`.lib.panel.Panel.register`
"""
super().register(registry, panel_class, area)
if 'systray' not in registry:
registry['systray'] = []
registry['systray'].append(registry['panels'][panel_class.uid])
return registry['panels'][panel_class.uid]
# -------------------------------------------------------------------------
[docs]
@classmethod
def is_empty(cls, request: Request) -> bool:
"""Return ``True`` if the clipboard is empty.
:type request: pyramid.request.Request
:param request:
Current request.
:rtype: bool
"""
return bool(not request.session.get('clipboard'))
# -------------------------------------------------------------------------
[docs]
@classmethod
def entries(cls, request: Request) -> list:
"""Return the list of entries.
:type request: pyramid.request.Request
:param request:
Current request.
:rtype: list
"""
return request.session['clipboard'] \
if 'clipboard' in request.session else []
# -------------------------------------------------------------------------
[docs]
@classmethod
def push(
cls, request: Request, domain: str, cut: bool, data, preview: str):
"""Push a new entry in the clipboard buffer.
:type request: pyramid.request.Request
:param request:
Current request.
:param str domain:
Domain of the entry (ex.: ``'warehouse/file'``).
:param bool cut:
``True`` if it is a `cut` operation.
:param data:
Content of this entry. It depends on the domain.
:type preview: helpers.literal.Literal
:param preview:
Representation of the entry in the clipboard.
"""
# Ajust size
if 'clipboard' not in request.session:
request.session['clipboard'] = []
request.session['clipboard'] = request.session[
'clipboard'][:request.registry['settings'].get(
'clipboard-size', SETTINGS_DEFAULTS['clipboard-size']) - 1]
# Push the new entry in the buffer
request.session['clipboard'].insert(0, (domain, cut, data, preview))
# -------------------------------------------------------------------------
[docs]
@classmethod
def selection(cls, request: Request, domains: list) -> list:
"""Return entries selected in the clipboard and compatible with almost
one domain of ``domains``.
:type request: pyramid.request.Request
:param request:
Current request.
:param list domains:
List of accepted formats of the entry.
:rtype: list
"""
if 'clipboard' not in request.session \
or not request.session['clipboard']:
return []
# Selected entries
entries = []
kept_nums = []
requested_nums = cls._requested_numbers(request, domains)
for num in requested_nums:
entries.append(request.session['clipboard'][num])
if not request.session['clipboard'][num][1]:
kept_nums.append(num)
# Reorganization of the buffer
my_buffer = []
for num in kept_nums:
my_buffer.append(request.session['clipboard'][num])
for num in range(len(request.session['clipboard'])):
if num not in requested_nums:
my_buffer.append(request.session['clipboard'][num])
request.session['clipboard'] = my_buffer
return entries
# -------------------------------------------------------------------------
@classmethod
def _requested_numbers(cls, request: Request, domains: list) -> list:
"""Return a list of numbers of entry requested and compatible with
``domains``.
:type request: pyramid.request.Request
:param request:
Current request.
:param list domains:
List of accepted formats of the entry.
:rtype: list
"""
selected = []
size = len(request.session['clipboard'])
# Selected in the clipboard panel
for num in request.params:
if num.startswith(PANEL_ITEM_PREFIX):
num = int(num[len(PANEL_ITEM_PREFIX):])
if num < size and \
request.session['clipboard'][num][0] in domains:
selected.append(num)
if selected:
return selected
# The first compatible entry
for num in range(size):
if request.session['clipboard'][num][0] in domains:
selected.append(num)
break
return selected