Files
Sourcetrail/src/lib_gui/qt/element/code/QtCodeSnippet.cpp
T

321 lines
7.8 KiB
C++

#include "QtCodeSnippet.h"
#include <QBoxLayout>
#include <QPushButton>
#include <QStyle>
#include <qmenu.h>
#include "MessageShowScope.h"
#include "QtCodeFile.h"
#include "QtCodeNavigator.h"
#include "QtHoverButton.h"
#include "SourceLocationFile.h"
QtCodeSnippet::QtCodeSnippet(const CodeSnippetParams& params, QtCodeNavigator* navigator, QtCodeFile* file)
: QFrame(file)
, m_navigator(navigator)
, m_file(file)
, m_titleId(params.titleId)
, m_titleString(params.title)
, m_footerId(params.footerId)
, m_footerString(params.footer)
{
setObjectName(QStringLiteral("code_snippet"));
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
if (!m_titleString.empty() && !params.isOverview)
{
m_title = createScopeLine(layout);
m_titleDots = m_dots.back();
if (m_titleId == 0) // title is a file path
{
m_title->setText(QString::fromStdWString(FilePath(m_titleString).fileName()));
}
else
{
m_title->setText(QString::fromStdWString(m_titleString));
}
connect(m_title, &QPushButton::clicked, this, &QtCodeSnippet::clickedTitle);
}
m_codeArea = new QtCodeArea(
params.startLineNumber, params.code, params.locationFile, navigator, !params.isOverview, this);
layout->addWidget(m_codeArea);
if (!m_footerString.empty())
{
m_footer = createScopeLine(layout);
m_footerDots = m_dots.back();
if (m_footerId == 0) // footer is a file path
{
m_footer->setText(QString::fromStdWString(FilePath(m_footerString).fileName()));
}
else
{
m_footer->setText(QString::fromStdWString(m_footerString));
}
connect(m_footer, &QPushButton::clicked, this, &QtCodeSnippet::clickedFooter);
}
}
QtCodeSnippet::~QtCodeSnippet() {}
QtCodeFile* QtCodeSnippet::getFile() const
{
return m_file;
}
QtCodeArea* QtCodeSnippet::getArea() const
{
return m_codeArea;
}
size_t QtCodeSnippet::getStartLineNumber() const
{
return m_codeArea->getStartLineNumber();
}
size_t QtCodeSnippet::getEndLineNumber() const
{
return m_codeArea->getEndLineNumber();
}
int QtCodeSnippet::lineNumberDigits() const
{
return m_codeArea->lineNumberDigits();
}
void QtCodeSnippet::updateSourceLocations(const CodeSnippetParams& params)
{
m_codeArea->updateSourceLocations(params.locationFile);
ensureLocationIdVisible(m_codeArea->getLocationIdOfFirstHighlightedLocation(), false);
}
void QtCodeSnippet::updateLineNumberAreaWidthForDigits(int digits)
{
m_codeArea->updateLineNumberAreaWidthForDigits(digits);
updateDots();
}
void QtCodeSnippet::updateContent()
{
m_codeArea->updateContent();
updateDots();
updateScopeLineFocus(m_title, m_titleDots);
updateScopeLineFocus(m_footer, m_footerDots);
}
void QtCodeSnippet::setIsActiveFile(bool isActiveFile)
{
m_codeArea->setIsActiveFile(isActiveFile);
}
size_t QtCodeSnippet::getLineNumberForLocationId(Id locationId) const
{
return m_codeArea->getLineNumberForLocationId(locationId);
}
std::pair<size_t, size_t> QtCodeSnippet::getLineNumbersForLocationId(Id locationId) const
{
return m_codeArea->getLineNumbersForLocationId(locationId);
}
Id QtCodeSnippet::getFirstActiveLocationId(Id tokenId) const
{
Id scopeId = m_codeArea->getLocationIdOfFirstActiveScopeLocation(tokenId);
if (scopeId)
{
return scopeId;
}
return m_codeArea->getLocationIdOfFirstActiveLocation(tokenId);
}
QRectF QtCodeSnippet::getLineRectForLineNumber(size_t lineNumber) const
{
return m_codeArea->getLineRectForLineNumber(lineNumber);
}
std::string QtCodeSnippet::getCode() const
{
return m_codeArea->getCode();
}
void QtCodeSnippet::findScreenMatches(
const std::wstring& query, std::vector<std::pair<QtCodeArea*, Id>>* screenMatches)
{
m_codeArea->findScreenMatches(query, screenMatches);
}
bool QtCodeSnippet::hasFocus(const CodeFocusHandler::Focus& focus) const
{
return m_codeArea == focus.area;
}
bool QtCodeSnippet::setFocus(Id locationId)
{
return m_codeArea->setFocus(locationId);
}
bool QtCodeSnippet::moveFocus(const CodeFocusHandler::Focus& focus, CodeFocusHandler::Direction direction)
{
if (m_codeArea == focus.area)
{
if (focus.scopeLine)
{
if (m_title == focus.scopeLine && direction == CodeFocusHandler::Direction::DOWN)
{
return m_codeArea->moveFocus(direction, m_codeArea->getStartLineNumber() - 1, 0);
}
else if (m_footer == focus.scopeLine && direction == CodeFocusHandler::Direction::UP)
{
return m_codeArea->moveFocus(direction, m_codeArea->getEndLineNumber() + 1, 0);
}
}
else
{
bool moved = m_codeArea->moveFocus(direction, focus.lineNumber, focus.locationId);
if (!moved)
{
if (m_title && direction == CodeFocusHandler::Direction::UP)
{
m_navigator->setFocusedScopeLine(m_codeArea, m_title, getStartLineNumber());
return true;
}
else if (m_footer && direction == CodeFocusHandler::Direction::DOWN)
{
m_navigator->setFocusedScopeLine(m_codeArea, m_footer, getEndLineNumber());
return true;
}
}
return moved;
}
}
return false;
}
void QtCodeSnippet::focusTop()
{
if (m_title)
{
m_navigator->setFocusedScopeLine(m_codeArea, m_title, getStartLineNumber());
}
else
{
m_codeArea->moveFocus(
CodeFocusHandler::Direction::DOWN, m_codeArea->getStartLineNumber() - 1, 0);
}
}
void QtCodeSnippet::focusBottom()
{
if (m_footer)
{
m_navigator->setFocusedScopeLine(m_codeArea, m_footer, getEndLineNumber());
}
else
{
m_codeArea->moveFocus(CodeFocusHandler::Direction::UP, m_codeArea->getEndLineNumber() + 1, 0);
}
}
void QtCodeSnippet::copySelection()
{
m_codeArea->copySelection();
}
void QtCodeSnippet::ensureLocationIdVisible(Id locationId, bool animated)
{
m_codeArea->ensureLocationIdVisible(locationId, width(), animated);
}
void QtCodeSnippet::clickedTitle()
{
m_codeArea->moveFocusToLine(static_cast<int>(m_codeArea->getStartLineNumber()), 0, false);
if (m_titleId > 0)
{
MessageShowScope(m_titleId, m_navigator->hasErrors()).dispatch();
}
else
{
getFile()->requestWholeFileContent(getStartLineNumber());
}
}
void QtCodeSnippet::clickedFooter()
{
m_codeArea->moveFocusToLine(static_cast<int>(m_codeArea->getEndLineNumber()), 0, true);
if (m_footerId > 0)
{
MessageShowScope(m_footerId, m_navigator->hasErrors()).dispatch();
}
else
{
getFile()->requestWholeFileContent(getEndLineNumber());
}
}
QtHoverButton* QtCodeSnippet::createScopeLine(QBoxLayout* layout)
{
QHBoxLayout* lineLayout = new QHBoxLayout();
lineLayout->setContentsMargins(0, 0, 0, 0);
lineLayout->setSpacing(0);
lineLayout->setAlignment(Qt::AlignLeft);
layout->addLayout(lineLayout);
QPushButton* dots = new QPushButton(this);
dots->setObjectName(QStringLiteral("dots"));
dots->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
lineLayout->addWidget(dots);
m_dots.push_back(dots);
QtHoverButton* line = new QtHoverButton(this);
line->setObjectName(QStringLiteral("scope_name"));
line->minimumSizeHint(); // force font loading
line->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
line->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
lineLayout->addWidget(line);
connect(line, &QtHoverButton::hoveredIn, [this, line]() {
m_navigator->setFocusedScopeLine(m_codeArea, line, 0);
m_navigator->setFocus();
});
return line;
}
void QtCodeSnippet::updateDots()
{
for (QPushButton* dots: m_dots)
{
dots->setText(QString::fromStdString(std::string(lineNumberDigits(), '.')));
dots->setMinimumWidth(m_codeArea->lineNumberAreaWidth());
}
}
void QtCodeSnippet::updateScopeLineFocus(QPushButton* line, QPushButton* dots)
{
if (line && dots)
{
bool focus = line == m_navigator->getCurrentFocus().scopeLine;
if (focus != dots->property("focused").toBool())
{
line->setProperty("focused", focus);
line->style()->polish(line); // recomputes style to make property take effect
dots->setProperty("focused", focus);
dots->style()->polish(dots); // recomputes style to make property take effect
}
}
}