/* This file is part of KCachegrind. Copyright (C) 2003 Josef Weidendorfer KCachegrind is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Tab View, enclosing detailed views for one trace item in * two tab widgets, separated by a splitter */ #include #include #include #include #include #include #include #include #include "tabview.h" #include "costtypeview.h" #include "partview.h" #include "callview.h" #include "coverageview.h" #include "callmapview.h" #include "instrview.h" #include "sourceview.h" #include "callgraphview.h" // TabBar TabBar::TabBar(TabView* v, TQTabWidget* parent, const char *name) : TQTabBar(parent, name) { _tabWidget = parent; _tabView = v; } void TabBar::mousePressEvent(TQMouseEvent *e) { if (e->button() == Qt::RightButton) { TQTab *tab = selectTab( e->pos() ); TQWidget* page; page = tab ? _tabWidget->page( indexOf( tab->identifier() ) ) :0; TQPopupMenu popup, popup1, popup2, popup3; if (page) { TraceItemView::Position p = _tabView->tabPosition(page); if (p != TraceItemView::Top) { popup.insertItem(i18n("Move to Top"), 81); popup2.insertItem(i18n("Top"), 91); } if (p != TraceItemView::Right) { popup.insertItem(i18n("Move to Right"), 82); popup2.insertItem(i18n("Right"), 92); } if (p != TraceItemView::Bottom) { popup.insertItem(i18n("Move to Bottom"), 83); popup2.insertItem(i18n("Bottom"), 93); } if (p != TraceItemView::Left) { popup.insertItem(i18n("Move to Bottom Left"), 84); popup2.insertItem(i18n("Bottom Left"), 94); } popup.insertItem(i18n("Move Area To"), &popup2, 2); popup.insertSeparator(); popup.insertItem(i18n("Hide This Tab"), 80); popup.insertItem(i18n("Hide Area"), 90); if (_tabView->visibleTabs() <2) { popup.setItemEnabled(80, false); popup.setItemEnabled(90, false); } else if (_tabView->visibleAreas() <2) popup.setItemEnabled(90, false); } popup3.insertItem(i18n("Top"), 101); popup3.insertItem(i18n("Right"), 102); popup3.insertItem(i18n("Bottom"), 103); popup3.insertItem(i18n("Bottom Left"), 104); popup.insertItem(i18n("Show Hidden On"), &popup3, 3); int r = popup.exec( mapToGlobal( e->pos() ) ); TraceItemView::Position p = TraceItemView::Hidden; if ((r % 10) == 1) p = TraceItemView::Top; if ((r % 10) == 2) p = TraceItemView::Right; if ((r % 10) == 3) p = TraceItemView::Bottom; if ((r % 10) == 4) p = TraceItemView::Left; if (r>=80 && r<100) _tabView->moveTab(page, p, r>=90); if (r>=100 && r<110) _tabView->moveTab(0, p, true); } TQTabBar::mousePressEvent( e ); } // // Splitter // Splitter::Splitter(Qt::Orientation o, TQWidget* parent, const char* name) : TQSplitter(o, parent, name) {} void Splitter::moveEvent(TQMoveEvent* e) { TQSplitter::moveEvent(e); if (0) tqDebug("Splitter %s: Move", name()); checkVisiblity(); } void Splitter::checkVisiblity() { const TQObjectList l = childrenListObject(); TQObjectListIt it( l ); TQObject *obj; while ( (obj = it.current()) != 0 ) { ++it; if (obj->isA("Splitter")) ((Splitter*)obj)->checkVisiblity(); else if (obj->isA("TabWidget")) ((TabWidget*)obj)->checkVisibility(); } } // // TabWidget // TabWidget::TabWidget(TabView* v, TQWidget* parent, const char* name, WFlags f) : TQTabWidget(parent, name, f) { _hasVisibleRect = false; setTabBar(new TabBar(v, this)); } void TabWidget::checkVisibility() { bool hasVisibleRect = (visibleRect().width()>1) && (visibleRect().height()>1); if (0) tqDebug("TabWidget %s: VR (%dx%d) HasVisibleRect: %s => %s", name(), visibleRect().width(), visibleRect().height(), _hasVisibleRect ? "Yes":"No", hasVisibleRect ? "Yes":"No"); if (hasVisibleRect != _hasVisibleRect) { _hasVisibleRect = hasVisibleRect; emit visibleRectChanged(this); } } void TabWidget::resizeEvent(TQResizeEvent *e) { TQTabWidget::resizeEvent(e); if (0) tqDebug("TabWidget %s:\n Resize from (%d/%d) to (%d/%d)", name(), e->oldSize().width(), e->oldSize().height(), e->size().width(), e->size().height()); checkVisibility(); } void TabWidget::showEvent(TQShowEvent* e) { TQTabWidget::showEvent(e); if (0) tqDebug("TabWidget %s: Show", name()); checkVisibility(); } void TabWidget::hideEvent(TQHideEvent* e) { TQTabWidget::hideEvent(e); if (0) tqDebug("TabWidget %s: Hide", name()); checkVisibility(); } void TabWidget::moveEvent(TQMoveEvent* e) { TQTabWidget::moveEvent(e); if (0) tqDebug("TabWidget %s: Move", name()); checkVisibility(); } // // TabView // /* * Areas for child views * * leftSplitter * | * | ----- ----- * | _/ \_______________/ \____ * | | Top | TopRight | * | | | | * -> |---------------------| | * | BottomLeft | Bottom | | * | | | | * -\_____/------\____/-------------- * * ^ ^ * bottomSplitter mainSplitter */ TabView::TabView(TraceItemView* parentView, TQWidget* parent, const char* name) : TQWidget(parent, name), TraceItemView(parentView) { setFocusPolicy(TQ_StrongFocus); _isCollapsed = true; TQVBoxLayout* vbox = new TQVBoxLayout( this, 6, 6); _nameLabel = new KSqueezedTextLabel( this, "nameLabel" ); _nameLabel->setText(i18n("(No profile data file loaded)")); vbox->addWidget( _nameLabel ); _mainSplitter = new TQSplitter(Qt::Horizontal, this); _leftSplitter = new Splitter(Qt::Vertical, _mainSplitter, "Left"); vbox->addWidget( _mainSplitter ); _rightTW = new TabWidget(this, _mainSplitter, "Right"); connect(_rightTW, TQT_SIGNAL(currentChanged(TQWidget*)), this, TQT_SLOT(tabChanged(TQWidget*))); connect(_rightTW, TQT_SIGNAL(visibleRectChanged(TabWidget*)), this, TQT_SLOT(visibleRectChangedSlot(TabWidget*))); _topTW = new TabWidget(this, _leftSplitter, "Top"); connect(_topTW, TQT_SIGNAL(currentChanged(TQWidget*)), this, TQT_SLOT(tabChanged(TQWidget*))); connect(_topTW, TQT_SIGNAL(visibleRectChanged(TabWidget*)), this, TQT_SLOT(visibleRectChangedSlot(TabWidget*))); _bottomSplitter = new Splitter(Qt::Horizontal, _leftSplitter, "Bottom"); _leftTW = new TabWidget(this, _bottomSplitter, "Left"); _leftTW->setTabPosition(TQTabWidget::Bottom); connect(_leftTW, TQT_SIGNAL(currentChanged(TQWidget*)), this, TQT_SLOT(tabChanged(TQWidget*))); connect(_leftTW, TQT_SIGNAL(visibleRectChanged(TabWidget*)), this, TQT_SLOT(visibleRectChangedSlot(TabWidget*))); _bottomTW = new TabWidget(this, _bottomSplitter, "Bottom"); _bottomTW->setTabPosition(TQTabWidget::Bottom); connect(_bottomTW, TQT_SIGNAL(currentChanged(TQWidget*)), this, TQT_SLOT(tabChanged(TQWidget*))); connect(_bottomTW, TQT_SIGNAL(visibleRectChanged(TabWidget*)), this, TQT_SLOT(visibleRectChangedSlot(TabWidget*))); // default positions... addTop( addTab( i18n("Types"), new CostTypeView(this, _topTW, "CostTypeView"))); addTop( addTab( i18n("Callers"), new CallView(true, this, _topTW, "CallerView"))); addTop( addTab( i18n("All Callers"), new CoverageView(true, this, _topTW, "AllCallerView"))); addTop( addTab( i18n("Caller Map"), new CallMapView(true, this, _bottomTW, "CallerMapView"))); addTop( addTab( i18n("Source"), new SourceView(this, _topTW, "SourceView"))); addBottom( addTab( i18n("Parts"), new PartView(this, _bottomTW, "PartView"))); addBottom( addTab( i18n("Call Graph"), new CallGraphView(this, _bottomTW, "CallGraphView"))); addBottom( addTab( i18n("Callees"), new CallView(false, this, _bottomTW, "CalleeView"))); addBottom( addTab( i18n("All Callees"), new CoverageView(false, this, _bottomTW, "AllCalleeView"))); addBottom( addTab( i18n("Callee Map"), new CallMapView(false, this, _topTW, "CalleeMapView"))); addBottom( addTab( i18n("Assembler"), new InstrView(this, _bottomTW, "InstrView"))); // after all child widgets are created... _lastFocus = 0; _active = false; installFocusFilters(); updateVisibility(); TQWhatsThis::add( this, whatsThis() ); } void TabView::setData(TraceData* d) { TraceItemView::setData(d); TraceItemView* v; for (v=_tabs.first();v;v=_tabs.next()) v->setData(d); } TraceItemView* TabView::addTab(TQString label, TraceItemView* view) { view->setTitle(label); _tabs.append(view); return view; } void TabView::addTop(TraceItemView* view) { view->setPosition(TraceItemView::Top); _topTW->insertTab(view->widget(), view->title()); } void TabView::addBottom(TraceItemView* view) { view->setPosition(TraceItemView::Bottom); _bottomTW->insertTab(view->widget(), view->title()); } TraceItemView::Position TabView::tabPosition(TQWidget* w) { TraceItemView* v; for (v=_tabs.first();v;v=_tabs.next()) if (v->widget() == w) return v->position(); return Hidden; } int TabView::visibleTabs() { int c = 0; TraceItemView* v; for (v=_tabs.first();v;v=_tabs.next()) { if (v->position() == Hidden) continue; c++; } return c; } int TabView::visibleAreas() { int c = 0, t = 0, b = 0, r = 0, l = 0; TraceItemView* v; for (v=_tabs.first();v;v=_tabs.next()) { switch(v->position()) { case TraceItemView::Top: t++; break; case TraceItemView::Bottom: b++; break; case TraceItemView::Left: l++; break; case TraceItemView::Right: r++; break; default: break; } } if (t>0) c++; if (b>0) c++; if (l>0) c++; if (r>0) c++; return c; } // This hides/shows splitters and tabwidgets according to tab childs void TabView::updateVisibility() { // calculate count of tabs in areas int t = 0, b = 0, r = 0, l = 0; TraceItemView* v; for (v=_tabs.first();v;v=_tabs.next()) { switch(v->position()) { case TraceItemView::Top: t++; break; case TraceItemView::Bottom: b++; break; case TraceItemView::Left: l++; break; case TraceItemView::Right: r++; break; default: break; } } if (0) tqDebug("TabView::updateVisiblity t %d, b %d, l %d, r %d", t, b, l, r); TQValueList s; s.append(100); // children of mainSplitter if (_rightTW->isHidden() != (r == 0)) { if (r == 0) { _rightTW->hide(); if (!_topTW->hasVisibleRect() && !_bottomTW->hasVisibleRect() && !_leftTW->hasVisibleRect()) _mainSplitter->setSizes(s); } else _rightTW->show(); } if (_leftSplitter->isHidden() != (t+b+l == 0)) { if (t+b+l == 0) { _leftSplitter->hide(); if (!_rightTW->hasVisibleRect()) _mainSplitter->setSizes(s); } else _leftSplitter->show(); } // children of leftSplitter if (_topTW->isHidden() != (t == 0)) { if (t == 0) { _topTW->hide(); if (!_bottomTW->hasVisibleRect() && !_leftTW->hasVisibleRect()) _leftSplitter->setSizes(s); } else _topTW->show(); } if (_bottomSplitter->isHidden() != (b+l == 0)) { if (b+l == 0) { _bottomSplitter->hide(); if (!_topTW->hasVisibleRect()) _leftSplitter->setSizes(s); } else _bottomSplitter->show(); } // children of bottomSplitter if (_bottomTW->isHidden() != (b == 0)) { if (b == 0) { _bottomTW->hide(); if (!_leftTW->hasVisibleRect()) _bottomSplitter->setSizes(s); } else _bottomTW->show(); } if (_leftTW->isHidden() != (l == 0)) { if (l == 0) { _leftTW->hide(); if (!_bottomTW->hasVisibleRect()) _bottomSplitter->setSizes(s); } else _leftTW->show(); } } TabWidget* TabView::tabWidget(Position p) { switch(p) { case TraceItemView::Top: return _topTW; case TraceItemView::Bottom: return _bottomTW; case TraceItemView::Left: return _leftTW; case TraceItemView::Right: return _rightTW; default: break; } return 0; } void TabView::moveTab(TQWidget* w, Position p, bool wholeArea) { TraceItemView *v; Position origPos = Hidden; if (w) { for (v=_tabs.first();v;v=_tabs.next()) if (v->widget() == w) break; if (!v) return; origPos = v->position(); } if (origPos == p) return; TabWidget *from, *to; from = tabWidget(origPos); to = tabWidget(p); TQPtrList tabs; for (v=_tabs.first();v;v=_tabs.next()) if ((v->position() == origPos) && (wholeArea || (v->widget() == w))) tabs.append(v); bool isEnabled; for (v=tabs.first();v;v=tabs.next()) { v->setPosition(p); w = v->widget(); if (from) { isEnabled = from->isTabEnabled(w); from->removePage(w); } else isEnabled = (v->canShow(_activeItem)!=0); if (to) { TraceItemView *vv; int idx = -1, i; for(vv = _tabs.first(); vv && (vv!=v); vv = _tabs.next()) { i = to->indexOf(vv->widget()); if (i>=0) idx = i; } to->insertTab(w, v->title(), idx+1); to->setTabEnabled(w, isEnabled); if (isEnabled) { to->showPage(w); v->updateView(); } } } updateVisibility(); } TQString TabView::whatsThis() const { return i18n( "Information Tabs" "

