File indexing completed on 2024-05-12 16:43:55

0001 /*
0002     SPDX-FileCopyrightText: 2015-2018 Thomas Baumgart <tbaumgart@kde.org>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "widgethintframe.h"
0007 
0008 // ----------------------------------------------------------------------------
0009 // QT Includes
0010 
0011 #include <QEvent>
0012 #include <QMoveEvent>
0013 
0014 // ----------------------------------------------------------------------------
0015 // KDE Includes
0016 
0017 // ----------------------------------------------------------------------------
0018 // Project Includes
0019 
0020 class WidgetHintFrameCollection::Private
0021 {
0022 public:
0023     QList<QWidget*>           widgetList;
0024     QList<WidgetHintFrame*>   frameList;
0025 };
0026 
0027 WidgetHintFrameCollection::WidgetHintFrameCollection(QObject* parent)
0028     : QObject(parent)
0029     , d(new Private)
0030 {
0031 }
0032 
0033 WidgetHintFrameCollection::~WidgetHintFrameCollection()
0034 {
0035     delete d;
0036 }
0037 
0038 void WidgetHintFrameCollection::addFrame(WidgetHintFrame* frame)
0039 {
0040     if(!d->frameList.contains(frame)) {
0041         connect(frame, &QObject::destroyed, this, &WidgetHintFrameCollection::frameDestroyed);
0042         connect(frame, &WidgetHintFrame::changed, this, [=] { QMetaObject::invokeMethod(this, "updateWidgets", Qt::QueuedConnection); });
0043         d->frameList.append(frame);
0044     }
0045 }
0046 
0047 void WidgetHintFrameCollection::addWidget(QWidget* w)
0048 {
0049     if(!d->widgetList.contains(w)) {
0050         d->widgetList.append(w);
0051         updateWidgets();
0052     }
0053 }
0054 
0055 void WidgetHintFrameCollection::removeWidget(QWidget* w)
0056 {
0057     d->widgetList.removeAll(w);
0058     w->setEnabled(true);
0059 }
0060 
0061 void WidgetHintFrameCollection::frameDestroyed(QObject* o)
0062 {
0063     WidgetHintFrame* frame = qobject_cast< WidgetHintFrame* >(o);
0064     if(frame) {
0065         d->frameList.removeAll(frame);
0066     }
0067 }
0068 
0069 void WidgetHintFrameCollection::updateWidgets()
0070 {
0071     bool enabled = true;
0072     Q_FOREACH(WidgetHintFrame* frame, d->frameList) {
0073         enabled &= !frame->isErroneous();
0074         if(!enabled) {
0075             break;
0076         }
0077     }
0078 
0079     Q_FOREACH(QWidget* w, d->widgetList) {
0080         w->setEnabled(enabled);
0081     }
0082 }
0083 
0084 
0085 
0086 
0087 
0088 
0089 
0090 class WidgetHintFrame::Private
0091 {
0092 public:
0093     QWidget*    editWidget;
0094     bool        status;
0095     FrameStyle  style;
0096 };
0097 
0098 WidgetHintFrame::WidgetHintFrame(QWidget* editWidget, FrameStyle style, Qt::WindowFlags f)
0099     : QFrame(editWidget->parentWidget(), f)
0100     , d(new Private)
0101 {
0102     d->editWidget = 0;
0103     d->status = false;
0104     d->style = style;
0105     switch(style) {
0106     case Error:
0107         setStyleSheet("QFrame { background-color: none; padding: 1px; border: 2px solid red; border-radius: 4px; }");
0108         break;
0109     case Warning:
0110     case Info:
0111         setStyleSheet("QFrame { background-color: none; padding: 1px; border: 2px dashed red; border-radius: 4px; }");
0112         break;
0113     }
0114     attachToWidget(editWidget);
0115 }
0116 
0117 WidgetHintFrame::~WidgetHintFrame()
0118 {
0119     delete d;
0120 }
0121 
0122 bool WidgetHintFrame::isErroneous() const
0123 {
0124     return (d->style == Error) && (d->status == true);
0125 }
0126 
0127 static WidgetHintFrame* frame(QWidget* editWidget)
0128 {
0129     QList<WidgetHintFrame*> allErrorFrames = editWidget->parentWidget()->findChildren<WidgetHintFrame*>();
0130     QList<WidgetHintFrame*>::const_iterator it;
0131     foreach(WidgetHintFrame* f, allErrorFrames) {
0132         if(f->editWidget() == editWidget) {
0133             return f;
0134         }
0135     }
0136     return 0;
0137 }
0138 
0139 
0140 void WidgetHintFrame::show(QWidget* editWidget, const QString& tooltip)
0141 {
0142     WidgetHintFrame* f = frame(editWidget);
0143     if(f) {
0144         f->QWidget::show();
0145         f->d->status = true;
0146         emit f->changed();
0147     }
0148     if(!tooltip.isNull())
0149         editWidget->setToolTip(tooltip);
0150 }
0151 
0152 void WidgetHintFrame::hide(QWidget* editWidget, const QString& tooltip)
0153 {
0154     WidgetHintFrame* f = frame(editWidget);
0155     if(f) {
0156         f->QWidget::hide();
0157         f->d->status = false;
0158         emit f->changed();
0159     }
0160     if(!tooltip.isNull())
0161         editWidget->setToolTip(tooltip);
0162 }
0163 
0164 QWidget* WidgetHintFrame::editWidget() const
0165 {
0166     return d->editWidget;
0167 }
0168 
0169 void WidgetHintFrame::detachFromWidget()
0170 {
0171     if(d->editWidget) {
0172         d->editWidget->removeEventFilter(this);
0173         d->editWidget = 0;
0174     }
0175 }
0176 
0177 void WidgetHintFrame::attachToWidget(QWidget* w)
0178 {
0179     // detach first
0180     detachFromWidget();
0181     if(w) {
0182         d->editWidget = w;
0183         // make sure we receive changes in position and size
0184         w->installEventFilter(this);
0185         // place frame around widget
0186         move(w->pos() - QPoint(2, 2));
0187         resize(w->width()+4, w->height()+4);
0188         // make sure widget is on top of frame
0189         w->raise();
0190         // and hide frame for now
0191         QWidget::hide();
0192     }
0193 }
0194 
0195 bool WidgetHintFrame::eventFilter(QObject* o, QEvent* e)
0196 {
0197     if(o == d->editWidget) {
0198         QMoveEvent* mev = 0;
0199         QResizeEvent* sev = 0;
0200         switch(e->type()) {
0201         case QEvent::EnabledChange:
0202         case QEvent::Hide:
0203         case QEvent::Show:
0204             /**
0205              * @todo think about what to do when widget is enabled/disabled
0206              * hidden or shown
0207              */
0208             break;
0209 
0210         case QEvent::Move:
0211             mev = static_cast<QMoveEvent*>(e);
0212             move(mev->pos() - QPoint(2, 2));
0213             break;
0214 
0215         case QEvent::Resize:
0216             sev = static_cast<QResizeEvent*>(e);
0217             resize(sev->size().width()+4, sev->size().height()+4);
0218             break;
0219         default:
0220             break;
0221         }
0222     }
0223     return QObject::eventFilter(o, e);
0224 }