Skip to content

Commit

Permalink
GUI. Changed cut/copy/paste behaviour when the clipboard library is n…
Browse files Browse the repository at this point in the history
…ot present: Put iCal object on clipboard as text. When pasting, try to interpret data as iCal object, and only use as text if that doesn't work.
  • Loading branch information
semiprime committed May 25, 2024
1 parent 754e47e commit ccfdecb
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 30 deletions.
14 changes: 9 additions & 5 deletions docs/Development.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ clipboard library manually, as in the section below.)

Building clipboard library
--------------------------
This is a small C library required for cutting/copying entries. Built
automatically with `./setup.py install`. Tested on Gemian, postmarketOS
and Slackware, and probably works on other Linux distributions. It might
need tweaking for Windows/MacOS/BSD/other. To build by hand and copy to
the correct location in the source tree:
This is a small C library to improve cutting/copying behaviour.
Specifically it allows Pygenda entries to be copied+pasted as text
into applications that expect text, and as calendar entries into
applications that expect clendar entries. Built automatically with
`./setup.py install`. Tested on Gemian, postmarketOS and Slackware,
and probably works on other Linux distributions. It might need
tweaking for Windows/MacOS/BSD/other.

To build by hand and copy to the correct location in the source tree:

cd csrc
cmake .
Expand Down
5 changes: 0 additions & 5 deletions docs/known_issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,6 @@ Medium

* An undo/redo function would be useful

* Copying/cutting entries doesn't work on all platforms. This functionality
relies on a small C library, due to limits of Python GObject module.
Builds on my devices and on Gemini. Needs looking at for other Linux
distributions and Windows/MacOS.

* Softkeys should be user-customisable

* Date/time widgets are not easy to click (tap) on since most of the area
Expand Down
51 changes: 31 additions & 20 deletions pygenda/pygenda_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ def _init_clipboard(cls) -> None:
libclip_file = '{:s}/libpygenda_clipboard.so'.format(ospath.dirname(__file__))
cls._lib_clip = ctypes.CDLL(libclip_file)
except:
print('Warning: Failed to load clipboard library', file=stderr)
print('Notice: Clipboard library not found, using fallback', file=stderr)


@classmethod
Expand Down Expand Up @@ -877,22 +877,17 @@ def cut_request(cls, *args) -> bool:
# Handler to implement "cut" from GUI, e.g. cut clicked in menu
en = cls.views[cls._view_idx].get_cursor_entry()
if en and 'SUMMARY' in en:
if cls._lib_clip is None:
# Don't do fallback - might lead to unexpected data loss
print('Warning: No clipboard library, cut not available', file=stderr)
elif 'RRULE' in en: # repeating entry
if 'RRULE' in en: # repeating entry
# Need to think about how to implement this from UI side.
# Problem: Does user expect single occurrence to be cut, or all?
# Maybe bring up dialog "Cut single occurrence, or all repeats?"
# Then, do we do the came for Copying repeating entries?
# How do we adapt repeats when moved to a different date?
print('Warning: Cutting repeating entries not implemented', file=stderr)
else:
txtbuf = bytes(en['SUMMARY'], 'utf-8')
calbuf = en.to_ical()
cls._lib_clip.set_cb(ctypes.create_string_buffer(txtbuf),ctypes.create_string_buffer(calbuf))
Calendar.delete_entry(en)
cls.view_redraw(en_changes=True)
return True
cls._put_entry_on_clipboard(en)
Calendar.delete_entry(en)
cls.view_redraw(en_changes=True)
return True # don't propagate event


Expand All @@ -901,18 +896,21 @@ def copy_request(cls, *args) -> bool:
# Handler to implement "copy" from GUI, e.g. copy clicked in menu
en = cls.views[cls._view_idx].get_cursor_entry()
if en and 'SUMMARY' in en:
if cls._lib_clip is None:
print('Warning: No clipboard library, fallback to text copy', file=stderr)
cb = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
txt = en['SUMMARY']
cb.set_text(txt, -1)
else:
txtbuf = bytes(en['SUMMARY'], 'utf-8')
calbuf = en.to_ical()
cls._lib_clip.set_cb(ctypes.create_string_buffer(txtbuf),ctypes.create_string_buffer(calbuf))
cls._put_entry_on_clipboard(en)
return True # don't propagate event


@classmethod
def _put_entry_on_clipboard(cls, en:Union[iEvent,iTodo]) -> None:
calbuf = en.to_ical()
if cls._lib_clip is None:
cb = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
cb.set_text(calbuf.decode('utf-8'), -1)
else:
txtbuf = bytes(en['SUMMARY'], 'utf-8')
cls._lib_clip.set_cb(ctypes.create_string_buffer(txtbuf),ctypes.create_string_buffer(calbuf))


@classmethod
def paste_request(cls, *args) -> bool:
# Handler to implement "paste" from GUI, e.g. paste clicked in menu
Expand All @@ -929,6 +927,19 @@ def paste_request(cls, *args) -> bool:
# Fallback: request plain text from clipboard
txt = cb.wait_for_text()
if txt: # might be None
if cls._lib_clip is None:
# "Text" might be ical data, let's check...
try:
ical = iCalendar.from_ical(txt)
en = ical.walk()[0]
cls.views[cls._view_idx].paste_entry(en)
cls.view_redraw(en_changes=True)
return True
except:
pass
# We got text. Either clipboard library is present, or
# there was an exception trying to treat it as ical data.
# So, let's just treat it as plain text...
txt = cls._sanitise_pasted_text(txt)
# Type of entry created depends on View, so call View paste fn
if txt:
Expand Down

0 comments on commit ccfdecb

Please sign in to comment.