ClipmanLinux/context_help.py
Rama main · réplica de lectura del repositorio original.
"""Focused-control help. Field values are never used as help content."""
INSTRUCTIONS = {
"history sections": "Switch between enabled history sections. Left and Right select a section; Alt+Left and Alt+Right reorder its tab.",
"search clipboard history": "Filter visible clips by their text. Clear the search to show all clips in the current section and group or device filter.",
"filter by group or device": "Show clips belonging to one group or device. All removes this filter; the search and selected history section still apply.",
"enable clipmerge": "Copy the same selection twice within the merge window to start appending. Formatted text becomes plain text; file copies and cuts only merge with matching operations.",
"custom clipmerge text separator": "Text inserted between appended selections when Custom is selected. Backslash n, backslash r backslash n, backslash r and backslash t are supported.",
"custom multiple-entry separator": "Text inserted between selected clips copied together when Custom is selected. This is independent of ClipMerge; backslash escape sequences are supported.",
"after enter, paste into the previous application": "Enter copies the selected clip, closes history, returns to the previous application and pastes. This requires the desktop session to allow simulated keyboard input.",
"keep duplicate text entries": "Retain separate copies when captured text already exists. When disabled, Clipman reuses the existing entry.",
"confirm before deleting entries": "Ask before removing history entries. Removing file-history records never deletes the original files.",
"run clipman when this desktop session starts": "Start the background clipboard manager when you sign into this desktop session; history stays hidden until requested.",
"automatically remove unavailable file-history events": "Remove unpinned file events whose original paths no longer exist. The original files are never deleted.",
"install updates silently": "Install available Linux-client updates without asking. Settings and history are preserved and Clipman restarts afterward.",
"change server connection and device name": "Review this device's identity, storage folder, server address, token and history password in the connection dialog.",
"sync rules": "Route clips into named channels and choose which channels each device receives. Enable only after every device supports sync rules.",
"preference sections": "Choose a preference section. Control+1 through Control+6 select sections directly; Tab moves into their controls.",
"save and close": "Apply the pending preferences and close this dialog. Cancel discards changes that have not been saved.",
"save and connect": "Save reviewed connection details and connect using the history password. A new password selects a separate server bucket.",
"server address": "Enter the reachable server address and port. Use HTTPS for a remote connection; 0.0.0.0 is a listen address, not a client destination.",
"enable sync rules": "Route new clips into channels using the saved rules. Unchecked restores main-history behavior without deleting the rule definitions.",
"add channel": "Create a routing channel. The first matching rule receives each clip; unmatched clips stay in main history.",
"edit channel": "Change the selected channel's routing conditions. Saving may relocate matching clips.",
"remove channel": "Remove the channel and relocate its clips back to another matching channel or main history, without deleting them.",
"edit device subscriptions": "Select which channels the chosen device receives. Unsubscribing hides clips locally without deleting shared history.",
"channel name": "Use 1 to 32 letters, digits, spaces, hyphens or underscores. Reserved names cannot be used.",
"groups, comma-separated": "Match any of these group names. Leave blank to match every group. Group and device conditions must both match.",
"source devices, comma-separated": "Match any of these source device names. Leave blank to match every device.",
"match rich text containing embedded images": "Require the clip to contain an embedded image as well as meeting any group and source-device conditions.",
"pinned": "Protect this entry from normal history limits and bulk clearing. Unpin it to let those rules apply again.",
"resolve template fields when copied": "Expand supported template fields when this clip is copied. Use Preview Template to inspect the result without changing the saved text.",
"use as a quick paste target": "Assign a global shortcut to this entry. The Quick Paste mode determines how that shortcut affects the clipboard.",
"quick paste mode": "Choose whether the shortcut pastes and restores the previous clipboard, pastes and keeps this clip, or copies without pasting.",
"insert sample": "Insert the selected sample template into the editor at its cursor.",
"insert field": "Insert the selected template field into the editor at its cursor.",
"template sample": "Select a sample, then use Insert Sample to put it into the editor.",
"template field": "Select a variable, then use Insert Field to put it into the editor.",
"preview template": "Show the text after template fields are resolved without changing the saved template.",
"resolved template preview": "Read the resolved template output. This preview is not editable and does not change the saved clip.",
"formatted clipboard text": "Read the selected formatted clip. Copying the history entry preserves supported formatting.",
"file paths": "Read the original paths referenced by this device-local file event. Viewing or clearing the event does not change the files.",
"saved secrets": "Device-local secret names, with values hidden. Select a secret to edit, delete or paste it.",
"secret name": "Visible label for a device-local secret. Its value is kept out of shared history.",
"secret value": "Private value kept in this device's encrypted secrets database. Help never reads its contents.",
"confirm secret value": "Retype the private value to catch mistakes before saving.",
"remember on this device": "Protect and retain the history password for this Linux user so it need not be entered each session.",
"remember history password on this device": "Protect and retain the history password for this Linux user so it need not be entered each session.",
"import private authority": "Import the public certificate of a private authority for this HTTPS server. Verify its fingerprint with the server owner.",
"remove private authority": "Remove Clipman's app-specific private authority without changing the server address or token.",
"import clipman server connection file": "Import server connection details, review them, set your history password and save before syncing.",
"import file password": "Password used to decrypt the selected history export. It need not match the current history password.",
"current history password": "Unlock the history before exporting. The export can use its own separate encryption password.",
"export password choice": "Keep the history password, choose a different export password, or export without encryption after confirmation.",
"new export password": "Encrypt this export with a separate password. It does not change the live history password.",
"confirm new export password": "Retype the export password to catch mistakes before the export is written.",
"do not show this again": "Skip future website-title confirmations. Explicit requests still make network contact; unsafe destinations remain blocked.",
"do not ask again before deleting entries": "Turn off future deletion confirmations. You can turn them back on in Preferences.",
"add": "Create a new device-local secret with a name, private value and optional shortcut.",
"edit": "Edit the selected secret's name, private value and optional shortcut.",
"delete": "Remove the selected secret after confirmation without altering shared history.",
"paste": "Paste the selected secret using its configured mode, without adding its value to shared history.",
"device name": "Name recorded on newly captured clips. Existing clips keep their original device name.",
"history storage type": "Local or shared folder uses your data folder. Clipman Server exchanges encrypted history; file events and secrets remain device-local.",
"server host": "Enter the reachable server address and port. Use HTTPS for a remote connection. A wildcard listen address is not a client destination.",
"server token": "Private server access credential. The token lets you connect; the history password selects and encrypts your separate history bucket.",
"history password": "Unlock encrypted history. Use the same password only on devices that should share that history. The server never receives this password.",
"confirm password": "Retype the new history password to catch mistakes before saving.",
"data folder": "Use a dedicated folder for settings and history. For sharing, the chosen provider must actually synchronize its files.",
"settings folder": "Use a dedicated folder for settings and history. For sharing, the chosen provider must actually synchronize its files.",
"monitor clipboard text, links and files while clipman is running": "Record new clipboard events automatically. Turning this off does not remove history; deliberate capture remains separate.",
"add current clipboard item when clipman starts": "Capture the clipboard once at startup, following monitoring, exclusion and privacy settings. Off by default.",
"play sounds": "Play sounds for accepted copy, sync and monitoring events without changing capture behavior.",
"clipmerge window in milliseconds": "Time allowed for a deliberate second copy to start appending, from 200 to 2000 milliseconds. Shorter windows reduce accidental merges.",
"clipmerge text separator": "Choose what goes between appended clipboard selections. This is independent of copying several selected history entries.",
"multiple selected entries separator": "Choose what goes between entries copied together from history. No separator joins them directly; this does not change ClipMerge.",
"automatically group new clips by source application": "Use the source application as the group for newly captured clips. Existing groups are unchanged.",
"put new text received from another device on the clipboard": "Copy newly created remote text onto this device's clipboard. Reusing an older remote entry does not trigger this.",
"open history to the section that most recently received an item": "Select the history section for the most recent accepted clipboard type when opening history.",
"automatically remove tracking from copied links": "Remove recognized tracking parameters from new links. Disable this to keep the original destination unchanged.",
"show links history": "Show standalone HTTP and HTTPS links separately. When disabled, they remain in Text history.",
"save list position": "Remember your place in each history section after closing and reopening it.",
"duplicate handling": "Move to top reuses an existing entry; Ignore leaves it in place; Keep both retains separate copies.",
"maximum entries": "Limit normal history by count. Zero means no limit; pinned entries are retained.",
"maximum age in days": "Limit normal history by age. Zero means no limit; pinned entries are retained.",
"check for updates": "Choose when automatic Linux-client update checks run. Never still permits manual checks.",
"ignored applications": "One application or process name per line. Automatic capture ignores these apps; explicit imports remain separate.",
"sensitive data mode": "Exclude selected detected patterns from automatic capture. Existing history, the system clipboard and deliberate imports are unchanged.",
"entry name": "Give this clip a descriptive name without changing its text or image content.",
"name": "Give this clip a descriptive name without changing its text or image content.",
"group": "Organize this entry under a group. Group names differing only by case are treated as the same group.",
"clipboard text": "Edit the stored text. Enter inserts a new line; Control+Enter saves. Tab leaves the editor rather than inserting a tab.",
"text history": "Select clips with the arrow keys. Enter copies and closes, optionally pasting according to Preferences. F2 edits; F4 views.",
"links history": "Select links with the arrow keys. Control+Enter copies name and destination; Alt+Enter opens the link and closes History.",
"rich text history": "Formatted clips and embedded images. Copy preserves supported formatting. Alt+Enter opens a selected image in its default application.",
"file history": "Device-local file events, not uploaded files. Enter restores the file selection to the clipboard. Alt+Enter reveals one selected file or folder and closes History. Clearing history does not delete original files.",
"sync channels": "Rules are evaluated in order. The first matching channel receives an entry; unmatched entries stay in main history.",
"devices": "Choose a device and edit the channels it receives. Unsubscribing hides clips locally without deleting them from shared history.",
"cancel": "Dismiss this dialog without accepting pending changes.",
"save": "Save pending changes. In a clip editor, Enter inserts a new line and Control+Enter saves.",
"close": "Close this window and return to the previous control.",
}
def description_for(name, hint=None):
if hint:
return hint
return INSTRUCTIONS.get(name.strip().rstrip(".").casefold(), "Use the focused control in this window. Tab moves forward; Shift+Tab moves backward. The manual covers the complete workflow.")
def set_properties(widget, properties, values):
from gi.repository import Gtk
forwarded, content = [], []
for prop, value in zip(properties, values):
if prop == Gtk.AccessibleProperty.DESCRIPTION:
widget._clipman_help = value
value = ""
elif prop == Gtk.AccessibleProperty.LABEL:
widget._clipman_help_name = value
forwarded.append(prop)
content.append(value)
widget.update_property(forwarded, content)
def focused_content(widget):
from gi.repository import Gtk
current = widget
while current is not None:
# Row labels can contain the full clip or a secret name; use their list.
if not isinstance(current, (Gtk.ListBoxRow, Gtk.Label)):
name = getattr(current, "_clipman_help_name", None)
if not name and isinstance(current, Gtk.Button):
name = current.get_label()
if not name and isinstance(current, Gtk.CheckButton):
name = current.get_label()
if name:
name = name.replace("_", "").strip()
return name, description_for(name, getattr(current, "_clipman_help", None))
current = current.get_parent()
return "Current window", description_for("Current window")
def attach(window, manual):
from gi.repository import Gdk, Gtk
if getattr(window, "_clipman_help_controller", None):
return
controller = Gtk.EventControllerKey()
controller.set_propagation_phase(Gtk.PropagationPhase.CAPTURE)
def pressed(_controller, keyval, _keycode, state):
modifiers = state & (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.ALT_MASK |
Gdk.ModifierType.SHIFT_MASK | Gdk.ModifierType.SUPER_MASK |
Gdk.ModifierType.META_MASK | Gdk.ModifierType.HYPER_MASK)
if keyval != Gdk.KEY_F1 or modifiers:
return False
show(window, manual)
return True
controller.connect("key-pressed", pressed)
window.add_controller(controller)
window._clipman_help_controller = controller
def show(owner, manual):
from gi.repository import Gtk
if owner is None or getattr(owner, "_clipman_help_dialog", False):
return
if getattr(owner, "_clipman_active_help", None):
return
focused = owner.get_focus()
name, instructions = focused_content(focused)
dialog = Gtk.Dialog(title="Help: " + name, transient_for=owner, modal=True)
dialog._clipman_help_dialog = True
owner._clipman_active_help = dialog
dialog.set_default_size(580, 300)
area = dialog.get_content_area()
view = Gtk.TextView(editable=False, cursor_visible=True, wrap_mode=Gtk.WrapMode.WORD_CHAR)
view.set_accepts_tab(False)
view.get_buffer().set_text(instructions)
view.update_property([Gtk.AccessibleProperty.LABEL], [name + " help"])
scroll = Gtk.ScrolledWindow(vexpand=True, hexpand=True)
scroll.set_child(view)
area.append(scroll)
dialog.add_button("Open _Manual", Gtk.ResponseType.HELP)
dialog.add_button("_Close", Gtk.ResponseType.CLOSE)
def finished(_dialog, code):
if code == Gtk.ResponseType.HELP:
manual()
return
dialog.destroy()
owner._clipman_active_help = None
if focused is not None and focused.get_root() is owner:
focused.grab_focus()
dialog.connect("response", finished)
def close_requested(*_args):
finished(dialog, Gtk.ResponseType.CLOSE)
return True
dialog.connect("close-request", close_requested)
dialog.present()
view.grab_focus()