File indexing completed on 2024-12-08 04:31:13
0001 /*************************************************************************** 0002 * Copyright (C) 2009 Matthias Fuchs <mat69@gmx.net> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify * 0005 * it under the terms of the GNU General Public License as published by * 0006 * the Free Software Foundation; either version 2 of the License, or * 0007 * (at your option) any later version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, * 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0012 * GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License * 0015 * along with this program; if not, write to the * 0016 * Free Software Foundation, Inc., * 0017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * 0018 ***************************************************************************/ 0019 0020 #include "mirrormodel.h" 0021 0022 #include <QComboBox> 0023 #include <QSpinBox> 0024 #include <QStandardPaths> 0025 0026 #include <KCountry> 0027 #include <KLineEdit> 0028 #include <KLocalizedString> 0029 0030 MirrorDelegate::MirrorDelegate(QObject *parent) 0031 : QStyledItemDelegate(parent) 0032 , m_countrySort(nullptr) 0033 { 0034 } 0035 0036 MirrorDelegate::MirrorDelegate(QSortFilterProxyModel *countrySort, QObject *parent) 0037 : QStyledItemDelegate(parent) 0038 , m_countrySort(countrySort) 0039 { 0040 } 0041 0042 QWidget *MirrorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const 0043 { 0044 Q_UNUSED(option) 0045 0046 if (index.isValid()) { 0047 if (index.column() == MirrorItem::Url) { 0048 auto *line = new KLineEdit(parent); 0049 0050 return line; 0051 } else if (index.column() == MirrorItem::Connections) { 0052 auto *numConnections = new QSpinBox(parent); 0053 numConnections->setRange(0, 20); 0054 0055 return numConnections; 0056 } else if (index.column() == MirrorItem::Priority) { 0057 auto *priority = new QSpinBox(parent); 0058 priority->setRange(0, 999999); 0059 0060 return priority; 0061 } else if (index.column() == MirrorItem::Country) { 0062 if (m_countrySort) { 0063 auto *countrySort = new QComboBox(parent); 0064 countrySort->setModel(m_countrySort); 0065 0066 return countrySort; 0067 } 0068 } 0069 } 0070 0071 return nullptr; 0072 } 0073 0074 void MirrorDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const 0075 { 0076 if (index.isValid() && editor) { 0077 if (index.column() == MirrorItem::Url) { 0078 auto *line = static_cast<KLineEdit *>(editor); 0079 const QUrl url = index.data(Qt::EditRole).toUrl(); 0080 line->setUrl(url); 0081 } else if (index.column() == MirrorItem::Connections) { 0082 auto *numConnections = static_cast<QSpinBox *>(editor); 0083 const int num = index.data(Qt::EditRole).toInt(); 0084 numConnections->setValue(num); 0085 } else if (index.column() == MirrorItem::Priority) { 0086 auto *priority = static_cast<QSpinBox *>(editor); 0087 const int num = index.data(Qt::EditRole).toInt(); 0088 priority->setValue(num); 0089 } else if (index.column() == MirrorItem::Country) { 0090 auto *countrySort = static_cast<QComboBox *>(editor); 0091 const QString countryCode = index.data(Qt::EditRole).toString(); 0092 const int indexCountrySort = countrySort->findData(countryCode); 0093 countrySort->setCurrentIndex(indexCountrySort); 0094 } 0095 } 0096 } 0097 0098 void MirrorDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const 0099 { 0100 if (index.isValid() && editor && model) { 0101 if (index.column() == MirrorItem::Url) { 0102 auto *line = static_cast<KLineEdit *>(editor); 0103 if (!line->text().isEmpty()) { 0104 model->setData(index, line->text()); 0105 } 0106 } else if (index.column() == MirrorItem::Connections) { 0107 auto *numConnections = static_cast<QSpinBox *>(editor); 0108 model->setData(index, numConnections->value()); 0109 } else if (index.column() == MirrorItem::Priority) { 0110 auto *priority = static_cast<QSpinBox *>(editor); 0111 model->setData(index, priority->value()); 0112 } else if (index.column() == MirrorItem::Country) { 0113 auto *countrySort = static_cast<QComboBox *>(editor); 0114 const QString countryCode = countrySort->itemData(countrySort->currentIndex()).toString(); 0115 model->setData(index, countryCode); 0116 } 0117 } 0118 } 0119 0120 void MirrorDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const 0121 { 0122 Q_UNUSED(index) 0123 editor->setGeometry(option.rect); 0124 } 0125 0126 QSize MirrorDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const 0127 { 0128 // make the sizeHint a little bit nicer to have more beautiful editors 0129 QSize hint; 0130 hint.setWidth(QStyledItemDelegate::sizeHint(option, index).width()); 0131 hint.setHeight(option.fontMetrics.height() + 7); 0132 return hint; 0133 } 0134 0135 MirrorProxyModel::MirrorProxyModel(QObject *parent) 0136 : QSortFilterProxyModel(parent) 0137 { 0138 } 0139 0140 bool MirrorProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const 0141 { 0142 if (left.column() == MirrorItem::Used) { 0143 const int leftData = sourceModel()->data(left, Qt::CheckStateRole).toInt(); 0144 const int rightData = sourceModel()->data(right, Qt::CheckStateRole).toInt(); 0145 return leftData < rightData; 0146 } else if (left.column() == MirrorItem::Priority) { 0147 const int leftData = sourceModel()->data(left, Qt::UserRole).toInt(); 0148 const int rightData = sourceModel()->data(right, Qt::UserRole).toInt(); 0149 return (!leftData ? true : (leftData > rightData) && rightData); // 0 is always smallest, otherwise larger is smaller 0150 } 0151 0152 return QSortFilterProxyModel::lessThan(left, right); 0153 } 0154 0155 MirrorItem::MirrorItem() 0156 : m_checked(Qt::Unchecked) 0157 , m_numConnections(0) 0158 , m_priority(0) 0159 { 0160 } 0161 0162 QVariant MirrorItem::data(int column, int role) const 0163 { 0164 if (column == MirrorItem::Used) { 0165 if (role == Qt::CheckStateRole) { 0166 return m_checked; 0167 } 0168 } else if (column == MirrorItem::Url) { 0169 if (role == Qt::DisplayRole) { 0170 return m_url.toString(); 0171 } else if ((role == Qt::UserRole) || (role == Qt::EditRole)) { 0172 return QVariant(m_url); 0173 } 0174 } else if (column == MirrorItem::Connections) { 0175 if (role == Qt::DisplayRole) { 0176 if (m_numConnections) { 0177 return m_numConnections; 0178 } else { 0179 return i18n("not specified"); 0180 } 0181 } else if ((role == Qt::EditRole) || (role == Qt::UserRole)) { 0182 return m_numConnections; 0183 } 0184 } else if (column == MirrorItem::Priority) { 0185 if (role == Qt::DisplayRole) { 0186 if (m_priority) { 0187 return m_priority; 0188 } else { 0189 return i18n("not specified"); 0190 } 0191 } else if ((role == Qt::EditRole) || (role == Qt::UserRole)) { 0192 return m_priority; 0193 } 0194 } else if (column == MirrorItem::Country) { 0195 if (role == Qt::DisplayRole) { 0196 return m_countryName; 0197 } else if ((role == Qt::UserRole) || (role == Qt::EditRole)) { 0198 return m_countryCode; 0199 } 0200 } 0201 0202 return QVariant(); 0203 } 0204 0205 Qt::ItemFlags MirrorItem::flags(int column) const 0206 { 0207 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; 0208 if (column == MirrorItem::Used) { 0209 flags |= Qt::ItemIsUserCheckable; 0210 } else if (column == MirrorItem::Url) { 0211 flags |= Qt::ItemIsEditable; 0212 } else if (column == MirrorItem::Connections) { 0213 flags |= Qt::ItemIsEditable; 0214 } else if (column == MirrorItem::Priority) { 0215 flags |= Qt::ItemIsEditable; 0216 } else if (column == MirrorItem::Country) { 0217 flags |= Qt::ItemIsEditable; 0218 } 0219 0220 return flags; 0221 } 0222 0223 bool MirrorItem::setData(int column, const QVariant &value, int role) 0224 { 0225 if ((column == MirrorItem::Used) && (role == Qt::CheckStateRole)) { 0226 m_checked = static_cast<Qt::CheckState>(value.toInt()); 0227 return true; 0228 } else if ((column == MirrorItem::Url) && (role == Qt::EditRole)) { 0229 QUrl url; 0230 if (value.type() == QVariant::Url) { 0231 url = QUrl(value.toUrl()); 0232 } else if (value.type() == QVariant::String) { 0233 url = QUrl(value.toString()); 0234 } 0235 0236 if (!url.isEmpty()) { 0237 m_url = url; 0238 return true; 0239 } 0240 } else if ((column == MirrorItem::Connections) && (role == Qt::EditRole)) { 0241 m_numConnections = value.toInt(); 0242 return true; 0243 } else if ((column == MirrorItem::Priority) && (role == Qt::EditRole)) { 0244 m_priority = value.toInt(); 0245 return true; 0246 } else if ((column == MirrorItem::Country) && (role == Qt::EditRole)) { 0247 m_countryCode = value.toString(); 0248 m_countryName = KCountry::fromAlpha2(m_countryCode).name(); 0249 return true; 0250 } 0251 0252 return false; 0253 } 0254 0255 MirrorModel::MirrorModel(QObject *parent) 0256 : QAbstractTableModel(parent) 0257 { 0258 } 0259 0260 MirrorModel::~MirrorModel() 0261 { 0262 qDeleteAll(m_data); 0263 } 0264 0265 int MirrorModel::rowCount(const QModelIndex &index) const 0266 { 0267 if (!index.isValid()) { 0268 return m_data.count(); 0269 } else { 0270 return 0; 0271 } 0272 } 0273 0274 int MirrorModel::columnCount(const QModelIndex &index) const 0275 { 0276 if (index.isValid()) { 0277 return 0; 0278 } 0279 0280 return 5; 0281 } 0282 0283 QVariant MirrorModel::headerData(int section, Qt::Orientation orientation, int role) const 0284 { 0285 if (orientation == Qt::Vertical) { 0286 return QVariant(); 0287 } 0288 0289 if ((section == MirrorItem::Url) && (role == Qt::DisplayRole)) { 0290 return i18nc("Mirror as in server, in url", "Mirror"); 0291 } else if (section == MirrorItem::Priority) { 0292 if (role == Qt::DisplayRole) { 0293 return i18nc("The priority of the mirror", "Priority"); 0294 } else if (role == Qt::DecorationRole) { 0295 return QIcon::fromTheme("games-highscores"); 0296 } 0297 } else if ((section == MirrorItem::Connections) && (role == Qt::DisplayRole)) { 0298 return i18nc("Number of parallel connections to the mirror", "Connections"); 0299 } else if ((section == MirrorItem::Country) && (role == Qt::DisplayRole)) { 0300 return i18nc("Location = country", "Location"); 0301 } 0302 0303 return QVariant(); 0304 } 0305 0306 QVariant MirrorModel::data(const QModelIndex &index, int role) const 0307 { 0308 if (!index.isValid()) { 0309 return QVariant(); 0310 } 0311 0312 return m_data.at(index.row())->data(index.column(), role); 0313 } 0314 0315 Qt::ItemFlags MirrorModel::flags(const QModelIndex &index) const 0316 { 0317 if (!index.isValid()) { 0318 return Qt::NoItemFlags; 0319 } 0320 0321 return m_data.at(index.row())->flags(index.column()); 0322 } 0323 0324 bool MirrorModel::setData(const QModelIndex &index, const QVariant &value, int role) 0325 { 0326 if (!index.isValid()) { 0327 return false; 0328 } 0329 0330 const bool changed = m_data.at(index.row())->setData(index.column(), value, role); 0331 if (changed) { 0332 Q_EMIT dataChanged(index, index); 0333 } 0334 return changed; 0335 } 0336 0337 bool MirrorModel::removeRows(int row, int count, const QModelIndex &parent) 0338 { 0339 if (parent.isValid() || (row < 0) || (count < 1) || (row + count > rowCount())) { 0340 return false; 0341 } 0342 0343 beginRemoveRows(parent, row, row + count - 1); 0344 while (count) { 0345 MirrorItem *item = m_data[row]; 0346 m_data.removeAt(row); 0347 delete item; 0348 --count; 0349 } 0350 endRemoveRows(); 0351 0352 return true; 0353 } 0354 0355 void MirrorModel::addMirror(const QUrl &url, int numConnections, int priority, const QString &countryCode) 0356 { 0357 if (!url.isValid()) { 0358 return; 0359 } 0360 0361 for (int i = 0; i < rowCount(); ++i) { 0362 // exists already, so remove the row 0363 if (QUrl(m_data.at(i)->data(MirrorItem::Url).toString()) == url) { 0364 removeRow(i); 0365 break; 0366 } 0367 } 0368 0369 int index = rowCount(); 0370 Q_EMIT beginInsertRows(QModelIndex(), index, index); 0371 0372 auto *item = new MirrorItem; 0373 m_data.append(item); 0374 item->setData(MirrorItem::Used, Qt::Checked, Qt::CheckStateRole); // every newly added mirror is set to checked automatically 0375 item->setData(MirrorItem::Url, QVariant(url)); 0376 item->setData(MirrorItem::Connections, numConnections); 0377 item->setData(MirrorItem::Priority, priority); 0378 item->setData(MirrorItem::Country, countryCode); 0379 0380 Q_EMIT endInsertRows(); 0381 } 0382 0383 void MirrorModel::setMirrors(const QHash<QUrl, QPair<bool, int>> &mirrors) 0384 { 0385 beginResetModel(); 0386 removeRows(0, rowCount()); 0387 0388 QHash<QUrl, QPair<bool, int>>::const_iterator it; 0389 QHash<QUrl, QPair<bool, int>>::const_iterator itEnd = mirrors.constEnd(); 0390 for (it = mirrors.constBegin(); it != itEnd; ++it) { 0391 auto *item = new MirrorItem; 0392 item->setData(MirrorItem::Url, QVariant(it.key())); 0393 Qt::CheckState state = (*it).first ? Qt::Checked : Qt::Unchecked; 0394 item->setData(MirrorItem::Used, state, Qt::CheckStateRole); 0395 item->setData(MirrorItem::Connections, (*it).second); 0396 m_data.append(item); 0397 } 0398 0399 endResetModel(); 0400 } 0401 0402 QHash<QUrl, QPair<bool, int>> MirrorModel::availableMirrors() const 0403 { 0404 QHash<QUrl, QPair<bool, int>> mirrors; 0405 foreach (MirrorItem *item, m_data) { 0406 bool used = (item->data(MirrorItem::Used, Qt::CheckStateRole).toInt() == Qt::Checked) ? true : false; 0407 const QUrl url = QUrl(item->data(MirrorItem::Url).toString()); 0408 mirrors[url] = QPair<bool, int>(used, item->data(MirrorItem::Connections, Qt::UserRole).toInt()); 0409 } 0410 return mirrors; 0411 } 0412 0413 #include "moc_mirrormodel.cpp"