Skip to content

Commit

Permalink
Save AND Save as ... actions
Browse files Browse the repository at this point in the history
  • Loading branch information
hnesk committed Oct 20, 2020
1 parent f64cfd5 commit 03c9e86
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 52 deletions.
6 changes: 5 additions & 1 deletion gresources/gtk/menus.ui
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
<attribute name="label" translatable="yes">_Close</attribute>
<attribute name="accel">&lt;Primary&gt;w</attribute>
</item>

<item>
<attribute name="action">win.save</attribute>
<attribute name="label" translatable="yes">_Save</attribute>
<attribute name="accel">&lt;Primary&gt;s</attribute>
</item>
<item>
<attribute name="action">app.new</attribute>
<attribute name="label" translatable="yes">_New</attribute>
Expand Down
2 changes: 1 addition & 1 deletion ocrd_browser/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def on_about(self, _action: Gio.SimpleAction, _param: str = None) -> None:
about_dialog.present()

def on_quit(self, _action: Gio.SimpleAction, _param: str = None) -> None:
open_windows:int = 0
open_windows: int = 0
window: MainWindow
for window in self.get_windows():
if isinstance(window, MainWindow) and window.close_confirm():
Expand Down
32 changes: 17 additions & 15 deletions ocrd_browser/model/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,11 @@ def save(self, backup_directory: Union[bool, Path, str] = True):
if not self._original_url:
raise ValueError('Need an _original_url to save')
self.save_as(self._original_url, backup_directory=backup_directory)
self._modified = False

def save_as(self, mets_url: Union[Path, str], backup_directory: Union[bool, Path, str] = True) -> None:
log = getLogger('ocrd_browser.model.document.Document.save_as')
mets_path = Path(self._strip_local(mets_url, disallow_remote=True))

