File indexing completed on 2024-04-14 14:53:45

0001 /* This file is part of the KDE project
0002    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
0003    Copyright (C) 2004 Alexander Dymo <cloudtemple@mskat.net>
0004    Copyright (C) 2004-2017 Jarosław Staniek <staniek@kde.org>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This library is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this library; see the file COPYING.LIB.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "KPropertyUtils.h"
0023 #include "KPropertyUtils_p.h"
0024 #include "KPropertyEditorDataModel_p.h"
0025 #include "KPropertyEditorView.h"
0026 
0027 #include <QPainter>
0028 #include <QPixmap>
0029 #include <QStyle>
0030 #include <QStyleOption>
0031 #include <QStyleOptionHeader>
0032 #include <QMouseEvent>
0033 #include <QVBoxLayout>
0034 #include <QPointer>
0035 #include <QMetaEnum>
0036 
0037 #define BRANCHBOX_SIZE 9
0038 
0039 //! @internal
0040 static void paintListViewExpander(QPainter* p, QWidget* w, int height, const QPalette& palette, bool isOpen)
0041 {
0042     const int marg = (height - 2 - BRANCHBOX_SIZE) / 2;
0043     int xmarg = marg;
0044 #if 0
0045 //! @todo disabled: kstyles do not paint background yet... reenable in the future...
0046     KStyle* kstyle = dynamic_cast<KStyle*>(widget->style());
0047     if (kstyle) {
0048         kstyle->drawKStylePrimitive(
0049             KStyle::KPE_ListViewExpander, p, w, QRect(xmarg, marg, BRANCHBOX_SIZE, BRANCHBOX_SIZE),
0050             cg, isOpen ? 0 : QStyle::Style_On,
0051             QStyleOption::Default);
0052     }
0053 #endif
0054         Q_UNUSED(w);
0055         //draw by hand
0056         p->setPen(KPropertyEditorView::defaultGridLineColor());
0057         p->drawRect(xmarg, marg, BRANCHBOX_SIZE, BRANCHBOX_SIZE);
0058         p->fillRect(xmarg + 1, marg + 1, BRANCHBOX_SIZE - 2, BRANCHBOX_SIZE - 2,
0059                     palette.brush(QPalette::Base));
0060         p->setPen(palette.color(QPalette::Foreground));
0061         p->drawLine(xmarg + 2, marg + BRANCHBOX_SIZE / 2, xmarg + BRANCHBOX_SIZE - 3, marg + BRANCHBOX_SIZE / 2);
0062         if (!isOpen) {
0063             p->drawLine(xmarg + BRANCHBOX_SIZE / 2, marg + 2,
0064                         xmarg + BRANCHBOX_SIZE / 2, marg + BRANCHBOX_SIZE - 3);
0065         }
0066 }
0067 
0068 //! @internal
0069 //! Based on KPopupTitle, see kpopupmenu.cpp
0070 class GroupWidgetBase : public QWidget
0071 {
0072 public:
0073     explicit GroupWidgetBase(QWidget* parent)
0074             : QWidget(parent)
0075             , m_isOpen(true)
0076             , m_mouseDown(false) {
0077         QSizePolicy sp(QSizePolicy::Preferred, QSizePolicy::Fixed);
0078         sp.setHorizontalStretch(0);
0079         sp.setVerticalStretch(1);
0080         setSizePolicy(sp);
0081     }
0082 
0083     void setText(const QString &text) {
0084         m_titleStr = text;
0085     }
0086 
0087     void setIcon(const QPixmap &pix) {
0088         m_miniicon = pix;
0089     }
0090 
0091     virtual bool isOpen() const {
0092         return m_isOpen;
0093     }
0094 
0095     virtual void setOpen(bool set) {
0096         m_isOpen = set;
0097     }
0098 
0099     QSize sizeHint() const override {
0100         QSize s(QWidget::sizeHint());
0101         s.setHeight(fontMetrics().height()*2);
0102         return s;
0103     }
0104 
0105 protected:
0106     void paintEvent(QPaintEvent *) override {
0107         QRect r(rect());
0108         QPainter p(this);
0109         QStyleOptionHeader option;
0110         option.initFrom(this);
0111         option.state = m_mouseDown ? QStyle::State_Sunken : QStyle::State_Raised;
0112         style()->drawControl(QStyle::CE_Header, &option, &p, this);
0113 
0114         paintListViewExpander(&p, this, r.height() + 2, palette(), isOpen());
0115         if (!m_miniicon.isNull()) {
0116             p.drawPixmap(24, (r.height() - m_miniicon.height()) / 2, m_miniicon);
0117         }
0118 
0119         if (!m_titleStr.isEmpty()) {
0120             int indent = 16 + (m_miniicon.isNull() ? 0 : (m_miniicon.width() + 4));
0121             p.setPen(palette().color(QPalette::Text));
0122             QFont f = p.font();
0123             f.setBold(true);
0124             p.setFont(f);
0125             p.drawText(indent + 8, 0, width() - (indent + 8),
0126                        height(), Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine,
0127                        m_titleStr);
0128         }
0129     }
0130 
0131     bool event(QEvent * e) override {
0132         if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease) {
0133             QMouseEvent* me = static_cast<QMouseEvent*>(e);
0134             if (me->button() == Qt::LeftButton) {
0135                 m_mouseDown = e->type() == QEvent::MouseButtonPress;
0136                 update();
0137             }
0138         }
0139         return QWidget::event(e);
0140     }
0141 
0142 protected:
0143     QString m_titleStr;
0144     QPixmap m_miniicon;
0145     bool m_isOpen;
0146     bool m_mouseDown;
0147 };
0148 
0149 /*    class GroupWidget : public GroupWidgetBase
0150     {
0151     public:
0152         explicit GroupWidget(EditorGroupItem *parentItem)
0153                 : GroupWidgetBase(parentItem->listView()->viewport())
0154                 , m_parentItem(parentItem) {
0155         }
0156 
0157         virtual bool isOpen() const {
0158             return m_parentItem->isOpen();
0159         }
0160 
0161     protected:
0162         EditorGroupItem *m_parentItem;
0163     };*/
0164 
0165 class Q_DECL_HIDDEN KPropertyGroupWidget::Private
0166 {
0167 public:
0168     Private() {}
0169     QVBoxLayout* lyr;
0170     GroupWidgetBase *groupWidget;
0171     QPointer<QWidget> contents;
0172 };
0173 
0174 KPropertyGroupWidget::KPropertyGroupWidget(const QString& title, QWidget* parent)
0175         : QWidget(parent)
0176         , d(new Private())
0177 {
0178     QSizePolicy sp(QSizePolicy::Preferred, QSizePolicy::Fixed);
0179     sp.setHorizontalStretch(0);
0180     sp.setVerticalStretch(1);
0181     setSizePolicy(sp);
0182     d->lyr = new QVBoxLayout(this);
0183     d->groupWidget = new GroupWidgetBase(this);
0184     d->groupWidget->setText(title);
0185     d->lyr->addWidget(d->groupWidget);
0186     d->lyr->addSpacing(4);
0187 }
0188 
0189 KPropertyGroupWidget::~KPropertyGroupWidget()
0190 {
0191     delete d;
0192 }
0193 
0194 void KPropertyGroupWidget::setContents(QWidget* contents)
0195 {
0196     if (d->contents) {
0197         d->contents->hide();
0198         d->lyr->removeWidget(d->contents);
0199         delete d->contents;
0200     }
0201     d->contents = contents;
0202     if (d->contents) {
0203         d->lyr->addWidget(d->contents);
0204         d->contents->show();
0205     }
0206     update();
0207 }
0208 
0209 bool KPropertyGroupWidget::event(QEvent * e)
0210 {
0211     if (e->type() == QEvent::MouseButtonPress) {
0212         QMouseEvent* me = static_cast<QMouseEvent*>(e);
0213         if (me->button() == Qt::LeftButton && d->contents && d->groupWidget->rect().contains(me->pos())) {
0214             d->groupWidget->setOpen(!d->groupWidget->isOpen());
0215             if (d->groupWidget->isOpen())
0216                 d->contents->show();
0217             else
0218                 d->contents->hide();
0219             d->lyr->invalidate();
0220             update();
0221         }
0222     }
0223     return QWidget::event(e);
0224 }
0225 
0226 QColor KPropertyUtilsPrivate::contrastColor(const QColor& c)
0227 {
0228     int g = qGray(c.rgb());
0229     if (g > 110)
0230         return c.dark(300);
0231     else if (g > 80)
0232         return c.light(250);
0233     else if (g > 20)
0234         return c.light(400);
0235     return Qt::lightGray;
0236 }
0237 
0238 QColor KPropertyUtilsPrivate::gridLineColor(const QWidget *widget)
0239 {
0240     Q_ASSERT(widget);
0241     KPropertyEditorView *view = nullptr;
0242     if (widget->parentWidget()) {
0243         view = qobject_cast<KPropertyEditorView*>(widget->parentWidget()->parentWidget());
0244     }
0245     return view ? view->gridLineColor() : QColor();
0246 }
0247 
0248 // -------------------
0249 
0250 KPROPERTYWIDGETS_EXPORT KProperty* KPropertyUtils::propertyForIndex(const QModelIndex &index)
0251 {
0252     const KPropertyEditorDataModel *editorModel
0253             = qobject_cast<const KPropertyEditorDataModel*>(index.model());
0254     return editorModel ? editorModel->propertyForIndex(index) : nullptr;
0255 }
0256 
0257 bool KPropertyUtilsPrivate::shouldUseNativeDialogs()
0258 {
0259 #if defined Q_OS_UNIX && !defined Q_OS_MACOS
0260     const QString xdgSessionDesktop = QString::fromLatin1(qgetenv("XDG_CURRENT_DESKTOP").trimmed());
0261     return xdgSessionDesktop.isEmpty()
0262         && 0 == xdgSessionDesktop.compare(QStringLiteral("KDE"), Qt::CaseInsensitive);
0263 #else
0264     return true;
0265 #endif
0266 }