Make sure the tabbar base line is always aligned with the tabbar
[kdevelop:agateau-kdevplatform.git] / sublime / mainwindow_p.cpp
1 /***************************************************************************
2  *   Copyright 2006-2009 Alexander Dymo  <adymo@kdevelop.org>              *
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 "mainwindow_p.h"
20
21 #include <QtGui/QMenu>
22 #include <QtGui/QLayout>
23 #include <QtGui/QSplitter>
24 #include <QtGui/QDockWidget>
25 #include <QtGui/QWidgetAction>
26 #include <QtGui/QComboBox>
27 #include <QtGui/QHBoxLayout>
28 #include <QtGui/QToolButton>
29 #include <QtGui/QCommonStyle>
30
31 #include <kdebug.h>
32 #include <klocale.h>
33 #include <kactionmenu.h>
34 #include <kacceleratormanager.h>
35 #include <kactioncollection.h>
36
37 #include "area.h"
38 #include "view.h"
39 #include "areaindex.h"
40 #include "document.h"
41 #include "container.h"
42 #include "controller.h"
43 #include "mainwindow.h"
44 #include "ideal.h"
45 #include <KToolBar>
46 #include <KSelectAction>
47 #include <ktoggleaction.h>
48
49 namespace Sublime {
50
51 MainWindowPrivate::MainWindowPrivate(MainWindow *w, Controller* controller)
52 :controller(controller), area(0), activeView(0), activeToolView(0), centralWidget(0),
53  ignoreDockShown(false), autoAreaSettingsSave(false), m_mainWindow(w)
54 {
55     KActionCollection *ac = m_mainWindow->actionCollection();
56
57     KAction* action = new KAction(i18n("Show Left Dock"), this);
58     action->setCheckable(true);
59     action->setShortcut(Qt::META | Qt::CTRL | Qt::Key_L);
60     connect(action, SIGNAL(toggled(bool)), SLOT(showLeftDock(bool)));
61     ac->addAction("show_left_dock", action);
62
63     action = new KAction(i18n("Show Right Dock"), this);
64     action->setCheckable(true);
65     action->setShortcut(Qt::META | Qt::CTRL | Qt::Key_R);
66     connect(action, SIGNAL(toggled(bool)), SLOT(showRightDock(bool)));
67     ac->addAction("show_right_dock", action);
68
69     action = new KAction(i18n("Show Bottom Dock"), this);
70     action->setCheckable(true);
71     action->setShortcut(Qt::META | Qt::CTRL | Qt::Key_B);
72     connect(action, SIGNAL(toggled(bool)), SLOT(showBottomDock(bool)));
73     ac->addAction("show_bottom_dock", action);
74
75     action = new KAction(i18n("Show Top Dock"), this);
76     action->setCheckable(true);
77     action->setShortcut(Qt::META | Qt::CTRL | Qt::Key_T);
78     connect(action, SIGNAL(toggled(bool)), SLOT(showTopDock(bool)));
79     ac->addAction("show_top_dock", action);
80
81     action = new KAction(i18n("Focus Editor"), this);
82     action->setShortcuts(QList<QKeySequence>() << (Qt::META | Qt::CTRL | Qt::Key_E) << Qt::META + Qt::Key_C);
83     connect(action, SIGNAL(triggered(bool)), this, SLOT(focusEditor()));
84     ac->addAction("focus_editor", action);
85
86     action = new KAction(i18n("Hide/Restore Docks"), this);
87     action->setShortcut(Qt::META | Qt::CTRL | Qt::Key_H);
88     connect(action, SIGNAL(triggered(bool)), SLOT(toggleDocksShown()));
89     ac->addAction("hide_all_docks", action);
90
91     action = new KAction(i18n("Next Tool View"), this);
92     action->setShortcut(Qt::META | Qt::CTRL | Qt::Key_N);
93     connect(action, SIGNAL(triggered(bool)), SLOT(selectNextDock()));
94     ac->addAction("select_next_dock", action);
95
96     action = new KAction(i18n("Previous Tool View"), this);
97     action->setShortcut(Qt::META | Qt::CTRL | Qt::Key_P);
98     connect(action, SIGNAL(triggered(bool)), SLOT(selectPreviousDock()));
99     ac->addAction("select_previous_dock", action);
100
101     action = new KAction(i18n("Remove view"), this);
102     connect(action, SIGNAL(triggered(bool)), SLOT(removeView()));
103     ac->addAction("remove_view", action);
104
105     action = new KAction(i18n("Anchor Current Dock"), this);
106     action->setCheckable(true);
107     action->setEnabled(false);
108     action->setShortcut(Qt::META | Qt::CTRL | Qt::Key_A);
109     connect(action, SIGNAL(toggled(bool)), SLOT(anchorCurrentDock(bool)));
110     ac->addAction("anchor_current_dock", action);
111
112     action = new KAction(i18n("Maximize Current Dock"), this);
113     action->setCheckable(true);
114     action->setEnabled(false);
115     connect(action, SIGNAL(toggled(bool)), SLOT(maximizeCurrentDock(bool)));
116     ac->addAction("maximize_current_dock", action);
117
118     action = new KActionMenu(i18n("Tool Views"), this);
119     ac->addAction("docks_submenu", action);
120
121     recreateCentralWidget();
122 }
123
124
125 MainWindowPrivate::~MainWindowPrivate()
126 {
127     delete m_leftTabbarCornerWidget;
128 }
129
130 void MainWindowPrivate::showLeftDock(bool b)
131 {
132     idealMainWidget->showLeftDock(b);
133 }
134
135 void MainWindowPrivate::showBottomDock(bool b)
136 {
137     idealMainWidget->showBottomDock(b);
138 }
139
140 void MainWindowPrivate::showRightDock(bool b)
141 {
142     idealMainWidget->showRightDock(b);
143 }
144
145 void MainWindowPrivate::showTopDock(bool b)
146 {
147     idealMainWidget->showTopDock(b);
148 }
149
150 void MainWindowPrivate::anchorCurrentDock(bool b)
151 {
152     idealMainWidget->anchorCurrentDock(b);
153 }
154
155 void MainWindowPrivate::maximizeCurrentDock(bool b)
156 {
157     idealMainWidget->maximizeCurrentDock(b);
158 }
159
160 void MainWindowPrivate::focusEditor()
161 {
162     idealMainWidget->focusEditor();
163 }
164
165 void MainWindowPrivate::toggleDocksShown()
166 {
167     idealMainWidget->toggleDocksShown();
168 }
169
170 void MainWindowPrivate::removeView()
171 {
172     idealMainWidget->removeView();
173 }
174
175 void MainWindowPrivate::selectNextDock()
176 {
177     idealMainWidget->selectNextDock();
178 }
179
180 void MainWindowPrivate::selectPreviousDock()
181 {
182     idealMainWidget->selectPreviousDock();
183 }
184
185 Area::WalkerMode MainWindowPrivate::IdealToolViewCreator::operator() (View *view, Sublime::Position position)
186 {
187     if (!d->docks.contains(view))
188     {
189         d->docks << view;
190         d->idealMainWidget->addView(d->positionToDockArea(position), view);
191     }
192     return Area::ContinueWalker;
193 }
194
195 Area::WalkerMode MainWindowPrivate::ViewCreator::operator() (AreaIndex *index)
196 {
197     kDebug() << "reconstructing views for area index" << index;
198     QSplitter *parent = 0;
199     QSplitter *splitter = d->m_indexSplitters.value(index);
200     if (!splitter)
201     {
202         //no splitter - we shall create it and populate with views
203         if (!index->parent())
204         {
205             kDebug() << "reconstructing root area";
206             //this is root area
207             splitter = new QSplitter(d->centralWidget);
208             d->m_indexSplitters[index] = splitter;
209             d->centralWidget->layout()->addWidget(splitter);
210         }
211         else
212         {
213             parent = d->m_indexSplitters[index->parent()];
214             Q_ASSERT(parent);
215             kDebug() << "adding new splitter to" << parent;
216             splitter = new QSplitter(parent);
217             d->m_indexSplitters[index] = splitter;
218             parent->addWidget(splitter);
219         }
220     }
221     splitter->show();
222
223     if (index->isSplitted()) //this is a visible splitter
224         splitter->setOrientation(index->orientation());
225     else
226     {
227         Container *container = 0;
228         if (!splitter->widget(0))
229         {
230             //we need to create view container
231             container = new Container(splitter);
232             connect(container, SIGNAL(activateView(Sublime::View*)), d->m_mainWindow, SLOT(activateView(Sublime::View*)));
233             connect(container, SIGNAL(tabContextMenuRequested(Sublime::View*,KMenu*)),
234                     d->m_mainWindow, SLOT(tabContextMenuRequested(Sublime::View*,KMenu*)));
235             connect(container, SIGNAL(tabToolTipRequested(Sublime::View*,QPoint)),
236                     d->m_mainWindow, SLOT(tabToolTipRequested(Sublime::View*,QPoint)));
237             connect(container, SIGNAL(closeRequest(QWidget*)),
238                     d, SLOT(widgetCloseRequest(QWidget*)));
239             splitter->addWidget(container);
240         }
241         else
242             container = qobject_cast<Container*>(splitter->widget(0));
243         container->show();
244
245         int position = 0;
246         foreach (View *view, index->views())
247         {
248             QWidget *widget = view->widget(container);
249             if (widget && !container->hasWidget(widget))
250             {
251                 widget->installEventFilter(d);
252                 foreach (QWidget* w, widget->findChildren<QWidget*>())
253                     w->installEventFilter(d);
254                 container->addWidget(view, position);
255                 d->viewContainers[view] = container;
256                 d->widgetToView[widget] = view;
257             }
258             position++;
259         }
260     }
261     return Area::ContinueWalker;
262 }
263
264 void MainWindowPrivate::reconstruct()
265 {
266     if(m_leftTabbarCornerWidget) {
267         m_leftTabbarCornerWidget->hide();
268         m_leftTabbarCornerWidget->setParent(0);
269     }
270     
271     IdealToolViewCreator toolViewCreator(this);
272     area->walkToolViews(toolViewCreator, Sublime::AllPositions);
273
274     ViewCreator viewCreator(this);
275     area->walkViews(viewCreator, area->rootIndex());
276
277     idealMainWidget->blockSignals(true);
278     IdealMainLayout *l = idealMainWidget->mainLayout();
279     l->setWidthForRole(IdealMainLayout::Left, area->thickness(Sublime::Left));
280     l->setWidthForRole(IdealMainLayout::Right, area->thickness(Sublime::Right));
281     l->setWidthForRole(IdealMainLayout::Bottom,
282                        area->thickness(Sublime::Bottom));
283     l->setWidthForRole(IdealMainLayout::Top, area->thickness(Sublime::Top));
284     kDebug() << "RECONSTRUCT" << area << "  " << area->shownToolView(Sublime::Left) << "\n";
285     foreach (View *view, area->toolViews())
286     {
287         QString id = view->document()->documentSpecifier();
288         if (!id.isEmpty())
289         {
290             Sublime::Position pos = area->toolViewPosition(view);
291             if (area->shownToolView(pos) == id)
292                 idealMainWidget->raiseView(view);
293         }
294     }
295     idealMainWidget->blockSignals(false);
296     
297     setTabBarLeftCornerWidget(m_leftTabbarCornerWidget);
298 }
299
300 void MainWindowPrivate::clearArea()
301 {
302     if(m_leftTabbarCornerWidget)
303         m_leftTabbarCornerWidget->setParent(0);
304     
305     //reparent toolview widgets to 0 to prevent their deletion together with dockwidgets
306     foreach (View *view, area->toolViews())
307     {
308         // FIXME should we really delete here??
309         bool nonDestructive = true;
310         idealMainWidget->removeView(view, nonDestructive);
311
312         if (view->hasWidget())
313             view->widget()->setParent(0);
314     }
315
316     docks.clear();
317
318     //reparent all view widgets to 0 to prevent their deletion together with central
319     //widget. this reparenting is necessary when switching areas inside the same mainwindow
320     foreach (View *view, area->views())
321     {
322         if (view->hasWidget())
323             view->widget()->setParent(0);
324     }
325     recreateCentralWidget();
326     m_mainWindow->setActiveView(0);
327     m_indexSplitters.clear();
328     area = 0;
329     viewContainers.clear();
330     
331     setTabBarLeftCornerWidget(m_leftTabbarCornerWidget);
332 }
333
334 void MainWindowPrivate::recreateCentralWidget()
335 {
336     idealMainWidget = new IdealMainWidget(m_mainWindow, m_mainWindow->actionCollection());
337     m_mainWindow->setCentralWidget(idealMainWidget);
338
339     centralWidget = new QWidget();
340     idealMainWidget->setCentralWidget(centralWidget);
341
342     QVBoxLayout* layout = new QVBoxLayout(centralWidget);
343     layout->setMargin(0);
344     centralWidget->setLayout(layout);
345
346     connect(idealMainWidget,
347             SIGNAL(dockShown(Sublime::View*, Sublime::Position, bool)),
348             this,
349             SLOT(slotDockShown(Sublime::View*, Sublime::Position, bool)));
350
351     connect(idealMainWidget->mainLayout(),
352             SIGNAL(widgetResized(IdealMainLayout::Role, int)),
353             this,
354             SLOT(widgetResized(IdealMainLayout::Role, int)));
355
356     connect(idealMainWidget, SIGNAL(dockBarContextMenuRequested(Qt::DockWidgetArea, const QPoint&)),
357             m_mainWindow, SLOT(dockBarContextMenuRequested(Qt::DockWidgetArea, const QPoint&)));
358 }
359
360 void MainWindowPrivate::
361 slotDockShown(Sublime::View* view, Sublime::Position pos, bool shown)
362 {
363     if (ignoreDockShown)
364         return;
365
366     QString id;
367     if (shown)
368         id = view->document()->documentSpecifier();
369     kDebug() << "View " << view->document()->documentSpecifier() << " " << shown;
370     area->setShownToolView(pos, id);
371 }
372
373 void MainWindowPrivate::viewRemovedInternal(AreaIndex* index, View* view)
374 {
375     Q_UNUSED(index);
376     Q_UNUSED(view);
377     // A formerly non-empty working-set has become empty, and a relayout of the area-selector may be required
378     if(m_mainWindow->area()->views().size() == 0)
379         m_mainWindow->setupAreaSelector();
380 }
381
382 void MainWindowPrivate::viewAdded(Sublime::AreaIndex *index, Sublime::View *view)
383 {
384     if(m_leftTabbarCornerWidget) {
385         m_leftTabbarCornerWidget->hide();
386         m_leftTabbarCornerWidget->setParent(0);
387     }
388     
389     ViewCreator viewCreator(this);
390     QSplitter *splitter = m_indexSplitters[index];
391     if (index->isSplitted() && (splitter->count() == 1) &&
392             qobject_cast<Sublime::Container*>(splitter->widget(0)))
393     {
394         Container *container = qobject_cast<Sublime::Container*>(splitter->widget(0));
395         //we need to remove extra container before reconstruction
396         //first reparent widgets in container so that they are not deleted
397         while (container->count())
398         {
399             container->widget(0)->setParent(0);
400         }
401         //and then delete the container
402         delete container;
403     }
404     area->walkViews(viewCreator, index);
405     emit m_mainWindow->viewAdded( view );
406     
407     setTabBarLeftCornerWidget(m_leftTabbarCornerWidget);
408     
409     // A formerly empty working-set may become non-empty, and a relayout of the area-selector may be required
410     if(m_mainWindow->area()->views().size() == 1)
411         m_mainWindow->setupAreaSelector();
412 }
413
414 void Sublime::MainWindowPrivate::raiseToolView(Sublime::View * view)
415 {
416     idealMainWidget->raiseView(view);
417 }
418
419 void MainWindowPrivate::aboutToRemoveView(Sublime::AreaIndex *index, Sublime::View *view)
420 {
421     if (!m_indexSplitters.contains(index))
422         return;
423
424     QSplitter *splitter = m_indexSplitters[index];
425     kDebug() << "index " << index << " root " << area->rootIndex();
426     kDebug() << "splitter " << splitter << " container " << splitter->widget(0);
427     //find the container for the view and remove the widget
428     Container *container = qobject_cast<Container*>(splitter->widget(0));
429     if (!container) {
430         kWarning() << "Splitter does not have a left widget!";
431         return;
432     }
433     
434     emit m_mainWindow->aboutToRemoveView( view );
435
436     if (view->widget())
437         widgetToView.remove(view->widget());
438     viewContainers.remove(view);
439
440     const bool wasActive = m_mainWindow->activeView() == view;
441     if (container->count() > 1)
442     {
443         //container is not empty or this is a root index
444         //just remove a widget
445                 if( view->widget() ) {
446                         container->removeWidget(view->widget());
447                         view->widget()->setParent(0);
448                         //activate what is visible currently in the container if the removed view was active
449                         if (wasActive)
450                                 return m_mainWindow->setActiveView(container->viewForWidget(container->currentWidget()));
451                 }
452     }
453     else
454     {
455         if(m_leftTabbarCornerWidget) {
456             m_leftTabbarCornerWidget->hide();
457             m_leftTabbarCornerWidget->setParent(0);
458         }
459         
460         // We've about to remove the last view of this container.  It will
461         // be empty, so have to delete it, as well.
462
463         // If we have a container, then it should be the only child of
464         // the splitter.
465         Q_ASSERT(splitter->count() == 1);
466         container->removeWidget(view->widget());
467
468         if (view->widget())
469             view->widget()->setParent(0);
470         else
471             kWarning() << "View does not have a widget!";
472
473         Q_ASSERT(container->count() == 0);
474         // We can be called from signal handler of container
475         // (which is tab widget), so defer deleting it.
476         container->deleteLater();
477         container->setParent(0);
478
479         /* If we're not at the top level, we get to collapse split views.  */
480         if (index->parent())
481         {
482             /* The splitter used to have container as the only child, now it's
483                time to get rid of it.  Make sure deleting splitter does not
484                delete container -- per above comment, we'll delete it later.  */
485             QCommonStyle* tmpStyle = new QCommonStyle; // temp style since container uses it's parents style, which gets zeroed
486             container->setStyle(tmpStyle);
487             connect(container, SIGNAL(destroyed(QObject*)), tmpStyle, SLOT(deleteLater()));
488             container->setParent(0);
489             m_indexSplitters.remove(index);
490             delete splitter;
491
492             AreaIndex *parent = index->parent();
493             QSplitter *parentSplitter = m_indexSplitters[parent];
494
495             AreaIndex *sibling = parent->first() == index ? parent->second() : parent->first();
496             QSplitter *siblingSplitter = m_indexSplitters[sibling];
497
498             parentSplitter->setUpdatesEnabled(false);
499             //save sizes and orientation of the sibling splitter
500             parentSplitter->setOrientation(siblingSplitter->orientation());
501             QList<int> sizes = siblingSplitter->sizes();
502
503             /* Parent has two children -- 'index' that we've deleted and
504                'sibling'.  We move all children of 'sibling' into parent,
505                and delete 'sibling'.  sibling either contains a single
506                Container instance, or a bunch of further QSplitters.  */
507             while (siblingSplitter->count() > 0)
508             {
509                 //reparent contents into parent splitter
510                 QWidget *siblingWidget = siblingSplitter->widget(0);
511                 siblingWidget->setParent(parentSplitter);
512                 parentSplitter->addWidget(siblingWidget);
513             }
514
515             m_indexSplitters.remove(sibling);
516             delete siblingSplitter;
517
518             parentSplitter->setSizes(sizes);
519             parentSplitter->setUpdatesEnabled(true);
520
521             kDebug() << "after deleation " << parent << " has "
522                          << parentSplitter->count() << " elements";
523
524             
525             //find the container somewhere to activate
526             Container *containerToActivate = parentSplitter->findChild<Sublime::Container*>();
527             //activate the current view there
528             if (containerToActivate) {
529                 m_mainWindow->setActiveView(containerToActivate->viewForWidget(containerToActivate->currentWidget()));
530                 setTabBarLeftCornerWidget(m_leftTabbarCornerWidget);
531                 return;
532             }
533         }
534     }
535
536     setTabBarLeftCornerWidget(m_leftTabbarCornerWidget);
537     if ( wasActive ) {
538         m_mainWindow->setActiveView(0L);
539     }
540 }
541
542 void MainWindowPrivate::toolViewAdded(Sublime::View* /*toolView*/, Sublime::Position position)
543 {
544     IdealToolViewCreator toolViewCreator(this);
545     area->walkToolViews(toolViewCreator, position);
546 }
547
548 void MainWindowPrivate::aboutToRemoveToolView(Sublime::View *toolView, Sublime::Position /*position*/)
549 {
550     if (!docks.contains(toolView))
551         return;
552
553     idealMainWidget->removeView(toolView);
554     // TODO are Views unique?
555     docks.removeAll(toolView);
556 }
557
558 void MainWindowPrivate::toolViewMoved(
559     Sublime::View *toolView, Sublime::Position position)
560 {
561     if (!docks.contains(toolView))
562         return;
563
564     idealMainWidget->moveView(toolView, positionToDockArea(position));
565 }
566
567 Qt::DockWidgetArea MainWindowPrivate::positionToDockArea(Position position)
568 {
569     switch (position)
570     {
571         case Sublime::Left: return Qt::LeftDockWidgetArea;
572         case Sublime::Right: return Qt::RightDockWidgetArea;
573         case Sublime::Bottom: return Qt::BottomDockWidgetArea;
574         case Sublime::Top: return Qt::TopDockWidgetArea;
575         default: return Qt::LeftDockWidgetArea;
576     }
577 }
578
579 void MainWindowPrivate::switchToArea(QAction *action)
580 {
581     kDebug() << "for" << action;
582     controller->showArea(m_actionAreas[action], m_mainWindow);
583 }
584
585 void MainWindowPrivate::updateAreaSwitcher(Sublime::Area *area)
586 {
587     if (m_areaActions.contains(area))
588         m_areaActions[area]->setChecked(true);
589 }
590
591 void MainWindowPrivate::activateFirstVisibleView()
592 {
593     if (area->views().count() > 0)
594         m_mainWindow->activateView(area->views().first());
595 }
596
597 bool MainWindowPrivate::eventFilter(QObject *, QEvent *event)
598 {
599     if (event->type() == QEvent::FocusIn)
600         idealMainWidget->centralWidgetFocused();
601
602     return false;
603 }
604
605 void MainWindowPrivate::widgetResized(IdealMainLayout::Role role, int thickness)
606 {
607     area->setThickness(IdealMainLayout::positionForRole(role), thickness);
608 }
609
610 void MainWindowPrivate::widgetCloseRequest(QWidget* widget)
611 {
612     if (widgetToView.contains(widget))
613     {
614         View *view = widgetToView[widget];
615         area->closeView(view);
616     }
617 }
618
619 void MainWindowPrivate::toggleArea ( int index ) {
620     m_mainWindow->controller()->showArea(areaSwitcher->tabBar()->areaId(index), m_mainWindow);
621 }
622
623 void AreaTabBar::paintEvent ( QPaintEvent* ev ) {
624     QTabBar::paintEvent(ev);
625     if ( currentIndex() != -1 ) {
626         QStylePainter p ( this );
627         //Draw highlight behind current area
628         QRect activeRect = tabRect ( currentIndex() );
629         QRect tabArea = activeRect;
630         QImage img ( tabArea.width(), tabArea.height(), QImage::Format_ARGB32 );
631         img.fill ( 0 );
632         QPainter paintImg ( &img );
633         QColor color ( palette().color ( QPalette::Active, QPalette::Highlight ) );
634         color.setAlpha ( 70 );
635         QRect paint = tabArea;
636         const int margin = 8;
637         paint.setLeft ( margin );
638         paint.setTop ( margin );
639         paint.setRight ( activeRect.width()-margin );
640         paint.setBottom ( activeRect.height()-margin );
641
642         paintImg.fillRect ( paint, color );
643         expblur<16,7> ( img, margin/2 );
644         p.drawImage ( tabArea, img );
645     }
646 }
647
648 void AreaTabWidget::paintEvent ( QPaintEvent* ev ) {
649     QWidget::paintEvent ( ev );
650
651     if ( m_tabBar->isVisible() && m_tabBar->count() > 0 ) {
652         QStylePainter p ( this );
653
654         QStyleOptionTabBarBase optTabBase;
655         optTabBase.init ( m_tabBar );
656         optTabBase.shape = m_tabBar->shape();
657         optTabBase.tabBarRect = m_tabBar->rect();
658         optTabBase.tabBarRect.moveTopLeft(m_tabBar->pos());
659
660         int sideWidth = width()-m_tabBar->width();
661
662         QStyleOptionTab tabOverlap;
663         tabOverlap.shape = m_tabBar->shape();
664         int overlap = style()->pixelMetric ( QStyle::PM_TabBarBaseOverlap, &tabOverlap, m_tabBar );
665         QRect rect;
666         rect.setRect ( 0, m_tabBar->height()-overlap, sideWidth, overlap );
667         optTabBase.rect = rect;
668
669         QImage img ( sideWidth, height(), QImage::Format_ARGB32 );
670         img.fill ( 0 );
671         QStylePainter p2 ( &img, m_tabBar );
672         p2.drawPrimitive ( QStyle::PE_FrameTabBarBase, optTabBase );
673
674         {
675             //Blend the painted line out to the left
676             QLinearGradient blendOut ( 0, 0, sideWidth, 0 );
677             blendOut.setColorAt ( 0, QColor ( 255, 255, 255, 255 ) );
678             blendOut.setColorAt ( 1, QColor ( 0, 0, 0, 0 ) );
679             QBrush blendBrush ( blendOut );
680
681             p2.setCompositionMode ( QPainter::CompositionMode_DestinationOut );
682             p2.fillRect ( img.rect(), blendBrush );
683         }
684
685         p.setCompositionMode ( QPainter::CompositionMode_SourceOver );
686         p.drawImage ( img.rect(), img );
687     }
688 }
689
690 QSize AreaTabWidget::sizeHint() const {
691     QMenuBar* bar = qobject_cast<QMenuBar*>(parent());
692     if ( !bar ) {
693         return QWidget::sizeHint();
694     }
695     //Resize to hold the whole length up to the menu
696     static bool zeroSizeHint = false;
697     if ( zeroSizeHint )
698         return QSize();
699     zeroSizeHint = true;
700     int available = bar->parentWidget()->width() - bar->sizeHint().width() - 10;
701     zeroSizeHint = false;
702     QSize orig = m_tabBar->sizeHint();
703     int addFade = available - orig.width();
704     
705     int perfectFade = 500;
706     if(areaSideWidget)
707         perfectFade += areaSideWidget->sizeHint().width();
708     
709     if(addFade > perfectFade)
710         addFade = perfectFade;
711     
712     int wantWidth = addFade + orig.width();
713     
714     if ( wantWidth > orig.width() )
715         orig.setWidth ( wantWidth );
716     return orig;
717 }
718
719 AreaTabWidget::AreaTabWidget ( QWidget* parent ) : QWidget ( parent ), areaSideWidget(0) {
720     m_layout = new QHBoxLayout ( this );
721     m_layout->setAlignment ( Qt::AlignRight );
722     m_tabBar = new AreaTabBar ( this );
723     m_layout->addWidget ( m_tabBar );
724     m_layout->setContentsMargins ( 0,0,0,0 );
725     m_leftLayout = new QVBoxLayout;
726     
727     m_leftLayout->setContentsMargins(11, 4, 11, 8); ///@todo These margins are a bit too hardcoded, should depend on style
728     m_layout->insertLayout(0, m_leftLayout);
729 }
730
731 QSize AreaTabBar::tabSizeHint ( int index ) const {
732     //Since we move all contents into the button, we give approximately the button size as size-hint
733     //QTabBar seems to add useless space for the non-existing tab text
734     QSize ret = QTabBar::tabSizeHint(index);
735     
736     if(ret.width() > buttons[index]->sizeHint().width()+16)
737         ret.setWidth(buttons[index]->sizeHint().width() + 16); ///@todo Where does the offset come from?
738     return ret;
739 }
740
741
742 void AreaTabButton::setIsCurrent ( bool arg1 ) {
743     m_isCurrent = arg1;
744 }
745
746 void AreaTabBar::setCurrentIndex ( int index ) {
747     m_currentIndex = index;
748     foreach(AreaTabButton* button, buttons) {
749         button->setIsCurrent(buttons.indexOf(button) == index);
750     }
751     QTabBar::setCurrentIndex ( index );
752     foreach(AreaTabButton* button, buttons) {
753         button->update();
754     }
755     update();
756 }
757
758 AreaTabBar::AreaTabBar ( QWidget* parent ) : QTabBar ( parent ), m_currentIndex ( -1 ) {
759     setShape ( QTabBar::RoundedNorth );
760     setDocumentMode ( true );
761     setExpanding ( false );
762     setLayoutDirection ( Qt::RightToLeft );
763     setDrawBase ( false );
764     setUsesScrollButtons ( false );
765     setFocusPolicy( Qt::NoFocus );
766     QPalette pal = palette();
767 }
768
769 AreaTabButton::AreaTabButton ( QString text, QIcon icon, uint iconSize, QWidget* parent, bool isCurrent, QWidget* _customButtonWidget )
770         : QWidget ( parent ), customButtonWidget(_customButtonWidget), m_isCurrent ( isCurrent )
771 {
772     QHBoxLayout* layout = new QHBoxLayout ( this );
773     iconLabel = new QLabel ( this );
774     iconLabel->setPixmap ( icon.pixmap ( QSize ( iconSize, iconSize ) ) );
775     iconLabel->setAutoFillBackground ( false );
776     textLabel = new QLabel ( this );
777     textLabel->setText ( text );
778     textLabel->setAutoFillBackground ( false );
779     if(customButtonWidget) {
780         customButtonWidget->setParent(this);
781         layout->addWidget(customButtonWidget);
782     }
783     layout->addWidget ( textLabel );
784     layout->addWidget ( iconLabel );
785     layout->setMargin ( 0 );
786 }
787
788 void MainWindowPrivate::setTabBarLeftCornerWidget(QWidget* widget)
789 {
790     if(widget != m_leftTabbarCornerWidget)
791         delete m_leftTabbarCornerWidget;
792     m_leftTabbarCornerWidget = widget;
793     
794     if(!widget || !area || viewContainers.isEmpty())
795         return;
796     
797     AreaIndex* putToIndex = area->rootIndex();
798     QSplitter* splitter = m_indexSplitters[putToIndex];
799     while(putToIndex->isSplitted()) {
800         putToIndex = putToIndex->first();
801         splitter = m_indexSplitters[putToIndex];
802     }
803     
804 //     Q_ASSERT(splitter || putToIndex == area->rootIndex());
805     
806     Container* c = 0;
807     if(splitter) {
808         c = qobject_cast<Container*>(splitter->widget(0));
809     }else{
810         c = viewContainers.values()[0];
811     }
812     Q_ASSERT(c);
813     
814     c->setLeftCornerWidget(widget);
815 }
816
817 }
818
819 #include "mainwindow_p.moc"
820