root/gaphor/tags/gaphor-0.12.5/gaphor/ui/diagramtab.py

Revision 2083, 9.3 kB (checked in by arj..@yirdis.nl, 1 year ago)

Fixed bug #60. Create a list of selected items.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 #!/usr/bin/env python
2 # vim: sw=4:et
3
4 import gtk
5 from cairo import Matrix
6
7 from zope import component
8 from gaphor import UML
9 from gaphor.core import _, inject, transactional, action, build_action_group
10 from gaphor.diagram import get_diagram_item
11 from gaphor.diagram.items import DiagramItem
12 from gaphor.transaction import Transaction
13 from gaphor.ui.diagramview import DiagramView
14 from gaphor.ui.diagramtoolbox import DiagramToolbox
15 from event import DiagramSelectionChange
16
17 class DiagramTab(object):
18    
19     element_factory = inject('element_factory')
20     action_manager = inject('action_manager')
21
22     menu_xml = """
23       <ui>
24         <menubar action="mainwindow">
25           <menu action="edit">
26             <menuitem action="diagram-delete" />
27             <separator />
28             <menuitem action="diagram-select-all" />
29             <menuitem action="diagram-unselect-all" />
30           </menu>
31           <menu action="diagram">
32             <placeholder name="secondary">
33               <menuitem action="diagram-zoom-in" />
34               <menuitem action="diagram-zoom-out" />
35               <menuitem action="diagram-zoom-100" />
36               <separator />
37               <menuitem action="diagram-close" />
38             </placeholder>
39           </menu>
40         </menubar>
41         <toolbar name='mainwindow-toolbar'>
42           <separator />
43           <toolitem action="diagram-zoom-in" />
44           <toolitem action="diagram-zoom-out" />
45           <toolitem action="diagram-zoom-100" />
46         </toolbar>
47       </ui>
48     """
49
50     def __init__(self, owning_window):
51         self.diagram = None
52         self.view = None
53         self.owning_window = owning_window
54         self.action_group = build_action_group(self)
55         self.toolbox = None
56
57     title = property(lambda s: s.diagram and s.diagram.name or _('<None>'))
58
59     def get_diagram(self):
60         return self.diagram
61
62     def get_view(self):
63         return self.view
64
65     def get_canvas(self):
66         return self.diagram.canvas
67
68     def set_diagram(self, diagram):
69         if self.diagram:
70             self.diagram.disconnect(self._on_diagram_event)
71         self.diagram = diagram
72         if diagram:
73             diagram.connect(('name', '__unlink__'), self._on_diagram_event)
74
75             if self.view:
76                 self.view.hadjustment.set_value(0.0)
77                 self.view.vadjustment.set_value(0.0)
78
79
80     def construct(self):
81         """
82         Create the widget.
83         
84         Returns: the newly created widget.
85         """
86         assert self.diagram
87
88         table = gtk.Table(2,2, False)
89
90         frame = gtk.Frame()
91         frame.set_shadow_type(gtk.SHADOW_IN)
92         table.attach(frame, 0, 1, 0, 1,
93                      gtk.EXPAND | gtk.FILL | gtk.SHRINK,
94                      gtk.EXPAND | gtk.FILL | gtk.SHRINK)
95
96         view = DiagramView(diagram=self.diagram)
97         #view.set_scroll_region(0, 0, 600, 450)
98
99         frame.add(view)
100        
101         sbar = gtk.VScrollbar(view.vadjustment)
102         table.attach(sbar, 1, 2, 0, 1, gtk.FILL,
103                      gtk.EXPAND | gtk.FILL | gtk.SHRINK)
104
105         sbar = gtk.HScrollbar(view.hadjustment)
106         table.attach(sbar, 0, 1, 1, 2, gtk.EXPAND | gtk.FILL | gtk.SHRINK,
107                      gtk.FILL)
108
109         view.connect('focus-changed', self._on_view_selection_changed)
110         view.connect('selection-changed', self._on_view_selection_changed)
111         view.connect_after('key-press-event', self._on_key_press_event)
112         view.connect('drag-data-received', self._on_drag_data_received)
113
114         self.view = view
115
116         table.show_all()
117         self.widget = table
118        
119         self.toolbox = DiagramToolbox(view)
120        
121         return table
122
123     @action(name='diagram-close', stock_id='gtk-close')
124     def close(self):
125         """
126         Tab is destroyed. Do the same thing that would
127         be done if File->Close was pressed.
128         """
129         # Set diagram to None, so all refrences to the diagram are destroyed.
130         #self.widget.destroy()
131
132         self.owning_window.remove_tab(self)
133         self.set_diagram(None)
134         # We need this to get the view deleted properly:
135         #del self.view.diagram
136         del self.view
137         del self.diagram
138
139     @action(name='diagram-zoom-in', stock_id='gtk-zoom-in')
140     def zoom_in(self):
141         self.view.zoom(1.2)
142
143     @action(name='diagram-zoom-out', stock_id='gtk-zoom-out')
144     def zoom_out(self):
145         self.view.zoom(1 / 1.2)
146
147     @action(name='diagram-zoom-100', stock_id='gtk-zoom-100')
148     def zoom_100(self):
149         zx = self.view.matrix[0]
150         self.view.zoom(1 / zx)
151
152     @action(name='diagram-select-all', label='_Select all', accel='<Control>a')
153     def select_all(self):
154         self.view.select_all()
155
156     @action(name='diagram-unselect-all', label='Des_elect all',
157             accel='<Control><Shift>a')
158     def unselect_all(self):
159         self.view.unselect_all()
160        
161     @action(name='diagram-delete', stock_id='gtk-delete')
162     @transactional
163     def delete_selected_items(self):
164         items = self.view.selected_items
165         for i in list(items):
166             if isinstance(i, DiagramItem):
167                 s = i.subject
168                 if s and len(s.presentation) == 1:
169                     s.unlink()
170                 i.unlink()
171             else:
172                 if i.canvas:
173                     i.canvas.remove(i)
174
175     def may_remove_from_model(self, view):
176         """
177         Check if there are items which will be deleted from the model
178         (when their last views are deleted). If so request user
179         confirmation before deletion.
180         """
181         items = self.view.selected_items
182         last_in_model = filter(lambda i: i.subject and len(i.subject.presentation) == 1, items)
183         log.debug('Last in model: %s' % str(last_in_model))
184         if last_in_model:
185             return self.confirm_deletion_of_items(last_in_model)
186         return True
187
188     def confirm_deletion_of_items(self, last_in_model):
189         """
190         Request user confirmation on deleting the item from the model.
191         """
192         s = ''
193         for item in last_in_model:
194             s += '%s\n' % str(item)
195
196         dialog = gtk.MessageDialog(
197                 None,
198                 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
199                 gtk.MESSAGE_WARNING,
200                 gtk.BUTTONS_YES_NO,
201                 'This will remove the following selected items from the model:\n%s\nAre you sure?' % s
202                 )
203         dialog.set_transient_for(self.owning_window.window)
204         value = dialog.run()
205         dialog.destroy()
206         if value == gtk.RESPONSE_YES:
207             return True
208         return False
209
210     def _on_key_press_event(self, view, event):
211         """
212         Handle the 'Delete' key. This can not be handled directly (through
213         GTK's accelerators) since otherwise this key will confuse the text
214         edit stuff.
215         """
216         if view.is_focus():
217             if event.keyval == 0xFFFF and \
218                     (event.state == 0 or event.state & gtk.gdk.MOD2_MASK): # Delete
219                 self.delete_selected_items()
220             elif event.keyval == 0xFF08 and \
221                     (event.state == 0 or event.state & gtk.gdk.MOD2_MASK): # Backspace
222                 self.delete_selected_items()
223             else:
224                 print '%x' %event.keyval, event.state
225                 #self.action_manager.execute('diagram-delete')
226
227
228     def _on_view_selection_changed(self, view, selection_or_focus):
229         component.handle(DiagramSelectionChange(view, view.focused_item, view.selected_items))
230
231     def _on_diagram_event(self, element, pspec):
232         if pspec == '__unlink__':
233             self.close()
234         elif pspec.name == 'name':
235             print 'Trying to set name to', element.name
236             self.owning_window.set_tab_label(self, element.name)
237             #self.get_window().set_title(self.diagram.name or '<None>')
238
239     def _on_drag_data_received(self, view, context, x, y, data, info, time):
240         """
241         Handle data dropped on the canvas.
242         """
243         #print 'drag_data_received'
244         if data and data.format == 8 and info == DiagramView.TARGET_ELEMENT_ID:
245             #print 'drag_data_received:', data.data, info
246             element = self.element_factory.lookup(data.data)
247             assert element
248
249             # TODO: use adapters to execute code below
250
251             item_class = get_diagram_item(type(element))
252             if isinstance(element, UML.Diagram):
253                 self.action_manager.execute('OpenModelElement')
254             elif item_class:
255                 tx = Transaction()
256                 item = self.diagram.create(item_class)
257                 assert item
258                 inverse = Matrix(*view.matrix)
259                 inverse.invert()
260                 cx, cy = inverse.transform_point(x + view.hadjustment.value,
261                                                  y + view.vadjustment.value)
262
263                 ix, iy = view.canvas.get_matrix_c2i(item, calculate=True).transform_point(max(0, cx), max(0, cy))
264                 item.matrix.translate(ix, iy)
265                 item.subject = element
266                 tx.commit()
267                 view.unselect_all()
268                 view.focused_item = item
269
270             else:
271                 log.warning('No graphical representation for UML element %s' % type(element).__name__)
272             context.finish(True, False, time)
273         else:
274             context.finish(False, False, time)
275
Note: See TracBrowser for help on using the browser.