class TalkEditorApp(FreeseerApp): '''Freeseer talk database editor main gui class''' def __init__(self, config, db): super(TalkEditorApp, self).__init__(config) self.db = db icon = QIcon() icon.addPixmap(QPixmap(':/freeseer/logo.png'), QIcon.Normal, QIcon.Off) self.setWindowIcon(icon) self.resize(960, 600) # # Setup Layout # self.mainWidget = QWidget() self.mainLayout = QVBoxLayout() self.mainWidget.setLayout(self.mainLayout) self.setCentralWidget(self.mainWidget) self.mainLayout.setAlignment(Qt.AlignTop) # Add custom widgets self.commandButtons = CommandButtons() self.tableView = QTableView() self.tableView.setSortingEnabled(True) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.talkDetailsWidget = TalkDetailsWidget() self.importTalksWidget = ImportTalksWidget() self.newTalkWidget = NewTalkWidget() self.mainLayout.addWidget(self.importTalksWidget) #self.mainLayout.addLayout(self.titleLayout) self.mainLayout.addWidget(self.commandButtons) self.mainLayout.addWidget(self.tableView) self.mainLayout.addWidget(self.talkDetailsWidget) self.mainLayout.addWidget(self.importTalksWidget) # --- End Layout # Keep track of index of the most recently selected talk self.currentTalkIndex = QPersistentModelIndex() # Prompt user to "Continue Editing", "Discard Changes" or "Save Changes" self.savePromptBox = QMessageBox() self.savePromptBox.setWindowTitle("Unsaved Changes Exist") self.savePromptBox.setIcon(QMessageBox.Information) self.savePromptBox.setText( "The talk you were editing has unsaved changes.") self.continueButton = self.savePromptBox.addButton( "Continue Editing", QMessageBox.RejectRole) self.discardButton = self.savePromptBox.addButton( "Discard Changes", QMessageBox.DestructiveRole) self.saveButton = self.savePromptBox.addButton("Save Changes", QMessageBox.AcceptRole) self.savePromptBox.setDefaultButton(self.saveButton) # Initialize geometry, to be used for restoring window positioning. self.geometry = None # # Setup Menubar # self.actionExportCsv = QAction(self) self.actionExportCsv.setObjectName('actionExportCsv') self.actionRemoveAll = QAction(self) self.actionRemoveAll.setObjectName('actionRemoveAll') # Actions self.menuFile.insertAction(self.actionExit, self.actionExportCsv) self.menuFile.insertAction(self.actionExit, self.actionRemoveAll) # --- End Menubar # # TableView Connections # self.connect(self.tableView, SIGNAL('activated(const QModelIndex)'), self.click_talk) self.connect(self.tableView, SIGNAL('selected(const QModelIndex)'), self.click_talk) self.connect(self.tableView, SIGNAL('clicked(const QModelIndex)'), self.click_talk) # Import Widget self.connect(self.importTalksWidget.csvRadioButton, SIGNAL('toggled(bool)'), self.toggle_import) self.connect(self.importTalksWidget.importButton, SIGNAL('clicked()'), self.import_talks) self.connect(self.importTalksWidget.cancelButton, SIGNAL('clicked()'), self.hide_import_talks_widget) self.importTalksWidget.setHidden(True) self.connect(self.importTalksWidget.csvFileSelectButton, SIGNAL('clicked()'), self.csv_file_select) self.connect(self.importTalksWidget.csvLineEdit, SIGNAL('returnPressed()'), self.importTalksWidget.importButton.click) self.connect(self.importTalksWidget.rssLineEdit, SIGNAL('returnPressed()'), self.importTalksWidget.importButton.click) self.connect(self.actionExportCsv, SIGNAL('triggered()'), self.export_talks_to_csv) self.connect(self.actionRemoveAll, SIGNAL('triggered()'), self.confirm_reset) # Command Buttons self.connect(self.commandButtons.addButton, SIGNAL('clicked()'), self.click_add_button) self.connect(self.commandButtons.removeButton, SIGNAL('clicked()'), self.remove_talk) self.connect(self.commandButtons.removeAllButton, SIGNAL('clicked()'), self.confirm_reset) self.connect(self.commandButtons.importButton, SIGNAL('clicked()'), self.show_import_talks_widget) self.connect(self.commandButtons.exportButton, SIGNAL('clicked()'), self.export_talks_to_csv) self.connect(self.commandButtons.searchButton, SIGNAL('clicked()'), self.search_talks) self.connect(self.commandButtons.searchLineEdit, SIGNAL('textEdited(QString)'), self.search_talks) self.connect(self.commandButtons.searchLineEdit, SIGNAL('returnPressed()'), self.search_talks) # Talk Details Buttons self.connect(self.talkDetailsWidget.saveButton, SIGNAL('clicked()'), self.update_talk) # Talk Details Widget self.connect(self.talkDetailsWidget.titleLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.presenterLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.categoryLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.eventLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.roomLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.descriptionTextEdit, SIGNAL('modificationChanged(bool)'), self.enable_save) self.connect(self.talkDetailsWidget.dateEdit, SIGNAL('dateChanged(const QDate)'), self.enable_save) self.connect(self.talkDetailsWidget.startTimeEdit, SIGNAL('timeChanged(const QTime)'), self.enable_save) self.connect(self.talkDetailsWidget.endTimeEdit, SIGNAL('timeChanged(const QTime)'), self.enable_save) # New Talk Widget self.newTalkWidget.connect(self.newTalkWidget.addButton, SIGNAL('clicked()'), self.add_talk) self.newTalkWidget.connect(self.newTalkWidget.cancelButton, SIGNAL('clicked()'), self.newTalkWidget.reject) # Load default language actions = self.menuLanguage.actions() for action in actions: if action.data().toString() == self.config.default_language: action.setChecked(True) self.translate(action) break # Load Talk Database self.load_presentations_model() # Setup Autocompletion self.update_autocomplete_fields() self.talkDetailsWidget.saveButton.setEnabled(False) # Select first item #self.tableView.setCurrentIndex(self.proxy.index(0,0)) #self.talk_selected(self.proxy.index(0,0)) # # Translation # def retranslate(self): self.setWindowTitle( self.app.translate("TalkEditorApp", "Freeseer Talk Editor")) # # Reusable Strings # self.confirmDBClearTitleString = self.app.translate( "TalkEditorApp", "Remove All Talks from Database") self.confirmDBClearQuestionString = self.app.translate( "TalkEditorApp", "Are you sure you want to clear the DB?") self.confirmTalkDetailsClearTitleString = self.app.translate( "TalkEditorApp", "Unsaved Data") self.confirmTalkDetailsClearQuestionString = self.app.translate( "TalkEditorApp", "Unsaved talk details will be lost. Continue?") # --- End Reusable Strings # # Menubar # self.actionExportCsv.setText( self.app.translate("TalkEditorApp", "&Export to CSV")) self.actionRemoveAll.setText( self.app.translate("TalkEditorApp", "&Remove All Talks")) # --- End Menubar # # TalkDetailsWidget # self.talkDetailsWidget.titleLabel.setText( self.app.translate("TalkEditorApp", "Title")) self.talkDetailsWidget.presenterLabel.setText( self.app.translate("TalkEditorApp", "Presenter")) self.talkDetailsWidget.categoryLabel.setText( self.app.translate("TalkEditorApp", "Category")) self.talkDetailsWidget.eventLabel.setText( self.app.translate("TalkEditorApp", "Event")) self.talkDetailsWidget.roomLabel.setText( self.app.translate("TalkEditorApp", "Room")) self.talkDetailsWidget.dateLabel.setText( self.app.translate("TalkEditorApp", "Date")) self.talkDetailsWidget.startTimeLabel.setText( self.app.translate("TalkEditorApp", "Start Time")) self.talkDetailsWidget.endTimeLabel.setText( self.app.translate("TalkEditorApp", "End Time")) # --- End TalkDetailsWidget # # Import Talks Widget Translations # self.importTalksWidget.rssRadioButton.setText( self.app.translate("TalkEditorApp", "RSS URL")) self.importTalksWidget.csvRadioButton.setText( self.app.translate("TalkEditorApp", "CSV File")) self.importTalksWidget.importButton.setText( self.app.translate("TalkEditorApp", "Import")) # --- End Talks Widget Translations # # Command Button Translations\ # self.commandButtons.importButton.setText( self.app.translate("TalkEditorApp", "Import")) self.commandButtons.exportButton.setText( self.app.translate("TalkEditorApp", "Export")) self.commandButtons.addButton.setText( self.app.translate("TalkEditorApp", "Add New Talk")) self.commandButtons.removeButton.setText( self.app.translate("TalkEditorApp", "Remove")) self.commandButtons.removeAllButton.setText( self.app.translate("TalkEditorApp", "Remove All")) # --- End Command Butotn Translations # # Search Widget Translations # self.commandButtons.searchButton.setText( self.app.translate("TalkEditorApp", "Search")) # --- End Command Button Translations def load_presentations_model(self): # Load Presentation Model self.presentationModel = self.db.get_presentations_model() self.proxy = QSortFilterProxyModel() self.proxy.setSourceModel(self.presentationModel) self.tableView.setModel(self.proxy) self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive) # Fill table whitespace. self.tableView.horizontalHeader().setStretchLastSection(False) self.tableView.horizontalHeader().setResizeMode(1, QHeaderView.Stretch) # Hide the ID field self.tableView.setColumnHidden(0, True) # Map data to widgets self.mapper = QDataWidgetMapper() self.mapper.setModel(self.proxy) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.addMapping(self.talkDetailsWidget.titleLineEdit, 1) self.mapper.addMapping(self.talkDetailsWidget.presenterLineEdit, 2) self.mapper.addMapping(self.talkDetailsWidget.categoryLineEdit, 4) self.mapper.addMapping(self.talkDetailsWidget.eventLineEdit, 5) self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6) self.mapper.addMapping(self.talkDetailsWidget.descriptionTextEdit, 3) self.mapper.addMapping(self.talkDetailsWidget.dateEdit, 7) self.mapper.addMapping(self.talkDetailsWidget.startTimeEdit, 8) self.mapper.addMapping(self.talkDetailsWidget.endTimeEdit, 9) # Load StringLists self.titleList = QStringList(self.db.get_string_list("Title")) #self.speakerList = QStringList(self.db.get_speaker_list()) #self.categoryList = QStringList(self.db.get_category_list()) #self.eventList = QStringList(self.db.get_event_list()) #self.roomList = QStringList(self.db.get_room_list()) #Disble input self.talkDetailsWidget.disable_input_fields() def search_talks(self): # The default value is 0. If the value is -1, the keys will be read from all columns. self.proxy.setFilterKeyColumn(-1) self.proxy.setFilterFixedString( self.commandButtons.searchLineEdit.text()) def show_save_prompt(self): """Prompts the user to save or discard changes, or continue editing.""" self.savePromptBox.exec_() self.savePromptBox.setDefaultButton(self.saveButton) return self.savePromptBox.clickedButton() def click_talk(self, model): """Warns user if there are unsaved changes, and selects talk clicked by the user.""" log.info("Selecting row %d", model.row()) modelRow = model.row() if self.unsaved_details_exist(): log.info("Unsaved changes exist in row %d", self.currentTalkIndex.row()) confirm = self.show_save_prompt() if confirm == self.saveButton: log.info("Saving changes in row %d...", self.currentTalkIndex.row()) self.tableView.selectRow(self.currentTalkIndex.row()) self.update_talk() newModel = self.tableView.currentIndex().sibling(modelRow, 0) self.select_talk(newModel) elif confirm == self.discardButton: log.info("Discarding changes in row %d...", self.currentTalkIndex.row()) self.talk_selected(model) else: log.info("Continue editing row %d", self.currentTalkIndex.row()) self.tableView.selectRow(self.currentTalkIndex.row()) else: self.talk_selected(model) def click_add_button(self): """Warns user if there are unsaved changes, and shows the New Talk window.""" if self.unsaved_details_exist(): log.info("Unsaved changes exist in row %d", self.currentTalkIndex.row()) confirm = self.show_save_prompt() if confirm == self.saveButton: log.info("Saving changes in row %d...", self.currentTalkIndex.row()) self.update_talk() self.show_new_talk_popup() elif confirm == self.discardButton: log.info("Discarding changes in row %d...", self.currentTalkIndex.row()) # Ensure that changes are discarded self.talk_selected(self.currentTalkIndex) self.show_new_talk_popup() else: log.info("Continue editing row %d", self.currentTalkIndex.row()) else: self.show_new_talk_popup() def talk_selected(self, model): self.mapper.setCurrentIndex(model.row()) self.talkDetailsWidget.enable_input_fields() self.talkDetailsWidget.saveButton.setEnabled(False) self.currentTalkIndex = QPersistentModelIndex(model) def toggle_import(self): if self.importTalksWidget.csvRadioButton.isChecked(): self.importTalksWidget.csvLineEdit.setEnabled(True) self.importTalksWidget.csvFileSelectButton.setEnabled(True) self.importTalksWidget.rssLineEdit.setEnabled(False) else: self.importTalksWidget.csvLineEdit.setEnabled(False) self.importTalksWidget.csvFileSelectButton.setEnabled(False) self.importTalksWidget.rssLineEdit.setEnabled(True) def show_import_talks_widget(self): self.commandButtons.setHidden(True) self.tableView.setHidden(True) self.talkDetailsWidget.setHidden(True) self.importTalksWidget.setHidden(False) def hide_import_talks_widget(self): self.commandButtons.setHidden(False) self.tableView.setHidden(False) self.talkDetailsWidget.setHidden(False) self.importTalksWidget.setHidden(True) def add_talk(self): """Adds a new talk to the database using data from the NewTalkWidget input fields""" presentation = self.create_presentation( self.newTalkWidget.talkDetailsWidget) if presentation: self.db.insert_presentation(presentation) self.newTalkWidget.accept() # Close the dialog def update_talk(self): """Updates the currently selected talk using data from the TalkEditorApp input fields""" selected_talk = self.tableView.currentIndex() if selected_talk.row( ) >= 0: # The tableView index begins at 0 and is -1 by default talk_id = selected_talk.sibling(selected_talk.row(), 0).data().toString() presentation = self.create_presentation(self.talkDetailsWidget) if presentation: self.db.update_presentation(talk_id, presentation) self.apply_changes(selected_talk) self.talkDetailsWidget.saveButton.setEnabled(False) def create_presentation(self, talkDetailsWidget): """Creates and returns an instance of Presentation using data from the input fields""" date = talkDetailsWidget.dateEdit.date() startTime = talkDetailsWidget.startTimeEdit.time() endTime = talkDetailsWidget.endTimeEdit.time() title = unicode(talkDetailsWidget.titleLineEdit.text()).strip() if title: return Presentation( unicode(talkDetailsWidget.titleLineEdit.text()).strip(), unicode(talkDetailsWidget.presenterLineEdit.text()).strip(), unicode(talkDetailsWidget.descriptionTextEdit.toPlainText()). strip(), unicode(talkDetailsWidget.categoryLineEdit.text()).strip(), unicode(talkDetailsWidget.eventLineEdit.text()).strip(), unicode(talkDetailsWidget.roomLineEdit.text()).strip(), unicode(date.toString(Qt.ISODate)), unicode(startTime.toString(Qt.ISODate)), unicode(endTime.toString(Qt.ISODate))) def show_new_talk_popup(self): """Displays a modal dialog with a talk details view When Add is selected, a new talk is added to the database using the input field data. When Cancel is selected, no talk is added. """ log.info('Opening Add Talk window...') self.clear_new_talk_fields() self.remove_new_talk_placeholder_text() self.newTalkWidget.talkDetailsWidget.titleLineEdit.setFocus() if self.newTalkWidget.exec_() == 1: self.apply_changes() self.talkDetailsWidget.disable_input_fields() else: log.info('No talk added...') def apply_changes(self, updated_talk=None): """Repopulates the model to display the effective changes Updates the autocomplete fields. Displays the updated model in the table view, and selects the newly updated/added talk. """ self.presentationModel.select() self.select_talk(updated_talk) self.update_autocomplete_fields() def select_talk(self, talk=None): """Selects the given talk in the table view If no talk is given, the last row in the table view is selected. """ if talk: row = talk.row() column = talk.column() else: row = self.presentationModel.rowCount() - 1 # Select last row column = 0 self.tableView.selectRow(row) self.tableView.setCurrentIndex(self.proxy.index(row, column)) self.talk_selected(self.proxy.index(row, column)) def remove_talk(self): try: rows_selected = self.tableView.selectionModel().selectedRows() except: return # Reversed because rows in list change position once row is removed for row in reversed(rows_selected): self.presentationModel.removeRow(row.row()) self.talkDetailsWidget.clear_input_fields() self.talkDetailsWidget.disable_input_fields() def load_talk(self): try: self.tableView.currentIndex().row() except: return self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6) self.presentationModel.select() def reset(self): self.db.clear_database() self.presentationModel.select() self.talkDetailsWidget.clear_input_fields() self.talkDetailsWidget.disable_input_fields() def confirm_reset(self): """Presents a confirmation dialog to ask the user if they are sure they wish to remove the talk database. If Yes call the reset() function""" confirm = QMessageBox.question(self, self.confirmDBClearTitleString, self.confirmDBClearQuestionString, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if confirm == QMessageBox.Yes: self.reset() def add_talks_from_rss(self): rss_url = unicode(self.importTalksWidget.rssLineEdit.text()) if rss_url: self.db.add_talks_from_rss(rss_url) self.presentationModel.select() self.hide_import_talks_widget() else: error = QMessageBox() error.setText("Please enter a RSS URL") error.exec_() def closeEvent(self, event): if self.unsaved_details_exist(): log.info("Unsaved changes exist in row %d", self.currentTalkIndex.row()) confirm = self.show_save_prompt() if confirm == self.saveButton: log.info("Saving changes in row %d...", self.currentTalkIndex.row()) self.update_talk() log.info('Exiting talk database editor...') self.geometry = self.saveGeometry() event.accept() elif confirm == self.discardButton: log.info("Discarding changes in row %d...", self.currentTalkIndex.row()) # Ensure that changes are discarded self.talk_selected(self.currentTalkIndex) log.info('Exiting talk database editor...') self.geometry = self.saveGeometry() event.accept() else: log.info("Continue editing row %d", self.currentTalkIndex.row()) event.ignore() else: log.info('Exiting talk database editor...') self.geometry = self.saveGeometry() event.accept() def csv_file_select(self): fname = QFileDialog.getOpenFileName(self, 'Select file', "", "*.csv") if fname: self.importTalksWidget.csvLineEdit.setText(fname) def add_talks_from_csv(self): fname = self.importTalksWidget.csvLineEdit.text() if fname: self.db.add_talks_from_csv(fname) self.presentationModel.select() self.hide_import_talks_widget() else: error = QMessageBox() error.setText("Please select a file") error.exec_() def import_talks(self): if self.importTalksWidget.csvRadioButton.isChecked(): self.add_talks_from_csv() else: self.add_talks_from_rss() self.update_autocomplete_fields() def export_talks_to_csv(self): fname = QFileDialog.getSaveFileName(self, 'Select file', "", "*.csv") if fname: self.db.export_talks_to_csv(fname) def update_autocomplete_fields(self): self.titleList = QStringList(self.db.get_string_list("Title")) self.speakerList = QStringList(self.db.get_string_list("Speaker")) self.categoryList = QStringList(self.db.get_string_list("Category")) self.eventList = QStringList(self.db.get_string_list("Event")) self.roomList = QStringList(self.db.get_string_list("Room")) self.titleCompleter = QCompleter(self.titleList) self.titleCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.speakerCompleter = QCompleter(self.speakerList) self.speakerCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.categoryCompleter = QCompleter(self.categoryList) self.categoryCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.eventCompleter = QCompleter(self.eventList) self.eventCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.roomCompleter = QCompleter(self.roomList) self.roomCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.talkDetailsWidget.titleLineEdit.setCompleter(self.titleCompleter) self.talkDetailsWidget.presenterLineEdit.setCompleter( self.speakerCompleter) self.talkDetailsWidget.categoryLineEdit.setCompleter( self.categoryCompleter) self.talkDetailsWidget.eventLineEdit.setCompleter(self.eventCompleter) self.talkDetailsWidget.roomLineEdit.setCompleter(self.roomCompleter) def are_fields_enabled(self): return (self.talkDetailsWidget.titleLineEdit.isEnabled() and self.talkDetailsWidget.presenterLineEdit.isEnabled() and self.talkDetailsWidget.categoryLineEdit.isEnabled() and self.talkDetailsWidget.eventLineEdit.isEnabled() and self.talkDetailsWidget.roomLineEdit.isEnabled() and self.talkDetailsWidget.dateEdit.isEnabled() and self.talkDetailsWidget.startTimeEdit.isEnabled() and self.talkDetailsWidget.endTimeEdit.isEnabled()) def unsaved_details_exist(self): """Checks if changes have been made to new/existing talk details Looks for text in the input fields and check the enabled state of the Save Talk button If the Save Talk button is enabled, the input fields contain modified values """ return (self.talkDetailsWidget.saveButton.isEnabled() and (self.talkDetailsWidget.titleLineEdit.text() or self.talkDetailsWidget.presenterLineEdit.text() or self.talkDetailsWidget.categoryLineEdit.text() or self.talkDetailsWidget.descriptionTextEdit.toPlainText())) def enable_save(self): self.talkDetailsWidget.saveButton.setEnabled(True) def clear_new_talk_fields(self): """Removes existing data from all NewTalkWidget fields except event, room, date and time""" self.newTalkWidget.talkDetailsWidget.titleLineEdit.clear() self.newTalkWidget.talkDetailsWidget.presenterLineEdit.clear() self.newTalkWidget.talkDetailsWidget.descriptionTextEdit.clear() self.newTalkWidget.talkDetailsWidget.categoryLineEdit.clear() def remove_new_talk_placeholder_text(self): """Removes placeholder text in NewTalkWidget originally set by TalkDetailsWidget""" self.newTalkWidget.talkDetailsWidget.titleLineEdit.setPlaceholderText( "") self.newTalkWidget.talkDetailsWidget.presenterLineEdit.setPlaceholderText( "") self.newTalkWidget.talkDetailsWidget.categoryLineEdit.setPlaceholderText( "") self.newTalkWidget.talkDetailsWidget.eventLineEdit.setPlaceholderText( "") self.newTalkWidget.talkDetailsWidget.roomLineEdit.setPlaceholderText( "")
class MainWindow(QMainWindow, fatture_ui.Ui_MainWindow): FIRST, PREV, NEXT, LAST = range(4) def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.setupMenu() self.restoreWinSettings() self.editindex = None self.filename = None self.db = QSqlDatabase.addDatabase("QSQLITE") self.loadInitialFile() self.setupUiSignals() def mmUpdate(self): row = self.mapper.currentIndex() id = self.mModel.data(self.mModel.index(row,MID)).toString() self.sModel.setFilter("mmid=%s" % id) self.sModel.select() self.sTableView.setColumnHidden(SID, True) self.sTableView.setColumnHidden(SMID, True) def addDdtRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return row = self.mModel.rowCount() self.mapper.submit() self.mModel.insertRow(row) self.mapper.setCurrentIndex(row) self.dateEdit.setDate(QDate.currentDate()) self.dateEdit.setFocus() self.mmUpdate() def delDdtRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return row = self.mapper.currentIndex() if row == -1: self.statusbar.showMessage( "Nulla da cancellare...", 5000) return record = self.mModel.record(row) id = record.value(MID).toInt()[0] fatt = record.value(MDOC).toString() if(QMessageBox.question(self, "Cancella Scaffale", "Vuoi cancellare il ddt N': {0} ?".format(fatt), QMessageBox.Yes|QMessageBox.No) == QMessageBox.No): self.statusbar.showMessage( "Cancellazione ddt annullata...", 5000) return # cancella scaffale self.mModel.removeRow(row) self.mModel.submitAll() if row + 1 >= self.mModel.rowCount(): row = self.mModel.rowCount() - 1 self.mapper.setCurrentIndex(row) if self.mModel.rowCount() == 0: self.cauLineEdit.setText(QString("")) self.noteLineEdit.setText(QString("")) self.ddtLineEdit.setText(QString("")) self.cliComboBox.setCurrentIndex(-1) # cancella tutti gli articoli che si riferiscono # allo scaffale cancellato self.sModel.setFilter("mmid=%s" % id) self.sModel.select() self.sModel.removeRows(0, self.sModel.rowCount()) self.sModel.submitAll() self.statusbar.showMessage( "Cancellazione eseguita...", 5000) self.mmUpdate() def addDettRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return rowfatt = self.mapper.currentIndex() record = self.mModel.record(rowfatt) masterid = record.value(MID).toInt()[0] if masterid < 1: self.statusbar.showMessage( "Scaffale non valido o non confermato...", 5000) self.dateEdit.setFocus() return # aggiunge la nuova riga alla vista self.sModel.submitAll() self.sModel.select() row = self.sModel.rowCount() self.sModel.insertRow(row) self.sModel.setData(self.sModel.index(row, SMID), QVariant(masterid)) self.sModel.setData(self.sModel.index(row, SQT), QVariant(1)) self.sModel.setData(self.sModel.index(row, SDESC), QVariant("")) self.sModel.setData(self.sModel.index(row, SIMP), QVariant(0.0)) self.sModel.setData(self.sModel.index(row, SIVA), QVariant(20.0)) self.editindex = self.sModel.index(row, SQT) self.sTableView.setCurrentIndex(self.editindex) self.sTableView.edit(self.editindex) def delDettRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return selrows = self.sItmSelModel.selectedRows() if not selrows: self.statusbar.showMessage( "No articles selected to delete...", 5000) return if(QMessageBox.question(self, "Cancellazione righe", "Vuoi cancellare: {0} righe?".format(len(selrows)), QMessageBox.Yes|QMessageBox.No) == QMessageBox.No): return QSqlDatabase.database().transaction() query = QSqlQuery() query.prepare("DELETE FROM fattslave WHERE id = :val") for i in selrows: if i.isValid(): query.bindValue(":val", QVariant(i.data().toInt()[0])) query.exec_() QSqlDatabase.database().commit() self.sModel.revertAll() self.mmUpdate() def setupMenu(self): # AboutBox self.connect(self.action_About, SIGNAL("triggered()"), self.showAboutBox) # FileNew self.connect(self.action_New_File, SIGNAL("triggered()"), self.newFile) # FileLoad self.connect(self.action_Load_File, SIGNAL("triggered()"), self.openFile) # Edit customers self.connect(self.action_Add_Customers, SIGNAL("triggered()"), self.editCustomers) def editCustomers(self): relpath = os.path.dirname(__file__) if relpath: relpath = "%s/" % relpath subprocess.call(['python',os.path.join("%s../clienti/" % relpath, "clienti.py")]) self.setupModels() self.setupMappers() self.setupTables() self.mmUpdate() def showAboutBox(self): dlg = aboutfatt.AboutBox(self) dlg.exec_() def creaStrutturaDB(self): query = QSqlQuery() if not ("tipofatt" in self.db.tables()): if not query.exec_("""CREATE TABLE tipofatt ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, tfatt VARCHAR(50) NOT NULL)"""): QMessageBox.warning(self, "Gestione Fatture", QString("Creazione tabella tipofatt fallita!")) return False else: # aggiungi voci !!!! query.exec_("""INSERT INTO tipofatt VALUES (NULL,'Fattura Semplice')""") query.exec_("""INSERT INTO tipofatt VALUES (NULL,'Fattura Accompagnatoria')""") query.exec_("""INSERT INTO tipofatt VALUES (NULL,'Nota Accredito')""") if not ("fattmaster" in self.db.tables()): if not query.exec_("""CREATE TABLE fattmaster ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, data DATE NOT NULL, doc VARCHAR(50) NOT NULL, idtdoc INTEGER NOT NULL, idcli INTEGER NOT NULL, tpag VARCHAR(50) NOT NULL DEFAULT 'Contanti', causale VARCHAR(200), note VARCHAR(200))"""): QMessageBox.warning(self, "Gestione Fatture", QString("Creazione tabella master fallita!")) return False if not ("fattslave" in self.db.tables()): if not query.exec_("""CREATE TABLE fattslave ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, qt INTEGER NOT NULL DEFAULT '1', desc VARCHAR(200) NOT NULL, imp DOUBLE NOT NULL DEFAULT '0.0', iva DOUBLE NOT NULL DEFAULT '20.0', mmid INTEGER NOT NULL, FOREIGN KEY (mmid) REFERENCES master)"""): QMessageBox.warning(self, "Gestione Fatture", QString("Creazione tabella slave fallita!")) return False QMessageBox.information(self, "Gestione Fatture", QString("Database Creato!")) return True if not ("clienti" in self.db.tables()): if not query.exec_("""CREATE TABLE clienti ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, ragsoc VARCHAR(200) NOT NULL, indirizzo VARCHAR(200) NOT NULL, piva VARCHAR(15), cf VARCHAR(15), tel VARCHAR(30), fax VARCHAR(30), cell VARCHAR(30), email VARCHAR(50))"""): QMessageBox.warning(self, "Gestione Fatture", QString("Creazione tabella clienti fallita!")) return False return True def loadFile(self, fname=None): if fname is None: return if self.db.isOpen(): self.db.close() self.db.setDatabaseName(QString(fname)) if not self.db.open(): QMessageBox.warning(self, "Gestione Fatture", QString("Database Error: %1") .arg(db.lastError().text())) else: if not self.creaStrutturaDB(): return self.filename = unicode(fname) self.setWindowTitle("Gestione Fatture - %s" % self.filename) self.setupModels() self.setupMappers() self.setupTables() #self.setupItmSignals() self.restoreTablesSettings() self.mmUpdate() def loadInitialFile(self): settings = QSettings() fname = unicode(settings.value("Settings/lastFile").toString()) if fname and QFile.exists(fname): self.loadFile(fname) def openFile(self): dir = os.path.dirname(self.filename) \ if self.filename is not None else "." fname = QFileDialog.getOpenFileName(self, "Gestione Fatture - Scegli database", dir, "*.db") if fname: self.loadFile(fname) def newFile(self): dir = os.path.dirname(self.filename) \ if self.filename is not None else "." fname = QFileDialog.getSaveFileName(self, "Gestione Fatture - Scegli database", dir, "*.db") if fname: self.loadFile(fname) def restoreWinSettings(self): settings = QSettings() self.restoreGeometry( settings.value("MainWindow/Geometry").toByteArray()) def restoreTablesSettings(self): settings = QSettings(self) # per la tablelview for column in range(1, self.sModel.columnCount()-1): width = settings.value("Settings/sTableView/%s" % column, QVariant(60)).toInt()[0] self.sTableView.setColumnWidth(column, width if width > 0 else 60) def keyPressEvent(self, event): if event.key() == Qt.Key_Down: self.addDettRecord() else: QMainWindow.keyPressEvent(self, event) def closeEvent(self, event): self.mapper.submit() settings = QSettings() settings.setValue("MainWindow/Geometry", QVariant( self.saveGeometry())) if self.filename is not None: settings.setValue("Settings/lastFile", QVariant(self.filename)) if self.db.isOpen(): # salva larghezza colonne tabella for column in range(1, self.sModel.columnCount()-1): width = self.sTableView.columnWidth(column) if width: settings.setValue("Settings/sTableView/%s" % column, QVariant(width)) self.db.close() del self.db def setupModels(self): """ Initialize all the application models """ # setup slaveModel self.sModel = MyQSqlTableModel(self) self.sModel.setTable(QString("fattslave")) self.sModel.setHeaderData(SID, Qt.Horizontal, QVariant("ID")) self.sModel.setHeaderData(SQT, Qt.Horizontal, QVariant("Qt")) self.sModel.setHeaderData(SDESC, Qt.Horizontal, QVariant("Descrizione")) self.sModel.setHeaderData(SIMP, Qt.Horizontal, QVariant("Importo")) self.sModel.setHeaderData(SIVA, Qt.Horizontal, QVariant("Iva")) self.sModel.setHeaderData(SMID, Qt.Horizontal, QVariant("idlegato")) self.sModel.setEditStrategy(QSqlTableModel.OnRowChange) self.sModel.select() # setup masterModel self.mModel = QSqlRelationalTableModel(self) self.mModel.setTable(QString("fattmaster")) self.mModel.setSort(MDATA, Qt.AscendingOrder) self.mModel.setRelation(MIDCLI, QSqlRelation("clienti", "id", "ragsoc")) self.mModel.setRelation(MIDTDOC, QSqlRelation("tipofatt", "id", "tfatt")) self.mModel.select() def setupMappers(self): ''' Initialize all the application mappers ''' self.mapper = QDataWidgetMapper(self) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setModel(self.mModel) self.mapper.setItemDelegate(QSqlRelationalDelegate(self)) self.mapper.addMapping(self.dateEdit, MDATA) self.mapper.addMapping(self.fattLineEdit, MDOC) relationModel = self.mModel.relationModel(MIDTDOC) relationModel.setSort(1, Qt.AscendingOrder) relationModel.select() self.tipoFattComboBox.setModel(relationModel) self.tipoFattComboBox.setModelColumn(relationModel.fieldIndex("tfatt")) self.mapper.addMapping(self.tipoFattComboBox, MIDTDOC) relationModel = self.mModel.relationModel(MIDCLI) relationModel.setSort(CRAGSOC, Qt.AscendingOrder) relationModel.select() self.cliComboBox.setModel(relationModel) self.cliComboBox.setModelColumn(relationModel.fieldIndex("ragsoc")) self.mapper.addMapping(self.cliComboBox, MIDCLI) self.mapper.addMapping(self.tipoPagLineEdit, MPAG) self.mapper.addMapping(self.cauLineEdit, MCAU) self.mapper.addMapping(self.noteLineEdit, MNOTE) self.mapper.toFirst() def setupTables(self): """ Initialize all the application tablesview """ self.sTableView.setModel(self.sModel) self.sTableView.setColumnHidden(SID, True) self.sTableView.setColumnHidden(SMID, True) self.sTableView.setWordWrap(True) self.sTableView.resizeRowsToContents() self.sTableView.setAlternatingRowColors(True) self.sItmSelModel = QItemSelectionModel(self.sModel) self.sTableView.setSelectionModel(self.sItmSelModel) self.sTableView.setSelectionBehavior(QTableView.SelectRows) self.sTableView.setTabKeyNavigation(False) self.myDelegate = MyQSqlRelationalDelegate(self) self.sTableView.setItemDelegate(self.myDelegate) self.connect(self.myDelegate, SIGNAL("addDettRecord()"), self.addDettRecord) def setupUiSignals(self): self.connect(self.printPushButton, SIGNAL("clicked()"), self.printFatt) self.connect(self.addMPushButton, SIGNAL("clicked()"), self.addDdtRecord) self.connect(self.delMPushButton, SIGNAL("clicked()"), self.delDdtRecord) self.connect(self.addSPushButton, SIGNAL("clicked()"), self.addDettRecord) self.connect(self.delSPushButton, SIGNAL("clicked()"), self.delDettRecord) self.connect(self.firstMPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.FIRST)) self.connect(self.prevMPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.PREV)) self.connect(self.nextMPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.NEXT)) self.connect(self.lastMPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.LAST)) def saveRecord(self, where): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return row = self.mapper.currentIndex() self.mapper.submit() self.sModel.revertAll() if where == MainWindow.FIRST: row=0 elif where == MainWindow.PREV: row = 0 if row <= 1 else row - 1 elif where == MainWindow.NEXT: row += 1 if row >= self.mModel.rowCount(): row = self.mModel.rowCount() -1 elif where == MainWindow.LAST: row = self.mModel.rowCount()- 1 self.mapper.setCurrentIndex(row) self.mmUpdate() def printFatt(self): ''' Print Inventory ''' if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return def makeFATT(copia="Copia Cliente"): qmaster = QSqlQuery() qcli = QSqlQuery() qslave = QSqlQuery() curidx = self.mapper.currentIndex() currec = self.mModel.record(curidx) masterid = currec.value("id").toInt()[0] qmaster.exec_("SELECT id,data,doc,idtdoc,idcli,causale,note " "FROM fattmaster WHERE doc = '%s'" % (currec.value("doc").toString())) qmaster.next() curcli = qmaster.value(4).toInt()[0] qcli.exec_("SELECT id,ragsoc,indirizzo,piva " "FROM clienti WHERE id = %d" % (curcli)) qslave.exec_("SELECT mmid,qt,desc,imp,iva " "FROM fattslave WHERE mmid = '%s'" % (masterid)) qcli.next() # variabili utili alla stampa del report datadoc = currec.value("data").toDate().toString(DATEFORMAT) causaledoc = currec.value("causale").toString() notedoc = currec.value("note").toString() tipodoc = currec.value(3).toString() numdoc = currec.value("doc").toString() cliragsoc = qcli.value(1).toString() cliind = qcli.value(2).toString() clipiva = qcli.value(3).toString() from reportlab.pdfgen.canvas import Canvas from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import cm from reportlab.lib.enums import TA_LEFT,TA_RIGHT,TA_CENTER from reportlab.platypus import Spacer, SimpleDocTemplate, Table, TableStyle, Paragraph, KeepTogether from reportlab.rl_config import defaultPageSize from reportlab.lib import colors from reportlab.lib.pagesizes import letter, A4 from reportlab.lib import textsplit PAGE_WIDTH, PAGE_HEIGHT=defaultPageSize styles = getSampleStyleSheet() styleN = styles['Normal'] styleH = styles['Heading1'] styleH.alignment=TA_CENTER Elements = [] #add some flowables p=Paragraph ps=ParagraphStyle Author = "Stefano Zamprogno" URL = "http://www.zamprogno.it/" email = "*****@*****.**" pageinfo = "%s / %s" % (Author, email) def myLaterPages(c, doc): c.saveState() c.setFont("Times-Bold", 82) c.rotate(45) c.setFillColorRGB(0.9,0.9,0.9) c.drawString(11*cm,2*cm, copia) c.rotate(-45) c.setFillColorRGB(0,0,0) # HEADER if tipodoc == "Fattura Accompagnatoria": subt = 0 else: subt = 3 c.setLineWidth(0.1*cm) c.setStrokeColorRGB(0,0,0) c.line(1.8*cm,(6.2-subt)*cm,19.5*cm,(6.2-subt)*cm) c.setStrokeColorRGB(0.5,0.5,0.5) c.line(1.9*cm,(6.1-subt)*cm,19.6*cm,(6.1-subt)*cm) # cerchi carta c.circle(0.9*cm,6*cm,0.3*cm, fill=1) c.circle(0.9*cm,24*cm,0.3*cm, fill=1) c.setFont("Times-Bold", 14) c.drawCentredString(5*cm, 28*cm, r1) c.setFont("Times-Bold", 9) c.drawCentredString(5*cm, 27.5*cm, r2) c.drawCentredString(5*cm, 27*cm, r3) c.drawCentredString(5*cm, 26.5*cm, r4) c.drawCentredString(5*cm, 26*cm, r5) # numero ddt e descrizione copia c.setFont("Times-Bold", 12) c.drawCentredString(18*cm, 28*cm, "DOC N: %s" % (numdoc)) c.setFont("Times-Bold", 7) c.drawCentredString(18*cm, 27.6*cm, "(%s)" % (copia)) c.drawCentredString(18*cm, 27.2*cm, "%s" % (tipodoc.toUpper())) # Data e causale c.setFont("Times-Bold", 10) c.drawString(1.8*cm, 25*cm, "Data:") c.drawString(1.8*cm, 24.5*cm, "Causale:") c.setFont("Times-Roman", 10) c.drawString(4*cm, 25*cm, unicode(datadoc)) c.drawString(4*cm, 24.5*cm, unicode(causaledoc)) # Cliente c.setFont("Times-Bold", 10) c.drawString(11*cm, 25*cm, "Destinatario:") c.setFont("Times-Roman", 10) c.drawCentredString(16*cm, 25*cm, unicode(cliragsoc)) c.drawCentredString(16*cm, 24.5*cm, unicode(cliind)) c.drawCentredString(16*cm, 24*cm, unicode(clipiva)) # FOOTER c.setFont("Times-Bold", 10) c.setLineWidth(0.01*cm) c.drawString(1.8*cm, (5.5-subt)*cm, "Note:") c.setFont("Times-Roman", 10) strt = (5.5-subt)*cm for i in textsplit.wordSplit(unicode(notedoc),6*cm, "Times-Roman", 10): c.drawString(3*cm, strt, i[1]) strt -= 0.5*cm if tipodoc == "Fattura Accompagnatoria": c.setFont("Times-Bold", 10) c.drawString(12*cm, 5.5*cm, "Data inizio trasporto:") c.line(15.5*cm,5.4*cm,19*cm,5.4*cm) c.drawString(12*cm, 5*cm, "Aspetto dei beni:") c.line(15*cm,4.9*cm,19*cm,4.9*cm) c.drawString(12*cm, 4.5*cm, "Numero colli:") c.line(15*cm,4.4*cm,19*cm,4.4*cm) c.drawString(12*cm, 3.8*cm, "Conducente:") c.line(15*cm,3.7*cm,19*cm,3.7*cm) c.drawString(12*cm, 3*cm, "Destinatario:") c.line(15*cm,2.9*cm,19*cm,2.9*cm) c.drawString(1.8*cm, 4*cm, "Trasporto a Mezzo:") c.line(2.3*cm,3*cm,7*cm,3*cm) # note pie' pagina c.setFont('Times-Roman',9) c.drawString(12.4*cm, 1.5*cm, "Pagina %d %s" % (doc.page, pageinfo)) c.restoreState() # crea il body del ddt data = [['Qt', 'Descrizione dei beni, natura e qualità', 'Importo', 'IVA'],] totimp = 0 totiva = 0 totesiva = 0 while qslave.next(): if qslave.value(4).toDouble()[0]!= 0: totimp += qslave.value(3).toDouble()[0] totiva += (qslave.value(3).toDouble()[0]* qslave.value(4).toDouble()[0] / 100.0) else: totesiva += qslave.value(3).toDouble()[0] data.append([qslave.value(1).toInt()[0], p(unicode(qslave.value(2).toString()), ps(name='Normal')), "€ %.2f" % qslave.value(3).toDouble()[0], "%.2f %%" % qslave.value(4).toDouble()[0]]) Elements.append(Table(data,colWidths=(1*cm,12.5*cm,2*cm,2*cm),repeatRows=1, style=( ['LINEBELOW', (0,0), (-1,0), 1, colors.black], ['BACKGROUND',(0,0),(-1,0), colors.lightgrey], ['GRID',(0,0),(-1,-1), 0.2, colors.black], ['FONT', (0, 0), (-1, 0), 'Helvetica-Bold', 10], ['VALIGN', (0,0), (-1,-1), 'TOP'], ['ALIGN', (0,0), (-1,0), 'CENTER'], ['ALIGN', (2,1), (3,-1), 'RIGHT'], ))) summary = [] summary.append(Spacer(0.5*cm, 0.5*cm)) summary.append(Paragraph("<para align=right><b>___________________________________" "</b></para>", styleN)) summary.append(Paragraph("<para align=right><b>TOTALE IMPONIBILE: " "€ %.2f</b></para>" % totimp, styleN)) summary.append(Paragraph("<para align=right><b>TOTALE IVA: " "€ %.2f</b></para>" % totiva, styleN)) summary.append(Paragraph("<para align=right><b>TOTALE Es.IVA: " "€ %.2f</b></para>" % totesiva, styleN)) summary.append(Spacer(0.5*cm, 0.5*cm)) summary.append(Paragraph("<para align=right><b>TOTALE GENERALE: " "€ %.2f</b></para>" % (totesiva+totimp+totiva), styleN)) Elements.append(KeepTogether(summary)) # 'depure' numddt numdoc = numdoc.replace("/",".") if tipodoc == "Fattura Accompagnatoria": doc = SimpleDocTemplate(os.path.join(os.path.dirname(__file__), "fatt%s.%s.pdf" % (numdoc, copia.replace(" ","."))),topMargin=6.2*cm, bottomMargin=6.2*cm) else: doc = SimpleDocTemplate(os.path.join(os.path.dirname(__file__), "fatt%s.%s.pdf" % (numdoc, copia.replace(" ","."))),topMargin=6.2*cm, bottomMargin=3*cm) doc.build(Elements,onFirstPage=myLaterPages,onLaterPages=myLaterPages) subprocess.Popen(['gnome-open',os.path.join(os.path.dirname(__file__), "fatt%s.%s.pdf" % (numdoc, copia.replace(" ",".")))]) if self.copiaCliCheckBox.isChecked(): makeFATT() if self.copiaIntCheckBox.isChecked(): makeFATT(copia="Copia Interna") if self.copiaVettCheckBox.isChecked(): makeFATT(copia="Copia Vettore")
class TalkEditorApp(FreeseerApp): '''Freeseer talk database editor main gui class''' def __init__(self, config, db): FreeseerApp.__init__(self) self.config = config self.db = db icon = QIcon() icon.addPixmap(QPixmap(':/freeseer/logo.png'), QIcon.Normal, QIcon.Off) self.setWindowIcon(icon) self.resize(960, 600) # # Setup Layout # self.mainWidget = QWidget() self.mainLayout = QVBoxLayout() self.mainWidget.setLayout(self.mainLayout) self.setCentralWidget(self.mainWidget) self.mainLayout.setAlignment(Qt.AlignTop) # Add custom widgets self.commandButtons = CommandButtons() self.tableView = QTableView() self.tableView.setSortingEnabled(True) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.talkDetailsWidget = TalkDetailsWidget() self.importTalksWidget = ImportTalksWidget() self.newTalkWidget = NewTalkWidget() self.mainLayout.addWidget(self.importTalksWidget) #self.mainLayout.addLayout(self.titleLayout) self.mainLayout.addWidget(self.commandButtons) self.mainLayout.addWidget(self.tableView) self.mainLayout.addWidget(self.talkDetailsWidget) self.mainLayout.addWidget(self.importTalksWidget) # --- End Layout # Initialize geometry, to be used for restoring window positioning. self.geometry = None # # Setup Menubar # self.actionExportCsv = QAction(self) self.actionExportCsv.setObjectName('actionExportCsv') self.actionRemoveAll = QAction(self) self.actionRemoveAll.setObjectName('actionRemoveAll') # Actions self.menuFile.insertAction(self.actionExit, self.actionExportCsv) self.menuFile.insertAction(self.actionExit, self.actionRemoveAll) # --- End Menubar # # TableView Connections # self.connect(self.tableView, SIGNAL('activated(const QModelIndex)'), self.talk_selected) self.connect(self.tableView, SIGNAL('selected(const QModelIndex)'), self.talk_selected) self.connect(self.tableView, SIGNAL('clicked(const QModelIndex)'), self.talk_selected) # Import Widget self.connect(self.importTalksWidget.csvRadioButton, SIGNAL('toggled(bool)'), self.toggle_import) self.connect(self.importTalksWidget.importButton, SIGNAL('clicked()'), self.import_talks) self.connect(self.importTalksWidget.cancelButton, SIGNAL('clicked()'), self.hide_import_talks_widget) self.importTalksWidget.setHidden(True) self.connect(self.importTalksWidget.csvFileSelectButton, SIGNAL('clicked()'), self.csv_file_select) self.connect(self.importTalksWidget.csvLineEdit, SIGNAL('returnPressed()'), self.importTalksWidget.importButton.click) self.connect(self.importTalksWidget.rssLineEdit, SIGNAL('returnPressed()'), self.importTalksWidget.importButton.click) self.connect(self.actionExportCsv, SIGNAL('triggered()'), self.export_talks_to_csv) self.connect(self.actionRemoveAll, SIGNAL('triggered()'), self.confirm_reset) # Command Buttons self.connect(self.commandButtons.addButton, SIGNAL('clicked()'), self.show_new_talk_popup) self.connect(self.commandButtons.removeButton, SIGNAL('clicked()'), self.remove_talk) self.connect(self.commandButtons.removeAllButton, SIGNAL('clicked()'), self.confirm_reset) self.connect(self.commandButtons.importButton, SIGNAL('clicked()'), self.show_import_talks_widget) self.connect(self.commandButtons.exportButton, SIGNAL('clicked()'), self.export_talks_to_csv) self.connect(self.commandButtons.searchButton, SIGNAL('clicked()'), self.search_talks) self.connect(self.commandButtons.searchLineEdit, SIGNAL('textEdited(QString)'), self.search_talks) self.connect(self.commandButtons.searchLineEdit, SIGNAL('returnPressed()'), self.search_talks) # Talk Details Buttons self.connect(self.talkDetailsWidget.saveButton, SIGNAL('clicked()'), self.update_talk) # Talk Details Widget self.connect(self.talkDetailsWidget.titleLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.presenterLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.categoryLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.eventLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.roomLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.descriptionTextEdit, SIGNAL('modificationChanged(bool)'), self.enable_save) self.connect(self.talkDetailsWidget.dateEdit, SIGNAL('dateChanged(const QDate)'), self.enable_save) self.connect(self.talkDetailsWidget.startTimeEdit, SIGNAL('timeChanged(const QTime)'), self.enable_save) self.connect(self.talkDetailsWidget.endTimeEdit, SIGNAL('timeChanged(const QTime)'), self.enable_save) # New Talk Widget self.newTalkWidget.connect(self.newTalkWidget.addButton, SIGNAL('clicked()'), self.add_talk) self.newTalkWidget.connect(self.newTalkWidget.cancelButton, SIGNAL('clicked()'), self.newTalkWidget.reject) # Load default language actions = self.menuLanguage.actions() for action in actions: if action.data().toString() == self.config.default_language: action.setChecked(True) self.translate(action) break # Load Talk Database self.load_presentations_model() # Setup Autocompletion self.update_autocomplete_fields() self.talkDetailsWidget.saveButton.setEnabled(False) # Select first item #self.tableView.setCurrentIndex(self.proxy.index(0,0)) #self.talk_selected(self.proxy.index(0,0)) # # Translation # def retranslate(self): self.setWindowTitle(self.app.translate("TalkEditorApp", "Freeseer Talk Editor")) # # Reusable Strings # self.confirmDBClearTitleString = self.app.translate("TalkEditorApp", "Remove All Talks from Database") self.confirmDBClearQuestionString = self.app.translate("TalkEditorApp", "Are you sure you want to clear the DB?") self.confirmTalkDetailsClearTitleString = self.app.translate("TalkEditorApp", "Unsaved Data") self.confirmTalkDetailsClearQuestionString = self.app.translate("TalkEditorApp", "Unsaved talk details will be lost. Continue?") # --- End Reusable Strings # # Menubar # self.actionExportCsv.setText(self.app.translate("TalkEditorApp", "&Export to CSV")) self.actionRemoveAll.setText(self.app.translate("TalkEditorApp", "&Remove All Talks")) # --- End Menubar # # TalkDetailsWidget # self.talkDetailsWidget.titleLabel.setText(self.app.translate("TalkEditorApp", "Title")) self.talkDetailsWidget.presenterLabel.setText(self.app.translate("TalkEditorApp", "Presenter")) self.talkDetailsWidget.categoryLabel.setText(self.app.translate("TalkEditorApp", "Category")) self.talkDetailsWidget.eventLabel.setText(self.app.translate("TalkEditorApp", "Event")) self.talkDetailsWidget.roomLabel.setText(self.app.translate("TalkEditorApp", "Room")) self.talkDetailsWidget.dateLabel.setText(self.app.translate("TalkEditorApp", "Date")) self.talkDetailsWidget.startTimeLabel.setText(self.app.translate("TalkEditorApp", "Start Time")) self.talkDetailsWidget.endTimeLabel.setText(self.app.translate("TalkEditorApp", "End Time")) # --- End TalkDetailsWidget # # Import Talks Widget Translations # self.importTalksWidget.rssRadioButton.setText(self.app.translate("TalkEditorApp", "RSS URL")) self.importTalksWidget.csvRadioButton.setText(self.app.translate("TalkEditorApp", "CSV File")) self.importTalksWidget.importButton.setText(self.app.translate("TalkEditorApp", "Import")) # --- End Talks Widget Translations # # Command Button Translations\ # self.commandButtons.importButton.setText(self.app.translate("TalkEditorApp", "Import")) self.commandButtons.exportButton.setText(self.app.translate("TalkEditorApp", "Export")) self.commandButtons.addButton.setText(self.app.translate("TalkEditorApp", "Add New Talk")) self.commandButtons.removeButton.setText(self.app.translate("TalkEditorApp", "Remove")) self.commandButtons.removeAllButton.setText(self.app.translate("TalkEditorApp", "Remove All")) # --- End Command Butotn Translations # # Search Widget Translations # self.commandButtons.searchButton.setText(self.app.translate("TalkEditorApp", "Search")) # --- End Command Button Translations def load_presentations_model(self): # Load Presentation Model self.presentationModel = self.db.get_presentations_model() self.proxy = QSortFilterProxyModel() self.proxy.setSourceModel(self.presentationModel) self.tableView.setModel(self.proxy) self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive) # Fill table whitespace. self.tableView.horizontalHeader().setStretchLastSection(False) self.tableView.horizontalHeader().setResizeMode(1, QHeaderView.Stretch) # Hide the ID field self.tableView.setColumnHidden(0, True) # Map data to widgets self.mapper = QDataWidgetMapper() self.mapper.setModel(self.proxy) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.addMapping(self.talkDetailsWidget.titleLineEdit, 1) self.mapper.addMapping(self.talkDetailsWidget.presenterLineEdit, 2) self.mapper.addMapping(self.talkDetailsWidget.categoryLineEdit, 4) self.mapper.addMapping(self.talkDetailsWidget.eventLineEdit, 5) self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6) self.mapper.addMapping(self.talkDetailsWidget.descriptionTextEdit, 3) self.mapper.addMapping(self.talkDetailsWidget.dateEdit, 7) self.mapper.addMapping(self.talkDetailsWidget.startTimeEdit, 8) self.mapper.addMapping(self.talkDetailsWidget.endTimeEdit, 9) # Load StringLists self.titleList = QStringList(self.db.get_string_list("Title")) #self.speakerList = QStringList(self.db.get_speaker_list()) #self.categoryList = QStringList(self.db.get_category_list()) #self.eventList = QStringList(self.db.get_event_list()) #self.roomList = QStringList(self.db.get_room_list()) #Disble input self.talkDetailsWidget.disable_input_fields() def search_talks(self): # The default value is 0. If the value is -1, the keys will be read from all columns. self.proxy.setFilterKeyColumn(-1) self.proxy.setFilterFixedString(self.commandButtons.searchLineEdit.text()) def talk_selected(self, model): self.mapper.setCurrentIndex(model.row()) self.talkDetailsWidget.enable_input_fields() self.talkDetailsWidget.saveButton.setEnabled(False) def toggle_import(self): if self.importTalksWidget.csvRadioButton.isChecked(): self.importTalksWidget.csvLineEdit.setEnabled(True) self.importTalksWidget.csvFileSelectButton.setEnabled(True) self.importTalksWidget.rssLineEdit.setEnabled(False) else: self.importTalksWidget.csvLineEdit.setEnabled(False) self.importTalksWidget.csvFileSelectButton.setEnabled(False) self.importTalksWidget.rssLineEdit.setEnabled(True) def show_import_talks_widget(self): self.commandButtons.setHidden(True) self.tableView.setHidden(True) self.talkDetailsWidget.setHidden(True) self.importTalksWidget.setHidden(False) def hide_import_talks_widget(self): self.commandButtons.setHidden(False) self.tableView.setHidden(False) self.talkDetailsWidget.setHidden(False) self.importTalksWidget.setHidden(True) def add_talk(self): """Adds a new talk to the database using data from the NewTalkWidget input fields""" presentation = self.create_presentation(self.newTalkWidget.talkDetailsWidget) if presentation: self.db.insert_presentation(presentation) self.newTalkWidget.accept() # Close the dialog def update_talk(self): """Updates the currently selected talk using data from the TalkEditorApp input fields""" selected_talk = self.tableView.currentIndex() if selected_talk.row() >= 0: # The tableView index begins at 0 and is -1 by default talk_id = selected_talk.sibling(selected_talk.row(), 0).data().toString() presentation = self.create_presentation(self.talkDetailsWidget) if presentation: self.db.update_presentation(talk_id, presentation) self.apply_changes(selected_talk) self.talkDetailsWidget.saveButton.setEnabled(False) def create_presentation(self, talkDetailsWidget): """Creates and returns an instance of Presentation using data from the input fields""" date = talkDetailsWidget.dateEdit.date() startTime = talkDetailsWidget.startTimeEdit.time() endTime = talkDetailsWidget.endTimeEdit.time() title = unicode(talkDetailsWidget.titleLineEdit.text()).strip() if title: return Presentation( unicode(talkDetailsWidget.titleLineEdit.text()).strip(), unicode(talkDetailsWidget.presenterLineEdit.text()).strip(), unicode(talkDetailsWidget.descriptionTextEdit.toPlainText()).strip(), unicode(talkDetailsWidget.categoryLineEdit.text()).strip(), unicode(talkDetailsWidget.eventLineEdit.text()).strip(), unicode(talkDetailsWidget.roomLineEdit.text()).strip(), unicode(date.toString(Qt.ISODate)), unicode(startTime.toString(Qt.ISODate)), unicode(endTime.toString(Qt.ISODate))) def show_new_talk_popup(self): """Displays a modal dialog with a talk details view When Add is selected, a new talk is added to the database using the input field data. When Cancel is selected, no talk is added. """ log.info('Opening Add Talk window...') self.clear_new_talk_fields() self.remove_new_talk_placeholder_text() self.newTalkWidget.talkDetailsWidget.titleLineEdit.setFocus() if self.newTalkWidget.exec_() == 1: self.apply_changes() self.talkDetailsWidget.disable_input_fields() else: log.info('No talk added...') def apply_changes(self, updated_talk=None): """Repopulates the model to display the effective changes Updates the autocomplete fields. Displays the updated model in the table view, and selects the newly updated/added talk. """ self.presentationModel.select() self.select_talk(updated_talk) self.update_autocomplete_fields() def select_talk(self, talk=None): """Selects the given talk in the table view If no talk is given, the last row in the table view is selected. """ if talk: row = talk.row() column = talk.column() else: row = self.presentationModel.rowCount() - 1 # Select last row column = 0 self.tableView.selectRow(row) self.tableView.setCurrentIndex(self.proxy.index(row, column)) self.talk_selected(self.proxy.index(row, column)) def remove_talk(self): try: rows_selected = self.tableView.selectionModel().selectedRows() except: return # Reversed because rows in list change position once row is removed for row in reversed(rows_selected): self.presentationModel.removeRow(row.row()) def load_talk(self): try: self.tableView.currentIndex().row() except: return self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6) self.presentationModel.select() def reset(self): self.db.clear_database() self.presentationModel.select() def confirm_reset(self): """Presents a confirmation dialog to ask the user if they are sure they wish to remove the talk database. If Yes call the reset() function""" confirm = QMessageBox.question(self, self.confirmDBClearTitleString, self.confirmDBClearQuestionString, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if confirm == QMessageBox.Yes: self.reset() def add_talks_from_rss(self): rss_url = unicode(self.importTalksWidget.rssLineEdit.text()) if rss_url: self.db.add_talks_from_rss(rss_url) self.presentationModel.select() self.hide_import_talks_widget() else: error = QMessageBox() error.setText("Please enter a RSS URL") error.exec_() def closeEvent(self, event): log.info('Exiting talk database editor...') self.geometry = self.saveGeometry() event.accept() def csv_file_select(self): fname = QFileDialog.getOpenFileName( self, 'Select file', "", "*.csv") if fname: self.importTalksWidget.csvLineEdit.setText(fname) def add_talks_from_csv(self): fname = self.importTalksWidget.csvLineEdit.text() if fname: self.db.add_talks_from_csv(fname) self.presentationModel.select() self.hide_import_talks_widget() else: error = QMessageBox() error.setText("Please select a file") error.exec_() def import_talks(self): if self.importTalksWidget.csvRadioButton.isChecked(): self.add_talks_from_csv() else: self.add_talks_from_rss() self.update_autocomplete_fields() def export_talks_to_csv(self): fname = QFileDialog.getSaveFileName(self, 'Select file', "", "*.csv") if fname: self.db.export_talks_to_csv(fname) def update_autocomplete_fields(self): self.titleList = QStringList(self.db.get_string_list("Title")) self.speakerList = QStringList(self.db.get_string_list("Speaker")) self.categoryList = QStringList(self.db.get_string_list("Category")) self.eventList = QStringList(self.db.get_string_list("Event")) self.roomList = QStringList(self.db.get_string_list("Room")) self.titleCompleter = QCompleter(self.titleList) self.titleCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.speakerCompleter = QCompleter(self.speakerList) self.speakerCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.categoryCompleter = QCompleter(self.categoryList) self.categoryCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.eventCompleter = QCompleter(self.eventList) self.eventCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.roomCompleter = QCompleter(self.roomList) self.roomCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.talkDetailsWidget.titleLineEdit.setCompleter(self.titleCompleter) self.talkDetailsWidget.presenterLineEdit.setCompleter(self.speakerCompleter) self.talkDetailsWidget.categoryLineEdit.setCompleter(self.categoryCompleter) self.talkDetailsWidget.eventLineEdit.setCompleter(self.eventCompleter) self.talkDetailsWidget.roomLineEdit.setCompleter(self.roomCompleter) def are_fields_enabled(self): return (self.talkDetailsWidget.titleLineEdit.isEnabled() and self.talkDetailsWidget.presenterLineEdit.isEnabled() and self.talkDetailsWidget.categoryLineEdit.isEnabled() and self.talkDetailsWidget.eventLineEdit.isEnabled() and self.talkDetailsWidget.roomLineEdit.isEnabled() and self.talkDetailsWidget.dateEdit.isEnabled() and self.talkDetailsWidget.startTimeEdit.isEnabled() and self.talkDetailsWidget.endTimeEdit.isEnabled()) def unsaved_details_exist(self): """Checks if changes have been made to new/existing talk details Looks for text in the input fields and check the enabled state of the Save Talk button If the Save Talk button is enabled, the input fields contain modified values """ return (self.talkDetailsWidget.saveButton.isEnabled() and (self.talkDetailsWidget.titleLineEdit.text() or self.talkDetailsWidget.presenterLineEdit.text() or self.talkDetailsWidget.categoryLineEdit.text() or self.talkDetailsWidget.descriptionTextEdit.toPlainText())) def enable_save(self): self.talkDetailsWidget.saveButton.setEnabled(True) def clear_new_talk_fields(self): """Removes existing data from all NewTalkWidget fields except event, room, date and time""" self.newTalkWidget.talkDetailsWidget.titleLineEdit.clear() self.newTalkWidget.talkDetailsWidget.presenterLineEdit.clear() self.newTalkWidget.talkDetailsWidget.descriptionTextEdit.clear() self.newTalkWidget.talkDetailsWidget.categoryLineEdit.clear() def remove_new_talk_placeholder_text(self): """Removes placeholder text in NewTalkWidget originally set by TalkDetailsWidget""" self.newTalkWidget.talkDetailsWidget.titleLineEdit.setPlaceholderText("") self.newTalkWidget.talkDetailsWidget.presenterLineEdit.setPlaceholderText("") self.newTalkWidget.talkDetailsWidget.categoryLineEdit.setPlaceholderText("") self.newTalkWidget.talkDetailsWidget.eventLineEdit.setPlaceholderText("") self.newTalkWidget.talkDetailsWidget.roomLineEdit.setPlaceholderText("")
class SrwrViewRecord(object): """ Functionality to view a SRWR record in separate form. This class is generic and can be used by all 3 SRWR tabs. """ whole_road_col = int() def __init__(self, model, iface, dialog, whole_rd_col, widget_info, params): """ Basic setup of class variables and some initial setup of mapper. :param model: Model from tableview :param iface: qgis iface hook :param dialog: dialog which is unique to each tab :param whole_rd_col: int for whole road column in tab table :param widget_info: List of widgetinfo objects for the provided dialog """ self.view_dlg = dialog self.widgets = widget_info # Find the date columns from the widget info objects self.date_cols = [] self.id_lineedit = None for w in widget_info: if w.date_col: self.date_cols.append(w.db_col) if w.id_col: self.id_lineedit = w.widget self.model = model self.whole_road_col = whole_rd_col self.iface = iface self.mapper = None self.proxy = None self.params = params self.view_dlg.setWindowFlags(Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint) self.setup_mapper() self.view_dlg.ui.mapPushButton.clicked.connect(self.zoom_to_map) self.view_dlg.ui.closePushButton.clicked.connect(self.complete) def whole_rd_state(self, state): """ Checks if its a whole record and set checkbox accordingly :param state: Current state """ checked = True if state == 2: checked = False self.view_dlg.ui.wholeRoadCheckBox.blockSignals(True) self.view_dlg.ui.wholeRoadCheckBox.setChecked(checked) self.view_dlg.ui.wholeRoadCheckBox.setChecked(False) def view(self, idx, usrn): """ View a record details in a dialog :param idx: index of view in the model :param usrn: usrn of current record """ row = idx.row() self.mapper.setCurrentIndex(row) self.view_dlg.ui.wholeRoadCheckBox.setEnabled(False) self.whole_road_checkbox(row) self.hide_buttons() self.view_dlg.show() def zoom_to_map(self): """ Zoom the canvas to the start/end coords of the maint record """ startx = self.view_dlg.ui.startXLineEdit.text() endx = self.view_dlg.ui.endXLineEdit.text() starty = self.view_dlg.ui.startYLineEdit.text() endy = self.view_dlg.ui.endYLineEdit.text() # Only zoom if values are present if startx and starty: coords_f = [ QgsPoint(float(startx), float(starty)), QgsPoint(float(endx), float(endy)) ] geom = QgsGeometry().fromMultiPoint(coords_f) bbox = geom.boundingBox() self.iface.mapCanvas().setExtent(bbox) self.iface.mapCanvas().refresh() def complete(self): """ Close the view form. """ self.view_dlg.close() def whole_road_checkbox(self, row): """ Sets whole road combo box based on value as it cannot be mapped. :param row: row in model """ whole_rd = self.model.data(self.model.index(row, self.whole_road_col), Qt.DisplayRole) if whole_rd == 1 or str(whole_rd).lower() == "yes": self.view_dlg.ui.wholeRoadCheckBox.setChecked(True) self.view_dlg.ui.locationTextEdit.setPlainText("Whole road") else: self.view_dlg.ui.wholeRoadCheckBox.setChecked(False) def hide_buttons(self): """ Hide buttons """ self.view_dlg.ui.editLinkPushButton.setVisible(False) self.view_dlg.ui.editCoordsPushButton.setVisible(False) def setup_mapper(self): """ Create the data widget mapper and set a proxy on the model """ self.mapper = QDataWidgetMapper() self.proxy = QSortFilterProxyModel() self.proxy.setSourceModel(self.model) self.proxy.setDynamicSortFilter(True) self.mapper.setModel(self.proxy) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) # Set custom delegate for mapping to date widgets self.mapper.setItemDelegate(DateMapperCustomDelegate(self.date_cols)) self.map_widgets(self.mapper) def map_widgets(self, mapper): """ Map widgets to columns :param mapper: QDataWidgetMapper """ for w in self.widgets: if w.mapped: mapper.addMapping(w.widget, w.db_col)
class RdpolyRecordEditor(object): """ Handles forms and database connections for editing RAMP features. """ dlg = None rdpoly_model = None rdpoly_mapper = None mcl_model = None mcl_mapper = None def __init__(self, db, selector_tool, iface): self.db = db self.selector_tool = selector_tool self.iface = iface self.prepare_dialog() self.connect_signals() def prepare_dialog(self): """ Prepare MCL edit dialog including setting comobox entries and validation. :return: RampMclEditorDlg """ self.dlg = RampRdpolyEditorDlg() self.dlg.setWindowFlags(Qt.WindowStaysOnTopHint) self.dlg.move(5, 5) self.set_combobox_items() self.set_dialog_validators() def set_combobox_items(self): """ Populate the items in the comboboxes. """ self.dlg.ui.elementComboBox.addItems([''] + ELEMENT_VALUES) self.dlg.ui.hierarchyComboBox.addItems([''] + HIERARCHY_VALUES) self.dlg.ui.offsetComboBox.addItems([''] + OFFSET_VALUES) def set_dialog_validators(self): """ Add validators to the free-text fields of the dialog. """ self.dlg.ui.numberLineEdit.setValidator( QRegExpValidator(QRegExp(r"\d{0,3}"))) def connect_signals(self): """ Connect GUI signals and slots. Extends parent class function """ # GUI controls self.selector_tool.selected_id.connect(self.select_record) save_button = self.dlg.ui.buttonBox.button(QDialogButtonBox.Save) cancel_button = self.dlg.ui.buttonBox.button(QDialogButtonBox.Cancel) save_button.clicked.connect(self.save_record) cancel_button.clicked.connect(self.close_tool) # reject() is called if user presses escape self.dlg.rejected.connect(self.close_tool) # Auto updates on combined ref line edit self.dlg.ui.numberLineEdit.textChanged.connect( self.update_combined_ref) self.dlg.ui.elementComboBox.currentIndexChanged.connect( self.update_combined_ref) self.dlg.ui.elementComboBox.currentIndexChanged.connect( self.set_length_readonly_state) self.dlg.ui.hierarchyComboBox.currentIndexChanged.connect( self.update_combined_ref) self.dlg.ui.offsetComboBox.currentIndexChanged.connect( self.update_combined_ref) def select_record(self, rd_pol_id): """ Update the GUI to populate with data from the chosen record. Show if not already visible. :param rd_pol_id: int, emitted by selector_tool """ try: self.setup_models_and_mappers(rd_pol_id) except rn_except.RampNoLinkedPolyPopupError: return self.set_length_readonly_state() if not self.dlg.isVisible(): # Emit the index changed symbol so update_combined_ref() is triggered, # ensuring combined ref box is populated on initial load self.dlg.ui.elementComboBox.currentIndexChanged.emit( self.dlg.ui.elementComboBox.currentIndex()) self.dlg.show() def close_tool(self): """ Close the dialog, reverting unsaved changes. """ self.mcl_mapper.revert() self.rdpoly_mapper.revert() self.dlg.hide() def save_record(self): """ Save changes to the record, then close dialog. """ self.mcl_mapper.submit() self.rdpoly_mapper.submit() self.update_label_fields() self.update_ref_3() self.iface.mapCanvas().refresh() self.dlg.hide() def setup_models_and_mappers(self, rd_pol_id): """ Load the table data for selected record into a model and map to widgets. """ self.setup_rdpoly_model_and_mapper(rd_pol_id) mcl_ref = self.get_mcl_ref_from_rd_pol_id(rd_pol_id) self.setup_mcl_model_and_mapper(mcl_ref) def get_mcl_ref_from_rd_pol_id(self, rd_pol_id): """ Query database to get mcl_ref associated with given polygon :param rd_pol_id: str, id number :return mcl_ref: str, id number """ sql = """ SELECT mcl_cref FROM rdpoly WHERE rd_pol_id = {}""".format(rd_pol_id) query = QSqlQuery(sql, self.db) if not query.first(): msg = "No MCLs are linked to polygon {}".format(rd_pol_id) raise rn_except.RampNoLinkedPolyPopupError(msg) mcl_ref = query.record().value('mcl_cref') if isinstance(mcl_ref, QPyNullVariant): msg = "No MCLs are linked to polygon {}".format(rd_pol_id) raise rn_except.RampNoLinkedPolyPopupError(msg) return str(mcl_ref) def set_length_readonly_state(self): """ Make the length lineedit writeable for non-MCL fields """ element_value = self.dlg.ui.elementComboBox.currentText() delegate = self.rdpoly_mapper.itemDelegate() element_key = get_key(delegate.element_codes, element_value) if element_key in ('CGWAY', 'FPATH'): self.dlg.ui.lengthLineEdit.setReadOnly(True) self.dlg.ui.lengthLineEdit.setStyleSheet(""" border-width: 0.5px; border-style: solid; border-radius: 2px; border-color: rgb(100, 100, 100); background-color: rgb(213, 234, 234);""") else: self.dlg.ui.lengthLineEdit.setReadOnly(False) self.dlg.ui.lengthLineEdit.setStyleSheet("") def update_label_fields(self): """ Update the label columns of the rdpoly table based on new values """ element = self.rdpoly_data(ELEMENT) side = self.rdpoly_data(OFFSET) number = self.rdpoly_data(DESC_3) if isinstance(number, QPyNullVariant) or number in (0, ''): label = "/{}".format(element) label1 = "/{}/{}".format(element, side) else: label = "/{}/{}".format(element, number) label1 = "/{}/{}/{}".format(element, side, number) self.rdpoly_model.setData(self.rdpoly_model.index(0, LABEL), label) self.rdpoly_model.setData(self.rdpoly_model.index(0, LABEL1), label1) self.rdpoly_model.submit() def update_ref_3(self): """ Update the ref_3 column of rdpoly with value from desc_3. """ number = self.rdpoly_data(DESC_3) self.rdpoly_model.setData(self.rdpoly_model.index(0, REF_3), number) self.rdpoly_model.submit() def setup_rdpoly_model_and_mapper(self, rd_pol_id): """ Load the data for the Polygon portion of the form :param rd_pol_id: str rd_pol_id :return: """ # Set up model self.rdpoly_model = QSqlTableModel(db=self.db) self.rdpoly_model.setTable('rdpoly') self.rdpoly_model.setFilter("rd_pol_id = {}".format(int(rd_pol_id))) self.rdpoly_model.select() if self.rdpoly_model.rowCount() != 1: msg = "Table rdpoly query for rd_pol_id = {} returned {} rows".format( rd_pol_id, self.rdpoly_model.rowCount()) raise rn_except.RdpolyFormBadRdpolyRefError(msg) # Set up rdpoly_mapper self.rdpoly_mapper = QDataWidgetMapper() self.rdpoly_mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.rdpoly_mapper.setModel(self.rdpoly_model) self.rdpoly_mapper.addMapping(self.dlg.ui.rdpolyLineEdit, RD_POL_ID) self.rdpoly_mapper.addMapping(self.dlg.ui.numberLineEdit, DESC_3) self.rdpoly_mapper.addMapping(self.dlg.ui.elementComboBox, ELEMENT) self.rdpoly_mapper.addMapping(self.dlg.ui.hierarchyComboBox, HIERARCHY) self.rdpoly_mapper.addMapping(self.dlg.ui.offsetComboBox, OFFSET) self.rdpoly_mapper.setItemDelegate(RdpolyEditorDelegate(self.dlg)) self.rdpoly_mapper.toFirst() def setup_mcl_model_and_mapper(self, mcl_ref): """ Load the data for the MCL portion of the form :param mcl_ref: str mcl_ref :return: """ # Set up model self.mcl_model = QSqlTableModel(db=self.db) self.mcl_model.setTable('mcl') self.mcl_model.setFilter("mcl_ref = {}".format(int(mcl_ref))) self.mcl_model.select() if self.mcl_model.rowCount() != 1: msg = "MCL query for mcl_ref = {} returned {} rows".format( mcl_ref, self.mcl_model.rowCount()) raise rn_except.RdpolyFormBadMclRefError(msg) # Set up mcl_mapper self.mcl_mapper = QDataWidgetMapper() self.mcl_mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mcl_mapper.setModel(self.mcl_model) self.mcl_mapper.addMapping(self.dlg.ui.mclLineEdit, MCL_REF) self.mcl_mapper.addMapping(self.dlg.ui.usrnLineEdit, USRN) self.mcl_mapper.addMapping(self.dlg.ui.lorDescPlainTextEdit, LOR_DESC) self.mcl_mapper.addMapping(self.dlg.ui.laneNumberLineEdit, LANE_NUMBER) self.mcl_mapper.addMapping(self.dlg.ui.speedLineEdit, SPEED_LIMIT) self.mcl_mapper.toFirst() def update_combined_ref(self): """ Update combinedRefLineEdit with value derived from other fields. """ if self.mcl_model is None: # This happens if signal calls function before model created return # Get strings from MCLs mcl_ref1 = self.mcl_data(LOR_REF_1) mcl_ref2 = self.mcl_data(LOR_REF_2) # Get strings from rdpoly delegate = self.rdpoly_mapper.itemDelegate() element_value = self.dlg.ui.elementComboBox.currentText() element_key = get_key(delegate.element_codes, element_value) offset_value = self.dlg.ui.offsetComboBox.currentText() offset_key = get_key(delegate.offset_codes, offset_value) number = self.dlg.ui.numberLineEdit.text() new_text = "{}/{}/{}/{}/{}".format(mcl_ref1, mcl_ref2, element_key, offset_key, number) self.dlg.ui.combinedRefLineEdit.setText(new_text) def rdpoly_data(self, column): return self.rdpoly_model.data(self.rdpoly_model.index(0, column)) def mcl_data(self, column): return self.mcl_model.data(self.mcl_model.index(0, column))
class MclRecordEditor(object): """ Handles forms and database connections for editing RAMP features. """ edit_linked_polys_tool = None original_linked_polys = None mcl_ref = None dlg = None model = None mapper = None def __init__(self, db, selector_tool, iface): self.db = db self.selector_tool = selector_tool self.iface = iface self.prepare_dialog() self.connect_signals() def prepare_dialog(self): """ Prepare MCL edit dialog including setting comobox entries and validation. :return: RampMclEditorDlg """ self.dlg = RampMclEditorDlg() self.dlg.setWindowFlags(Qt.WindowStaysOnTopHint) self.dlg.move(5, 5) self.set_combobox_items() self.set_dialog_validators() def set_combobox_items(self): """ Populate the items in the comboboxes. """ self.dlg.ui.streetClassComboBox.addItems([''] + STREET_CLASS_VALUES) self.dlg.ui.laneNumberComboBox.addItems([''] + LANE_NUMBER_VALUES) self.dlg.ui.carriagewayComboBox.addItems([''] + CARRIAGEWAY_VALUES) self.dlg.ui.ruralUrbanComboBox.addItems([''] + RURAL_URBAN_VALUES) self.dlg.ui.speedLimitComboBox.addItems([''] + SPEED_LIMIT_VALUES) self.dlg.ui.sectionTypeComboBox.addItems([''] + SECTION_TYPE_VALUES) def set_dialog_validators(self): """ Add validators to the free-text fields of the dialog. """ # These widgets are 'free-text' self.dlg.ui.usrnLineEdit.setValidator( QRegExpValidator(QRegExp(r"\d{0,8}"))) self.dlg.ui.ref1LineEdit.setValidator( QRegExpValidator(QRegExp(r"[ABCUFTMZ]{1,2}-?\d{0,}"))) self.dlg.ui.ref2LineEdit.setValidator( QRegExpValidator(QRegExp(r"\d{0,}"))) # There isn't length validation for plain text edit, so implement our own self.dlg.ui.sectionDescriptionPlainTextEdit.textChanged.connect( self.trim_section_description) def trim_section_description(self): """ Trim text in street section description to within 150 characters. """ editor = self.dlg.ui.sectionDescriptionPlainTextEdit text = editor.toPlainText() if len(text) > 150: text = text[:150] editor.setPlainText(text) editor.moveCursor(QTextCursor.End) def connect_signals(self): """ Connect GUI signals and slots. Extends parent class function """ # GUI controls self.selector_tool.selected_id.connect(self.select_record) save_button = self.dlg.ui.buttonBox.button(QDialogButtonBox.Save) cancel_button = self.dlg.ui.buttonBox.button(QDialogButtonBox.Cancel) save_button.clicked.connect(self.save_record) cancel_button.clicked.connect(self.close_tool) self.dlg.rejected.connect(self.close_tool) self.dlg.ui.editLinksPushButton.clicked.connect( self.launch_edit_linked_polys_tool) # Auto updates on combined ref line edit self.dlg.ui.ref1LineEdit.textChanged.connect(self.update_combined_ref) self.dlg.ui.ref2LineEdit.textChanged.connect(self.update_combined_ref) def select_record(self, mcl_ref): """ Update the GUI to populate with data from the chosen record. Show if not already visible. :param mcl_ref: int, emitted by selector_tool """ self.mcl_ref = mcl_ref self.setup_model_and_mapper(mcl_ref) self.populate_length_lineedit(mcl_ref) self.original_linked_polys = self.get_linked_polys_in_db(mcl_ref) self.set_linked_poly_box_items(self.original_linked_polys) if not self.dlg.isVisible(): self.dlg.show() def launch_edit_linked_polys_tool(self): """ Create new instance of edit linked polys tool for current record """ linked_polys = self.get_items_from_linked_poly_box() self.edit_linked_polys_tool = EditLinkedPolysTool( linked_polys, self.iface, self.dlg) self.edit_linked_polys_tool.linked_polys_updated.connect( self.set_linked_poly_box_items) self.edit_linked_polys_tool.launch() def close_tool(self): """ Close the dialog, reverting unsaved changes. """ self.mapper.revert() self.dlg.hide() def save_record(self): """ Save changes to the record, then close dialog. """ self.mapper.submit() self.update_db_linked_polys() self.iface.mapCanvas().refresh() self.dlg.hide() def setup_model_and_mapper(self, mcl_ref): """ Load the table data for selected record into a model and map to widgets. """ # Set up model self.model = QSqlTableModel(db=self.db) self.model.setTable('mcl') self.model.setFilter("mcl_ref = {}".format(int(mcl_ref))) self.model.select() if self.model.rowCount() != 1: msg = "MCL query for mcl_ref = {} returned {} rows".format( mcl_ref, self.model.rowCount()) raise rn_except.MclFormBadMclRefError(msg) # Set up mapper self.mapper = QDataWidgetMapper() self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.setModel(self.model) self.mapper.addMapping(self.dlg.ui.mclLineEdit, MCL_REF) self.mapper.addMapping(self.dlg.ui.usrnLineEdit, USRN) self.mapper.addMapping(self.dlg.ui.streetClassComboBox, STREET_CLASS) self.mapper.addMapping(self.dlg.ui.ref1LineEdit, LOR_REF_1) self.mapper.addMapping(self.dlg.ui.ref2LineEdit, LOR_REF_2) self.mapper.addMapping(self.dlg.ui.laneNumberComboBox, LANE_NUMBER) self.mapper.addMapping(self.dlg.ui.carriagewayComboBox, CARRIAGEWAY) self.mapper.addMapping(self.dlg.ui.ruralUrbanComboBox, RURAL_URBAN_ID) self.mapper.addMapping(self.dlg.ui.speedLimitComboBox, SPEED_LIMIT) self.mapper.addMapping(self.dlg.ui.sectionTypeComboBox, SECTION_TYPE) self.mapper.addMapping(self.dlg.ui.sectionDescriptionPlainTextEdit, LOR_DESC) self.mapper.setItemDelegate(MclEditorDelegate(self.dlg)) self.mapper.toFirst() def update_combined_ref(self): """ Update combinedRefLineEdit with value derived from other fields. """ ref1 = self.dlg.ui.ref1LineEdit.text() ref2 = self.dlg.ui.ref2LineEdit.text() new_text = "{}/{}".format(ref1, ref2) self.dlg.ui.combinedRefLineEdit.setText(new_text) def populate_length_lineedit(self, mcl_ref): """ Calculate the length of the MCL and populate lineedit with data. :param mcl_ref: int, id of the MCL to calculate """ # Don't do calculation if spatialite version is too low. (libgeos bug) if lor.get_spatialite_version_as_int(self.db) < 430: length_text = "Spatialite < 4.3.0" self.dlg.ui.lengthLineEdit.setText(length_text) return # Run query sql = """ SELECT GLength(geometry) AS length FROM mcl WHERE mcl_ref = {} ;""".format(mcl_ref) query = QSqlQuery(sql, self.db) # Raise exception if query fails if not query.first(): msg = ("Could not calculate MCL length. Query:\n{}\n" "Database returned:\n{}".format(sql, query.lastError().text())) raise rn_except.MclFormLengthCalculationError(msg) # Update field length = query.record().value('length') length_text = "{:.2f}".format(length) self.dlg.ui.lengthLineEdit.setText(length_text) def update_db_linked_polys(self): """ Update the database with changes to linked polygons. """ linked_polys = self.get_items_from_linked_poly_box() # Clear links for polygons that have been removed for polygon in self.original_linked_polys: if polygon not in linked_polys: self.clear_rdpoly_mcl_fields(polygon) # Create links for polygons that have been added. for polygon in linked_polys: if polygon not in self.original_linked_polys: self.clear_rdpoly_mcl_fields(polygon) self.set_rdpoly_mcl_links_in_db(polygon, self.mcl_ref) def get_items_from_linked_poly_box(self): """ Get the values from the Linked Polygons box :return: list of strings """ poly_box = self.dlg.ui.linkedPolygonsListWidget items = [] for i in range(poly_box.count()): items.append(poly_box.item(i).data(Qt.DisplayRole)) return items def set_linked_poly_box_items(self, items): """ Populate the Linked Polygons box with items :param items: list of strings """ # Cannot link already linked polygon try: self.validate_polygon_links(items) except rn_except.RampRdPolyAlreadyLinkedPopupError: # Don't update if polygons already have links to other MCLs return poly_box = self.dlg.ui.linkedPolygonsListWidget poly_box.clear() poly_box.addItems(items) def validate_polygon_links(self, linked_polys): """ Raise exception if any polygons have link to other MCLs. """ already_linked = [] for rd_pol_id in linked_polys: linked_mcl_cref = self.get_mcl_cref(rd_pol_id) if linked_mcl_cref == str(self.mcl_ref): # OK if linked to current MCL continue elif linked_mcl_cref in ('', 'NULL', 'Null'): # Null is OK continue else: # Otherwise already linked to other polygon already_linked.append(rd_pol_id) if already_linked: msg = "Cannot update links. The following polygons are already linked" msg += " to other MCLs.\n\n" msg += ", ".join(already_linked) raise rn_except.RampRdPolyAlreadyLinkedPopupError(msg) def get_mcl_cref(self, rd_pol_id): """ Get the MCL ref attached to given polygon :param rd_pol_id: :return: str, mcl_cref """ sql = """ SELECT mcl_cref FROM rdpoly WHERE rd_pol_id = '{}' ;""".format(rd_pol_id) query = QSqlQuery(sql, self.db) if not query.isActive(): msg = "Invalid rd_pol_id:" msg += "\n\nSQL command:\n\n{}".format(sql) msg += "\n\nDatabase reply:\n\n{}".format(query.lastError().text()) raise rn_except.RampRdPolyUpdateFailedPopupError(msg) query.first() mcl_ref = str(query.record().value('mcl_cref')) return mcl_ref def get_linked_polys_in_db(self, mcl_ref): """ Get the polygons that have current mcl_ref :param mcl_ref: str with reference :return: list of strings """ sql = """ SELECT rd_pol_id FROM rdpoly WHERE mcl_cref = {} ;""".format(mcl_ref) query = QSqlQuery(sql, self.db) linked_polys = [] while query.next(): record = query.record() rd_pol_id = str(record.value('rd_pol_id')) linked_polys.append(rd_pol_id) return linked_polys def set_rdpoly_mcl_links_in_db(self, rd_pol_id, mcl_ref): """ Update the fields of the rdpoly table with values for the given mcl_ref from the mcl table. :param rd_pol_id: str, rd_pol_id to update :param mcl_ref: str, mcl_ref to supply values """ if config.DEBUG_MODE: print( "DEBUG_MODE: Updating rdpoly {} with data from mcl {}".format( rd_pol_id, mcl_ref)) # Get update values mcl_attrs = self.get_mcl_attrs_for_rdpoly(mcl_ref) mcl_attrs['mcl_ref'] = mcl_ref mcl_attrs['rd_pol_id'] = rd_pol_id # Update database sql = """ UPDATE rdpoly SET part_label = "{part_label}", mcl_cref = {mcl_cref} WHERE rd_pol_id = {rd_pol_id} ;""".format(**mcl_attrs) if config.DEBUG_MODE: print(sql) query = QSqlQuery(sql, self.db) if not query.isActive(): msg = "Failed to update rdpoly with mcl data." msg += "\n\nSQL command:\n\n{}".format(sql) msg += "\n\nDatabase reply:\n\n{}".format(query.lastError().text()) raise rn_except.RampRdPolyUpdateFailedPopupError(msg) def clear_rdpoly_mcl_fields(self, rd_pol_id): """ Clear values in rdpoly that were derived from linked MCL. Used when MCL is unlinked. :param rd_pol_id: str, rd_pol_id """ sql = """ UPDATE rdpoly SET element = NULL, hierarchy = NULL, ref_1 = NULL, ref_2 = NULL, ref_3 = NULL, desc_1 = NULL, desc_2 = NULL, desc_3 = NULL, part_label = NULL, label = NULL, label1 = NULL, feature_length = NULL, r_usrn = NULL, mcl_cref = NULL WHERE rd_pol_id = {} ;""".format(rd_pol_id) if config.DEBUG_MODE: print(sql) query = QSqlQuery(sql, self.db) if not query.isActive(): msg = "Problem updating rdpoly with mcl data." msg += "\n\nSQL command:\n\n{}".format(sql) msg += "\n\nDatabase reply:\n\n{}".format(query.lastError().text()) raise rn_except.RampRdPolyUpdateFailedPopupError(msg) def get_mcl_attrs_for_rdpoly(self, mcl_ref): """ Get values from database and prepare attributes to insert into rdpoly table. :param mcl_ref: str, mcl_ref :return: dict, mcl_attributes """ sql = """ SELECT lor_ref_1 || "/" || lor_ref_2 AS part_label FROM mcl WHERE mcl_ref={};""".format(mcl_ref) query = QSqlQuery(sql, self.db) if not query.isActive(): msg = "Failed to get MCL attributes." msg += "\n\nSQL command:\n\n{}".format(sql) msg += "\n\nDatabase reply:\n\n{}".format(query.lastError().text()) raise rn_except.RampRdPolyUpdateFailedPopupError(msg) query.first() part_label = query.record().value("part_label") mcl_attrs = {'mcl_cref': mcl_ref, 'part_label': part_label} return mcl_attrs
class MainWindow(QMainWindow, magazzino_ui.Ui_MainWindow): FIRST, PREV, NEXT, LAST = range(4) Clipboard = [] # lista di oggetti def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.setupMenu() self.restoreWinSettings() self.editindex = None self.filename = None self.db = QSqlDatabase.addDatabase("QSQLITE") self.loadInitialFile() self.setupUiSignals() def keyPressEvent(self, event): if event.key() == Qt.Key_Down: self.addDettRecord() else: QMainWindow.keyPressEvent(self, event) def creaStrutturaDB(self): query = QSqlQuery() if not ("magamaster" in self.db.tables()): if not query.exec_("""CREATE TABLE magamaster ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, scaff VARCHAR(10) NOT NULL)"""): QMessageBox.warning(self, "Magazzino", QString("Creazione tabella fallita!")) return False if not ("magaslave" in self.db.tables()): if not query.exec_("""CREATE TABLE magaslave ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, datains DATE NOT NULL, abbi VARCHAR(50), angro VARCHAR(50), desc VARCHAR(100), qt INTEGER NOT NULL DEFAULT '1', imp DOUBLE NOT NULL DEFAULT '0.0', equiv VARCHAR(100), mmid INTEGER NOT NULL, fatt VARCHAR(50), note VARCHAR(200), FOREIGN KEY (mmid) REFERENCES magamaster)"""): QMessageBox.warning(self, "Magazzino", QString("Creazione tabella fallita!")) return False QMessageBox.information(self, "Magazzino", QString("Database Creato!")) return True def loadFile(self, fname=None): if fname is None: return if self.db.isOpen(): self.db.close() self.db.setDatabaseName(QString(fname)) if not self.db.open(): QMessageBox.warning(self, "Magazzino", QString("Database Error: %1") .arg(self.db.lastError().text())) else: if not self.creaStrutturaDB(): return self.filename = unicode(fname) self.setWindowTitle("Gestione Magazzino - %s" % self.filename) self.setupModels() self.setupMappers() self.setupTables() #self.setupItmSignals() self.restoreTablesSettings() self.mmUpdate() def loadInitialFile(self): settings = QSettings() fname = unicode(settings.value("Settings/lastFile").toString()) if fname and QFile.exists(fname): self.loadFile(fname) def openFile(self): dir = os.path.dirname(self.filename) \ if self.filename is not None else "." fname = QFileDialog.getOpenFileName(self, "Gestione Magazzino - Scegli database", dir, "*.db") if fname: self.loadFile(fname) def newFile(self): dir = os.path.dirname(self.filename) \ if self.filename is not None else "." fname = QFileDialog.getSaveFileName(self, "Gestione Magazzino - Scegli database", dir, "*.db") if fname: self.loadFile(fname) def setupMenu(self): # AboutBox self.connect(self.actionA_bout, SIGNAL("triggered()"), self.showAboutBox) # FileNew self.connect(self.action_New_File, SIGNAL("triggered()"), self.newFile) # FileLoad self.connect(self.action_Load_File, SIGNAL("triggered()"), self.openFile) def showAboutBox(self): dlg = aboutmaga.AboutBox(self) dlg.exec_() def printInventory(self): ''' Print Inventory ''' if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return querygrp = QSqlQuery() querydett = QSqlQuery() querygrp.exec_("SELECT abbi,qt,imp,sum(qt*imp) " "FROM magaslave GROUP BY abbi") querydett.prepare("SELECT datains,abbi,angro,desc,qt,imp " "FROM magaslave WHERE abbi = :abbi AND " "qt > 0 ORDER BY datains") from reportlab.pdfgen.canvas import Canvas from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import cm from reportlab.lib.enums import TA_LEFT,TA_RIGHT,TA_CENTER from reportlab.platypus import Spacer, SimpleDocTemplate from reportlab.platypus import Table, TableStyle, Paragraph from reportlab.rl_config import defaultPageSize from reportlab.lib import colors PAGE_WIDTH, PAGE_HEIGHT=defaultPageSize styles = getSampleStyleSheet() styleN = styles['Normal'] styleH = styles['Heading1'] styleH.alignment=TA_CENTER Elements = [] #add some flowables p=Paragraph ps=ParagraphStyle Title = unicode(self.prtTitleLineEdit.text()) Year = unicode(self.prtDateLineEdit.text()) Author = "Stefano Zamprogno" URL = "http://www.zamprogno.it/" email = "*****@*****.**" pageinfo = "%s / %s / %s" % (Author, email, Title) def myFirstPage(canvas, doc): canvas.saveState() canvas.setStrokeColorRGB(0.50,0.50,0.50) canvas.setLineWidth(10) canvas.line(45,72,45,PAGE_HEIGHT-72) #canvas.setFont('Times-Bold',16) #canvas.drawCentredString(3*cm, 1.5*cm,Title) canvas.setFont('Times-Roman',9) canvas.drawString(3*cm, 1.5*cm, "First Page / %s" % pageinfo) canvas.restoreState() def myLaterPages(canvas, doc): canvas.saveState() canvas.setStrokeColorRGB(0.50,0.50,0.50) canvas.setLineWidth(5) canvas.line(45,72,45,PAGE_HEIGHT-72) canvas.setFont('Times-Roman',9) canvas.drawString(3*cm, 1.5*cm, "Page %d %s" % (doc.page, pageinfo)) canvas.restoreState() Elements.append(Paragraph(Title, styleH)) Elements.append(Paragraph(Year,styleN)) Elements.append(Spacer(0.5*cm, 0.5*cm)) tot=0 while querygrp.next(): tot += querygrp.value(3).toDouble()[0] querydett.bindValue(":abbi", QVariant(querygrp.value(0).toString())) querydett.exec_() data = [['Abbi', 'Angro', 'Descrizione', 'Qt', 'Imp'],] while querydett.next(): data.append([ p(unicode(querydett.value(1).toString()), ps(name='Normal')), p(unicode(querydett.value(2).toString()), ps(name='Normal')), p(unicode(querydett.value(3).toString()), ps(name='Normal')), querydett.value(4).toInt()[0], unicode("%.2f" % querydett.value(5).toDouble()[0])]) data.append([None, None, unicode("GRUPPO '%s'" % querygrp.value(0).toString()), unicode("Subtotale:"), unicode("€ %.2f" % querygrp.value(3).toDouble()[0])]) Elements.append(Table(data,repeatRows=1, style=(['LINEBELOW', (3,-2), (-1,-2), 1, colors.black], ['LINEBELOW', (0,0), (-1,0), 1, colors.black], ['ALIGN', (1,0), (3,-1),'CENTER'], ['ALIGN', (4,0), (-1,0),'RIGHT'], ['VALIGN', (0,0), (-1,-1), 'TOP'], ['ALIGN', (4,0), (-1,-1), 'RIGHT'], # ['TEXTCOLOR', (0,0), (-1,0), # colors.red], ['BACKGROUND',(0,0),(-1,0), colors.lightgrey], ['GRID',(0,0),(-1,-1), 0.2, colors.black], ['FONT', (0, 0), (-1, 0), 'Helvetica-Bold', 10], ['FONT', (3, -1), (3, -1), 'Helvetica-Bold', 10]))) Elements.append(Spacer(0.5*cm, 0.5*cm)) Elements.append(Paragraph("<para align=right><b>TOTALE GENERALE:" "€ %.2f</b></para>" % tot, styleN)) doc = SimpleDocTemplate(os.path.join(os.path.dirname(__file__), 'mydoc.pdf')) doc.build(Elements,onFirstPage=myFirstPage, onLaterPages=myLaterPages) subprocess.Popen(['gnome-open',os.path.join(os.path.dirname(__file__), 'mydoc.pdf')]) def setupMappers(self): ''' Initialize all the application mappers ''' self.mapper = QDataWidgetMapper(self) self.mapper.setModel(self.mModel) self.mapper.addMapping(self.scaffLineEdit, SCAFF) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.toFirst() def setupTables(self): """ Initialize all the application tablesview """ self.sTableView.setModel(self.sModel) self.sTableView.setItemDelegate(MSDelegate(self)) self.sTableView.setColumnHidden(ID, True) self.sTableView.setColumnHidden(MMID, True) self.sTableView.setWordWrap(True) self.sTableView.resizeRowsToContents() self.sTableView.setAlternatingRowColors(True) self.sItmSelModel = QItemSelectionModel(self.sModel) self.sTableView.setSelectionModel(self.sItmSelModel) self.sTableView.setSelectionBehavior(QTableView.SelectRows) #self.sTableView.setTabKeyNavigation(True) self.fTableView.setModel(self.fModel) self.fTableView.setColumnHidden(ID, True) self.fTableView.setWordWrap(True) self.fTableView.resizeRowsToContents() self.fTableView.setAlternatingRowColors(True) self.fItmSelModel = QItemSelectionModel(self.fModel) self.fTableView.setSelectionModel(self.fItmSelModel) def setupModels(self): """ Initialize all the application models """ # setup slaveModel self.sModel = ssModel(self) self.sModel.setTable(QString("magaslave")) self.sModel.setHeaderData(ID, Qt.Horizontal, QVariant("ID")) self.sModel.setHeaderData(DATAINS, Qt.Horizontal, QVariant("DataIns")) self.sModel.setHeaderData(ABBI, Qt.Horizontal, QVariant("Abbi")) self.sModel.setHeaderData(ANGRO, Qt.Horizontal, QVariant("Angro")) self.sModel.setHeaderData(DESC, Qt.Horizontal, QVariant("Desc")) self.sModel.setHeaderData(QT, Qt.Horizontal, QVariant("Qt")) self.sModel.setHeaderData(IMP, Qt.Horizontal, QVariant("Imp")) self.sModel.setHeaderData(EQUIV, Qt.Horizontal, QVariant("Equiv")) self.sModel.setHeaderData(MMID, Qt.Horizontal, QVariant("ScaffId")) self.sModel.setHeaderData(FATT, Qt.Horizontal, QVariant("Fatt")) self.sModel.setHeaderData(NOTE, Qt.Horizontal, QVariant("Note")) self.sModel.setSort(DATAINS, Qt.AscendingOrder) self.sModel.setEditStrategy(QSqlTableModel.OnRowChange) self.sModel.select() # setup masterModel self.mModel = QSqlTableModel(self) self.mModel.setTable(QString("magamaster")) self.mModel.setSort(SCAFF, Qt.AscendingOrder) self.mModel.setHeaderData(ID, Qt.Horizontal, QVariant("ID")) self.mModel.setHeaderData(SCAFF, Qt.Horizontal, QVariant("Scaff")) self.mModel.select() # setup findModel self.fModel = QSqlRelationalTableModel(self) self.fModel.setTable(QString("magaslave")) self.fModel.setHeaderData(ID, Qt.Horizontal, QVariant("ID")) self.fModel.setHeaderData(DATAINS, Qt.Horizontal, QVariant("DataIns")) self.fModel.setHeaderData(ABBI, Qt.Horizontal, QVariant("Abbi")) self.fModel.setHeaderData(ANGRO, Qt.Horizontal, QVariant("Angro")) self.fModel.setHeaderData(DESC, Qt.Horizontal, QVariant("Desc")) self.fModel.setHeaderData(QT, Qt.Horizontal, QVariant("Qt")) self.fModel.setHeaderData(IMP, Qt.Horizontal, QVariant("Imp")) self.fModel.setHeaderData(EQUIV, Qt.Horizontal, QVariant("Equiv")) self.fModel.setHeaderData(MMID, Qt.Horizontal, QVariant("ScaffId")) self.fModel.setHeaderData(FATT, Qt.Horizontal, QVariant("Fatt")) self.fModel.setHeaderData(NOTE, Qt.Horizontal, QVariant("Note")) self.fModel.setSort(MMID, Qt.AscendingOrder) self.fModel.setRelation(MMID, QSqlRelation("magamaster", "id", "scaff")) self.fModel.select() def clipCopy(self): self.Clipboard = self.sTableView.selectedIndexes() selrows = self.sItmSelModel.selectedRows() # TODO : da usare: selrows = self.sItmSelModel.selectedRows() print(selrows, len(selrows)) print(len(self.Clipboard)) # FIXME : bla bla bla def clipDel(self): self.delDettRecord() def clipPaste(self): pass def ctxtMenu(self, point): menu = QMenu(self) copyAction = menu.addAction("&Copy") self.connect(copyAction, SIGNAL("triggered()"), self.clipCopy) delAction = menu.addAction("&Del") self.connect(delAction, SIGNAL("triggered()"), self.clipDel) if len(self.Clipboard) > 0: pasteAction = menu.addAction("&Paste") self.connect(pasteAction, SIGNAL("triggered()"), self.clipPaste) menu.exec_(self.sTableView.mapToGlobal(point)) def setupUiSignals(self): self.sTableView.setContextMenuPolicy(Qt.CustomContextMenu) self.connect(self.sTableView, SIGNAL( "customContextMenuRequested(const QPoint &)"), self.ctxtMenu) self.connect(self.scaffLineEdit, SIGNAL("returnPressed()"), lambda: self.saveRecord(MainWindow.FIRST)) self.connect(self.findLineEdit, SIGNAL("returnPressed()"), self.globalFilter) self.connect(self.printPushButton, SIGNAL("clicked()"), self.printInventory) self.connect(self.createFilterPushButton, SIGNAL("clicked()"), self.createFilter) self.connect(self.findPushButton, SIGNAL("clicked()"), self.applyFilter) self.connect(self.gSearchPushButton, SIGNAL("clicked()"), self.globalFilter) self.connect(self.addscaffPushButton, SIGNAL("clicked()"), self.addScaffRecord) self.connect(self.adddettPushButton, SIGNAL("clicked()"), self.addDettRecord) self.connect(self.deldettPushButton, SIGNAL("clicked()"), self.delDettRecord) self.connect(self.delscaffPushButton, SIGNAL("clicked()"), self.delScaffRecord) self.connect(self.scaffFirstPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.FIRST)) self.connect(self.scaffPrevPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.PREV)) self.connect(self.scaffNextPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.NEXT)) self.connect(self.scaffLastPushButton, SIGNAL("clicked()"), lambda: self.saveRecord(MainWindow.LAST)) def globalFilter(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return txt = self.findLineEdit.text() qry = ("(datains like '%s') OR " "(abbi like '%s') OR " "(angro like '%s') OR " "(desc like '%s') OR " "(equiv like '%s') OR" "(fatt like '%s') OR" "(note like '%s')") % ((txt,)*7) self.fModel.setFilter(qry) self.updateFilter() def updateFilter(self): self.fModel.select() self.fTableView.setColumnHidden(ID, True) def applyFilter(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return self.fModel.setFilter(self.findLineEdit.text()) self.updateFilter() def createFilter(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return headerDef = ("datains VARCHAR(100)", "abbi VARCHAR(100)", "angro VARCHAR(100)", "desc VARCHAR(100)", "qt VARCHAR(100)", "imp VARCHAR(100)", "equiv VARCHAR(100)", "fatt VARCHAR(100)", "note VARCHAR(100)") dlg = filterdialog.FilterDialog(headerDef, QSqlDatabase.database(), self) if(dlg.exec_()): self.findLineEdit.setText(dlg.filterDone() if dlg.filterDone() else "") self.applyFilter() #~ def editEsc(self, idxcur, idxold): #~ if self.editindex and self.editindex.isValid(): #~ if idxcur.row() != self.editindex.row(): #~ self.sModel.revertAll() #~ self.editindex = None def mmUpdate(self): row = self.mapper.currentIndex() id = self.mModel.data(self.mModel.index(row,ID)).toString() self.sModel.setFilter("mmid=%s" % id) self.sModel.select() self.sTableView.setColumnHidden(ID, True) self.sTableView.setColumnHidden(MMID, True) def saveRecord(self, where): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return row = self.mapper.currentIndex() self.mapper.submit() self.sModel.revertAll() if where == MainWindow.FIRST: row=0 elif where == MainWindow.PREV: row = 0 if row <= 1 else row - 1 elif where == MainWindow.NEXT: row += 1 if row >= self.mModel.rowCount(): row = self.mModel.rowCount() -1 elif where == MainWindow.LAST: row = self.mModel.rowCount()- 1 self.mapper.setCurrentIndex(row) self.mmUpdate() def addScaffRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return row = self.mModel.rowCount() self.mapper.submit() self.mModel.insertRow(row) self.mapper.setCurrentIndex(row) self.scaffLineEdit.setFocus() self.mmUpdate() def addDettRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return rowscaff = self.mapper.currentIndex() record = self.mModel.record(rowscaff) masterid = record.value(ID).toInt()[0] if masterid < 1: self.statusbar.showMessage( "Scaffale non valido o non confermato...", 5000) self.scaffLineEdit.setFocus() return # aggiunge la nuova riga alla vista self.sModel.submitAll() self.sModel.select() row = self.sModel.rowCount() self.sModel.insertRow(row) if row > 1: precfatt = self.sModel.data(self.sModel.index(row-1, FATT)) else: precfatt = '' if row > 1: lastData = self.sModel.data(self.sModel.index(row-1, DATAINS)) else: lastData = '' self.sModel.setData(self.sModel.index(row, MMID), QVariant(masterid)) self.sModel.setData(self.sModel.index(row, QT), QVariant(1)) self.sModel.setData(self.sModel.index(row, IMP), QVariant(0.0)) self.sModel.setData(self.sModel.index(row, FATT), QVariant(precfatt)) self.editindex = self.sModel.index(row, DATAINS) self.sTableView.setCurrentIndex(self.editindex) self.sTableView.edit(self.editindex) def delDettRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return selrows = self.sItmSelModel.selectedRows() if not selrows: self.statusbar.showMessage( "No articles selected to delete...", 5000) return if(QMessageBox.question(self, "Cancella Articoli", "Vuoi cancellare: {0} articoli?".format(len(selrows)), QMessageBox.Yes|QMessageBox.No) == QMessageBox.No): return QSqlDatabase.database().transaction() query = QSqlQuery() query.prepare("DELETE FROM magaslave WHERE id = :val") for i in selrows: if i.isValid(): query.bindValue(":val", QVariant(i.data().toInt()[0])) query.exec_() QSqlDatabase.database().commit() self.sModel.revertAll() self.mmUpdate() def delScaffRecord(self): if not self.db.isOpen(): self.statusbar.showMessage( "Database non aperto...", 5000) return row = self.mapper.currentIndex() if row == -1: self.statusbar.showMessage( "Nulla da cancellare...", 5000) return record = self.mModel.record(row) id = record.value(ID).toInt()[0] scaff = record.value(SCAFF).toString() if(QMessageBox.question(self, "Cancella Scaffale", "Vuoi cancellare lo scaffale: {0} ?".format(scaff), QMessageBox.Yes|QMessageBox.No) == QMessageBox.No): self.statusbar.showMessage( "Cancellazione scaffale annullata...", 5000) return # cancella scaffale self.mModel.removeRow(row) self.mModel.submitAll() if row + 1 >= self.mModel.rowCount(): row = self.mModel.rowCount() - 1 self.mapper.setCurrentIndex(row) if self.mModel.rowCount() == 0: self.scaffLineEdit.setText(QString("")) # cancella tutti gli articoli che si riferiscono # allo scaffale cancellato self.sModel.setFilter("mmid=%s" % id) self.sModel.select() self.sModel.removeRows(0, self.sModel.rowCount()) self.sModel.submitAll() self.statusbar.showMessage( "Cancellazione eseguita...", 5000) self.mmUpdate() def restoreTablesSettings(self): settings = QSettings(self) if self.saveTableGeometryCheckBox.isChecked(): # per la tabella slave for c in range(1, self.sModel.columnCount()-1): width = settings.value("Settings/sTableView/%s" % c, QVariant(60)).toInt()[0] self.sTableView.setColumnWidth(c, width if width > 0 else 60) # per la tabella find for c in range(1, self.fModel.columnCount()): width = settings.value("Settings/fTableView/%s" % c, QVariant(60)).toInt()[0] self.fTableView.setColumnWidth(c, width if width > 0 else 60) def restoreWinSettings(self): settings = QSettings() self.prtTitleLineEdit.setText(QString(settings.value( "Settings/printTitle", QVariant( "Situazione Magazzino - TIME di Stefano Zamprogno")).toString())) self.prtDateLineEdit.setText(QString(settings.value( "Settings/printDate", QVariant( "Al 31/12/2008")).toString())) self.saveWinPosCheckBox.setChecked( settings.value("Settings/saveWinPos", QVariant(True)).toBool()) self.saveTableGeometryCheckBox.setChecked( settings.value("Settings/saveTableGeometry", QVariant(True)).toBool()) self.restoreGeometry( settings.value("MainWindow/Geometry").toByteArray()) def closeEvent(self, event): settings = QSettings() if self.filename is not None: settings.setValue("Settings/lastFile", QVariant(self.filename)) settings.setValue("MainWindow/Geometry", QVariant( self.saveGeometry())) settings.setValue("Settings/saveWinPos", QVariant( self.saveWinPosCheckBox.isChecked())) settings.setValue("Settings/saveTableGeometry", QVariant( self.saveTableGeometryCheckBox.isChecked())) settings.setValue("Settings/printTitle", QVariant( self.prtTitleLineEdit.text())) settings.setValue("Settings/printDate", QVariant( self.prtDateLineEdit.text())) if self.db.isOpen(): # salva larghezza colonne tabella slave for c in range(1, self.sModel.columnCount()-1): width = self.sTableView.columnWidth(c) if width: settings.setValue("Settings/sTableView/%s" % c, QVariant(width)) # salva larghezza colonne tabella find for c in range(1, self.fModel.columnCount()): width = self.fTableView.columnWidth(c) if width: settings.setValue("Settings/fTableView/%s" % c, QVariant(width)) self.db.close() del self.db
class StreetBrowser: def __init__(self, iface, street_browser, model, db, params): # Local ref to street browsers dock and iface self.street_browser = street_browser self.iface = iface self.model = model self.db = db self.params = params self.fltr_street_rcd_dlg = FilterStreetRecordsDlg() # Connect db self.mapper = None self.proxy = None self.setup_proxy_and_mapper() self.show_street = None # Display first record on load self.mapper.toFirst() # Create instance of editing class self.modify = EditRecord(self.iface, self.street_browser, self.model, self.mapper, self.db, self.params) self.modify.edit_signals.currentIndexSet.connect(self.disable_close) self.add = AddRecord(self.iface, self.street_browser, self.model, self.mapper, self.db, self.params) self.close = CloseRecord(self.iface, self.street_browser, self.model, self.mapper, self.db, self.params) # Create instance of filter pop class self.pop_filter_table = PopulateFilterTableView( self, self.fltr_street_rcd_dlg, self.db, self.model) self.canvas_functs = ZoomSelectCanvas(self.iface, self.street_browser, self.db) self.srwr = ScottishRoadWorksRegister(self.street_browser, self.db, self.iface, self.params) self.srwr.tab_idx_changed(0) self.connect_model_navigation() def setup_proxy_and_mapper(self): """ Map data fields to widgets in street browser and create proxy for filtering """ self.mapper = QDataWidgetMapper() self.proxy = QSortFilterProxyModel() self.proxy.setSourceModel(self.model) self.proxy.setDynamicSortFilter(True) self.mapper.setModel(self.proxy) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) # Set custom delegate for mapping to date widgets self.mapper.setItemDelegate(DateMapperCustomDelegate([6, 7, 8, 18])) self.mapper.currentIndexChanged.connect(self.mapper_idx_changed) self.map_widgets(self.mapper) def view_record(self): """ Changes current displayed record to one from xref table """ try: indexes = self.street_browser.ui.crossReferenceTableView.selectedIndexes( ) view_usrn = indexes[0].data() row_count = self.model.rowCount() counter = 0 match = False while counter <= row_count and not match: idx = self.model.index(counter, 1) usrn = idx.data() counter += 1 if view_usrn == usrn: match = True self.mapper.setCurrentIndex(idx.row()) except IndexError: pass def mapper_idx_changed(self): """ Remove abandoned 'show' geom and populate x-ref table """ if str(self.street_browser.ui.showPushButton.text()).lower() == 'hide': self.show_street.remove() self.street_browser.ui.showPushButton.setText('Show') usrn = self.street_browser.ui.usrnLineEdit.text() xref = CrossRefTable(self.db, self.street_browser) xref.populate_cross_ref(usrn) self.populate_linked_esu_list() self.srwr_tab_repopulate() self.disable_close(usrn) def populate_linked_esu_list(self): """ Populate the linked ESU list in the street browser """ self.street_browser.ui.linkEsuListWidget.clear() # Add new linked esu's self.gn_fnc = ZoomSelectCanvas(self.iface, self.street_browser, self.db) esu_list = self.gn_fnc.query_esu( self.street_browser.ui.usrnLineEdit.text()) for esu_id in esu_list: QListWidgetItem(str(esu_id), self.street_browser.ui.linkEsuListWidget) def set_buttons_initial_state(self, role): """ checks the role of the user and enables/disables buttons accordingly if usrn button is already disabled it leaves it alone because usrn is linked to other categories :param role: user role :return: void """ if role == 'admin' or role == 'editor': state = True else: state = False self.street_browser.ui.modifyPushButton.setEnabled(state) self.street_browser.ui.addPushButton.setEnabled(state) if self.street_browser.ui.closeOpPushButton.isEnabled(): self.street_browser.ui.closeOpPushButton.setEnabled(state) def connect_model_navigation(self): """ Connect record navigation buttons to widgetmapper functions """ self.street_browser.ui.firstPushButton.clicked.connect( self.mapper.toFirst) self.street_browser.ui.lastPushButton.clicked.connect( self.mapper.toLast) self.street_browser.ui.previousPushButton.clicked.connect( self.mapper.toPrevious) self.street_browser.ui.nextPushButton.clicked.connect( self.mapper.toNext) # Connect filter btn to filter dlg self.street_browser.ui.filterPushButton.clicked.connect( self.filter_street_records) # Connect close button and map button kwargs = {'zoom_to': True, 'select': True, 'close': False} self.street_browser.ui.mapPushButton.clicked.connect( lambda: self.canvas_functs.zoom_to_record(**kwargs)) self.street_browser.ui.viewPushButton.clicked.connect(self.view_record) self.street_browser.ui.showPushButton.clicked.connect( self.show_street_coordinates) # Connect modify button self.street_browser.ui.modifyPushButton.clicked.connect( self.modify_record) self.street_browser.ui.addPushButton.clicked.connect(self.add_record) self.street_browser.ui.closeOpPushButton.clicked.connect( self.close_record) # Connect SRWR tab self.street_browser.ui.srwrPushButton.clicked.connect(self.enable_srwr) # connect the default close button self.street_browser.signals.closed_sb.connect(self.remove_coords) def srwr_tab_repopulate(self): """ Repopulate SRWR tab if appropriate """ if self.street_browser.ui.srwrRecordsGroupBox.isVisible(): cur_tab = self.street_browser.ui.srwrTabWidget.currentIndex() if not self.srwr: self.srwr = ScottishRoadWorksRegister(self.street_browser, self.db, self.iface, self.params) self.srwr.tab_idx_changed(cur_tab) def filter_street_records(self): self.fltr_street_rcd_dlg.exec_( ) # DO NOT USE .show() FOR CHILD PROCESSES! def enable_srwr(self): """ Toggles visibility of SRWR Records group """ if self.street_browser.ui.srwrRecordsGroupBox.isVisible(): self.street_browser.ui.srwrRecordsGroupBox.setVisible(False) self.street_browser.ui.srwrPushButton.setText("Show SRWR Details") else: self.street_browser.ui.srwrRecordsGroupBox.setVisible(True) self.street_browser.ui.srwrPushButton.setText("Hide SRWR Details") if not self.srwr: # Mimic tab change to populate the default tab self.srwr = ScottishRoadWorksRegister(self.street_browser, self.db, self.iface, self.params) self.srwr.tab_idx_changed(0) def show_street_coordinates(self): if str(self.street_browser.ui.showPushButton.text()).lower() == "show": startx = self.street_browser.ui.startXLineEdit.text() endx = self.street_browser.ui.endXLineEdit.text() starty = self.street_browser.ui.startYLineEdit.text() endy = self.street_browser.ui.endYLineEdit.text() coords = ((startx, starty), (endx, endy)) if coords[0][0] and coords[1][0]: self.show_street = ShowStreetCoordinates(self.iface) self.show_street.show(coords) self.street_browser.ui.showPushButton.setText('Hide') else: self.show_street.remove() self.street_browser.ui.showPushButton.setText('Show') def modify_record(self): """ Modify a an existing street record """ if not self.is_layer_editing(): self.modify.modify_record() def add_record(self): """ Add a new new record """ if not self.is_layer_editing(): self.add.add() def close_record(self): """ Close an existing street record """ if not self.is_layer_editing(): self.close.close() def is_layer_editing(self): """ Checks if either the rd poly layer or esu layer are currently in editing state. :return: True if editing """ esu_layer = QgsMapLayerRegistry.instance().mapLayersByName( 'ESU Graphic')[0] rdpoly_layer = QgsMapLayerRegistry.instance().mapLayersByName( 'Road Polygons')[0] if esu_layer.isEditable() or rdpoly_layer.isEditable(): no_add_esu_layer_msg_box = QMessageBox( QMessageBox.Warning, '', 'Cannot modify street record while editing layers', QMessageBox.Ok, None) no_add_esu_layer_msg_box.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowTitleHint) no_add_esu_layer_msg_box.exec_() return True else: return False def goto_record(self, index): """ Navigate to a specific index in the model :param index: model idx """ self.mapper.setCurrentIndex(index) def remove_coords(self): """ remove the start/end coords from the canvas when the street browser is closed from the default button """ if self.show_street: self.show_street.remove() if self.street_browser.ui.showPushButton.text() == "Hide": self.street_browser.ui.showPushButton.setText("Show") def map_widgets(self, mapper): """ Map widgets to columns :param mapper: Data widget mapper """ mapper.addMapping(self.street_browser.ui.classLineEdit, 19) # street_class mapper.addMapping(self.street_browser.ui.versionLineEdit, 2) # version_no mapper.addMapping(self.street_browser.ui.typeLineEdit, 4) # street_ref_type mapper.addMapping(self.street_browser.ui.descriptionTextEdit, 5) # description mapper.addMapping(self.street_browser.ui.localityLineEdit, 20) # loc_ref mapper.addMapping(self.street_browser.ui.townLineEdit, 22) # town_ref mapper.addMapping(self.street_browser.ui.countyLineEdit, 21) # county_ref mapper.addMapping(self.street_browser.ui.authorityLineEdit, 9) # authority mapper.addMapping(self.street_browser.ui.byLineEdit, 23) # updated_by mapper.addMapping(self.street_browser.ui.updateDateLineEdit, 7) # update_date mapper.addMapping(self.street_browser.ui.startDateLineEdit, 8) # start_date mapper.addMapping(self.street_browser.ui.entryDateLineEdit, 6) # entry_date mapper.addMapping(self.street_browser.ui.startXLineEdit, 11) # start_xref mapper.addMapping(self.street_browser.ui.startYLineEdit, 12) # start_yref mapper.addMapping(self.street_browser.ui.tolLineEdit, 15) # tolerance mapper.addMapping(self.street_browser.ui.endXLineEdit, 13) # end_xref mapper.addMapping(self.street_browser.ui.endYLineEdit, 14) # end_yref mapper.addMapping(self.street_browser.ui.stateLineEdit, 17) # street_state mapper.addMapping(self.street_browser.ui.stateDateLineEdit, 18) # street_date mapper.addMapping(self.street_browser.ui.usrnLineEdit, 1) # USRN @pyqtSlot(str) def disable_close(self, usrn): """ disables the delete button in case a street is linked to other categories :param usrn : [str] the usrn of the current record in widget mapper """ usrn_num_str = "SELECT (SELECT COUNT (usrn) FROM tblSPEC_DES WHERE usrn = {} AND currency_flag = 0) + " \ "(SELECT COUNT (usrn) FROM tblMAINT WHERE usrn = {} AND currency_flag = 0) + " \ "(SELECT COUNT (usrn) FROM tblREINS_CAT WHERE usrn = {} AND currency_flag = 0) AS NoUSRN"\ .format(usrn, usrn, usrn) usrn_num_query = QSqlQuery(usrn_num_str, self.db) usrn_num_query.first() linked_usrn_num = usrn_num_query.value(0) if linked_usrn_num > 0 or self.params['role'] == 'readonly': self.street_browser.ui.closeOpPushButton.setEnabled(False) else: self.street_browser.ui.closeOpPushButton.setEnabled(True)