File indexing completed on 2024-03-24 15:35:49

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2007-2008 Rafael Fernández López <ereslibre@kde.org>
0004     SPDX-FileCopyrightText: 2008 Kevin Ottens <ervin@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include <QAbstractItemView>
0010 #include <QApplication>
0011 #include <QDebug>
0012 #include <QLineEdit>
0013 #include <QListView>
0014 #include <QMainWindow>
0015 #include <QMenu>
0016 #include <QMessageBox>
0017 #include <QPaintEvent>
0018 #include <QPainter>
0019 #include <QPushButton>
0020 #include <QRadialGradient>
0021 #include <QStringListModel>
0022 #include <QToolButton>
0023 
0024 #include <kwidgetitemdelegate.h>
0025 
0026 #define HARDCODED_BORDER 10
0027 #define EQUALLY_SIZED_TOOLBUTTONS 1
0028 
0029 #if EQUALLY_SIZED_TOOLBUTTONS
0030 #include <QStyleOptionToolButton>
0031 #endif
0032 
0033 class TestWidget : public QWidget
0034 {
0035     Q_OBJECT
0036 
0037 public:
0038     TestWidget(QWidget *parent = nullptr)
0039         : QWidget(parent)
0040     {
0041         setMouseTracking(true);
0042         setAttribute(Qt::WA_Hover);
0043     }
0044 
0045     ~TestWidget() override
0046     {
0047     }
0048 
0049     QSize sizeHint() const override
0050     {
0051         return QSize(30, 30);
0052     }
0053 
0054 protected:
0055     void paintEvent(QPaintEvent *event) override
0056     {
0057         QPainter p(this);
0058 
0059         QRadialGradient radialGrad(QPointF(event->rect().width() / 2, event->rect().height() / 2), qMin(event->rect().width() / 2, event->rect().height() / 2));
0060 
0061         if (underMouse()) {
0062             radialGrad.setColorAt(0, Qt::green);
0063         } else {
0064             radialGrad.setColorAt(0, Qt::red);
0065         }
0066 
0067         radialGrad.setColorAt(1, Qt::transparent);
0068 
0069         p.fillRect(event->rect(), radialGrad);
0070 
0071         p.setPen(Qt::black);
0072         p.drawLine(0, 15, 30, 15);
0073         p.drawLine(15, 0, 15, 30);
0074 
0075         p.end();
0076     }
0077 
0078     bool event(QEvent *event) override
0079     {
0080         if (event->type() == QEvent::MouseButtonPress) {
0081             QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
0082 
0083             if (mouseEvent->pos().x() > 15 //
0084                 && mouseEvent->pos().y() < 15) {
0085                 qDebug() << "First quarter";
0086             } else if (mouseEvent->pos().x() < 15 //
0087                        && mouseEvent->pos().y() < 15) {
0088                 qDebug() << "Second quarter";
0089             } else if (mouseEvent->pos().x() < 15 //
0090                        && mouseEvent->pos().y() > 15) {
0091                 qDebug() << "Third quarter";
0092             } else {
0093                 qDebug() << "Forth quarter";
0094             }
0095         }
0096 
0097         return QWidget::event(event);
0098     }
0099 };
0100 
0101 class MyDelegate : public KWidgetItemDelegate
0102 {
0103     Q_OBJECT
0104 
0105 public:
0106     MyDelegate(QAbstractItemView *itemView, QObject *parent = nullptr)
0107         : KWidgetItemDelegate(itemView, parent)
0108     {
0109         for (int i = 0; i < 100; i++) {
0110             installed[i] = i % 5;
0111         }
0112     }
0113 
0114     ~MyDelegate() override
0115     {
0116     }
0117 
0118     QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
0119     {
0120         Q_UNUSED(option);
0121         Q_UNUSED(index);
0122 
0123         return sizeHint();
0124     }
0125 
0126     QSize sizeHint() const
0127     {
0128         return QSize(600, 60);
0129     }
0130 
0131     void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
0132     {
0133         Q_UNUSED(index);
0134         painter->save();
0135 
0136         itemView()->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, nullptr);
0137 
0138         if (option.state & QStyle::State_Selected) {
0139             painter->setPen(option.palette.highlightedText().color());
0140         }
0141 
0142         painter->restore();
0143     }
0144 
0145     QList<QWidget *> createItemWidgets(const QModelIndex &index) const override
0146     {
0147         Q_UNUSED(index);
0148         QPushButton *button = new QPushButton();
0149         QToolButton *toolButton = new QToolButton();
0150 
0151         setBlockedEventTypes(button, QList<QEvent::Type>() << QEvent::MouseButtonPress << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick);
0152 
0153         setBlockedEventTypes(toolButton, QList<QEvent::Type>() << QEvent::MouseButtonPress << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick);
0154 
0155         connect(button, SIGNAL(clicked(bool)), this, SLOT(mySlot()));
0156         connect(toolButton, SIGNAL(triggered(QAction *)), this, SLOT(mySlot2()));
0157         connect(toolButton, SIGNAL(clicked(bool)), this, SLOT(mySlot3()));
0158 
0159         return QList<QWidget *>() << button << new TestWidget() << new QLineEdit() << toolButton;
0160     }
0161 
0162     void updateItemWidgets(const QList<QWidget *> widgets, const QStyleOptionViewItem &option, const QPersistentModelIndex &index) const override
0163     {
0164         QPushButton *button = static_cast<QPushButton *>(widgets[0]);
0165         button->setText(QStringLiteral("Test me"));
0166         button->setIcon(QIcon::fromTheme(QStringLiteral("kde")));
0167         button->resize(button->sizeHint());
0168         button->move(HARDCODED_BORDER, sizeHint().height() / 2 - button->height() / 2);
0169 
0170         TestWidget *testWidget = static_cast<TestWidget *>(widgets[1]);
0171 
0172         testWidget->resize(testWidget->sizeHint());
0173         testWidget->move(2 * HARDCODED_BORDER + button->sizeHint().width(), //
0174                          sizeHint().height() / 2 - testWidget->size().height() / 2);
0175 
0176         // Hide the test widget when row can be divided by three
0177         testWidget->setVisible((index.row() % 3) != 0);
0178 
0179         QLineEdit *lineEdit = static_cast<QLineEdit *>(widgets[2]);
0180 
0181         lineEdit->setClearButtonEnabled(true);
0182         lineEdit->resize(lineEdit->sizeHint());
0183         lineEdit->move(3 * HARDCODED_BORDER + button->sizeHint().width() + testWidget->sizeHint().width(),
0184                        sizeHint().height() / 2 - lineEdit->size().height() / 2);
0185 
0186         QToolButton *toolButton = static_cast<QToolButton *>(widgets[3]);
0187 
0188         if (!toolButton->menu()) {
0189             QMenu *myMenu = new QMenu(toolButton);
0190             myMenu->addAction(QStringLiteral("Save"));
0191             myMenu->addAction(QStringLiteral("Load"));
0192             myMenu->addSeparator();
0193             myMenu->addAction(QStringLiteral("Close"));
0194             toolButton->setMenu(myMenu);
0195         }
0196 
0197         toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
0198         toolButton->setPopupMode(QToolButton::MenuButtonPopup);
0199 
0200         if (installed[index.row()]) {
0201             toolButton->setText(QStringLiteral("Uninstall"));
0202         } else {
0203             toolButton->setText(QStringLiteral("Install"));
0204         }
0205 
0206         toolButton->resize(toolButton->sizeHint());
0207 #if EQUALLY_SIZED_TOOLBUTTONS
0208         QStyleOptionToolButton toolButtonOpt;
0209         toolButtonOpt.initFrom(toolButton);
0210         toolButtonOpt.features = QStyleOptionToolButton::MenuButtonPopup;
0211         toolButtonOpt.arrowType = Qt::DownArrow;
0212         toolButtonOpt.toolButtonStyle = Qt::ToolButtonTextBesideIcon;
0213 
0214         toolButtonOpt.text = "Install";
0215         int widthInstall = QApplication::style()
0216                                ->sizeFromContents(QStyle::CT_ToolButton,
0217                                                   &toolButtonOpt,
0218                                                   QSize(option.fontMetrics.boundingRect(QStringLiteral("Install")).width() + HARDCODED_BORDER * 3,
0219                                                         option.fontMetrics.height()),
0220                                                   toolButton)
0221                                .width();
0222         toolButtonOpt.text = "Uninstall";
0223         int widthUninstall = QApplication::style()
0224                                  ->sizeFromContents(QStyle::CT_ToolButton,
0225                                                     &toolButtonOpt,
0226                                                     QSize(option.fontMetrics.boundingRect(QStringLiteral("Uninstall")).width() + HARDCODED_BORDER * 3,
0227                                                           option.fontMetrics.height()),
0228                                                     toolButton)
0229                                  .width();
0230 
0231         QSize size = toolButton->sizeHint();
0232         size.setWidth(qMax(widthInstall, widthUninstall));
0233         toolButton->resize(size);
0234 #endif
0235         toolButton->move(option.rect.width() - toolButton->size().width() - HARDCODED_BORDER, //
0236                          sizeHint().height() / 2 - toolButton->size().height() / 2);
0237 
0238         // Eat more space
0239         lineEdit->resize(option.rect.width() - toolButton->width() - testWidget->width() - button->width() - 5 * HARDCODED_BORDER, lineEdit->height());
0240     }
0241 
0242 private Q_SLOTS:
0243     void mySlot()
0244     {
0245         QMessageBox::information(nullptr, QStringLiteral("Button clicked"), QStringLiteral("The button in row %1 was clicked").arg(focusedIndex().row()));
0246     }
0247 
0248     void mySlot2()
0249     {
0250         QMessageBox::information(nullptr,
0251                                  QStringLiteral("Toolbutton menu item clicked"),
0252                                  QStringLiteral("A menu item was triggered in row %1").arg(focusedIndex().row()));
0253     }
0254 
0255     void mySlot3()
0256     {
0257         bool isInstalled = installed[focusedIndex().row()];
0258         installed[focusedIndex().row()] = !isInstalled;
0259         const_cast<QAbstractItemModel *>(focusedIndex().model())->setData(focusedIndex(), QStringLiteral("makemodelbeupdated"));
0260     }
0261 
0262 private:
0263     bool installed[100];
0264 };
0265 
0266 int main(int argc, char **argv)
0267 {
0268     QApplication app(argc, argv);
0269 
0270     QMainWindow *mainWindow = new QMainWindow();
0271     mainWindow->setMinimumSize(640, 480);
0272     QListView *listView = new QListView();
0273     QStringListModel *model = new QStringListModel();
0274 
0275     model->insertRows(0, 100);
0276     for (int i = 0; i < 100; ++i) {
0277         model->setData(model->index(i, 0), QString("Test " + QString::number(i)), Qt::DisplayRole);
0278     }
0279 
0280     listView->setModel(model);
0281     MyDelegate *myDelegate = new MyDelegate(listView);
0282     listView->setItemDelegate(myDelegate);
0283     listView->setVerticalScrollMode(QListView::ScrollPerPixel);
0284 
0285     mainWindow->setCentralWidget(listView);
0286 
0287     mainWindow->show();
0288 
0289     model->removeRows(0, 95);
0290 
0291     return app.exec();
0292 }
0293 
0294 #include "kwidgetitemdelegatetest.moc"