2015-07-26 14:23:17 +03:00
|
|
|
/*
|
|
|
|
Copyright 2008 David Nolden <david.nolden.kdevelop@art-master.de>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License version 2 as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
This library 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
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "useswidget.h"
|
|
|
|
|
|
|
|
#include <language/duchain/duchainlock.h>
|
|
|
|
#include <language/duchain/duchain.h>
|
|
|
|
#include <language/duchain/uses.h>
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
#include <QLabel>
|
|
|
|
#include <QProgressBar>
|
|
|
|
#include <klocalizedstring.h>
|
|
|
|
#include <QToolButton>
|
|
|
|
#include <language/duchain/declaration.h>
|
|
|
|
#include <language/duchain/use.h>
|
|
|
|
#include <kicon.h>
|
|
|
|
#include <interfaces/icore.h>
|
|
|
|
#include <interfaces/idocumentcontroller.h>
|
|
|
|
#include <interfaces/iprojectcontroller.h>
|
|
|
|
#include <qtextdocument.h>
|
2015-11-25 10:00:54 +00:00
|
|
|
#include <QtGui/qevent.h>
|
2015-07-26 14:23:17 +03:00
|
|
|
#include <language/duchain/duchainutils.h>
|
|
|
|
#include <language/codegen/coderepresentation.h>
|
|
|
|
#include <interfaces/iproject.h>
|
|
|
|
#include <interfaces/foregroundlock.h>
|
|
|
|
|
|
|
|
using namespace KDevelop;
|
|
|
|
|
|
|
|
|
|
|
|
const int tooltipContextSize = 2; //How many lines around the use are shown in the tooltip
|
|
|
|
|
|
|
|
///The returned text is fully escaped
|
|
|
|
///@param cutOff The total count of characters that should be cut of, all in all on both sides together.
|
|
|
|
///@param range The range that is highlighted, and that will be preserved during cutting, given that there is enough room beside it.
|
|
|
|
QString highlightAndEscapeUseText(QString line, uint cutOff, SimpleRange range) {
|
|
|
|
uint leftCutRoom = range.start.column;
|
|
|
|
uint rightCutRoom = line.length() - range.end.column;
|
|
|
|
|
|
|
|
if(range.start.column < 0 || range.end.column > line.length() || cutOff > leftCutRoom + rightCutRoom)
|
|
|
|
return QString(); //Not enough room for cutting off on sides
|
|
|
|
|
|
|
|
uint leftCut = 0;
|
|
|
|
uint rightCut = 0;
|
|
|
|
|
|
|
|
if(leftCutRoom < rightCutRoom) {
|
|
|
|
if(leftCutRoom * 2 >= cutOff) {
|
|
|
|
//Enough room on both sides. Just cut.
|
|
|
|
leftCut = cutOff / 2;
|
|
|
|
rightCut = cutOff - leftCut;
|
|
|
|
}else{
|
|
|
|
//Not enough room in left side, but enough room all together
|
|
|
|
leftCut = leftCutRoom;
|
|
|
|
rightCut = cutOff - leftCut;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
if(rightCutRoom * 2 >= cutOff) {
|
|
|
|
//Enough room on both sides. Just cut.
|
|
|
|
rightCut = cutOff / 2;
|
|
|
|
leftCut = cutOff - rightCut;
|
|
|
|
}else{
|
|
|
|
//Not enough room in right side, but enough room all together
|
|
|
|
rightCut = rightCutRoom;
|
|
|
|
leftCut = cutOff - rightCut;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Q_ASSERT(leftCut + rightCut <= cutOff);
|
|
|
|
|
|
|
|
line = line.left(line.length() - rightCut);
|
|
|
|
line = line.mid(leftCut);
|
|
|
|
range.start.column -= leftCut;
|
|
|
|
range.end.column -= leftCut;
|
|
|
|
|
|
|
|
Q_ASSERT(range.start.column >= 0 && range.end.column <= line.length());
|
|
|
|
|
|
|
|
//TODO: share code with context browser
|
|
|
|
// mixing (255, 255, 0, 100) with white yields this:
|
|
|
|
const QColor background(251, 250, 150);
|
|
|
|
const QColor foreground(0, 0, 0);
|
|
|
|
|
|
|
|
return "<span style=\"font-family:'monospace'\">" + Qt::escape(line.left(range.start.column))
|
|
|
|
+ "<span style=\"background-color:" + background.name() + ";color:" + foreground.name() + ";\">"
|
|
|
|
+ Qt::escape(line.mid(range.start.column, range.end.column - range.start.column))
|
|
|
|
+ "</span>" + Qt::escape(line.mid(range.end.column, line.length() - range.end.column)) + "</span>";
|
|
|
|
}
|
|
|
|
|
|
|
|
OneUseWidget::OneUseWidget(IndexedDeclaration declaration, IndexedString document, SimpleRange range, const CodeRepresentation& code) : m_range(new PersistentMovingRange(range, document)), m_declaration(declaration), m_document(document) {
|
|
|
|
|
|
|
|
//Make the sizing of this widget independent of the content, because we will adapt the content to the size
|
|
|
|
setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
|
|
|
|
|
|
|
|
m_sourceLine = code.line(m_range->range().start.line);
|
|
|
|
|
|
|
|
m_layout = new QHBoxLayout(this);
|
|
|
|
setLayout(m_layout);
|
|
|
|
|
|
|
|
m_label = new QLabel(this);
|
|
|
|
m_icon = new QLabel(this);
|
|
|
|
m_icon->setPixmap(KIcon("code-function").pixmap(16));
|
|
|
|
|
|
|
|
connect(m_label, SIGNAL(linkActivated(QString)), this, SLOT(jumpTo()));
|
|
|
|
|
|
|
|
DUChainReadLocker lock(DUChain::lock());
|
|
|
|
QString text = "<a href='open'>" + i18nc("refers to a line in source code", "Line <b>%1</b>:", range.start.line) + QString("</a>");
|
|
|
|
if(!m_sourceLine.isEmpty() && m_sourceLine.length() > m_range->range().end.column) {
|
|
|
|
|
|
|
|
text += " " + highlightAndEscapeUseText(m_sourceLine, 0, m_range->range());
|
|
|
|
|
|
|
|
//Useful tooltip:
|
|
|
|
int start = m_range->range().start.line - tooltipContextSize;
|
|
|
|
int end = m_range->range().end.line + tooltipContextSize + 1;
|
|
|
|
|
|
|
|
QString toolTipText;
|
|
|
|
for(int a = start; a < end; ++a) {
|
|
|
|
QString lineText = Qt::escape(code.line(a));
|
|
|
|
if (m_range->range().start.line <= a && m_range->range().end.line >= a) {
|
|
|
|
lineText = QString("<b>") + lineText + QString("</b>");
|
|
|
|
}
|
|
|
|
if(!lineText.trimmed().isEmpty()) {
|
|
|
|
toolTipText += lineText + "<br>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( toolTipText.endsWith("<br>") ) {
|
|
|
|
toolTipText.remove(toolTipText.length() - 4, 4);
|
|
|
|
}
|
|
|
|
setToolTip(QString("<html><body><pre>") + toolTipText + QString("</pre></body></html>"));
|
|
|
|
}
|
|
|
|
m_label->setText(text);
|
|
|
|
|
|
|
|
m_layout->addWidget(m_icon);
|
|
|
|
m_layout->addWidget(m_label);
|
|
|
|
m_layout->setAlignment(Qt::AlignLeft);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OneUseWidget::jumpTo() {
|
|
|
|
//This is used to execute the slot delayed in the event-loop, so crashes are avoided
|
|
|
|
ICore::self()->documentController()->openDocument(m_document.toUrl(), m_range->range().start.textCursor());
|
|
|
|
}
|
|
|
|
|
|
|
|
OneUseWidget::~OneUseWidget() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void OneUseWidget::resizeEvent ( QResizeEvent * event ) {
|
|
|
|
///Adapt the content
|
|
|
|
QSize size = event->size();
|
|
|
|
|
|
|
|
SimpleRange range = m_range->range();
|
|
|
|
|
|
|
|
int cutOff = 0;
|
|
|
|
int maxCutOff = m_sourceLine.length() - (range.end.column - range.start.column);
|
|
|
|
|
|
|
|
//Reset so we also get more context while up-sizing
|
|
|
|
m_label->setText(QString("<a href='open'>") + i18nc("Refers to a line in source code", "Line <b>%1</b>", range.start.line+1)
|
|
|
|
+ QString("</a> %2").arg(highlightAndEscapeUseText(m_sourceLine, cutOff, range)));
|
|
|
|
|
|
|
|
while(sizeHint().width() > size.width() && cutOff < maxCutOff) {
|
|
|
|
//We've got to save space
|
|
|
|
m_label->setText(QString("<a href='open'>") + i18nc("Refers to a line in source code", "Line <b>%1</b>", range.start.line+1)
|
|
|
|
+ QString("</a> %2").arg(highlightAndEscapeUseText(m_sourceLine, cutOff, range)));
|
|
|
|
cutOff += 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
event->accept();
|
|
|
|
|
|
|
|
QWidget::resizeEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NavigatableWidgetList::setShowHeader(bool show) {
|
|
|
|
if(show && !m_headerLayout->parent())
|
|
|
|
m_layout->insertLayout(0, m_headerLayout);
|
|
|
|
else
|
|
|
|
m_headerLayout->setParent(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
NavigatableWidgetList::~NavigatableWidgetList() {
|
|
|
|
delete m_headerLayout;
|
|
|
|
}
|
|
|
|
|
|
|
|
NavigatableWidgetList::NavigatableWidgetList(bool allowScrolling, uint maxHeight, bool vertical)
|
|
|
|
: m_allowScrolling(allowScrolling)
|
|
|
|
{
|
|
|
|
m_layout = new QVBoxLayout;
|
|
|
|
m_layout->setMargin(0);
|
|
|
|
m_layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
|
|
|
|
m_layout->setSpacing(0);
|
|
|
|
setBackgroundRole(QPalette::Base);
|
|
|
|
m_useArrows = false;
|
|
|
|
|
|
|
|
if(vertical)
|
|
|
|
m_itemLayout = new QVBoxLayout;
|
|
|
|
else
|
|
|
|
m_itemLayout = new QHBoxLayout;
|
|
|
|
|
|
|
|
m_itemLayout->setMargin(0);
|
|
|
|
m_itemLayout->setSpacing(0);
|
|
|
|
// m_layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
|
|
|
|
// setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum);
|
|
|
|
setWidgetResizable(true);
|
|
|
|
|
|
|
|
m_headerLayout = new QHBoxLayout;
|
|
|
|
m_headerLayout->setMargin(0);
|
|
|
|
m_headerLayout->setSpacing(0);
|
|
|
|
|
|
|
|
if(m_useArrows) {
|
|
|
|
m_previousButton = new QToolButton();
|
|
|
|
m_previousButton->setIcon(KIcon("go-previous"));
|
|
|
|
|
|
|
|
m_nextButton = new QToolButton();
|
|
|
|
m_nextButton->setIcon(KIcon("go-next"));
|
|
|
|
|
|
|
|
m_headerLayout->addWidget(m_previousButton);
|
|
|
|
m_headerLayout->addWidget(m_nextButton);
|
|
|
|
}
|
|
|
|
|
|
|
|
//hide these buttons for now, they're senseless
|
|
|
|
|
|
|
|
m_layout->addLayout(m_headerLayout);
|
|
|
|
|
|
|
|
QHBoxLayout* spaceLayout = new QHBoxLayout;
|
|
|
|
spaceLayout->addSpacing(10);
|
|
|
|
spaceLayout->addLayout(m_itemLayout);
|
|
|
|
|
|
|
|
m_layout->addLayout(spaceLayout);
|
|
|
|
|
|
|
|
if(maxHeight)
|
|
|
|
setMaximumHeight(maxHeight);
|
|
|
|
|
|
|
|
if(m_allowScrolling) {
|
|
|
|
QWidget* contentsWidget = new QWidget;
|
|
|
|
contentsWidget->setLayout(m_layout);
|
|
|
|
setWidget(contentsWidget);
|
|
|
|
}else{
|
|
|
|
setLayout(m_layout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NavigatableWidgetList::deleteItems() {
|
|
|
|
foreach(QWidget* item, items())
|
|
|
|
delete item;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NavigatableWidgetList::addItem(QWidget* widget, int pos) {
|
|
|
|
if(pos == -1)
|
|
|
|
m_itemLayout->addWidget(widget);
|
|
|
|
else
|
|
|
|
m_itemLayout->insertWidget(pos, widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<QWidget*> NavigatableWidgetList::items() const {
|
|
|
|
QList<QWidget*> ret;
|
|
|
|
for(int a = 0; a < m_itemLayout->count(); ++a) {
|
|
|
|
QWidgetItem* widgetItem = dynamic_cast<QWidgetItem*>(m_itemLayout->itemAt(a));
|
|
|
|
if(widgetItem) {
|
|
|
|
ret << widgetItem->widget();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NavigatableWidgetList::hasItems() const {
|
|
|
|
return (bool)m_itemLayout->count();
|
|
|
|
}
|
|
|
|
|
|
|
|
void NavigatableWidgetList::addHeaderItem(QWidget* widget, Qt::Alignment alignment) {
|
|
|
|
if(m_useArrows) {
|
|
|
|
Q_ASSERT(m_headerLayout->count() >= 2); //At least the 2 back/next buttons
|
|
|
|
m_headerLayout->insertWidget(m_headerLayout->count()-1, widget, alignment);
|
|
|
|
}else{
|
|
|
|
//We need to do this so the header doesn't get stretched
|
|
|
|
widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
|
|
|
m_headerLayout->insertWidget(m_headerLayout->count(), widget, alignment);
|
|
|
|
// widget->setMaximumHeight(20);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///Returns whether the uses in the child should be a new uses-group
|
|
|
|
bool isNewGroup(DUContext* parent, DUContext* child) {
|
|
|
|
if(parent->type() == DUContext::Other && child->type() == DUContext::Other)
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint countUses(int usedDeclarationIndex, DUContext* context) {
|
|
|
|
uint ret = 0;
|
|
|
|
|
|
|
|
for(int useIndex = 0; useIndex < context->usesCount(); ++useIndex)
|
|
|
|
if(context->uses()[useIndex].m_declarationIndex == usedDeclarationIndex)
|
|
|
|
++ret;
|
|
|
|
|
|
|
|
foreach(DUContext* child, context->childContexts())
|
|
|
|
if(!isNewGroup(context, child))
|
|
|
|
ret += countUses(usedDeclarationIndex, child);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<OneUseWidget*> createUseWidgets(const CodeRepresentation& code, int usedDeclarationIndex, IndexedDeclaration decl, DUContext* context) {
|
|
|
|
QList<OneUseWidget*> ret;
|
|
|
|
VERIFY_FOREGROUND_LOCKED
|
|
|
|
|
|
|
|
for(int useIndex = 0; useIndex < context->usesCount(); ++useIndex)
|
|
|
|
if(context->uses()[useIndex].m_declarationIndex == usedDeclarationIndex)
|
|
|
|
ret << new OneUseWidget(decl, context->url(), context->transformFromLocalRevision(context->uses()[useIndex].m_range), code);
|
|
|
|
|
|
|
|
foreach(DUContext* child, context->childContexts())
|
|
|
|
if(!isNewGroup(context, child))
|
|
|
|
ret += createUseWidgets(code, usedDeclarationIndex, decl, child);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ContextUsesWidget::ContextUsesWidget(const CodeRepresentation& code, QList<IndexedDeclaration> usedDeclarations, IndexedDUContext context) : m_context(context) {
|
|
|
|
|
|
|
|
setFrameShape(NoFrame);
|
|
|
|
|
|
|
|
DUChainReadLocker lock(DUChain::lock());
|
|
|
|
QString headerText = i18n("Unknown context");
|
|
|
|
setUpdatesEnabled(false);
|
|
|
|
|
|
|
|
if(context.data()) {
|
|
|
|
DUContext* ctx = context.data();
|
|
|
|
|
|
|
|
if(ctx->scopeIdentifier(true).isEmpty())
|
|
|
|
headerText = i18n("Global");
|
|
|
|
else {
|
|
|
|
headerText = ctx->scopeIdentifier(true).toString();
|
|
|
|
if(ctx->type() == DUContext::Function || (ctx->owner() && ctx->owner()->isFunctionDeclaration()))
|
|
|
|
headerText += "(...)";
|
|
|
|
}
|
|
|
|
|
|
|
|
QSet<int> hadIndices;
|
|
|
|
|
|
|
|
foreach(const IndexedDeclaration &usedDeclaration, usedDeclarations) {
|
|
|
|
int usedDeclarationIndex = ctx->topContext()->indexForUsedDeclaration(usedDeclaration.data(), false);
|
|
|
|
if(hadIndices.contains(usedDeclarationIndex))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
hadIndices.insert(usedDeclarationIndex);
|
|
|
|
|
|
|
|
if(usedDeclarationIndex != std::numeric_limits<int>::max()) {
|
|
|
|
foreach(OneUseWidget* widget, createUseWidgets(code, usedDeclarationIndex, usedDeclaration, ctx))
|
|
|
|
addItem(widget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QLabel* headerLabel = new QLabel(i18nc("%1: source file", "In %1", "<a href='navigateToFunction'>"
|
|
|
|
+ Qt::escape(headerText) + "</a>: "));
|
|
|
|
addHeaderItem(headerLabel);
|
|
|
|
setUpdatesEnabled(true);
|
|
|
|
connect(headerLabel, SIGNAL(linkActivated(QString)), this, SLOT(linkWasActivated(QString)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ContextUsesWidget::linkWasActivated(QString link) {
|
|
|
|
if ( link == "navigateToFunction" ) {
|
|
|
|
DUChainReadLocker lock(DUChain::lock());
|
|
|
|
DUContext* context = m_context.context();
|
|
|
|
if(context) {
|
|
|
|
CursorInRevision contextStart = context->range().start;
|
|
|
|
KTextEditor::Cursor cursor(contextStart.line, contextStart.column);
|
|
|
|
KUrl url = context->url().toUrl();
|
|
|
|
lock.unlock();
|
|
|
|
ForegroundLock fgLock;
|
|
|
|
ICore::self()->documentController()->openDocument(url, cursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DeclarationWidget::DeclarationWidget(const CodeRepresentation& code, const IndexedDeclaration& decl) {
|
|
|
|
|
|
|
|
setFrameShape(NoFrame);
|
|
|
|
DUChainReadLocker lock(DUChain::lock());
|
|
|
|
|
|
|
|
setUpdatesEnabled(false);
|
|
|
|
if (Declaration* dec = decl.data()) {
|
|
|
|
QLabel* headerLabel = new QLabel(dec->isDefinition() ? i18n("Definition") : i18n("Declaration"));
|
|
|
|
addHeaderItem(headerLabel);
|
|
|
|
addItem(new OneUseWidget(decl, dec->url(), dec->rangeInCurrentRevision(), code));
|
|
|
|
}
|
|
|
|
|
|
|
|
setUpdatesEnabled(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
TopContextUsesWidget::TopContextUsesWidget(IndexedDeclaration declaration, QList<IndexedDeclaration> allDeclarations, IndexedTopDUContext topContext)
|
|
|
|
: m_topContext(topContext)
|
|
|
|
, m_declaration(declaration)
|
|
|
|
, m_allDeclarations(allDeclarations)
|
|
|
|
, m_usesCount(0)
|
|
|
|
{
|
|
|
|
m_itemLayout->setContentsMargins(10, 0, 0, 5);
|
|
|
|
setFrameShape(NoFrame);
|
|
|
|
setUpdatesEnabled(false);
|
|
|
|
DUChainReadLocker lock(DUChain::lock());
|
|
|
|
QHBoxLayout * labelLayout = new QHBoxLayout;
|
|
|
|
QWidget* headerWidget = new QWidget;
|
|
|
|
headerWidget->setLayout(labelLayout);
|
|
|
|
headerWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
|
|
|
|
|
|
|
|
QLabel* label = new QLabel(this);
|
|
|
|
m_icon = new QLabel(this);
|
|
|
|
m_toggleButton = new QLabel(this);
|
|
|
|
m_icon->setPixmap(KIcon("code-class").pixmap(16));
|
|
|
|
labelLayout->addWidget(m_icon);
|
|
|
|
labelLayout->addWidget(label);
|
|
|
|
labelLayout->addWidget(m_toggleButton);
|
|
|
|
labelLayout->setAlignment(Qt::AlignLeft);
|
|
|
|
|
|
|
|
if(topContext.isLoaded())
|
|
|
|
m_usesCount = DUChainUtils::contextCountUses(topContext.data(), declaration.data());
|
|
|
|
|
|
|
|
QString labelText = i18ncp("%1: number of uses, %2: filename with uses", "%2: 1 use", "%2: %1 uses",
|
|
|
|
m_usesCount, ICore::self()->projectController()->prettyFileName(topContext.url().toUrl()));
|
|
|
|
label->setText(labelText);
|
|
|
|
|
|
|
|
m_toggleButton->setText(" <a href='toggleCollapsed'>[" + i18nc("Refers to closing a UI element", "Collapse") + "]</a>");
|
|
|
|
|
|
|
|
connect(m_toggleButton, SIGNAL(linkActivated(QString)), this, SLOT(labelClicked()));
|
|
|
|
addHeaderItem(headerWidget);
|
|
|
|
setUpdatesEnabled(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
int TopContextUsesWidget::usesCount() const
|
|
|
|
{
|
|
|
|
return m_usesCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<ContextUsesWidget*> buildContextUses(const CodeRepresentation& code, QList<IndexedDeclaration> declarations, DUContext* context) {
|
|
|
|
QList<ContextUsesWidget*> ret;
|
|
|
|
|
|
|
|
if(!context->parentContext() || isNewGroup(context->parentContext(), context)) {
|
|
|
|
ContextUsesWidget* created = new ContextUsesWidget(code, declarations, context);
|
|
|
|
if(created->hasItems())
|
|
|
|
ret << created;
|
|
|
|
else
|
|
|
|
delete created;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach(DUContext* child, context->childContexts())
|
|
|
|
ret += buildContextUses(code, declarations, child);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TopContextUsesWidget::setExpanded(bool expanded) {
|
|
|
|
if(!expanded) {
|
|
|
|
m_toggleButton->setText(" <a href='toggleCollapsed'>[" + i18nc("Refers to opening a UI element", "Expand") + "]</a>");
|
|
|
|
deleteItems();
|
|
|
|
}else{
|
|
|
|
m_toggleButton->setText(" <a href='toggleCollapsed'>[" + i18nc("Refers to closing a UI element", "Collapse") + "]</a>");
|
|
|
|
if(hasItems())
|
|
|
|
return;
|
|
|
|
DUChainReadLocker lock(DUChain::lock());
|
|
|
|
TopDUContext* topContext = m_topContext.data();
|
|
|
|
|
|
|
|
if(topContext && m_declaration.data()) {
|
|
|
|
|
|
|
|
CodeRepresentation::Ptr code = createCodeRepresentation(topContext->url());
|
|
|
|
setUpdatesEnabled(false);
|
|
|
|
|
|
|
|
IndexedTopDUContext localTopContext(topContext);
|
|
|
|
foreach(const IndexedDeclaration &decl, m_allDeclarations) {
|
|
|
|
if(decl.indexedTopContext() == localTopContext) {
|
|
|
|
addItem(new DeclarationWidget(*code, decl));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach(ContextUsesWidget* usesWidget, buildContextUses(*code, m_allDeclarations, topContext)) {
|
|
|
|
addItem(usesWidget);
|
|
|
|
}
|
|
|
|
setUpdatesEnabled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TopContextUsesWidget::labelClicked() {
|
|
|
|
if(hasItems()) {
|
|
|
|
setExpanded(false);
|
|
|
|
}else{
|
|
|
|
setExpanded(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UsesWidget::~UsesWidget()
|
|
|
|
{
|
|
|
|
if (m_collector) {
|
|
|
|
m_collector->setWidget(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UsesWidget::UsesWidget(const IndexedDeclaration& declaration, QSharedPointer<UsesWidgetCollector> customCollector)
|
|
|
|
: NavigatableWidgetList(true)
|
|
|
|
{
|
|
|
|
DUChainReadLocker lock(DUChain::lock());
|
|
|
|
setUpdatesEnabled(false);
|
|
|
|
|
|
|
|
m_headerLine = new QLabel;
|
|
|
|
redrawHeaderLine();
|
|
|
|
connect(m_headerLine, SIGNAL(linkActivated(QString)), this, SLOT(headerLinkActivated(QString)));
|
|
|
|
m_layout->insertWidget(0, m_headerLine, 0, Qt::AlignTop);
|
|
|
|
|
|
|
|
m_layout->setAlignment(Qt::AlignTop);
|
|
|
|
m_itemLayout->setAlignment(Qt::AlignTop);
|
|
|
|
|
|
|
|
m_progressBar = new QProgressBar;
|
|
|
|
addHeaderItem(m_progressBar);
|
|
|
|
|
|
|
|
if (!customCollector) {
|
|
|
|
m_collector = QSharedPointer<UsesWidgetCollector>(new UsesWidgetCollector(declaration));
|
|
|
|
} else {
|
|
|
|
m_collector = customCollector;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_collector->setProcessDeclarations(true);
|
|
|
|
m_collector->setWidget(this);
|
|
|
|
m_collector->startCollecting();
|
|
|
|
|
|
|
|
setUpdatesEnabled(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UsesWidget::redrawHeaderLine()
|
|
|
|
{
|
|
|
|
m_headerLine->setText(headerLineText());
|
|
|
|
}
|
|
|
|
|
|
|
|
const QString UsesWidget::headerLineText() const
|
|
|
|
{
|
|
|
|
return i18np("1 use found", "%1 uses found", countAllUses()) + " • "
|
|
|
|
"<a href='expandAll'>[" + i18n("Expand all") + "]</a> • "
|
|
|
|
"<a href='collapseAll'>[" + i18n("Collapse all") + "]</a>";
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int UsesWidget::countAllUses() const
|
|
|
|
{
|
|
|
|
unsigned int totalUses = 0;
|
|
|
|
foreach ( QWidget* w, items() ) {
|
|
|
|
if ( TopContextUsesWidget* useWidget = dynamic_cast<TopContextUsesWidget*>(w) ) {
|
|
|
|
totalUses += useWidget->usesCount();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return totalUses;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UsesWidget::setAllExpanded(bool expanded)
|
|
|
|
{
|
|
|
|
foreach ( QWidget* w, items() ) {
|
|
|
|
if ( TopContextUsesWidget* useWidget = dynamic_cast<TopContextUsesWidget*>(w) ) {
|
|
|
|
useWidget->setExpanded(expanded);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UsesWidget::headerLinkActivated(QString linkName)
|
|
|
|
{
|
|
|
|
if(linkName == "expandAll") {
|
|
|
|
setAllExpanded(true);
|
|
|
|
}
|
|
|
|
else if(linkName == "collapseAll") {
|
|
|
|
setAllExpanded(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UsesWidget::UsesWidgetCollector::UsesWidgetCollector(IndexedDeclaration decl) : UsesCollector(decl), m_widget(0) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void UsesWidget::UsesWidgetCollector::setWidget(UsesWidget* widget ) {
|
|
|
|
m_widget = widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UsesWidget::UsesWidgetCollector::maximumProgress(uint max) {
|
|
|
|
if (!m_widget) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_widget->m_progressBar) {
|
|
|
|
m_widget->m_progressBar->setMaximum(max);
|
|
|
|
m_widget->m_progressBar->setMinimum(0);
|
|
|
|
m_widget->m_progressBar->setValue(0);
|
|
|
|
}else{
|
|
|
|
kWarning() << "maximumProgress called twice";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UsesWidget::UsesWidgetCollector::progress(uint processed, uint total) {
|
|
|
|
if (!m_widget) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_widget->redrawHeaderLine();
|
|
|
|
|
|
|
|
if(m_widget->m_progressBar) {
|
|
|
|
m_widget->m_progressBar->setValue(processed);
|
|
|
|
|
|
|
|
if(processed == total) {
|
|
|
|
m_widget->setUpdatesEnabled(false);
|
|
|
|
delete m_widget->m_progressBar;
|
|
|
|
m_widget->m_progressBar = 0;
|
|
|
|
m_widget->setShowHeader(false);
|
|
|
|
m_widget->setUpdatesEnabled(true);
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
kWarning() << "progress() called too often";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UsesWidget::UsesWidgetCollector::processUses( KDevelop::ReferencedTopDUContext topContext ) {
|
|
|
|
if (!m_widget) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DUChainReadLocker lock;
|
|
|
|
|
|
|
|
kDebug() << "processing" << topContext->url().str();
|
|
|
|
TopContextUsesWidget* widget = new TopContextUsesWidget(declaration(), declarations(), topContext.data());
|
|
|
|
|
|
|
|
// move to back if it's just the declaration/definition
|
|
|
|
bool toBack = widget->usesCount() == 0;
|
|
|
|
// move to front the item belonging to the current open document
|
|
|
|
IDocument* doc = ICore::self()->documentController()->activeDocument();
|
|
|
|
bool toFront = doc && doc->url().equals(topContext->url().toUrl());
|
|
|
|
|
|
|
|
widget->setExpanded(true);
|
|
|
|
|
|
|
|
m_widget->addItem(widget, toFront ? 0 : toBack ? widget->items().size() : -1);
|
|
|
|
m_widget->redrawHeaderLine();
|
|
|
|
}
|
|
|
|
|
|
|
|
QSize KDevelop::UsesWidget::sizeHint() const {
|
|
|
|
QSize ret = QWidget::sizeHint();
|
|
|
|
if(ret.height() < 300)
|
|
|
|
ret.setHeight(300);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "moc_useswidget.cpp"
|