1 /* This file is part of the KDE project
2 *
3 * Copyright (c) 2010-2011 C. Boemann <cbo@boemann.dk>
4 * Copyright (c) 2005-2006 Boudewijn Rempt <boud@valdyas.org>
5 * Copyright (c) 2006 Thomas Zander <zander@kde.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22 #include "KoToolDocker.h"
23
24 #include <KoDockWidgetTitleBarButton.h>
25 #include <KoDockWidgetTitleBar.h>
26 #include <KoIcon.h>
27
28 #include <klocalizedstring.h>
29 #include <kconfiggroup.h>
30 #include <ksharedconfig.h>
31
32 #include <QIcon>
33 #include <QApplication>
34 #include <QPointer>
35 #include <QGridLayout>
36 #include <QScrollArea>
37 #include <QScrollBar>
38 #include <QLabel>
39 #include <QSet>
40 #include <QAction>
41 #include <QStyleOptionFrame>
42 #include <QToolButton>
43 #include <QTabWidget>
44
45 #include <WidgetsDebug.h>
46
47 class Q_DECL_HIDDEN KoToolDocker::Private
48 {
49 public:
Private(KoToolDocker * dock)50 Private(KoToolDocker *dock)
51 : q(dock)
52 , tabbed(false)
53 , tabIcon(koIcon("tab-new"))
54 , unTabIcon(koIcon("tab-close"))
55 {
56 }
57
58 QList<QPointer<QWidget> > currentWidgetList;
59 QSet<QWidget *> currentAuxWidgets;
60 QScrollArea *scrollArea;
61 QWidget *hiderWidget; // non current widgets are hidden by being children of this
62 QWidget *housekeeperWidget;
63 QGridLayout *housekeeperLayout;
64 KoToolDocker *q;
65 Qt::DockWidgetArea dockingArea;
66 bool tabbed;
67 QIcon tabIcon;
68 QIcon unTabIcon;
69 QToolButton *tabButton;
70
71
resetWidgets()72 void resetWidgets()
73 {
74 currentWidgetList.clear();
75 qDeleteAll(currentAuxWidgets);
76 currentAuxWidgets.clear();
77 }
78
recreateLayout(const QList<QPointer<QWidget>> & optionWidgetList)79 void recreateLayout(const QList<QPointer<QWidget> > &optionWidgetList)
80 {
81 foreach(QPointer<QWidget> widget, currentWidgetList) {
82 if (!widget.isNull() && widget && hiderWidget) {
83 widget->setParent(hiderWidget);
84 }
85 }
86 qDeleteAll(currentAuxWidgets);
87 currentAuxWidgets.clear();
88
89 currentWidgetList = optionWidgetList;
90
91 // need to unstretch row that have previously been stretched
92 housekeeperLayout->setRowStretch(housekeeperLayout->rowCount()-1, 0);
93
94 if (tabbed && currentWidgetList.size() > 1) {
95 QTabWidget *t;
96 housekeeperLayout->addWidget(t = new QTabWidget(), 0, 0);
97 t->setDocumentMode(true);
98 currentAuxWidgets.insert(t);
99 foreach(QPointer<QWidget> widget, currentWidgetList) {
100 if (widget.isNull() || widget->objectName().isEmpty()) {
101 Q_ASSERT(!(widget->objectName().isEmpty()));
102 continue; // skip this docker in release build when assert don't crash
103 }
104 t->addTab(widget, widget->windowTitle());
105 }
106 } else {
107 int cnt = 0;
108 QFrame *s;
109 QLabel *l;
110 switch(dockingArea) {
111 case Qt::TopDockWidgetArea:
112 case Qt::BottomDockWidgetArea:
113 housekeeperLayout->setHorizontalSpacing(2);
114 housekeeperLayout->setVerticalSpacing(0);
115 foreach(QPointer<QWidget> widget, currentWidgetList) {
116 if (widget.isNull() || widget->objectName().isEmpty()) {
117 continue; // skip this docker in release build when assert don't crash
118 }
119 if (!widget->windowTitle().isEmpty()) {
120 housekeeperLayout->addWidget(l = new QLabel(widget->windowTitle()), 0, 2*cnt);
121 currentAuxWidgets.insert(l);
122 }
123 housekeeperLayout->addWidget(widget, 1, 2*cnt);
124 widget->show();
125 if (widget != currentWidgetList.last()) {
126 housekeeperLayout->addWidget(s = new QFrame(), 0, 2*cnt+1, 2, 1);
127 s->setFrameShape(QFrame::VLine);
128 currentAuxWidgets.insert(s);
129 }
130 cnt++;
131 }
132 break;
133 case Qt::LeftDockWidgetArea:
134 case Qt::RightDockWidgetArea: {
135 housekeeperLayout->setHorizontalSpacing(0);
136 housekeeperLayout->setVerticalSpacing(2);
137 int specialCount = 0;
138 foreach(QPointer<QWidget> widget, currentWidgetList) {
139 if (widget.isNull() || widget->objectName().isEmpty()) {
140 Q_ASSERT(!(widget->objectName().isEmpty()));
141 continue; // skip this docker in release build when assert don't crash
142 }
143 if (!widget->windowTitle().isEmpty()) {
144 housekeeperLayout->addWidget(l = new QLabel(widget->windowTitle()), cnt++, 0);
145 currentAuxWidgets.insert(l);
146 }
147 housekeeperLayout->addWidget(widget, cnt++, 0);
148 QLayout *subLayout = widget->layout();
149 if (subLayout) {
150 for (int i = 0; i < subLayout->count(); ++i) {
151 QWidget *spacerWidget = subLayout->itemAt(i)->widget();
152 if (spacerWidget && spacerWidget->objectName().contains("SpecialSpacer")) {
153 specialCount++;
154 }
155 }
156 }
157 widget->show();
158 if (widget != currentWidgetList.last()) {
159 housekeeperLayout->addWidget(s = new QFrame(), cnt++, 0);
160 s->setFrameShape(QFrame::HLine);
161 currentAuxWidgets.insert(s);
162 }
163 }
164 if (specialCount == currentWidgetList.count()) {
165 housekeeperLayout->setRowStretch(cnt, 10000);
166 }
167 break;
168 }
169 default:
170 break;
171 }
172 }
173 housekeeperLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
174 housekeeperLayout->invalidate();
175 }
176
locationChanged(Qt::DockWidgetArea area)177 void locationChanged(Qt::DockWidgetArea area)
178 {
179 dockingArea = area;
180 recreateLayout(currentWidgetList);
181 }
182
toggleTab()183 void toggleTab()
184 {
185 if (!tabbed) {
186 tabbed = true;
187 tabButton->setIcon(unTabIcon);
188 } else {
189 tabbed = false;
190 tabButton->setIcon(tabIcon);
191 }
192 recreateLayout(currentWidgetList);
193 }
194 };
195
KoToolDocker(QWidget * parent)196 KoToolDocker::KoToolDocker(QWidget *parent)
197 : QDockWidget(i18n("Tool Options"), parent),
198 d(new Private(this))
199 {
200 KConfigGroup cfg = KSharedConfig::openConfig()->group("DockWidget sharedtooldocker");
201 d->tabbed = cfg.readEntry("TabbedMode", false);
202
203 toggleViewAction()->setVisible(false); //should always be visible, so hide option in menu
204 setFeatures(DockWidgetMovable|DockWidgetFloatable);
205 setTitleBarWidget(new KoDockWidgetTitleBar(this));
206
207 connect(this, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(locationChanged(Qt::DockWidgetArea)));
208
209 d->housekeeperWidget = new QWidget();
210 d->housekeeperLayout = new QGridLayout();
211 d->housekeeperLayout->setContentsMargins(4,4,4,0);
212 d->housekeeperWidget->setLayout(d->housekeeperLayout);
213
214 d->housekeeperLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
215
216 d->hiderWidget = new QWidget(d->housekeeperWidget);
217 d->hiderWidget->setVisible(false);
218
219 d->scrollArea = new QScrollArea();
220 d->scrollArea->setWidget(d->housekeeperWidget);
221 d->scrollArea->setFrameShape(QFrame::NoFrame);
222 d->scrollArea->setWidgetResizable(true);
223 d->scrollArea->setFocusPolicy(Qt::NoFocus);
224
225 setWidget(d->scrollArea);
226
227 d->tabButton = new QToolButton(this); // parent hack in toggleLock to keep it clickable
228 d->tabButton->setIcon(d->tabIcon);
229 d->tabButton->setToolTip(i18n("Toggles organizing the options in tabs or not"));
230 d->tabButton->setAutoRaise(true);
231 connect(d->tabButton, SIGNAL(clicked()), SLOT(toggleTab()));
232 d->tabButton->resize(d->tabButton->sizeHint());
233 }
234
~KoToolDocker()235 KoToolDocker::~KoToolDocker()
236 {
237 KConfigGroup cfg = KSharedConfig::openConfig()->group("DockWidget sharedtooldocker");
238 cfg.writeEntry("TabbedMode", d->tabbed);
239 cfg.sync();
240
241 delete d;
242 }
243
hasOptionWidget()244 bool KoToolDocker::hasOptionWidget()
245 {
246 return !d->currentWidgetList.isEmpty();
247 }
248
setTabEnabled(bool enabled)249 void KoToolDocker::setTabEnabled(bool enabled)
250 {
251 d->tabButton->setVisible(enabled);
252 }
253
setOptionWidgets(const QList<QPointer<QWidget>> & optionWidgetList)254 void KoToolDocker::setOptionWidgets(const QList<QPointer<QWidget> > &optionWidgetList)
255 {
256 d->recreateLayout(optionWidgetList);
257 }
258
resizeEvent(QResizeEvent *)259 void KoToolDocker::resizeEvent(QResizeEvent*)
260 {
261 int fw = isFloating() ? style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, nullptr, this) : 0;
262 d->tabButton->move(width() - d->tabButton->width() - d->scrollArea->verticalScrollBar()->sizeHint().width(), fw);
263 }
264
resetWidgets()265 void KoToolDocker::resetWidgets()
266 {
267 d->resetWidgets();
268 }
269
270
setCanvas(KoCanvasBase * canvas)271 void KoToolDocker::setCanvas(KoCanvasBase *canvas)
272 {
273 setEnabled(canvas != 0);
274 }
275
unsetCanvas()276 void KoToolDocker::unsetCanvas()
277 {
278 setEnabled(false);
279 }
280
281 //have to include this because of Q_PRIVATE_SLOT
282 #include <moc_KoToolDocker.cpp>
283