ui: scope names in snippet titles

* added title for snippets
* title displays name of parent scope.
* when new TokenLocationFiles are created in the storage they are now returned as shared_ptr to ensure correct linking in the contained data.
* Storage::getTokenLocationsForLinesInFile() now always returns pairs of start and end locations.
* Adjusted code snippet view to regard the change described above.
This commit is contained in:
malte_langkabel
2015-05-11 12:34:27 +02:00
parent 7d48a873f7
commit 97345cc72f
22 changed files with 667 additions and 556 deletions
+2
View File
@@ -7,6 +7,8 @@ add_files(
qt/element/QtAutocompletionList.cpp
qt/element/QtAutocompletionList.h
qt/element/QtCodeArea.cpp
qt/element/QtCodeArea.h
qt/element/QtCodeFile.cpp
qt/element/QtCodeFile.h
qt/element/QtCodeFileList.cpp
+438
View File
@@ -0,0 +1,438 @@
#include "qt/element/QtCodeArea.h"
#include <QFont>
#include <QHBoxLayout>
#include <QPainter>
#include <QPushButton>
#include <QToolTip>
#include "utility/messaging/type/MessageActivateTokenLocation.h"
#include "utility/messaging/type/MessageShowFile.h"
#include "data/location/TokenLocation.h"
#include "data/location/TokenLocationFile.h"
#include "qt/element/QtCodeFile.h"
#include "qt/utility/QtHighlighter.h"
#include "settings/ApplicationSettings.h"
QtCodeArea::LineNumberArea::LineNumberArea(QtCodeArea *codeArea)
: QWidget(codeArea)
, m_codeArea(codeArea)
{
setObjectName("line_number_area");
}
QtCodeArea::LineNumberArea::~LineNumberArea()
{
}
QSize QtCodeArea::LineNumberArea::sizeHint() const
{
return QSize(m_codeArea->lineNumberAreaWidth(), 0);
}
void QtCodeArea::LineNumberArea::paintEvent(QPaintEvent *event)
{
m_codeArea->lineNumberAreaPaintEvent(event);
}
QtCodeArea::QtCodeArea(
uint startLineNumber,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
QtCodeFile* parent
)
: QPlainTextEdit(parent)
, m_parent(parent)
, m_maximizeButton(nullptr)
, m_startLineNumber(startLineNumber)
, m_hoveredAnnotation(nullptr)
, m_digits(0)
{
setObjectName("code_area");
setReadOnly(true);
setFrameStyle(QFrame::NoFrame);
setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setLineWrapMode(QPlainTextEdit::NoWrap);
m_lineNumberArea = new LineNumberArea(this);
m_highlighter = new QtHighlighter(document());
std::string displayCode = code;
if (*code.rbegin() == '\n')
{
displayCode.pop_back();
}
setPlainText(QString::fromUtf8(displayCode.c_str()));
createAnnotations(locationFile);
annotateText();
m_digits = lineNumberDigits();
updateLineNumberAreaWidth(0);
connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int)));
connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int)));
connect(this, SIGNAL(selectionChanged()), this, SLOT(clearSelection()));
this->setMouseTracking(true);
}
QtCodeArea::~QtCodeArea()
{
}
QSize QtCodeArea::sizeHint() const
{
int width = 480;
int height = (document()->size().height() + 0.7f) * fontMetrics().lineSpacing();
return QSize(width, height);
}
void QtCodeArea::addMaximizeButton()
{
QHBoxLayout* layout = new QHBoxLayout();
layout->setMargin(0);
layout->setSpacing(0);
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
m_maximizeButton = new QPushButton(this);
m_maximizeButton->setObjectName("maximize_button");
m_maximizeButton->setEnabled(false);
layout->addWidget(m_maximizeButton);
layout->setAlignment(m_maximizeButton, Qt::AlignRight);
connect(m_maximizeButton, SIGNAL(clicked()), this, SLOT(clickedMaximizeButton()));
}
void QtCodeArea::lineNumberAreaPaintEvent(QPaintEvent *event)
{
QPainter painter(m_lineNumberArea);
QTextBlock block = firstVisibleBlock();
int blockNumber = block.blockNumber();
int top = static_cast<int>(blockBoundingGeometry(block).translated(contentOffset()).top());
int bottom = top + static_cast<int>(blockBoundingRect(block).height());
while (block.isValid() && top <= event->rect().bottom())
{
if (block.isVisible() && bottom >= event->rect().top())
{
QString number = QString::number(blockNumber + m_startLineNumber);
painter.setPen(Qt::black);
painter.drawText(0, top, m_lineNumberArea->width() - 13, fontMetrics().height(), Qt::AlignRight, number);
}
block = block.next();
top = bottom;
bottom = top + static_cast<int>(blockBoundingRect(block).height());
blockNumber++;
}
}
int QtCodeArea::lineNumberDigits() const
{
int digits = 1;
int max = qMax(1, int(m_startLineNumber) + blockCount());
while (max >= 10)
{
max /= 10;
digits++;
}
return digits;
}
int QtCodeArea::lineNumberAreaWidth() const
{
return fontMetrics().width(QLatin1Char('9')) * m_digits + 30;
}
void QtCodeArea::updateLineNumberAreaWidthForDigits(int digits)
{
m_digits = digits;
updateLineNumberAreaWidth(0);
}
void QtCodeArea::update()
{
annotateText();
}
void QtCodeArea::resizeEvent(QResizeEvent *e)
{
QPlainTextEdit::resizeEvent(e);
QRect cr = contentsRect();
m_lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}
void QtCodeArea::showEvent(QShowEvent* event)
{
int tabWidth = ApplicationSettings::getInstance()->getCodeTabWidth();
setTabStopWidth(tabWidth * fontMetrics().width('9'));
setMaximumHeight(sizeHint().height());
}
void QtCodeArea::enterEvent(QEvent* event)
{
if (m_maximizeButton)
{
m_maximizeButton->setEnabled(true);
}
}
void QtCodeArea::leaveEvent(QEvent* event)
{
if (m_maximizeButton)
{
m_maximizeButton->setEnabled(false);
}
m_hoveredAnnotation = nullptr;
annotateText();
}
void QtCodeArea::mouseReleaseEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
QTextCursor cursor = this->cursorForPosition(event->pos());
const Annotation* annotation = findAnnotationForPosition(cursor.position());
if (annotation)
{
MessageActivateTokenLocation(annotation->locationId).dispatch();
}
}
}
void QtCodeArea::mouseDoubleClickEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton && m_maximizeButton)
{
clickedMaximizeButton();
}
}
void QtCodeArea::mouseMoveEvent(QMouseEvent* event)
{
QTextCursor cursor = this->cursorForPosition(event->pos());
const Annotation* annotation = findAnnotationForPosition(cursor.position());
if (annotation && annotation->isScope)
{
annotation = nullptr;
}
if (annotation != m_hoveredAnnotation)
{
m_hoveredAnnotation = annotation;
const std::vector<std::string>& errorMessages = m_parent->getErrorMessages();
if (annotation && errorMessages.size() > annotation->tokenId)
{
QToolTip::showText(event->globalPos(), QString::fromStdString(m_parent->getErrorMessages()[annotation->tokenId]));
}
else
{
QToolTip::hideText();
}
annotateText();
}
}
void QtCodeArea::updateLineNumberAreaWidth(int /* newBlockCount */)
{
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}
void QtCodeArea::updateLineNumberArea(const QRect &rect, int dy)
{
if (dy)
{
m_lineNumberArea->scroll(0, dy);
}
else
{
m_lineNumberArea->update(0, rect.y(), m_lineNumberArea->width(), rect.height());
}
if (rect.contains(viewport()->rect()))
{
updateLineNumberAreaWidth(0);
}
}
void QtCodeArea::clickedMaximizeButton()
{
MessageShowFile(m_parent->getFilePath().absoluteStr(), m_startLineNumber, m_startLineNumber + blockCount() - 1).dispatch();
}
void QtCodeArea::clearSelection()
{
QTextCursor cursor = textCursor();
cursor.clearSelection();
setTextCursor(cursor);
}
const QtCodeArea::Annotation* QtCodeArea::findAnnotationForPosition(int pos) const
{
const Annotation* annotationPtr = nullptr;
int diff = endTextEditPosition() + 1;
for (const Annotation& annotation : m_annotations)
{
if (pos >= annotation.start && pos <= annotation.end)
{
int d = annotation.end - annotation.start;
if (d < diff)
{
diff = d;
annotationPtr = &annotation;
}
}
}
return annotationPtr;
}
void QtCodeArea::createAnnotations(std::shared_ptr<TokenLocationFile> locationFile)
{
locationFile->forEachStartTokenLocation(
[&](TokenLocation* startLocation)
{
Annotation annotation;
int endLineNumber = m_startLineNumber + blockCount() - 1;
if (startLocation->getLineNumber() <= endLineNumber)
{
if (startLocation->getLineNumber() < m_startLineNumber)
{
annotation.start = startTextEditPosition();
}
else
{
annotation.start = toTextEditPosition(startLocation->getLineNumber(), startLocation->getColumnNumber() - 1);
}
}
else
{
return;
}
TokenLocation* endLocation = startLocation->getEndTokenLocation();
if (endLocation->getLineNumber() >= m_startLineNumber)
{
if (endLocation->getLineNumber() > endLineNumber)
{
annotation.end = endTextEditPosition();
}
else
{
annotation.end = toTextEditPosition(endLocation->getLineNumber(), endLocation->getColumnNumber());
}
}
else
{
return;
}
annotation.tokenId = startLocation->getTokenId();
annotation.locationId = startLocation->getId();
annotation.isScope = (startLocation->getType() == TokenLocation::LOCATION_SCOPE);
m_annotations.push_back(annotation);
}
);
}
void QtCodeArea::annotateText()
{
Colori color;
const std::vector<Id>& ids = m_parent->getActiveTokenIds();
const std::vector<std::string>& errorMessages = m_parent->getErrorMessages();
QList<QTextEdit::ExtraSelection> extraSelections;
for (const Annotation& annotation: m_annotations)
{
bool isActive = std::find(ids.begin(), ids.end(), annotation.tokenId) != ids.end();
if (&annotation == m_hoveredAnnotation && errorMessages.size())
{
color = Colori(255, 0, 0, 128);
}
else if (&annotation == m_hoveredAnnotation)
{
color = ApplicationSettings::getInstance()->getCodeActiveLinkColor();
}
else if (errorMessages.size())
{
color = Colori(255, 0, 0, 255);
}
else if (isActive)
{
color = ApplicationSettings::getInstance()->getCodeActiveLinkColor();
if (annotation.isScope)
{
color.a /= 2;
}
}
else if (annotation.isScope)
{
color = ApplicationSettings::getInstance()->getCodeScopeColor();
}
else
{
color = ApplicationSettings::getInstance()->getCodeLinkColor();
}
QTextEdit::ExtraSelection selection;
selection.format.setBackground(QColor(color.r, color.g, color.b, color.a));
selection.cursor = textCursor();
selection.cursor.clearSelection();
selection.cursor.setPosition(annotation.start);
selection.cursor.setPosition(annotation.end, QTextCursor::KeepAnchor);
extraSelections.append(selection);
}
setExtraSelections(extraSelections);
}
int QtCodeArea::toTextEditPosition(int lineNumber, int columnNumber) const
{
lineNumber -= m_startLineNumber - 1;
int position = 0;
for (int i = 0; i < lineNumber - 1; i++)
{
position += document()->findBlockByLineNumber(i).length();
}
position += columnNumber;
return position;
}
int QtCodeArea::startTextEditPosition() const
{
return 0;
}
int QtCodeArea::endTextEditPosition() const
{
int position = 0;
for (int i = 0; i < document()->blockCount(); i++)
{
position += document()->findBlockByLineNumber(i).length();
}
return position - 1;
}
+110
View File
@@ -0,0 +1,110 @@
#ifndef QT_CODE_AREA_H
#define QT_CODE_AREA_H
#include <vector>
#include <memory>
#include <QPlainTextEdit>
#include "utility/types.h"
class QPaintEvent;
class QPushButton;
class QResizeEvent;
class QSize;
class QtCodeFile;
class QtHighlighter;
class QWidget;
class TokenLocation;
class TokenLocationFile;
class QtCodeArea: public QPlainTextEdit
{
Q_OBJECT
public:
class LineNumberArea: public QWidget
{
public:
LineNumberArea(QtCodeArea *codeArea);
virtual ~LineNumberArea();
QSize sizeHint() const;
protected:
void paintEvent(QPaintEvent* event);
private:
QtCodeArea *m_codeArea;
};
QtCodeArea(
uint startLineNumber,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
QtCodeFile* parent
);
virtual ~QtCodeArea();
QSize sizeHint() const;
void addMaximizeButton();
void lineNumberAreaPaintEvent(QPaintEvent *event);
int lineNumberDigits() const;
int lineNumberAreaWidth() const;
void updateLineNumberAreaWidthForDigits(int digits);
void update();
protected:
virtual void resizeEvent(QResizeEvent *event);
virtual void showEvent(QShowEvent* event);
virtual void enterEvent(QEvent* event);
virtual void leaveEvent(QEvent* event);
virtual void mouseReleaseEvent(QMouseEvent* event);
virtual void mouseDoubleClickEvent(QMouseEvent* event);
virtual void mouseMoveEvent(QMouseEvent* event);
private slots:
void updateLineNumberAreaWidth(int newBlockCount);
void updateLineNumberArea(const QRect &, int);
void clickedMaximizeButton();
void clearSelection();
private:
struct Annotation
{
int start;
int end;
Id tokenId;
Id locationId;
bool isScope;
};
const Annotation* findAnnotationForPosition(int pos) const;
void createAnnotations(std::shared_ptr<TokenLocationFile> locationFile);
void annotateText();
bool locationBelongsToSnippet(TokenLocation* location) const;
int toTextEditPosition(int lineNumber, int columnNumber) const;
int startTextEditPosition() const;
int endTextEditPosition() const;
QtCodeFile* m_parent;
QWidget* m_lineNumberArea;
QtHighlighter* m_highlighter;
QPushButton* m_maximizeButton;
const uint m_startLineNumber;
std::vector<Annotation> m_annotations;
const Annotation* m_hoveredAnnotation;
int m_digits;
};
#endif // QT_CODE_AREA_H
+3 -2
View File
@@ -61,11 +61,12 @@ const std::vector<std::string>& QtCodeFile::getErrorMessages() const
void QtCodeFile::addCodeSnippet(
uint startLineNumber,
const std::string& title,
const std::string& code,
const TokenLocationFile& locationFile
std::shared_ptr<TokenLocationFile> locationFile
){
std::shared_ptr<QtCodeSnippet> snippet(
new QtCodeSnippet(startLineNumber, code, locationFile, this));
new QtCodeSnippet(startLineNumber, title, code, locationFile, this));
if (m_parent->getShowMaximizeButton())
{
+2 -1
View File
@@ -31,8 +31,9 @@ public:
void addCodeSnippet(
uint startLineNumber,
const std::string& title,
const std::string& code,
const TokenLocationFile& locationFile
std::shared_ptr<TokenLocationFile> locationFile
);
void update();
+5 -4
View File
@@ -36,10 +36,11 @@ QSize QtCodeFileList::sizeHint() const
void QtCodeFileList::addCodeSnippet(
uint startLineNumber,
const std::string& title,
const std::string& code,
const TokenLocationFile& locationFile
std::shared_ptr<TokenLocationFile> locationFile
){
FilePath filePath = locationFile.getFilePath();
FilePath filePath = locationFile->getFilePath();
QtCodeFile* file = nullptr;
for (std::shared_ptr<QtCodeFile> filePtr : m_files)
@@ -53,14 +54,14 @@ void QtCodeFileList::addCodeSnippet(
if (!file)
{
std::shared_ptr<QtCodeFile> filePtr = std::make_shared<QtCodeFile>(locationFile.getFilePath(), this);
std::shared_ptr<QtCodeFile> filePtr = std::make_shared<QtCodeFile>(locationFile->getFilePath(), this);
m_files.push_back(filePtr);
file = filePtr.get();
m_frame->layout()->addWidget(file);
}
file->addCodeSnippet(startLineNumber, code, locationFile);
file->addCodeSnippet(startLineNumber, title, code, locationFile);
}
void QtCodeFileList::clearCodeSnippets()
+2 -1
View File
@@ -24,8 +24,9 @@ public:
void addCodeSnippet(
uint startLineNumber,
const std::string& title,
const std::string& code,
const TokenLocationFile& locationFile
std::shared_ptr<TokenLocationFile> locationFile
);
void clearCodeSnippets();
+20 -427
View File
@@ -1,466 +1,59 @@
#include "qt/element/QtCodeSnippet.h"
#include <QFont>
#include <QHBoxLayout>
#include <QPainter>
#include <QPushButton>
#include <QToolTip>
#include "utility/messaging/type/MessageActivateTokenLocation.h"
#include "utility/messaging/type/MessageShowFile.h"
#include "data/location/TokenLocation.h"
#include "data/location/TokenLocationFile.h"
#include "qt/element/QtCodeFile.h"
#include "qt/utility/QtHighlighter.h"
#include "settings/ApplicationSettings.h"
QtCodeSnippet::LineNumberArea::LineNumberArea(QtCodeSnippet *codeSnippet)
: QWidget(codeSnippet)
, m_codeSnippet(codeSnippet)
{
setObjectName("line_number_area");
}
QtCodeSnippet::LineNumberArea::~LineNumberArea()
{
}
QSize QtCodeSnippet::LineNumberArea::sizeHint() const
{
return QSize(m_codeSnippet->lineNumberAreaWidth(), 0);
}
void QtCodeSnippet::LineNumberArea::paintEvent(QPaintEvent *event)
{
m_codeSnippet->lineNumberAreaPaintEvent(event);
}
QtCodeSnippet::QtCodeSnippet(
uint startLineNumber,
const std::string& title,
const std::string& code,
const TokenLocationFile& locationFile,
std::shared_ptr<TokenLocationFile> locationFile,
QtCodeFile* parent
)
: QPlainTextEdit(parent)
: QWidget(parent)
, m_parent(parent)
, m_maximizeButton(nullptr)
, m_startLineNumber(startLineNumber)
, m_hoveredAnnotation(nullptr)
, m_digits(0)
, m_codeArea(std::make_shared<QtCodeArea>(startLineNumber, code, locationFile, parent))
{
setObjectName("code_snippet");
setReadOnly(true);
setFrameStyle(QFrame::NoFrame);
setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setLineWrapMode(QPlainTextEdit::NoWrap);
m_lineNumberArea = new LineNumberArea(this);
m_highlighter = new QtHighlighter(document());
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->setSpacing(0);
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
std::string displayCode = code;
if (*code.rbegin() == '\n')
{
displayCode.pop_back();
}
m_title = new QPushButton(title.c_str(), this);
m_title->setObjectName("title_label");
m_title->minimumSizeHint(); // force font loading
m_title->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
m_title->setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed);
layout->addWidget(m_title);
setPlainText(QString::fromUtf8(displayCode.c_str()));
createAnnotations(locationFile);
annotateText();
m_digits = lineNumberDigits();
updateLineNumberAreaWidth(0);
connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int)));
connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int)));
connect(this, SIGNAL(selectionChanged()), this, SLOT(clearSelection()));
this->setMouseTracking(true);
layout->addWidget(m_codeArea.get());
}
QtCodeSnippet::~QtCodeSnippet()
{
}
QSize QtCodeSnippet::sizeHint() const
{
int width = 480;
int height = (document()->size().height() + 0.7f) * fontMetrics().lineSpacing();
return QSize(width, height);
}
void QtCodeSnippet::addMaximizeButton()
{
QHBoxLayout* layout = new QHBoxLayout();
layout->setMargin(0);
layout->setSpacing(0);
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
m_maximizeButton = new QPushButton(this);
m_maximizeButton->setObjectName("maximize_button");
m_maximizeButton->setEnabled(false);
layout->addWidget(m_maximizeButton);
layout->setAlignment(m_maximizeButton, Qt::AlignRight);
connect(m_maximizeButton, SIGNAL(clicked()), this, SLOT(clickedMaximizeButton()));
}
void QtCodeSnippet::lineNumberAreaPaintEvent(QPaintEvent *event)
{
QPainter painter(m_lineNumberArea);
QTextBlock block = firstVisibleBlock();
int blockNumber = block.blockNumber();
int top = static_cast<int>(blockBoundingGeometry(block).translated(contentOffset()).top());
int bottom = top + static_cast<int>(blockBoundingRect(block).height());
while (block.isValid() && top <= event->rect().bottom())
{
if (block.isVisible() && bottom >= event->rect().top())
{
QString number = QString::number(blockNumber + m_startLineNumber);
painter.setPen(Qt::black);
painter.drawText(0, top, m_lineNumberArea->width() - 13, fontMetrics().height(), Qt::AlignRight, number);
}
block = block.next();
top = bottom;
bottom = top + static_cast<int>(blockBoundingRect(block).height());
blockNumber++;
}
m_codeArea->addMaximizeButton();
}
int QtCodeSnippet::lineNumberDigits() const
{
int digits = 1;
int max = qMax(1, int(m_startLineNumber) + blockCount());
while (max >= 10)
{
max /= 10;
digits++;
}
return digits;
}
int QtCodeSnippet::lineNumberAreaWidth() const
{
return fontMetrics().width(QLatin1Char('9')) * m_digits + 30;
return m_codeArea->lineNumberDigits();
}
void QtCodeSnippet::updateLineNumberAreaWidthForDigits(int digits)
{
m_digits = digits;
updateLineNumberAreaWidth(0);
m_codeArea->updateLineNumberAreaWidthForDigits(digits);
}
void QtCodeSnippet::update()
{
annotateText();
}
void QtCodeSnippet::resizeEvent(QResizeEvent *e)
{
QPlainTextEdit::resizeEvent(e);
QRect cr = contentsRect();
m_lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}
void QtCodeSnippet::showEvent(QShowEvent* event)
{
int tabWidth = ApplicationSettings::getInstance()->getCodeTabWidth();
setTabStopWidth(tabWidth * fontMetrics().width('9'));
setMaximumHeight(sizeHint().height());
}
void QtCodeSnippet::enterEvent(QEvent* event)
{
if (m_maximizeButton)
{
m_maximizeButton->setEnabled(true);
}
}
void QtCodeSnippet::leaveEvent(QEvent* event)
{
if (m_maximizeButton)
{
m_maximizeButton->setEnabled(false);
}
m_hoveredAnnotation = nullptr;
annotateText();
}
void QtCodeSnippet::mouseReleaseEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
QTextCursor cursor = this->cursorForPosition(event->pos());
const Annotation* annotation = findAnnotationForPosition(cursor.position());
if (annotation)
{
MessageActivateTokenLocation(annotation->locationId).dispatch();
}
}
}
void QtCodeSnippet::mouseDoubleClickEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton && m_maximizeButton)
{
clickedMaximizeButton();
}
}
void QtCodeSnippet::mouseMoveEvent(QMouseEvent* event)
{
QTextCursor cursor = this->cursorForPosition(event->pos());
const Annotation* annotation = findAnnotationForPosition(cursor.position());
if (annotation && annotation->isScope)
{
annotation = nullptr;
}
if (annotation != m_hoveredAnnotation)
{
m_hoveredAnnotation = annotation;
const std::vector<std::string>& errorMessages = m_parent->getErrorMessages();
if (annotation && errorMessages.size() > annotation->tokenId)
{
QToolTip::showText(event->globalPos(), QString::fromStdString(m_parent->getErrorMessages()[annotation->tokenId]));
}
else
{
QToolTip::hideText();
}
annotateText();
}
}
void QtCodeSnippet::updateLineNumberAreaWidth(int /* newBlockCount */)
{
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}
void QtCodeSnippet::updateLineNumberArea(const QRect &rect, int dy)
{
if (dy)
{
m_lineNumberArea->scroll(0, dy);
}
else
{
m_lineNumberArea->update(0, rect.y(), m_lineNumberArea->width(), rect.height());
}
if (rect.contains(viewport()->rect()))
{
updateLineNumberAreaWidth(0);
}
}
void QtCodeSnippet::clickedMaximizeButton()
{
MessageShowFile(m_parent->getFilePath().absoluteStr(), m_startLineNumber, m_startLineNumber + blockCount() - 1).dispatch();
}
void QtCodeSnippet::clearSelection()
{
QTextCursor cursor = textCursor();
cursor.clearSelection();
setTextCursor(cursor);
}
const QtCodeSnippet::Annotation* QtCodeSnippet::findAnnotationForPosition(int pos) const
{
const Annotation* annotationPtr = nullptr;
int diff = endTextEditPosition() + 1;
for (const Annotation& annotation : m_annotations)
{
if (pos >= annotation.start && pos <= annotation.end)
{
int d = annotation.end - annotation.start;
if (d < diff)
{
diff = d;
annotationPtr = &annotation;
}
}
}
return annotationPtr;
}
void QtCodeSnippet::createAnnotations(const TokenLocationFile& locationFile)
{
locationFile.forEachTokenLocation(
[&](TokenLocation* location)
{
if (!locationBelongsToSnippet(location))
{
return;
}
Annotation annotation;
if (location->isStartTokenLocation() && location->getLineNumber() >= m_startLineNumber)
{
annotation.start = toTextEditPosition(location->getLineNumber(), location->getColumnNumber() - 1);
}
else
{
annotation.start = startTextEditPosition();
}
TokenLocation* endLocation = location->getEndTokenLocation();
if (endLocation)
{
annotation.end = toTextEditPosition(endLocation->getLineNumber(), endLocation->getColumnNumber());
}
else
{
annotation.end = endTextEditPosition();
}
annotation.tokenId = location->getTokenId();
annotation.locationId = location->getId();
annotation.isScope = location->getType() == TokenLocation::LOCATION_SCOPE;
m_annotations.push_back(annotation);
}
);
}
void QtCodeSnippet::annotateText()
{
Colori color;
const std::vector<Id>& ids = m_parent->getActiveTokenIds();
const std::vector<std::string>& errorMessages = m_parent->getErrorMessages();
QList<QTextEdit::ExtraSelection> extraSelections;
for (const Annotation& annotation: m_annotations)
{
bool isActive = std::find(ids.begin(), ids.end(), annotation.tokenId) != ids.end();
if (&annotation == m_hoveredAnnotation && errorMessages.size())
{
color = Colori(255, 0, 0, 128);
}
else if (&annotation == m_hoveredAnnotation)
{
color = ApplicationSettings::getInstance()->getCodeActiveLinkColor();
}
else if (errorMessages.size())
{
color = Colori(255, 0, 0, 255);
}
else if (isActive)
{
color = ApplicationSettings::getInstance()->getCodeActiveLinkColor();
if (annotation.isScope)
{
color.a /= 2;
}
}
else if (annotation.isScope)
{
color = ApplicationSettings::getInstance()->getCodeScopeColor();
}
else
{
color = ApplicationSettings::getInstance()->getCodeLinkColor();
}
QTextEdit::ExtraSelection selection;
selection.format.setBackground(QColor(color.r, color.g, color.b, color.a));
selection.cursor = textCursor();
selection.cursor.clearSelection();
selection.cursor.setPosition(annotation.start);
selection.cursor.setPosition(annotation.end, QTextCursor::KeepAnchor);
extraSelections.append(selection);
}
setExtraSelections(extraSelections);
}
bool QtCodeSnippet::locationBelongsToSnippet(TokenLocation* location) const
{
uint lineNumber = location->getLineNumber();
if (location->isEndTokenLocation())
{
if (location->getStartTokenLocation() ||
lineNumber < m_startLineNumber || lineNumber >= m_startLineNumber + blockCount())
{
return false;
}
else
{
return true;
}
}
if (lineNumber >= m_startLineNumber + blockCount())
{
return false;
}
if (lineNumber >= m_startLineNumber)
{
return true;
}
TokenLocation* endLocation = location->getEndTokenLocation();
if (endLocation && endLocation->getLineNumber() < m_startLineNumber)
{
return false;
}
return true;
}
int QtCodeSnippet::toTextEditPosition(int lineNumber, int columnNumber) const
{
lineNumber -= m_startLineNumber - 1;
int position = 0;
for (int i = 0; i < lineNumber - 1; i++)
{
position += document()->findBlockByLineNumber(i).length();
}
position += columnNumber;
return position;
}
int QtCodeSnippet::startTextEditPosition() const
{
return 0;
}
int QtCodeSnippet::endTextEditPosition() const
{
int position = 0;
for (int i = 0; i < document()->blockCount(); i++)
{
position += document()->findBlockByLineNumber(i).length();
}
return position - 1;
m_codeArea->update();
}
+9 -76
View File
@@ -2,108 +2,41 @@
#define QT_CODE_SNIPPET_H
#include <vector>
#include <QPlainTextEdit>
#include <memory>
#include "utility/types.h"
#include "qt/element/QtCodeArea.h"
class QPaintEvent;
class QPushButton;
class QResizeEvent;
class QSize;
class QtCodeFile;
class QtHighlighter;
class QWidget;
class TokenLocation;
class TokenLocationFile;
class QtCodeSnippet: public QPlainTextEdit
class QtCodeSnippet: public QWidget
{
Q_OBJECT
public:
class LineNumberArea: public QWidget
{
public:
LineNumberArea(QtCodeSnippet *codeSnippet);
virtual ~LineNumberArea();
QSize sizeHint() const;
protected:
void paintEvent(QPaintEvent* event);
private:
QtCodeSnippet *m_codeSnippet;
};
QtCodeSnippet(
uint startLineNumber,
const std::string& title,
const std::string& code,
const TokenLocationFile& locationFile,
std::shared_ptr<TokenLocationFile> locationFile,
QtCodeFile* parent
);
virtual ~QtCodeSnippet();
QSize sizeHint() const;
void addMaximizeButton();
void lineNumberAreaPaintEvent(QPaintEvent *event);
int lineNumberDigits() const;
int lineNumberAreaWidth() const;
void updateLineNumberAreaWidthForDigits(int digits);
void updateLineNumberAreaWidthForDigits(int digits);
void update();
protected:
virtual void resizeEvent(QResizeEvent *event);
virtual void showEvent(QShowEvent* event);
virtual void enterEvent(QEvent* event);
virtual void leaveEvent(QEvent* event);
virtual void mouseReleaseEvent(QMouseEvent* event);
virtual void mouseDoubleClickEvent(QMouseEvent* event);
virtual void mouseMoveEvent(QMouseEvent* event);
private slots:
void updateLineNumberAreaWidth(int newBlockCount);
void updateLineNumberArea(const QRect &, int);
void clickedMaximizeButton();
void clearSelection();
private:
struct Annotation
{
int start;
int end;
Id tokenId;
Id locationId;
bool isScope;
};
const Annotation* findAnnotationForPosition(int pos) const;
void createAnnotations(const TokenLocationFile& locationFile);
void annotateText();
bool locationBelongsToSnippet(TokenLocation* location) const;
int toTextEditPosition(int lineNumber, int columnNumber) const;
int startTextEditPosition() const;
int endTextEditPosition() const;
QtCodeFile* m_parent;
QWidget* m_lineNumberArea;
QtHighlighter* m_highlighter;
QPushButton* m_maximizeButton;
const uint m_startLineNumber;
std::vector<Annotation> m_annotations;
const Annotation* m_hoveredAnnotation;
int m_digits;
QtCodeFile* m_parent; // need this?
QPushButton* m_title;
std::shared_ptr<QtCodeArea> m_codeArea;
};
#endif // QT_CODE_SNIPPET_H
+3 -3
View File
@@ -90,7 +90,7 @@ void QtCodeView::doShowCodeSnippets(const std::vector<CodeSnippetParams>& snippe
for (const CodeSnippetParams& params : snippets)
{
m_widget->addCodeSnippet(params.startLineNumber, params.code, params.locationFile);
m_widget->addCodeSnippet(params.startLineNumber, params.title, params.code, params.locationFile);
}
}
@@ -102,9 +102,9 @@ void QtCodeView::doShowCodeFile(const CodeSnippetParams& params)
ptr->setShowMaximizeButton(false);
ptr->setActiveTokenIds(m_activeTokenIds);
ptr->setErrorMessages(m_errorMessages);
ptr->addCodeSnippet(1, params.code, params.locationFile);
ptr->addCodeSnippet(1, params.title, params.code, params.locationFile);
ptr->setWindowTitle(params.locationFile.getFilePath().fileName().c_str());
ptr->setWindowTitle(params.locationFile->getFilePath().fileName().c_str());
ptr->show();
float percent = float(params.startLineNumber + params.endLineNumber) / float(params.lineCount) / 2;