DockAreaTabBar.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 ** Qt Advanced Docking System
3 ** Copyright (C) 2017 Uwe Kindler
4 **
5 ** This library is free software; you can redistribute it and/or
6 ** modify it under the terms of the GNU Lesser General Public
7 ** License as published by the Free Software Foundation; either
8 ** version 2.1 of the License, or (at your option) any later version.
9 **
10 ** This library is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ** Lesser General Public License for more details.
14 **
15 ** You should have received a copy of the GNU Lesser General Public
16 ** License along with this library; If not, see <http://www.gnu.org/licenses/>.
17 ******************************************************************************/
18 
19 
20 //============================================================================
25 //============================================================================
26 
27 //============================================================================
28 // INCLUDES
29 //============================================================================
30 #include "FloatingDragPreview.h"
31 #include "DockAreaTabBar.h"
32 
33 #include <QMouseEvent>
34 #include <QScrollBar>
35 #include <QDebug>
36 #include <QBoxLayout>
37 #include <QApplication>
38 #include <QtGlobal>
39 
40 #include "FloatingDockContainer.h"
41 #include "DockAreaWidget.h"
42 #include "DockOverlay.h"
43 #include "DockManager.h"
44 #include "DockWidget.h"
45 #include "DockWidgetTab.h"
46 
47 #include <iostream>
48 
49 
50 namespace ads
51 {
56 {
60  QBoxLayout* TabsLayout;
61  int CurrentIndex = -1;
62 
67 
72  void updateTabs();
73 
77  CDockWidgetTab* firstTab() const {return _this->tab(0);}
78 
82  CDockWidgetTab* lastTab() const {return _this->tab(_this->count() - 1);}
83 };
84 // struct DockAreaTabBarPrivate
85 
86 //============================================================================
88  _this(_public)
89 {
90 
91 }
92 
93 
94 //============================================================================
96 {
97  // Set active TAB and update all other tabs to be inactive
98  for (int i = 0; i < _this->count(); ++i)
99  {
100  auto TabWidget = _this->tab(i);
101  if (!TabWidget)
102  {
103  continue;
104  }
105 
106  if (i == CurrentIndex)
107  {
108  TabWidget->show();
109  TabWidget->setActiveTab(true);
110  _this->ensureWidgetVisible(TabWidget);
111  }
112  else
113  {
114  TabWidget->setActiveTab(false);
115  }
116  }
117 }
118 
119 
120 //============================================================================
122  QScrollArea(parent),
123  d(new DockAreaTabBarPrivate(this))
124 {
125  d->DockArea = parent;
126  setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
127  setFrameStyle(QFrame::NoFrame);
128  setWidgetResizable(true);
129  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
130  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
131 
132  d->TabsContainerWidget = new QWidget();
133  d->TabsContainerWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
134  d->TabsContainerWidget->setObjectName("tabsContainerWidget");
135  d->TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
136  d->TabsLayout->setContentsMargins(0, 0, 0, 0);
137  d->TabsLayout->setSpacing(0);
138  d->TabsLayout->addStretch(1);
139  d->TabsContainerWidget->setLayout(d->TabsLayout);
140  setWidget(d->TabsContainerWidget);
141 
142  setFocusPolicy(Qt::NoFocus);
143 }
144 
145 
146 //============================================================================
148 {
149  delete d;
150 }
151 
152 
153 //============================================================================
154 void CDockAreaTabBar::wheelEvent(QWheelEvent* Event)
155 {
156  Event->accept();
157  const int direction = Event->angleDelta().y();
158  if (direction < 0)
159  {
160  horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 20);
161  }
162  else
163  {
164  horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20);
165  }
166 }
167 
168 
169 //============================================================================
171 {
172  if (index == d->CurrentIndex)
173  {
174  return;
175  }
176 
177  if (index < -1 || index > (count() - 1))
178  {
179  qWarning() << Q_FUNC_INFO << "Invalid index" << index;
180  return;
181  }
182 
183  emit currentChanging(index);
184  d->CurrentIndex = index;
185  d->updateTabs();
186  updateGeometry();
187  emit currentChanged(index);
188 }
189 
190 
191 //============================================================================
193 {
194  // The tab bar contains a stretch item as last item
195  return d->TabsLayout->count() - 1;
196 }
197 
198 
199 //===========================================================================
201 {
202  d->TabsLayout->insertWidget(Index, Tab);
203  connect(Tab, SIGNAL(clicked()), this, SLOT(onTabClicked()));
204  connect(Tab, SIGNAL(closeRequested()), this, SLOT(onTabCloseRequested()));
205  connect(Tab, SIGNAL(closeOtherTabsRequested()), this, SLOT(onCloseOtherTabsRequested()));
206  connect(Tab, SIGNAL(moved(const QPoint&)), this, SLOT(onTabWidgetMoved(const QPoint&)));
207  connect(Tab, SIGNAL(elidedChanged(bool)), this, SIGNAL(elidedChanged(bool)));
208  Tab->installEventFilter(this);
209  emit tabInserted(Index);
210  if (Index <= d->CurrentIndex)
211  {
213  }
214  else if (d->CurrentIndex == -1)
215  {
216  setCurrentIndex(Index);
217  }
218 
219  updateGeometry();
220 }
221 
222 
223 //===========================================================================
225 {
226  if (!count())
227  {
228  return;
229  }
230  ADS_PRINT("CDockAreaTabBar::removeTab ");
231  int NewCurrentIndex = currentIndex();
232  int RemoveIndex = d->TabsLayout->indexOf(Tab);
233  if (count() == 1)
234  {
235  NewCurrentIndex = -1;
236  }
237  if (NewCurrentIndex > RemoveIndex)
238  {
239  NewCurrentIndex--;
240  }
241  else if (NewCurrentIndex == RemoveIndex)
242  {
243  NewCurrentIndex = -1;
244  // First we walk to the right to search for the next visible tab
245  for (int i = (RemoveIndex + 1); i < count(); ++i)
246  {
247  if (tab(i)->isVisibleTo(this))
248  {
249  NewCurrentIndex = i - 1;
250  break;
251  }
252  }
253 
254  // If there is no visible tab right to this tab then we walk to
255  // the left to find a visible tab
256  if (NewCurrentIndex < 0)
257  {
258  for (int i = (RemoveIndex - 1); i >= 0; --i)
259  {
260  if (tab(i)->isVisibleTo(this))
261  {
262  NewCurrentIndex = i;
263  break;
264  }
265  }
266  }
267  }
268 
269  emit removingTab(RemoveIndex);
270  d->TabsLayout->removeWidget(Tab);
271  Tab->disconnect(this);
272  Tab->removeEventFilter(this);
273  ADS_PRINT("NewCurrentIndex " << NewCurrentIndex);
274  if (NewCurrentIndex != d->CurrentIndex)
275  {
276  setCurrentIndex(NewCurrentIndex);
277  }
278  else
279  {
280  d->updateTabs();
281  }
282 
283  updateGeometry();
284 }
285 
286 
287 //===========================================================================
289 {
290  return d->CurrentIndex;
291 }
292 
293 
294 //===========================================================================
296 {
297  if (d->CurrentIndex < 0)
298  {
299  return nullptr;
300  }
301  else
302  {
303  return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(d->CurrentIndex)->widget());
304  }
305 }
306 
307 
308 //===========================================================================
310 {
311  CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender());
312  if (!Tab)
313  {
314  return;
315  }
316 
317  int index = d->TabsLayout->indexOf(Tab);
318  if (index < 0)
319  {
320  return;
321  }
322  setCurrentIndex(index);
323  emit tabBarClicked(index);
324 }
325 
326 
327 //===========================================================================
329 {
330  CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender());
331  int Index = d->TabsLayout->indexOf(Tab);
332  closeTab(Index);
333 }
334 
335 
336 //===========================================================================
338 {
339  auto Sender = qobject_cast<CDockWidgetTab*>(sender());
340  for (int i = 0; i < count(); ++i)
341  {
342  auto Tab = tab(i);
343  if (Tab->isClosable() && !Tab->isHidden() && Tab != Sender)
344  {
345  // If the dock widget is deleted with the closeTab() call, its tab
346  // it will no longer be in the layout, and thus the index needs to
347  // be updated to not skip any tabs
348  int Offset = Tab->dockWidget()->features().testFlag(
350  closeTab(i);
351 
352  // If the the dock widget blocks closing, i.e. if the flag
353  // CustomCloseHandling is set, and the dock widget is still open,
354  // then we do not need to correct the index
355  if (Tab->dockWidget()->isClosed())
356  {
357  i -= Offset;
358  }
359  }
360  }
361 }
362 
363 
364 //===========================================================================
366 {
367  if (Index >= count() || Index < 0)
368  {
369  return nullptr;
370  }
371  return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(Index)->widget());
372 }
373 
374 
375 //===========================================================================
376 void CDockAreaTabBar::onTabWidgetMoved(const QPoint& GlobalPos)
377 {
378  CDockWidgetTab* MovingTab = qobject_cast<CDockWidgetTab*>(sender());
379  if (!MovingTab)
380  {
381  return;
382  }
383 
384  int fromIndex = d->TabsLayout->indexOf(MovingTab);
385  auto MousePos = mapFromGlobal(GlobalPos);
386  MousePos.rx() = qMax(d->firstTab()->geometry().left(), MousePos.x());
387  MousePos.rx() = qMin(d->lastTab()->geometry().right(), MousePos.x());
388  int toIndex = -1;
389  // Find tab under mouse
390  for (int i = 0; i < count(); ++i)
391  {
392  CDockWidgetTab* DropTab = tab(i);
393  if (DropTab == MovingTab || !DropTab->isVisibleTo(this)
394  || !DropTab->geometry().contains(MousePos))
395  {
396  continue;
397  }
398 
399  toIndex = d->TabsLayout->indexOf(DropTab);
400  if (toIndex == fromIndex)
401  {
402  toIndex = -1;
403  }
404  break;
405  }
406 
407  if (toIndex > -1)
408  {
409  d->TabsLayout->removeWidget(MovingTab);
410  d->TabsLayout->insertWidget(toIndex, MovingTab);
411  ADS_PRINT("tabMoved from " << fromIndex << " to " << toIndex);
412  emit tabMoved(fromIndex, toIndex);
413  setCurrentIndex(toIndex);
414  }
415  else
416  {
417  // Ensure that the moved tab is reset to its start position
418  d->TabsLayout->update();
419  }
420 }
421 
422 //===========================================================================
424 {
425  if (Index < 0 || Index >= count())
426  {
427  return;
428  }
429 
430  auto Tab = tab(Index);
431  if (Tab->isHidden())
432  {
433  return;
434  }
435  emit tabCloseRequested(Index);
436 }
437 
438 
439 //===========================================================================
440 bool CDockAreaTabBar::eventFilter(QObject *watched, QEvent *event)
441 {
442  bool Result = Super::eventFilter(watched, event);
443  CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(watched);
444  if (!Tab)
445  {
446  return Result;
447  }
448 
449  switch (event->type())
450  {
451  case QEvent::Hide:
452  emit tabClosed(d->TabsLayout->indexOf(Tab));
453  updateGeometry();
454  break;
455 
456  case QEvent::Show:
457  emit tabOpened(d->TabsLayout->indexOf(Tab));
458  updateGeometry();
459  break;
460 
461  // Setting the text of a tab will cause a LayoutRequest event
462  case QEvent::LayoutRequest:
463  updateGeometry();
464  break;
465 
466  default:
467  break;
468  }
469 
470  return Result;
471 }
472 
473 
474 //===========================================================================
475 bool CDockAreaTabBar::isTabOpen(int Index) const
476 {
477  if (Index < 0 || Index >= count())
478  {
479  return false;
480  }
481 
482  return !tab(Index)->isHidden();
483 }
484 
485 
486 //===========================================================================
488 {
489  QSize Size = sizeHint();
490  Size.setWidth(10);
491  return Size;
492 }
493 
494 
495 //===========================================================================
497 {
498  return d->TabsContainerWidget->sizeHint();
499 }
500 
501 } // namespace ads
502 
503 
504 //---------------------------------------------------------------------------
505 // EOF DockAreaTabBar.cpp
Declaration of CDockWidgetTab class.
enum MQTTPropertyCodes value
void tabBarClicked(int index)
CDockWidgetTab * tab(int Index) const
void tabClosed(int index)
CDockWidgetTab * firstTab() const
virtual QSize minimumSizeHint() const override
MQTTClient d
Definition: test10.c:1656
deletes the dock widget when it is closed
Definition: DockWidget.h:153
virtual QSize sizeHint() const override
Declaration of CDockAreaTabBar class.
Declaration of CFloatingDockContainer class.
void insertTab(int Index, CDockWidgetTab *Tab)
void tabCloseRequested(int index)
CDockWidgetTab * currentTab() const
CDockWidgetTab * lastTab() const
void tabMoved(int from, int to)
void currentChanging(int Index)
Declaration of CFloatingDragPreview.
void closeTab(int Index)
CDockAreaWidget * DockArea
bool isTabOpen(int Index) const
#define ADS_PRINT(s)
Definition: ads_globals.h:60
DockAreaTabBarPrivate(CDockAreaTabBar *_public)
void currentChanged(int Index)
DockAreaTabBarPrivate * d
private data (pimpl)
virtual void wheelEvent(QWheelEvent *Event) override
void removeTab(CDockWidgetTab *Tab)
void tabInserted(int index)
void setCurrentIndex(int Index)
void elidedChanged(bool elided)
Declaration of CDockAreaWidget class.
void onTabWidgetMoved(const QPoint &GlobalPos)
Declaration of CDockWidget class.
Declaration of CDockManager class.
void removingTab(int index)
void tabOpened(int index)
virtual bool eventFilter(QObject *watched, QEvent *event) override
CDockAreaTabBar(CDockAreaWidget *parent)


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 03:47:34