def __init__(self, parent=None): super(MaeBird, self).__init__(parent) self.models = ModelFactory() self.table = None self.languages = {'perimary': 'Fin', 'secondary': 'Eng', 'tertiary': 'Swe'} self.dbtype = __DB__ self.dbfile = None self.db = None self.matches = [] self.currentsearchitem = 0 self.fullscreen = False self.setupUi(self) self.setWindowTitle(__APPNAME__ + ' ' + __VERSION__) # TODO: loading settings should be moved to a separate method settings = QSettings() # Set up logging loggingdir = settings.value("Logging/loggingDir") if loggingdir is None: loggingdir = __USER_DATA_DIR__ self.logger = Logger('root', loggingdir=loggingdir) if settings.value("Settings/debugging"): self.logger.debugging = int(settings.value("Settings/debugging")) self.logger.debug('Logging initialized') # Try to load previous session if settings.value("Settings/saveSettings"): self.saveSettings = int(settings.value("Settings/saveSettings")) else: self.saveSettings = 1 if self.saveSettings: QTimer.singleShot(0, self.load_initial_data) #QTimer.singleShot(0, self.load_initial_model) self.header = self.tableView.horizontalHeader() self.header.sectionDoubleClicked.connect(self.sort_table) self.search.textEdited.connect(self.update_ui) self.search.setFocus() self.searchNextButton.clicked.connect(self.update_ui) self.searchPrevButton.clicked.connect(self.update_ui) self.tableView.pressed.connect(self.update_ui) self.tableView.doubleClicked.connect( lambda: self.handle_observation(ObservationDialog.SHOW)) self.addButton.clicked.connect( lambda: self.handle_observation(ObservationDialog.ADD)) self.deleteButton.clicked.connect( lambda: self.handle_observation(ObservationDialog.DELETE))
class ObservationDialog(QDialog, Ui_observationDialog): ''' A dialog delegate that handles the displaying of the observation model in a suitable GUI dialog. ''' FIRST, PREV, NEXT, LAST, CURRENT = range(5) ADD, DELETE, SHOW = range(3) def __init__(self, model, index, parent=None): super(ObservationDialog, self).__init__(parent) self.logger = Logger('root.observationDialog') self.logger.debug('Debug set to: %s' % str(parent.logger.debugging)) self.setupUi(self) # self.dateTimeEdit.setDateTime(QDateTime.currentDateTime()) # An observation model is passed to the constructor as a parameter self.model = model # Build a QCompleter that is based on a species model's species name. # This way user can start typing the name in a line edit and the # completion will suggest suitable species names based on the model # TODO: language for the species name completion needs to be handled # TODO: both completers have model column indexes hard coded in, thus # they will break if the model is modified sppCompleter = QCompleter(self) sppCompleter.setModel(self.model.data_model) sppCompleter.setCompletionColumn(4) sppCompleter.setCompletionMode(QCompleter.InlineCompletion) sppCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.sppLineEdit.setCompleter(sppCompleter) # Build a QCompleter that is based on a species model's abbreviation. # This way user can start typing the abbreviation in a line edit and the # completion will suggest suitable species names based on the model abbrCompleter = QCompleter(self) abbrCompleter.setModel(self.model.data_model) abbrCompleter.setCompletionColumn(1) abbrCompleter.setCompletionMode(QCompleter.InlineCompletion) self.abbrLineEdit.setCompleter(abbrCompleter) # The underlying (observation) model is automatically updated through # a QDataWidgetMapper self.mapper = QDataWidgetMapper(self) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setModel(model) # ID is mapped to a disabled dummy label in order to include it in the # WidgetMapper --> not very elegant self.mapper.addMapping(self.idLineEdit, model.ID) self.mapper.addMapping(self.sppLineEdit, model.SPECIES) self.mapper.addMapping(self.abbrLineEdit, model.ABBR) self.mapper.addMapping(self.countSpinBox, model.COUNT) self.mapper.addMapping(self.dateTimeEdit, model.TIME) self.mapper.addMapping(self.locLineEdit, model.LOCATION) self.mapper.addMapping(self.notesTextEdit, model.NOTES) self.mapper.setCurrentModelIndex(index) self.firstButton.clicked.connect( lambda: self.saveRecord(ObservationDialog.FIRST)) self.prevButton.clicked.connect( lambda: self.saveRecord(ObservationDialog.PREV)) self.nextButton.clicked.connect( lambda: self.saveRecord(ObservationDialog.NEXT)) self.lastButton.clicked.connect( lambda: self.saveRecord(ObservationDialog.LAST)) self.saveButton.clicked.connect( lambda: self.saveRecord(ObservationDialog.CURRENT)) self.closeButton.clicked.connect(self.reject) self.sppLineEdit.editingFinished.connect(self.update_fields) def addRecord(self): row = self.model.rowCount() self.model.insertRow(row) now = QDateTime.currentDateTime() self.dateTimeEdit.setDateTime(now) self.sppLineEdit.setFocus() self.mapper.setCurrentIndex(row) def deleteRecord(self): species = self.sppLineEdit.text() obstime = self.dateTimeEdit.dateTime().toString( DATETIME_FORMAT) if (QMessageBox.question(self, "Delete", "Delete observation of <br>%s on %s?" % (species, obstime), QMessageBox.Yes|QMessageBox.No) == QMessageBox.No): return row = self.mapper.currentIndex() self.model.removeRow(row) self.model.submitAll() if row + 1 >= self.model.rowCount(): row = self.model.rowCount() - 1 self.mapper.setCurrentIndex(row) def reject(self): QDialog.reject(self) def accept(self): self.mapper.submit() QDialog.accept(self) def saveRecord(self, where): ''' Method saves the current row in the self.mapper and moves the data model cursor to a given location. ''' if self.sppLineEdit.text() == "": QMessageBox.warning(self, "Warning", "You must enter a species name!", QMessageBox.Ok) return # Get the current index and submit changes to the underlying model row = self.mapper.currentIndex() self.mapper.submit() # Move the data model cursor to a given location if where == ObservationDialog.FIRST: row = 0 elif where == ObservationDialog.PREV: row = 0 if row <= 1 else row - 1 elif where == ObservationDialog.NEXT: row += 1 if row >= self.model.rowCount(): row = self.model.rowCount() - 1 elif where == ObservationDialog.LAST: row = self.model.rowCount() - 1 self.mapper.setCurrentIndex(row) def update_fields(self): '''Called when editing of the sppLineEdit stops, etc. species name input is complete. Species name will be searched from the model and corresponding abbreviation string and ID number will be set.''' item = self.sppLineEdit.text() item = item.capitalize() # Match the user entered name to an abbreviation in the species model matches = self.model.data_model.match(self.model.data_model.index(0, 4), Qt.DisplayRole, item, hits=1, flags=Qt.MatchExactly) if matches: # There should be only one match match_row = matches[0].row() abbreviation = self.model.data_model.index(match_row, self.model.data_model.ABBR).data() # Also get the ID for updating the model id = self.model.data_model.index(match_row, self.model.data_model.ID).data() self.abbrLineEdit.setText(abbreviation)
def __init__(self, model, index, parent=None): super(ObservationDialog, self).__init__(parent) self.logger = Logger('root.observationDialog') self.logger.debug('Debug set to: %s' % str(parent.logger.debugging)) self.setupUi(self) # self.dateTimeEdit.setDateTime(QDateTime.currentDateTime()) # An observation model is passed to the constructor as a parameter self.model = model # Build a QCompleter that is based on a species model's species name. # This way user can start typing the name in a line edit and the # completion will suggest suitable species names based on the model # TODO: language for the species name completion needs to be handled # TODO: both completers have model column indexes hard coded in, thus # they will break if the model is modified sppCompleter = QCompleter(self) sppCompleter.setModel(self.model.data_model) sppCompleter.setCompletionColumn(4) sppCompleter.setCompletionMode(QCompleter.InlineCompletion) sppCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.sppLineEdit.setCompleter(sppCompleter) # Build a QCompleter that is based on a species model's abbreviation. # This way user can start typing the abbreviation in a line edit and the # completion will suggest suitable species names based on the model abbrCompleter = QCompleter(self) abbrCompleter.setModel(self.model.data_model) abbrCompleter.setCompletionColumn(1) abbrCompleter.setCompletionMode(QCompleter.InlineCompletion) self.abbrLineEdit.setCompleter(abbrCompleter) # The underlying (observation) model is automatically updated through # a QDataWidgetMapper self.mapper = QDataWidgetMapper(self) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setModel(model) # ID is mapped to a disabled dummy label in order to include it in the # WidgetMapper --> not very elegant self.mapper.addMapping(self.idLineEdit, model.ID) self.mapper.addMapping(self.sppLineEdit, model.SPECIES) self.mapper.addMapping(self.abbrLineEdit, model.ABBR) self.mapper.addMapping(self.countSpinBox, model.COUNT) self.mapper.addMapping(self.dateTimeEdit, model.TIME) self.mapper.addMapping(self.locLineEdit, model.LOCATION) self.mapper.addMapping(self.notesTextEdit, model.NOTES) self.mapper.setCurrentModelIndex(index) self.firstButton.clicked.connect( lambda: self.saveRecord(ObservationDialog.FIRST)) self.prevButton.clicked.connect( lambda: self.saveRecord(ObservationDialog.PREV)) self.nextButton.clicked.connect( lambda: self.saveRecord(ObservationDialog.NEXT)) self.lastButton.clicked.connect( lambda: self.saveRecord(ObservationDialog.LAST)) self.saveButton.clicked.connect( lambda: self.saveRecord(ObservationDialog.CURRENT)) self.closeButton.clicked.connect(self.reject) self.sppLineEdit.editingFinished.connect(self.update_fields)
class MaeBird(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MaeBird, self).__init__(parent) self.models = ModelFactory() self.table = None self.languages = {'perimary': 'Fin', 'secondary': 'Eng', 'tertiary': 'Swe'} self.dbtype = __DB__ self.dbfile = None self.db = None self.matches = [] self.currentsearchitem = 0 self.fullscreen = False self.setupUi(self) self.setWindowTitle(__APPNAME__ + ' ' + __VERSION__) # TODO: loading settings should be moved to a separate method settings = QSettings() # Set up logging loggingdir = settings.value("Logging/loggingDir") if loggingdir is None: loggingdir = __USER_DATA_DIR__ self.logger = Logger('root', loggingdir=loggingdir) if settings.value("Settings/debugging"): self.logger.debugging = int(settings.value("Settings/debugging")) self.logger.debug('Logging initialized') # Try to load previous session if settings.value("Settings/saveSettings"): self.saveSettings = int(settings.value("Settings/saveSettings")) else: self.saveSettings = 1 if self.saveSettings: QTimer.singleShot(0, self.load_initial_data) #QTimer.singleShot(0, self.load_initial_model) self.header = self.tableView.horizontalHeader() self.header.sectionDoubleClicked.connect(self.sort_table) self.search.textEdited.connect(self.update_ui) self.search.setFocus() self.searchNextButton.clicked.connect(self.update_ui) self.searchPrevButton.clicked.connect(self.update_ui) self.tableView.pressed.connect(self.update_ui) self.tableView.doubleClicked.connect( lambda: self.handle_observation(ObservationDialog.SHOW)) self.addButton.clicked.connect( lambda: self.handle_observation(ObservationDialog.ADD)) self.deleteButton.clicked.connect( lambda: self.handle_observation(ObservationDialog.DELETE)) def closeEvent(self, event): settings = QSettings() if self.saveSettings: db = self.dbfile if self.db is not None else '' settings.setValue("Database/LastDb", db) if self.tableView.model() is not None: settings.setValue("Database/DefaultModel", self.tableView.model().name) visible_fields = [not bool(self.tableView.isColumnHidden(i)) for i in range(0, self.tableView.model().columnCount())] settings.setValue("Database/visibleFields", visible_fields) settings.setValue("Settings/debugging", int(self.logger.debugging)) settings.setValue("Settings/saveSettings", int(self.saveSettings)) def load_initial_data(self): settings = QSettings() dbfile = unicode(settings.value("Database/LastDb")) modelname = unicode(settings.value("Database/DefaultModel")) if dbfile and QFile.exists(dbfile): self.load_db(dbfile, modelname=modelname) self.logger.debug("Loaded database %s with model %s" % (dbfile, modelname)) if settings.value("Database/visibleFields"): visible_fields = [item for item in settings.value("Database/visibleFields")] # FIXME: in absence of QVariant, deal with values visible_fields = [False if item == 'false' else True for item in visible_fields] if not all(visible_fields): self.logger.debug("Hiding fields %s" % visible_fields) self.show_fields(visible_fields) def load_db(self, dbname, modelname=None): self.db = QSqlDatabase.addDatabase(self.dbtype) self.db.setDatabaseName(dbname) if not self.db.open(): QMessageBox.warning(self, "Batabase connection", "Database Error: %s" % (self.db.lastError().text())) return self.dbfile = dbname if modelname not in self.models.model_names: modeldlg = ModelDialog(self.models.model_names) if modeldlg.exec_(): modelname = modeldlg.selected_model() if modelname: self.load_model(modelname) def load_model(self, modelname): ''' Loads a specific database model and sets it to view. ''' try: model = self.models.get_model(modelname) except NotImplementedError, e: QMessageBox.warning(self, "Database model", "Database Model Error: %s" % str(e)) return self.tableView.setModel(model(self)) self.tableView.setItemDelegate(QSqlRelationalDelegate(self)) self.tableView.setSelectionMode(QTableView.SingleSelection) self.tableView.setSelectionBehavior(QTableView.SelectRows) self.tableView.setColumnHidden(0, True) self.tableView.resizeColumnsToContents() self.update_ui()