mirror of
https://github.com/1j01/textual-paint.git
synced 2025-01-03 20:34:12 +03:00
Confirm discarding information during Save/Open/New, not just Save As
This commit is contained in:
parent
29e9e7a384
commit
faa41d07b2
@ -171,7 +171,6 @@ To preview ANSI art files in file managers like Nautilus, Thunar, Nemo, or Caja,
|
||||
|
||||
## Known Issues
|
||||
|
||||
- When saving as a TXT file, color information is discarded without warning. It is considered saved, so the backup will be discarded, even though the saved file doesn't match the visible document.
|
||||
- Undo/Redo doesn't work inside the Text tool's textbox. Ctrl+Z will delete the textbox. (Also note that the Text tool works differently from MS Paint; it will overwrite characters and the cursor can move freely, which makes it better for ASCII art and worse for prose.)
|
||||
- The selection box border appears inside instead of outside (and lacks dashes). For the text box, I hid the border because it was too visually confusing, but it should also have an outer border.
|
||||
- Pick Color can't be cancelled (with Esc or by pressing both mouse buttons), since it samples the color continuously.
|
||||
|
@ -2550,6 +2550,20 @@ class PaintApp(App[None]):
|
||||
self.message_box(dialog_title, _("An unexpected error occurred while writing %1.", file_path), "ok", error=e)
|
||||
return False
|
||||
|
||||
def reload_after_save(self, content: bytes, file_path: str) -> None:
|
||||
"""Reload the document from saved content, to show information loss from the file format.
|
||||
|
||||
Unlike `open_from_file_path`, this method:
|
||||
- doesn't short circuit when the file path matches the current file path, crucially
|
||||
- skips backup management
|
||||
- skips the file system, which is more efficient
|
||||
- fails to handle errors... FIXME
|
||||
"""
|
||||
self.resize_document(self.image.width, self.image.height) # (hackily) make this undoable
|
||||
new_image = AnsiArtDocument.decode_based_on_file_extension(content, file_path)
|
||||
self.canvas.image = self.image = new_image
|
||||
self.canvas.refresh(layout=True)
|
||||
|
||||
async def save(self) -> bool:
|
||||
"""Save the image to a file.
|
||||
|
||||
@ -2558,13 +2572,20 @@ class PaintApp(App[None]):
|
||||
self.stop_action_in_progress()
|
||||
dialog_title = _("Save")
|
||||
if self.file_path:
|
||||
format_id = AnsiArtDocument.format_from_extension(self.file_path)
|
||||
information_loss = await self.confirm_information_loss_async(format_id or "ANSI")
|
||||
try:
|
||||
content = self.image.encode_based_on_file_extension(self.file_path)
|
||||
content = self.image.encode_to_format(format_id)
|
||||
except FormatWriteNotSupported as e:
|
||||
self.message_box(_("Save"), e.localized_message, "ok")
|
||||
return False
|
||||
if self.write_file_path(self.file_path, content, dialog_title):
|
||||
self.saved_undo_count = len(self.undos)
|
||||
if information_loss:
|
||||
# Note: this fails to preview the lost information in the case
|
||||
# of saving the old file in prompt_save_changes,
|
||||
# because the document will be unloaded.
|
||||
self.reload_after_save(content, self.file_path)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@ -2610,10 +2631,7 @@ class PaintApp(App[None]):
|
||||
self.saved_undo_count = len(self.undos)
|
||||
window.close()
|
||||
if reload_after_save:
|
||||
self.resize_document(self.image.width, self.image.height) # (hackily) make this undoable
|
||||
new_image = AnsiArtDocument.decode_based_on_file_extension(content, file_path)
|
||||
self.canvas.image = self.image = new_image
|
||||
self.canvas.refresh(layout=True)
|
||||
self.reload_after_save(content, file_path)
|
||||
saved_future.set_result(None)
|
||||
|
||||
# TODO: should this look for a backup file and offer to recover it?
|
||||
@ -2753,7 +2771,7 @@ class PaintApp(App[None]):
|
||||
self.message_box(_("Paint"), message, "yes/no", handle_button)
|
||||
|
||||
def confirm_information_loss(self, format_id: str, callback: Callable[[bool], None]) -> None:
|
||||
"""Confirms discarding information when saving as a particular format."""
|
||||
"""Confirms discarding information when saving as a particular format. Callback variant. Never calls back if unconfirmed."""
|
||||
if format_id in ("ANSI", "SVG", "HTML", "RICH_CONSOLE_MARKUP"):
|
||||
callback(False)
|
||||
elif format_id == "PLAINTEXT":
|
||||
@ -2761,6 +2779,12 @@ class PaintApp(App[None]):
|
||||
else:
|
||||
self.confirm_lose_text_information(lambda: callback(True))
|
||||
|
||||
async def confirm_information_loss_async(self, format_id: str) -> Coroutine[None, None, bool]:
|
||||
"""Confirms discarding information when saving as a particular format. Awaitable variant, which uses the callback variant."""
|
||||
future = asyncio.get_running_loop().create_future()
|
||||
self.confirm_information_loss(format_id, lambda result: future.set_result(result))
|
||||
return await future
|
||||
|
||||
def is_document_modified(self) -> bool:
|
||||
"""Returns whether the document has been modified since the last save."""
|
||||
return len(self.undos) != self.saved_undo_count
|
||||
|
Loading…
Reference in New Issue
Block a user