File indexing completed on 2024-05-12 16:02:12

0001 /* This file is part of the KDE project
0002  *
0003  * SPDX-FileCopyrightText: 2010-2011 C. Boemann <cbo@boemann.dk>
0004  * SPDX-FileCopyrightText: 2005-2006 Boudewijn Rempt <boud@valdyas.org>
0005  * SPDX-FileCopyrightText: 2006 Thomas Zander <zander@kde.org>
0006  *
0007  * SPDX-License-Identifier: LGPL-2.0-or-later
0008  */
0009 #include "KoToolDocker.h"
0010 
0011 #include <klocalizedstring.h>
0012 
0013 #include <QApplication>
0014 #include <QBoxLayout>
0015 #include <QGridLayout>
0016 #include <QLabel>
0017 #include <QScrollArea>
0018 #include <QScroller>
0019 
0020 class Q_DECL_HIDDEN KoToolDocker::Private
0021 {
0022 public:
0023     Private(KoToolDocker *dock)
0024         : q(dock)
0025     {
0026     }
0027 
0028     ~Private() {
0029         /// Hider widget is not part of any widget hierarchy (which is intentional
0030         /// due to bug 447522), so we need to delete it manually
0031         delete hiderWidget;
0032     }
0033 
0034     QList<QPointer<QWidget> > currentWidgetList;
0035     QSet<QWidget *> currentAuxWidgets;
0036     QScrollArea *scrollArea {nullptr};
0037     QWidget *hiderWidget {nullptr}; // non current widgets are hidden by being children of this
0038     QWidget *housekeeperWidget {nullptr};
0039     QGridLayout *housekeeperLayout {nullptr};
0040     QBoxLayout *housekeeperMainLayout{nullptr};
0041     KoToolDocker *q {nullptr};
0042     Qt::DockWidgetArea dockingArea;
0043 
0044     void resetWidgets()
0045     {
0046         currentWidgetList.clear();
0047         qDeleteAll(currentAuxWidgets);
0048         currentAuxWidgets.clear();
0049     }
0050 
0051     void recreateLayout(const QList<QPointer<QWidget> > &optionWidgetList)
0052     {
0053         Q_FOREACH (QPointer<QWidget> widget, currentWidgetList) {
0054             if (!widget.isNull() && widget && hiderWidget) {
0055                 widget->setParent(hiderWidget);
0056             }
0057         }
0058         qDeleteAll(currentAuxWidgets);
0059         currentAuxWidgets.clear();
0060 
0061         currentWidgetList = optionWidgetList;
0062 
0063         // need to unstretch row that have previously been stretched
0064         housekeeperLayout->setRowStretch(housekeeperLayout->rowCount()-1, 0);
0065 
0066         int cnt = 0;
0067         QFrame *s;
0068         QLabel *l;
0069         switch (dockingArea) {
0070         case Qt::TopDockWidgetArea:
0071         case Qt::BottomDockWidgetArea:
0072             housekeeperMainLayout->setDirection(QBoxLayout::LeftToRight);
0073             housekeeperMainLayout->setStretch(0, 1);
0074             housekeeperMainLayout->setStretch(1, 0);
0075             housekeeperLayout->setHorizontalSpacing(2);
0076             housekeeperLayout->setVerticalSpacing(0);
0077             Q_FOREACH (QPointer<QWidget> widget, currentWidgetList) {
0078                 if (widget.isNull() || widget->objectName().isEmpty()) {
0079                     continue;
0080                 }
0081                 if (!widget->windowTitle().isEmpty()) {
0082                     housekeeperLayout->addWidget(
0083                         l = new QLabel(widget->windowTitle()),
0084                         0,
0085                         2 * cnt);
0086                     currentAuxWidgets.insert(l);
0087                 }
0088                 housekeeperLayout->addWidget(widget, 1, 2 * cnt);
0089                 widget->show();
0090                 if (widget != currentWidgetList.last()) {
0091                     housekeeperLayout->addWidget(s = new QFrame(),
0092                                                  0,
0093                                                  2 * cnt + 1,
0094                                                  2,
0095                                                  1);
0096                     s->setFrameShape(QFrame::VLine);
0097                     currentAuxWidgets.insert(s);
0098                 }
0099                 cnt++;
0100             }
0101             break;
0102         case Qt::NoDockWidgetArea:
0103         case Qt::LeftDockWidgetArea:
0104         case Qt::RightDockWidgetArea: {
0105             housekeeperMainLayout->setDirection(QBoxLayout::TopToBottom);
0106             housekeeperMainLayout->setStretch(0, 0);
0107             housekeeperMainLayout->setStretch(1, 1);
0108             housekeeperLayout->setHorizontalSpacing(0);
0109             housekeeperLayout->setVerticalSpacing(2);
0110             Q_FOREACH (QPointer<QWidget> widget, currentWidgetList) {
0111                 if (widget.isNull() || widget->objectName().isEmpty()) {
0112                     continue;
0113                 }
0114                 if (!widget->windowTitle().isEmpty()) {
0115                     housekeeperLayout->addWidget(
0116                         l = new QLabel(widget->windowTitle()),
0117                         cnt++,
0118                         0);
0119                     currentAuxWidgets.insert(l);
0120                 }
0121                 housekeeperLayout->addWidget(widget, cnt++, 0);
0122                 widget->show();
0123                 if (widget != currentWidgetList.last()) {
0124                     housekeeperLayout->addWidget(s = new QFrame(), cnt++, 0);
0125                     s->setFrameStyle(QFrame::HLine | QFrame::Sunken);
0126                     currentAuxWidgets.insert(s);
0127                 }
0128             }
0129             break;
0130         }
0131         default:
0132             break;
0133         }
0134 
0135         housekeeperLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
0136         housekeeperLayout->invalidate();
0137     }
0138 
0139     void locationChanged(Qt::DockWidgetArea area)
0140     {
0141         dockingArea = area;
0142         recreateLayout(currentWidgetList);
0143     }
0144 
0145 };
0146 
0147 KoToolDocker::KoToolDocker(QWidget *parent)
0148     : QDockWidget(i18n("Tool Options"), parent),
0149       d(new Private(this))
0150 {
0151     connect(this, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(locationChanged(Qt::DockWidgetArea)));
0152 
0153     d->housekeeperWidget = new QWidget();
0154     d->housekeeperLayout = new QGridLayout;
0155     d->housekeeperLayout->setContentsMargins(4,4,4,0);
0156     d->housekeeperLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
0157     d->housekeeperMainLayout =
0158         new QBoxLayout(QBoxLayout::TopToBottom, d->housekeeperWidget);
0159     d->housekeeperMainLayout->setContentsMargins(0, 0, 0, 0);
0160     d->housekeeperMainLayout->setSpacing(0);
0161     d->housekeeperMainLayout->addLayout(d->housekeeperLayout, 0);
0162     d->housekeeperMainLayout->addStretch(1);
0163 
0164     d->hiderWidget = new QWidget();
0165     d->hiderWidget->setVisible(false);
0166 
0167     d->scrollArea = new QScrollArea();
0168     d->scrollArea->setWidget(d->housekeeperWidget);
0169     d->scrollArea->setFrameShape(QFrame::NoFrame);
0170     d->scrollArea->setWidgetResizable(true);
0171     d->scrollArea->setFocusPolicy(Qt::NoFocus);
0172 
0173     QScroller *scroller = KisKineticScroller::createPreconfiguredScroller(d->scrollArea);
0174     if( scroller ) {
0175         connect(scroller, SIGNAL(stateChanged(QScroller::State)), this, SLOT(slotScrollerStateChange(QScroller::State)));
0176     }
0177 
0178     setWidget(d->scrollArea);
0179 }
0180 
0181 KoToolDocker::~KoToolDocker()
0182 {
0183     delete d;
0184 }
0185 
0186 bool KoToolDocker::hasOptionWidget()
0187 {
0188     return !d->currentWidgetList.isEmpty();
0189 }
0190 
0191 void KoToolDocker::setOptionWidgets(const QList<QPointer<QWidget> > &optionWidgetList)
0192 {
0193     d->recreateLayout(optionWidgetList);
0194 }
0195 
0196 void KoToolDocker::slotScrollerStateChange(QScroller::State state)
0197 {
0198     KisKineticScroller::updateCursor(d->scrollArea, state);
0199 }
0200 
0201 void KoToolDocker::resetWidgets()
0202 {
0203     d->resetWidgets();
0204 }
0205 
0206 
0207 void KoToolDocker::setCanvas(KoCanvasBase *canvas)
0208 {
0209     setEnabled(canvas != 0);
0210 }
0211 
0212 void KoToolDocker::unsetCanvas()
0213 {
0214     setEnabled(false);
0215 }
0216 
0217 //have to include this because of Q_PRIVATE_SLOT
0218 #include <moc_KoToolDocker.cpp>