This widget shows information for the " "current selected function in different tabs: " "

    " "
  • The Costs tab shows a list of available event types " "and the inclusive and self costs regarding to these types.
  • " "
  • The Parts tab shows a list of trace parts " "if the trace consists of more than one part (otherwise, " "this tab is hided). " "The cost of the selected function spent in the different " "parts together with the calls happening is shown.
  • " "
  • The Call Lists tab shows direct callers and " "callees of the function in more detail.
  • " "
  • The Coverage tab shows the same is the Call " "Lists tab, but not only direct callers and callees " "but also indirect ones.
  • " "
  • The Call Graph tab shows a graphical " "visualization of the calls done by this function.
  • " "
  • The Source tab presents annotated source code " "if debugging information and the source file " "is available.
  • " "
  • The Assembler tab presents annotated assembler code " "if trace information on instruction level " "is available.
" "For more information, see the What's This? " "help of the corresponding tab widget

"); } void TabView::installFocusFilters() { TQObjectList *l = queryList(TQWIDGET_OBJECT_NAME_STRING); TQObjectListIt it( *l ); TQObject *obj; while ( (obj = it.current()) != 0 ) { ++it; if ( ((TQWidget*)obj)->isFocusEnabled() ) obj->installEventFilter(this); } delete l; } bool TabView::eventFilter(TQObject* o, TQEvent* e) { if (e->type() == TQEvent::FocusIn) { _lastFocus = o->isWidgetType() ? (TQWidget*) o : 0; setActive(_lastFocus != 0); } return TQWidget::eventFilter(o,e); } void TabView::mousePressEvent(TQMouseEvent*) { if (_lastFocus) _lastFocus->setFocus(); setActive(true); } void TabView::setActive(bool a) { if (a == _active) return; _active = a; TQFont nameLabel_font( _nameLabel->font() ); nameLabel_font.setBold(a); _nameLabel->setFont( nameLabel_font ); if (0) tqDebug("%s::setActive(%s)", name(), a ? "true":"false"); if (a) emit activated(this); } void TabView::doUpdate(int changeType) { if (changeType & (activeItemChanged | configChanged | dataChanged)) _nameLabel->setText( !_data ? i18n("(No Data loaded)") : !_activeItem ? i18n("(No function selected)") : _activeItem->prettyName()); // we use our own list iterators because setTabEnabled can // invoke tabChanged, which mangles with the lists, too bool canShow; TraceItemView *v; TQPtrListIterator it( _tabs ); while ( (v=it.current()) != 0) { ++it; TabWidget *tw = 0; switch(v->position()) { case TraceItemView::Top: tw = _topTW; break; case TraceItemView::Bottom: tw = _bottomTW; break; case TraceItemView::Left: tw = _leftTW; break; case TraceItemView::Right: tw = _rightTW; break; default: break; } // update even if hidden if (tw) { if (!tw->hasVisibleRect()) continue; } canShow = v->set(changeType, _data, _costType, _costType2, _groupType, _partList, _activeItem, _selectedItem); v->notifyChange(changeType); if (!tw) continue; if (tw->isTabEnabled(v->widget()) != canShow) tw->setTabEnabled(v->widget(), canShow); if (v->widget() == tw->currentPage()) v->updateView(); } } void TabView::tabChanged(TQWidget* w) { TraceItemView *v; for (v=_tabs.first();v;v=_tabs.next()) if (v->widget() == w) v->updateView(); } void TabView::visibleRectChangedSlot(TabWidget* tw) { if (0) tqDebug("%s: %svisible !", tw->name(), tw->hasVisibleRect() ? "":"un"); if (tw->hasVisibleRect()) doUpdate(0); } void TabView::resizeEvent(TQResizeEvent* e) { TQWidget::resizeEvent(e); bool collapsed = (e->size().width()<=1) || (e->size().height()<=1); if (_isCollapsed != collapsed) { _isCollapsed = collapsed; updateView(); } if (0) tqDebug("TabView::Resize from (%d/%d) to (%d/%d)", e->oldSize().width(), e->oldSize().height(), e->size().width(), e->size().height()); } void TabView::selected(TraceItemView*, TraceItem* s) { // we set selected item for our own children select(s); updateView(); // still forward to parent if (_parentView) _parentView->selected(this, s); } void TabView::readViewConfig(TDEConfig* c, TQString prefix, TQString postfix, bool withOptions) { if (0) tqDebug("%s::readConfig(%s%s)", name(), prefix.ascii(), postfix.ascii()); TDEConfigGroup* g = configGroup(c, prefix, postfix); _mainSplitter->setSizes(g->readIntListEntry("MainSizes")); _leftSplitter->setSizes(g->readIntListEntry("LeftSizes")); _bottomSplitter->setSizes(g->readIntListEntry("BottomSizes")); TQString activeT = g->readEntry("ActiveTop", "CallerView"); TQString activeB = g->readEntry("ActiveBottom", "CalleeView"); TQString activeL = g->readEntry("ActiveLeft", ""); TQString activeR = g->readEntry("ActiveRight", ""); TQStringList topTabs = g->readListEntry("TopTabs"); TQStringList bottomTabs = g->readListEntry("BottomTabs"); TQStringList leftTabs = g->readListEntry("LeftTabs"); TQStringList rightTabs = g->readListEntry("RightTabs"); if (topTabs.isEmpty() && bottomTabs.isEmpty() && rightTabs.isEmpty() && leftTabs.isEmpty()) { // no tabs visible ?! Reset to default topTabs << "CostTypeView" << "CallerView" << "AllCallerView" << "CalleeMapView" << "SourceView"; bottomTabs << "PartView" << "CalleeView" << "CallGraphView" << "AllCalleeView" << "CallerMapView" << "InstrView"; } TraceItemView *activeTop = 0, *activeBottom = 0; TraceItemView *activeLeft = 0, *activeRight = 0; moveTab(0, TraceItemView::Top, true); TraceItemView *v; TQPtrListIterator it( _tabs ); while ( (v=it.current()) != 0) { ++it; TQString n = TQString(v->widget()->name()); if (topTabs.contains(n)) { moveTab(v->widget(), TraceItemView::Top); if (n == activeT) activeTop = v; } else if (bottomTabs.contains(n)) { moveTab(v->widget(), TraceItemView::Bottom); if (n == activeB) activeBottom = v; } else if (leftTabs.contains(n)) { moveTab(v->widget(), TraceItemView::Left); if (n == activeL) activeLeft = v; } else if (rightTabs.contains(n)) { moveTab(v->widget(), TraceItemView::Right); if (n == activeR) activeRight = v; } else moveTab(v->widget(), Hidden); if (withOptions) v->readViewConfig(c, TQString("%1-%2") .arg(prefix).arg(v->widget()->name()), postfix, true); } if (activeTop) _topTW->showPage(activeTop->widget()); if (activeBottom)_bottomTW->showPage(activeBottom->widget()); if (activeLeft) _leftTW->showPage(activeLeft->widget()); if (activeRight) _rightTW->showPage(activeRight->widget()); TQString activeType = g->readEntry("ActiveItemType", ""); TQString activeName = g->readEntry("ActiveItemName", ""); TQString selectedType = g->readEntry("SelectedItemType", ""); TQString selectedName = g->readEntry("SelectedItemName", ""); delete g; if (!_data) return; if (withOptions) { // restore active item TraceItem::CostType t = TraceItem::costType(activeType); if (t==TraceItem::NoCostType) t = TraceItem::Function; TraceCost* activeItem = _data->search(t, activeName, _costType); if (!activeItem) return; activate(activeItem); // restore selected item t = TraceItem::costType(selectedType); if (t==TraceItem::NoCostType) t = TraceItem::Function; TraceCost* selectedItem = _data->search(t, selectedName, _costType, activeItem); if (selectedItem) select(selectedItem); } updateView(); } void TabView::saveViewConfig(TDEConfig* c, TQString prefix, TQString postfix, bool withOptions) { TDEConfigGroup g(c, (prefix+postfix).ascii()); g.writeEntry("MainSizes", _mainSplitter->sizes()); g.writeEntry("LeftSizes", _leftSplitter->sizes()); g.writeEntry("BottomSizes", _bottomSplitter->sizes()); TQString a; if ((_topTW->count()>0) && (_topTW->isTabEnabled(_topTW->currentPage()))) a = TQString(_topTW->currentPage()->name()); g.writeEntry("ActiveTop", a); a.setLength(0); if ((_bottomTW->count()>0) && (_bottomTW->isTabEnabled(_bottomTW->currentPage()))) a = TQString(_bottomTW->currentPage()->name()); g.writeEntry("ActiveBottom", a); a.setLength(0); if ((_leftTW->count()>0) && (_leftTW->isTabEnabled(_leftTW->currentPage()))) a = TQString(_leftTW->currentPage()->name()); g.writeEntry("ActiveLeft", a); a.setLength(0); if ((_rightTW->count()>0) && (_rightTW->isTabEnabled(_rightTW->currentPage()))) a = TQString(_rightTW->currentPage()->name()); g.writeEntry("ActiveRight", a); if (withOptions) if (_activeItem) { g.writeEntry("ActiveItemType", TraceItem::typeName(_activeItem->type())); g.writeEntry("ActiveItemName", _activeItem->name()); if (_selectedItem) { g.writeEntry("SelectedItemType", TraceItem::typeName(_selectedItem->type())); g.writeEntry("SelectedItemName", _selectedItem->name()); } } TQStringList topList, bottomList, leftList, rightList; TraceItemView *v; for (v=_tabs.first();v;v=_tabs.next()) { switch(v->position()) { case TraceItemView::Top: topList << TQString(v->widget()->name()); break; case TraceItemView::Bottom: bottomList << TQString(v->widget()->name()); break; case TraceItemView::Left: leftList << TQString(v->widget()->name()); break; case TraceItemView::Right: rightList << TQString(v->widget()->name()); break; default: break; } } g.writeEntry("TopTabs", topList); g.writeEntry("BottomTabs", bottomList); g.writeEntry("LeftTabs", leftList); g.writeEntry("RightTabs", rightList); if (withOptions) for (v=_tabs.first();v;v=_tabs.next()) v->saveViewConfig(c, TQString("%1-%2").arg(prefix) .arg(v->widget()->name()), postfix, true); } #include "tabview.moc"