File indexing completed on 2024-05-12 16:40:55
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 <QPainter> 0029 #include <QTextLayout> 0030 0031 const int KEXILISTVIEW_VERTICAL_MARGIN = 10; 0032 const int KEXILISTVIEW_HORIZONTAL_MARGIN = 12; 0033 0034 KexiListView::KexiListView(QWidget *parent) 0035 : QListView(parent) 0036 { 0037 setViewMode(QListView::ListMode); 0038 setMovement(QListView::Static); 0039 setVerticalScrollMode(QListView::ScrollPerPixel); 0040 setItemDelegate(new KexiListViewDelegate(this)); 0041 } 0042 0043 KexiListView::~KexiListView() 0044 { 0045 } 0046 0047 void KexiListView::setModel(QAbstractItemModel *model) 0048 { 0049 /* 0050 KPageListViewProxy *proxy = new KPageListViewProxy( this ); 0051 proxy->setSourceModel( model ); 0052 proxy->rebuildMap(); 0053 0054 connect( model, SIGNAL(layoutChanged()), proxy, SLOT(rebuildMap()) ); 0055 */ 0056 connect(model, SIGNAL(layoutChanged()), this, SLOT(updateWidth())); 0057 0058 // QListView::setModel( proxy ); 0059 QListView::setModel(model); 0060 0061 // Set our own selection model, which won't allow our current selection to be cleared 0062 setSelectionModel(new KexiListViewSelectionModel(model, this)); 0063 0064 updateWidth(); 0065 } 0066 0067 void KexiListView::updateWidth() 0068 { 0069 if (!model()) { 0070 return; 0071 } 0072 0073 int rows = model()->rowCount(); 0074 0075 int width = 0; 0076 for (int i = 0; i < rows; ++i) { 0077 width = qMax(width, sizeHintForIndex(model()->index(i, 0)).width()); 0078 } 0079 0080 setFixedWidth(width + KEXILISTVIEW_HORIZONTAL_MARGIN * 2); 0081 } 0082 0083 // ---- 0084 0085 KexiListViewDelegate::KexiListViewDelegate(QObject *parent) 0086 : QAbstractItemDelegate(parent) 0087 { 0088 } 0089 0090 static int layoutText(QTextLayout *layout, int maxWidth) 0091 { 0092 qreal height = 0; 0093 int textWidth = 0; 0094 layout->beginLayout(); 0095 while (true) { 0096 QTextLine line = layout->createLine(); 0097 if (!line.isValid()) { 0098 break; 0099 } 0100 line.setLineWidth(maxWidth); 0101 line.setPosition(QPointF(0, height)); 0102 height += line.height(); 0103 textWidth = qMax(textWidth, qRound(line.naturalTextWidth() + 0.5)); 0104 } 0105 layout->endLayout(); 0106 return textWidth; 0107 } 0108 0109 void KexiListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, 0110 const QModelIndex &index) const 0111 { 0112 if (!index.isValid()) { 0113 return; 0114 } 0115 0116 QStyleOptionViewItem opt(option); 0117 opt.showDecorationSelected = true; 0118 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); 0119 0120 int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize); 0121 const QString text = index.model()->data(index, Qt::DisplayRole).toString(); 0122 const QIcon icon = index.model()->data(index, Qt::DecorationRole).value<QIcon>(); 0123 const QPixmap pixmap = icon.pixmap(iconSize, iconSize, 0124 (option.state & QStyle::State_Selected) ? QIcon::Selected : QIcon::Normal); 0125 0126 QFontMetrics fm = painter->fontMetrics(); 0127 int wp = pixmap.width() / pixmap.devicePixelRatio(); 0128 int hp = pixmap.height() / pixmap.devicePixelRatio(); 0129 0130 QTextLayout iconTextLayout(text, option.font); 0131 QTextOption textOption(Qt::AlignHCenter); 0132 iconTextLayout.setTextOption(textOption); 0133 int maxWidth = qMax(3 * wp, 8 * fm.height()); 0134 layoutText(&iconTextLayout, maxWidth); 0135 0136 QPen pen = painter->pen(); 0137 QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) 0138 ? QPalette::Normal : QPalette::Disabled; 0139 if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) { 0140 cg = QPalette::Inactive; 0141 } 0142 0143 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); 0144 if (option.state & QStyle::State_Selected) { 0145 painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); 0146 } else { 0147 painter->setPen(option.palette.color(cg, QPalette::Text)); 0148 } 0149 0150 painter->drawPixmap(option.rect.x() + (option.rect.width() / 2) 0151 - (wp / 2), option.rect.y() + KEXILISTVIEW_VERTICAL_MARGIN, 0152 pixmap); 0153 if (!text.isEmpty()) { 0154 iconTextLayout.draw(painter, 0155 QPoint(option.rect.x() + (option.rect.width() / 2) 0156 - (maxWidth / 2), option.rect.y() + hp + KEXILISTVIEW_VERTICAL_MARGIN + 2)); 0157 } 0158 0159 painter->setPen(pen); 0160 0161 drawFocus(painter, option, option.rect); 0162 } 0163 0164 QSize KexiListViewDelegate::sizeHint(const QStyleOptionViewItem &option, 0165 const QModelIndex &index) const 0166 { 0167 if (!index.isValid()) { 0168 return QSize(0, 0); 0169 } 0170 0171 QStyleOptionViewItem opt(option); 0172 opt.showDecorationSelected = true; 0173 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); 0174 0175 int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize); 0176 const QString text = index.model()->data(index, Qt::DisplayRole).toString(); 0177 const QIcon icon = index.model()->data(index, Qt::DecorationRole).value<QIcon>(); 0178 const QPixmap pixmap = icon.pixmap(iconSize, iconSize); 0179 0180 QFontMetrics fm = option.fontMetrics; 0181 int gap = 0; //fm.height(); 0182 int wp = pixmap.width() / pixmap.devicePixelRatio(); 0183 int hp = pixmap.height() / pixmap.devicePixelRatio(); 0184 0185 if (hp == 0) { 0186 /** 0187 * No pixmap loaded yet, we'll use the default icon size in this case. 0188 */ 0189 hp = iconSize; 0190 wp = iconSize; 0191 } 0192 0193 QTextLayout iconTextLayout(text, option.font); 0194 int wt = layoutText(&iconTextLayout, qMax(3 * wp, 8 * fm.height())); 0195 int ht = iconTextLayout.boundingRect().height(); 0196 0197 int width, height; 0198 if (text.isEmpty()) { 0199 height = hp; 0200 } else { 0201 height = hp + ht + 2 * KEXILISTVIEW_VERTICAL_MARGIN; 0202 } 0203 0204 width = qMax(wt, wp) + gap; 0205 0206 return QSize(width, height); 0207 } 0208 0209 void KexiListViewDelegate::drawFocus(QPainter *painter, const QStyleOptionViewItem &option, 0210 const QRect &rect) const 0211 { 0212 if (option.state & QStyle::State_HasFocus) { 0213 QStyleOptionFocusRect o; 0214 o.QStyleOption::operator=(option); 0215 o.rect = rect; 0216 o.state |= QStyle::State_KeyboardFocusChange; 0217 QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) 0218 ? QPalette::Normal : QPalette::Disabled; 0219 o.backgroundColor = option.palette.color(cg, (option.state & QStyle::State_Selected) 0220 ? QPalette::Highlight : QPalette::Background); 0221 QApplication::style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter); 0222 } 0223 } 0224 0225 // ---- 0226 0227 KexiListViewSelectionModel::KexiListViewSelectionModel(QAbstractItemModel *model, QObject *parent) 0228 : QItemSelectionModel(model, parent) 0229 { 0230 } 0231 0232 void KexiListViewSelectionModel::clear() 0233 { 0234 // Don't allow the current selection to be cleared 0235 } 0236 0237 void KexiListViewSelectionModel::select(const QModelIndex &index, 0238 QItemSelectionModel::SelectionFlags command) 0239 { 0240 // Don't allow the current selection to be cleared 0241 if (!index.isValid() && (command & QItemSelectionModel::Clear)) { 0242 return; 0243 } 0244 QItemSelectionModel::select(index, command); 0245 } 0246 0247 void KexiListViewSelectionModel::select(const QItemSelection &selection, 0248 QItemSelectionModel::SelectionFlags command) 0249 { 0250 // Don't allow the current selection to be cleared 0251 if (!selection.count() && (command & QItemSelectionModel::Clear)) { 0252 return; 0253 } 0254 QItemSelectionModel::select(selection, command); 0255 }