workspace_directory = mets_path.parent
if workspace_directory.exists():
if backup_directory:
Expand All @@ -139,6 +140,8 @@ def save_as(self, mets_url: Union[Path, str], backup_directory: Union[bool, Path
self._emit('document_saving', 1, None)
self._emit('document_saved', Document(saved_space, self.emitter))
self._original_url = str(mets_path)
self._modified = False
log.info('Saved to %s', self._original_url)

@property
def directory(self) -> Path:
Expand Down Expand Up @@ -243,7 +246,8 @@ def get_file_index(self) -> Dict[str, OcrdFile]:
file.static_page_id = None
file_index[file.ID] = file

file_pointers: List[Element] = self.xpath('mets:structMap[@TYPE="PHYSICAL"]/mets:div[@TYPE="physSequence"]/mets:div[@TYPE="page"]/mets:fptr')
file_pointers: List[Element] = self.xpath(
'mets:structMap[@TYPE="PHYSICAL"]/mets:div[@TYPE="physSequence"]/mets:div[@TYPE="page"]/mets:fptr')
for file_pointer in file_pointers:
file_id = file_pointer.get('FILEID')
page_id = file_pointer.getparent().get('ID')
Expand All @@ -264,15 +268,16 @@ def get_image_paths(self, file_group: str) -> Dict[str, Path]:
image_paths = {}
file_index = self.get_file_index()
for page_id in self.page_ids:
images = [image for image in file_index.values() if image.static_page_id == page_id and image.fileGrp == file_group]
images = [image for image in file_index.values() if
image.static_page_id == page_id and image.fileGrp == file_group]
if len(images) == 1:
image_paths[page_id] = self.path(images[0])
else:
# log.warning('Found %d images for page %s and fileGrp %s, expected 1', len(images), page_id, file_group)
log.warning('Found %d images for PAGE %s and fileGrp %s, expected 1', len(images), page_id, file_group)
image_paths[page_id] = None
return image_paths

def get_default_image_group(self, preferred_image_file_groups:Optional[List] = None) -> Optional[str]:
def get_default_image_group(self, preferred_image_file_groups: Optional[List] = None) -> Optional[str]:
image_file_groups = []
for file_group, mimetype in self.file_groups_and_mimetypes:
weight = 0.0
Expand All @@ -286,17 +291,16 @@ def get_default_image_group(self, preferred_image_file_groups:Optional[List] = N
weight += (len(preferred_image_file_groups) - i)
break
# prefer shorter `file_group`s
weight -= len(file_group)*0.00001
image_file_groups.append((file_group,weight))
weight -= len(file_group) * 0.00001
image_file_groups.append((file_group, weight))
# Sort by weight
image_file_groups = sorted(image_file_groups, key=lambda e:e[1], reverse=True)
image_file_groups = sorted(image_file_groups, key=lambda e: e[1], reverse=True)

if len(image_file_groups) > 0:
return image_file_groups[0][0]
else:
return None


def get_unused_page_id(self, template_page_id: str = 'PAGE_{page_nr}') -> Tuple[str, int]:
"""
Finds a page_nr that yields an unused page_id for the workspace and returns page_id, page_nr
Expand Down Expand Up @@ -446,9 +450,8 @@ def add_image(self, image: ndarray, page_id: str, file_id: str, file_group: str
retval, image_array = cv2.imencode(extension, image)
image_bytes = add_dpi_to_png_buffer(image_array.tostring(), dpi)
local_filename = Path(file_group, '%s%s' % (file_id, extension))
url = (Path(self.workspace.directory) / local_filename)
current_file = self.workspace.add_file(file_group, ID=file_id, mimetype=mimetype, force=True,
content=image_bytes, url=str(url),
content=image_bytes,
local_filename=str(local_filename), pageId=page_id)
self._empty = False
self.save_mets()
Expand All @@ -467,7 +470,6 @@ def empty(self):
def original_url(self):
return self._original_url


@property
def editable(self):
return self._editable
Expand All @@ -480,8 +482,8 @@ def editable(self, editable):
else:
self.workspace = Resolver().workspace_from_url(self.baseurl_mets)
self._editable = editable
#self._empty = False
#self._modified = False
# self._empty = False
# self._modified = False


def _emit(self, event: str, *args: Any) -> None:
Expand Down Expand Up @@ -512,4 +514,4 @@ def delete_temporary_workspaces(cls):
raise


atexit.register(Document.delete_temporary_workspaces)
atexit.register(Document.delete_temporary_workspaces)
53 changes: 36 additions & 17 deletions ocrd_browser/resources/main-window.ui
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ THE SOFTWARE.
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<object class="GtkMenuButton" id="main_menu_button">
<property name="visible">True</property>
Expand Down Expand Up @@ -156,21 +159,6 @@ THE SOFTWARE.
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="save_button">
<property name="label">_Save</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">win.save</property>
<property name="use_underline">True</property>
<accelerator key="s" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
<child>
Expand Down Expand Up @@ -388,6 +376,37 @@ THE SOFTWARE.
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">win.save</property>
<property name="text" translatable="yes">_Save</property>
<accelerator key="s" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">win.save_as</property>
<property name="text" translatable="yes">Save _as ...</property>
<accelerator key="s" signal="activate" modifiers="GDK_CONTROL_MASK"/>

</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
Expand All @@ -396,7 +415,7 @@ THE SOFTWARE.
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">9</property>
<property name="position">11</property>
</packing>
</child>
<child>
Expand All @@ -410,7 +429,7 @@ THE SOFTWARE.
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">10</property>
<property name="position">12</property>
</packing>
</child>
</object>
Expand Down
12 changes: 10 additions & 2 deletions ocrd_browser/ui/dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,19 @@ def __init__(self, document: Document, **kwargs: Any):
Gtk.MessageDialog.__init__(self, **kwargs)
name = document.workspace.mets.unique_identifier if document.workspace.mets.unique_identifier else '<unnamed>'
self.props.text = 'Save changes to document "{}" before closing?'.format(name)
self.props.secondary_text = 'If you don’t save, changes to {} will be permanently lost.'.format(document.original_url if document.original_url else 'this file')
self.props.secondary_text = 'If you don’t save, changes to {} will be permanently lost.'.format(
document.original_url if document.original_url else 'this file')
self.props.message_type = Gtk.MessageType.QUESTION

# Close Button
close_button: Gtk.Button = self.add_button('Close without saving', Gtk.ResponseType.NO)
close_button.get_style_context().add_class('destructive-action')
cancel_button: Gtk.Button = self.add_button('_Cancel', Gtk.ResponseType.CANCEL)

# Cancel Button
self.add_button('_Cancel', Gtk.ResponseType.CANCEL)

# Save Button
save_text = '_Save' if document.original_url else '_Save as ...'
save_button: Gtk.Button = self.add_button(save_text, Gtk.ResponseType.YES)

self.set_default(save_button)
37 changes: 21 additions & 16 deletions ocrd_browser/ui/window.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from gi.repository import Gtk, GdkPixbuf, Gio, GObject, GLib
from gi.repository import Gtk, GdkPixbuf, Gio, GObject, GLib, Gdk
from ocrd_models import OcrdFile

from ocrd_browser.model import Document
Expand All @@ -20,7 +20,6 @@ class MainWindow(Gtk.ApplicationWindow):
current_page_label: Gtk.Label = Gtk.Template.Child()
view_container: Gtk.Box = Gtk.Template.Child()
view_menu_box: Gtk.Box = Gtk.Template.Child()
save_button: Gtk.Button = Gtk.Template.Child()

def __init__(self, **kwargs: Any):
Gtk.ApplicationWindow.__init__(self, **kwargs)
Expand All @@ -43,6 +42,7 @@ def __init__(self, **kwargs: Any):
self.actions.create('create_view', param_type=GLib.VariantType("s"))
self.actions.create('toggle_edit_mode', state=GLib.Variant('b', False))
self.actions.create('save')
self.actions.create('save_as')

self.connect('delete-event', self.on_delete_event)

Expand Down Expand Up @@ -125,15 +125,17 @@ def document_changed(self, subtype: str, page_ids: List[str]) -> None:
self.update_ui()

@GObject.Signal(arg_types=[object])
def document_saved(self, saved: Document) -> None:
def document_saved(self, _saved: Document) -> None:
self.update_ui()

@GObject.Signal(arg_types=[float,object])
@GObject.Signal(arg_types=[float, object])
def document_saving(self, progress: float, file: Optional[OcrdFile]) -> None:
pass

def update_ui(self) -> None:
title = self.document.workspace.mets.unique_identifier if self.document.workspace.mets.unique_identifier else '<unnamed>'
if self.document.modified:
title = title + ' *'
self.set_title(title)
self.header_bar.set_title(title)
self.header_bar.set_subtitle(self.document.original_url)
Expand All @@ -153,7 +155,7 @@ def update_ui(self) -> None:
self.actions['page_remove'].set_enabled(self.document.editable)
self.actions['toggle_edit_mode'].set_state(GLib.Variant.new_boolean(self.document.editable))
self.actions['save'].set_enabled(self.document.modified)
self.save_button.set_label('Save' if self.document.original_url else 'Save as ...')
# self.actions['save_as'].set_enabled(self.document.modified)
for view in self.views:
view.update_ui()

Expand All @@ -178,7 +180,7 @@ def on_close(self, _a: Gio.SimpleAction = None, _p: None = None) -> None:
if self.close_confirm():
self.destroy()

def on_delete_event(self, *args, **kwargs):
def on_delete_event(self, _window: 'MainWindow', _event: Gdk.Event):
return not self.close_confirm()

def on_goto_first(self, _a: Gio.SimpleAction = None, _p: None = None) -> None:
Expand All @@ -187,10 +189,10 @@ def on_goto_first(self, _a: Gio.SimpleAction = None, _p: None = None) -> None:
def on_go_forward(self, _a: Gio.SimpleAction = None, _p: None = None) -> None:
self.page_list.skip(1)

def on_go_back(self, _a: Gio.SimpleAction = None, _p: None = None) -> None:
def on_go_back(self, _a: Gio.SimpleAction = None, _p: None = None) -> None:
self.page_list.skip(-1)

def on_goto_last(self, _a: Gio.SimpleAction = None, _p: None = None) -> None:
def on_goto_last(self, _a: Gio.SimpleAction = None, _p: None = None) -> None:
self.page_list.goto_index(-1)

def on_create_view(self, _a: Gio.SimpleAction, selected_view_id: GLib.Variant) -> None:
Expand All @@ -213,28 +215,31 @@ def on_close_view(self, _action: Gio.SimpleAction, view_name: GLib.Variant) -> N

def on_save(self, _a: Gio.SimpleAction = None, _p: None = None):
if self.document.original_url:
self.save(None)
return self.save()
else:
self.save_as(None)
return self.save_as()

def on_save_as(self, _a: Gio.SimpleAction = None, _p: None = None):
self.save_as()

def save(self, _a: Gio.SimpleAction = None, _p: None = None) -> None:
def save(self) -> bool:
self.document.save()
self.update_ui()
return True

def save_as(self, _a: Gio.SimpleAction = None, _p: None = None) -> None:
def save_as(self) -> bool:
save_dialog = SaveDialog(application=self.get_application(), transient_for=self, modal=True)
if self.document.original_url:
save_dialog.set_filename(self.document.original_url)
else:
#save_dialog.set_current_folder()
save_dialog.set_current_name('mets.xml')
response = save_dialog.run()
if response == Gtk.ResponseType.OK:
should_save = response == Gtk.ResponseType.OK
if should_save:
self.document.save_as(save_dialog.get_uri())
save_dialog.destroy()
self.update_ui()
return response == Gtk.ResponseType.OK

return should_save

def on_toggle_edit_mode(self, _a: Gio.SimpleAction = None, _p: None = None):
self.document.editable = not self.document.editable
Expand Down

0 comments on commit 03c9e86

Please sign in to comment.