File indexing completed on 2024-05-19 12:55:40
0001 /* This file is part of the KDE project 0002 Copyright (C) 2016 Jarosław Staniek <staniek@kde.org> 0003 0004 Forked from kwidgetsaddons/src/kpageview_p.cpp: 0005 Copyright (C) 2006 Tobias Koenig (tokoe@kde.org) 0006 Copyright (C) 2007 Rafael Fernández López (ereslibre@kde.org) 0007 0008 This library is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU Library General Public 0010 License as published by the Free Software Foundation; either 0011 version 2 of the License, or (at your option) any later version. 0012 0013 This library is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 Library General Public License for more details. 0017 0018 You should have received a copy of the GNU Library General Public License 0019 along with this library; see the file COPYING.LIB. If not, write to 0020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0021 * Boston, MA 02110-1301, USA. 0022 */ 0023 0024 #include "KexiListView.h" 0025 #include "KexiListView_p.h" 0026 0027 #include <QApplication> 0028 #include <QDebug> 0029 #include <QPainter> 0030 #include <QTextLayout> 0031 0032 const int KEXILISTVIEW_VERTICAL_MARGIN = 10; 0033 const int KEXILISTVIEW_HORIZONTAL_MARGIN = 12; 0034 0035 KexiListView::KexiListView(QWidget *parent) 0036 : KexiListView(UseDefaultDelegate, parent) 0037 { 0038 } 0039 0040 KexiListView::KexiListView(UseDelegate useDelegate, QWidget *parent) 0041 : QListView(parent) 0042 { 0043 setViewMode(QListView::ListMode); 0044 setMovement(QListView::Static); 0045 setVerticalScrollMode(QListView::ScrollPerPixel); 0046 if (useDelegate == UseDefaultDelegate) { 0047 setItemDelegate(new KexiListViewDelegate(this)); 0048 } 0049 } 0050 0051 KexiListView::~KexiListView() 0052 { 0053 } 0054 0055 void KexiListView::setModel(QAbstractItemModel *model) 0056 { 0057 /* 0058 KPageListViewProxy *proxy = new KPageListViewProxy( this ); 0059 proxy->setSourceModel( model ); 0060 proxy->rebuildMap(); 0061 0062 connect( model, SIGNAL(layoutChanged()), proxy, SLOT(rebuildMap()) ); 0063 */ 0064 connect(model, SIGNAL(layoutChanged()), this, SLOT(updateWidth())); 0065 0066 // QListView::setModel( proxy ); 0067 QListView::setModel(model); 0068 0069 // Set our own selection model, which won't allow our current selection to be cleared 0070 setSelectionModel(new KexiListViewSelectionModel(model, this)); 0071 0072 updateWidth(); 0073 } 0074 0075 void KexiListView::updateWidth() 0076 { 0077 if (!model()) { 0078 return; 0079 } 0080 0081 int rows = model()->rowCount(); 0082 0083 int width = 0; 0084 for (int i = 0; i < rows; ++i) { 0085 width = qMax(width, sizeHintForIndex(model()->index(i, 0)).width()); 0086 } 0087 0088 setFixedWidth(width + KEXILISTVIEW_HORIZONTAL_MARGIN * 2); 0089 } 0090 0091 // ---- 0092 0093 KexiListViewDelegate::KexiListViewDelegate(QObject *parent) 0094 : QAbstractItemDelegate(parent) 0095 { 0096 } 0097 0098 static int layoutText(QTextLayout *layout, int maxWidth) 0099 { 0100 qreal height = 0; 0101 int textWidth = 0; 0102 layout->beginLayout(); 0103 while (true) { 0104 QTextLine line = layout->createLine(); 0105 if (!line.isValid()) { 0106 break; 0107 } 0108 line.setLineWidth(maxWidth); 0109 line.setPosition(QPointF(0, height)); 0110 height += line.height(); 0111 textWidth = qMax(textWidth, qRound(line.naturalTextWidth() + 0.5)); 0112 } 0113 layout->endLayout(); 0114 return textWidth; 0115 } 0116 0117 void KexiListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, 0118 const QModelIndex &index) const 0119 { 0120 if (!index.isValid()) { 0121 return; 0122 } 0123 0124 QStyleOptionViewItem opt(option); 0125 opt.showDecorationSelected = true; 0126 const QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); 0127 paint(painter, *style, &opt, index); 0128 } 0129 0130 void KexiListViewDelegate::paint(QPainter *painter, const QStyle &style, 0131 QStyleOptionViewItem *option, 0132 const QModelIndex &index) const 0133 { 0134 int iconSize = style.pixelMetric(QStyle::PM_IconViewIconSize); 0135 const QString text = index.model()->data(index, Qt::DisplayRole).toString(); 0136 const QIcon icon = index.model()->data(index, Qt::DecorationRole).value<QIcon>(); 0137 QIcon::Mode iconMode; 0138 if (option->state & QStyle::State_Enabled && option->state & QStyle::State_Selected) { 0139 iconMode = QIcon::Selected; 0140 } else { 0141 iconMode = (option->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled; 0142 } 0143 const QPixmap pixmap = icon.pixmap(iconSize, iconSize, iconMode); 0144 QFontMetrics fm = painter->fontMetrics(); 0145 int wp = pixmap.width() / pixmap.devicePixelRatio(); 0146 int hp = pixmap.height() / pixmap.devicePixelRatio(); 0147 0148 QTextLayout iconTextLayout(text, option->font); 0149 QTextOption textOption(Qt::AlignHCenter); 0150 iconTextLayout.setTextOption(textOption); 0151 int maxWidth = qMax(3 * wp, 8 * fm.height()); 0152 layoutText(&iconTextLayout, maxWidth); 0153 0154 QPen pen = painter->pen(); 0155 QPalette::ColorGroup cg; 0156 if (option->state & QStyle::State_Enabled) { 0157 cg = (option->state & QStyle::State_Active) ? QPalette::Normal : QPalette::Inactive; 0158 } else { 0159 cg = QPalette::Disabled; 0160 option->state &= ~QStyle::State_MouseOver; 0161 } 0162 //qDebug() << hex << int(option->state) << text << int(iconMode) << cg; 0163 0164 style.drawPrimitive(QStyle::PE_PanelItemViewItem, option, painter, option->widget); 0165 if (option->state & QStyle::State_Selected) { 0166 painter->setPen(option->palette.color(cg, QPalette::HighlightedText)); 0167 } else { 0168 painter->setPen(option->palette.color(cg, QPalette::Text)); 0169 } 0170 0171 painter->drawPixmap(option->rect.x() + (option->rect.width() / 2) 0172 - (wp / 2), option->rect.y() + KEXILISTVIEW_VERTICAL_MARGIN, 0173 pixmap); 0174 if (!text.isEmpty()) { 0175 iconTextLayout.draw(painter, 0176 QPoint(option->rect.x() + (option->rect.width() / 2) 0177 - (maxWidth / 2), option->rect.y() + hp + KEXILISTVIEW_VERTICAL_MARGIN + 2)); 0178 } 0179 0180 painter->setPen(pen); 0181 drawFocus(painter, *option, option->rect); 0182 } 0183 0184 QSize KexiListViewDelegate::sizeHint(const QStyleOptionViewItem &option, 0185 const QModelIndex &index) const 0186 { 0187 if (!index.isValid()) { 0188 return QSize(0, 0); 0189 } 0190 0191 QStyleOptionViewItem opt(option); 0192 opt.showDecorationSelected = true; 0193 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); 0194 0195 int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize); 0196 const QString text = index.model()->data(index, Qt::DisplayRole).toString(); 0197 const QIcon icon = index.model()->data(index, Qt::DecorationRole).value<QIcon>(); 0198 const QPixmap pixmap = icon.pixmap(iconSize, iconSize); 0199 0200 QFontMetrics fm = option.fontMetrics; 0201 int gap = 0; //fm.height(); 0202 int wp = pixmap.width() / pixmap.devicePixelRatio(); 0203 int hp = pixmap.height() / pixmap.devicePixelRatio(); 0204 0205 if (hp == 0) { 0206 /** 0207 * No pixmap loaded yet, we'll use the default icon size in this case. 0208 */ 0209 hp = iconSize; 0210 wp = iconSize; 0211 } 0212 0213 QTextLayout iconTextLayout(text, option.font); 0214 int wt = layoutText(&iconTextLayout, qMax(3 * wp, 8 * fm.height())); 0215 int ht = iconTextLayout.boundingRect().height(); 0216 0217 int width, height; 0218 if (text.isEmpty()) { 0219 height = hp; 0220 } else { 0221 height = hp + ht + 2 * KEXILISTVIEW_VERTICAL_MARGIN; 0222 } 0223 0224 width = qMax(wt, wp) + gap; 0225 0226 return QSize(width, height); 0227 } 0228 0229 void KexiListViewDelegate::drawFocus(QPainter *painter, const QStyleOptionViewItem &option, 0230 const QRect &rect) const 0231 { 0232 if (option.state & QStyle::State_HasFocus) { 0233 QStyleOptionFocusRect o; 0234 o.QStyleOption::operator=(option); 0235 o.rect = rect; 0236 o.state |= QStyle::State_KeyboardFocusChange; 0237 QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) 0238 ? QPalette::Normal : QPalette::Disabled; 0239 o.backgroundColor = option.palette.color(cg, (option.state & QStyle::State_Selected) 0240 ? QPalette::Highlight : QPalette::Background); 0241 QApplication::style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter); 0242 } 0243 } 0244 0245 // ---- 0246 0247 KexiListViewSelectionModel::KexiListViewSelectionModel(QAbstractItemModel *model, QObject *parent) 0248 : QItemSelectionModel(model, parent) 0249 { 0250 } 0251 0252 void KexiListViewSelectionModel::clear() 0253 { 0254 // Don't allow the current selection to be cleared 0255 } 0256 0257 void KexiListViewSelectionModel::select(const QModelIndex &index, 0258 QItemSelectionModel::SelectionFlags command) 0259 { 0260 // Don't allow the current selection to be cleared 0261 if (!index.isValid() && (command & Clear || command & Deselect)) { 0262 return; 0263 } 0264 QItemSelectionModel::select(index, command); 0265 } 0266 0267 void KexiListViewSelectionModel::select(const QItemSelection &selection, 0268 QItemSelectionModel::SelectionFlags command) 0269 { 0270 // Don't allow the current selection to be cleared 0271 if (!selection.count() && (command & QItemSelectionModel::Clear)) { 0272 return; 0273 } 0274 QItemSelectionModel::select(selection, command); 0275 }