File indexing completed on 2024-04-28 05:41:37

0001 /*
0002     This file is part of KCachegrind.
0003 
0004     SPDX-FileCopyrightText: 2003-2016 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only
0007 */
0008 
0009 /*
0010  * Tab View, enclosing detailed views for one trace item in
0011  * two tab widgets, separated by a splitter
0012  */
0013 
0014 
0015 #include "tabview.h"
0016 
0017 #include <QLabel>
0018 #include <QSplitter>
0019 #include <QTabWidget>
0020 #include <QHideEvent>
0021 #include <QMoveEvent>
0022 #include <QEvent>
0023 #include <QShowEvent>
0024 #include <QVBoxLayout>
0025 #include <QResizeEvent>
0026 #include <QMouseEvent>
0027 #include <QAction>
0028 #include <QMenu>
0029 
0030 #include "config.h"
0031 #include "globalconfig.h"
0032 #include "eventtypeview.h"
0033 #include "partview.h"
0034 #include "callview.h"
0035 #include "coverageview.h"
0036 #include "callmapview.h"
0037 #include "instrview.h"
0038 #include "sourceview.h"
0039 #include "callgraphview.h"
0040 
0041 
0042 // defaults for subviews in TabView
0043 
0044 #define DEFAULT_TOPTABS \
0045     "EventTypeView" << "CallerView" << "AllCallerView" \
0046     << "CalleeMapView" << "SourceView"
0047 #define DEFAULT_BOTTOMTABS \
0048     "PartView" << "CalleeView" << "CallGraphView" \
0049     << "AllCalleeView" << "CallerMapView" << "InstrView"
0050 
0051 #define DEFAULT_ACTIVETOP "CallerView"
0052 #define DEFAULT_ACTIVEBOTTOM "CalleeView"
0053 
0054 #define DEFAULT_RIGHTSIZE 0
0055 #define DEFAULT_TOPSIZE   50
0056 #define DEFAULT_LEFTSIZE  0
0057 
0058 // TabBar
0059 
0060 TabBar::TabBar(TabView* v, QTabWidget* parent) :
0061     QTabBar(parent)
0062 {
0063     _tabWidget = parent;
0064     _tabView = v;
0065 }
0066 
0067 void TabBar::mousePressEvent(QMouseEvent *e)
0068 {
0069     if (e->button() == Qt::RightButton) {
0070         int idx = tabAt(e->pos());
0071         QWidget* page = nullptr;
0072         if (idx >=0) {
0073             setCurrentIndex(idx);
0074             page = _tabWidget->widget(idx);
0075         }
0076         context(page, e->globalPos());
0077     }
0078     QTabBar::mousePressEvent(e );
0079 }
0080 
0081 void TabBar::context(QWidget* page, const QPoint & pos)
0082 {
0083     QMenu popup, popup2, popup3;
0084 
0085     QAction* pageToTopAction = nullptr;
0086     QAction* areaToTopAction = nullptr;
0087     QAction* showOnTopAction = nullptr;
0088     QAction* pageToRightAction = nullptr;
0089     QAction* areaToRightAction = nullptr;
0090     QAction* showOnRightAction = nullptr;
0091     QAction* pageToBottomAction = nullptr;
0092     QAction* areaToBottomAction = nullptr;
0093     QAction* showOnBottomAction = nullptr;
0094     QAction* pageToLeftAction = nullptr;
0095     QAction* areaToLeftAction = nullptr;
0096     QAction* showOnLeftAction = nullptr;
0097     QAction* hidePageAction = nullptr;
0098     QAction* hideAreaAction = nullptr;
0099 
0100     if (page) {
0101         TraceItemView::Position p = _tabView->tabPosition(page);
0102         if (p != TraceItemView::Top) {
0103             pageToTopAction = popup.addAction(tr("Move to Top"));
0104             areaToTopAction = popup2.addAction(tr("Top", "Move to Top"));
0105         }
0106         if (p != TraceItemView::Right) {
0107             pageToRightAction = popup.addAction(tr("Move to Right"));
0108             areaToRightAction = popup2.addAction(tr("Right", "Move to Right"));
0109         }
0110         if (p != TraceItemView::Bottom) {
0111             pageToBottomAction = popup.addAction(tr("Move to Bottom"));
0112             areaToBottomAction = popup2.addAction(tr("Bottom", "Move to Bottom"));
0113         }
0114         if (p != TraceItemView::Left) {
0115             pageToLeftAction = popup.addAction(tr("Move to Bottom Left"));
0116             areaToLeftAction = popup2.addAction(tr("Bottom Left", "Move to Bottom Left"));
0117         }
0118         popup2.setTitle(tr("Move Area To"));
0119         popup.addMenu(&popup2);
0120         popup.addSeparator();
0121         hidePageAction = popup.addAction(tr("Hide This Tab"));
0122         hideAreaAction = popup.addAction(tr("Hide Area"));
0123 
0124         if (_tabView->visibleTabs() <2) {
0125             hidePageAction->setEnabled(false);
0126             hideAreaAction->setEnabled(false);
0127         } else if (_tabView->visibleAreas() <2)
0128             hideAreaAction->setEnabled(false);
0129     }
0130 
0131     showOnTopAction = popup3.addAction(tr("Top", "Show on Top"));
0132     showOnRightAction = popup3.addAction(tr("Right", "Show on Right"));
0133     showOnBottomAction = popup3.addAction(tr("Bottom", "Show on Bottom"));
0134     showOnLeftAction = popup3.addAction(tr("Bottom Left", "Show on Bottom Left"));
0135     popup3.setTitle(tr("Show Hidden On"));
0136     popup.addMenu(&popup3);
0137 
0138     QAction* a = popup.exec(pos);
0139     if (a == hidePageAction)
0140         _tabView->moveTab(page, TraceItemView::Hidden, false);
0141     else if (a == hideAreaAction)
0142         _tabView->moveTab(page, TraceItemView::Hidden, true);
0143 
0144     else if (a == pageToTopAction)
0145         _tabView->moveTab(page, TraceItemView::Top, false);
0146     else if (a == pageToRightAction)
0147         _tabView->moveTab(page, TraceItemView::Right, false);
0148     else if (a == pageToBottomAction)
0149         _tabView->moveTab(page, TraceItemView::Bottom, false);
0150     else if (a == pageToLeftAction)
0151         _tabView->moveTab(page, TraceItemView::Left, false);
0152 
0153     else if (a == areaToTopAction)
0154         _tabView->moveTab(page, TraceItemView::Top, true);
0155     else if (a == areaToRightAction)
0156         _tabView->moveTab(page, TraceItemView::Right, true);
0157     else if (a == areaToBottomAction)
0158         _tabView->moveTab(page, TraceItemView::Bottom, true);
0159     else if (a == areaToLeftAction)
0160         _tabView->moveTab(page, TraceItemView::Left, true);
0161 
0162     else if (a == showOnTopAction)
0163         _tabView->moveTab(nullptr, TraceItemView::Top, true);
0164     else if (a == showOnRightAction)
0165         _tabView->moveTab(nullptr, TraceItemView::Right, true);
0166     else if (a == showOnBottomAction)
0167         _tabView->moveTab(nullptr, TraceItemView::Bottom, true);
0168     else if (a == showOnLeftAction)
0169         _tabView->moveTab(nullptr, TraceItemView::Left, true);
0170 }
0171 
0172 
0173 //
0174 // Splitter
0175 //
0176 
0177 Splitter::Splitter(Qt::Orientation o, QWidget* parent)
0178     : QSplitter(o, parent)
0179 {}
0180 
0181 void Splitter::moveEvent(QMoveEvent* e)
0182 {
0183     QSplitter::moveEvent(e);
0184 
0185     if (0) qDebug("Splitter %s: Move", qPrintable(objectName()));
0186     checkVisiblity();
0187 }
0188 
0189 void Splitter::checkVisiblity()
0190 {
0191 #if 0
0192     const QObjectList l = children();
0193     QObjectList::Iterator it( l );
0194     QObject *obj;
0195     while ( (obj = it.current()) != 0 ) {
0196         ++it;
0197         if (obj->isA("Splitter")) ((Splitter*)obj)->checkVisiblity();
0198         else if (obj->isA("TabWidget")) ((TabWidget*)obj)->checkVisibility();
0199     }
0200 #endif
0201 }
0202 
0203 
0204 
0205 
0206 //
0207 // TabWidget
0208 //
0209 
0210 TabWidget::TabWidget(TabView* v, QWidget* parent)
0211     : QTabWidget(parent)
0212 {
0213     _hasVisibleRect = false;
0214     setTabBar(new TabBar(v, this));
0215 }
0216 
0217 void TabWidget::checkVisibility()
0218 {
0219     bool hasVisibleRect = (visibleRegion().boundingRect().width()>1) &&
0220                           (visibleRegion().boundingRect().height()>1);
0221 
0222     if (0) qDebug("TabWidget %s: VR (%dx%d) HasVisibleRect: %s => %s",
0223                   qPrintable(objectName()),
0224                   visibleRegion().boundingRect().width(),
0225                   visibleRegion().boundingRect().height(),
0226                   _hasVisibleRect ? "Yes":"No",
0227                   hasVisibleRect ? "Yes":"No");
0228 
0229     if (hasVisibleRect != _hasVisibleRect) {
0230         _hasVisibleRect = hasVisibleRect;
0231         emit visibleRectChanged(this);
0232     }
0233 }
0234 
0235 void TabWidget::resizeEvent(QResizeEvent *e)
0236 {
0237     QTabWidget::resizeEvent(e);
0238     if (0) qDebug("TabWidget %s:\n  Resize from (%d/%d) to (%d/%d)",
0239                   objectName().toLatin1().constData(),
0240                   e->oldSize().width(), e->oldSize().height(),
0241                   e->size().width(), e->size().height());
0242     checkVisibility();
0243 }
0244 
0245 void TabWidget::showEvent(QShowEvent* e)
0246 {
0247     QTabWidget::showEvent(e);
0248 
0249     if (0) qDebug("TabWidget %s: Show", objectName().toLatin1().constData());
0250     checkVisibility();
0251 }
0252 
0253 void TabWidget::hideEvent(QHideEvent* e)
0254 {
0255     QTabWidget::hideEvent(e);
0256 
0257     if (0) qDebug("TabWidget %s: Hide", objectName().toLatin1().constData());
0258     checkVisibility();
0259 }
0260 
0261 void TabWidget::moveEvent(QMoveEvent* e)
0262 {
0263     QTabWidget::moveEvent(e);
0264 
0265     if (0) qDebug("TabWidget %s: Move", objectName().toLatin1().constData());
0266     checkVisibility();
0267 }
0268 
0269 
0270 
0271 //
0272 // TabView
0273 //
0274 
0275 /*
0276  * Areas for child views
0277  *
0278  * leftSplitter
0279  * |
0280  * |    -----                 -----
0281  * |  _/     \_______________/     \____
0282  * |  | Top                 | Right    |
0283  * |  |                     |          |
0284  * -> |---------------------|          |
0285  *    | BottomLeft | Bottom |          |
0286  *    |            |        |          |
0287  *    -\_____/------\____/--------------
0288  *
0289  *                 ^        ^
0290  *      bottomSplitter    mainSplitter
0291  */
0292 
0293 TabView::TabView(TraceItemView* parentView, QWidget* parent)
0294     : QWidget(parent), TraceItemView(parentView)
0295 {
0296     setFocusPolicy(Qt::StrongFocus);
0297 
0298     _isCollapsed = true;
0299 
0300     QVBoxLayout* vbox = new QVBoxLayout( this );
0301     vbox->setSpacing( 6 );
0302     vbox->setContentsMargins( 6 ,  6 ,  6 ,  6 );
0303 
0304     _nameLabel = new QLabel(this); //KSqueezedTextLabel( this);
0305     _nameLabel->setSizePolicy(QSizePolicy( QSizePolicy::Ignored,
0306                                            QSizePolicy::Fixed ));
0307     _nameLabel->setObjectName( QStringLiteral("nameLabel") );
0308     _nameLabel->setText(tr("(No profile data file loaded)"));
0309     vbox->addWidget( _nameLabel );
0310     updateNameLabel(tr("(No profile data file loaded)"));
0311 
0312     _mainSplitter   = new QSplitter(Qt::Horizontal, this);
0313     _leftSplitter   = new Splitter(Qt::Vertical, _mainSplitter);
0314     _leftSplitter->setObjectName(QStringLiteral("Left"));
0315     vbox->addWidget( _mainSplitter );
0316 
0317     _rightTW = new TabWidget(this, _mainSplitter);
0318     _rightTW->setObjectName(QStringLiteral("Right"));
0319     connect(_rightTW, &QTabWidget::currentChanged,
0320             this, &TabView::tabChanged);
0321     connect(_rightTW, &TabWidget::visibleRectChanged,
0322             this, &TabView::visibleRectChangedSlot);
0323 
0324     _topTW = new TabWidget(this, _leftSplitter);
0325     _topTW->setObjectName(QStringLiteral("Top"));
0326     connect(_topTW, &QTabWidget::currentChanged,
0327             this, &TabView::tabChanged);
0328     connect(_topTW, &TabWidget::visibleRectChanged,
0329             this, &TabView::visibleRectChangedSlot);
0330 
0331     _bottomSplitter = new Splitter(Qt::Horizontal, _leftSplitter);
0332     _bottomSplitter->setObjectName(QStringLiteral("Bottom"));
0333 
0334     _leftTW = new TabWidget(this, _bottomSplitter);
0335     _leftTW->setObjectName(QStringLiteral("Left"));
0336     _leftTW->setTabPosition(QTabWidget::South);
0337     connect(_leftTW, &QTabWidget::currentChanged,
0338             this, &TabView::tabChanged);
0339     connect(_leftTW, &TabWidget::visibleRectChanged,
0340             this, &TabView::visibleRectChangedSlot);
0341 
0342     _bottomTW = new TabWidget(this, _bottomSplitter);
0343     _bottomTW->setObjectName(QStringLiteral("Bottom"));
0344     _bottomTW->setTabPosition(QTabWidget::South);
0345     connect(_bottomTW, &QTabWidget::currentChanged,
0346             this, &TabView::tabChanged);
0347     connect(_bottomTW, &TabWidget::visibleRectChanged,
0348             this, &TabView::visibleRectChangedSlot);
0349 
0350     CallView* callerView = new CallView(true, this);
0351     CallView* calleeView = new CallView(false, this);
0352     CoverageView * allCallerView = new CoverageView(true, this);
0353     CoverageView * allCalleeView = new CoverageView(false, this);
0354     SourceView* sourceView = new SourceView(this);
0355     InstrView* instrView = new InstrView(this);
0356     PartView* partView = new PartView(this);
0357 
0358     // Options of visualization views are stored by their view name
0359     callerView->setObjectName(QStringLiteral("CallerView"));
0360     calleeView->setObjectName(QStringLiteral("CalleeView"));
0361     allCallerView->setObjectName(QStringLiteral("AllCallerView"));
0362     allCalleeView->setObjectName(QStringLiteral("AllCalleeView"));
0363     sourceView->setObjectName(QStringLiteral("SourceView"));
0364     instrView->setObjectName(QStringLiteral("InstrView"));
0365     partView->setObjectName(QStringLiteral("PartView"));
0366 
0367     // default positions...
0368     // Keep following order in sync with DEFAULT_xxxTABS defines!
0369 
0370     addTop( addTab( tr("Types"),
0371                     new EventTypeView(this, nullptr,
0372                                       "EventTypeView")));
0373     addTop( addTab( tr("Callers"), callerView) );
0374     addTop( addTab( tr("All Callers"), allCallerView) );
0375     addTop( addTab( tr("Callee Map"),
0376                     new CallMapView(false, this, nullptr,
0377                                     "CalleeMapView")));
0378     addTop( addTab( tr("Source Code"), sourceView) );
0379 
0380     addBottom( addTab( tr("Parts"), partView ) );
0381     addBottom( addTab( tr("Callees"), calleeView) );
0382     addBottom( addTab( tr("Call Graph"),
0383                        new CallGraphView(this, nullptr,
0384                                          "CallGraphView")));
0385     addBottom( addTab( tr("All Callees"), allCalleeView) );
0386     addBottom( addTab( tr("Caller Map"),
0387                        new CallMapView(true, this, nullptr,
0388                                        "CallerMapView")));
0389     addBottom( addTab( tr("Machine Code"), instrView) );
0390 
0391     // after all child widgets are created...
0392     _lastFocus = nullptr;
0393     _active = false;
0394     installFocusFilters();
0395 
0396     updateVisibility();
0397 
0398     this->setWhatsThis( whatsThis() );
0399 }
0400 
0401 void TabView::updateNameLabel(const QString& n)
0402 {
0403     QFontMetrics fm(_nameLabel->fontMetrics());
0404 
0405     if (!n.isNull()) {
0406         _nameLabelText = n;
0407         _textWidth = fm.boundingRect(_nameLabelText).width();
0408     }
0409 
0410     int labelWidth = _nameLabel->size().width();
0411     if (_textWidth > labelWidth) {
0412         _nameLabel->setText(fm.elidedText(_nameLabelText,
0413                                           Qt::ElideMiddle, labelWidth));
0414         _nameLabel->setToolTip(_nameLabelText);
0415     }
0416     else {
0417         _nameLabel->setText(_nameLabelText);
0418         _nameLabel->setToolTip(QString());
0419     }
0420     if (!_nameLabelTooltip.isEmpty())
0421         _nameLabel->setToolTip(_nameLabelTooltip);
0422 }
0423 
0424 void TabView::setData(TraceData* d)
0425 {
0426     TraceItemView::setData(d);
0427 
0428     foreach(TraceItemView* v, _tabs)
0429         v->setData(d);
0430 }
0431 
0432 TraceItemView* TabView::addTab(const QString& label, TraceItemView* view)
0433 {
0434     view->setTitle(label);
0435     _tabs.append(view);
0436     return view;
0437 }
0438 
0439 void TabView::addTop(TraceItemView* view)
0440 {
0441     view->setPosition(TraceItemView::Top);
0442     _topTW->addTab(view->widget(), view->title());
0443 }
0444 
0445 void TabView::addBottom(TraceItemView* view)
0446 {
0447     view->setPosition(TraceItemView::Bottom);
0448     _bottomTW->addTab(view->widget(), view->title());
0449 }
0450 
0451 TraceItemView::Position TabView::tabPosition(QWidget* w)
0452 {
0453     foreach(TraceItemView* v, _tabs)
0454         if (v->widget() == w) return v->position();
0455 
0456     return Hidden;
0457 }
0458 
0459 int TabView::visibleTabs()
0460 {
0461     int c = 0;
0462     foreach(TraceItemView* v, _tabs) {
0463         if (v->position() == Hidden) continue;
0464         c++;
0465     }
0466     return c;
0467 }
0468 
0469 // calculate count of tabs in areas
0470 void TabView::tabCounts(int& top, int& bottom,
0471                         int& left, int& right)
0472 {
0473     top = bottom = left = right = 0;
0474 
0475     foreach(TraceItemView* v, _tabs) {
0476         switch(v->position()) {
0477         case TraceItemView::Top:
0478             top++;
0479             break;
0480         case TraceItemView::Bottom:
0481             bottom++;
0482             break;
0483         case TraceItemView::Left:
0484             left++;
0485             break;
0486         case TraceItemView::Right:
0487             right++;
0488             break;
0489         default:
0490             break;
0491         }
0492     }
0493 
0494     if (0) qDebug("TabView::tabCounts top %d, bottom %d, left %d, right %d",
0495                   top, bottom, left, right);
0496 }
0497 
0498 int TabView::visibleAreas()
0499 {
0500     int count, top, bottom, left, right;
0501 
0502     tabCounts(top, bottom, left, right);
0503     count = 0;
0504     if (top>0) count++;
0505     if (bottom>0) count++;
0506     if (left>0) count++;
0507     if (right>0) count++;
0508 
0509     return count;
0510 }
0511 
0512 // This hides/shows splitters and tabwidgets according to tab children
0513 void TabView::updateVisibility()
0514 {
0515     int top, bottom, left, right;
0516 
0517     tabCounts(top, bottom, left, right);
0518 
0519     QList<int> s;
0520     s.append(100);
0521 
0522     // children of mainSplitter
0523     if (_rightTW->isHidden() != (right == 0)) {
0524         if (right == 0) {
0525             _rightTW->hide();
0526         }
0527         else
0528             _rightTW->show();
0529     }
0530     if (_leftSplitter->isHidden() != (top+bottom+left == 0)) {
0531         if (top+bottom+left == 0) {
0532             _leftSplitter->hide();
0533         }
0534         else
0535             _leftSplitter->show();
0536     }
0537 
0538     // children of leftSplitter
0539     if (_topTW->isHidden() != (top == 0)) {
0540         if (top == 0) {
0541             _topTW->hide();
0542         }
0543         else
0544             _topTW->show();
0545     }
0546 
0547     if (_bottomSplitter->isHidden() != (bottom+left == 0)) {
0548         if (bottom+left == 0) {
0549             _bottomSplitter->hide();
0550         }
0551         else
0552             _bottomSplitter->show();
0553     }
0554 
0555     // children of bottomSplitter
0556     if (_bottomTW->isHidden() != (bottom == 0)) {
0557         if (bottom == 0) {
0558             _bottomTW->hide();
0559         }
0560         else
0561             _bottomTW->show();
0562     }
0563     if (_leftTW->isHidden() != (left == 0)) {
0564         if (left == 0) {
0565             _leftTW->hide();
0566         }
0567         else
0568             _leftTW->show();
0569     }
0570 }
0571 
0572 TabWidget* TabView::tabWidget(Position p)
0573 {
0574     switch(p) {
0575     case TraceItemView::Top:
0576         return _topTW;
0577     case TraceItemView::Bottom:
0578         return _bottomTW;
0579     case TraceItemView::Left:
0580         return _leftTW;
0581     case TraceItemView::Right:
0582         return _rightTW;
0583     default:
0584         break;
0585     }
0586     return nullptr;
0587 }
0588 
0589 void TabView::moveTab(QWidget* w, Position p, bool wholeArea)
0590 {
0591     Position origPos = Hidden;
0592     if (w) {
0593         TraceItemView* found = nullptr;
0594         foreach(TraceItemView* v, _tabs)
0595             if (v->widget() == w) { found = v; break; }
0596 
0597         if (!found) return;
0598         origPos = found->position();
0599     }
0600     if (origPos == p) return;
0601 
0602     TabWidget *from, *to;
0603     from = tabWidget(origPos);
0604     to = tabWidget(p);
0605 
0606     QList<TraceItemView*> tabs;
0607     foreach(TraceItemView* v, _tabs)
0608         if ((v->position() == origPos) &&
0609             (wholeArea || (v->widget() == w))) tabs.append(v);
0610 
0611     bool isEnabled;
0612     foreach(TraceItemView* v, tabs) {
0613         v->setPosition(p);
0614         w = v->widget();
0615 
0616         if (from) {
0617             isEnabled = from->isTabEnabled(from->indexOf(w));
0618             from->removeTab(from->indexOf(w));
0619         }
0620         else isEnabled = (v->canShow(_activeItem)!=nullptr);
0621 
0622         if (to) {
0623             int idx = -1, i;
0624             foreach(TraceItemView* vv, _tabs) {
0625                 if (v == vv) continue;
0626                 i = to->indexOf(vv->widget());
0627                 if (i>=0) idx = i;
0628             }
0629             to->insertTab(idx+1, w, v->title());
0630             to->setTabEnabled(to->indexOf(w), isEnabled);
0631             if (isEnabled) {
0632                 to->setCurrentIndex(to->indexOf(w));
0633                 v->updateView();
0634             }
0635         }
0636     }
0637     updateVisibility();
0638 }
0639 
0640 
0641 QString TabView::whatsThis() const
0642 {
0643     return tr( "<b>Information Tabs</b>"
0644                "<p>This widget shows information for the "
0645                "currently selected function in different tabs: "
0646                "<ul>"
0647                "<li>The Costs tab shows a list of available event types "
0648                "and the inclusive and self-costs related to these types.</li>"
0649                "<li>The Parts tab shows a list of trace parts "
0650                "if the trace consists of more than one part (otherwise, "
0651                "this tab is hidden). "
0652                "The cost of the selected function spent in the different "
0653                "parts together with the calls happening is shown.</li>"
0654                "<li>The Call Lists tab shows direct callers and "
0655                "callees of the function in more detail.</li>"
0656                "<li>The Coverage tab shows the same as the Call "
0657                "Lists tab, but also shows indirect callers and callees, "
0658                "not just direct ones.</li>"
0659                "<li>The Call Graph tab shows a graphical "
0660                "visualization of the calls made by this function.</li>"
0661                "<li>The Source Code tab presents annotated source code "
0662                "if debugging information and the source file "
0663                "are available.</li>"
0664                "<li>The Machine Code tab presents annotated assembly "
0665                "instructions if profile information at instruction level "
0666                "is available.</li></ul>"
0667                "For more information, see the <em>What's This?</em> "
0668                "help of the corresponding tab widget.</p>");
0669 }
0670 
0671 void TabView::installFocusFilters()
0672 {
0673     QList<QWidget*> wList = findChildren<QWidget*>();
0674     foreach(QWidget* w, wList) {
0675         if (w->focusPolicy() != Qt::NoFocus)
0676             w->installEventFilter(this);
0677     }
0678 }
0679 
0680 
0681 bool TabView::eventFilter(QObject* o, QEvent* e)
0682 {
0683     if (e->type() == QEvent::FocusIn) {
0684         _lastFocus = o->isWidgetType() ? (QWidget*) o : nullptr;
0685         setActive(_lastFocus != nullptr);
0686     }
0687     return QWidget::eventFilter(o,e);
0688 }
0689 
0690 void TabView::mousePressEvent(QMouseEvent*)
0691 {
0692     if (_lastFocus)
0693         _lastFocus->setFocus();
0694     setActive(true);
0695 }
0696 
0697 void TabView::setActive(bool a)
0698 {
0699     if (a == _active) return;
0700     _active = a;
0701 
0702     QFont nameLabel_font(  _nameLabel->font() );
0703     nameLabel_font.setBold(a);
0704     _nameLabel->setFont( nameLabel_font );
0705     // force recalculation of label width by passing current label text
0706     updateNameLabel(_nameLabelText);
0707 
0708     if (0) qDebug("%s::setActive(%s)", objectName().toLatin1().constData(),
0709                   a ? "true":"false");
0710 
0711     if (a) emit tabActivated(this);
0712 }
0713 
0714 void TabView::doUpdate(int changeType, bool force)
0715 {
0716     if (changeType & (activeItemChanged |
0717                       configChanged |
0718                       dataChanged))
0719     {
0720         if (_data && _activeItem) {
0721             _nameLabelTooltip = _activeItem->formattedName();
0722             updateNameLabel(_activeItem->prettyName());
0723         }
0724         else {
0725             _nameLabelTooltip = QString();
0726             updateNameLabel( !_data ?
0727                                  tr("(No profile data file loaded)") :
0728                                  tr("(No function selected)"));
0729         }
0730     }
0731 
0732     bool canShow;
0733     foreach(TraceItemView *v, _tabs) {
0734 
0735         TabWidget *tw = nullptr;
0736         switch(v->position()) {
0737         case TraceItemView::Top:    tw = _topTW; break;
0738         case TraceItemView::Bottom: tw = _bottomTW; break;
0739         case TraceItemView::Left:   tw = _leftTW; break;
0740         case TraceItemView::Right:  tw = _rightTW; break;
0741         default: break;
0742         }
0743 
0744         // update even if hidden
0745         if (tw) {
0746             if (!tw->hasVisibleRect()) continue;
0747         }
0748         canShow = v->set(changeType, _data, _eventType, _eventType2,
0749                          _groupType, _partList,
0750                          _activeItem, _selectedItem);
0751         v->notifyChange(changeType);
0752 
0753         if (!tw) continue;
0754         int idx = tw->indexOf(v->widget());
0755         if (tw->isTabEnabled(idx) != canShow)
0756             tw->setTabEnabled(idx, canShow);
0757 
0758         if (v->widget() == tw->currentWidget())
0759             v->updateView(force);
0760     }
0761 }
0762 
0763 
0764 void TabView::tabChanged(int i)
0765 {
0766     TabWidget* tw = qobject_cast<TabWidget*>(sender());
0767     if (!tw) return;
0768     QWidget* w = tw->widget(i);
0769 
0770     foreach(TraceItemView *v, _tabs)
0771         if (v->widget() == w) v->updateView();
0772 }
0773 
0774 void TabView::visibleRectChangedSlot(TabWidget* tw)
0775 {
0776     if (0) qDebug("%s: %svisible !",
0777                   tw->objectName().toLatin1().constData(),
0778                   tw->hasVisibleRect() ? "":"un");
0779 
0780     if (tw->hasVisibleRect()) doUpdate(0, false);
0781 }
0782 
0783 void TabView::resizeEvent(QResizeEvent* e)
0784 {
0785     QWidget::resizeEvent(e);
0786 
0787     updateNameLabel();
0788 
0789     bool collapsed = (e->size().width()<=1) || (e->size().height()<=1);
0790     if (_isCollapsed != collapsed) {
0791         _isCollapsed = collapsed;
0792         updateView();
0793     }
0794 
0795     if (0) qDebug("TabView::Resize from (%d/%d) to (%d/%d)",
0796                   e->oldSize().width(), e->oldSize().height(),
0797                   e->size().width(), e->size().height());
0798 }
0799 
0800 void TabView::selected(TraceItemView*, CostItem* s)
0801 {
0802     // we set selected item for our own children
0803     select(s);
0804 
0805     // still forward to parent
0806     if (_parentView) _parentView->selected(this, s);
0807 }
0808 
0809 void TabView::restoreLayout(const QString& prefix, const QString& postfix)
0810 {
0811     ConfigGroup* g = ConfigStorage::group(prefix, postfix);
0812 
0813     int rightSize = g->value(QStringLiteral("RightSize"), DEFAULT_RIGHTSIZE).toInt();
0814     int topSize = g->value(QStringLiteral("TopSize"), DEFAULT_TOPSIZE).toInt();
0815     int leftSize = g->value(QStringLiteral("LeftSize"), DEFAULT_LEFTSIZE).toInt();
0816 
0817     QList<int> mainSizes, leftSizes, bottomSizes;
0818 
0819     int mainWidth = _mainSplitter->width();
0820     mainSizes << (100 - rightSize)*mainWidth/100 << rightSize*mainWidth/100;
0821     _mainSplitter->setSizes(mainSizes);
0822 
0823     int leftHeight = _leftSplitter->height();
0824     leftSizes << topSize*leftHeight/100 << (100 - topSize)*leftHeight/100;
0825     _leftSplitter->setSizes(leftSizes);
0826 
0827     int bottomWidth = _bottomSplitter->width();
0828     bottomSizes << leftSize*bottomWidth/100 << (100 - leftSize)*bottomWidth/100;
0829     _bottomSplitter->setSizes(bottomSizes);
0830 
0831     QString activeT = g->value(QStringLiteral("ActiveTop"), QStringLiteral(DEFAULT_ACTIVETOP)).toString();
0832     QString activeB = g->value(QStringLiteral("ActiveBottom"), QStringLiteral(DEFAULT_ACTIVEBOTTOM)).toString();
0833     QString activeL = g->value(QStringLiteral("ActiveLeft"), QString()).toString();
0834     QString activeR = g->value(QStringLiteral("ActiveRight"), QString()).toString();
0835 
0836     QStringList topTabsDefault, bottomTabsDefault;
0837     topTabsDefault << DEFAULT_TOPTABS;
0838     bottomTabsDefault << DEFAULT_BOTTOMTABS;
0839 
0840     QStringList topTabs    = g->value(QStringLiteral("TopTabs"),topTabsDefault).toStringList();
0841     QStringList bottomTabs = g->value(QStringLiteral("BottomTabs"),bottomTabsDefault).toStringList();
0842     QStringList leftTabs   = g->value(QStringLiteral("LeftTabs"),QStringList()).toStringList();
0843     QStringList rightTabs  = g->value(QStringLiteral("RightTabs"),QStringList()).toStringList();
0844 
0845     delete g;
0846 
0847     if (topTabs.isEmpty() && bottomTabs.isEmpty() &&
0848         rightTabs.isEmpty() && leftTabs.isEmpty()) {
0849         // no tabs visible ?! Reset to default
0850         topTabs = topTabsDefault;
0851         bottomTabs = bottomTabsDefault;
0852     }
0853 
0854     TraceItemView *activeTop = nullptr, *activeBottom = nullptr;
0855     TraceItemView *activeLeft = nullptr, *activeRight = nullptr;
0856 
0857     moveTab(nullptr, TraceItemView::Top, true);
0858     foreach(TraceItemView *v, _tabs) {
0859         QString n = v->widget()->objectName();
0860         if (topTabs.contains(n)) {
0861             moveTab(v->widget(), TraceItemView::Top);
0862             if (n == activeT) activeTop = v;
0863         }
0864         else if (bottomTabs.contains(n)) {
0865             moveTab(v->widget(), TraceItemView::Bottom);
0866             if (n == activeB) activeBottom = v;
0867         }
0868         else if (leftTabs.contains(n)) {
0869             moveTab(v->widget(), TraceItemView::Left);
0870             if (n == activeL) activeLeft = v;
0871         }
0872         else if (rightTabs.contains(n)) {
0873             moveTab(v->widget(), TraceItemView::Right);
0874             if (n == activeR) activeRight = v;
0875         }
0876         else moveTab(v->widget(), Hidden);
0877     }
0878     if (activeTop)
0879         _topTW->setCurrentIndex(_topTW->indexOf(activeTop->widget()));
0880     if (activeBottom)
0881         _bottomTW->setCurrentIndex(_bottomTW->indexOf(activeBottom->widget()));
0882     if (activeLeft)
0883         _leftTW->setCurrentIndex(_leftTW->indexOf(activeLeft->widget()));
0884     if (activeRight)
0885         _rightTW->setCurrentIndex(_rightTW->indexOf(activeRight->widget()));
0886 
0887     if (!_data) return;
0888 
0889     updateView();
0890 }
0891 
0892 void TabView::saveLayout(const QString& prefix, const QString& postfix)
0893 {
0894     ConfigGroup* g = ConfigStorage::group(prefix + postfix);
0895 
0896     // convert splitter sizes into percentage numbers
0897     QList<int> s;
0898     s = _mainSplitter->sizes();
0899     int rightSize = (s[0]+s[1]==0) ? 0 : (100 * s[1]/(s[0]+s[1]));
0900     s = _leftSplitter->sizes();
0901     int topSize = (s[0]+s[1]==0) ? 0 : (100 * s[0]/(s[0]+s[1]));
0902     s = _bottomSplitter->sizes();
0903     int leftSize = (s[0]+s[1]==0) ? 0 : (100 * s[0]/(s[0]+s[1]));
0904 
0905     g->setValue(QStringLiteral("RightSize"), rightSize, DEFAULT_RIGHTSIZE);
0906     g->setValue(QStringLiteral("TopSize"), topSize, DEFAULT_TOPSIZE);
0907     g->setValue(QStringLiteral("LeftSize"), leftSize, DEFAULT_LEFTSIZE);
0908 
0909     QString a;
0910     QWidget* w;
0911     w = _topTW->currentWidget();
0912     if ((_topTW->count()>0) &&
0913         (_topTW->isTabEnabled(_topTW->indexOf(w))))
0914         a = w->objectName();
0915     g->setValue(QStringLiteral("ActiveTop"), a, QStringLiteral(DEFAULT_ACTIVETOP));
0916 
0917     a = QString();
0918     w = _bottomTW->currentWidget();
0919     if ((_bottomTW->count()>0) &&
0920         (_bottomTW->isTabEnabled(_bottomTW->indexOf(w))))
0921         a = w->objectName();
0922     g->setValue(QStringLiteral("ActiveBottom"), a, QStringLiteral(DEFAULT_ACTIVEBOTTOM));
0923 
0924     a = QString();
0925     w = _leftTW->currentWidget();
0926     if ((_leftTW->count()>0) &&
0927         (_leftTW->isTabEnabled(_leftTW->indexOf(w))))
0928         a = w->objectName();
0929     g->setValue(QStringLiteral("ActiveLeft"), a, QString());
0930 
0931     a= QString();
0932     w = _rightTW->currentWidget();
0933     if ((_rightTW->count()>0) &&
0934         (_rightTW->isTabEnabled(_rightTW->indexOf(w))))
0935         a = w->objectName();
0936     g->setValue(QStringLiteral("ActiveRight"), a, QString());
0937 
0938     QStringList topList, bottomList, leftList, rightList;
0939     foreach(TraceItemView *v, _tabs) {
0940         switch(v->position()) {
0941         case TraceItemView::Top:
0942             topList << v->widget()->objectName();
0943             break;
0944 
0945         case TraceItemView::Bottom:
0946             bottomList << v->widget()->objectName();
0947             break;
0948 
0949         case TraceItemView::Left:
0950             leftList << v->widget()->objectName();
0951             break;
0952 
0953         case TraceItemView::Right:
0954             rightList << v->widget()->objectName();
0955             break;
0956 
0957         default: break;
0958         }
0959     }
0960 
0961     QStringList topTabsDefault, bottomTabsDefault;
0962     topTabsDefault << DEFAULT_TOPTABS;
0963     bottomTabsDefault << DEFAULT_BOTTOMTABS;
0964 
0965     g->setValue(QStringLiteral("TopTabs"), topList, topTabsDefault);
0966     g->setValue(QStringLiteral("BottomTabs"), bottomList, bottomTabsDefault);
0967     g->setValue(QStringLiteral("LeftTabs"), leftList, QStringList());
0968     g->setValue(QStringLiteral("RightTabs"), rightList, QStringList());
0969 
0970     delete g;
0971 }
0972 
0973 void TabView::restoreOptions(const QString& prefix, const QString& postfix)
0974 {
0975     foreach(TraceItemView *v, _tabs)
0976         v->restoreOptions(QStringLiteral("%1-%2").arg(prefix).arg(v->widget()->objectName()),
0977                           postfix);
0978 
0979     if (!_data) return;
0980 
0981     ConfigGroup* g = ConfigStorage::group(prefix, postfix);
0982 
0983     QString activeType = g->value(QStringLiteral("ActiveItemType"), QString()).toString();
0984     QString activeName = g->value(QStringLiteral("ActiveItemName"), QString()).toString();
0985     QString selectedType = g->value(QStringLiteral("SelectedItemType"), QString()).toString();
0986     QString selectedName = g->value(QStringLiteral("SelectedItemName"), QString()).toString();
0987 
0988     delete g;
0989 
0990     // restore active item
0991     ProfileContext::Type t = ProfileContext::type(activeType);
0992     if (t==ProfileContext::InvalidType) t = ProfileContext::Function;
0993     ProfileCostArray* activeItem = _data->search(t, activeName, _eventType);
0994     if (!activeItem) return;
0995     activated(activeItem);
0996 
0997     // restore selected item
0998     t = ProfileContext::type(selectedType);
0999     if (t==ProfileContext::InvalidType) t = ProfileContext::Function;
1000     ProfileCostArray* selectedItem;
1001     selectedItem = _data->search(t, selectedName, _eventType, activeItem);
1002     if (selectedItem)
1003         selected(this, selectedItem);
1004 }
1005 
1006 void TabView::saveOptions(const QString& prefix, const QString& postfix)
1007 {
1008     if (_activeItem) {
1009         ConfigGroup* g = ConfigStorage::group(prefix + postfix);
1010 
1011         g->setValue(QStringLiteral("ActiveItemType"),
1012                     ProfileContext::typeName(_activeItem->type()));
1013         g->setValue(QStringLiteral("ActiveItemName"), _activeItem->name());
1014 
1015         if (_selectedItem) {
1016             g->setValue(QStringLiteral("SelectedItemType"),
1017                         ProfileContext::typeName(_selectedItem->type()));
1018             g->setValue(QStringLiteral("SelectedItemName"), _selectedItem->name());
1019         }
1020         delete g;
1021     }
1022 
1023     foreach(TraceItemView *v, _tabs)
1024         v->saveOptions(QStringLiteral("%1-%2").arg(prefix)
1025                        .arg(v->widget()->objectName()), postfix);
1026 }
1027 
1028 #include "moc_tabview.cpp"