def extract_rmc(self, data): self.info.latitude = data.latitude self.info.longitude = data.longitude self.info.speed = KNOTS_TO_KM * safe_float(data.spd_over_grnd) self.info.status = data.data_validity self.info.direction = safe_float(data.true_course) if data.datestamp and data.timestamp: date = QDate(data.datestamp.year, data.datestamp.month, data.datestamp.day) time = QTime(data.timestamp.hour, data.timestamp.minute, data.timestamp.second) dt = QDateTime() self.info.utcDateTime.setTimeSpec(Qt.UTC) self.info.utcDateTime.setDate(date) self.info.utcDateTime.setTime(time) return self.info
def data(self, index, role): if not index.isValid(): return QVariant() elif role == Qt.TextAlignmentRole and index.column() != SAMPLE_COLUMN: return QVariant(Qt.AlignHCenter | Qt.AlignVCenter) elif role != Qt.DisplayRole: return QVariant() if index.column() == DATE_COLUMN: return QDate(self.arraydata[index.row()][index.column()]) elif index.column() == TIME_COLUMN: return QTime(self.arraydata[index.row()][index.column()]) else: return QVariant(self.arraydata[index.row()][index.column()])
def test__years_QDate(self): """ Überprüft, daß die Funktion der Berechnung der Jahre auch Ergebnisse im zu erwartenden Rahmen zurückgibt. """ DATE_STEP = 1 DATE_YEAR = { "min": -1, "max": 2, } ## Eine Liste mit Daten anlegen dates_all = [] ## Von ... year_min = DATE_YEAR["min"] ## ... bis year_max = DATE_YEAR["max"] ## Startdatum date_store = QDate(year_min, 1, 1) date_max = QDate(year_max, 1, 1) ## Die Listen tatsächlich anlegen while date_store < date_max: dates_all.append(date_store) date_store = date_store.addDays(DATE_STEP) ## Kopie erstellen dates_to_compare = dates_all[:] results_expected = tuple(range(year_max - year_min + 1)) for date_1 in dates_all: dates_to_compare.remove(date_1) for date_2 in dates_to_compare: self.assertIn(Calc.years(date_1, date_2), results_expected)
def setDateEnd(self, dateEnd): """ Sets the end date for this item. This method will only affect the start date if the end date is set to occur before its start, in which case it will set the start date as the same date. (1 day duration) Otherwise, this method will scale the duration of the event. :param dateEnd | <QDate> """ dateEnd = QDate(dateEnd) if (dateEnd < self._dateStart): self._dateStart = dateEnd self._dateEnd = dateEnd self.markForRebuild()
def toVariant(v): if v is None: return QVariant() t = type(v) if t == QVariant: return v elif t == datetime.time: return QVariant(QTime(v)) elif t == datetime.datetime: return QVariant(QDateTime(v)) elif t == datetime.date: return QVariant(QDate(v)) elif t == Decimal: return QVariant(unicode(v)) else: return QVariant(v)
def setDateStart(self, dateStart): """ Sets the start date for this item. This will automatically push the end date to match the duration for this item. So if the item starts on 1/1/12 and ends on 1/2/12, and the start date is changed to 2/1/12, the end date will change to 2/2/12. To affect the duration of the item, use either setDuration, or setDateEnd. :param dateStart | <QDate> """ dateStart = QDate(dateStart) duration = self.duration() self._dateStart = dateStart self._dateEnd = dateStart.addDays(duration - 1) self.markForRebuild()
def setupCalendar(calendarWidget, timeEdit): timeGuiLaunched = datetime.now() timeGuiLaunchedStr = str(timeGuiLaunched) year = timeGuiLaunchedStr[0:4] month = timeGuiLaunchedStr[5:7] day = timeGuiLaunchedStr[8:10] dateLaunched = QDate(int(year), int(month), int(day)) # Set current date for GUI calendar calendarWidget.setSelectedDate(dateLaunched) timeGuiLaunched = timeGuiLaunchedStr[11:16] # Set current time for GUI time field timeEdit.setTime( QTime(int(timeGuiLaunched[0:2]), int(timeGuiLaunched[3:5])))
def __init__(self, parent=None): super(NewTaskDialog, self).__init__(parent) # task name nameLabel = QLabel(self.tr("Name:")) self.name = QLineEdit() nameLabel.setBuddy(self.name) # priority priorityLabel = QLabel(self.tr("Priority:")) self.priority = QComboBox() priorityLabel.setBuddy(self.priority) dateLabel = QLabel(self.tr("Deadline:")) self.deadline = QDateEdit() dateLabel.setBuddy(self.deadline) self.deadline.setCalendarPopup(True) self.deadline.calendarWidget().setFirstDayOfWeek(Qt.Monday) self.deadline.setDate(QDate(date.today())) createButton = QPushButton(self.tr("Save")) cancelButton = QPushButton(self.tr("Cancel")) buttonLayout = QHBoxLayout() buttonLayout.addStretch() buttonLayout.addWidget(createButton) buttonLayout.addWidget(cancelButton) layout = QGridLayout() layout.addWidget(nameLabel, 0, 0) layout.addWidget(self.name, 0, 1) layout.addWidget(priorityLabel, 1, 0) layout.addWidget(self.priority, 1, 1) layout.addWidget(dateLabel, 2, 0) layout.addWidget(self.deadline, 2, 1) layout.addLayout(buttonLayout, 3, 0, 3, 2) self.setLayout(layout) self.connect(self.deadline, SIGNAL("dateChanged(const QDate&)"), self, SLOT("changed()")) self.connect(createButton, SIGNAL("clicked()"), self, SLOT("accept()")) self.connect(cancelButton, SIGNAL("clicked()"), self, SLOT("reject()")) self.setWindowTitle(self.tr("Task")) self.resize(350, 120) self.setMinimumSize(QSize(250, 120)) self.setMaximumSize(QSize(450, 120))
def loadQDataStream(self): error = None fh = None try: fh = QFile(self.__fname) if not fh.open(QIODevice.ReadOnly): raise IOError(str(fh.errorString())) stream = QDataStream(fh) magic = stream.readInt32() if magic != MovieContainer.MAGIC_NUMBER: raise IOError("unrecognized file type") version = stream.readInt32() if version < MovieContainer.OLD_FILE_VERSION: raise IOError("old and unreadable file format") elif version > MovieContainer.FILE_VERSION: raise IOError("new and unreadable file format") old = False if version == MovieContainer.OLD_FILE_VERSION: old = True stream.setVersion(QDataStream.Qt_4_2) self.clear(False) while not stream.atEnd(): title = QString() acquired = QDate() location = QString() notes = QString() stream >> title year = stream.readInt16() minutes = stream.readInt16() if old: stream >> acquired >> notes else: stream >> acquired >> location >> notes self.add(Movie(title, year, minutes, acquired, location, notes)) except EnvironmentError as e: error = "Failed to load: {0}".format(e) finally: if fh is not None: fh.close() if error is not None: return False, error self.__dirty = False return True, "Loaded {0} movie records from {1}".format( len(self.__movies), QFileInfo(self.__fname).fileName())
def on_exception_but_clicked(self): #Local vars for testing value display in debugger t01 = QgsApplication.pluginPath() t02 = QgsApplication.svgPaths() #t03 = QChar('x') t04 = QPoint(4, 5) t05 = QPointF(4.1, 5.1) t06 = QDate() t07 = QTime() t08 = QDir() t09 = QFile() t10 = QUrl() x01 = 42 x02 = 'fortytwo' raise Exception( "Exception raised. Check local variables in your debugger.")
def update_db_content(self): """Populate the payment table ensuring all "visible" data""" today = QDate.currentDate() first_month_day = QDate(today.year(), today.month(), 1) datebefore = first_month_day.addMonths(-self.months_before) dateafter = first_month_day.addMonths(self.months_after) query = QSqlQuery( 'SELECT client, machine, selldate, deltamonth, ' 'anticiped FROM clients', self._db) if not query.exec_(): raise StandardError('SYNTAX ERROR') while query.next(): client = Client(query) payments_date = client.selldate.addMonths( 0 if client.anticiped else client.deltamonth) while payments_date < datebefore: # ignora date non visibili payments_date = payments_date.addMonths(client.deltamonth) while payments_date < dateafter: query2 = QSqlQuery( 'SELECT effective_datepayd FROM payments ' 'WHERE clients_client = :client AND clients_machine = ' ':machine AND clients_selldate = :selldate AND ' 'expected_datepayd = :expected_datepayd', self._db) query2.bindValue(':client', QVariant(client.client)) query2.bindValue(':machine', QVariant(client.machine)) query2.bindValue(':selldate', QVariant(client.selldate)) query2.bindValue(':expected_datepayd', QVariant(payments_date)) if not query2.exec_(): raise StandardError('SYNTAX ERROR') if not query2.first(): query3 = QSqlQuery( 'INSERT INTO payments (clients_client, ' 'clients_machine, clients_selldate, ' 'expected_datepayd) VALUES (:client, :machine, ' ':selldate, :expected_datepayd)', self._db) query3.bindValue(':client', QVariant(client.client)) query3.bindValue(':machine', QVariant(client.machine)) query3.bindValue(':selldate', QVariant(client.selldate)) query3.bindValue(':expected_datepayd', QVariant(payments_date)) if not query3.exec_(): raise StandardError('SYNTAX ERROR') payments_date = payments_date.addMonths(client.deltamonth) self.emit(SIGNAL("layoutChanged()"))
def __init__(self): QARecord.__init__() self.Type = QARecordType.Session self.NULLDATE = QDateTime(QDate(2222, 2, 22), QTime(22, 22, 22, 22)) self.dwgCreated = QDateTime() self.dwgSaved = QDateTime() self.dwgFileName = None self.dwgSizeOpened = 0 self.dwgSizeClosed = 0 self.tagName = None self.tagProject = None self.tagReason = None self.tagSection = None self.sessionType = None self.qaLastSaved = QDateTime() self.closed = QDateTime() self.correlation = None self.corrupted = None
def to_pyqt(obj, type_=None): """ Converts data from python object type to PyQt equivalent :param obj: Python object :type obj: Multiple types :param type_: Cast type :type type_: Object :return: Converted value :rtype: Multiple types """ if isinstance(obj, int): return obj if isinstance(obj, (Decimal, float)): obj = Decimal(obj).normalize() elif type(obj) is datetime.date: return QDate(obj) elif type(obj) is datetime.datetime: return QDateTime(obj).toLocalTime() return unicode(obj) if obj is not None else obj
def test_metadata_date(self): metadata = OutputLayerMetadata('random_layer_id') path = TEST_XML_BASEPATH + 'gco:Date' # using QDate test_value = QDate(2015, 6, 7) metadata.set('ISO19115_TEST', test_value, path) self.assertEqual(metadata.get_xml_value('ISO19115_TEST'), '2015-06-07') # using datetime test_value = datetime(2015, 6, 7) metadata.update('ISO19115_TEST', test_value) self.assertEqual(metadata.get_xml_value('ISO19115_TEST'), '2015-06-07') # using date test_value = date(2015, 6, 7) metadata.set('ISO19115_TEST', test_value, path) self.assertEqual(metadata.get_xml_value('ISO19115_TEST'), '2015-06-07') # using str should fail test_value = 'String' with self.assertRaises(TypeError): metadata.update('ISO19115_TEST', test_value)
def __init_sale_date(cls): cls.grid_layout_widget_10.setGeometry(QRect(450, 110, 101, 41)) cls.grid_layout_widget_10.setObjectName( _fromUtf8("gridLayoutWidget_10")) cls.grid_layout_10.setObjectName(_fromUtf8("gridLayout_10")) cls.sale_date_title.setFont(WindowCons.get_font(bold=True)) cls.sale_date_title.setTextFormat(Qt.PlainText) cls.sale_date_title.setAlignment(Qt.AlignCenter) cls.sale_date_title.setObjectName(_fromUtf8("buy_date_title_2")) cls.grid_layout_10.addWidget(cls.sale_date_title, 0, 0, 1, 1) cls.grid_layout_widget_20.setGeometry(QRect(570, 110, 141, 41)) cls.grid_layout_widget_20.setObjectName( _fromUtf8("gridLayoutWidget_20")) cls.grid_layout_20.setObjectName(_fromUtf8("gridLayout_20")) cls.sale_date_input.setFont( WindowCons.get_font(size=12, family=WindowCons.YAHEI_LIGHT_FAMILY)) cls.sale_date_input.setWrapping(False) cls.sale_date_input.setFrame(False) cls.sale_date_input.setCalendarPopup(True) cls.sale_date_input.setDate( QDate(datetime.datetime.date(datetime.datetime.now()))) cls.sale_date_input.setObjectName(_fromUtf8("sale_date_input")) cls.grid_layout_20.addWidget(cls.sale_date_input, 0, 0, 1, 1)
def __init__(self, parent=None): super(TalkDetailsWidget, self).__init__(parent) self.layout = QGridLayout() self.setLayout(self.layout) self.buttonLayout = QHBoxLayout() saveIcon = QIcon.fromTheme("document-save") self.saveButton = QPushButton('Save Talk') self.saveButton.setIcon(saveIcon) self.buttonLayout.addWidget(self.saveButton) self.layout.addLayout(self.buttonLayout, 0, 1, 1, 1) self.titleLabel = QLabel('Title') self.titleLineEdit = QLineEdit() self.presenterLabel = QLabel('Presenter') self.presenterLineEdit = QLineEdit() self.layout.addWidget(self.titleLabel, 1, 0, 1, 1) self.layout.addWidget(self.titleLineEdit, 1, 1, 1, 1) self.layout.addWidget(self.presenterLabel, 1, 2, 1, 1) self.layout.addWidget(self.presenterLineEdit, 1, 3, 1, 1) self.eventLabel = QLabel('Event') self.eventLineEdit = QLineEdit() self.categoryLabel = QLabel('Category') self.categoryLineEdit = QLineEdit() self.layout.addWidget(self.eventLabel, 2, 0, 1, 1) self.layout.addWidget(self.eventLineEdit, 2, 1, 1, 1) self.layout.addWidget(self.categoryLabel, 2, 2, 1, 1) self.layout.addWidget(self.categoryLineEdit, 2, 3, 1, 1) self.roomLabel = QLabel('Room') self.roomLineEdit = QLineEdit() self.dateLayout = QHBoxLayout() self.dateLabel = QLabel('Date') self.dateEdit = QDateEdit() currentDate = QDate() self.dateEdit.setDate(currentDate.currentDate()) self.dateEdit.setCalendarPopup(True) self.layout.addWidget(self.roomLabel, 3, 0, 1, 1) self.layout.addWidget(self.roomLineEdit, 3, 1, 1, 1) self.dateLayout.addWidget(self.dateEdit) self.layout.addWidget(self.dateLabel, 3, 2, 1, 1) self.layout.addLayout(self.dateLayout, 3, 3, 1, 1) self.startTimeLayout = QHBoxLayout() self.startTimeLabel = QLabel('Start Time') self.startTimeEdit = QTimeEdit() self.startTimeLayout.addWidget(self.startTimeEdit) self.endTimeLayout = QHBoxLayout() self.endTimeLabel = QLabel('End Time') self.endTimeEdit = QTimeEdit() self.endTimeLayout.addWidget(self.endTimeEdit) self.layout.addWidget(self.startTimeLabel, 4, 0, 1, 1) self.layout.addLayout(self.startTimeLayout, 4, 1, 1, 1) self.layout.addWidget(self.endTimeLabel, 4, 2, 1, 1) self.layout.addLayout(self.endTimeLayout, 4, 3, 1, 1) self.descriptionLabel = QLabel('Description') self.descriptionLabel.setAlignment(Qt.AlignTop) self.descriptionTextEdit = QPlainTextEdit() self.layout.addWidget(self.descriptionLabel, 5, 0, 1, 1) self.layout.addWidget(self.descriptionTextEdit, 5, 1, 1, 3)
def __init__(self, table_p, parent, scoop=None, member=None, *args, **kwargs): FWidget.__init__(self, parent, *args, **kwargs) self.table_p = table_p self.member = member self.scoop = scoop self.parent = parent full_name = "" self.ddn_field = FormatDate(QDate(QDate.currentDate())) addres = "" nationality = "" phone = "" if self.member: self.new = False full_name = self.member.full_name mddn = self.member.ddn if mddn: day, month, year = mddn.split("/") ddn = datetime.strptime(mddn, '%d/%m/%Y') self.ddn_field.setDate(QDate(ddn)) addres = self.member.addres nationality = self.member.nationality phone = str(self.member.phone or "") self.title = u"Modification de {}".format(self.member) self.succes_msg = u"{} a été bien mise à jour".format(self.member) else: self.new = True self.succes_msg = u"Client a été bien enregistré" self.title = u"Ajout nouveau membre" self.member = CooperativeMember() self.setWindowTitle(self.title) vbox = QVBoxLayout() # vbox.addWidget(FPageTitle(u"Utilisateur: %s " % self.member.name)) self.full_name_field = LineEdit(full_name) self.sex_list = CooperativeMember.SEX.items() # Combobox widget self.sex_box = QComboBox() for index, value in enumerate(self.sex_list): # form = self.sex_list[index] self.sex_box.addItem("{}".format(value[1].upper()), value[0]) if self.member.sex == value[0]: self.sex_box.setCurrentIndex(index) # print("DE", ddn) # self.ddn_field.setDate(ddn) # self.ddn_field = QDateEdit(QDate(ddn)) self.addres_field = QTextEdit(addres) self.nationality_field = LineEdit(nationality) self.phone_field = IntLineEdit(phone) self.phone_field.setInputMask("## ## ## ##") self.poste_list = get_postes() self.poste_box = QComboBox() for index, value in enumerate(self.poste_list): self.poste_box.addItem( "{}".format(self.poste_list.get(value).upper()), value) if self.member.poste == value: print(value) self.poste_box.setCurrentIndex(index) formbox = QFormLayout() formbox.addRow(FormLabel(u"Nom complet : *"), self.full_name_field) formbox.addRow(FormLabel(u"Sexe *:"), self.sex_box) formbox.addRow(FormLabel(u"Date de naissance *:"), self.ddn_field) formbox.addRow(FormLabel(u"Poste occupé *:"), self.poste_box) formbox.addRow(FormLabel(u"Nationalité *:"), self.nationality_field) formbox.addRow(FormLabel(u"Téléphone :"), self.phone_field) formbox.addRow(FormLabel(u"Adresse :"), self.addres_field) butt = Button(u"Enregistrer") butt.clicked.connect(self.save_edit) formbox.addRow("", butt) vbox.addLayout(formbox) self.setLayout(vbox)
def details(regdent, trtdent, startdate, enddate, filters=""): ''' returns an html table, for regdent, trtdent,startdate,enddate ''' dent_conditions = "" dents = [] try: if regdent != "*ALL*": dent_conditions = 'dntid=%s and ' dents.append(localsettings.ops_reverse[regdent]) if trtdent != "*ALL*": dent_conditions += 'trtid=%s and ' dents.append(localsettings.ops_reverse[trtdent]) except KeyError: print "Key Error - %s or %s unregconised" % (regdent, trtdent) return '<html><body>%s</body></html>' % _( "Error - unrecognised practioner- sorry") total, nettotal = 0, 0 iterDate = QDate(startdate.year(), startdate.month(), 1) retarg = ''' <html><body><h4>%s %s %s %s %s %s %s %s %s</h4>''' % ( _("Patients of"), regdent, _("treated by"), trtdent, _("between"), localsettings.formatDate(startdate.toPyDate()), _("and"), localsettings.formatDate(enddate.toPyDate()), filters) retarg += '''<table width="100%" border="1"><tr><th>DATE</th> <th>Dents</th><th>Serial Number</th><th>Name</th> <th>Pt Type</th><th>Treatment</th><th></th> <th>Gross Fee</th><th>Net Fee</th>''' db = connect.connect() cursor = db.cursor() query = DETAILS_QUERY.replace("{{DENT CONDITIONS}}", dent_conditions) query = query.replace("{{FILTERS}}", filters) while enddate >= iterDate: monthtotal, monthnettotal = 0, 0 if startdate > iterDate: queryStartDate = startdate else: queryStartDate = iterDate queryEndDate = iterDate.addMonths(1).addDays(-1) if enddate < queryEndDate: queryEndDate = enddate values = tuple( dents + [queryStartDate.toPyDate(), queryEndDate.toPyDate()]) cursor.execute(query, (values)) rows = cursor.fetchall() for i, row in enumerate(rows): retarg += '<tr>' if i % 2 else '<tr bgcolor="#eeeeee">' retarg += "<td>%s</td>" % row[0] try: retarg += '<td> %s / ' % localsettings.ops[row[4]] except KeyError: retarg += "<td>?? / " try: retarg += localsettings.ops[row[5]] except KeyError: retarg += "??" retarg += '</td><td>%s</td><td>%s</td><td>%s</td>' % (row[1:4]) tx = "" for item in (6, 7, 8, 9, 10, 11, 12, 13, 14, 15): if row[item] is not None and row[item] != "": tx += "%s " % row[item] if ALLOW_TX_EDITS: extra_link = ' / <a href="daybook_id_edit?%s">%s</a>' % ( row[19], _("Edit Tx")) else: extra_link = "" retarg += '''<td>%s</td> <td><a href="daybook_id?%sfeesa=%sfeesb=%s">%s</a>%s</td> <td align="right">%s</td> <td align="right">%s</td></tr>''' % (tx.strip("%s " % chr(0)), row[19], row[16], row[17], _("Ests"), extra_link, localsettings.formatMoney( row[16]), localsettings.formatMoney(row[17])) total += int(row[16]) monthtotal += int(row[16]) nettotal += int(row[17]) monthnettotal += int(row[17]) retarg += '''<tr><td colspan="6"></td><td><b>SUBTOTAL - %s %s</b></td> <td align="right"><b>%s</b></td> <td align="right"><b>%s</b></td></tr>''' % ( localsettings.monthName(iterDate.toPyDate()), iterDate.year(), localsettings.formatMoney(monthtotal), localsettings.formatMoney(monthnettotal)) iterDate = iterDate.addMonths(1) cursor.close() # db.close() retarg += '''<tr><td colspan="6"></td><td><b>GRAND TOTAL</b></td> <td align="right"><b>%s</b></td> <td align="right"><b>%s</b></td></tr></table></body></html>''' % ( localsettings.formatMoney(total), localsettings.formatMoney(nettotal)) return retarg
_("You can filter using the following fields.") ) for i, field in enumerate(self.field_names): if i == 0: html += "<tr>" elif i % 5 == 0: html += "</tr><tr>" html += "<td>%s</td>" % field html += "</tr></table><h5>%s</h5><pre>%s</pre></body></html>" % ( _("Examples"), 'patients.serialno=1 AND chart REGEXP ".*MOD,CO.*"\n' 'ndu="SR/F"\nexmpt="M"\n') return html _filter_help = FilterHelp() def filter_help_text(): return _filter_help.help_text() if __name__ == "__main__": localsettings.initiate() for combo in (("*ALL*", "NW"), ("NW", "AH"), ("NW", "NW")): r = details(combo[0], combo[1], QDate( 2008, 10, 31), QDate(2008, 11, 11)) print r.encode("ascii", "replace") print filter_help_text()
def qDateFromSeconds(self, seconds): t = time.localtime(seconds) return QDate(*t[0:3])
def __init__(self, template, parent=None): """ \todo Eigentlich benötigt Subpower keinen eigenen Datentyp. Da die ganzen Zusatzinformationen ja nur im Template zu stehen haben und nicht auch für den Charakter bekannt sein müssen. Der Wert "level" ist aber interessant und gilt für andere Klassen nicht. """ super(StorageCharacter, self).__init__(parent) self.__storage = template self.isLoading = False self.__modified = False self.__dateBirth = QDate(1, 1, 1) self.__dateBecoming = QDate(1, 1, 1) self.__dateGame = QDate(1, 1, 1) self.__age = 0 self.__ageBecoming = 0 self.__species = "" self.__virtue = "" self.__vice = "" self.__breed = "" self.__bonus = {} self.__kith = "" self.__faction = "" self.__organisation = "" self.__party = "" self.__height = 0.0 self.__weight = 0.0 self.__eyes = "" self.__hair = "" self.__nationality = "" self.__description = "" self.__powerstat = 0 self.__morality = 0 self.__era = "" self.__picture = None self.__armor = { "name": "", "dedicated": False, } self.__equipment = [] self.__magicalTool = "" self.identity = Identity() self.__derangements = {} self.__nimbus = "" self.__paradoxMarks = "" self.__vinculi = [] for i in range(Config.VINCULI_COUNT_MAX): vinculum = AbstractTrait() self.__vinculi.append(vinculum) vinculum.traitChanged.connect(self.setModified) self.__companionName = "" self.__companionPower = 0 self.__companionFinesse = 0 self.__companionResistance = 0 self.__companionSize = 0 self.__companionSpeedFactor = 0 self.__companionFuel = 0 self.__companionInfluences = [] for i in range(Config.COMPANION_INFLUENCES_MAX): companionInfluence = AbstractTrait() self.__companionInfluences.append(companionInfluence) companionInfluence.traitChanged.connect(self.setModified) self.__companionNumina = [] self.__companionBan = "" self.dateBirthChanged.connect(self.__calcAge) self.dateGameChanged.connect(self.__calcAge) self.dateBirthChanged.connect(self.__calcAgeBecoming) self.dateBecomingChanged.connect(self.__calcAgeBecoming) self.weaponAdded.connect(self.weaponsChanged) self.weaponRemoved.connect(self.weaponsChanged) self.equipmentAdded.connect(self.automobilesChanged) self.equipmentRemoved.connect(self.equipmentChanged) self.automobileAdded.connect(self.automobilesChanged) self.automobileRemoved.connect(self.automobilesChanged) self.extraordinaryItemAdded.connect(self.extraordinaryItemsChanged) self.extraordinaryItemRemoved.connect(self.extraordinaryItemsChanged) # Die Eigenschaften in den Charakter laden. self.__traits = {} # Eigenschaften setzen. for typ in self.__storage.traits.keys(): self.__traits.setdefault(typ, {}) for item in template.traits[typ]: self.__traits[typ].setdefault(item, {}) for subitem in template.traits[typ][item].items(): #Debug.debug(subitem) val = 2 # Dies mache ich, damit beim initialen Charakter-Reset, auch alle Voraussetzungen überprüft werden. # Eigenschaften, die Zusaztext erhalten können (bspw. Language), werden mehrfach in das Dictionary eingefügt. Aber da ein Dictonary immer nur einen Eintrag desselben Namens haben kann, muß selbiger um ein numerisches Suffix erweitert werden. loop = 1 custom = False customText = None if typ != "Subpower" and subitem[1]["custom"]: loop = Config.MULTIPLE_TRAITS_MAX custom = True for i in range(loop): trait = None if typ == "Subpower": trait = SubPowerTrait(self, subitem[1]["name"], val) trait.level = subitem[1]["level"] trait.powers = subitem[1]["powers"] else: if typ == "Attribute" or typ == "Skill": trait = BonusTrait(self, subitem[1]["name"], val) else: trait = StandardTrait(self, subitem[1]["name"], val) trait.age = subitem[1]["age"] trait.era = subitem[1]["era"] trait.custom = custom trait.customText = customText trait.identifier = subitem[0] trait.species = subitem[1]["species"] trait.cheap = subitem[1]["cheap"] #if typ == "Subpower" and trait.species == "Werewolf": #Debug.debug(subitem[1]["name"], subitem[1]["only"]) trait.only = subitem[1]["only"] if "prerequisites" in subitem[1] and subitem[1][ "prerequisites"]: trait.hasPrerequisites = True trait.prerequisitesText = subitem[1][ "prerequisites"] # In der Eigenschaft steht der richtige Name aber im Dictionary der Name mit einem numerischen Suffix, damit die Eigenschaft häufiger auftauchen kann. dictKey = subitem[0] if custom: dictKey = "{}{}".format(subitem[0], i) self.__traits[typ][item].setdefault(dictKey, trait) # Wenn sich eine Eigenschaft ändert, gilt der Charakter als modifiziert. trait.traitChanged.connect(self.setModified) #if typ == "Subpower": #Debug.debug(self.__traits[typ][item]) self.bonusChanged.connect(self.__changeBonusTrait) # Sobald irgendein Aspekt des Charakters verändert wird, muß festgelegt werden, daß sich der Charkater seit dem letzten Speichern verändert hat. # Es ist Aufgabe der Speicher-Funktion, dafür zu sorgen, daß beim Speichern diese Inforamtion wieder zurückgesetzt wird. self.identity.identityChanged.connect(self.setModified) self.eraChanged.connect(self.setModified) self.dateBirthChanged.connect(self.setModified) self.dateBecomingChanged.connect(self.setModified) self.dateGameChanged.connect(self.setModified) # Unerwünschte Wirkung #self.speciesChanged.connect(self.clearUnusableTraits) self.speciesChanged.connect(self.setModified) self.virtueChanged.connect(self.setModified) self.viceChanged.connect(self.setModified) self.breedChanged.connect(self.setModified) self.kithChanged.connect(self.setModified) self.bonusChanged.connect(self.setModified) self.factionChanged.connect(self.setModified) self.partyChanged.connect(self.setModified) self.descriptionChanged.connect(self.setModified) self.powerstatChanged.connect(self.setModified) self.moralityChanged.connect(self.setModified) self.derangementChanged.connect(self.setModified) self.pictureChanged.connect(self.setModified) self.weaponsChanged.connect(self.setModified) self.armorChanged.connect(self.setModified) self.equipmentChanged.connect(self.setModified) self.automobilesChanged.connect(self.setModified) self.extraordinaryItemsChanged.connect(self.setModified) self.magicalToolChanged.connect(self.setModified) self.nimbusChanged.connect(self.setModified) self.paradoxMarksChanged.connect(self.setModified) self.companionPowerChanged.connect(self.setModified) self.companionFinesseChanged.connect(self.setModified) self.companionResistanceChanged.connect(self.setModified) self.companionSizeChanged.connect(self.setModified) self.companionSpeedFactorChanged.connect(self.setModified) self.companionFuelChanged.connect(self.setModified) self.companionNuminaChanged.connect(self.setModified) self.companionBanChanged.connect(self.setModified) self.ageChanged.connect(self.deselctTraitsWithWrongAge) self.speciesChanged.connect(self.__emitTraitVisibleReasonChanged) self.ageChanged.connect(self.__emitTraitVisibleReasonChanged) self.eraChanged.connect(self.__emitTraitVisibleReasonChanged) self.breedChanged.connect(self.__emitTraitVisibleReasonChanged) self.factionChanged.connect(self.__emitTraitVisibleReasonChanged)
def resetCharacter(self): ## Der Charkater wird umorganisiert, ohne daß wir haufenweise Warnhinweise haben wollen. self.isLoading = True # Standardspezies ist der Mensch. self.species = Config.SPECIES_INITIAL # Zeitalter festlegen. self.era = Config.ERA_INITIAL ## Anfangsdatum setzen. self.dateGame = QDate.currentDate() self.dateBirth = QDate(self.dateGame.year() - Config.AGE_INITIAL, self.dateGame.month(), self.dateGame.day()) self.dateBecoming = QDate(self.dateGame.year() - Config.AGE_ADULT, self.dateGame.month(), self.dateGame.day()) # Löschen aller Identitäten. self.identity.reset() #Debug.debug(self.__storage.virtues[0]) #Debug.debug(self.__storage.virtues[0]["name"]) self.virtue = self.__storage.virtues[0]["name"] self.vice = self.__storage.vices[0]["name"] self.breed = "" self.bonus = "" self.kith = "" self.faction = "" self.height = 1.60 self.weight = 60 self.eyes = "" self.hair = "" self.nationality = "" # Nicht notwendig, da ja schon die Spezies gewechselt wird, was automatisch diese Felder zurücksetzt. #self.breed = self.__storage.breeds(Config.SPECIES_INITIAL)[0] self.__derangements = {} self.party = "" self.description = "" # Menschen haben eine Leere liste, also kann ich auch die Indizes nicht ändern. #// setBreed(storage.breedNames(species()).at(0)); #// setFaction(storage.breedNames(species()).at(0)); # Attribute und andere Eigenschaften auf Anfangswerte setzen. for item in self.__traits: val = 0 if item == "Attribute": val = 1 for subitem in self.__traits[item]: for subsubitem in self.__traits[item][subitem].values(): subsubitem.value = val subsubitem.customText = "" subsubitem.specialties = [] self.morality = Config.TRAIT_MORALITY_VALUE_DEFAULT # Übernatürliche Eigenschaft festlegen. self.powerstat = Config.TRAIT_POWERSTAT_VALUE_DEFAULT # Beim Löschen ist darauf zu achten, daß ich nicht aus der Liste löschen kann, über die ich iteriere. Sonst wird nicht alles gelöscht. for category in self.__weapons: ## Kopie erstellen weaponList = self.__weapons[category][:] for weapon in weaponList: self.deleteWeapon(category, weapon) self.setArmor(name="") ## Kopie erstellen eqipmentList = self.__equipment[:] for item in eqipmentList: self.deleteEquipment(item) for category in self.__automobiles: ## Kopie erstellen automobileList = self.__automobiles[category][:] for automobile in automobileList: self.deleteAutomobile(category, automobile) for typ in self.__extraordinaryItems: ## Kopie erstellen extraordinaryItemList = self.__extraordinaryItems[typ][:] for item in extraordinaryItemList: self.deleteExtraordinaryItem(typ, item) self.magicalTool = "" self.nimbus = "" self.paradoxMarks = "" for vinculum in self.__vinculi: vinculum.name = "" vinculum.value = 0 self.companionName = "" self.companionPower = 0 self.companionFinesse = 0 self.companionResistance = 0 self.companionSize = 0 self.companionSpeedFactor = 0 self.companionFuel = 0 for companionInfluence in self.__companionInfluences: companionInfluence.name = "" companionInfluence.value = 0 self.companionNumina = [] self.companionBan = "" self.picture = QPixmap() ## Fertig mit dem Laden der enuen Werte. self.isLoading = False
def __init__(self, template, character, parent=None): super(TemplateWidget, self).__init__(parent) self.ui = Ui_TemplateWidget() self.ui.setupUi(self) self.__storage = template self.__character = character speciesList = [ species[0] for species in self.__storage.species.items() if species[1]["playable"] ] speciesList.sort() #self.ui.comboBox_species.addItems(speciesList) for species in speciesList: self.ui.comboBox_species.addItem( QIcon(":/icons/images/species/{}/Skull.png".format(species)), species) self.ui.dateEdit_dateBecoming.setMinimumDate(QDate(100, 1, 1)) ## Speichern der vom Benutzer veränderten Werte self.ui.dateEdit_dateBecoming.dateChanged.connect( self.__character.setDateBecoming) self.ui.comboBox_species.currentIndexChanged[str].connect( self.__character.setSpecies) self.ui.comboBox_breed.currentIndexChanged[str].connect( self.__character.setBreed) self.ui.comboBox_bonus.currentIndexChanged[str].connect( self.setCharacterBonus) self.ui.comboBox_kith.currentIndexChanged[str].connect( self.__character.setKith) self.ui.comboBox_faction.currentIndexChanged[str].connect( self.__character.setFaction) self.ui.lineEdit_faction.textEdited.connect( self.__character.setFaction) self.ui.comboBox_organisation.currentIndexChanged[str].connect( self.__character.setOrganisation) self.ui.lineEdit_party.textEdited.connect(self.__character.setParty) ## Aktualisieren der Darstellung der im Charakter veränderten Werte. self.__character.dateBecomingChanged.connect( self.ui.dateEdit_dateBecoming.setDate) self.__character.ageBecomingChanged.connect( self.ui.label_ageBecoming.setNum) self.__character.speciesChanged.connect(self.updateSpecies) self.__character.breedChanged.connect(self.updateBreed) self.__character.breedChanged.connect(self.repopulateBonus) self.__character.breedChanged.connect(self.repopulateKiths) self.__character.bonusChanged.connect(self.updateBonus) self.__character.kithChanged.connect(self.updateKith) self.__character.speciesChanged.connect(self.updateBreedTitle) self.__character.speciesChanged.connect(self.repopulateBreeds) self.__character.factionChanged.connect(self.updateFaction) self.__character.speciesChanged.connect(self.updateFactionTitle) self.__character.speciesChanged.connect(self.repopulateFactions) self.__character.organisationChanged.connect(self.updateOrganisation) self.__character.speciesChanged.connect(self.updateOrganisationTitle) self.__character.speciesChanged.connect(self.repopulateOrganisations) self.__character.partyChanged.connect(self.ui.lineEdit_party.setText) self.__character.speciesChanged.connect(self.updatePartyTitle) # Menschen können ihre Fraktion selbst eintragen und haben einige Angaben einfach nicht nötig. self.__character.speciesChanged.connect(self.hideShowWidgets_species) ## Das Alter darf nie negativ werden können self.__character.dateBirthChanged.connect( self.ui.dateEdit_dateBecoming.setMinimumDate) self.__character.dateGameChanged.connect( self.ui.dateEdit_dateBecoming.setMaximumDate)
import time_util import bcdate_util import conf import layer_settings """ The QTSlider only supports integers as the min and max, therefore the maximum maximum value is whatever can be stored in an int. Making it a signed int to be sure. (http://qt-project.org/doc/qt-4.8/qabstractslider.html) """ MAX_TIME_LENGTH_SECONDS_SLIDER = 2 ** 31 - 1 """ according to the docs of QDateTime, the minimum date supported is the first day of year 100 (http://qt-project.org/doc/qt-4.8/qdatetimeedit.html#minimumDate-prop) """ MIN_QDATE = QDate(100, 1, 1) DOCK_WIDGET_FILE = "dockwidget2.ui" ADD_VECTOR_LAYER_WIDGET_FILE = "addLayer.ui" ADD_RASTER_LAYER_WIDGET_FILE = "addRasterLayer.ui" ARCH_WIDGET_FILE = "arch.ui" OPTIONS_WIDGET_FILE = "options.ui" ANIMATION_WIDGET_FILE = "animate.ui" class TimestampLabelConfig(object): """Object that has the settings for rendering timestamp labels. Can be customized via the UI""" PLACEMENTS = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'] DEFAULT_FONT_SIZE = 25 font = "Arial" # Font names or family, comma-separated CSS style size = DEFAULT_FONT_SIZE # Relative values between 1-7
def dateFromJSON(strDate): pyDate = datetime.datetime.strptime( strDate, "%Y-%m-%d").date() if strDate else None return QDate(pyDate.year, pyDate.month, pyDate.day) if pyDate else QDate()
def __init__(self, session, parent=None): super(ExpensesDialog, self).__init__(parent) self.session = session session = self.pullOnes('session', session) self.sessionname = str(session['name']) + ' Session' self.pagetitle = self.sessionname self.tableFont = QFont('Century Gothic', 8) #self.tableFont.setFamily('Century Gothic') self.tableHeaderStyle = "::section {" "background-color: teal; color:white}" #pull all CA self.editID = 0 self.hold_account = {} self.hold_expenses = {} self.hold_expensesGroup = {} from_label = QLabel('From:') to_label = QLabel('To:') self.fromData = QDateEdit() self.toData = QDateEdit() currentDate = QDate() self.fromData.setDate(currentDate.currentDate()) self.fromData.setCalendarPopup(True) self.toData.setDate(currentDate.currentDate()) self.toData.setCalendarPopup(True) self.pull_btn = QPushButton() self.pull_btn.setText("Load") h_pull_box = QHBoxLayout() h_pull_box.addWidget(from_label) h_pull_box.addWidget(self.fromData) h_pull_box.addWidget(to_label) h_pull_box.addWidget(self.toData) h_pull_box.addWidget(self.pull_btn) expensesGroup = self.pullGroupExpenses() account = self.pullAccount() self.expenseGroupText = QLabel('Category') self.expenseGroupData = QComboBox() self.expenseGroupData.currentIndexChanged.connect(self.reloadExpenses) self.expenseText = QLabel('Expenses') self.expenseData = QComboBox() self.amountText = QLabel('Amount') self.amountData = QLineEdit() self.amountData.setPlaceholderText('0000.00') self.tellerText = QLabel('Teller/Reciept No.') self.tellerData = QLineEdit() self.tellerData.setPlaceholderText('xxxxxxxxx') self.accountText = QLabel('Account') self.accountData = QComboBox() self.dateText = QLabel('Date') self.dateData = QDateEdit() self.dateData.setDate(currentDate.currentDate()) self.dateData.setCalendarPopup(True) self.descriptionText = QLabel('Brief Description') self.descriptionData = QPlainTextEdit() self.descriptionData.move(200, 100) hboz = QHBoxLayout() self.gender = QLabel('State') self.r1 = QRadioButton('Expenses') self.r1.setChecked(True) self.r2 = QRadioButton('Refund') hboz.addWidget(self.r1) hboz.addWidget(self.r2) i = 0 for a in expensesGroup: self.hold_expensesGroup[i] = a['id'] tex = str(a['name']).upper() self.expenseGroupData.addItem(tex) i += 1 i = 0 exp_key = self.hold_expensesGroup[self.expenseGroupData.currentIndex()] expenses = self.pullExpenses(exp_key) for a in expenses: self.hold_expenses[i] = a['id'] tex = str(a['name']).upper() self.expenseData.addItem(tex) i += 1 i = 0 for a in account: self.hold_account[i] = a['id'] tex = str(a['name']).upper() self.accountData.addItem(tex) i += 1 self.FormLayout = QFormLayout() self.FormLayout.addRow(self.expenseGroupText, self.expenseGroupData) self.FormLayout.addRow(self.expenseText, self.expenseData) self.FormLayout.addRow(self.accountText, self.accountData) self.FormLayout.addRow(self.tellerText, self.tellerData) self.FormLayout.addRow(self.amountText, self.amountData) self.FormLayout.addRow(self.gender, hboz) self.FormLayout.addRow(self.dateText, self.dateData) self.FormLayout.addRow(self.descriptionText, self.descriptionData) groupBox1 = QGroupBox('Add Expenses') groupBox1.setLayout(self.FormLayout) self.pb = QPushButton() self.pb.setObjectName("Add") self.pb.setText("Add Expenses") self.pb1 = QPushButton() self.pb1.setObjectName("Edit") self.pb1.setText("Edit Row") self.pb1.setEnabled(False) self.pb2 = QPushButton() self.pb2.setObjectName("Close") self.pb2.setText("Close") self.pb3 = QPushButton() self.pb3.setObjectName("Delete") self.pb3.setText("Delete Row") self.pb3.setEnabled(False) self.pb4 = QPushButton() self.pb4.setObjectName("Reset") self.pb4.setText("Reset") self.pb4.hide() self.pb5 = QPushButton() self.pb5.setObjectName("Change") self.pb5.setText("Change Expenses") self.pb5.hide() self.pb6 = QPushButton() self.pb6.setObjectName("Clear") self.pb6.setText("Clear Selection") self.pb6.setEnabled(False) hbo = QHBoxLayout() hbo.addWidget(self.pb) hbo.addWidget(self.pb5) hbo.addWidget(self.pb4) hbo.addWidget(self.pb2) groupBox2 = QGroupBox('Expenses Data') groupBox2.setLayout(hbo) self.cols = ['SN', 'EXPENSES', 'ACCOUNT', 'AMOUNT', 'DATE'] al = self.pullExpensesData() if len(al) > 0: al = al else: al = {} self.table = QTableWidget() header = self.table.horizontalHeader() header.setResizeMode(QHeaderView.ResizeToContents) header.setStretchLastSection(True) header.setStyleSheet(self.tableHeaderStyle) vheader = self.table.verticalHeader() vheader.setStyleSheet(self.tableHeaderStyle) # Body self.table.setWindowTitle("Expenses") self.table.resize(300, 250) self.table.setFont(self.tableFont) self.table.setSortingEnabled(2) #self.table.resizeColumnsToContents() self.table.setRowCount(len(al)) self.table.setColumnCount(len(self.cols)) self.table.setHorizontalHeaderLabels(self.cols) self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.table.customContextMenuRequested.connect(self.handleHeaderMenu) self.table.hideColumn(0) self.table.setSelectionMode(QAbstractItemView.MultiSelection) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) i = 0 for q in al: #row id self.table.setItem(i, 0, QTableWidgetItem(str(q['id']))) self.table.setItem(i, 1, QTableWidgetItem(str(q['expensename']).upper())) self.table.setItem(i, 2, QTableWidgetItem(str(q['accountname']).upper())) zamt = str("{:,}".format(float(q['amount']))) self.table.setItem(i, 3, QTableWidgetItem(zamt)) damz = float(q['datepaid']) damt = datetime.utcfromtimestamp(damz).strftime('%d-%m-%Y') self.table.setItem(i, 4, QTableWidgetItem(str(damt))) i += 1 self.table.itemSelectionChanged.connect(self.confirmSelection) self.table.resizeRowsToContents() v_pull_box = QVBoxLayout() self.h1_pull_box = QVBoxLayout() self.h1_pull_box.addWidget(self.table) v_pull_box.addLayout(h_pull_box) v_pull_box.addLayout(self.h1_pull_box) h2_pull_box = QHBoxLayout() h2_pull_box.addWidget(self.pb1) h2_pull_box.addWidget(self.pb3) h2_pull_box.addWidget(self.pb6) v_pull_box.addLayout(h2_pull_box) groupBox3 = QGroupBox() groupBox3.setLayout(hbo) groupBox2.setLayout(v_pull_box) grid = QGridLayout() grid.addWidget(groupBox1, 0, 0) grid.addWidget(groupBox2, 0, 1, 2, 1) grid.addWidget(groupBox3, 1, 0) self.setLayout(grid) self.connect(self.pb, SIGNAL("clicked()"), lambda: self.button_click()) self.connect(self.pb1, SIGNAL("clicked()"), lambda: self.button_editshow()) self.connect(self.pb2, SIGNAL("clicked()"), lambda: self.button_close(self)) self.connect(self.pb3, SIGNAL("clicked()"), lambda: self.button_delete()) self.connect(self.pb4, SIGNAL("clicked()"), lambda: self.button_reset()) self.connect(self.pb5, SIGNAL("clicked()"), lambda: self.button_edit()) self.connect(self.pb6, SIGNAL("clicked()"), lambda: self.button_clear()) self.connect(self.pull_btn, SIGNAL("clicked()"), lambda x=1: self.reloadTable(x)) self.setWindowTitle(self.pagetitle)
def __init__(self, table_p, report, parent, *args, **kwargs): QDialog.__init__(self, parent, *args, **kwargs) self.setWindowTitle(u"Modification") self.table_p = table_p self.rpt = report self.parent = parent self.out_op = True if self.rpt.type_ == Report.E: self.out_op = False self.selling_price_field = IntLineEdit(unicode(self.rpt.selling_price)) self.cost_buying_field = IntLineEdit(unicode(self.rpt.cost_buying)) self.qty_field = IntLineEdit(unicode(self.rpt.qty)) self.date_field = FormatDate(QDate(self.rpt.date)) self.date_field.setEnabled(False) butt = Button(u"Mise à jour") butt.clicked.connect(self.edit_report) cancel_but = Button(u"Annuler") cancel_but.clicked.connect(self.cancel) # Combobox widget i = 0 self.liste_type = [Report.E, Report.S] self.box_type = QComboBox() self.box_type.setEnabled(False) for index in xrange(0, len(self.liste_type)): ty = self.liste_type[index] if ty == self.rpt.type_: i = index sentence = u"%(ty)s" % {'ty': ty} self.box_type.addItem(sentence, ty) self.box_type.setCurrentIndex(i) # Combobox widget # self.liste_store = Store.order_by(desc(Store.id)).all() # self.box_mag = QComboBox() # for index in xrange(0, len(self.liste_store)): # op = self.liste_store[index] # sentence = u"%(name)s" % {'name': op.name} # self.box_mag.addItem(sentence, QVariant(op.id)) # Combobox widget self.liste_product = Product.all() self.box_prod_field = QComboBox() self.box_prod_field.setEnabled(False) for index in xrange(0, len(self.liste_product)): prod = self.liste_product[index] if prod.name == self.rpt.product.name: i = index sentence = u"%(name)s" % {'name': prod.name} self.box_prod_field.addItem(sentence, prod.id) self.box_prod_field.setCurrentIndex(i) vbox = QVBoxLayout() formbox = QFormLayout() # editbox.addWidget(FormLabel((_(u"Store"))), 0, 1) # editbox.addWidget(self.box_mag, 1, 1) formbox.addRow(FormLabel(u"Type"), FormLabel(self.rpt.type_)) formbox.addRow(FormLabel(u"Désignation"), self.box_prod_field) formbox.addRow(FormLabel(u"Quantité"), self.qty_field) formbox.addRow(FormLabel("Prix d'achat"), self.cost_buying_field) formbox.addRow(FormLabel("Prix vente"), self.selling_price_field) formbox.addRow(FormLabel(u"Date"), self.date_field) formbox.addRow(butt, cancel_but) vbox.addLayout(formbox) self.setLayout(vbox)
def populateBirth(self): for noi, vals in self.scenario.indiv.iteritems(): birth = QDate(vals['birth']) self._listPerson[noi][S.birth].setDate(birth)
def processAlgorithm(self, progress): inLayer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) boundary = self.getParameterValue(self.MODE) == self.MODE_BOUNDARY smallestArea = self.getParameterValue( self.MODE) == self.MODE_SMALLEST_AREA keepSelection = self.getParameterValue(self.KEEPSELECTION) if not keepSelection: # Make a selection with the values provided attribute = self.getParameterValue(self.ATTRIBUTE) comparison = self.comparisons[self.getParameterValue( self.COMPARISON)] comparisonvalue = self.getParameterValue(self.COMPARISONVALUE) selectindex = inLayer.dataProvider().fieldNameIndex(attribute) selectType = inLayer.dataProvider().fields()[selectindex].type() selectionError = False if selectType == 2: try: y = int(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to integer' % unicode(comparisonvalue)) elif selectType == 6: try: y = float(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to float' % unicode(comparisonvalue)) elif selectType == 10: # 10: string, boolean try: y = unicode(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to unicode' % unicode(comparisonvalue)) elif selectType == 14: # date dateAndFormat = comparisonvalue.split(' ') if len(dateAndFormat) == 1: # QtCore.QDate object y = QLocale.system().toDate(dateAndFormat[0]) if y.isNull(): msg = self.tr( 'Cannot convert "%s" to date with system date format %s' % (unicode(dateAndFormat), QLocale.system().dateFormat())) elif len(dateAndFormat) == 2: y = QDate.fromString(dateAndFormat[0], dateAndFormat[1]) if y.isNull(): msg = self.tr( 'Cannot convert "%s" to date with format string "%s"' % (unicode(dateAndFormat[0]), dateAndFormat[1])) else: y = QDate() msg = '' if y.isNull(): # Conversion was unsuccessfull selectionError = True msg += self.tr( 'Enter the date and the date format, e.g. "07.26.2011" "MM.dd.yyyy".' ) if (comparison == 'begins with' or comparison == 'contains') \ and selectType != 10: selectionError = True msg = self.tr('"%s" can only be used with string fields' % comparison) selected = [] if selectionError: raise GeoAlgorithmExecutionException( self.tr('Error in selection input: %s' % msg)) else: for feature in inLayer.getFeatures(): aValue = feature.attributes()[selectindex] if aValue is None: continue if selectType == 2: x = int(aValue) elif selectType == 6: x = float(aValue) elif selectType == 10: # 10: string, boolean x = unicode(aValue) elif selectType == 14: # date x = aValue # should be date match = False if comparison == '==': match = x == y elif comparison == '!=': match = x != y elif comparison == '>': match = x > y elif comparison == '>=': match = x >= y elif comparison == '<': match = x < y elif comparison == '<=': match = x <= y elif comparison == 'begins with': match = x.startswith(y) elif comparison == 'contains': match = x.find(y) >= 0 if match: selected.append(feature.id()) inLayer.setSelectedFeatures(selected) if inLayer.selectedFeatureCount() == 0: ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, self.tr('%s: (No selection in input layer "%s")' % (self.commandLineName(), self.getParameterValue(self.INPUT)))) # Keep references to the features to eliminate featToEliminate = [] for aFeat in inLayer.selectedFeatures(): featToEliminate.append(aFeat) # Delete all features to eliminate in inLayer (we won't save this) inLayer.startEditing() inLayer.deleteSelectedFeatures() # ANALYZE if len(featToEliminate) > 0: # Prevent zero division start = 20.00 add = 80.00 / len(featToEliminate) else: start = 100 progress.setPercentage(start) madeProgress = True # We go through the list and see if we find any polygons we can # merge the selected with. If we have no success with some we # merge and then restart the whole story. while madeProgress: # Check if we made any progress madeProgress = False featNotEliminated = [] # Iterate over the polygons to eliminate for i in range(len(featToEliminate)): feat = featToEliminate.pop() geom2Eliminate = feat.geometry() bbox = geom2Eliminate.boundingBox() fit = inLayer.getFeatures( QgsFeatureRequest().setFilterRect(bbox)) mergeWithFid = None mergeWithGeom = None max = 0 min = -1 selFeat = QgsFeature() while fit.nextFeature(selFeat): selGeom = selFeat.geometry() if geom2Eliminate.intersects(selGeom): # We have a candidate iGeom = geom2Eliminate.intersection(selGeom) if iGeom is None: continue if boundary: selValue = iGeom.length() else: # area. We need a common boundary in # order to merge if 0 < iGeom.length(): selValue = selGeom.area() else: selValue = -1 if -1 != selValue: useThis = True if smallestArea: if -1 == min: min = selValue else: if selValue < min: min = selValue else: useThis = False else: if selValue > max: max = selValue else: useThis = False if useThis: mergeWithFid = selFeat.id() mergeWithGeom = QgsGeometry(selGeom) # End while fit if mergeWithFid is not None: # A successful candidate newGeom = mergeWithGeom.combine(geom2Eliminate) if inLayer.changeGeometry(mergeWithFid, newGeom): madeProgress = True else: raise GeoAlgorithmExecutionException( self. tr('Could not replace geometry of feature with id %s' % mergeWithFid)) start = start + add progress.setPercentage(start) else: featNotEliminated.append(feat) # End for featToEliminate featToEliminate = featNotEliminated # End while # Create output provider = inLayer.dataProvider() output = self.getOutputFromName(self.OUTPUT) writer = output.getVectorWriter(provider.fields(), provider.geometryType(), inLayer.crs()) # Write all features that are left over to output layer iterator = inLayer.getFeatures() for feature in iterator: writer.addFeature(feature) # Leave inLayer untouched inLayer.rollBack() for feature in featNotEliminated: writer.addFeature(feature)
def run(self): """Run method that performs all the real work""" self.dlg.show() # show the dialog result = self.dlg.exec_() # Run the dialog event loop if result: # The user pressed OK, and this is what happened next! survex3dfile = self.dlg.selectedFile.text() gpkg_file = self.dlg.selectedGPKG.text() include_legs = self.dlg.Legs.isChecked() include_stations = self.dlg.Stations.isChecked() include_polygons = self.dlg.Polygons.isChecked() include_walls = self.dlg.Walls.isChecked() include_xsections = self.dlg.XSections.isChecked() include_traverses = self.dlg.Traverses.isChecked() exclude_surface_legs = not self.dlg.LegsSurface.isChecked() exclude_splay_legs = not self.dlg.LegsSplay.isChecked() exclude_duplicate_legs = not self.dlg.LegsDuplicate.isChecked() exclude_surface_stations = not self.dlg.StationsSurface.isChecked() use_clino_wgt = self.dlg.UseClinoWeights.isChecked() include_up_down = self.dlg.IncludeUpDown.isChecked() discard_features = not self.dlg.KeepFeatures.isChecked() get_crs_from_file = self.dlg.CRSFromFile.isChecked() get_crs_from_project = self.dlg.CRSFromProject.isChecked() if not os.path.exists(survex3dfile): raise Exception("File '%s' doesn't exist" % survex3dfile) if discard_features: self.leg_list = [] self.station_list = [] self.station_xyz = {} self.xsect_list = [] # Read .3d file as binary, parse, and save data structures with open(survex3dfile, 'rb') as fp: line = fp.readline().rstrip() # File ID check if not line.startswith(b'Survex 3D Image File'): raise IOError('Not a survex .3d file: ' + survex3dfile) line = fp.readline().rstrip() # File format version if not line.startswith(b'v'): raise IOError('Unrecognised survex .3d version in ' + survex3dfile) version = int(line[1:]) if version < 8: raise IOError('Survex .3d version >= 8 required in ' + survex3dfile) line = fp.readline().rstrip( ) # Metadata (title and coordinate system) fields = line.split(b'\x00') previous_title = '' if discard_features else self.title if previous_title: self.title = previous_title + ' + ' + fields[0] else: self.title = fields[0] # Try to work out EPSG number from second field if available. # The project_crs should end up as a lowercase string like 'epsg:27700' if get_crs_from_project: project_crs = self.iface.mapCanvas().mapRenderer( ).destinationCrs() self.extract_epsg(project_crs.authid().lower()) elif get_crs_from_file and len(fields) > 1: self.extract_epsg(fields[1]) else: self.epsg = None line = fp.readline().rstrip( ) # Timestamp, unused in present application if not line.startswith(b'@'): raise IOError('Unrecognised timestamp in ' + survex3dfile) # timestamp = int(line[1:]) flag = ord(fp.read(1)) # file-wide flag if flag & 0x80: # abort if extended elevation raise IOError("Can't deal with extended elevation in " + survex3dfile) # All front-end data read in, now read byte-wise # according to .3d spec. Note that all elements must # be processed, in order, otherwise we get out of sync. # We first define some baseline dates date0 = QDate(1900, 1, 1) date1 = QDate(1900, 1, 1) date2 = QDate(1900, 1, 1) label, style = '', 0xff # initialise label and style legs = [] # will be used to capture leg data between MOVEs xsect = [] # will be used to capture XSECT data nlehv = None # .. remains None if there isn't any error data... while True: # start of byte-gobbling while loop char = fp.read(1) if not char: # End of file (reached prematurely?) raise IOError('Premature end of file in ' + survex3dfile) byte = ord(char) if byte <= 0x05: # STYLE if byte == 0x00 and style == 0x00: # this signals end of data if legs: # there may be a pending list of legs to save self.leg_list.append((legs, nlehv)) break # escape from byte-gobbling while loop else: style = byte elif byte <= 0x0e: # Reserved continue elif byte == 0x0f: # MOVE xyz = self.read_xyz(fp) if legs: self.leg_list.append((legs, nlehv)) legs = [] elif byte == 0x10: # DATE (none) date1 = date2 = date0 elif byte == 0x11: # DATE (single date) days = unpack('<H', fp.read(2))[0] date1 = date2 = date0.addDays(days) elif byte == 0x12: # DATE (date range, short format) days, extra = unpack('<HB', fp.read(3)) date1 = date0.addDays(days) date2 = date0.addDays(days + extra + 1) elif byte == 0x13: # DATE (date range, long format) days1, days2 = unpack('<HH', fp.read(4)) date1 = date0.addDays(days1) date2 = date0.addDays(days2) elif byte <= 0x1e: # Reserved continue elif byte == 0x1f: # Error info nlehv = unpack('<iiiii', fp.read(20)) elif byte <= 0x2f: # Reserved continue elif byte <= 0x33: # XSECT label = self.read_label(fp, label) if byte & 0x02: lrud = unpack('<iiii', fp.read(16)) else: lrud = unpack('<hhhh', fp.read(8)) xsect.append((label, lrud)) if byte & 0x01: # XSECT_END self.xsect_list.append(xsect) xsect = [] elif byte <= 0x3f: # Reserved continue elif byte <= 0x7f: # LINE flag = byte & 0x3f if not (flag & 0x20): label = self.read_label(fp, label) xyz_prev = xyz xyz = self.read_xyz(fp) while (True): # code pattern to implement logic if exclude_surface_legs and flag & 0x01: break if exclude_duplicate_legs and flag & 0x02: break if exclude_splay_legs and flag & 0x04: break legs.append(((xyz_prev, xyz), label, style, date1, date2, flag)) break elif byte <= 0xff: # LABEL (or NODE) flag = byte & 0x7f label = self.read_label(fp, label) xyz = self.read_xyz(fp) while (True): # code pattern to implement logic if exclude_surface_stations and flag & 0x01 and not flag & 0x02: break self.station_list.append((xyz, label, flag)) break self.station_xyz[label] = xyz # End of byte-gobbling while loop # file closes automatically, with open(survex3dfile, 'rb') as fp: # Now create the layers in QGIS. Attributes are inserted # like pushing onto a stack, so in reverse order. Layers # are created only if required and data is available. # If nlehv is still None, then no error data has been provided. layers = [] # used to keep a list of the created layers if include_stations and self.station_list: # station layer station_layer = self.add_layer('stations', 'Point') attrs = [ QgsField(self.station_attr[k], QVariant.Int) for k in self.station_flags ] attrs.insert(0, QgsField('ELEVATION', QVariant.Double)) attrs.insert(0, QgsField('NAME', QVariant.String)) station_layer.dataProvider().addAttributes(attrs) station_layer.updateFields() features = [] for (xyz, label, flag) in self.station_list: xyz = [0.01 * v for v in xyz] attrs = [1 if flag & k else 0 for k in self.station_flags] attrs.insert(0, round(xyz[2], 2)) # elevation attrs.insert(0, label) feat = QgsFeature() geom = QgsGeometry(QgsPointV2(QgsWKBTypes.PointZ, *xyz)) feat.setGeometry(geom) feat.setAttributes(attrs) features.append(feat) station_layer.dataProvider().addFeatures(features) layers.append(station_layer) if include_legs and self.leg_list: # leg layer leg_layer = self.add_layer('legs', 'LineString') attrs = [ QgsField(self.leg_attr[k], QVariant.Int) for k in self.leg_flags ] if nlehv: [ attrs.insert(0, QgsField(s, QVariant.Double)) for s in self.error_fields ] attrs.insert(0, QgsField('NLEGS', QVariant.Int)) attrs.insert(0, QgsField('DATE2', QVariant.Date)) attrs.insert(0, QgsField('DATE1', QVariant.Date)) attrs.insert(0, QgsField('STYLE', QVariant.String)) attrs.insert(0, QgsField('ELEVATION', QVariant.Double)) attrs.insert(0, QgsField('NAME', QVariant.String)) leg_layer.dataProvider().addAttributes(attrs) leg_layer.updateFields() features = [] for legs, nlehv in self.leg_list: for (xyz_pair, label, style, from_date, to_date, flag) in legs: elev = 0.5 * sum([0.01 * xyz[2] for xyz in xyz_pair]) points = [] for xyz in xyz_pair: xyz = [0.01 * v for v in xyz] points.append(QgsPointV2(QgsWKBTypes.PointZ, *xyz)) attrs = [1 if flag & k else 0 for k in self.leg_flags] if nlehv: [ attrs.insert(0, 0.01 * v) for v in reversed(nlehv[1:5]) ] attrs.insert(0, nlehv[0]) attrs.insert(0, to_date) attrs.insert(0, from_date) attrs.insert(0, self.style_type[style]) attrs.insert(0, round(elev, 2)) attrs.insert(0, label) linestring = QgsLineStringV2() linestring.setPoints(points) feat = QgsFeature() geom = QgsGeometry(linestring) feat.setGeometry(geom) feat.setAttributes(attrs) features.append(feat) leg_layer.dataProvider().addFeatures(features) layers.append(leg_layer) # Now do wall features if asked if (include_traverses or include_xsections or include_walls or include_polygons) and self.xsect_list: trav_features = [] wall_features = [] xsect_features = [] quad_features = [] for xsect in self.xsect_list: if len(xsect) < 2: # if there's only one station .. continue # .. give up as we don't know which way to face centerline = [ ] # will contain the station position and LRUD data for label, lrud in xsect: xyz = self.station_xyz[ label] # look up coordinates from label lrud_or_zero = tuple([max(0, v) for v in lrud ]) # deal with missing data centerline.append( xyz + lrud_or_zero) # and collect as 7-uple direction = [ ] # will contain the corresponding direction vectors # The calculations below use integers for xyz and lrud, and # conversion to metres is left to the end. Then dh2 is an # integer and the test for a plumb is safely dh2 = 0. # The directions are unit vectors optionally weighted by # cos(inclination) = dh/dl where dh^2 = dx^2 + dy^2 + dz^2 # and dl^2 = dh^2 + dz^2. The normalisation is correspondingly # either 1/dh, or 1/dh * dh/dl = 1/dl. for i, xyzlrud in enumerate(centerline): x, y, z = xyzlrud[0:3] if i > 0: dx, dy, dz = x - xp, y - yp, z - zp dh2 = dx * dx + dy * dy # integer horizontal displacement (mm^2) norm = sqrt(dh2 + dz * dz) if use_clino_wgt else sqrt(dh2) dx, dy = (dx / norm, dy / norm) if dh2 > 0 and norm > 0 else (0, 0) direction.append((dx, dy)) xp, yp, zp = x, y, z left_wall = [] right_wall = [] up_down = [] # We build the walls by walking through the list # of stations and directions, with simple defaults # for the start and end stations for i, (x, y, z, l, r, u, d) in enumerate(centerline): d1x, d1y = direction[i - 1] if i > 0 else (0, 0) d2x, d2y = direction[i] if i + 1 < len( centerline) else (0, 0) dx, dy = d1x + d2x, d1y + d2y # mean (sum of) direction vectors norm = sqrt(dx * dx + dy * dy) # normalise to unit vector ex, ey = (dx / norm, dy / norm) if norm > 0 else (0, 0) # Convert to metres when saving the points left_wall.append((0.01 * (x - l * ey), 0.01 * (y + l * ex), 0.01 * z)) right_wall.append((0.01 * (x + r * ey), 0.01 * (y - r * ex), 0.01 * z)) up_down.append((0.01 * u, 0.01 * d)) # Mean elevation of centerline, used for elevation attribute elev = 0.01 * sum([xyzlrud[2] for xyzlrud in centerline ]) / len(centerline) attrs = [round(elev, 2)] # Now create the feature sets - first the centerline traverse points = [] for xyzlrud in centerline: xyz = [0.01 * v for v in xyzlrud[0:3] ] # These were mm, convert to metres points.append(QgsPointV2(QgsWKBTypes.PointZ, *xyz)) linestring = QgsLineStringV2() linestring.setPoints(points) feat = QgsFeature() geom = QgsGeometry(linestring) feat.setGeometry(geom) feat.setAttributes(attrs) trav_features.append(feat) # The walls as line strings for wall in (left_wall, right_wall): points = [ QgsPointV2(QgsWKBTypes.PointZ, *xyz) for xyz in wall ] linestring = QgsLineStringV2() linestring.setPoints(points) feat = QgsFeature() geom = QgsGeometry(linestring) feat.setGeometry(geom) feat.setAttributes(attrs) wall_features.append(feat) # Slightly more elaborate, pair up points on left # and right walls, and build a cross section as a # 2-point line string, and a quadrilateral polygon # with a closed 5-point line string for the # exterior ring. Note that QGIS polygons are # supposed to have their points ordered clockwise. for i, xyz_pair in enumerate(zip(left_wall, right_wall)): elev = 0.01 * centerline[i][ 2] # elevation of station in centerline attrs = [round(elev, 2)] points = [ QgsPointV2(QgsWKBTypes.PointZ, *xyz) for xyz in xyz_pair ] linestring = QgsLineStringV2() linestring.setPoints(points) feat = QgsFeature() geom = QgsGeometry(linestring) feat.setGeometry(geom) feat.setAttributes(attrs) xsect_features.append(feat) if i > 0: elev = 0.5 * (prev_xyz_pair[0][2] + xyz_pair[0][2] ) # average elevation attrs = [round(elev, 2)] if include_up_down: # average up / down attrs += [ 0.5 * (v1 + v2) for (v1, v2) in zip(up_down[i - 1], up_down[i]) ] points = [ ] # will contain the exterior 5-point ring, as follows... for xyz in tuple( reversed(prev_xyz_pair)) + xyz_pair + ( prev_xyz_pair[1], ): points.append( QgsPointV2(QgsWKBTypes.PointZ, *xyz)) linestring = QgsLineStringV2() linestring.setPoints(points) polygon = QgsPolygonV2() polygon.setExteriorRing(linestring) feat = QgsFeature() geom = QgsGeometry(polygon) feat.setGeometry(geom) feat.setAttributes(attrs) quad_features.append(feat) prev_xyz_pair = xyz_pair # End of processing xsect_list - now add features to requested layers attrs = [QgsField('ELEVATION', QVariant.Double)] # common to all if include_traverses and trav_features: # traverse layer travs_layer = self.add_layer('traverses', 'LineString') travs_layer.dataProvider().addAttributes(attrs) travs_layer.updateFields() travs_layer.dataProvider().addFeatures(trav_features) layers.append(travs_layer) if include_xsections and xsect_features: # xsection layer xsects_layer = self.add_layer('xsections', 'LineString') xsects_layer.dataProvider().addAttributes(attrs) xsects_layer.updateFields() xsects_layer.dataProvider().addFeatures(xsect_features) layers.append(xsects_layer) if include_walls and wall_features: # wall layer walls_layer = self.add_layer('walls', 'LineString') walls_layer.dataProvider().addAttributes(attrs) walls_layer.updateFields() walls_layer.dataProvider().addFeatures(wall_features) layers.append(walls_layer) if include_up_down: # add fields if requested for polygons attrs += [ QgsField(s, QVariant.Double) for s in ('MEAN_UP', 'MEAN_DOWN') ] if include_polygons and quad_features: # polygon layer quads_layer = self.add_layer('polygons', 'Polygon') quads_layer.dataProvider().addAttributes(attrs) quads_layer.updateFields() quads_layer.dataProvider().addFeatures(quad_features) layers.append(quads_layer) # All layers have been created, now update extents and add to QGIS registry if layers: [layer.updateExtents() for layer in layers] QgsMapLayerRegistry.instance().addMapLayers(layers) # Save layers to a GeoPackage if selected. # QgsVectorFileWriter would be ideal but it can only write # single layers (afaik!), so the GeoPackage layers, # fields, and attributes are created using OGR calls, # translating the corresponding QGIS objects on the fly. # It's possible this could be done faster by iterating # numerically over the attributes but I'm not sure the OGR # features would be visited in the right order, so here # use the field names as indices. Meanwhile, the user is # appraised of progress by a progress bar. if gpkg_file: nfeatures = 0 # how many features in total for layer in layers: nfeatures += layer.featureCount() if nfeatures > 100: # create a progress bar progress_bar = QProgressBar() progress_bar.setMaximum(nfeatures) progress_bar.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) msg = 'Saving ' + QFileInfo(gpkg_file).fileName() progressMessageBar = self.iface.messageBar().createMessage( msg) progressMessageBar.layout().addWidget(progress_bar) self.iface.messageBar().pushWidget( progressMessageBar, self.iface.messageBar().INFO) ntrack = int(10**(floor(log10(nfeatures)) - 1)) # update frequency else: progress_bar = None gpkg_driver = ogr.GetDriverByName('GPKG') if os.path.exists(gpkg_file): gpkg_driver.DeleteDataSource(gpkg_file) ogr_dataset = gpkg_driver.CreateDataSource(gpkg_file) if self.epsg: # figure out the spatial reference system in OGR terms ogr_srs = osr.SpatialReference() ogr_srs.ImportFromEPSG(self.epsg) else: ogr_srs = None ncount = 0 # to keep track of number of features processed for layer in layers: # go through all the layers qgis_name = layer.name() match = search(' - ([a-z]*)', qgis_name) ogr_name = str(match.group( 1)) if match else qgis_name # ie, legs, stations, etc ogr_type = self.ogr_vec_type[layer.wkbType()] ogr_layer = ogr_dataset.CreateLayer(ogr_name, srs=ogr_srs, geom_type=ogr_type) qgis_fields = layer.pendingFields() names = [str(field.name()) for field in qgis_fields] types = [ self.ogr_type[field.type()] for field in qgis_fields ] ogr_type_of_ = dict(zip( names, types)) # map field names to OGR field types [ ogr_layer.CreateField( ogr.FieldDefn(name, ogr_type_of_[name])) for name in names ] ogr_schema = ogr_layer.GetLayerDefn( ) # for creating features in the OGR layer for qgis_feat in layer.getFeatures( ): # go through all the features ncount += 1 # update feature count if progress_bar and ncount % ntrack: # update progress bar progress_bar.setValue(ncount) ogr_feat = ogr.Feature(ogr_schema) ogr_wkt = qgis_feat.geometry().exportToWkt().replace( *self.wkt_replace[ogr_type]) ogr_feat.SetGeometry( ogr.CreateGeometryFromWkt(ogr_wkt)) qgis_attrs = qgis_feat.attributes() for name, qgis_attr in zip(names, qgis_attrs): if ogr_type_of_[ name] == ogr.OFTString: # fix for strings ogr_feat.SetField(name, str(qgis_attr)) elif ogr_type_of_[ name] == ogr.OFTDate: # translate dates ogr_feat.SetField( name, str(qgis_attr.toString(Qt.ISODate))) else: # everything else just passes through ogr_feat.SetField(name, qgis_attr) ogr_layer.CreateFeature(ogr_feat) ogr_dataset = None # all done, flush to disk if progress_bar: # clean up and free resources self.iface.messageBar().clearWidgets() progress_bar = None msg = QFileInfo(gpkg_file).fileName() + ' to ' + QFileInfo( gpkg_file).path() QgsMessageLog.logMessage('Saved ' + msg, tag='Import .3d', level=QgsMessageLog.INFO) self.iface.messageBar().pushMessage('Saved', msg, level=QgsMessageBar.INFO, duration=5)