File indexing completed on 2024-05-12 16:36:01

0001 /* This file is part of the KDE project
0002    Copyright 2011 Marijn Kruisselbrink <mkruisselbrink@kde.org>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "ActionOptionWidget.h"
0021 
0022 // Qt
0023 #include <QDomElement>
0024 #include <QHBoxLayout>
0025 #include <QToolButton>
0026 #include <QWidgetAction>
0027 
0028 #include <QStyle>
0029 
0030 // KF5
0031 #include <KLocalizedString>
0032 
0033 // Calligra
0034 #include <KoFontComboBox.h>
0035 
0036 // Calligra Sheets
0037 #include "CellToolBase.h"
0038 
0039 using namespace Calligra::Sheets;
0040 
0041 class GroupFlowLayout : public QLayout
0042 {
0043 public:
0044     GroupFlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
0045     GroupFlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
0046     ~GroupFlowLayout() override;
0047 
0048     void addItem(QLayoutItem *item) override;
0049     int horizontalSpacing() const;
0050     int verticalSpacing() const;
0051     Qt::Orientations expandingDirections() const override;
0052     bool hasHeightForWidth() const override;
0053     int heightForWidth(int) const override;
0054     int count() const override;
0055     QLayoutItem *itemAt(int index) const override;
0056     QSize minimumSize() const override;
0057     void setGeometry(const QRect &rect) override;
0058     QSize sizeHint() const override;
0059     QLayoutItem *takeAt(int index) override;
0060 
0061 private:
0062     int doLayout(const QRect &rect, bool testOnly) const;
0063     int smartSpacing(QStyle::PixelMetric pm) const;
0064 
0065     QList<QLayoutItem *> itemList;
0066     int m_hSpace;
0067     int m_vSpace;
0068 };
0069 
0070 ActionOptionWidget::ActionOptionWidget(CellToolBase* cellTool, const QDomElement& e, QWidget *parent) :
0071     QWidget(parent)
0072 {
0073     QString name = e.attribute("name");
0074     setObjectName(name);
0075     setWindowTitle(i18n(name.toLatin1()));
0076 
0077     QLayout* layout = new GroupFlowLayout(this);//QBoxLayout(QBoxLayout::TopToBottom, this);
0078 
0079     for (QDomElement group = e.firstChildElement("group"); !group.isNull(); group = group.nextSiblingElement("group")) {
0080         QHBoxLayout *groupLayout = new QHBoxLayout();
0081         layout->addItem(groupLayout);
0082 
0083         // In each group there are a number of actions that will be layouted together.
0084         for (QDomElement action = group.firstChildElement("action"); !action.isNull(); action = action.nextSiblingElement("action")) {
0085             QString actionName = action.attribute("name");
0086             QAction* a = cellTool->action(actionName);
0087             if (!a) {
0088                 warnSheets << "unknown action" << actionName << "in CellToolOptionWidgets.xml";
0089                 continue;
0090             }
0091             QWidgetAction* wa = qobject_cast<QWidgetAction *>(a);
0092             QWidget* w = wa ? wa->requestWidget(this) : 0;
0093             if (w && qobject_cast<KoFontComboBox*>(w)) {
0094                 w->setMinimumWidth(w->minimumWidth() / 2);
0095             }
0096             if (!w) {
0097                 QToolButton* b = new QToolButton(this);
0098                 b->setFocusPolicy(Qt::NoFocus);
0099                 b->setDefaultAction(a);
0100                 w = b;
0101             }
0102 
0103             if (w) {
0104                 groupLayout->addWidget(w);
0105             }
0106         }
0107     }
0108 
0109     // The following widget activates a special feature in the
0110     // ToolOptionsDocker that makes the components of the widget align
0111     // to the top if there is extra space.
0112     QWidget *specialSpacer = new QWidget(this);
0113     specialSpacer->setObjectName("SpecialSpacer");
0114     layout->addWidget(specialSpacer);
0115 }
0116 
0117 GroupFlowLayout::GroupFlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
0118     : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
0119 {
0120     setContentsMargins(margin, margin, margin, margin);
0121 }
0122 
0123 GroupFlowLayout::GroupFlowLayout(int margin, int hSpacing, int vSpacing)
0124     : m_hSpace(hSpacing), m_vSpace(vSpacing)
0125 {
0126     setContentsMargins(margin, margin, margin, margin);
0127 }
0128 
0129 GroupFlowLayout::~GroupFlowLayout()
0130 {
0131     QLayoutItem *item;
0132     while ((item = takeAt(0)))
0133         delete item;
0134 }
0135 
0136 void GroupFlowLayout::addItem(QLayoutItem *item)
0137 {
0138     itemList.append(item);
0139 }
0140 
0141 int GroupFlowLayout::horizontalSpacing() const
0142 {
0143     if (m_hSpace >= 0) {
0144         return m_hSpace;
0145     } else {
0146         return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
0147     }
0148 }
0149 
0150 int GroupFlowLayout::verticalSpacing() const
0151 {
0152     if (m_vSpace >= 0) {
0153         return m_vSpace;
0154     } else {
0155         return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
0156     }
0157 }
0158 
0159 int GroupFlowLayout::count() const
0160 {
0161     return itemList.size();
0162 }
0163 
0164 QLayoutItem *GroupFlowLayout::itemAt(int index) const
0165 {
0166     return itemList.value(index);
0167 }
0168 
0169 QLayoutItem *GroupFlowLayout::takeAt(int index)
0170 {
0171     if (index >= 0 && index < itemList.size())
0172         return itemList.takeAt(index);
0173     else
0174         return 0;
0175 }
0176 
0177 Qt::Orientations GroupFlowLayout::expandingDirections() const
0178 {
0179     return 0;
0180 }
0181 
0182 bool GroupFlowLayout::hasHeightForWidth() const
0183 {
0184     return true;
0185 }
0186 
0187 int GroupFlowLayout::heightForWidth(int width) const
0188 {
0189     int height = doLayout(QRect(0, 0, width, 0), true);
0190     return height;
0191 }
0192 
0193 void GroupFlowLayout::setGeometry(const QRect &rect)
0194 {
0195     QLayout::setGeometry(rect);
0196     doLayout(rect, false);
0197 }
0198 
0199 QSize GroupFlowLayout::sizeHint() const
0200 {
0201     return minimumSize();
0202 }
0203 
0204 QSize GroupFlowLayout::minimumSize() const
0205 {
0206     QSize size;
0207     QLayoutItem *item;
0208     foreach (item, itemList)
0209         size = size.expandedTo(item->minimumSize());
0210 
0211     size += QSize(2*margin(), 2*margin());
0212     return size;
0213 }
0214 
0215 int GroupFlowLayout::doLayout(const QRect &rect, bool testOnly) const
0216 {
0217     int left, top, right, bottom;
0218     getContentsMargins(&left, &top, &right, &bottom);
0219     QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
0220     int x = effectiveRect.x();
0221     int y = effectiveRect.y();
0222     int lineHeight = 0;
0223 
0224     QLayoutItem *item;
0225     foreach (item, itemList) {
0226         QWidget *wid = item->widget();
0227         int spaceX = horizontalSpacing();
0228         if (wid && spaceX == -1)
0229             spaceX = wid->style()->layoutSpacing(
0230                         QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
0231         if (spaceX == -1) spaceX = 5;
0232         int spaceY = verticalSpacing();
0233         if (wid && spaceY == -1)
0234             spaceY = wid->style()->layoutSpacing(
0235                         QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
0236         if (spaceY == -1) spaceX = 5;
0237         int nextX = x + item->sizeHint().width() + spaceX;
0238         if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
0239             x = effectiveRect.x();
0240             y = y + lineHeight + spaceY;
0241             nextX = x + item->sizeHint().width() + spaceX;
0242             lineHeight = 0;
0243         }
0244 
0245         if (!testOnly) {
0246             QSize s = item->sizeHint();
0247             if (nextX - spaceX > effectiveRect.right()) {
0248                 QSize minSize = item->minimumSize();
0249                 int neededW = effectiveRect.right() - x;
0250                 s.setWidth(qMax(neededW, minSize.width()));
0251             }
0252             item->setGeometry(QRect(QPoint(x, y), s));
0253         }
0254 
0255         x = nextX;
0256         lineHeight = qMax(lineHeight, item->sizeHint().height());
0257     }
0258     return y + lineHeight - rect.y() + bottom;
0259 }
0260 
0261 int GroupFlowLayout::smartSpacing(QStyle::PixelMetric pm) const
0262 {
0263     QObject *parent = this->parent();
0264     if (!parent) {
0265         return -1;
0266     } else if (parent->isWidgetType()) {
0267         QWidget *pw = static_cast<QWidget *>(parent);
0268         return pw->style()->pixelMetric(pm, 0, pw);
0269     } else {
0270         return static_cast<QLayout *>(parent)->spacing();
0271     }
0272 }