Commit db5a8832 authored by Volker Krause's avatar Volker Krause
Browse files

Make country subdivision a editable combo box

This allow selection/auto-completion of the region for the current country.
parent f7a046fc
......@@ -80,6 +80,7 @@ endif()
add_executable(itinerary-app ${itinerary_app_srcs})
target_sources(itinerary-app PRIVATE
main.cpp
countrysubdivisionmodel.cpp
developmentmodecontroller.cpp
documentsmodel.cpp
locationinformationdelegatecontroller.cpp
......
......@@ -33,7 +33,11 @@ Kirigami.FormLayout {
addr.streetAddress = streetAddress.text;
addr.postalCode = postalCode.text;
addr.addressLocality = addressLocality.text;
addr.addressRegion = addressRegion.text;
if (addressRegion.visible) {
addr.addressRegion = addressRegion.currentIndex < 0 ? addressRegion.editText : addressRegion.currentValue.substr(3);
} else {
addr.addressRegion = '';
}
addr.addressCountry = addressCountry.currentValue;
var geo = place.geo;
geo.latitude = latitude;
......@@ -95,11 +99,41 @@ Kirigami.FormLayout {
text: place.address.addressLocality
}
QQC2.TextField {
CountrySubdivisionModel {
id: regionModel
country: addressCountry.currentCountry
onCountryChanged: {
if (addressRegion.currentIndex < 0) {
addressRegion.tryFindRegion(addressRegion.editText != '' ? addressRegion.editText : place.address.addressRegion);
} else {
addressRegion.currentIndex = -1;
}
}
}
QQC2.ComboBox {
id: addressRegion
Kirigami.FormData.label: i18n("Region:")
text: place.address.addressRegion
visible: (root.addressFormat.usedFields & KContacts.AddressFormatField.Region) || text
editable: true
model: regionModel
textRole: "display"
valueRole: "code"
Layout.fillWidth: true
visible: (root.addressFormat.usedFields & KContacts.AddressFormatField.Region) || editText
function tryFindRegion(input) {
const i = regionModel.rowForNameOrCode(input)
if (i >= 0) {
currentIndex = i;
} else if (input) {
editText = input;
} else {
currentIndex = -1;
editText = '';
}
}
Component.onCompleted: tryFindRegion(place.address.addressRegion)
onAccepted: tryFindRegion(editText)
}
App.CountryComboBox {
......
/*
SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "countrysubdivisionmodel.h"
#include <QDebug>
CountrySubdivisionModel::CountrySubdivisionModel(QObject *parent)
: QAbstractListModel(parent)
{
}
CountrySubdivisionModel::~CountrySubdivisionModel() = default;
KCountry CountrySubdivisionModel::country() const
{
return m_country;
}
void CountrySubdivisionModel::setCountry(const KCountry &country)
{
if (m_country == country) {
return;
}
beginResetModel();
m_country = country;
if (m_country.isValid()) {
m_subdivs = country.subdivisions();
std::sort(m_subdivs.begin(), m_subdivs.end(), [](const auto &lhs, const auto &rhs) {
return lhs.name().localeAwareCompare(rhs.name()) < 0;
});
}
endResetModel();
Q_EMIT countryChanged();
}
int CountrySubdivisionModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return m_subdivs.size();
}
QVariant CountrySubdivisionModel::data(const QModelIndex &index, int role) const
{
if (!checkIndex(index)) {
return {};
}
switch (role) {
case Qt::DisplayRole:
return m_subdivs.at(index.row()).name();
case CodeRole:
return m_subdivs.at(index.row()).code();
}
return {};
}
QHash<int, QByteArray> CountrySubdivisionModel::roleNames() const
{
auto r = QAbstractListModel::roleNames();
r.insert(CodeRole, "code");
r.insert(SubdivisionRole, "subdivision");
return r;
}
int CountrySubdivisionModel::rowForNameOrCode(const QString &input) const
{
for (auto i = 0; i < m_subdivs.size(); ++i) {
const auto subdiv = m_subdivs[i];
if (subdiv.code().compare(input, Qt::CaseInsensitive) == 0 || QStringView(subdiv.code()).mid(3).compare(input, Qt::CaseInsensitive) == 0 || subdiv.name().compare(input, Qt::CaseInsensitive) == 0) {
return i;
}
}
return -1;
}
/*
SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef COUNTRYSUBDIVISIONMODEL_H
#define COUNTRYSUBDIVISIONMODEL_H
#include <KCountry>
#include <KCountrySubdivision>
#include <QAbstractListModel>
/** Country subdivision model, for a given country. */
class CountrySubdivisionModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(KCountry country READ country WRITE setCountry NOTIFY countryChanged)
public:
enum {
CodeRole = Qt::UserRole,
SubdivisionRole,
};
explicit CountrySubdivisionModel(QObject *parent = nullptr);
~CountrySubdivisionModel();
KCountry country() const;
void setCountry(const KCountry &country);
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE int rowForNameOrCode(const QString &input) const;
Q_SIGNALS:
void countryChanged();
private:
KCountry m_country;
QList<KCountrySubdivision> m_subdivs;
};
#endif // COUNTRYSUBDIVISIONMODEL_H
......@@ -9,6 +9,7 @@
#include "logging.h"
#include "applicationcontroller.h"
#include "countrysubdivisionmodel.h"
#include "developmentmodecontroller.h"
#include "documentmanager.h"
#include "documentsmodel.h"
......@@ -125,6 +126,7 @@ void registerApplicationTypes()
qmlRegisterUncreatableType<TimelineModel>("org.kde.itinerary", 1, 0, "TimelineModel", {});
qmlRegisterUncreatableType<Transfer>("org.kde.itinerary", 1, 0, "Transfer", {});
qmlRegisterType<CountrySubdivisionModel>("org.kde.itinerary", 1, 0, "CountrySubdivisionModel");
qmlRegisterType<DocumentsModel>("org.kde.itinerary", 1, 0, "DocumentsModel");
qmlRegisterType<LocationInformationDelegateController>("org.kde.itinerary", 1, 0, "LocationInformationDelegateController");
qmlRegisterType<QSortFilterProxyModel>("org.kde.itinerary", 1, 0, "SortFilterProxyModel"); // TODO use this from kitemmodels?
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment