• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdevelop API Reference
  • KDE Home
  • Contact Us
 

kdevplatform/sublime

  • sources
  • kfour-appscomplete
  • kdevelop
  • kdevplatform
  • sublime
container.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright 2006-2009 Alexander Dymo <[email protected]> *
3  * *
4  * This program is free software; you can redistribute it and/or modify *
5  * it under the terms of the GNU Library General Public License as *
6  * published by the Free Software Foundation; either version 2 of the *
7  * License, or (at your option) any later version. *
8  * *
9  * This program is distributed in the hope that it will be useful, *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12  * GNU General Public License for more details. *
13  * *
14  * You should have received a copy of the GNU Library General Public *
15  * License along with this program; if not, write to the *
16  * Free Software Foundation, Inc., *
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18  ***************************************************************************/
19 #include "container.h"
20 
21 #include <QApplication>
22 #include <QBoxLayout>
23 #include <QClipboard>
24 #include <QDir>
25 #include <QEvent>
26 #include <QSpacerItem>
27 #include <QLabel>
28 #include <QMenu>
29 #include <QMouseEvent>
30 #include <QPointer>
31 #include <QStackedWidget>
32 #include <QStyleFactory>
33 #include <QStyleOptionTabBarBase>
34 #include <QStylePainter>
35 #include <QTabBar>
36 #include <QToolButton>
37 #include <QWindow>
38 
39 #include <KAcceleratorManager>
40 #include <KConfigGroup>
41 #include <KLocalizedString>
42 #include <KSharedConfig>
43 
44 #include "view.h"
45 #include "urldocument.h"
46 
47 #include <KSqueezedTextLabel>
48 
49 namespace Sublime {
50 
51 // class ContainerTabBar
52 
53 class ContainerTabBar : public QTabBar
54 {
55  Q_OBJECT
56 
57 public:
58  explicit ContainerTabBar(Container* container)
59  : QTabBar(container), m_container(container)
60  {
61  if (QApplication::style()->objectName() == QLatin1String("macintosh")) {
62  static QPointer<QStyle> qTabBarStyle = QStyleFactory::create(QStringLiteral("fusion"));
63  if (qTabBarStyle) {
64  setStyle(qTabBarStyle);
65  }
66  }
67  // configure the QTabBar style so it behaves as appropriately as possible,
68  // even if we end up using the native Macintosh style because the user's
69  // Qt doesn't have the Fusion style installed.
70  setDocumentMode(true);
71  setUsesScrollButtons(true);
72  setElideMode(Qt::ElideNone);
73 
74  installEventFilter(this);
75  }
76 
77  bool event(QEvent* ev) override {
78  if(ev->type() == QEvent::ToolTip)
79  {
80  ev->accept();
81 
82  auto* helpEvent = static_cast<QHelpEvent*>(ev);
83  int tab = tabAt(helpEvent->pos());
84 
85  if(tab != -1)
86  {
87  m_container->showTooltipForTab(tab);
88  }
89 
90  return true;
91  }
92 
93  return QTabBar::event(ev);
94  }
95  void mousePressEvent(QMouseEvent* event) override {
96  if (event->button() == Qt::MiddleButton) {
97  // just close on midbutton, drag can still be done with left mouse button
98 
99  int tab = tabAt(event->pos());
100  if (tab != -1) {
101  emit tabCloseRequested(tab);
102  }
103  return;
104  }
105  QTabBar::mousePressEvent(event);
106  }
107 
108  bool eventFilter(QObject* obj, QEvent* event) override
109  {
110  if (obj != this) {
111  return QObject::eventFilter(obj, event);
112  }
113 
114  // TODO Qt6: Move to mouseDoubleClickEvent when fixme in qttabbar.cpp is resolved
115  // see "fixme Qt 6: move to mouseDoubleClickEvent(), here for BC reasons." in qtabbar.cpp
116  if (event->type() == QEvent::MouseButtonDblClick) {
117  // block tabBarDoubleClicked signals with RMB, see https://bugs.kde.org/show_bug.cgi?id=356016
118  auto mouseEvent = static_cast<const QMouseEvent*>(event);
119  if (mouseEvent->button() == Qt::MiddleButton) {
120  return true;
121  }
122  }
123 
124  return QObject::eventFilter(obj, event);
125  }
126 
127 Q_SIGNALS:
128  void newTabRequested();
129 
130 private:
131  Container* const m_container;
132 };
133 
134 bool sortViews(const View* const lhs, const View* const rhs)
135 {
136  return lhs->document()->title().compare(rhs->document()->title(), Qt::CaseInsensitive) < 0;
137 }
138 
139 #ifdef Q_OS_MACOS
140 // only one of these per process:
141 static QMenu* currentDockMenu = nullptr;
142 #endif
143 
144 class ContainerPrivate
145 {
146 public:
147  QBoxLayout* layout;
148  QHash<QWidget*, View*> viewForWidget;
149 
150  ContainerTabBar *tabBar;
151  QStackedWidget *stack;
152  KSqueezedTextLabel *fileNameCorner;
153  QSpacerItem* shortCutHelpLeftSpacerItem;
154  QSpacerItem* shortCutHelpRightSpacerItem;
155  QLabel *shortcutHelpLabel;
156  QLabel *fileStatus;
157  KSqueezedTextLabel *statusCorner;
158  QPointer<QWidget> leftCornerWidget;
159  QToolButton* documentListButton;
160  QMenu* documentListMenu;
161  QHash<View*, QAction*> documentListActionForView;
162 
170  void updateDocumentListPopupMenu()
171  {
172  qDeleteAll(documentListActionForView);
173  documentListActionForView.clear();
174  documentListMenu->clear();
175 
176  // create a lexicographically sorted list
177  QVector<View*> views;
178  views.reserve(viewForWidget.size());
179 
180  for (View* view : qAsConst(viewForWidget)) {
181  views << view;
182  }
183 
184  std::sort(views.begin(), views.end(), sortViews);
185 
186  for (int i = 0; i < views.size(); ++i) {
187  View *view = views.at(i);
188  QString visibleEntryTitle;
189  // if filename is not unique, prepend containing directory
190  if ((i < views.size() - 1 && view->document()->title() == views.at(i + 1)->document()->title())
191  || (i > 0 && view->document()->title() == views.at(i - 1)->document()->title())
192  ) {
193  auto urlDoc = qobject_cast<Sublime::UrlDocument*>(view->document());
194  if (!urlDoc) {
195  visibleEntryTitle = view->document()->title();
196  }
197  else {
198  auto url = urlDoc->url().toString();
199  int secondOffset = url.lastIndexOf(QLatin1Char('/'));
200  secondOffset = url.lastIndexOf(QLatin1Char('/'), secondOffset - 1);
201  visibleEntryTitle = url.right(url.length() - url.lastIndexOf(QLatin1Char('/'), secondOffset) - 1);
202  }
203  } else {
204  visibleEntryTitle = view->document()->title();
205  }
206  QAction* action = documentListMenu->addAction(visibleEntryTitle);
207  action->setData(QVariant::fromValue(view));
208  documentListActionForView[view] = action;
209  action->setIcon(view->document()->icon());
212  }
213 
214  setAsDockMenu();
215  }
216 
217  void setAsDockMenu()
218  {
219 #ifdef Q_OS_MACOS
220  if (documentListMenu != currentDockMenu) {
221  documentListMenu->setAsDockMenu();
222  currentDockMenu = documentListMenu;
223  }
224 #endif
225  }
226 
227  ~ContainerPrivate()
228  {
229 #ifdef Q_OS_MACOS
230  if (documentListMenu == currentDockMenu) {
231  QMenu().setAsDockMenu();
232  currentDockMenu = nullptr;
233  }
234 #endif
235  }
236 };
237 
238 class UnderlinedLabel: public KSqueezedTextLabel {
239 Q_OBJECT
240 public:
241  explicit UnderlinedLabel(QTabBar *tabBar, QWidget* parent = nullptr)
242  :KSqueezedTextLabel(parent), m_tabBar(tabBar)
243  {
244  }
245 
246 protected:
247  void paintEvent(QPaintEvent *ev) override
248  {
249 #ifndef Q_OS_OSX
250  // getting the underlining right on OS X is tricky; omitting
251  // the underlining attracts the eye less than not getting it
252  // exactly right.
253  if (m_tabBar->isVisible() && m_tabBar->count() > 0)
254  {
255  QStylePainter p(this);
256  QStyleOptionTabBarBase optTabBase;
257  optTabBase.init(m_tabBar);
258  optTabBase.shape = m_tabBar->shape();
259  optTabBase.tabBarRect = m_tabBar->rect();
260  optTabBase.tabBarRect.moveRight(0);
261 
262  QStyleOptionTab tabOverlap;
263  tabOverlap.shape = m_tabBar->shape();
264  int overlap = style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &tabOverlap, m_tabBar);
265  if( overlap > 0 )
266  {
267  QRect rect;
268  rect.setRect(0, height()-overlap, width(), overlap);
269  optTabBase.rect = rect;
270  }
271  if( m_tabBar->drawBase() )
272  {
273  p.drawPrimitive(QStyle::PE_FrameTabBarBase, optTabBase);
274  }
275  }
276 #endif
277 
278  KSqueezedTextLabel::paintEvent(ev);
279  }
280 
281  QTabBar *m_tabBar;
282 };
283 
284 
285 class StatusLabel: public UnderlinedLabel {
286 Q_OBJECT
287 public:
288  explicit StatusLabel(QTabBar *tabBar, QWidget* parent = nullptr):
289  UnderlinedLabel(tabBar, parent)
290  {
291  setAlignment(Qt::AlignRight | Qt::AlignVCenter);
292  setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
293  }
294 
295  QSize minimumSizeHint() const override
296  {
297  QRect rect = style()->itemTextRect(fontMetrics(), QRect(), Qt::AlignRight, true, i18n("Line: 00000 Col: 000"));
298  rect.setHeight(m_tabBar->height());
299  return rect.size();
300  }
301 };
302 
303 // class Container
304 
305 Container::Container(QWidget *parent)
306  : QWidget(parent)
307  , d_ptr(new ContainerPrivate())
308 {
309  Q_D(Container);
310 
311  KAcceleratorManager::setNoAccel(this);
312 
313  auto *l = new QBoxLayout(QBoxLayout::TopToBottom, this);
314  l->setContentsMargins(0, 0, 0, 0);
315  l->setSpacing(0);
316 
317  d->layout = new QBoxLayout(QBoxLayout::LeftToRight);
318  d->layout->setContentsMargins(0, 0, 0, 0);
319  d->layout->setSpacing(0);
320 
321  d->documentListMenu = new QMenu(this);
322  d->documentListButton = new QToolButton(this);
323  d->documentListButton->setIcon(QIcon::fromTheme(QStringLiteral("format-list-unordered")));
324  d->documentListButton->setMenu(d->documentListMenu);
325 #ifdef Q_OS_MACOS
326  // for maintaining the Dock menu:
327  setFocusPolicy(Qt::StrongFocus);
328 #endif
329  d->documentListButton->setPopupMode(QToolButton::InstantPopup);
330  d->documentListButton->setAutoRaise(true);
331  d->documentListButton->setToolTip(i18nc("@info:tooltip", "Show sorted list of opened documents"));
332  d->documentListButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
333  d->layout->addWidget(d->documentListButton);
334  d->tabBar = new ContainerTabBar(this);
335  d->tabBar->setContextMenuPolicy(Qt::CustomContextMenu);
336  d->layout->addWidget(d->tabBar);
337  d->fileStatus = new QLabel( this );
338  d->fileStatus->setFixedSize( QSize( 16, 16 ) );
339  d->layout->addWidget(d->fileStatus);
340  d->fileNameCorner = new UnderlinedLabel(d->tabBar, this);
341  d->fileNameCorner->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
342  d->layout->addWidget(d->fileNameCorner);
343  d->shortcutHelpLabel = new QLabel(i18nc("@info", "(Press Ctrl+Tab to switch)"), this);
344  auto font = d->shortcutHelpLabel->font();
345  font.setPointSize(font.pointSize() - 2);
346  font.setItalic(true);
347  d->shortcutHelpLabel->setFont(font);
348  d->shortCutHelpLeftSpacerItem = new QSpacerItem(0, 0); // fully set in setTabBarHidden()
349  d->layout->addSpacerItem(d->shortCutHelpLeftSpacerItem);
350  d->shortcutHelpLabel->setAlignment(Qt::AlignCenter);
351  d->layout->addWidget(d->shortcutHelpLabel);
352  d->shortCutHelpRightSpacerItem = new QSpacerItem(0, 0); // fully set in setTabBarHidden()
353  d->layout->addSpacerItem(d->shortCutHelpRightSpacerItem);
354  d->statusCorner = new StatusLabel(d->tabBar, this);
355  d->layout->addWidget(d->statusCorner);
356  l->addLayout(d->layout);
357 
358  d->stack = new QStackedWidget(this);
359  l->addWidget(d->stack);
360 
361  connect(d->tabBar, &ContainerTabBar::currentChanged, this, &Container::widgetActivated);
362  connect(d->tabBar, &ContainerTabBar::tabCloseRequested, this, QOverload<int>::of(&Container::requestClose));
363  connect(d->tabBar, &ContainerTabBar::newTabRequested, this, &Container::newTabRequested);
364  connect(d->tabBar, &ContainerTabBar::tabMoved, this, &Container::tabMoved);
365  connect(d->tabBar, &ContainerTabBar::customContextMenuRequested, this, &Container::contextMenu);
366  connect(d->tabBar, &ContainerTabBar::tabBarDoubleClicked, this, &Container::doubleClickTriggered);
367  connect(d->documentListMenu, &QMenu::triggered, this, &Container::documentListActionTriggered);
368 
369 
370  setTabBarHidden(!configTabBarVisible());
371  d->tabBar->setTabsClosable(configCloseButtonsOnTabs());
372  d->tabBar->setMovable(true);
373  d->tabBar->setExpanding(false);
374  d->tabBar->setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab);
375 }
376 
377 Container::~Container() = default;
378 
379 bool Container::configTabBarVisible()
380 {
381  KConfigGroup group = KSharedConfig::openConfig()->group("UiSettings");
382  return group.readEntry("TabBarVisibility", 1);
383 }
384 
385 bool Container::configCloseButtonsOnTabs()
386 {
387  KConfigGroup group = KSharedConfig::openConfig()->group("UiSettings");
388  return group.readEntry("CloseButtonsOnTabs", 1);
389 }
390 
391 void Container::setLeftCornerWidget(QWidget* widget)
392 {
393  Q_D(Container);
394 
395  if(d->leftCornerWidget.data() == widget) {
396  if(d->leftCornerWidget)
397  d->leftCornerWidget.data()->setParent(nullptr);
398  }else{
399  delete d->leftCornerWidget.data();
400  d->leftCornerWidget.clear();
401  }
402  d->leftCornerWidget = widget;
403  if(!widget)
404  return;
405  widget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
406  d->layout->insertWidget(0, widget);
407  widget->show();
408 }
409 
410 QList<View*> Container::views() const
411 {
412  Q_D(const Container);
413 
414  return d->viewForWidget.values();
415 }
416 
417 void Container::requestClose(int idx)
418 {
419  emit requestClose(widget(idx));
420 }
421 
422 void Container::widgetActivated(int idx)
423 {
424  Q_D(Container);
425 
426  if (idx < 0)
427  return;
428  if (QWidget* w = d->stack->widget(idx)) {
429  Sublime::View* view = d->viewForWidget.value(w);
430  if(view)
431  emit activateView(view);
432  }
433 }
434 
435 void Container::addWidget(View *view, int position)
436 {
437  Q_D(Container);
438 
439  QWidget *w = view->widget(this);
440  int idx = 0;
441  if (position != -1)
442  {
443  idx = d->stack->insertWidget(position, w);
444  }
445  else
446  idx = d->stack->addWidget(w);
447  d->tabBar->insertTab(idx, view->document()->statusIcon(), view->document()->title());
448  Q_ASSERT(view);
449  d->viewForWidget[w] = view;
450 
451  // Update document list context menu. This has to be called before
452  // setCurrentWidget, because we call the status icon and title update slots
453  // already, which in turn need the document list menu to be setup.
454  d->updateDocumentListPopupMenu();
455 
456  setCurrentWidget(d->stack->currentWidget());
457 
458  // This fixes a strange layouting bug, that could be reproduced like this: Open a few files in KDevelop, activate the rightmost tab.
459  // Then temporarily switch to another area, and then switch back. After that, the tab-bar was gone.
460  // The problem could only be fixed by closing/opening another view.
461  d->tabBar->setMinimumHeight(d->tabBar->sizeHint().height());
462 
463  connect(view, &View::statusChanged, this, &Container::statusChanged);
464  connect(view->document(), &Document::statusIconChanged, this, &Container::statusIconChanged);
465  connect(view->document(), &Document::titleChanged, this, &Container::documentTitleChanged);
466 }
467 
468 void Container::statusChanged(Sublime::View* view)
469 {
470  Q_D(Container);
471 
472  const auto statusText = view->viewStatus();
473  d->statusCorner->setText(statusText);
474  d->statusCorner->setVisible(!statusText.isEmpty());
475 }
476 
477 void Container::statusIconChanged(Document* doc)
478 {
479  Q_D(Container);
480 
481  QHashIterator<QWidget*, View*> it = d->viewForWidget;
482  while (it.hasNext()) {
483  if (it.next().value()->document() == doc) {
484  d->fileStatus->setPixmap( doc->statusIcon().pixmap( QSize( 16,16 ) ) );
485  int tabIndex = d->stack->indexOf(it.key());
486  if (tabIndex != -1) {
487  d->tabBar->setTabIcon(tabIndex, doc->statusIcon());
488  }
489 
490  // Update the document title's menu associated action
491  // using the View* index map
492  Q_ASSERT(d->documentListActionForView.contains(it.value()));
493  d->documentListActionForView[it.value()]->setIcon(doc->icon());
494  break;
495  }
496  }
497 }
498 
499 void Container::documentTitleChanged(Sublime::Document* doc)
500 {
501  Q_D(Container);
502 
503  QHashIterator<QWidget*, View*> it = d->viewForWidget;
504  while (it.hasNext()) {
505  Sublime::View* view = it.next().value();
506  if (view->document() == doc) {
507  if (currentView() == view) {
508  d->fileNameCorner->setText( doc->title(Document::Extended) );
509  // TODO KF6: remove this as soon as it is included upstream and we reqire
510  // that version
511  // see https://phabricator.kde.org/D7010
512  d->fileNameCorner->updateGeometry();
513  }
514  int tabIndex = d->stack->indexOf(it.key());
515  if (tabIndex != -1) {
516  d->tabBar->setTabText(tabIndex, doc->title());
517  }
518  break;
519  }
520  }
521  // Update document list popup title
522  d->updateDocumentListPopupMenu();
523 }
524 
525 int Container::count() const
526 {
527  Q_D(const Container);
528 
529  return d->stack->count();
530 }
531 
532 QWidget* Container::currentWidget() const
533 {
534  Q_D(const Container);
535 
536  return d->stack->currentWidget();
537 }
538 
539 void Container::setCurrentWidget(QWidget* w)
540 {
541  Q_D(Container);
542 
543  if (d->stack->currentWidget() == w) {
544  return;
545  }
546  d->stack->setCurrentWidget(w);
547  d->tabBar->setCurrentIndex(d->stack->indexOf(w));
548  if (View* view = viewForWidget(w))
549  {
550  statusChanged(view);
551  if (!d->tabBar->isVisible())
552  {
553  // repaint icon and document title only in tabbar-less mode
554  // tabbar will do repainting for us
555  statusIconChanged( view->document() );
556  documentTitleChanged( view->document() );
557  }
558  }
559 }
560 
561 QWidget* Container::widget(int i) const
562 {
563  Q_D(const Container);
564 
565  return d->stack->widget(i);
566 }
567 
568 int Container::indexOf(QWidget* w) const
569 {
570  Q_D(const Container);
571 
572  return d->stack->indexOf(w);
573 }
574 
575 void Container::removeWidget(QWidget *w)
576 {
577  Q_D(Container);
578 
579  if (w) {
580  int widgetIdx = d->stack->indexOf(w);
581  d->stack->removeWidget(w);
582  d->tabBar->removeTab(widgetIdx);
583  if (d->tabBar->currentIndex() != -1 && !d->tabBar->isVisible()) {
584  // repaint icon and document title only in tabbar-less mode
585  // tabbar will do repainting for us
586  View* view = currentView();
587  if( view ) {
588  statusIconChanged( view->document() );
589  documentTitleChanged( view->document() );
590  }
591  }
592  View* view = d->viewForWidget.take(w);
593  if (view)
594  {
595  disconnect(view->document(), &Document::titleChanged, this, &Container::documentTitleChanged);
596  disconnect(view->document(), &Document::statusIconChanged, this, &Container::statusIconChanged);
597  disconnect(view, &View::statusChanged, this, &Container::statusChanged);
598 
599  // Update document list context menu
600  Q_ASSERT(d->documentListActionForView.contains(view));
601  delete d->documentListActionForView.take(view);
602  }
603  }
604 }
605 
606 bool Container::hasWidget(QWidget* w) const
607 {
608  Q_D(const Container);
609 
610  return d->stack->indexOf(w) != -1;
611 }
612 
613 View *Container::viewForWidget(QWidget *w) const
614 {
615  Q_D(const Container);
616 
617  return d->viewForWidget.value(w);
618 }
619 
620 void Container::setTabBarHidden(bool hide)
621 {
622  Q_D(Container);
623 
624  if (hide)
625  {
626  d->tabBar->hide();
627  d->fileStatus->show();
628  d->shortCutHelpLeftSpacerItem->changeSize(style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing), 0,
629  QSizePolicy::Fixed, QSizePolicy::Fixed);
630  d->shortcutHelpLabel->show();
631  d->shortCutHelpRightSpacerItem->changeSize(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
632  d->fileNameCorner->show();
633  }
634  else
635  {
636  d->fileNameCorner->hide();
637  d->fileStatus->hide();
638  d->tabBar->show();
639  d->shortCutHelpLeftSpacerItem->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed);
640  d->shortcutHelpLabel->hide();
641  d->shortCutHelpRightSpacerItem->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed);
642  }
643  // have spacer item changes taken into account
644  d->layout->invalidate();
645 
646  View* v = currentView();
647  if (v) {
648  documentTitleChanged(v->document());
649  }
650 }
651 
652 void Container::setCloseButtonsOnTabs(bool show)
653 {
654  Q_D(Container);
655 
656  d->tabBar->setTabsClosable(show);
657 }
658 
659 void Container::resetTabColors(const QColor& color)
660 {
661  Q_D(Container);
662 
663  for (int i = 0; i < count(); i++){
664  d->tabBar->setTabTextColor(i, color);
665  }
666 }
667 
668 void Container::setTabColor(const View* view, const QColor& color)
669 {
670  Q_D(Container);
671 
672  for (int i = 0; i < count(); i++){
673  if (view == viewForWidget(widget(i))) {
674  d->tabBar->setTabTextColor(i, color);
675  }
676  }
677 }
678 
679 void Container::setTabColors(const QHash<const View*, QColor>& colors)
680 {
681  Q_D(Container);
682 
683  for (int i = 0; i < count(); i++) {
684  auto view = viewForWidget(widget(i));
685  auto color = colors[view];
686  if (color.isValid()) {
687  d->tabBar->setTabTextColor(i, color);
688  }
689  }
690 }
691 
692 void Container::tabMoved(int from, int to)
693 {
694  Q_D(Container);
695 
696  QWidget *w = d->stack->widget(from);
697  d->stack->removeWidget(w);
698  d->stack->insertWidget(to, w);
699  d->viewForWidget[w]->notifyPositionChanged(to);
700 }
701 
702 void Container::contextMenu( const QPoint& pos )
703 {
704  Q_D(Container);
705 
706  QWidget* senderWidget = qobject_cast<QWidget*>(sender());
707  Q_ASSERT(senderWidget);
708 
709  int currentTab = d->tabBar->tabAt(pos);
710 
711  QMenu menu;
712  // Polish before creating a native window below. The style could want change the surface format
713  // of the window which will have no effect when the native window has already been created.
714  menu.ensurePolished();
715  // At least for positioning on Wayland the window the menu belongs to
716  // needs to be set. We cannot set senderWidget as parent because some actions (e.g. split view)
717  // result in sync destruction of the senderWidget, which then would also prematurely
718  // destruct the menu object
719  // Workaround (best known currently, check again API of Qt >5.9):
720  menu.winId(); // trigger being a native widget already, to ensure windowHandle created
721  auto parentWindowHandle = senderWidget->windowHandle();
722  if (!parentWindowHandle) {
723  parentWindowHandle = senderWidget->nativeParentWidget()->windowHandle();
724  }
725  menu.windowHandle()->setTransientParent(parentWindowHandle);
726 
727  Sublime::View* view = viewForWidget(widget(currentTab));
728  emit tabContextMenuRequested(view, &menu);
729 
730  menu.addSeparator();
731  QAction* copyPathAction = nullptr;
732  QAction* closeTabAction = nullptr;
733  QAction* closeOtherTabsAction = nullptr;
734  if (view) {
735  copyPathAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")),
736  i18nc("@action:inmenu", "Copy Filename"));
737  menu.addSeparator();
738  closeTabAction = menu.addAction(QIcon::fromTheme(QStringLiteral("document-close")),
739  i18nc("@action:inmenu", "Close"));
740  closeOtherTabsAction = menu.addAction(QIcon::fromTheme(QStringLiteral("document-close")),
741  i18nc("@action:inmenu", "Close All Other"));
742  }
743  QAction* closeAllTabsAction = menu.addAction(QIcon::fromTheme(QStringLiteral("document-close")), i18nc("@action:inmenu", "Close All"));
744 
745  QAction* triggered = menu.exec(senderWidget->mapToGlobal(pos));
746 
747  if (triggered) {
748  if ( triggered == closeTabAction ) {
749  requestClose(currentTab);
750  } else if ( triggered == closeOtherTabsAction ) {
751  // activate the remaining tab
752  widgetActivated(currentTab);
753  // first get the widgets to be closed since otherwise the indices will be wrong
754  QList<QWidget*> otherTabs;
755  for ( int i = 0; i < count(); ++i ) {
756  if ( i != currentTab ) {
757  otherTabs << widget(i);
758  }
759  }
760  // finally close other tabs
761  for (QWidget* tab : qAsConst(otherTabs)) {
762  emit requestClose(tab);
763  }
764  } else if ( triggered == closeAllTabsAction ) {
765  // activate last tab
766  widgetActivated(count() - 1);
767 
768  // close all
769  for ( int i = 0; i < count(); ++i ) {
770  emit requestClose(widget(i));
771  }
772  } else if( triggered == copyPathAction ) {
773  auto view = viewForWidget( widget( currentTab ) );
774  auto urlDocument = qobject_cast<UrlDocument*>( view->document() );
775  if( urlDocument ) {
776  QString toCopy = urlDocument->url().toDisplayString(QUrl::PreferLocalFile);
777  if (urlDocument->url().isLocalFile()) {
778  toCopy = QDir::toNativeSeparators(toCopy);
779  }
780  QApplication::clipboard()->setText(toCopy);
781  }
782  } // else the action was handled by someone else
783  }
784 }
785 
786 void Container::showTooltipForTab(int tab)
787 {
788  emit tabToolTipRequested(viewForWidget(widget(tab)), this, tab);
789 }
790 
791 bool Container::isCurrentTab(int tab) const
792 {
793  Q_D(const Container);
794 
795  return d->tabBar->currentIndex() == tab;
796 }
797 
798 QRect Container::tabRect(int tab) const
799 {
800  Q_D(const Container);
801 
802  return d->tabBar->tabRect(tab).translated(d->tabBar->mapToGlobal(QPoint(0, 0)));
803 }
804 
805 void Container::doubleClickTriggered(int tab)
806 {
807  if (tab == -1) {
808  emit newTabRequested();
809  } else {
810  emit tabDoubleClicked(viewForWidget(widget(tab)));
811  }
812 }
813 
814 void Container::documentListActionTriggered(QAction* action)
815 {
816  Q_D(Container);
817 
818  auto* view = action->data().value< Sublime::View* >();
819  Q_ASSERT(view);
820  QWidget* widget = d->viewForWidget.key(view);
821  Q_ASSERT(widget);
822  setCurrentWidget(widget);
823 }
824 Sublime::View* Container::currentView() const
825 {
826  Q_D(const Container);
827 
828  return d->viewForWidget.value(widget( d->tabBar->currentIndex() ));
829 }
830 
831 void Container::focusInEvent(QFocusEvent* event)
832 {
833  Q_D(Container);
834 
835  d->setAsDockMenu();
836  QWidget::focusInEvent(event);
837 }
838 
839 }
840 
841 #include "container.moc"
QTabBar::event
virtual bool event(QEvent *event)
QMenu::triggered
void triggered(QAction *action)
QMouseEvent::pos
const QPoint & pos() const
QPointer
QColor
QApplication::clipboard
QClipboard * clipboard()
QWidget::ensurePolished
void ensurePolished() const
QRect::size
QSize size() const
QVariant::fromValue
QVariant fromValue(const T &value)
QWidget::setSizePolicy
void setSizePolicy(QSizePolicy)
QRect
QMouseEvent::button
Qt::MouseButton button() const
QWidget::setStyle
void setStyle(QStyle *style)
QVector::begin
iterator begin()
QTabBar::setUsesScrollButtons
void setUsesScrollButtons(bool useButtons)
QTabBar
QVariant::value
T value() const
Sublime::View
View - the wrapper to the widget that knows about its document.
Definition: view.h:48
QWidget
QHash::clear
void clear()
QIcon::fromTheme
QIcon fromTheme(const QString &name, const QIcon &fallback)
QMenu::addSeparator
QAction * addSeparator()
QMenu
QSize
Sublime::Container::newTabRequested
void newTabRequested()
This signal is emitted whenever the users double clicks on the free space next to the tab bar.
urldocument.h
QTabBar::tabAt
int tabAt(const QPoint &position) const
QString::lastIndexOf
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QList
QTabBar::mousePressEvent
virtual void mousePressEvent(QMouseEvent *event)
QHashIterator::value
const T & value() const
Sublime::View::viewStatus
virtual QString viewStatus() const
Retrieve information to be placed in the status bar.
Definition: view.cpp:164
QMouseEvent
QLabel
Sublime::Document::title
virtual QString title(TitleType type=Normal) const
Definition: document.cpp:123
QObject::eventFilter
virtual bool eventFilter(QObject *watched, QEvent *event)
Sublime
Definition: aggregatemodel.cpp:25
QAction::setIcon
void setIcon(const QIcon &icon)
Sublime::Document
Abstract base class for all Sublime documents.
Definition: document.h:44
QHash::size
int size() const
Sublime::Container
Container for the widgets.
Definition: container.h:39
QObject
QSpacerItem
QRect::setHeight
void setHeight(int height)
QString
QToolButton
QHashIterator::next
Item next()
QVector::at
const T & at(int i) const
QObject::installEventFilter
void installEventFilter(QObject *filterObj)
QDir::toNativeSeparators
QString toNativeSeparators(const QString &pathName)
container.h
QStyleOptionTabBarBase
QFocusEvent
QTabBar::tabCloseRequested
void tabCloseRequested(int index)
QStylePainter
QTabBar::setElideMode
void setElideMode(Qt::TextElideMode)
QWidget::mapToGlobal
QPoint mapToGlobal(const QPoint &pos) const
Sublime::Container::requestClose
void requestClose(QWidget *w)
QHashIterator
QClipboard::setText
void setText(const QString &text, Mode mode)
QLatin1String
QVector::reserve
void reserve(int size)
QWidget::focusInEvent
virtual void focusInEvent(QFocusEvent *event)
QWidget::show
void show()
QHashIterator::hasNext
bool hasNext() const
QStyleOptionTab
QAction::data
QVariant data() const
QAction::setData
void setData(const QVariant &userData)
QVector::end
iterator end()
QStackedWidget
QLatin1Char
QString::right
QString right(int n) const
QRect::setRect
void setRect(int x, int y, int width, int height)
QStyleFactory::create
QStyle * create(const QString &key)
QEvent::type
Type type() const
QEvent
QObject::objectName
objectName
QPaintEvent
QStyleOption::init
void init(const QWidget *widget)
QAction
QBoxLayout
view.h
QColor::isValid
bool isValid() const
QTabBar::setDocumentMode
void setDocumentMode(bool set)
QWidget::winId
WId winId() const
QVector::size
int size() const
QMenu::clear
void clear()
Sublime::sortViews
bool sortViews(const View *const lhs, const View *const rhs)
Definition: container.cpp:150
QWidget::nativeParentWidget
QWidget * nativeParentWidget() const
QVector
QMenu::addAction
void addAction(QAction *action)
Sublime::Document::icon
QIcon icon() const
Definition: document.cpp:199
QHash
Sublime::Container::Container
Container(QWidget *parent=nullptr)
Definition: container.cpp:321
QHashIterator::key
const Key & key() const
QApplication::style
QStyle * style()
QMenu::exec
QAction * exec()
QPoint
QEvent::accept
void accept()
Sublime::View::document
Document * document() const
Definition: view.cpp:86
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Jan 18 2021 23:35:49 by doxygen 1.8.16 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kdevplatform/sublime

Skip menu "kdevplatform/sublime"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdevelop API Reference

Skip menu "kdevelop API Reference"
  • kdevplatform
  •   debugger
  •   documentation
  •   interfaces
  •   language
  •     assistant
  •     backgroundparser
  •     checks
  •     classmodel
  •     codecompletion
  •     codegen
  •     duchain
  •     editor
  •     highlighting
  •     interfaces
  •     util
  •   outputview
  •   project
  •   serialization
  •   shell
  •   sublime
  •   tests
  •   util
  •   vcs

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal