File indexing completed on 2025-01-19 07:43:00
0001 /* This file is part of the KDE project 0002 0003 Copyright (C) 2008 Javier Goday <jgoday@gmail.com> 0004 0005 This program is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 */ 0010 0011 #include "rangetreewidget.h" 0012 #include "settings.h" 0013 0014 #include <QDebug> 0015 0016 #include <QApplication> 0017 #include <QFont> 0018 #include <QHeaderView> 0019 #include <QLinearGradient> 0020 #include <QList> 0021 #include <QPainter> 0022 #include <QPalette> 0023 #include <QStandardItem> 0024 #include <QStandardItemModel> 0025 #include <QUrl> 0026 #include <QVariant> 0027 0028 class RangeTreeWidget::Range 0029 { 0030 public: 0031 Range() 0032 { 0033 } 0034 0035 bool check(const QVariant &data) const 0036 { 0037 if (data.type() == QVariant::String) { 0038 return (QString::compare(data.toString(), min.toString()) == 0); 0039 } else if (data.type() == QVariant::Int || data.type() == QVariant::Double) { 0040 if (data.toDouble() >= min.toDouble() && (data.toDouble() <= max.toDouble() || max.toDouble() < 0)) { 0041 // the last range ends with -1 0042 return true; 0043 } 0044 } 0045 0046 return false; 0047 } 0048 0049 int id; 0050 QVariant min; 0051 QVariant max; 0052 QString title; 0053 }; 0054 0055 RangeSortFilterProxyModel::RangeSortFilterProxyModel(QObject *parent) 0056 : QSortFilterProxyModel(parent) 0057 { 0058 } 0059 0060 RangeSortFilterProxyModel::~RangeSortFilterProxyModel() 0061 { 0062 } 0063 0064 bool RangeSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const 0065 { 0066 // if the row is a range row, we include in the filter always 0067 if (source_parent.isValid()) { 0068 return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); 0069 } 0070 0071 return true; 0072 } 0073 0074 RangeTreeWidget::RangeTreeWidget(QWidget *parent) 0075 : QTreeView(parent) 0076 , m_data() 0077 , m_ranges() 0078 , m_rangeDelegate(nullptr) 0079 { 0080 setDragEnabled(false); 0081 setAlternatingRowColors(true); 0082 setEditTriggers(QAbstractItemView::NoEditTriggers); 0083 header()->setSectionsMovable(false); 0084 0085 // initialize the standard item model of the tree 0086 m_model = new QStandardItemModel(this); 0087 m_proxyModel = new RangeSortFilterProxyModel(this); 0088 0089 m_proxyModel->setSourceModel(m_model); 0090 setModel(m_proxyModel); 0091 0092 // delegate for the range title 0093 auto *delegate = new RangeTreeWidgetItemDelegate(this); 0094 setItemDelegate(delegate); 0095 } 0096 0097 RangeTreeWidget::~RangeTreeWidget() 0098 { 0099 QList<int> list; 0100 for (int i = 0; i < 5; i++) { 0101 list.append(columnWidth(i)); 0102 } 0103 Settings::setHistoryColumnWidths(list); 0104 Settings::self()->save(); 0105 clear(); 0106 0107 delete m_rangeDelegate; 0108 } 0109 0110 int RangeTreeWidget::addRange(const QVariant &min, const QVariant &max, const QString &title) 0111 { 0112 int row = m_data.size(); 0113 0114 Range range; 0115 range.min = min; 0116 range.max = max; 0117 range.title = title; 0118 range.id = row; 0119 m_ranges << range; 0120 0121 m_data[row] = new QStandardItem(title); 0122 m_model->insertRow(row, m_data[row]); 0123 setFirstColumnSpanned(row, QModelIndex(), true); 0124 // openPersistentEditor(model()->index(row, 0, QModelIndex())); 0125 0126 // expand the first row 0127 if (row == 0) { 0128 setExpanded(model()->index(row, 0, QModelIndex()), true); 0129 } 0130 0131 return row; 0132 } 0133 0134 void RangeTreeWidget::clear() 0135 { 0136 m_model->clear(); 0137 m_data.clear(); 0138 m_ranges.clear(); 0139 } 0140 0141 void RangeTreeWidget::add(const QVariant &data, const QString &column) 0142 { 0143 QVariantList list; 0144 list << QVariant(column); 0145 0146 add(data, list); 0147 } 0148 0149 void RangeTreeWidget::add(const QVariant &data, const QVariantList &columns) 0150 { 0151 QStandardItem *parent = getRange(data); 0152 0153 QList<QStandardItem *> list; 0154 foreach (const QVariant &item, columns) { 0155 list << new QStandardItem(item.toString()); 0156 } 0157 0158 parent->appendRow(list); 0159 // TODO: need to find a better way to update rangetitlewidget count from the QStandardItem children count 0160 // closePersistentEditor(parent->index()); 0161 // openPersistentEditor(parent->index()); 0162 } 0163 0164 void RangeTreeWidget::addLabel(const QString &title) 0165 { 0166 int index = header()->count(); 0167 m_model->setColumnCount(index + 1); 0168 m_model->setHeaderData(index, Qt::Horizontal, title); 0169 } 0170 0171 void RangeTreeWidget::setLabels(const QStringList &labels) 0172 { 0173 m_model->setColumnCount(labels.size()); 0174 0175 for (int i = 0; i < labels.size(); i++) { 0176 m_model->setHeaderData(i, Qt::Horizontal, labels.at(i)); 0177 } 0178 } 0179 0180 void RangeTreeWidget::setRangeDelegate(RangeDelegate *delegate) 0181 { 0182 delete m_rangeDelegate; 0183 m_rangeDelegate = delegate; 0184 } 0185 0186 QList<QVariantList> RangeTreeWidget::data() 0187 { 0188 QList<QVariantList> list; 0189 foreach (const Range &range, m_ranges) { 0190 QStandardItem *parent = m_model->itemFromIndex(model()->index(range.id, 0, QModelIndex())); 0191 0192 for (int y = 0; y < parent->rowCount(); y++) { 0193 QVariantList items; 0194 for (int x = 0; x < header()->count(); x++) { 0195 QStandardItem *item = parent->child(y, x); 0196 items << item->data(Qt::DisplayRole); 0197 } 0198 list << items; 0199 } 0200 } 0201 0202 return list; 0203 } 0204 0205 QStandardItem *RangeTreeWidget::currentItem(int column) 0206 { 0207 QStandardItem *item = nullptr; 0208 if (column >= 0) { 0209 item = 0210 m_model->itemFromIndex(m_model->index(m_proxyModel->mapToSource(currentIndex()).row(), column, m_proxyModel->mapToSource(currentIndex()).parent())); 0211 } else { 0212 item = m_model->itemFromIndex(m_proxyModel->mapToSource(currentIndex())); 0213 } 0214 return item; 0215 } 0216 0217 QStandardItem *RangeTreeWidget::item(const QModelIndex &index, int column) 0218 { 0219 return m_model->item(m_proxyModel->mapToSource(index).row(), column); 0220 } 0221 0222 void RangeTreeWidget::removeRow(int row, const QModelIndex &parent) 0223 { 0224 m_model->removeRow(row, parent); 0225 } 0226 0227 void RangeTreeWidget::setFilterRegExp(const QString &text) 0228 { 0229 m_proxyModel->setFilterRegularExpression(text); 0230 } 0231 0232 QStandardItem *RangeTreeWidget::getRange(const QVariant &data) 0233 { 0234 QVariant rangeData = data; 0235 if (m_rangeDelegate) { 0236 rangeData = m_rangeDelegate->getRangeData(data); 0237 } 0238 0239 foreach (const Range &range, m_ranges) { 0240 if (range.check(rangeData)) { 0241 return m_data[range.id]; 0242 } 0243 } 0244 0245 if (m_rangeDelegate) { 0246 int id = addRange(rangeData, rangeData, rangeData.toString()); 0247 return m_data[id]; 0248 } else { 0249 // if no range found, return the last one 0250 return m_data[m_data.size() - 1]; 0251 } 0252 } 0253 0254 RangeDelegate::RangeDelegate(QObject *parent) 0255 : QObject(parent) 0256 { 0257 } 0258 0259 RangeDelegate::~RangeDelegate() 0260 { 0261 } 0262 0263 HostRangeDelegate::HostRangeDelegate(QObject *parent) 0264 : RangeDelegate(parent) 0265 { 0266 } 0267 0268 HostRangeDelegate::~HostRangeDelegate() 0269 { 0270 } 0271 0272 QVariant HostRangeDelegate::getRangeData(const QVariant &data) 0273 { 0274 return QUrl(data.toString()).host(); 0275 } 0276 0277 RangeTreeWidgetItemDelegate::RangeTreeWidgetItemDelegate(QAbstractItemView *parent) 0278 : QStyledItemDelegate(parent) 0279 { 0280 } 0281 0282 void RangeTreeWidgetItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const 0283 { 0284 if (index.parent().isValid()) { 0285 QStyledItemDelegate::paint(painter, option, index); 0286 } else if (index.isValid()) { 0287 QStyleOptionViewItem opt(option); 0288 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); 0289 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); 0290 0291 const auto *model = static_cast<const QSortFilterProxyModel *>(index.model()); 0292 const auto *s_model = static_cast<const QStandardItemModel *>(model->sourceModel()); 0293 QStandardItem *item = s_model->itemFromIndex(model->mapToSource(index)); 0294 // draw the range title 0295 painter->save(); 0296 QFont font; 0297 font.setBold(true); 0298 painter->setFont(font); 0299 painter->drawText(option.rect.left() + 10, 0300 option.rect.top() + 5, 0301 option.rect.width() - 20, 0302 15, 0303 Qt::AlignLeft, 0304 item->data(Qt::DisplayRole).toString() + " (" + QString::number(model->rowCount(index)) + ')'); 0305 painter->restore(); 0306 0307 // Draw the line under the title 0308 QColor color = option.palette.color(QPalette::Text); 0309 if (option.state & QStyle::State_Selected) { 0310 color = option.palette.color(QPalette::HighlightedText); 0311 } 0312 0313 QRect lineRect(option.rect.left() + 10, option.rect.bottom() - 2, 500, 1); 0314 0315 QLinearGradient gradient(option.rect.left() + 10, option.rect.top(), 500, option.rect.height()); 0316 gradient.setColorAt(0, color); 0317 gradient.setColorAt(1, Qt::transparent); 0318 0319 painter->fillRect(lineRect, gradient); 0320 } 0321 } 0322 0323 QSize RangeTreeWidgetItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const 0324 { 0325 Q_UNUSED(option) 0326 Q_UNUSED(index) 0327 0328 return QSize(0, 30); 0329 } 0330 0331 #include "moc_rangetreewidget.cpp"