Coverage for pyPhotoAlbum/mixins/operations/edit_ops.py: 92%
75 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-20 12:55 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-20 12:55 +0000
1"""
2Edit operations mixin for pyPhotoAlbum
3"""
5from pyPhotoAlbum.decorators import ribbon_action
6from pyPhotoAlbum.commands import DeleteElementCommand, RotateElementCommand
9class EditOperationsMixin:
10 """Mixin providing edit-related operations"""
12 @ribbon_action(label="Undo", tooltip="Undo last action (Ctrl+Z)", tab="Home", group="Edit", shortcut="Ctrl+Z")
13 def undo(self):
14 """Undo last action"""
15 if self.project.history.undo():
16 self.update_view()
17 self.show_status("Undo successful", 2000)
18 print("Undo successful")
19 else:
20 self.show_status("Nothing to undo", 2000)
21 print("Nothing to undo")
23 @ribbon_action(
24 label="Redo", tooltip="Redo last action (Ctrl+Y or Ctrl+Shift+Z)", tab="Home", group="Edit", shortcut="Ctrl+Y"
25 )
26 def redo(self):
27 """Redo last action"""
28 if self.project.history.redo():
29 self.update_view()
30 self.show_status("Redo successful", 2000)
31 print("Redo successful")
32 else:
33 self.show_status("Nothing to redo", 2000)
34 print("Nothing to redo")
36 @ribbon_action(
37 label="Delete",
38 tooltip="Delete selected element (Delete key)",
39 tab="Home",
40 group="Edit",
41 shortcut="Delete",
42 requires_selection=True,
43 )
44 def delete_selected_element(self):
45 """Delete the currently selected element"""
46 if not self.require_selection(min_count=1):
47 return
49 current_page = self.get_current_page()
50 if not current_page:
51 return
53 # Delete the first selected element (for backward compatibility)
54 # In the future, we could delete all selected elements
55 selected_element = next(iter(self.gl_widget.selected_elements))
57 try:
58 cmd = DeleteElementCommand(current_page.layout, selected_element, asset_manager=self.project.asset_manager)
59 self.project.history.execute(cmd)
61 # Clear selection
62 self.gl_widget.selected_elements.clear()
64 # Update display
65 self.update_view()
67 self.show_status("Element deleted (Ctrl+Z to undo)", 2000)
68 print("Deleted selected element")
70 except Exception as e:
71 self.show_error("Error", f"Failed to delete element: {str(e)}")
72 print(f"Error deleting element: {e}")
74 @ribbon_action(
75 label="Rotate Left",
76 tooltip="Rotate selected element 90° counter-clockwise",
77 tab="Arrange",
78 group="Transform",
79 requires_selection=True,
80 )
81 def rotate_left(self):
82 """Rotate selected element 90 degrees counter-clockwise"""
83 if not self.require_selection(min_count=1):
84 return
86 selected_element = next(iter(self.gl_widget.selected_elements))
87 old_rotation = selected_element.rotation
88 new_rotation = (old_rotation - 90) % 360
90 cmd = RotateElementCommand(selected_element, old_rotation, new_rotation)
91 self.project.history.execute(cmd)
93 self.update_view()
94 self.show_status(f"Rotated left (Ctrl+Z to undo)", 2000)
95 print(f"Rotated element left: {old_rotation}° → {new_rotation}°")
97 @ribbon_action(
98 label="Rotate Right",
99 tooltip="Rotate selected element 90° clockwise",
100 tab="Arrange",
101 group="Transform",
102 requires_selection=True,
103 )
104 def rotate_right(self):
105 """Rotate selected element 90 degrees clockwise"""
106 if not self.require_selection(min_count=1):
107 return
109 selected_element = next(iter(self.gl_widget.selected_elements))
110 old_rotation = selected_element.rotation
111 new_rotation = (old_rotation + 90) % 360
113 cmd = RotateElementCommand(selected_element, old_rotation, new_rotation)
114 self.project.history.execute(cmd)
116 self.update_view()
117 self.show_status(f"Rotated right (Ctrl+Z to undo)", 2000)
118 print(f"Rotated element right: {old_rotation}° → {new_rotation}°")
120 @ribbon_action(
121 label="Reset Rotation",
122 tooltip="Reset selected element rotation to 0°",
123 tab="Arrange",
124 group="Transform",
125 requires_selection=True,
126 )
127 def reset_rotation(self):
128 """Reset selected element rotation to 0 degrees"""
129 if not self.require_selection(min_count=1):
130 return
132 selected_element = next(iter(self.gl_widget.selected_elements))
133 old_rotation = selected_element.rotation
135 if old_rotation == 0:
136 self.show_status("Element already at 0°", 2000)
137 return
139 cmd = RotateElementCommand(selected_element, old_rotation, 0)
140 self.project.history.execute(cmd)
142 self.update_view()
143 self.show_status("Reset rotation to 0° (Ctrl+Z to undo)", 2000)
144 print(f"Reset element rotation: {old_rotation}° → 0°")