source: src/mlx/gui/checklist.py@ 1099:a2d5a4d1c6c1

python3
Last change on this file since 1099:a2d5a4d1c6c1 was 999:e096a5638b87, checked in by István Váradi <ivaradi@…>, 5 years ago

Removed Gtk 2/3 constant definitions (re #347)

File size: 14.9 KB
Line 
1
2from .common import *
3
4from mlx.i18n import xstr
5import mlx.const as const
6import mlx.config as config
7
8import os
9
10#------------------------------------------------------------------------------
11
12## @package mlx.gui.checklist
13#
14# The checklist editor dialog.
15#
16# This module implements the checklist editor dialog. A checklist is a list of
17# sound files that are played one-by-one when requested by the user. The top
18# part of the dialog contains an aircraft type selector. Below it, on the left
19# there is a file selector, and the list of the files in the checklist to the
20# right. There are some buttons in the middle to manipulate the checklist.
21
22#------------------------------------------------------------------------------
23
24class ChecklistEditor(Gtk.Dialog):
25 """The dialog to edit the checklists."""
26 def __init__(self, gui):
27 super(ChecklistEditor, self).__init__(WINDOW_TITLE_BASE + " - " +
28 xstr("chklst_title"),
29 gui.mainWindow,
30 Gtk.DialogFlags.MODAL)
31
32 self.add_button(xstr("button_cancel"), Gtk.ResponseType.REJECT)
33 self.add_button(xstr("button_ok"), Gtk.ResponseType.ACCEPT)
34
35 self._gui = gui
36 self._checklists = {}
37 self._currentAircraftType = const.aircraftTypes[0]
38
39 contentArea = self.get_content_area()
40
41 typeBox = Gtk.HBox()
42
43 label = Gtk.Label(xstr("chklst_aircraftType"))
44 label.set_use_underline(True)
45
46 typeBox.pack_start(label, False, False, 4)
47
48 self._aircraftTypeModel = Gtk.ListStore(str, int)
49 for type in const.aircraftTypes:
50 name = aircraftNames[type] if type in aircraftNames \
51 else "Aircraft type #%d" % (type,)
52 self._aircraftTypeModel.append([name, type])
53 self._aircraftType = Gtk.ComboBox(model = self._aircraftTypeModel)
54 renderer = Gtk.CellRendererText()
55 self._aircraftType.pack_start(renderer, True)
56 self._aircraftType.add_attribute(renderer, "text", 0)
57 self._aircraftType.set_tooltip_text(xstr("chklst_aircraftType_tooltip"))
58 self._aircraftType.set_active(0)
59 self._aircraftType.connect("changed", self._aircraftTypeChanged)
60 label.set_mnemonic_widget(self._aircraftType)
61
62 typeBox.pack_start(self._aircraftType, True, True, 4)
63
64 typeBoxAlignment = Gtk.Alignment(xalign = 0.5, yalign = 0.5,
65 xscale = 0.0, yscale = 0.0)
66 typeBoxAlignment.set_size_request(400, -1)
67 typeBoxAlignment.add(typeBox)
68
69 contentArea.pack_start(typeBoxAlignment, False, False, 12)
70
71 fileBox = Gtk.HBox()
72
73 self._fileChooser = Gtk.FileChooserWidget()
74 self._fileChooser.set_select_multiple(True)
75
76 filter = Gtk.FileFilter()
77 filter.set_name(xstr("file_filter_audio"))
78 filter.add_pattern("*.wav")
79 filter.add_pattern("*.mp3")
80 self._fileChooser.add_filter(filter)
81
82 filter = Gtk.FileFilter()
83 filter.set_name(xstr("file_filter_all"))
84 filter.add_pattern("*.*")
85 self._fileChooser.add_filter(filter)
86
87 self._fileChooser.connect("selection-changed",
88 self._fileChooserSelectionChanged)
89
90 fileBox.pack_start(self._fileChooser, True, True, 4)
91
92 controlBox = Gtk.VBox()
93 controlAlignment = Gtk.Alignment(xalign = 0.0, yalign = 0.0,
94 xscale = 0.0, yscale = 0.0)
95 controlAlignment.set_padding(padding_top = 0, padding_bottom = 0,
96 padding_left = 32, padding_right = 32)
97 controlAlignment.add(controlBox)
98 fileBox.pack_start(controlAlignment, False, False, 0)
99
100 self._addButton = Gtk.Button(xstr("chklst_add"))
101 self._addButton.set_use_underline(True)
102 self._addButton.set_tooltip_text(xstr("chklst_add_tooltip"))
103 self._addButton.connect("clicked", self._addButtonClicked)
104 addAlignment = Gtk.Alignment(xalign = 0.5, yalign = 0.0,
105 xscale = 0.0, yscale = 0.0)
106 addAlignment.set_padding(padding_top = 64, padding_bottom = 0,
107 padding_left = 0, padding_right = 0)
108 addAlignment.add(self._addButton)
109 controlBox.pack_start(addAlignment, False, False, 0)
110
111 self._removeButton = Gtk.Button(xstr("chklst_remove"))
112 self._removeButton.set_use_underline(True)
113 self._removeButton.set_tooltip_text(xstr("chklst_remove_tooltip"))
114 self._removeButton.set_sensitive(False)
115 self._removeButton.connect("clicked", self._removeButtonClicked)
116
117 removeAlignment = Gtk.Alignment(xalign = 0.5, yalign = 0.0,
118 xscale = 0.0, yscale = 0.0)
119 removeAlignment.set_padding(padding_top = 64, padding_bottom = 0,
120 padding_left = 0, padding_right = 0)
121 removeAlignment.add(self._removeButton)
122 controlBox.pack_start(removeAlignment, False, False, 0)
123
124 self._moveUpButton = Gtk.Button(xstr("chklst_moveUp"))
125 self._moveUpButton.set_use_underline(True)
126 self._moveUpButton.set_tooltip_text(xstr("chklst_moveUp_tooltip"))
127 self._moveUpButton.set_sensitive(False)
128 self._moveUpButton.connect("clicked", self._moveUpButtonClicked)
129
130 moveUpAlignment = Gtk.Alignment(xalign = 0.5, yalign = 0.0,
131 xscale = 0.0, yscale = 0.0)
132 moveUpAlignment.set_padding(padding_top = 16, padding_bottom = 0,
133 padding_left = 0, padding_right = 0)
134 moveUpAlignment.add(self._moveUpButton)
135 controlBox.pack_start(moveUpAlignment, False, False, 0)
136
137 self._moveDownButton = Gtk.Button(xstr("chklst_moveDown"))
138 self._moveDownButton.set_use_underline(True)
139 self._moveDownButton.set_tooltip_text(xstr("chklst_moveDown_tooltip"))
140 self._moveDownButton.set_sensitive(False)
141 self._moveDownButton.connect("clicked", self._moveDownButtonClicked)
142
143 moveDownAlignment = Gtk.Alignment(xalign = 0.5, yalign = 0.0,
144 xscale = 0.0, yscale = 0.0)
145 moveDownAlignment.set_padding(padding_top = 4, padding_bottom = 0,
146 padding_left = 0, padding_right = 0)
147 moveDownAlignment.add(self._moveDownButton)
148 controlBox.pack_start(moveDownAlignment, False, False, 0)
149
150 self._fileListModel = Gtk.ListStore(str, str)
151 self._fileList = Gtk.TreeView(model = self._fileListModel)
152 self._fileList.connect("button-press-event",
153 self._fileListButtonPressed)
154 column = Gtk.TreeViewColumn(xstr("chklst_header"),
155 Gtk.CellRendererText(), text = 0)
156 column.set_expand(True)
157 column.set_clickable(False)
158 column.set_reorderable(False)
159 self._fileList.append_column(column)
160 self._fileList.set_tooltip_column(1)
161 self._fileList.set_reorderable(True)
162 self._fileListPopupMenu = None
163 selection = self._fileList.get_selection()
164 selection.set_mode(Gtk.SelectionMode.MULTIPLE)
165 selection.connect("changed", self._fileListSelectionChanged)
166
167 self._buildFileListPopupMenu()
168
169 scrolledWindow = Gtk.ScrolledWindow()
170 scrolledWindow.add(self._fileList)
171 scrolledWindow.set_size_request(200, -1)
172 scrolledWindow.set_policy(Gtk.PolicyType.AUTOMATIC,
173 Gtk.PolicyType.AUTOMATIC)
174 scrolledWindow.set_shadow_type(Gtk.ShadowType.IN)
175
176 fileBox.pack_start(scrolledWindow, False, False, 4)
177
178 contentArea.pack_start(fileBox, True, True, 4)
179
180 self.set_size_request(900, 500)
181
182 def run(self):
183 """Run the checklist editor dialog."""
184 self._checklists = {}
185 self._displayCurrentChecklist()
186 self.show_all()
187 response = super(ChecklistEditor, self).run()
188 self.hide()
189
190 if response==Gtk.ResponseType.ACCEPT:
191 self._saveChecklist()
192 config = self._gui.config
193 for (aircraftType, checklist) in self._checklists.items():
194 config.setChecklist(aircraftType, checklist)
195 config.save()
196
197 def _aircraftTypeChanged(self, comboBox):
198 """Called when the aircraft's type has changed."""
199 self._saveChecklist()
200 self._displayCurrentChecklist()
201
202 def _fileChooserSelectionChanged(self, fileChooser):
203 """Called when the selection of the given file chooser is changed."""
204 numFiles = 0
205 numSelected = 0
206 for path in fileChooser.get_filenames():
207 numSelected += 1
208 if os.path.isfile(path): numFiles += 1
209
210 self._addButton.set_sensitive(numFiles>0 and numFiles==numSelected)
211
212 def _addButtonClicked(self, button):
213 """Called when the Add button is clicked."""
214 for path in self._fileChooser.get_filenames():
215 self._fileListModel.append([os.path.basename(path),
216 path])
217 self._fileChooser.unselect_all()
218
219 def _removeButtonClicked(self, button):
220 """Called when the Remove button is clicked."""
221 self._removeSelected()
222
223 def _removeSelected(self):
224 """Remove the currently selected files."""
225 selection = self._fileList.get_selection()
226 (model, paths) = selection.get_selected_rows()
227
228 iters = [model.get_iter(path) for path in paths]
229
230 for i in iters:
231 if i is not None:
232 model.remove(i)
233
234 def _moveUpButtonClicked(self, button):
235 """Called when the move up button is clicked."""
236 self._moveSelected(True)
237
238 def _moveDownButtonClicked(self, button):
239 """Called when the move down button is clicked."""
240 self._moveSelected(False)
241
242 def _moveSelected(self, up):
243 """Move the selected files up or down."""
244 selection = self._fileList.get_selection()
245 (model, paths) = selection.get_selected_rows()
246 indexes = [path.get_indices()[0] for path in paths]
247 indexes.sort()
248 if not up:
249 indexes.reverse()
250
251 for index in indexes:
252 fromIter = model.iter_nth_child(None, index)
253 toIter = model.iter_nth_child(None, index-1 if up else index + 1)
254 if up:
255 model.move_before(fromIter, toIter)
256 else:
257 model.move_after(fromIter, toIter)
258
259 self._moveUpButton.set_sensitive(indexes[0]>1 if up else True)
260 numRows = model.iter_n_children(None)
261 self._moveDownButton.set_sensitive(True if up else
262 indexes[0]<(numRows-2))
263
264 def _fileListSelectionChanged(self, selection):
265 """Called when the selection in the file list changes."""
266 anySelected = selection.count_selected_rows()>0
267 self._removeButton.set_sensitive(anySelected)
268 self._popupRemoveItem.set_sensitive(anySelected)
269
270 if anySelected:
271 (model, paths) = selection.get_selected_rows()
272 minIndex = None
273 maxIndex = None
274 for path in paths:
275 [index] = path.get_indices()
276 if minIndex is None or index<minIndex: minIndex = index
277 if maxIndex is None or index>maxIndex: maxIndex = index
278
279 self._moveUpButton.set_sensitive(minIndex>0)
280 self._popupMoveUpItem.set_sensitive(minIndex>0)
281
282 numRows = model.iter_n_children(None)
283 self._moveDownButton.set_sensitive(maxIndex<(numRows-1))
284 self._popupMoveDownItem.set_sensitive(maxIndex<(numRows-1))
285 else:
286 self._moveUpButton.set_sensitive(False)
287 self._popupMoveUpItem.set_sensitive(False)
288 self._moveDownButton.set_sensitive(False)
289 self._popupMoveDownItem.set_sensitive(False)
290
291 def _getAircraftType(self):
292 """Get the currently selected aircraft type."""
293 index = self._aircraftType.get_active()
294 return self._aircraftTypeModel[index][1]
295
296 def _saveChecklist(self):
297 """Save the currently displayed checklist for the previously displayed
298 aircraft type."""
299 fileList = []
300 model = self._fileListModel
301 iter = model.get_iter_first()
302 while iter is not None:
303 path = model.get(iter, 1)[0]
304 fileList.append(path)
305 iter = model.iter_next(iter)
306
307 self._checklists[self._currentAircraftType] = config.Checklist(fileList)
308
309 def _displayCurrentChecklist(self):
310 """Display the checklist for the currently selected aircraft type."""
311 aircraftType = self._getAircraftType()
312 self._currentAircraftType = aircraftType
313 if aircraftType not in self._checklists:
314 self._checklists[aircraftType] = \
315 self._gui.config.getChecklist(aircraftType).clone()
316 checklist = self._checklists[aircraftType]
317
318 self._fileListModel.clear()
319 for path in checklist:
320 self._fileListModel.append([os.path.basename(path), path])
321
322 def _fileListButtonPressed(self, widget, event):
323 """Called when a mouse button is pressed on the file list."""
324 if event.type!=Gdk.EventType.BUTTON_PRESS or event.button!=3:
325 return
326
327 menu = self._fileListPopupMenu
328 menu.popup(None, None, None, None, event.button, event.time)
329
330 def _buildFileListPopupMenu(self):
331 """Build the file list popup menu."""
332 menu = Gtk.Menu()
333
334 menuItem = Gtk.MenuItem()
335 menuItem.set_label(xstr("chklst_remove"))
336 menuItem.set_use_underline(True)
337 menuItem.connect("activate", self._popupRemove)
338 menuItem.show()
339 self._popupRemoveItem = menuItem
340
341 menu.append(menuItem)
342
343 menuItem = Gtk.MenuItem()
344 menuItem.set_label(xstr("chklst_moveUp"))
345 menuItem.set_use_underline(True)
346 menuItem.connect("activate", self._popupMoveUp)
347 menuItem.show()
348 self._popupMoveUpItem = menuItem
349
350 menu.append(menuItem)
351
352 menuItem = Gtk.MenuItem()
353 menuItem.set_label(xstr("chklst_moveDown"))
354 menuItem.set_use_underline(True)
355 menuItem.connect("activate", self._popupMoveDown)
356 menuItem.show()
357 self._popupMoveDownItem = menuItem
358
359 menu.append(menuItem)
360
361 self._fileListPopupMenu = menu
362
363 def _popupRemove(self, menuItem):
364 """Remove the currently selected menu items."""
365 self._removeSelected()
366
367 def _popupMoveUp(self, menuItem):
368 """Move up the currently selected menu items."""
369 self._moveSelected(True)
370
371 def _popupMoveDown(self, menuItem):
372 """Move down the currently selected menu items."""
373 self._moveSelected(False)
374
375#------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.