File indexing completed on 2024-04-21 16:29:35
0001 /* 0002 * Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde@gmail.com> 0003 * Copyright (C) 2008-2011 Daniel Nicoletti <dantti12@gmail.com> 0004 * 0005 * This program is free software; you can redistribute it and/or modify 0006 * it under the terms of the GNU Library/Lesser General Public License 0007 * version 2, or (at your option) any later version, as published by the 0008 * Free Software Foundation 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details 0014 * 0015 * You should have received a copy of the GNU Library/Lesser General Public 0016 * License along with this program; if not, write to the 0017 * Free Software Foundation, Inc., 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "ApplicationsDelegate.h" 0022 0023 #include <QLoggingCategory> 0024 #include <KLocalizedString> 0025 #include <QPushButton> 0026 #include <QApplication> 0027 0028 #include <QPainter> 0029 #include <QMouseEvent> 0030 0031 #include "PackageModel.h" 0032 #include "PkIcons.h" 0033 0034 #define UNIVERSAL_PADDING 4 0035 #define FADE_LENGTH 16 0036 0037 using namespace PackageKit; 0038 0039 ApplicationsDelegate::ApplicationsDelegate(QAbstractItemView *parent) 0040 : QStyledItemDelegate(parent), 0041 m_viewport(parent->viewport()), 0042 // loads it here to be faster when displaying items 0043 m_installIcon(QIcon::fromTheme(QLatin1String("go-down"))), 0044 m_installString(i18n("Install")), 0045 m_removeIcon(QIcon::fromTheme(QLatin1String("edit-delete"))), 0046 m_removeString(i18n("Remove")), 0047 m_undoIcon(QIcon::fromTheme(QLatin1String("edit-undo"))), 0048 m_undoString(i18n("Deselect")), 0049 m_checkedIcon(QIcon::fromTheme(QLatin1String("dialog-ok"))) 0050 { 0051 m_viewport->setAttribute(Qt::WA_Hover, true); 0052 QPushButton button, button2; 0053 button.setText(m_installString); 0054 button.setIcon(m_installIcon); 0055 button2.setText(m_removeString); 0056 button2.setIcon(m_removeIcon); 0057 m_buttonSize = button.sizeHint(); 0058 int width = qMax(button.sizeHint().width(), button2.sizeHint().width()); 0059 button.setText(m_undoString); 0060 width = qMax(width, button2.sizeHint().width()); 0061 m_buttonSize.setWidth(width); 0062 m_buttonIconSize = button.iconSize(); 0063 } 0064 0065 void ApplicationsDelegate::paint(QPainter *painter, 0066 const QStyleOptionViewItem &option, 0067 const QModelIndex &index) const 0068 { 0069 if (!index.isValid()) { 0070 return; 0071 } 0072 0073 // Button height 0074 int btHeight = m_buttonSize.height() + UNIVERSAL_PADDING; 0075 if (index.column() == PackageModel::VersionCol || 0076 index.column() == PackageModel::CurrentVersionCol || 0077 index.column() == PackageModel::ArchCol || 0078 index.column() == PackageModel::OriginCol || 0079 index.column() == PackageModel::SizeCol) { 0080 QStyleOptionViewItem opt(option); 0081 if (opt.state & QStyle::State_HasFocus) { 0082 opt.state ^= QStyle::State_HasFocus; 0083 } 0084 painter->save(); 0085 QStyledItemDelegate::paint(painter, opt, index); 0086 painter->restore(); 0087 return; 0088 } else if (index.column() == PackageModel::NameCol) { 0089 bool leftToRight = (painter->layoutDirection() == Qt::LeftToRight); 0090 QStyleOptionViewItem opt1(option); 0091 if (opt1.state & QStyle::State_HasFocus) { 0092 opt1.state ^= QStyle::State_HasFocus; 0093 } 0094 QSize size = QStyledItemDelegate::sizeHint(opt1, index); 0095 if (leftToRight) { 0096 opt1.rect.setRight(size.width()); 0097 } else { 0098 opt1.rect.setLeft(option.rect.left() + (option.rect.width() - size.width())); 0099 } 0100 painter->save(); 0101 QStyledItemDelegate::paint(painter, opt1, index); 0102 painter->restore(); 0103 0104 // a new option for the summary 0105 QStyleOptionViewItem opt(option); 0106 if (leftToRight) { 0107 opt.rect.setLeft(size.width() + 1); 0108 } else { 0109 opt.rect.setRight(option.rect.left() + (option.rect.width() - size.width()) - 1); 0110 } 0111 0112 QPixmap pixmap(opt.rect.size()); 0113 pixmap.fill(Qt::transparent); 0114 QPainter p(&pixmap); 0115 if (!p.isActive()) { 0116 return; // TODO test if this fixes warnigns 0117 } 0118 p.translate(-opt.rect.topLeft()); 0119 0120 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); 0121 opt.viewItemPosition = QStyleOptionViewItem::Middle; 0122 painter->save(); 0123 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); 0124 painter->restore(); 0125 0126 int left = opt.rect.left(); 0127 int width = opt.rect.width(); 0128 0129 QString pkgSummary = index.data(PackageModel::SummaryRole).toString(); 0130 if (!pkgSummary.isEmpty()) { 0131 if (leftToRight) { 0132 pkgSummary.prepend(QLatin1String("- ")); 0133 } else { 0134 pkgSummary.append(QLatin1String(" -")); 0135 } 0136 } 0137 0138 // store the original opacity 0139 qreal opa = p.opacity(); 0140 QStyleOptionViewItem local_option_normal(opt); 0141 QColor foregroundColor; 0142 0143 p.setOpacity(0.75); 0144 if (opt.state.testFlag(QStyle::State_Selected)) { 0145 foregroundColor = opt.palette.color(QPalette::HighlightedText); 0146 } else { 0147 foregroundColor = opt.palette.color(QPalette::Text); 0148 } 0149 0150 p.setFont(local_option_normal.font); 0151 p.setPen(foregroundColor); 0152 p.drawText(opt.rect, Qt::AlignVCenter | (leftToRight ? Qt::AlignLeft : Qt::AlignRight), pkgSummary); 0153 p.setOpacity(opa); 0154 0155 QLinearGradient gradient; 0156 // Gradient part of the background - fading of the text at the end 0157 if (leftToRight) { 0158 gradient = QLinearGradient(left + width - UNIVERSAL_PADDING - FADE_LENGTH, 0159 0, 0160 left + width - UNIVERSAL_PADDING, 0161 0); 0162 gradient.setColorAt(0, Qt::white); 0163 gradient.setColorAt(1, Qt::transparent); 0164 } else { 0165 gradient = QLinearGradient(left + UNIVERSAL_PADDING, 0166 0, 0167 left + UNIVERSAL_PADDING + FADE_LENGTH, 0168 0); 0169 gradient.setColorAt(0, Qt::transparent); 0170 gradient.setColorAt(1, Qt::white); 0171 } 0172 0173 QRect paintRect = opt.rect; 0174 p.setCompositionMode(QPainter::CompositionMode_DestinationIn); 0175 p.fillRect(paintRect, gradient); 0176 0177 if (leftToRight) { 0178 gradient.setStart(left + width 0179 - (UNIVERSAL_PADDING) - FADE_LENGTH, 0); 0180 gradient.setFinalStop(left + width 0181 - (UNIVERSAL_PADDING), 0); 0182 } else { 0183 gradient.setStart(left + UNIVERSAL_PADDING 0184 + (UNIVERSAL_PADDING ), 0); 0185 gradient.setFinalStop(left + UNIVERSAL_PADDING 0186 + (UNIVERSAL_PADDING) + FADE_LENGTH, 0); 0187 } 0188 paintRect.setHeight(btHeight); 0189 p.fillRect(paintRect, gradient); 0190 p.setCompositionMode(QPainter::CompositionMode_SourceOver); 0191 p.end(); 0192 0193 painter->drawPixmap(opt.rect.topLeft(), pixmap); 0194 return; 0195 } else if (index.column() == PackageModel::ActionCol) { 0196 bool pkgChecked = index.data(PackageModel::CheckStateRole).toBool(); 0197 QStyleOptionViewItem opt(option); 0198 if (opt.state & QStyle::State_HasFocus) { 0199 opt.state ^= QStyle::State_HasFocus; 0200 } 0201 0202 // Do not draw if the line is not selected or the mouse is over it 0203 if (!(option.state & QStyle::State_MouseOver) && 0204 !(option.state & QStyle::State_Selected) && 0205 !pkgChecked) { 0206 QStyledItemDelegate::paint(painter, opt, index); 0207 return; 0208 } 0209 0210 QStyledItemDelegate::paint(painter, opt, index); 0211 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); 0212 0213 QStyleOptionButton optBt; 0214 optBt.rect = option.rect; 0215 0216 Transaction::Info info; 0217 info = index.data(PackageModel::InfoRole).value<Transaction::Info>(); 0218 bool pkgInstalled = (info == Transaction::InfoInstalled || 0219 info == Transaction::InfoCollectionInstalled); 0220 0221 // Calculate the top of the button which is the item height - the button height size divided by 2 0222 // this give us a little value which is the top and bottom margin 0223 optBt.rect.setLeft(optBt.rect.left() + UNIVERSAL_PADDING / 2); 0224 optBt.rect.setTop(optBt.rect.top() + ((btHeight - m_buttonSize.height()) / 2)); 0225 optBt.rect.setSize(m_buttonSize); // the width and height sizes of the button 0226 0227 if (option.state & QStyle::State_Selected) { 0228 optBt.palette.setColor(QPalette::WindowText, option.palette.color(QPalette::HighlightedText)); 0229 } 0230 0231 optBt.features = QStyleOptionButton::Flat; 0232 optBt.iconSize = m_buttonIconSize; 0233 if (pkgChecked) { 0234 optBt.state |= QStyle::State_Sunken | QStyle::State_Active | QStyle::State_Enabled;; 0235 } else { 0236 if (option.state & QStyle::State_MouseOver) { 0237 optBt.state |= QStyle::State_MouseOver; 0238 } 0239 optBt.state |= QStyle::State_Raised | QStyle::State_Active | QStyle::State_Enabled; 0240 } 0241 optBt.icon = pkgInstalled ? m_removeIcon : m_installIcon; 0242 optBt.text = pkgInstalled ? m_removeString : m_installString; 0243 0244 style->drawControl(QStyle::CE_PushButton, &optBt, painter); 0245 return; 0246 } 0247 } 0248 0249 bool ApplicationsDelegate::insideButton(const QRect &rect, const QPoint &pos) const 0250 { 0251 // kDebug() << rect << pos; 0252 if ((pos.x() >= rect.x() && (pos.x() <= rect.x() + rect.width())) && 0253 (pos.y() >= rect.y() && (pos.y() <= rect.y() + rect.height()))) { 0254 return true; 0255 } 0256 return false; 0257 } 0258 0259 bool ApplicationsDelegate::editorEvent(QEvent *event, 0260 QAbstractItemModel *model, 0261 const QStyleOptionViewItem &option, 0262 const QModelIndex &index) 0263 { 0264 bool setData = false; 0265 if (index.column() == PackageModel::ActionCol && 0266 event->type() == QEvent::MouseButtonPress) { 0267 setData = true; 0268 } 0269 0270 const QWidget *widget = nullptr; 0271 if (const QStyleOptionViewItem *v = qstyleoption_cast<const QStyleOptionViewItem *>(&option)) { 0272 widget = v->widget; 0273 } 0274 0275 QStyle *style = widget ? widget->style() : QApplication::style(); 0276 0277 // make sure that we have the right event type 0278 if ((event->type() == QEvent::MouseButtonRelease) 0279 || (event->type() == QEvent::MouseButtonDblClick)) { 0280 QStyleOptionViewItem viewOpt(option); 0281 initStyleOption(&viewOpt, index); 0282 QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &viewOpt, widget); 0283 QMouseEvent *me = static_cast<QMouseEvent*>(event); 0284 if (me->button() != Qt::LeftButton || !checkRect.contains(me->pos())) 0285 return false; 0286 0287 // eat the double click events inside the check rect 0288 if (event->type() == QEvent::MouseButtonDblClick) 0289 return true; 0290 0291 setData = true; 0292 } else if (event->type() == QEvent::KeyPress) { 0293 if (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Space 0294 || static_cast<QKeyEvent*>(event)->key() == Qt::Key_Select) { 0295 setData = true; 0296 } 0297 } 0298 0299 if (setData) { 0300 return model->setData(index, 0301 !index.data(PackageModel::CheckStateRole).toBool(), 0302 Qt::CheckStateRole); 0303 } 0304 return false; 0305 } 0306 0307 void ApplicationsDelegate::setCheckable(bool checkable) 0308 { 0309 m_checkable = checkable; 0310 } 0311 0312 QSize ApplicationsDelegate::sizeHint(const QStyleOptionViewItem &option, 0313 const QModelIndex &index) const 0314 { 0315 QSize size; 0316 // kDebug() << index; 0317 if (index.column() == PackageModel::ActionCol) { 0318 size = m_buttonSize; 0319 size.rheight() += UNIVERSAL_PADDING; 0320 size.rwidth() += UNIVERSAL_PADDING; 0321 } else { 0322 QFontMetrics metric = QFontMetrics(option.font); 0323 // Button size is always bigger than text (since it has text in it 0324 size.setHeight(m_buttonSize.height() + UNIVERSAL_PADDING); 0325 size.setWidth(metric.width(index.data().toString())); 0326 if (index.column() == PackageModel::NameCol) { 0327 if (m_checkable) { 0328 const QStyle *style = QApplication::style(); 0329 QRect rect = style->subElementRect(QStyle::SE_CheckBoxIndicator, &option); 0330 // Adds the icon size AND the checkbox size 0331 // [ x ] (icon) Text 0332 size.rwidth() += 4 * UNIVERSAL_PADDING + 46 + rect.width(); 0333 // return QStyledItemDelegate::sizeHint(option, index); 0334 } else { 0335 // Adds the icon size 0336 size.rwidth() += 3 * UNIVERSAL_PADDING + 44; 0337 } 0338 } else { 0339 size.rwidth() += 2 * UNIVERSAL_PADDING; 0340 } 0341 } 0342 return size; 0343 } 0344 0345 #include "moc_ApplicationsDelegate.cpp"