#include "ConnectionListModel.h" #include "ScopeGuard.h" #include "util.h" #include #include #include #include namespace { /** Saves a connection configuration. Before calling this you may want to call beginGroup. */ void SaveConnectionConfig(QSettings &settings, const ConnectionConfig &cc) { settings.setValue("name", stdStrToQ(cc.name())); settings.setValue("host", stdStrToQ(cc.host())); settings.setValue("hostaddr", stdStrToQ(cc.hostAddr())); settings.setValue("port", cc.port()); settings.setValue("user", stdStrToQ(cc.user())); //settings.setValue("password", stdStrToQ(cc.password())); settings.setValue("dbname", stdStrToQ(cc.dbname())); settings.setValue("sslmode", static_cast(cc.sslMode())); settings.setValue("sslcert", stdStrToQ(cc.sslCert())); settings.setValue("sslkey", stdStrToQ(cc.sslKey())); settings.setValue("sslrootcert", stdStrToQ(cc.sslRootCert())); settings.setValue("sslcrl", stdStrToQ(cc.sslCrl())); settings.setValue("passwordState", static_cast(cc.passwordState())); } template bool in_range(T value) { return value >= std::numeric_limits::min() && value <= std::numeric_limits::max(); } void LoadConnectionConfig(QSettings &settings, ConnectionConfig &cc) { cc.setName(qvarToStdStr(settings.value("name"))); cc.setHost(qvarToStdStr(settings.value("host"))); cc.setHostAddr(qvarToStdStr(settings.value("hostaddr"))); int p = settings.value("port", 5432).toInt(); if (!in_range(p)) { p = 0; // let the user re-enter a valid value } cc.setPort(static_cast(p)); cc.setUser(qvarToStdStr(settings.value("user"))); //cc.setPassword(qvarToStdStr(settings.value("password"))); cc.setDbname(qvarToStdStr(settings.value("dbname"))); cc.setSslMode(static_cast(settings.value("sslmode").toInt())); cc.setSslCert(qvarToStdStr(settings.value("sslcert"))); cc.setSslKey(qvarToStdStr(settings.value("sslkey"))); cc.setSslRootCert(qvarToStdStr(settings.value("sslrootcert"))); cc.setSslCrl(qvarToStdStr(settings.value("sslcrl"))); PasswordState pwstate; QVariant v = settings.value("passwordState"); if (v.isNull()) pwstate = PasswordState::NotStored; else pwstate = static_cast(v.toInt()); cc.setPasswordState(pwstate); } } // end of unnamed namespace ConnectionListModel::ConnectionListModel(QObject *parent) : QAbstractListModel(parent) { } ConnectionListModel::~ConnectionListModel() = default; int ConnectionListModel::rowCount(const QModelIndex &parent) const { int result = 0; if (parent == QModelIndex()) { result = m_connections.size(); } return result; } int ConnectionListModel::columnCount(const QModelIndex &/*parent*/) const { return ColCount; } QVariant ConnectionListModel::data(const QModelIndex &index, int role) const { QVariant result; if (role == Qt::DisplayRole || role == Qt::EditRole) { int row = index.row(); int col = index.column(); const ConnectionConfig& cfg = m_connections.at(row); switch (col) { case Description: result = makeLongDescription(cfg); break; case Name: result = stdStrToQ(cfg.name()); break; case Host: result = stdStrToQ(cfg.host()); break; case Port: result = cfg.port(); break; case User: result = stdStrToQ(cfg.user()); break; case Password: result = stdStrToQ(cfg.password()); break; case DbName: result = stdStrToQ(cfg.dbname()); break; } } return result; } bool ConnectionListModel::setData(const QModelIndex &index, const QVariant &value, int role) { bool result = false; if (role == Qt::EditRole) { int row = index.row(); int col = index.column(); // auto& elem = m_connections.at(row); // elem.m_dirty = true; // ConnectionConfig& cfg = elem.m_config; ConnectionConfig& cfg = m_connections[row]; if (col > 0) { result = true; } switch (col) { case Description: break; case Name: cfg.setName( qStrToStd(value.toString()) ); break; case Host: cfg.setHost( qStrToStd(value.toString()) ); break; case Port: cfg.setPort( value.toInt() ); break; case User: cfg.setUser( qStrToStd(value.toString()) ); break; case Password: cfg.setPassword( qStrToStd(value.toString()) ); break; case DbName: cfg.setDbname( qStrToStd(value.toString()) ); break; } } if (result) { emit dataChanged(index, index); } return result; } Qt::ItemFlags ConnectionListModel::flags(const QModelIndex &index) const { Qt::ItemFlags result; int row = index.row(); if (row >= 0 && row < m_connections.size()) { result = Qt::ItemIsSelectable | Qt::ItemIsEnabled; if (index.column() != Description) result |= Qt::ItemIsEditable; } return result; } QString ConnectionListModel::makeLongDescription(const ConnectionConfig &cfg) { std::string result(cfg.name()); result += " ("; result += cfg.user(); result += "@"; result += cfg.host(); result += ":"; result += std::to_string(cfg.port()); result += "/"; result += cfg.dbname(); result += ")"; return stdStrToQ(result); } bool ConnectionListModel::removeRows(int row, int count, const QModelIndex &parent) { bool result = false; if (row >= 0 && row < m_connections.size()) { beginRemoveRows(parent, row, row + count -1); SCOPE_EXIT { endRemoveRows(); }; QString file_name = iniFileName(); QSettings settings(file_name, QSettings::IniFormat); for (int idx = 0; idx < count; ++idx) { auto&& cc = m_connections[idx+row]; settings.remove(cc.uuid().toString()); } settings.sync(); m_connections.remove(row, count); result = true; } return result; } //void ConnectionListModel::newItem() //{ //// int i = m_connections->createNew(); //// auto idx = createIndex(i, 0); //// emit dataChanged(idx, idx); //} Expected ConnectionListModel::get(int row) { if (row < m_connections.size()) { return m_connections.at(row); } return Expected::fromException(std::out_of_range("Invalid row")); } void ConnectionListModel::load() { QString file_name = iniFileName(); QSettings settings(file_name, QSettings::IniFormat); auto groups = settings.childGroups(); for (auto&& grp : groups) { if (grp == "c_IniGroupSecurity") { // Read security settings } else { QUuid uuid(grp); if ( ! uuid.isNull() ) { settings.beginGroup(grp); SCOPE_EXIT { settings.endGroup(); }; ConnectionConfig cc; cc.setUuid(uuid); LoadConnectionConfig(settings, cc); m_connections.push_back(cc); } } } } void ConnectionListModel::save() { QString file_name = iniFileName(); QSettings settings(file_name, QSettings::IniFormat); for (auto& e : m_connections) { settings.beginGroup(e.uuid().toString()); SCOPE_EXIT { settings.endGroup(); }; SaveConnectionConfig(settings, e); e.clean(); } settings.sync(); } void ConnectionListModel::save(int index) { auto& e = m_connections[index]; if (e.dirty()) { QString file_name = iniFileName(); QSettings settings(file_name, QSettings::IniFormat); settings.beginGroup(e.uuid().toString()); SaveConnectionConfig(settings, e); e.clean(); settings.sync(); } } void ConnectionListModel::save(const ConnectionConfig &cc) { auto find_res = std::find(m_connections.begin(), m_connections.end(), cc.uuid()); int i; if (find_res == m_connections.end()) { m_connections.push_back(cc); i = m_connections.size() - 1; } else { *find_res = cc; i = find_res - m_connections.begin(); } emit dataChanged(createIndex(i, 0), createIndex(i, ColCount-1)); save(i); } QString ConnectionListModel::iniFileName() { QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); QDir dir(path); if (!dir.exists()) { dir.mkpath("."); } path += "/connections.ini"; return path; }