Changeset 175:6db038066dec


Ignore:
Timestamp:
05/13/12 07:52:31 (12 years ago)
Author:
István Váradi <ivaradi@…>
Branch:
default
Phase:
public
Message:

Checklist saving/restoring and editing is implemented

Location:
src/mlx
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • src/mlx/config.py

    r166 r175  
    5252#-------------------------------------------------------------------------------
    5353
     54class Checklist(object):
     55    """A checklist for a certain aircraft type."""
     56    # The name of the section of the checklists
     57    SECTION="checklists"
     58   
     59    @staticmethod
     60    def fromConfig(config, aircraftType):
     61        """Create a checklist for the given aircraft type from the given
     62        config."""
     63        baseName = "checklist." + const.icaoCodes[aircraftType] + "."
     64        fileList = []
     65        while True:
     66            option = baseName + str(len(fileList))
     67            if config.has_option(Checklist.SECTION, option):
     68                fileList.append(config.get(Checklist.SECTION, option))
     69            else:
     70                break
     71
     72        return Checklist(fileList)
     73
     74    def __init__(self, fileList = None):
     75        """Construct the check list with the given file list."""
     76        self._fileList = [] if fileList is None else fileList[:]
     77
     78    def clone(self):
     79        """Clone the checklist."""
     80        return Checklist(self._fileList)
     81
     82    def toConfig(self, config, aircraftType):
     83        """Add this checklist to the given config."""
     84        baseName = "checklist." + const.icaoCodes[aircraftType] + "."
     85        for index in range(0, len(self._fileList)):
     86            option = baseName + str(index)
     87            config.set(Checklist.SECTION, option,
     88                       self._fileList[index])
     89
     90    def __eq__(self, other):
     91        """Determine if the checklist is equal to the given other one."""
     92        return self._fileList == other._fileList
     93
     94    def __len__(self):
     95        """Get the length of the file list."""
     96        return len(self._fileList)
     97
     98    def __getitem__(self, index):
     99        """Get the file with the given index."""
     100        return self._fileList[index]
     101
     102    def __iter__(self):
     103        """Iterate over the files."""
     104        return iter(self._fileList)
     105
     106#-------------------------------------------------------------------------------
     107
    54108class Config(object):
    55109    """Our configuration."""
     
    89143
    90144        self._messageTypeLevels = {}
     145
     146        self._checklists = {}
     147        for aircraftType in const.aircraftTypes:
     148            self._checklists[aircraftType] = Checklist()
    91149       
    92150        self._modified = False
     
    344402        if updateURL!=self._updateURL:
    345403            self._updateURL = updateURL
     404            self._modified = True
     405
     406    def getChecklist(self, aircraftType):
     407        """Get the checklist for the given aircraft type."""
     408        return self._checklists[aircraftType]
     409
     410    def setChecklist(self, aircraftType, checklist):
     411        """Set the checklist for the given aircraft type."""
     412        if checklist!=self._checklists[aircraftType]:
     413            self._checklists[aircraftType] = checklist.clone()
    346414            self._modified = True
    347415
     
    399467                                    Config.DEFAULT_UPDATE_URL)
    400468
     469        for aircraftType in const.aircraftTypes:
     470            self._checklists[aircraftType] = \
     471                Checklist.fromConfig(config, aircraftType)
     472
    401473        self._modified = False
    402474
     
    459531                   "yes" if self._autoUpdate else "no")
    460532        config.set("update", "url", self._updateURL)
     533
     534        config.add_section(Checklist.SECTION)
     535        for aircraftType in const.aircraftTypes:
     536            self._checklists[aircraftType].toConfig(config, aircraftType)
    461537
    462538        try:
  • src/mlx/const.py

    r170 r175  
    7777# Aircraft type: Yakovlev Yak-40
    7878AIRCRAFT_YK40 = 15
     79
     80#-------------------------------------------------------------------------------
     81
     82# The list of aircraft types that we know of
     83# The order is mostly from most recent to oldest considering
     84# Malev's history
     85aircraftTypes = [AIRCRAFT_B736, AIRCRAFT_B737, AIRCRAFT_B738,
     86                 AIRCRAFT_DH8D,
     87                 AIRCRAFT_F70, AIRCRAFT_CRJ2,
     88                 AIRCRAFT_B762, AIRCRAFT_B763,
     89                 AIRCRAFT_B733, AIRCRAFT_B734, AIRCRAFT_B735,
     90                 AIRCRAFT_T154, AIRCRAFT_T134,
     91                 AIRCRAFT_YK40, AIRCRAFT_DC3]
     92
     93#-------------------------------------------------------------------------------
     94
     95# A mapping of aircraft types to their ICAO codes
     96icaoCodes = { AIRCRAFT_B736 : "B736",
     97              AIRCRAFT_B737 : "B737",
     98              AIRCRAFT_B738 : "B738",
     99              AIRCRAFT_B733 : "B733",
     100              AIRCRAFT_B734 : "B734",
     101              AIRCRAFT_B735 : "B735",
     102              AIRCRAFT_DH8D : "DH8D",
     103              AIRCRAFT_B762 : "B762",
     104              AIRCRAFT_B763 : "B763",
     105              AIRCRAFT_CRJ2 : "CRJ2",
     106              AIRCRAFT_F70  : "F70",
     107              AIRCRAFT_DC3  : "DC3",
     108              AIRCRAFT_T134 : "T134",
     109              AIRCRAFT_T154 : "T154",
     110              AIRCRAFT_YK40 : "YK40" }
    79111
    80112#-------------------------------------------------------------------------------
  • src/mlx/gui/checklist.py

    r172 r175  
    66
    77from mlx.i18n import xstr
     8import mlx.const as const
     9import mlx.config as config
     10
     11import os
    812
    913#------------------------------------------------------------------------------
     
    1216    """The dialog to edit the checklists."""
    1317    def __init__(self, gui):
    14         super(ChecklistEditor, self).__init__(WINDOW_TITLE_BASE + " " +
     18        super(ChecklistEditor, self).__init__(WINDOW_TITLE_BASE + " - " +
    1519                                              xstr("chklst_title"),
    1620                                              gui.mainWindow,
     
    2024        self.add_button(xstr("button_ok"), RESPONSETYPE_ACCEPT)
    2125
     26        self._gui = gui
     27        self._checklists = {}
     28        self._currentAircraftType = const.aircraftTypes[0]
     29
    2230        contentArea = self.get_content_area()
    2331
     32        typeBox = gtk.HBox()
     33
     34        label = gtk.Label(xstr("chklst_aircraftType"))
     35        label.set_use_underline(True)
     36
     37        typeBox.pack_start(label, False, False, 4)
     38
     39        self._aircraftTypeModel = gtk.ListStore(str, int)
     40        for type in const.aircraftTypes:
     41            name = aircraftNames[type] if type in aircraftNames \
     42                   else "Aircraft type #%d" % (type,)
     43            self._aircraftTypeModel.append([name, type])
     44        self._aircraftType = gtk.ComboBox(model = self._aircraftTypeModel)
     45        renderer = gtk.CellRendererText()
     46        self._aircraftType.pack_start(renderer, True)
     47        self._aircraftType.add_attribute(renderer, "text", 0)
     48        self._aircraftType.set_tooltip_text(xstr("chklst_aircraftType_tooltip"))
     49        self._aircraftType.set_active(0)
     50        self._aircraftType.connect("changed", self._aircraftTypeChanged)
     51        label.set_mnemonic_widget(self._aircraftType)
     52
     53        typeBox.pack_start(self._aircraftType, True, True, 4)
     54
     55        typeBoxAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
     56                                         xscale = 0.0, yscale = 0.0)
     57        typeBoxAlignment.set_size_request(400, -1)
     58        typeBoxAlignment.add(typeBox)
     59
     60        contentArea.pack_start(typeBoxAlignment, False, False, 12)
     61
     62        fileBox = gtk.HBox()       
    2463
    2564        self._fileChooser = gtk.FileChooserWidget()
    2665        self._fileChooser.set_select_multiple(True)
    27 
    28         self._fileChooser.set_current_folder("/home/vi")
    29        
    30         contentArea.pack_start(self._fileChooser, True, True, 4)
     66       
     67        filter = gtk.FileFilter()
     68        filter.set_name(xstr("chklst_filter_audio"))
     69        filter.add_pattern("*.wav")
     70        filter.add_pattern("*.mp3")
     71        self._fileChooser.add_filter(filter)
     72           
     73        filter = gtk.FileFilter()
     74        filter.set_name(xstr("chklst_filter_all"))
     75        filter.add_pattern("*.*")
     76        self._fileChooser.add_filter(filter)
     77
     78        self._fileChooser.connect("selection-changed",
     79                                  self._fileChooserSelectionChanged)
     80
     81        fileBox.pack_start(self._fileChooser, True, True, 4)
     82
     83        controlBox = gtk.VBox()
     84        controlAlignment = gtk.Alignment(xalign = 0.0, yalign = 0.0,
     85                                         xscale = 0.0, yscale = 0.0)
     86        controlAlignment.set_padding(padding_top = 0, padding_bottom = 0,
     87                                     padding_left = 32, padding_right = 32)
     88        controlAlignment.add(controlBox)
     89        fileBox.pack_start(controlAlignment, False, False, 0)
     90
     91        self._addButton = gtk.Button(xstr("chklst_add"))
     92        self._addButton.set_use_underline(True)
     93        self._addButton.set_tooltip_text(xstr("chklst_add_tooltip"))
     94        self._addButton.connect("clicked", self._addButtonClicked)
     95        addAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
     96                                     xscale = 0.0, yscale = 0.0)
     97        addAlignment.set_padding(padding_top = 64, padding_bottom = 0,
     98                                 padding_left = 0, padding_right = 0)
     99        addAlignment.add(self._addButton)
     100        controlBox.pack_start(addAlignment, False, False, 0)
     101
     102        self._removeButton = gtk.Button(xstr("chklst_remove"))
     103        self._removeButton.set_use_underline(True)
     104        self._removeButton.set_tooltip_text(xstr("chklst_remove_tooltip"))
     105        self._removeButton.set_sensitive(False)
     106        self._removeButton.connect("clicked", self._removeButtonClicked)
     107
     108        removeAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
     109                                        xscale = 0.0, yscale = 0.0)
     110        removeAlignment.set_padding(padding_top = 64, padding_bottom = 0,
     111                                    padding_left = 0, padding_right = 0)
     112        removeAlignment.add(self._removeButton)
     113        controlBox.pack_start(removeAlignment, False, False, 0)
     114
     115        self._moveUpButton = gtk.Button(xstr("chklst_moveUp"))
     116        self._moveUpButton.set_use_underline(True)
     117        self._moveUpButton.set_tooltip_text(xstr("chklst_moveUp_tooltip"))
     118        self._moveUpButton.set_sensitive(False)
     119        self._moveUpButton.connect("clicked", self._moveUpButtonClicked)
     120
     121        moveUpAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
     122                                        xscale = 0.0, yscale = 0.0)
     123        moveUpAlignment.set_padding(padding_top = 16, padding_bottom = 0,
     124                                    padding_left = 0, padding_right = 0)
     125        moveUpAlignment.add(self._moveUpButton)
     126        controlBox.pack_start(moveUpAlignment, False, False, 0)
     127
     128        self._moveDownButton = gtk.Button(xstr("chklst_moveDown"))
     129        self._moveDownButton.set_use_underline(True)
     130        self._moveDownButton.set_tooltip_text(xstr("chklst_moveDown_tooltip"))
     131        self._moveDownButton.set_sensitive(False)
     132        self._moveDownButton.connect("clicked", self._moveDownButtonClicked)
     133
     134        moveDownAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.0,
     135                                        xscale = 0.0, yscale = 0.0)
     136        moveDownAlignment.set_padding(padding_top = 4, padding_bottom = 0,
     137                                    padding_left = 0, padding_right = 0)
     138        moveDownAlignment.add(self._moveDownButton)
     139        controlBox.pack_start(moveDownAlignment, False, False, 0)
     140
     141        self._fileListModel = gtk.ListStore(str, str)
     142        self._fileList = gtk.TreeView(model = self._fileListModel)
     143        column = gtk.TreeViewColumn(xstr("chklst_header"),
     144                                    gtk.CellRendererText(), text = 0)
     145        column.set_expand(True)
     146        column.set_clickable(False)
     147        column.set_reorderable(False)
     148        self._fileList.append_column(column)
     149        self._fileList.set_tooltip_column(1)
     150        self._fileList.set_reorderable(True)
     151        self._fileList.set_size_request(200, -1)
     152        selection = self._fileList.get_selection()
     153        selection.set_mode(SELECTION_MULTIPLE)
     154        selection.connect("changed", self._fileListSelectionChanged)
     155
     156        fileBox.pack_start(self._fileList, False, False, 4)
     157
     158        contentArea.pack_start(fileBox, True, True, 4)
     159
     160        self.set_size_request(900, 500)
    31161
    32162    def run(self):
    33163        """Run the checklist editor dialog."""
     164        self._checklists = {}
     165        self._displayCurrentChecklist()
    34166        self.show_all()
    35167        response = super(ChecklistEditor, self).run()
    36168        self.hide()
    37169
     170        if response==RESPONSETYPE_ACCEPT:
     171            self._saveChecklist()
     172            config = self._gui.config
     173            for (aircraftType, checklist) in self._checklists.iteritems():
     174                config.setChecklist(aircraftType, checklist)
     175            config.save()
     176
     177    def _aircraftTypeChanged(self, comboBox):
     178        """Called when the aircraft's type has changed."""       
     179        self._saveChecklist()
     180        self._displayCurrentChecklist()
     181       
     182    def _fileChooserSelectionChanged(self, fileChooser):
     183        """Called when the selection of the given file chooser is changed."""
     184        numFiles = 0
     185        numSelected = 0
     186        for path in fileChooser.get_filenames():
     187            numSelected += 1
     188            if os.path.isfile(path): numFiles += 1
     189
     190        self._addButton.set_sensitive(numFiles>0 and numFiles==numSelected)
     191
     192    def _addButtonClicked(self, button):
     193        """Called when the Add button is clicked."""
     194        for path in self._fileChooser.get_filenames():
     195            self._fileListModel.append([os.path.basename(path),
     196                                        path])
     197        self._fileChooser.unselect_all()
     198       
     199    def _removeButtonClicked(self, button):
     200        """Called when the Remove button is clicked."""
     201        selection = self._fileList.get_selection()
     202        (model, paths) = selection.get_selected_rows()
     203        while paths:
     204            model.remove(model.get_iter(paths[0]))
     205            (model, paths) = selection.get_selected_rows()
     206       
     207    def _moveUpButtonClicked(self, button):
     208        """Called when the move up button is clicked."""
     209        self._moveSelected(True)
     210       
     211    def _moveDownButtonClicked(self, button):
     212        """Called when the move down button is clicked."""
     213        self._moveSelected(False)
     214
     215    def _moveSelected(self, up):
     216        """Move the selected files up or down."""
     217        selection = self._fileList.get_selection()
     218        (model, paths) = selection.get_selected_rows()
     219        indexes = [(path.get_indices() if pygobject else path)[0]
     220                   for path in paths]
     221        indexes.sort()
     222        if not up:
     223            indexes.reverse()
     224
     225        for index in indexes:
     226            fromIter = model.iter_nth_child(None, index)
     227            toIter = model.iter_nth_child(None, index-1 if up else index + 1)
     228            if up:
     229                model.move_before(fromIter, toIter)
     230            else:
     231                model.move_after(fromIter, toIter)
     232       
     233        self._moveUpButton.set_sensitive(indexes[0]>1 if up else True)
     234        numRows = model.iter_n_children(None)
     235        self._moveDownButton.set_sensitive(True if up else
     236                                           indexes[-1]<(numRows-2))
     237
     238    def _fileListSelectionChanged(self, selection):
     239        """Called when the selection in the file list changes."""
     240        anySelected = selection.count_selected_rows()>0
     241        self._removeButton.set_sensitive(anySelected)
     242
     243        if anySelected:
     244            (model, paths) = selection.get_selected_rows()
     245            minIndex = None
     246            maxIndex = None
     247            for path in paths:
     248                [index] = path.get_indices() if pygobject else path
     249                if minIndex is None or index<minIndex: minIndex = index
     250                if maxIndex is None or index>maxIndex: maxIndex = index
     251                       
     252            self._moveUpButton.set_sensitive(minIndex>0)
     253
     254            numRows = model.iter_n_children(None)
     255            self._moveDownButton.set_sensitive(maxIndex<(numRows-1))
     256        else:
     257            self._moveUpButton.set_sensitive(False)
     258            self._moveDownButton.set_sensitive(False)
     259
     260    def _getAircraftType(self):
     261        """Get the currently selected aircraft type."""
     262        index = self._aircraftType.get_active()
     263        return self._aircraftTypeModel[index][1]       
     264
     265    def _saveChecklist(self):
     266        """Save the currently displayed checklist for the previously displayed
     267        aircraft type."""
     268        fileList = []
     269        model = self._fileListModel
     270        iter = model.get_iter_first()
     271        while iter is not None:
     272            path = model.get(iter, 1)[0]
     273            fileList.append(path)
     274            iter = model.iter_next(iter)
     275
     276        self._checklists[self._currentAircraftType] = config.Checklist(fileList)
     277       
     278    def _displayCurrentChecklist(self):
     279        """Display the checklist for the currently selected aircraft type."""
     280        aircraftType = self._getAircraftType()
     281        self._currentAircraftType = aircraftType
     282        if aircraftType not in self._checklists:
     283            self._checklists[aircraftType] = \
     284                self._gui.config.getChecklist(aircraftType).clone()
     285        checklist = self._checklists[aircraftType]
     286
     287        self._fileListModel.clear()
     288        for path in checklist:
     289            self._fileListModel.append([os.path.basename(path), path])
     290       
     291       
    38292#------------------------------------------------------------------------------
  • src/mlx/gui/common.py

    r151 r175  
    22
    33import mlx.const as _const
     4from mlx.i18n import xstr
    45
    56import os
     
    2425    MESSAGETYPE_QUESTION = gtk.MESSAGE_QUESTION
    2526    MESSAGETYPE_INFO = gtk.MESSAGE_INFO
     27
    2628    RESPONSETYPE_OK = gtk.RESPONSE_OK
    2729    RESPONSETYPE_YES = gtk.RESPONSE_YES
     
    3032    RESPONSETYPE_REJECT = gtk.RESPONSE_REJECT
    3133    RESPONSETYPE_CANCEL = gtk.RESPONSE_CANCEL
     34
    3235    ACCEL_VISIBLE = gtk.ACCEL_VISIBLE
    3336    CONTROL_MASK = gdk.CONTROL_MASK
     
    4851    FILE_CHOOSER_ACTION_OPEN = gtk.FILE_CHOOSER_ACTION_OPEN
    4952    FILE_CHOOSER_ACTION_SAVE = gtk.FILE_CHOOSER_ACTION_SAVE
     53
     54    SELECTION_MULTIPLE = gtk.SELECTION_MULTIPLE
    5055
    5156    def text2unicode(text):
     
    9095    FILE_CHOOSER_ACTION_SAVE = gtk.FileChooserAction.SAVE
    9196
     97    SELECTION_MULTIPLE = gtk.SelectionMode.MULTIPLE
     98
    9299    import codecs
    93100    _utf8Decoder = codecs.getdecoder("utf-8")
     
    192199
    193200#------------------------------------------------------------------------------
     201
     202# A mapping of aircraft types to their screen names
     203aircraftNames = { _const.AIRCRAFT_B736 : xstr("aircraft_b736"),
     204                  _const.AIRCRAFT_B737 : xstr("aircraft_b737"),
     205                  _const.AIRCRAFT_B738 : xstr("aircraft_b738"),
     206                  _const.AIRCRAFT_B733 : xstr("aircraft_b733"),
     207                  _const.AIRCRAFT_B734 : xstr("aircraft_b734"),
     208                  _const.AIRCRAFT_B735 : xstr("aircraft_b735"),
     209                  _const.AIRCRAFT_DH8D : xstr("aircraft_dh8d"),
     210                  _const.AIRCRAFT_B762 : xstr("aircraft_b762"),
     211                  _const.AIRCRAFT_B763 : xstr("aircraft_b763"),
     212                  _const.AIRCRAFT_CRJ2 : xstr("aircraft_crj2"),
     213                  _const.AIRCRAFT_F70  : xstr("aircraft_f70"),
     214                  _const.AIRCRAFT_DC3  : xstr("aircraft_dc3"),
     215                  _const.AIRCRAFT_T134 : xstr("aircraft_t134"),
     216                  _const.AIRCRAFT_T154 : xstr("aircraft_t154"),
     217                  _const.AIRCRAFT_YK40 : xstr("aircraft_yk40") }
     218
     219#------------------------------------------------------------------------------
  • src/mlx/i18n.py

    r173 r175  
    132132    def initialize(self):
    133133        """Initialize the strings."""
     134        self.add("aircraft_b736", "Boeing 737-600")
     135        self.add("aircraft_b737", "Boeing 737-700")
     136        self.add("aircraft_b738", "Boeing 737-800")
     137        self.add("aircraft_b733", "Boeing 737-300")
     138        self.add("aircraft_b734", "Boeing 737-400")
     139        self.add("aircraft_b735", "Boeing 737-500")
     140        self.add("aircraft_dh8d", "Bombardier Dash 8 Q400")
     141        self.add("aircraft_b762", "Boeing 767-200")
     142        self.add("aircraft_b763", "Boeing 767-300")
     143        self.add("aircraft_crj2", "Canadair Regional Jet CRJ-200")
     144        self.add("aircraft_f70",  "Fokker F70")
     145        self.add("aircraft_dc3",  "Lisunov Li-2")
     146        self.add("aircraft_t134", "Tupolev Tu-134")
     147        self.add("aircraft_t154", "Tupolev Tu-154")
     148        self.add("aircraft_yk40", "Yakovlev Yak-40")
     149
    134150        self.add("button_ok", "_OK")
    135151        self.add("button_cancel", "_Cancel")
     
    626642
    627643        self.add("chklst_title", "Checklist Editor")
     644        self.add("chklst_aircraftType", "Aircraft _type:")
     645        self.add("chklst_aircraftType_tooltip",
     646                 "The type of the aircraft for which the checklist "
     647                 "is being edited.")
     648        self.add("chklst_add", "_Add to checklist")
     649        self.add("chklst_add_tooltip",
     650                 "Append the files selected on the left to the "
     651                 "checklist on the right.")
     652        self.add("chklst_remove", "_Remove")
     653        self.add("chklst_remove_tooltip",
     654                 "Remove the selected items from the checklist.")
     655        self.add("chklst_moveUp", "Move _up")
     656        self.add("chklst_moveUp_tooltip",
     657                 "Move up the selected file(s) in the checklist.")
     658        self.add("chklst_moveDown", "Move _down")
     659        self.add("chklst_moveDown_tooltip",
     660                 "Move down the selected file(s) in the checklist.")
     661        self.add("chklst_filter_audio", "Audio files")
     662        self.add("chklst_filter_all", "All files")
     663        self.add("chklst_header", "Checklist files")
    628664
    629665        self.add("prefs_sounds_frame_bg", "Background")
     
    765801    def initialize(self):
    766802        """Initialize the strings."""
     803        self.add("aircraft_b736", "Boeing 737-600")
     804        self.add("aircraft_b737", "Boeing 737-700")
     805        self.add("aircraft_b738", "Boeing 737-800")
     806        self.add("aircraft_b733", "Boeing 737-300")
     807        self.add("aircraft_b734", "Boeing 737-400")
     808        self.add("aircraft_b735", "Boeing 737-500")
     809        self.add("aircraft_dh8d", "Bombardier Dash 8 Q400")
     810        self.add("aircraft_b762", "Boeing 767-200")
     811        self.add("aircraft_b763", "Boeing 767-300")
     812        self.add("aircraft_crj2", "Canadair Regional Jet CRJ-200")
     813        self.add("aircraft_f70",  "Fokker F70")
     814        self.add("aircraft_dc3",  "Liszunov Li-2")
     815        self.add("aircraft_t134", "Tupoljev Tu-134")
     816        self.add("aircraft_t154", "Tupoljev Tu-154")
     817        self.add("aircraft_yk40", "Jakovlev Jak-40")
     818
    767819        self.add("button_ok", "_OK")
    768820        self.add("button_cancel", "_Mégse")
Note: See TracChangeset for help on using the changeset viewer.