Warning, file /office/calligra/libs/widgets/KoDockWidgetTitleBar.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002    Copyright (c) 2007 Marijn Kruisselbrink <mkruisselbrink@kde.org>
0003    Copyright (C) 2007 Thomas Zander <zander@kde.org>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library 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 GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "KoDockWidgetTitleBar.h"
0022 #include "KoDockWidgetTitleBar_p.h"
0023 #include "KoDockWidgetTitleBarButton.h"
0024 
0025 #include <KoIcon.h>
0026 
0027 #include <WidgetsDebug.h>
0028 #include <klocalizedstring.h>
0029 
0030 #include <QAbstractButton>
0031 #include <QAction>
0032 #include <QLabel>
0033 #include <QLayout>
0034 #include <QStyle>
0035 #include <QStylePainter>
0036 #include <QStyleOptionFrame>
0037 
0038 static inline bool hasFeature(const QDockWidget *dockwidget, QDockWidget::DockWidgetFeature feature)
0039 {
0040     return (dockwidget->features() & feature) == feature;
0041 }
0042 
0043 static QIcon openIcon(QDockWidget *q)
0044 {
0045     QIcon icon = q->style()->standardIcon(QStyle::SP_TitleBarShadeButton);
0046     return icon.isNull() ? koIcon("arrow-down") : icon;
0047 }
0048 
0049 static QIcon closeIcon(QDockWidget *q)
0050 {
0051     QIcon icon = q->style()->standardIcon(QStyle::SP_TitleBarUnshadeButton);
0052     return icon.isNull() ? koIcon("arrow-right") : icon;
0053 }
0054 
0055 
0056 KoDockWidgetTitleBar::KoDockWidgetTitleBar(QDockWidget* dockWidget)
0057         : QWidget(dockWidget), d(new Private(this))
0058 {
0059     QDockWidget *q = dockWidget;
0060 
0061     d->floatButton = new KoDockWidgetTitleBarButton(this);
0062     d->floatButton->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton, nullptr, q));
0063     connect(d->floatButton, SIGNAL(clicked()), SLOT(toggleFloating()));
0064     d->floatButton->setVisible(true);
0065     d->floatButton->setToolTip(i18nc("@info:tooltip", "Float Docker"));
0066     d->floatButton->setStyleSheet("border: 0");
0067 
0068     d->closeButton = new KoDockWidgetTitleBarButton(this);
0069     d->closeButton->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton, nullptr, q));
0070     connect(d->closeButton, SIGNAL(clicked()), q, SLOT(close()));
0071     d->closeButton->setVisible(true);
0072     d->closeButton->setToolTip(i18nc("@info:tooltip", "Close Docker"));
0073     d->closeButton->setStyleSheet("border: 0"); // border makes the header busy looking (appears on some OSs)
0074 
0075     d->collapseButton = new KoDockWidgetTitleBarButton(this);
0076     d->collapseButton->setIcon(openIcon(q));
0077     connect(d->collapseButton, SIGNAL(clicked()), SLOT(toggleCollapsed()));
0078     d->collapseButton->setVisible(true);
0079     d->collapsable = true;
0080     d->collapseButton->setToolTip(i18nc("@info:tooltip", "Collapse Docker"));
0081     d->collapseButton->setStyleSheet("border: 0");
0082 
0083     d->lockButton = new KoDockWidgetTitleBarButton(this);
0084     d->lockButton->setCheckable(true);
0085     d->lockButton->setIcon(koIcon("object-unlocked"));
0086     connect(d->lockButton, SIGNAL(toggled(bool)), SLOT(setLocked(bool)));
0087     d->lockButton->setVisible(true);
0088     d->lockable = true;
0089     d->lockButton->setToolTip(i18nc("@info:tooltip", "Lock Docker"));
0090     d->lockButton->setStyleSheet("border: 0");
0091 
0092     connect(dockWidget, SIGNAL(featuresChanged(QDockWidget::DockWidgetFeatures)), SLOT(featuresChanged(QDockWidget::DockWidgetFeatures)));
0093     connect(dockWidget, SIGNAL(topLevelChanged(bool)), SLOT(topLevelChanged(bool)));
0094 
0095     d->featuresChanged(0);
0096 }
0097 
0098 KoDockWidgetTitleBar::~KoDockWidgetTitleBar()
0099 {
0100     delete d;
0101 }
0102 
0103 QSize KoDockWidgetTitleBar::minimumSizeHint() const
0104 {
0105     return sizeHint();
0106 }
0107 
0108 QSize KoDockWidgetTitleBar::sizeHint() const
0109 {
0110     if (isHidden()) {
0111         return QSize(0, 0);
0112     }
0113 
0114     QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
0115 
0116     int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);
0117     int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
0118 
0119     // get size of buttons...
0120     QSize closeSize(0, 0);
0121     if (d->closeButton && hasFeature(q, QDockWidget::DockWidgetClosable)) {
0122         closeSize = d->closeButton->sizeHint();
0123     }
0124 
0125     QSize floatSize(0, 0);
0126     if (d->floatButton && hasFeature(q, QDockWidget::DockWidgetFloatable)) {
0127         floatSize = d->floatButton->sizeHint();
0128     }
0129 
0130     QSize hideSize(0, 0);
0131     if (d->collapseButton && d->collapsable) {
0132         hideSize = d->collapseButton->sizeHint();
0133     }
0134 
0135     QSize lockSize(0, 0);
0136     if (d->lockButton && d->lockable) {
0137         lockSize = d->lockButton->sizeHint();
0138     }
0139 
0140     int buttonHeight = qMax(qMax(qMax(closeSize.height(), floatSize.height()), hideSize.height()), lockSize.height()) + 2;
0141     int buttonWidth = closeSize.width() + floatSize.width() + hideSize.width() + lockSize.width();
0142 
0143     int height = buttonHeight;
0144     if (d->textVisibilityMode == FullTextAlwaysVisible) {
0145         // get font size
0146         QFontMetrics titleFontMetrics = q->fontMetrics();
0147         int fontHeight = titleFontMetrics.lineSpacing() + 2 * mw;
0148 
0149         height = qMax(height, fontHeight);
0150     }
0151 
0152     /*
0153      * Calculate the width of title and add to the total width of the docker window when collapsed.
0154      */
0155     const int titleWidth =
0156         (d->textVisibilityMode == FullTextAlwaysVisible) ? (q->fontMetrics().width(q->windowTitle()) + 2*mw) :
0157                                                            0;
0158 
0159     if (d->preCollapsedWidth > 0) {
0160         return QSize(d->preCollapsedWidth, height);
0161     }
0162     else {
0163         if (d->textVisibilityMode == FullTextAlwaysVisible) {
0164             return QSize(buttonWidth /*+ height*/ + 2*mw + 2*fw + titleWidth, height);
0165         }
0166         else {
0167             if (q->widget()) {
0168                 return QSize(qMin(q->widget()->sizeHint().width(), buttonWidth), height);
0169             }
0170             else {
0171                 return QSize(buttonWidth, height);
0172             }
0173         }
0174     }
0175 }
0176 
0177 void KoDockWidgetTitleBar::paintEvent(QPaintEvent*)
0178 {
0179     QStylePainter p(this);
0180 
0181     QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
0182 
0183     int fw = q->isFloating() ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, nullptr, q) : 0;
0184     int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, nullptr, q);
0185 
0186     QStyleOptionDockWidget titleOpt;
0187     titleOpt.initFrom(q);
0188 
0189     QSize collapseButtonSize(0,0);
0190     if (d->collapsable) {
0191         collapseButtonSize = d->collapseButton->size();
0192     }
0193 
0194     QSize lockButtonSize(0,0);
0195     if (d->lockable) {
0196         lockButtonSize = d->lockButton->size();
0197     }
0198 
0199     titleOpt.rect = QRect(QPoint(fw + mw + collapseButtonSize.width() + lockButtonSize.width(), 0),
0200                           QSize(geometry().width() - (fw * 2) -  mw - collapseButtonSize.width() - lockButtonSize.width(), geometry().height()));
0201     titleOpt.title = q->windowTitle();
0202     titleOpt.closable = hasFeature(q, QDockWidget::DockWidgetClosable);
0203     titleOpt.floatable = hasFeature(q, QDockWidget::DockWidgetFloatable);
0204     p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt);
0205 }
0206 
0207 void KoDockWidgetTitleBar::resizeEvent(QResizeEvent*)
0208 {
0209     QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
0210 
0211     int fw = q->isFloating() ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, nullptr, q) : 0;
0212 
0213     QStyleOptionDockWidget opt;
0214     opt.initFrom(q);
0215     opt.rect = QRect(QPoint(fw, fw), QSize(geometry().width() - (fw * 2), geometry().height() - (fw * 2)));
0216     opt.title = q->windowTitle();
0217     opt.closable = hasFeature(q, QDockWidget::DockWidgetClosable);
0218     opt.floatable = hasFeature(q, QDockWidget::DockWidgetFloatable);
0219 
0220     QRect floatRect = q->style()->subElementRect(QStyle::SE_DockWidgetFloatButton, &opt, q);
0221     if (!floatRect.isNull())
0222         d->floatButton->setGeometry(floatRect);
0223 
0224     QRect closeRect = q->style()->subElementRect(QStyle::SE_DockWidgetCloseButton, &opt, q);
0225     if (!closeRect.isNull())
0226         d->closeButton->setGeometry(closeRect);
0227 
0228     int top = fw;
0229     if (!floatRect.isNull())
0230         top = floatRect.y();
0231     else if (!closeRect.isNull())
0232         top = closeRect.y();
0233 
0234     QSize size = d->collapseButton->size();
0235     if (!closeRect.isNull()) {
0236         size = d->closeButton->size();
0237     } else if (!floatRect.isNull()) {
0238         size = d->floatButton->size();
0239     }
0240     QRect collapseRect = QRect(QPoint(fw, top), size);
0241     d->collapseButton->setGeometry(collapseRect);
0242 
0243     size = d->lockButton->size();
0244 
0245     if (!closeRect.isNull()) {
0246         size = d->closeButton->size();
0247     } else if (!floatRect.isNull()) {
0248         size = d->floatButton->size();
0249     }
0250 
0251     int offset = 0;
0252 
0253     if (d->collapsable) {
0254         offset = collapseRect.width();
0255     }
0256     QRect lockRect = QRect(QPoint(fw + 2 + offset, top), size);
0257     d->lockButton->setGeometry(lockRect);
0258 
0259     if (width() < (closeRect.width() + lockRect.width()) + 50) {
0260         d->collapsable = false;
0261         d->collapseButton->setVisible(false);
0262         d->lockButton->setVisible(false);
0263         d->lockable = false;
0264     } else {
0265         d->collapsable = d->collapsableSet;
0266         d->collapseButton->setVisible(d->collapsableSet);
0267         d->lockButton->setVisible(true);
0268         d->lockable = true;
0269     }
0270 }
0271 
0272 void KoDockWidgetTitleBar::setCollapsed(bool collapsed)
0273 {
0274     QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
0275     if (q && q->widget() && q->widget()->isHidden() != collapsed)
0276         d->toggleCollapsed();
0277 }
0278 
0279 void KoDockWidgetTitleBar::setLocked(bool locked)
0280 {
0281     QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
0282 
0283     d->locked = locked;
0284     d->lockButton->blockSignals(true);
0285     d->lockButton->setChecked(locked);
0286     d->lockButton->blockSignals(false);
0287 
0288     //qDebug() << "setlocked" << q << d->locked << locked;
0289 
0290     if (locked) {
0291         d->features = q->features();
0292         q->setFeatures(QDockWidget::NoDockWidgetFeatures);
0293     }
0294     else {
0295         q->setFeatures(d->features);
0296     }
0297 
0298     q->toggleViewAction()->setEnabled(!locked);
0299     d->closeButton->setEnabled(!locked);
0300     d->floatButton->setEnabled(!locked);
0301     d->collapseButton->setEnabled(!locked);
0302 
0303     d->updateIcons();
0304     q->setProperty("Locked", locked);
0305     resizeEvent(nullptr);
0306 }
0307 
0308 
0309 void KoDockWidgetTitleBar::setCollapsable(bool collapsable)
0310 {
0311     d->collapsableSet = collapsable;
0312     d->collapsable = collapsable;
0313     d->collapseButton->setVisible(collapsable);
0314 }
0315 
0316 void KoDockWidgetTitleBar::setTextVisibilityMode(TextVisibilityMode textVisibilityMode)
0317 {
0318     d->textVisibilityMode = textVisibilityMode;
0319 }
0320 
0321 void KoDockWidgetTitleBar::updateIcons()
0322 {
0323     d->updateIcons();
0324 }
0325 
0326 void KoDockWidgetTitleBar::Private::toggleFloating()
0327 {
0328     QDockWidget *q = qobject_cast<QDockWidget*>(thePublic->parentWidget());
0329 
0330     q->setFloating(!q->isFloating());
0331 }
0332 
0333 void KoDockWidgetTitleBar::Private::topLevelChanged(bool topLevel)
0334 {
0335     lockButton->setEnabled(!topLevel);
0336 }
0337 
0338 void KoDockWidgetTitleBar::Private::toggleCollapsed()
0339 {
0340     QDockWidget *q = qobject_cast<QDockWidget*>(thePublic->parentWidget());
0341     if (q == nullptr) // there does not *have* to be anything on the dockwidget.
0342         return;
0343 
0344     preCollapsedWidth = q->widget()->isHidden() ? -1 : thePublic->width();
0345     q->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); // will be overwritten again next
0346     if (q->widget()) {
0347         q->widget()->setVisible(q->widget()->isHidden());
0348         collapseButton->setIcon(q->widget()->isHidden() ? closeIcon(q) : openIcon(q));
0349     }
0350 }
0351 
0352 void KoDockWidgetTitleBar::Private::featuresChanged(QDockWidget::DockWidgetFeatures)
0353 {
0354     QDockWidget *q = qobject_cast<QDockWidget*>(thePublic->parentWidget());
0355 
0356     closeButton->setVisible(hasFeature(q, QDockWidget::DockWidgetClosable));
0357     floatButton->setVisible(hasFeature(q, QDockWidget::DockWidgetFloatable));
0358 
0359     thePublic->resizeEvent(nullptr);
0360 }
0361 
0362 // QT5TODO: this is not yet triggered by theme changes it seems
0363 void KoDockWidgetTitleBar::Private::updateIcons()
0364 {
0365     QDockWidget *q = qobject_cast<QDockWidget*>(thePublic->parentWidget());
0366 
0367     lockButton->setIcon((!locked) ? koIcon("object-unlocked") : koIcon("object-locked"));
0368 
0369     // this method gets called when switching themes, so update all of the themed icons now
0370    floatButton->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton, 0, q));
0371    closeButton->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton, 0, q));
0372 
0373     if (q->widget()) {
0374         collapseButton->setIcon(q->widget()->isHidden() ? closeIcon(q) : openIcon(q));
0375     }
0376     thePublic->resizeEvent(nullptr);
0377 
0378 }
0379 
0380 //have to include this because of Q_PRIVATE_SLOT
0381 #include "moc_KoDockWidgetTitleBar.cpp"