build: trial version target

builds now app and trail target, lib_gui added, istrail function
This commit is contained in:
Andreas Stallinger
2015-12-08 17:55:12 +01:00
parent ed4b6546f0
commit 43409cd6b7
154 changed files with 444 additions and 213 deletions
@@ -0,0 +1,249 @@
#include "qt/element/QtAutocompletionList.h"
#include <QPainter>
#include <QScrollBar>
#include "component/view/GraphViewStyle.h"
#include "settings/ApplicationSettings.h"
#include "settings/ColorScheme.h"
QtAutocompletionModel::QtAutocompletionModel(QObject* parent)
: QAbstractTableModel(parent)
{
}
QtAutocompletionModel::~QtAutocompletionModel()
{
}
void QtAutocompletionModel::setMatchList(const std::vector<SearchMatch>& matchList)
{
m_matchList = matchList;
}
int QtAutocompletionModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_matchList.size();
}
int QtAutocompletionModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 4;
}
QVariant QtAutocompletionModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= int(m_matchList.size()) || role != Qt::DisplayRole)
{
return QVariant();
}
const SearchMatch& match = m_matchList[index.row()];
switch (index.column())
{
case 0:
return QString::fromStdString(match.getFullName());
case 1:
return QString::fromStdString(match.typeName);
case 2:
{
QList<QVariant> indices;
for (const size_t idx : match.indices)
{
indices.push_back(quint64(idx));
}
return indices;
}
case 3:
return match.nodeType;
default:
return QVariant();
}
}
const SearchMatch* QtAutocompletionModel::getSearchMatchAt(int idx) const
{
if (idx >= 0 && size_t(idx) < m_matchList.size())
{
return &m_matchList[idx];
}
return nullptr;
}
QtAutocompletionDelegate::QtAutocompletionDelegate(QObject* parent)
: QStyledItemDelegate(parent)
{
}
QtAutocompletionDelegate::~QtAutocompletionDelegate()
{
}
void QtAutocompletionDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
painter->save();
ColorScheme* scheme = ColorScheme::getInstance().get();
if (option.state & QStyle::State_Selected)
{
painter->fillRect(option.rect, option.palette.color(QPalette::Highlight));
}
else
{
painter->fillRect(option.rect, option.palette.color(QPalette::Base));
}
QString name = index.data().toString();
float charWidth = option.fontMetrics.width("FontWidth") / 9.0f;
QString type = index.sibling(index.row(), index.column() + 1).data().toString();
QColor color("#FFFFFF");
Node::NodeType nodeType = static_cast<Node::NodeType>(index.sibling(index.row(), index.column() + 3).data().toInt());
if (type.size())
{
color = QColor(GraphViewStyle::getNodeColor(Node::getTypeString(nodeType), false).fill.c_str());
}
else
{
color = QColor(scheme->getSearchTypeColor(SearchMatch::getSearchTypeName(SearchMatch::SEARCH_COMMAND)).c_str());
}
QList<QVariant> indices = index.sibling(index.row(), index.column() + 2).data().toList();
if (indices.size())
{
int idx = 0;
float x = charWidth + 2;
for (int i = 0; i < name.size(); i++)
{
if (idx < indices.size() && i == indices[idx])
{
QRect rect = option.rect.adjusted(x, 2, 0, -1);
rect.setWidth(charWidth + 1);
painter->fillRect(rect, color);
idx++;
}
x += charWidth;
}
}
else
{
QRect rect = option.rect.adjusted(0, 2, 0, -1);
rect.setWidth(charWidth - 1);
painter->fillRect(rect, color);
}
painter->drawText(option.rect.adjusted(charWidth + 2, -1, 0, 0), Qt::AlignLeft, name);
if (type.size())
{
QFont font = painter->font();
if (font.pointSize() > 0)
{
QFont typeFont = font;
typeFont.setPointSize(ApplicationSettings::getInstance()->getFontSize() - 4);
painter->setFont(typeFont);
}
QPen typePen = painter->pen();
typePen.setColor(scheme->getColor("search/popup/by_text").c_str());
painter->setPen(typePen);
painter->drawText(option.rect.adjusted(0, 3, -charWidth, 0), Qt::AlignRight, type);
}
painter->restore();
}
QSize QtAutocompletionDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
QString name = index.data().toString();
QString type = index.sibling(index.row(), index.column() + 1).data().toString();
return QSize( option.fontMetrics.width(name+type)+5, option.fontMetrics.height());
}
QtAutocompletionList::QtAutocompletionList(QWidget* parent)
: QCompleter(parent)
{
m_model = std::make_shared<QtAutocompletionModel>(this);
setModel(m_model.get());
m_delegate = std::make_shared<QtAutocompletionDelegate>(this);
QListView* list = new QListView(parent);
list->setItemDelegateForColumn(0, m_delegate.get());
list->setObjectName("search_box_popup");
list->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
list->setUniformItemSizes(true);
setPopup(list);
setCaseSensitivity(Qt::CaseInsensitive);
// setCompletionMode(QCompleter::UnfilteredPopupCompletion);
}
QtAutocompletionList::~QtAutocompletionList()
{
}
void QtAutocompletionList::completeAt(const QPoint& pos, const std::vector<SearchMatch>& autocompletionList)
{
m_model->setMatchList(autocompletionList);
QSize minSize(400, 253);
QListView* list = dynamic_cast<QListView*>(popup());
if (!autocompletionList.size())
{
list->hide();
return;
}
setCompletionPrefix("");
const QModelIndex& index = completionModel()->index(0, 0);
list->setCurrentIndex(index);
QRect rect = list->visualRect(index);
minSize.setHeight(std::min(minSize.height(), m_model->rowCount(index) * rect.height() + 16));
list->setMinimumSize(minSize);
list->verticalScrollBar()->setValue(list->verticalScrollBar()->minimum());
disconnect(); // must be done because of a bug where signals are no longer received by QtSmartSearchBox
connect(this, SIGNAL(highlighted(const QModelIndex&)), this, SLOT(onHighlighted(const QModelIndex&)), Qt::DirectConnection);
connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(onActivated(const QModelIndex&)), Qt::DirectConnection);
QWidget* textBox = dynamic_cast<QWidget*>(parent());
complete(QRect(pos.x(), pos.y(), textBox->width(), 1));
}
const SearchMatch* QtAutocompletionList::getSearchMatchAt(int idx) const
{
return m_model->getSearchMatchAt(idx);
}
void QtAutocompletionList::onHighlighted(const QModelIndex& index)
{
const SearchMatch* match = getSearchMatchAt(index.row());
if (match)
{
emit matchHighlighted(*match);
}
}
void QtAutocompletionList::onActivated(const QModelIndex& index)
{
const SearchMatch* match = getSearchMatchAt(index.row());
if (match)
{
emit matchActivated(*match);
}
}
@@ -0,0 +1,75 @@
#ifndef QT_AUTOCOMPLETION_LIST
#define QT_AUTOCOMPLETION_LIST
#include <memory>
#include <vector>
#include <QAbstractTableModel>
#include <QCompleter>
#include <QStyledItemDelegate>
#include <QListView>
#include "data/search/SearchMatch.h"
class QtAutocompletionModel
: public QAbstractTableModel
{
Q_OBJECT
public:
QtAutocompletionModel(QObject* parent = 0);
virtual ~QtAutocompletionModel();
void setMatchList(const std::vector<SearchMatch>& matchList);
virtual int rowCount(const QModelIndex& parent) const;
virtual int columnCount(const QModelIndex& parent) const;
virtual QVariant data(const QModelIndex& index, int role) const;
const SearchMatch* getSearchMatchAt(int idx) const;
private:
std::vector<SearchMatch> m_matchList;
};
class QtAutocompletionDelegate
: public QStyledItemDelegate
{
public:
explicit QtAutocompletionDelegate(QObject* parent = 0);
virtual ~QtAutocompletionDelegate();
virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
virtual QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const;
};
class QtAutocompletionList
: public QCompleter
{
Q_OBJECT
signals:
void matchHighlighted(const SearchMatch&);
void matchActivated(const SearchMatch&);
public:
QtAutocompletionList(QWidget* parent = 0);
virtual ~QtAutocompletionList();
void completeAt(const QPoint& pos, const std::vector<SearchMatch>& autocompletionList);
const SearchMatch* getSearchMatchAt(int idx) const;
private slots:
void onHighlighted(const QModelIndex& index);
void onActivated(const QModelIndex& index);
private:
std::shared_ptr<QtAutocompletionModel> m_model;
std::shared_ptr<QtAutocompletionDelegate> m_delegate;
};
#endif // QT_AUTOCOMPLETION_LIST
+814
View File
@@ -0,0 +1,814 @@
#include "qt/element/QtCodeArea.h"
#include <qapplication.h>
#include <QFont>
#include <QHBoxLayout>
#include <qmenu.h>
#include <QPainter>
#include <QPushButton>
#include <QToolTip>
#include <qscrollbar.h>
#include "utility/messaging/type/MessageActivateTokenLocations.h"
#include "utility/messaging/type/MessageShowFile.h"
#include "utility/messaging/type/MessageFocusIn.h"
#include "utility/messaging/type/MessageFocusOut.h"
#include "utility/messaging/type/MessageMoveIDECursor.h"
#include "utility/utility.h"
#include "data/location/TokenLocation.h"
#include "data/location/TokenLocationFile.h"
#include "qt/element/QtCodeFile.h"
#include "qt/element/QtCodeSnippet.h"
#include "qt/utility/QtHighlighter.h"
#include "settings/ApplicationSettings.h"
#include "settings/ColorScheme.h"
std::vector<QtCodeArea::AnnotationColor> QtCodeArea::s_annotationColors;
MouseWheelOverScrollbarFilter::MouseWheelOverScrollbarFilter(QObject* parent)
: QObject(parent)
{
}
bool MouseWheelOverScrollbarFilter::eventFilter(QObject* obj, QEvent* event)
{
QScrollBar* scrollbar = dynamic_cast<QScrollBar*>(obj);
if (event->type() == QEvent::Wheel && scrollbar)
{
QRect scrollbarArea(scrollbar->pos(), scrollbar->size());
QPoint globalMousePos = dynamic_cast<QWheelEvent*>(event)->globalPos();
QPoint localMousePos = scrollbar->mapFromGlobal(globalMousePos);
// instead of "scrollbar->underMouse()" we need this check implemented here because "underMouse()"
// does not work when the mouse enters the area without being moved
if (scrollbarArea.contains(localMousePos))
{
event->ignore();
return true;
}
}
return QObject::eventFilter(obj, event);
}
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);
}
void QtCodeArea::clearAnnotationColors()
{
s_annotationColors.clear();
}
QtCodeArea::QtCodeArea(
uint startLineNumber,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
QtCodeFile* file,
QtCodeSnippet* parent
)
: QPlainTextEdit(parent)
, m_fileWidget(file)
, m_startLineNumber(startLineNumber)
, m_code(code)
, m_locationFile(locationFile)
, m_digits(0)
, m_panningValue(-1)
, m_setIDECursorPositionAction(nullptr)
, m_eventPosition(0, 0)
, m_isActiveFile(false)
{
setObjectName("code_area");
setReadOnly(true);
setFrameStyle(QFrame::NoFrame);
setLineWrapMode(QPlainTextEdit::NoWrap);
setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed);
m_lineNumberArea = new LineNumberArea(this);
m_highlighter = new QtHighlighter(document());
std::string displayCode = m_code;
if (*displayCode.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);
// MouseWheelOverScrollbarFilter is deleted by parent.
horizontalScrollBar()->installEventFilter(new MouseWheelOverScrollbarFilter(this));
createActions();
}
QtCodeArea::~QtCodeArea()
{
if (m_setIDECursorPositionAction != nullptr)
{
m_setIDECursorPositionAction->disconnect();
delete m_setIDECursorPositionAction;
}
}
QSize QtCodeArea::sizeHint() const
{
QTextBlock block = firstVisibleBlock();
float height = blockBoundingGeometry(block).translated(contentOffset()).top();
while (block.isValid())
{
height += blockBoundingRect(block).height();
block = block.next();
}
if (horizontalScrollBar()->isVisible())
{
height += horizontalScrollBar()->height();
}
return QSize(320, height + 1);
}
uint QtCodeArea::getStartLineNumber() const
{
return m_startLineNumber;
}
uint QtCodeArea::getEndLineNumber() const
{
return m_startLineNumber + blockCount() - 1;
}
std::shared_ptr<TokenLocationFile> QtCodeArea::getTokenLocationFile() const
{
return m_locationFile;
}
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());
std::set<int> activeLineNumbers = getActiveLineNumbers();
ColorScheme* scheme = ColorScheme::getInstance().get();
QColor backgroundColor(scheme->getColor("code/snippet/line_number/background").c_str());
backgroundColor.setAlpha(150);
while (block.isValid() && top <= event->rect().bottom())
{
if (block.isVisible() && bottom >= event->rect().top())
{
int number = blockNumber + m_startLineNumber;
painter.drawText(0, top, m_lineNumberArea->width() - 13, fontMetrics().height(), Qt::AlignRight, QString::number(number));
if (!m_isActiveFile && activeLineNumbers.find(number) == activeLineNumbers.end())
{
painter.fillRect(0, top, m_lineNumberArea->width(), fontMetrics().height(), backgroundColor);
}
}
block = block.next();
top = bottom;
bottom = top + static_cast<int>(blockBoundingRect(block).height());
blockNumber++;
}
}
int QtCodeArea::lineNumberDigits() const
{
int max = qMax(1, int(m_startLineNumber) + blockCount());
return utility::digits(max);
}
int QtCodeArea::lineNumberAreaWidth() const
{
return fontMetrics().width(QLatin1Char('9')) * m_digits + 30;
}
void QtCodeArea::updateLineNumberAreaWidthForDigits(int digits)
{
m_digits = digits;
updateLineNumberAreaWidth(0);
}
void QtCodeArea::updateContent()
{
annotateText();
}
bool QtCodeArea::isActive() const
{
const std::vector<Id>& ids = m_fileWidget->getActiveTokenIds();
for (const Annotation& annotation: m_annotations)
{
if (std::find(ids.begin(), ids.end(), annotation.tokenId) != ids.end())
{
return true;
}
}
return false;
}
void QtCodeArea::setIsActiveFile(bool isActiveFile)
{
m_isActiveFile = isActiveFile;
}
QRectF QtCodeArea::getFirstActiveLineRect() const
{
int lineNumber = 0;
for (const Annotation& annotation : m_annotations)
{
if (annotation.isActive)
{
lineNumber = annotation.startLine;
break;
}
}
QTextBlock block = document()->findBlockByLineNumber(lineNumber - m_startLineNumber);
return blockBoundingGeometry(block);
}
std::string QtCodeArea::getCode() const
{
return m_code;
}
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'));
setFixedHeight(sizeHint().height());
}
void QtCodeArea::paintEvent(QPaintEvent* event)
{
QPainter painter(viewport());
QTextBlock block = firstVisibleBlock();
int top = blockBoundingGeometry(block).translated(contentOffset()).top();
int blockHeight = blockBoundingRect(block).height();
int borderRadius = 3;
for (const Annotation& annotation : m_annotations)
{
const AnnotationColor& color = getAnnotationColorForAnnotation(annotation);
painter.setPen(QPen(color.border.c_str()));
painter.setBrush(QBrush(color.fill.c_str()));
if (annotation.isScope)
{
painter.drawRoundedRect(
0, top + (annotation.startLine - m_startLineNumber) * blockHeight,
width(), (annotation.endLine - annotation.startLine + 1) * blockHeight,
borderRadius, borderRadius
);
}
else
{
std::vector<QRect> rects = getCursorRectsForAnnotation(annotation);
for (QRect rect : rects)
{
rect.adjust(-1, 0, 1, 1);
painter.drawRoundedRect(rect, borderRadius, borderRadius);
}
}
}
QPlainTextEdit::paintEvent(event);
QPainter painter2(viewport());
std::set<int> activeLineNumbers = getActiveLineNumbers();
ColorScheme* scheme = ColorScheme::getInstance().get();
QColor backgroundColor(scheme->getColor("code/snippet/background").c_str());
backgroundColor.setAlpha(75);
for (int i = 0; i < document()->blockCount(); i++)
{
if (!m_isActiveFile && activeLineNumbers.find(i + m_startLineNumber) == activeLineNumbers.end())
{
painter.fillRect(0, top + i * blockHeight, width(), blockHeight, backgroundColor);
}
}
}
void QtCodeArea::enterEvent(QEvent* event)
{
}
void QtCodeArea::leaveEvent(QEvent* event)
{
setHoveredAnnotations(std::vector<const Annotation*>());
}
void QtCodeArea::mousePressEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
m_panningValue = event->pos().x();
}
}
void QtCodeArea::mouseReleaseEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
m_panningValue = -1;
if (Qt::KeyboardModifier::ControlModifier && QApplication::keyboardModifiers())
{
// std::pair<int, int> lineColumn = toLineColumn(this->cursorForPosition(event->pos()).position());
m_eventPosition = event->pos();
setIDECursorPosition();
}
else
{
QTextCursor cursor = this->cursorForPosition(event->pos());
std::vector<Id> locationIds = findLocationIdsForPosition(cursor.position());
if (locationIds.size() && !m_fileWidget->getErrorMessages().size())
{
MessageActivateTokenLocations(locationIds).dispatch();
}
}
}
}
void QtCodeArea::mouseDoubleClickEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
MessageShowFile(m_fileWidget->getFilePath().str(), (m_fileWidget->getErrorMessages().size() > 0)).dispatch();
}
}
void QtCodeArea::mouseMoveEvent(QMouseEvent* event)
{
if (m_panningValue != -1)
{
int panningCurrentPosition = event->pos().x();
int deltaPos = panningCurrentPosition - m_panningValue;
m_panningValue = panningCurrentPosition;
QScrollBar* scrollbar = horizontalScrollBar();
int visibleContentWidth = width() - lineNumberAreaWidth();
float deltaPosRatio = float(deltaPos) / (visibleContentWidth);
scrollbar->setValue(scrollbar->value() - utility::roundToInt(deltaPosRatio * scrollbar->pageStep()));
}
QTextCursor cursor = this->cursorForPosition(event->pos());
std::vector<const Annotation*> annotations = getAnnotationsForPosition(cursor.position());
bool same = annotations.size() == m_hoveredAnnotations.size();
if (same)
{
for (size_t i = 0; i < annotations.size(); i++)
{
if (annotations[i] != m_hoveredAnnotations[i])
{
same = false;
break;
}
}
}
QToolTip::hideText();
if (!same)
{
setHoveredAnnotations(annotations);
const std::vector<std::string>& errorMessages = m_fileWidget->getErrorMessages();
if (annotations.size() == 1 && errorMessages.size() > annotations[0]->tokenId)
{
QToolTip::showText(event->globalPos(), QString::fromStdString(errorMessages[annotations[0]->tokenId]));
}
}
}
void QtCodeArea::contextMenuEvent(QContextMenuEvent* event)
{
if (m_setIDECursorPositionAction != nullptr)
{
m_eventPosition = event->pos();
QMenu menu(this);
menu.addAction(m_setIDECursorPositionAction);
menu.exec(event->globalPos());
}
}
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::clearSelection()
{
QTextCursor cursor = textCursor();
cursor.clearSelection();
setTextCursor(cursor);
}
void QtCodeArea::setIDECursorPosition()
{
std::pair<int, int> lineColumn = toLineColumn(this->cursorForPosition(m_eventPosition).position());
MessageMoveIDECursor(m_locationFile->getFilePath().str(), lineColumn.first, lineColumn.second).dispatch();
}
std::vector<Id> QtCodeArea::findLocationIdsForPosition(int pos) const
{
std::vector<Id> locationIds;
for (const Annotation& annotation : m_annotations)
{
if (!annotation.isScope && pos >= annotation.start && pos <= annotation.end)
{
locationIds.push_back(annotation.locationId);
}
}
return locationIds;
}
std::vector<const QtCodeArea::Annotation*> QtCodeArea::getAnnotationsForPosition(int pos) const
{
std::vector<const QtCodeArea::Annotation*> annotations;
for (const Annotation& annotation : m_annotations)
{
if (!annotation.isScope && pos >= annotation.start && pos <= annotation.end)
{
annotations.push_back(&annotation);
}
}
return annotations;
}
void QtCodeArea::createAnnotations(std::shared_ptr<TokenLocationFile> locationFile)
{
locationFile->forEachStartTokenLocation(
[&](TokenLocation* startLocation)
{
Annotation annotation;
uint endLineNumber = getEndLineNumber();
if (startLocation->getLineNumber() <= endLineNumber)
{
if (startLocation->getLineNumber() < m_startLineNumber)
{
annotation.start = startTextEditPosition();
annotation.startLine = m_startLineNumber;
annotation.startCol = 0;
}
else
{
annotation.start = toTextEditPosition(startLocation->getLineNumber(), startLocation->getColumnNumber() - 1);
annotation.startLine = startLocation->getLineNumber();
annotation.startCol = startLocation->getColumnNumber() - 1;
}
}
else
{
return;
}
TokenLocation* endLocation = startLocation->getEndTokenLocation();
if (endLocation->getLineNumber() >= m_startLineNumber)
{
if (endLocation->getLineNumber() > endLineNumber)
{
annotation.end = endTextEditPosition();
annotation.endLine = endLineNumber;
annotation.endCol = document()->findBlockByLineNumber(document()->blockCount() - 1).length();
}
else
{
annotation.end = toTextEditPosition(endLocation->getLineNumber(), endLocation->getColumnNumber());
annotation.endLine = endLocation->getLineNumber();
annotation.endCol = endLocation->getColumnNumber();
}
}
else
{
return;
}
annotation.tokenId = startLocation->getTokenId();
annotation.locationId = startLocation->getId();
annotation.isScope = (startLocation->getType() == TokenLocation::LOCATION_SCOPE);
annotation.isError = false;
annotation.isActive = false;
annotation.isFocused = false;
m_annotations.push_back(annotation);
}
);
}
void QtCodeArea::annotateText()
{
const std::vector<Id>& activeIds = m_fileWidget->getActiveTokenIds();
const std::vector<Id>& focusIds = m_fileWidget->getFocusedTokenIds();
bool isError = m_fileWidget->getErrorMessages().size() > 0;
bool needsUpdate = false;
for (Annotation& annotation: m_annotations)
{
bool wasActive = annotation.isActive;
bool wasFocused = annotation.isFocused;
annotation.isActive = std::find(activeIds.begin(), activeIds.end(), annotation.tokenId) != activeIds.end();
annotation.isFocused = std::find(focusIds.begin(), focusIds.end(), annotation.tokenId) != focusIds.end();
annotation.isError = isError;
if (wasFocused != annotation.isFocused || wasActive != annotation.isActive)
{
needsUpdate = true;
}
}
if (needsUpdate)
{
m_lineNumberArea->update();
viewport()->update();
}
}
void QtCodeArea::setHoveredAnnotations(const std::vector<const Annotation*>& annotations)
{
if (m_hoveredAnnotations.size())
{
std::vector<Id> tokenIds;
for (const Annotation* annotation : m_hoveredAnnotations)
{
tokenIds.push_back(annotation->tokenId);
}
MessageFocusOut(tokenIds).dispatch();
}
m_hoveredAnnotations = annotations;
if (annotations.size())
{
std::vector<Id> tokenIds;
for (const Annotation* annotation : annotations)
{
tokenIds.push_back(annotation->tokenId);
}
MessageFocusIn(tokenIds).dispatch();
}
}
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;
}
std::pair<int, int> QtCodeArea::toLineColumn(int textEditPosition) const
{
int lineNumber = m_startLineNumber;
for (int i = 0; i < document()->lineCount(); i++)
{
int nextTextEditPosition = textEditPosition - document()->findBlockByLineNumber(i).length();
if (nextTextEditPosition >= 0)
{
textEditPosition = nextTextEditPosition;
lineNumber++;
}
else
{
break;
}
}
return std::make_pair(lineNumber, textEditPosition);
}
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;
}
std::set<int> QtCodeArea::getActiveLineNumbers() const
{
std::set<int> activeLineNumbers;
if (m_isActiveFile)
{
return activeLineNumbers;
}
for (const Annotation& annotation : m_annotations)
{
if (annotation.isActive)
{
for (int i = annotation.startLine; i <= annotation.endLine; i++)
{
activeLineNumbers.insert(i);
}
}
}
if (activeLineNumbers.size())
{
for (const Annotation& annotation : m_annotations)
{
if (annotation.isFocused)
{
for (int i = annotation.startLine; i <= annotation.endLine; i++)
{
activeLineNumbers.insert(i);
}
}
}
}
return activeLineNumbers;
}
std::vector<QRect> QtCodeArea::getCursorRectsForAnnotation(const Annotation& annotation) const
{
std::vector<QRect> rects;
QTextCursor cursor = textCursor();
cursor.clearSelection();
cursor.setPosition(annotation.start);
QRect rectStart = cursorRect(cursor);
QRect rectEnd;
int line = annotation.startLine;
while (line <= annotation.endLine)
{
if (line == annotation.endLine)
{
cursor.setPosition(annotation.end);
}
else
{
cursor.setPosition(toTextEditPosition(line, document()->findBlockByLineNumber(line - m_startLineNumber).length() - 1));
}
rectEnd = cursorRect(cursor);
rects.push_back(QRect(rectStart.left(), rectStart.top(), rectEnd.right() - rectStart.left(), rectEnd.bottom() - rectStart.top()));
line++;
if (int(line - m_startLineNumber) < document()->blockCount())
{
cursor.setPosition(toTextEditPosition(line, 0));
rectStart = cursorRect(cursor);
}
}
return rects;
}
const QtCodeArea::AnnotationColor& QtCodeArea::getAnnotationColorForAnnotation(const Annotation& annotation)
{
if (!s_annotationColors.size())
{
ColorScheme* scheme = ColorScheme::getInstance().get();
std::vector<std::string> types;
types.push_back("location");
types.push_back("scope");
types.push_back("error");
std::vector<std::string> states;
states.push_back("normal");
states.push_back("focus");
states.push_back("active");
for (const std::string& type : types)
{
for (const std::string& state : states)
{
AnnotationColor color;
color.border = scheme->getColor("code/snippet/selection/" + type + "/" + state + "/border");
color.fill = scheme->getColor("code/snippet/selection/" + type + "/" + state + "/fill");
s_annotationColors.push_back(color);
}
}
}
size_t i = 0;
if (annotation.isScope)
{
i = 3;
}
else if (annotation.isError)
{
i = 6;
}
if (annotation.isActive)
{
i += 2;
}
else if (annotation.isFocused)
{
i += 1;
}
return s_annotationColors[i];
}
void QtCodeArea::createActions()
{
m_setIDECursorPositionAction = new QAction(tr("Set IDE Cursor"), this);
m_setIDECursorPositionAction->setStatusTip(tr("Set the IDE Cursor to this code position"));
m_setIDECursorPositionAction->setToolTip(tr("Set the IDE Cursor to this code position"));
connect(m_setIDECursorPositionAction, SIGNAL(triggered()), this, SLOT(setIDECursorPosition()));
}
+182
View File
@@ -0,0 +1,182 @@
#ifndef QT_CODE_AREA_H
#define QT_CODE_AREA_H
#include <memory>
#include <set>
#include <vector>
#include <QPlainTextEdit>
#include "utility/types.h"
class QDragMoveEvent;
class QPaintEvent;
class QResizeEvent;
class QSize;
class QtCodeFile;
class QtCodeSnippet;
class QtHighlighter;
class QWidget;
class TokenLocation;
class TokenLocationFile;
class MouseWheelOverScrollbarFilter
: public QObject
{
Q_OBJECT
public:
MouseWheelOverScrollbarFilter(QObject* parent);
protected:
bool eventFilter(QObject* obj, QEvent* event);
};
class QtCodeArea
: public QPlainTextEdit
{
Q_OBJECT
public:
class LineNumberArea
: public QWidget
{
public:
LineNumberArea(QtCodeArea* codeArea);
virtual ~LineNumberArea();
QSize sizeHint() const Q_DECL_OVERRIDE;
protected:
virtual void paintEvent(QPaintEvent* event) Q_DECL_OVERRIDE;
private:
QtCodeArea* m_codeArea;
};
static void clearAnnotationColors();
QtCodeArea(
uint startLineNumber,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
QtCodeFile* file,
QtCodeSnippet* parent
);
virtual ~QtCodeArea();
virtual QSize sizeHint() const Q_DECL_OVERRIDE;
uint getStartLineNumber() const;
uint getEndLineNumber() const;
std::shared_ptr<TokenLocationFile> getTokenLocationFile() const;
void lineNumberAreaPaintEvent(QPaintEvent* event);
int lineNumberDigits() const;
int lineNumberAreaWidth() const;
void updateLineNumberAreaWidthForDigits(int digits);
void updateContent();
bool isActive() const;
void setIsActiveFile(bool isActiveFile);
QRectF getFirstActiveLineRect() const;
std::string getCode() const;
protected:
virtual void resizeEvent(QResizeEvent* event) Q_DECL_OVERRIDE;
virtual void showEvent(QShowEvent* event) Q_DECL_OVERRIDE;
virtual void paintEvent(QPaintEvent* event) Q_DECL_OVERRIDE;
virtual void enterEvent(QEvent* event) Q_DECL_OVERRIDE;
virtual void leaveEvent(QEvent* event) Q_DECL_OVERRIDE;
virtual void mouseReleaseEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
virtual void mouseDoubleClickEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
virtual void mousePressEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
virtual void mouseMoveEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
virtual void contextMenuEvent(QContextMenuEvent* event) Q_DECL_OVERRIDE;
private slots:
void updateLineNumberAreaWidth(int newBlockCount);
void updateLineNumberArea(const QRect&, int);
void clearSelection();
void setIDECursorPosition();
private:
struct Annotation
{
int startLine;
int endLine;
int startCol;
int endCol;
int start;
int end;
Id tokenId;
Id locationId;
bool isScope;
bool isError;
bool isActive;
bool isFocused;
};
struct AnnotationColor
{
std::string border;
std::string fill;
};
std::vector<Id> findLocationIdsForPosition(int pos) const;
std::vector<const Annotation*> getAnnotationsForPosition(int pos) const;
void createAnnotations(std::shared_ptr<TokenLocationFile> locationFile);
void annotateText();
void setHoveredAnnotations(const std::vector<const Annotation*>& annotations);
int toTextEditPosition(int lineNumber, int columnNumber) const;
std::pair<int, int> toLineColumn(int textEditPosition) const;
int startTextEditPosition() const;
int endTextEditPosition() const;
std::set<int> getActiveLineNumbers() const;
std::vector<QRect> getCursorRectsForAnnotation(const Annotation& annotation) const;
const AnnotationColor& getAnnotationColorForAnnotation(const Annotation& annotation);
void createActions();
static std::vector<AnnotationColor> s_annotationColors;
QtCodeFile* m_fileWidget;
QWidget* m_lineNumberArea;
QtHighlighter* m_highlighter;
const uint m_startLineNumber;
const std::string m_code;
std::shared_ptr<TokenLocationFile> m_locationFile;
std::vector<Annotation> m_annotations;
std::vector<const Annotation*> m_hoveredAnnotations;
int m_digits;
int m_panningValue; // just for horizontal panning
QAction* m_setIDECursorPositionAction;
QPoint m_eventPosition; // is needed for IDE cursor control via context menu
// the position where the context menu is opened needs to be stored]
bool m_isActiveFile;
};
#endif // QT_CODE_AREA_H
+459
View File
@@ -0,0 +1,459 @@
#include "qt/element/QtCodeFile.h"
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include "utility/file/FileSystem.h"
#include "utility/logging/logging.h"
#include "utility/messaging/type/MessageActivateFile.h"
#include "utility/messaging/type/MessageShowFile.h"
#include "utility/messaging/type/MessageShowSnippets.h"
#include "data/location/TokenLocation.h"
#include "data/location/TokenLocationFile.h"
#include "qt/element/QtCodeFileList.h"
#include "qt/element/QtCodeSnippet.h"
#include "qt/utility/utilityQt.h"
#include "settings/ColorScheme.h"
QtCodeFile::QtCodeFile(const FilePath& filePath, QtCodeFileList* parent)
: QFrame(parent)
, m_updateTitleBarFunctor(std::bind(&QtCodeFile::doUpdateTitleBar, this))
, m_parent(parent)
, m_filePath(filePath)
{
setObjectName("code_file");
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->setSpacing(0);
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
m_titleBar = new QPushButton(this);
m_titleBar->setObjectName("title_widget");
layout->addWidget(m_titleBar);
QHBoxLayout* titleLayout = new QHBoxLayout();
titleLayout->setMargin(0);
titleLayout->setSpacing(0);
titleLayout->setAlignment(Qt::AlignLeft);
m_titleBar->setLayout(titleLayout);
m_title = new QPushButton(filePath.fileName().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->setToolTip(QString::fromStdString(filePath.str()));
m_title->setFixedWidth(m_title->fontMetrics().width(filePath.fileName().c_str()) + 52);
m_title->setFixedHeight(std::max(m_title->fontMetrics().height() * 1.2, 28.0));
m_title->setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed);
m_title->setIcon(utility::colorizePixmap(
QPixmap("data/gui/graph_view/images/file.png"),
ColorScheme::getInstance()->getColor("code/file/title/icon").c_str()
));
titleLayout->addWidget(m_title);
m_titleBar->setMinimumHeight(m_title->height() + 4);
m_referenceCount = new QLabel(this);
m_referenceCount->setObjectName("references_label");
m_referenceCount->hide();
titleLayout->addWidget(m_referenceCount);
titleLayout->addStretch(3);
m_minimizeButton = new QPushButton(this);
m_minimizeButton->setObjectName("minimize_button");
m_minimizeButton->setToolTip("minimize");
m_minimizeButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
titleLayout->addWidget(m_minimizeButton);
m_snippetButton = new QPushButton(this);
m_snippetButton->setObjectName("snippet_button");
m_snippetButton->setToolTip("show snippets");
m_snippetButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
titleLayout->addWidget(m_snippetButton);
m_maximizeButton = new QPushButton(this);
m_maximizeButton->setObjectName("maximize_button");
m_maximizeButton->setToolTip("maximize");
m_maximizeButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
titleLayout->addWidget(m_maximizeButton);
m_minimizeButton->setEnabled(false);
m_snippetButton->setEnabled(false);
m_maximizeButton->setEnabled(false);
connect(m_titleBar, SIGNAL(clicked()), this, SLOT(clickedTitleBar()));
connect(m_title, SIGNAL(clicked()), this, SLOT(clickedTitle()));
connect(m_minimizeButton, SIGNAL(clicked()), this, SLOT(clickedMinimizeButton()));
connect(m_snippetButton, SIGNAL(clicked()), this, SLOT(clickedSnippetButton()));
connect(m_maximizeButton, SIGNAL(clicked()), this, SLOT(clickedMaximizeButton()));
m_minimizePlaceholder = new QWidget(this);
m_minimizePlaceholder->setMinimumHeight(5);
layout->addWidget(m_minimizePlaceholder);
m_snippetLayout = new QVBoxLayout();
layout->addLayout(m_snippetLayout);
update();
}
QtCodeFile::~QtCodeFile()
{
}
void QtCodeFile::setModificationTime(TimePoint modificationTime)
{
m_modificationTime = modificationTime;
updateTitleBar();
}
const FilePath& QtCodeFile::getFilePath() const
{
return m_filePath;
}
std::string QtCodeFile::getFileName() const
{
return m_filePath.fileName();
}
const std::vector<Id>& QtCodeFile::getActiveTokenIds() const
{
return m_parent->getActiveTokenIds();
}
const std::vector<Id>& QtCodeFile::getFocusedTokenIds() const
{
return m_parent->getFocusedTokenIds();
}
const std::vector<std::string>& QtCodeFile::getErrorMessages() const
{
return m_parent->getErrorMessages();
}
void QtCodeFile::addCodeSnippet(
uint startLineNumber,
const std::string& title,
Id titleId,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
int refCount
){
m_locationFile.reset();
std::shared_ptr<QtCodeSnippet> snippet(
new QtCodeSnippet(startLineNumber, title, titleId, code, locationFile, this));
m_snippetLayout->addWidget(snippet.get());
if (locationFile->isWholeCopy)
{
snippet->setProperty("isFirst", true);
snippet->setProperty("isLast", true);
m_fileSnippet = snippet;
if (!m_snippets.size())
{
m_fileSnippet->setIsActiveFile(true);
}
clickedMaximizeButton();
if (refCount != -1)
{
updateRefCount(0);
}
return;
}
m_snippets.push_back(snippet);
updateSnippets();
updateRefCount(refCount);
}
QtCodeSnippet* QtCodeFile::insertCodeSnippet(
uint startLineNumber,
const std::string& title,
Id titleId,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
int refCount
){
m_locationFile.reset();
std::shared_ptr<QtCodeSnippet> snippet(
new QtCodeSnippet(startLineNumber, title, titleId, code, locationFile, this));
size_t i = 0;
while (i < m_snippets.size())
{
uint start = snippet->getStartLineNumber();
uint end = snippet->getEndLineNumber();
std::shared_ptr<QtCodeSnippet> s = m_snippets[i];
if (s->getEndLineNumber() + 1 < start)
{
i++;
continue;
}
else if (s->getStartLineNumber() > end + 1)
{
break;
}
else if (s->getStartLineNumber() < start || s->getEndLineNumber() > end)
{
snippet = QtCodeSnippet::merged(snippet.get(), s.get(), this);
}
s->hide();
m_snippetLayout->removeWidget(s.get());
m_snippets.erase(m_snippets.begin() + i);
}
m_snippetLayout->insertWidget(i, snippet.get());
m_snippets.insert(m_snippets.begin() + i, snippet);
updateSnippets();
updateRefCount(refCount);
return snippet.get();
}
QtCodeSnippet* QtCodeFile::findFirstActiveSnippet() const
{
if (m_locationFile)
{
return nullptr;
}
if (m_maximizeButton->isEnabled())
{
for (std::shared_ptr<QtCodeSnippet> snippet : m_snippets)
{
if (snippet->isActive())
{
return snippet.get();
}
}
}
else
{
if (m_fileSnippet->isActive())
{
return m_fileSnippet.get();
}
}
return nullptr;
}
bool QtCodeFile::openCollapsedActiveSnippet() const
{
if (m_locationFile)
{
std::vector<Id> ids = getActiveTokenIds();
bool isActiveFile = false;
m_locationFile->forEachTokenLocation(
[&](TokenLocation* location)
{
if (std::find(ids.begin(), ids.end(), location->getTokenId()) != ids.end())
{
isActiveFile = true;
}
}
);
if (isActiveFile)
{
MessageShowSnippets(m_locationFile).dispatch();
return true;
}
}
return false;
}
void QtCodeFile::updateContent()
{
for (std::shared_ptr<QtCodeSnippet> snippet : m_snippets)
{
snippet->updateContent();
}
if (m_fileSnippet)
{
m_fileSnippet->updateContent();
}
}
void QtCodeFile::setLocationFile(std::shared_ptr<TokenLocationFile> locationFile, int refCount)
{
m_locationFile = locationFile;
clickedMinimizeButton();
updateRefCount(refCount);
}
void QtCodeFile::clickedTitleBar()
{
if (m_minimizeButton->isEnabled())
{
clickedMinimizeButton();
}
else if (m_snippetButton->isEnabled())
{
clickedSnippetButton();
}
else
{
clickedMaximizeButton();
}
}
void QtCodeFile::clickedTitle()
{
MessageActivateFile(m_filePath).dispatch();
}
void QtCodeFile::clickedMinimizeButton()
{
for (std::shared_ptr<QtCodeSnippet> snippet : m_snippets)
{
snippet->hide();
}
if (m_fileSnippet)
{
m_fileSnippet->hide();
}
m_minimizeButton->setEnabled(false);
if (m_snippets.size() || m_locationFile)
{
m_snippetButton->setEnabled(true);
}
m_maximizeButton->setEnabled(true);
m_minimizePlaceholder->show();
}
void QtCodeFile::clickedSnippetButton()
{
if (m_locationFile)
{
MessageShowSnippets(m_locationFile).dispatch();
return;
}
for (std::shared_ptr<QtCodeSnippet> snippet : m_snippets)
{
snippet->show();
}
if (m_fileSnippet)
{
m_fileSnippet->hide();
}
m_minimizeButton->setEnabled(true);
m_snippetButton->setEnabled(false);
m_maximizeButton->setEnabled(true);
m_minimizePlaceholder->hide();
}
void QtCodeFile::clickedMaximizeButton()
{
for (std::shared_ptr<QtCodeSnippet> snippet : m_snippets)
{
snippet->hide();
}
if (m_fileSnippet)
{
m_fileSnippet->show();
}
else
{
MessageShowFile(m_filePath, (getErrorMessages().size() > 0)).dispatch();
}
m_minimizeButton->setEnabled(true);
if (m_snippets.size())
{
m_snippetButton->setEnabled(true);
}
m_maximizeButton->setEnabled(false);
m_minimizePlaceholder->hide();
}
void QtCodeFile::handleMessage(MessageWindowFocus* message)
{
updateTitleBar();
}
void QtCodeFile::updateSnippets()
{
int maxDigits = 1;
for (std::shared_ptr<QtCodeSnippet> snippet : m_snippets)
{
snippet->setProperty("isFirst", false);
snippet->setProperty("isLast", false);
maxDigits = qMax(maxDigits, snippet->lineNumberDigits());
}
for (std::shared_ptr<QtCodeSnippet> snippet : m_snippets)
{
snippet->updateLineNumberAreaWidthForDigits(maxDigits);
}
m_snippets.front()->setProperty("isFirst", true);
m_snippets.back()->setProperty("isLast", true);
clickedSnippetButton();
}
void QtCodeFile::updateRefCount(int refCount)
{
if (refCount > 0)
{
m_referenceCount->setText(QString::fromStdString(std::to_string(refCount) + (refCount == 1 ? " reference" : " references")));
m_referenceCount->show();
}
else
{
m_referenceCount->hide();
}
}
void QtCodeFile::updateTitleBar()
{
m_updateTitleBarFunctor();
}
void QtCodeFile::doUpdateTitleBar()
{
// cannot use m_filePath.exists() here since it is only checked when FilePath is constructed.
if ((!FileSystem::exists(m_filePath.str())) ||
(FileSystem::getLastWriteTime(m_filePath) > m_modificationTime))
{
m_title->setStyleSheet("background-image: url(data/gui/code_view/images/pattern.png);");
}
else
{
m_title->setStyleSheet("");
}
}
+107
View File
@@ -0,0 +1,107 @@
#ifndef QT_CODE_FILE_H
#define QT_CODE_FILE_H
#include <memory>
#include <string>
#include <vector>
#include <QFrame>
#include "utility/file/FilePath.h"
#include "utility/TimePoint.h"
#include "utility/types.h"
#include "utility/messaging/MessageListener.h"
#include "utility/messaging/type/MessageWindowFocus.h"
#include "qt/utility/QtThreadedFunctor.h"
class QLabel;
class QPushButton;
class QtCodeFileList;
class QtCodeSnippet;
class QVBoxLayout;
class TokenLocationFile;
class QtCodeFile
: public QFrame
, MessageListener<MessageWindowFocus>
{
Q_OBJECT
public:
QtCodeFile(const FilePath& filePath, QtCodeFileList* parent);
virtual ~QtCodeFile();
void setModificationTime(TimePoint modificationTime);
const FilePath& getFilePath() const;
std::string getFileName() const;
const std::vector<Id>& getActiveTokenIds() const;
const std::vector<Id>& getFocusedTokenIds() const;
const std::vector<std::string>& getErrorMessages() const;
void addCodeSnippet(
uint startLineNumber,
const std::string& title,
Id titleId,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
int refCount
);
QtCodeSnippet* insertCodeSnippet(
uint startLineNumber,
const std::string& title,
Id titleId,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
int refCount
);
QtCodeSnippet* findFirstActiveSnippet() const;
bool openCollapsedActiveSnippet() const;
void updateContent();
void setLocationFile(std::shared_ptr<TokenLocationFile> locationFile, int refCount);
public slots:
void clickedSnippetButton();
private slots:
void clickedTitleBar();
void clickedTitle();
void clickedMinimizeButton();
void clickedMaximizeButton();
private:
virtual void handleMessage(MessageWindowFocus* message);
void updateSnippets();
void updateRefCount(int refCount);
void updateTitleBar();
void doUpdateTitleBar();
QtThreadedFunctor<> m_updateTitleBarFunctor;
QtCodeFileList* m_parent;
QPushButton* m_titleBar;
QPushButton* m_title;
QLabel* m_referenceCount;
QPushButton* m_minimizeButton;
QPushButton* m_snippetButton;
QPushButton* m_maximizeButton;
QVBoxLayout* m_snippetLayout;
std::vector<std::shared_ptr<QtCodeSnippet>> m_snippets;
std::shared_ptr<QtCodeSnippet> m_fileSnippet;
QWidget* m_minimizePlaceholder;
const FilePath m_filePath;
TimePoint m_modificationTime;
std::shared_ptr<TokenLocationFile> m_locationFile;
};
#endif // QT_CODE_FILE_H
+227
View File
@@ -0,0 +1,227 @@
#include "qt/element/QtCodeFileList.h"
#include <QPropertyAnimation>
#include <QScrollBar>
#include <QVariant>
#include <QVBoxLayout>
#include "utility/file/FileSystem.h"
#include "data/location/TokenLocationFile.h"
#include "qt/element/QtCodeFile.h"
#include "qt/element/QtCodeSnippet.h"
QtCodeFileList::QtCodeFileList(QWidget* parent)
: QScrollArea(parent)
{
setObjectName("code_file_list_base");
m_frame = std::make_shared<QFrame>(this);
m_frame->setObjectName("code_file_list");
QVBoxLayout* layout = new QVBoxLayout(m_frame.get());
layout->setSpacing(8);
layout->setContentsMargins(8, 8, 8, 8);
layout->setAlignment(Qt::AlignTop);
m_frame->setLayout(layout);
setWidgetResizable(true);
setWidget(m_frame.get());
connect(this, SIGNAL(shouldScrollToSnippet(QtCodeSnippet*)), this, SLOT(scrollToSnippet(QtCodeSnippet*)), Qt::QueuedConnection);
}
QtCodeFileList::~QtCodeFileList()
{
}
QSize QtCodeFileList::sizeHint() const
{
return QSize(800, 800);
}
void QtCodeFileList::addCodeSnippet(
uint startLineNumber,
const std::string& title,
Id titleId,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
int refCount,
TimePoint modificationTime,
bool insert
){
QtCodeFile* file = getFile(locationFile);
if (insert)
{
QtCodeSnippet* snippet = file->insertCodeSnippet(startLineNumber, title, titleId, code, locationFile, refCount);
emit shouldScrollToSnippet(snippet);
}
else
{
file->addCodeSnippet(startLineNumber, title, titleId, code, locationFile, refCount);
}
file->setModificationTime(modificationTime);
}
void QtCodeFileList::addFile(std::shared_ptr<TokenLocationFile> locationFile, int refCount, TimePoint modificationTime)
{
QtCodeFile* file = getFile(locationFile);
file->setLocationFile(locationFile, refCount);
file->setModificationTime(modificationTime);
}
void QtCodeFileList::clearCodeSnippets()
{
m_files.clear();
this->verticalScrollBar()->setValue(0);
}
const std::vector<Id>& QtCodeFileList::getActiveTokenIds() const
{
return m_activeTokenIds;
}
void QtCodeFileList::setActiveTokenIds(const std::vector<Id>& activeTokenIds)
{
m_activeTokenIds = activeTokenIds;
}
const std::vector<Id>& QtCodeFileList::getFocusedTokenIds() const
{
return m_focusedTokenIds;
}
void QtCodeFileList::setFocusedTokenIds(const std::vector<Id>& focusedTokenIds)
{
m_focusedTokenIds = focusedTokenIds;
}
const std::vector<std::string>& QtCodeFileList::getErrorMessages() const
{
return m_errorMessages;
}
void QtCodeFileList::setErrorMessages(const std::vector<std::string>& errorMessages)
{
m_errorMessages = errorMessages;
}
bool QtCodeFileList::scrollToFirstActiveSnippet()
{
updateFiles();
QtCodeSnippet* snippet = nullptr;
for (std::shared_ptr<QtCodeFile> file: m_files)
{
snippet = file->findFirstActiveSnippet();
if (snippet)
{
if (!snippet->isVisible())
{
file->clickedSnippetButton();
}
emit shouldScrollToSnippet(snippet);
return true;
}
}
return false;
}
void QtCodeFileList::expandActiveSnippetFile()
{
for (std::shared_ptr<QtCodeFile> file: m_files)
{
if (file->openCollapsedActiveSnippet())
{
return;
}
}
}
void QtCodeFileList::focusTokenIds(const std::vector<Id>& focusedTokenIds)
{
setFocusedTokenIds(focusedTokenIds);
updateFiles();
}
void QtCodeFileList::defocusTokenIds()
{
setFocusedTokenIds(std::vector<Id>());
updateFiles();
}
void QtCodeFileList::scrollToSnippet(QtCodeSnippet* snippet)
{
this->ensureWidgetVisibleAnimated(snippet, snippet->getFirstActiveLineRect());
}
QtCodeFile* QtCodeFileList::getFile(std::shared_ptr<TokenLocationFile> locationFile)
{
FilePath filePath = locationFile->getFilePath();
QtCodeFile* file = nullptr;
for (std::shared_ptr<QtCodeFile> filePtr : m_files)
{
if (filePtr->getFilePath() == filePath)
{
file = filePtr.get();
break;
}
}
if (!file)
{
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);
}
return file;
}
void QtCodeFileList::updateFiles()
{
for (std::shared_ptr<QtCodeFile> file: m_files)
{
file->updateContent();
}
}
void QtCodeFileList::ensureWidgetVisibleAnimated(QWidget *childWidget, QRectF rect)
{
if (!widget()->isAncestorOf(childWidget))
{
return;
}
const QRect microFocus = childWidget->inputMethodQuery(Qt::ImCursorRectangle).toRect();
const QRect defaultMicroFocus = childWidget->QWidget::inputMethodQuery(Qt::ImCursorRectangle).toRect();
QRect focusRect = (microFocus != defaultMicroFocus)
? QRect(childWidget->mapTo(widget(), microFocus.topLeft()), microFocus.size())
: QRect(childWidget->mapTo(widget(), QPoint(0, 0)), childWidget->size());
const QRect visibleRect(-widget()->pos(), viewport()->size());
if (rect.height() > 0)
{
focusRect = QRect(childWidget->mapTo(widget(), rect.topLeft().toPoint()), rect.size().toSize());
focusRect.adjust(0, 0, 0, 100);
}
QScrollBar* scrollBar = verticalScrollBar();
int value = focusRect.center().y() - visibleRect.center().y();
if (scrollBar && value != 0)
{
QPropertyAnimation* anim = new QPropertyAnimation(scrollBar, "value");
anim->setDuration(500);
anim->setStartValue(scrollBar->value());
anim->setEndValue(scrollBar->value() + value);
anim->setEasingCurve(QEasingCurve::InOutQuad);
anim->start();
}
}
+79
View File
@@ -0,0 +1,79 @@
#ifndef QT_CODE_FILE_LIST
#define QT_CODE_FILE_LIST
#include <memory>
#include <vector>
#include <QFrame>
#include <QScrollArea>
#include "utility/TimePoint.h"
#include "utility/types.h"
class QtCodeFile;
class QtCodeSnippet;
class TokenLocationFile;
class QtCodeFileList
: public QScrollArea
{
Q_OBJECT
signals:
void shouldScrollToSnippet(QtCodeSnippet* widget);
public:
QtCodeFileList(QWidget* parent = 0);
virtual ~QtCodeFileList();
virtual QSize sizeHint() const;
void addCodeSnippet(
uint startLineNumber,
const std::string& title,
Id titleId,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
int refCount,
TimePoint modificationTime,
bool insert = false
);
void addFile(std::shared_ptr<TokenLocationFile> locationFile, int refCount, TimePoint modificationTime);
void clearCodeSnippets();
const std::vector<Id>& getActiveTokenIds() const;
void setActiveTokenIds(const std::vector<Id>& activeTokenIds);
const std::vector<Id>& getFocusedTokenIds() const;
void setFocusedTokenIds(const std::vector<Id>& focusedTokenIds);
const std::vector<std::string>& getErrorMessages() const;
void setErrorMessages(const std::vector<std::string>& errorMessages);
bool scrollToFirstActiveSnippet();
void expandActiveSnippetFile();
void focusTokenIds(const std::vector<Id>& focusedTokenIds);
void defocusTokenIds();
private slots:
void scrollToSnippet(QtCodeSnippet* snippet);
private:
QtCodeFile* getFile(std::shared_ptr<TokenLocationFile> locationFile);
void updateFiles();
void ensureWidgetVisibleAnimated(QWidget *childWidget, QRectF rect);
std::shared_ptr<QFrame> m_frame;
std::vector<std::shared_ptr<QtCodeFile>> m_files;
std::vector<Id> m_activeTokenIds;
std::vector<Id> m_focusedTokenIds;
std::vector<std::string> m_errorMessages;
};
#endif // QT_CODE_FILE_LIST
+191
View File
@@ -0,0 +1,191 @@
#include "qt/element/QtCodeSnippet.h"
#include <QBoxLayout>
#include <qmenu.h>
#include <QPushButton>
#include "utility/messaging/type/MessageShowScope.h"
#include "utility/messaging/type/MessageShowFile.h"
#include "utility/text/TextAccess.h"
#include "data/location/TokenLocationFile.h"
#include "qt/element/QtCodeFile.h"
std::shared_ptr<QtCodeSnippet> QtCodeSnippet::merged(QtCodeSnippet* a, QtCodeSnippet* b, QtCodeFile* file)
{
QtCodeSnippet* first = a->getStartLineNumber() < b->getStartLineNumber() ? a : b;
QtCodeSnippet* second = a->getStartLineNumber() > b->getStartLineNumber() ? a : b;
TokenLocationFile* aFile = a->m_codeArea->getTokenLocationFile().get();
TokenLocationFile* bFile = b->m_codeArea->getTokenLocationFile().get();
std::shared_ptr<TokenLocationFile> locationFile = std::make_shared<TokenLocationFile>(aFile->getFilePath());
aFile->forEachTokenLocation(
[&locationFile](TokenLocation* loc)
{
locationFile->addTokenLocationAsPlainCopy(loc);
}
);
bFile->forEachTokenLocation(
[&locationFile](TokenLocation* loc)
{
locationFile->addTokenLocationAsPlainCopy(loc);
}
);
std::string code = first->getCode();
std::string secondCode = second->getCode();
int secondCodeStartIndex = 0;
for (uint i = second->getStartLineNumber(); i <= first->getEndLineNumber(); i++)
{
secondCodeStartIndex = secondCode.find("\n", secondCodeStartIndex) + 1;
}
code += secondCode.substr(secondCodeStartIndex, secondCode.npos);
std::string title = first->m_titleString;
return std::shared_ptr<QtCodeSnippet>(new QtCodeSnippet(
first->getStartLineNumber(),
title,
first->m_titleId,
code,
locationFile,
file
));
}
QtCodeSnippet::QtCodeSnippet(
uint startLineNumber,
const std::string& title,
Id titleId,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
QtCodeFile* file
)
: QFrame(file)
, m_titleId(titleId)
, m_titleString(title)
, m_dots(nullptr)
, m_title(nullptr)
, m_codeArea(std::make_shared<QtCodeArea>(startLineNumber, code, locationFile, file, this))
{
setObjectName("code_snippet");
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->setSpacing(0);
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
if (m_titleString.size())
{
QHBoxLayout* titleLayout = new QHBoxLayout();
titleLayout->setMargin(0);
titleLayout->setSpacing(0);
titleLayout->setAlignment(Qt::AlignLeft);
layout->addLayout(titleLayout);
m_dots = new QPushButton(this);
m_dots->setObjectName("dots");
m_dots->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
titleLayout->addWidget(m_dots);
m_title = new QPushButton(FilePath(m_titleString).fileName().c_str(), this);
m_title->setObjectName("scope_name");
m_title->minimumSizeHint(); // force font loading
m_title->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
m_title->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
titleLayout->addWidget(m_title);
connect(m_title, SIGNAL(clicked()), this, SLOT(clickedTitle()));
}
layout->addWidget(m_codeArea.get());
updateDots();
}
QtCodeSnippet::~QtCodeSnippet()
{
}
uint QtCodeSnippet::getStartLineNumber() const
{
return m_codeArea->getStartLineNumber();
}
uint QtCodeSnippet::getEndLineNumber() const
{
return m_codeArea->getEndLineNumber();
}
int QtCodeSnippet::lineNumberDigits() const
{
return m_codeArea->lineNumberDigits();
}
void QtCodeSnippet::updateLineNumberAreaWidthForDigits(int digits)
{
m_codeArea->updateLineNumberAreaWidthForDigits(digits);
updateDots();
}
void QtCodeSnippet::updateContent()
{
m_codeArea->updateContent();
updateDots();
}
bool QtCodeSnippet::isActive() const
{
return m_codeArea->isActive();
}
void QtCodeSnippet::setIsActiveFile(bool isActiveFile)
{
m_codeArea->setIsActiveFile(isActiveFile);
}
QRectF QtCodeSnippet::getFirstActiveLineRect() const
{
return m_codeArea->getFirstActiveLineRect();
}
std::string QtCodeSnippet::getCode() const
{
return m_codeArea->getCode();
}
void QtCodeSnippet::contextMenuEvent(QContextMenuEvent* event)
{
QMenu menu(this);
menu.addAction(new QAction("Bar", this));
menu.addAction(new QAction("Brew Tea", this));
menu.addAction(new QAction("Translate", this));
menu.exec(event->globalPos());
}
void QtCodeSnippet::clickedTitle()
{
if (m_titleId > 0)
{
MessageShowScope(m_titleId).dispatch();
}
else
{
MessageShowFile(FilePath(m_titleString), (dynamic_cast<QtCodeFile*>(parent())->getErrorMessages().size() > 0)).dispatch();
}
}
void QtCodeSnippet::updateDots()
{
if (!m_dots)
{
return;
}
m_dots->setText(QString::fromStdString(std::string(lineNumberDigits(), '.')));
m_dots->setMinimumWidth(m_codeArea->lineNumberAreaWidth());
}
+68
View File
@@ -0,0 +1,68 @@
#ifndef QT_CODE_SNIPPET_H
#define QT_CODE_SNIPPET_H
#include <vector>
#include <memory>
#include <QFrame>
#include "utility/types.h"
#include "qt/element/QtCodeArea.h"
class QPushButton;
class QtCodeFile;
class TokenLocationFile;
class QtCodeSnippet
: public QFrame
{
Q_OBJECT
public:
static std::shared_ptr<QtCodeSnippet> merged(QtCodeSnippet* a, QtCodeSnippet* b, QtCodeFile* file);
QtCodeSnippet(
uint startLineNumber,
const std::string& title,
Id titleId,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
QtCodeFile* file
);
virtual ~QtCodeSnippet();
uint getStartLineNumber() const;
uint getEndLineNumber() const;
int lineNumberDigits() const;
void updateLineNumberAreaWidthForDigits(int digits);
void updateContent();
bool isActive() const;
void setIsActiveFile(bool isActiveFile);
QRectF getFirstActiveLineRect() const;
std::string getCode() const;
protected:
virtual void contextMenuEvent(QContextMenuEvent* event) Q_DECL_OVERRIDE;
private slots:
void clickedTitle();
private:
void updateDots();
Id m_titleId;
std::string m_titleString;
QPushButton* m_dots;
QPushButton* m_title;
std::shared_ptr<QtCodeArea> m_codeArea;
};
#endif // QT_CODE_SNIPPET_H
@@ -0,0 +1,224 @@
#include "qt/element/QtDirectoryListBox.h"
#include <QBoxLayout>
#include <QTreeView>
#include <QFileDialog>
#include <QMimeData>
#include "qt/utility/utilityQt.h"
QtListItemWidget::QtListItemWidget(QtDirectoryListBox* list, QListWidgetItem* item, QWidget *parent)
: QWidget(parent)
, m_list(list)
, m_item(item)
{
QBoxLayout* layout = new QHBoxLayout();
layout->setSpacing(3);
layout->setContentsMargins(0, 0, 0, 0);
layout->setAlignment(Qt::AlignTop);
m_data = new QtLineEdit(this);
m_data->setAttribute(Qt::WA_MacShowFocusRect, 0);
m_data->setObjectName("field");
m_button = new QPushButton("...");
m_button->setObjectName("button");
layout->addWidget(m_data);
layout->addWidget(m_button);
setLayout(layout);
connect(m_button, SIGNAL(clicked()), this, SLOT(handleButtonPress()));
connect(m_data, SIGNAL(focus()), this, SLOT(handleFocus()));
}
QString QtListItemWidget::getText()
{
return m_data->text();
}
void QtListItemWidget::setText(QString text)
{
m_data->setText(text);
}
void QtListItemWidget::setFocus()
{
m_data->setFocus(Qt::OtherFocusReason);
}
void QtListItemWidget::handleButtonPress()
{
QFileDialog dialog(this);
QListView *l = dialog.findChild<QListView*>("listView");
dialog.setFileMode(QFileDialog::Directory);
if (l)
{
l->setSelectionMode(QAbstractItemView::SingleSelection);
}
QTreeView *t = dialog.findChild<QTreeView*>();
if (t)
{
t->setSelectionMode(QAbstractItemView::SingleSelection);
}
if (dialog.exec())
{
QStringList list = dialog.selectedFiles();
for (int i = 0; i < list.size(); i++)
{
setText(list.at(i));
}
}
handleFocus();
}
void QtListItemWidget::handleFocus()
{
m_list->selectItem(m_item);
}
QtDirectoryListBox::QtDirectoryListBox(QWidget *parent)
:QFrame(parent)
{
QBoxLayout* layout = new QVBoxLayout();
layout->setSpacing(0);
layout->setContentsMargins(0, 6, 0, 0);
layout->setAlignment(Qt::AlignTop);
m_list = new QListWidget(this);
m_list->setObjectName("list");
m_list->setAttribute(Qt::WA_MacShowFocusRect, 0);
setStyleSheet(utility::getStyleSheet("data/gui/setting_window/listbox.css").c_str());
layout->addWidget(m_list);
QWidget* buttonContainer = new QWidget(this);
buttonContainer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
buttonContainer->setObjectName("bar");
QHBoxLayout* innerLayout = new QHBoxLayout();
innerLayout->setContentsMargins(8, 4, 8, 3);
innerLayout->setSpacing(0);
m_addButton = new QPushButton(QIcon("data/gui/setting_window/plus.png"), "", this);
m_addButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_addButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
m_addButton->setObjectName("roundedButton");
innerLayout->addWidget(m_addButton);
m_removeButton = new QPushButton(QIcon("data/gui/setting_window/minus.png"), "", this);
m_removeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_removeButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
m_removeButton->setObjectName("roundedButton");
innerLayout->addWidget(m_removeButton);
QLabel* dropInfoText = new QLabel("Drop Files & Folders");
dropInfoText->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
dropInfoText->setObjectName("dropInfo");
dropInfoText->setAlignment(Qt::AlignRight);
innerLayout->addWidget(dropInfoText);
buttonContainer->setLayout(innerLayout);
layout->addWidget(buttonContainer);
setLayout(layout);
connect(m_addButton, SIGNAL(clicked()), this, SLOT(addListBoxItem()));
connect(m_removeButton, SIGNAL(clicked()), this, SLOT(removeListBoxItem()));
setAcceptDrops(true);
resize();
}
void QtDirectoryListBox::clear()
{
m_list->clear();
}
void QtDirectoryListBox::dropEvent(QDropEvent *event)
{
QFileInfo fileInfo;
foreach(QUrl url, event->mimeData()->urls())
{
QtListItemWidget* widget = addListBoxItem();
widget->setText(url.toLocalFile());
}
}
std::vector<FilePath> QtDirectoryListBox::getList()
{
std::vector<FilePath> list;
for (int i = 0; i < m_list->count(); ++i)
{
QtListItemWidget* widget = dynamic_cast<QtListItemWidget*>(m_list->itemWidget(m_list->item(i)));
list.push_back(widget->getText().toStdString());
}
return list;
}
void QtDirectoryListBox::setList(const std::vector<FilePath>& list)
{
m_list->clear();
for (const FilePath& path : list)
{
QtListItemWidget* widget = addListBoxItem();
widget->setText(QString::fromStdString(path.str()));
}
}
void QtDirectoryListBox::selectItem(QListWidgetItem* item)
{
for (int i = 0; i < m_list->count(); i++)
{
m_list->item(i)->setSelected(false);
}
item->setSelected(true);
}
void QtDirectoryListBox::resize()
{
int height = 25;
if (m_list->count() > 0)
{
height += (m_list->itemWidget(m_list->item(0))->height() + 1) * m_list->count() + 8;
}
if (height < 150)
{
height = 150;
}
setMinimumHeight(height);
}
QtListItemWidget* QtDirectoryListBox::addListBoxItem()
{
QListWidgetItem *item = new QListWidgetItem(m_list);
m_list->addItem(item);
QtListItemWidget* widget = new QtListItemWidget(this, item);
m_list->setItemWidget(item, widget);
resize();
widget->setFocus();
return widget;
}
void QtDirectoryListBox::removeListBoxItem()
{
qDeleteAll(m_list->selectedItems());
resize();
}
void QtDirectoryListBox::dragEnterEvent(QDragEnterEvent *event)
{
event->accept();
}
@@ -0,0 +1,74 @@
#ifndef QT_DIRECTORY_LIST_BOX_H
#define QT_DIRECTORY_LIST_BOX_H
#include <QFrame>
#include <QLabel>
#include <QListWidget>
#include <QPushButton>
#include <QtGui/qevent.h>
#include "utility/file/FilePath.h"
#include "qt/element/QtLineEdit.h"
class QtDirectoryListBox;
class QtListItemWidget
: public QWidget
{
Q_OBJECT
public:
QtListItemWidget(QtDirectoryListBox* list, QListWidgetItem* item, QWidget *parent = nullptr);
QString getText();
void setText(QString text);
public slots:
void setFocus();
private slots:
void handleButtonPress();
void handleFocus();
private:
QPushButton* m_button;
QtLineEdit* m_data;
QtDirectoryListBox* m_list;
QListWidgetItem* m_item;
};
class QtDirectoryListBox
: public QFrame
{
Q_OBJECT
public:
QtDirectoryListBox(QWidget *parent);
void clear();
std::vector<FilePath> getList();
void setList(const std::vector<FilePath>& list);
void selectItem(QListWidgetItem* item);
protected:
void dropEvent(QDropEvent *event);
void dragEnterEvent(QDragEnterEvent* event);
private:
void resize();
QPushButton* m_addButton;
QPushButton* m_removeButton;
QListWidget* m_list;
private slots:
QtListItemWidget* addListBoxItem();
void removeListBoxItem();
};
#endif // QT_DIRECTORY_LIST_BOX_H
+12
View File
@@ -0,0 +1,12 @@
#include "qt/element/QtLineEdit.h"
QtLineEdit::QtLineEdit(QWidget* parent)
: QLineEdit(parent)
{
}
void QtLineEdit::focusInEvent(QFocusEvent* event)
{
emit focus();
QLineEdit::focusInEvent(event);
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef QT_LINE_EDIT_H
#define QT_LINE_EDIT_H
#include <QLineEdit>
class QtLineEdit
: public QLineEdit
{
Q_OBJECT
public:
QtLineEdit(QWidget* parent = nullptr);
signals:
void focus();
protected:
void focusInEvent(QFocusEvent* event);
};
#endif // QT_LINE_EDIT_H
+72
View File
@@ -0,0 +1,72 @@
#include "qt/element/QtRefreshBar.h"
#include <QHBoxLayout>
#include <QPushButton>
#include "utility/messaging/type/MessageAutoRefreshChanged.h"
#include "utility/messaging/type/MessageRefresh.h"
#include "qt/utility/utilityQt.h"
#include "settings/ApplicationSettings.h"
#include "settings/ColorScheme.h"
QtRefreshBar::QtRefreshBar()
{
setObjectName("refresh_bar");
QBoxLayout* layout = new QHBoxLayout();
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
m_refreshButton = new QPushButton(this);
m_refreshButton->setObjectName("refresh_button");
m_refreshButton->setToolTip("refresh");
m_refreshButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
layout->addWidget(m_refreshButton);
m_autoRefreshButton = new QPushButton(this);
m_autoRefreshButton->setObjectName("auto_refresh_button");
m_autoRefreshButton->setCheckable(true);
m_autoRefreshButton->setToolTip("automatic refresh on window focus");
m_autoRefreshButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
layout->addWidget(m_autoRefreshButton);
connect(m_refreshButton, SIGNAL(clicked()), this, SLOT(refreshClicked()));
connect(m_autoRefreshButton, SIGNAL(clicked()), this, SLOT(autoRefreshClicked()));
refreshStyle();
}
QtRefreshBar::~QtRefreshBar()
{
}
void QtRefreshBar::refreshClicked()
{
MessageRefresh().dispatch();
}
void QtRefreshBar::autoRefreshClicked()
{
MessageAutoRefreshChanged(m_autoRefreshButton->isChecked()).dispatch();
}
void QtRefreshBar::refreshStyle()
{
float height = std::max(ApplicationSettings::getInstance()->getFontSize() + 16, 30);
m_refreshButton->setFixedHeight(height);
m_autoRefreshButton->setFixedHeight(height);
m_refreshButton->setIcon(utility::colorizePixmap(
QPixmap("data/gui/refresh_view/images/refresh.png"),
ColorScheme::getInstance()->getColor("search/button/icon").c_str()
));
m_autoRefreshButton->setIcon(utility::colorizePixmap(
QPixmap("data/gui/refresh_view/images/auto_refresh.png"),
ColorScheme::getInstance()->getColor("search/button/icon").c_str()
));
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef QT_REFRESH_BAR_H
#define QT_REFRESH_BAR_H
#include <QFrame>
class QPushButton;
class QtRefreshBar
: public QFrame
{
Q_OBJECT
public:
QtRefreshBar();
virtual ~QtRefreshBar();
void refreshStyle();
private slots:
void refreshClicked();
void autoRefreshClicked();
private:
QPushButton* m_refreshButton;
QPushButton* m_autoRefreshButton;
};
#endif // QT_REFRESH_BAR_H
+93
View File
@@ -0,0 +1,93 @@
#include "qt/element/QtSearchBar.h"
#include <QCompleter>
#include <QHBoxLayout>
#include <QPushButton>
#include "qt/element/QtSmartSearchBox.h"
#include "qt/utility/utilityQt.h"
#include "settings/ApplicationSettings.h"
#include "settings/ColorScheme.h"
QtSearchBar::QtSearchBar()
{
setObjectName("search_bar");
QBoxLayout* layout = new QHBoxLayout();
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
m_searchBoxContainer = new QWidget(this);
m_searchBoxContainer->setObjectName("search_box_container");
m_searchBoxContainer->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
m_searchBoxContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
layout->addWidget(m_searchBoxContainer);
QBoxLayout* innerLayout = new QHBoxLayout();
innerLayout->setContentsMargins(7, 3, 5, 2);
m_searchBoxContainer->setLayout(innerLayout);
m_searchBox = new QtSmartSearchBox(m_searchBoxContainer);
m_searchBox->setObjectName("search_box");
m_searchBox->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
m_searchBox->setAttribute(Qt::WA_MacShowFocusRect, 0); // remove blue focus box on Mac
m_searchBox->setMinimumWidth(100);
m_searchBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
innerLayout->addWidget(m_searchBox);
m_searchButton = new QPushButton(this);
m_searchButton->setObjectName("search_button");
m_searchButton->setToolTip("search");
m_searchButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
layout->addWidget(m_searchButton);
connect(m_searchButton, SIGNAL(clicked()), m_searchBox, SLOT(search()));
refreshStyle();
}
QtSearchBar::~QtSearchBar()
{
}
QSize QtSearchBar::sizeHint() const
{
return QSize(400, 100);
}
void QtSearchBar::setMatches(const std::vector<SearchMatch>& matches)
{
m_searchBox->setMatches(matches);
}
void QtSearchBar::setFocus()
{
m_searchBox->setFocus();
}
void QtSearchBar::setAutocompletionList(const std::vector<SearchMatch>& autocompletionList)
{
m_searchBox->setAutocompletionList(autocompletionList);
}
QAbstractItemView* QtSearchBar::getCompleterPopup()
{
if (m_searchBox->completer())
{
return m_searchBox->completer()->popup();
}
return nullptr;
}
void QtSearchBar::refreshStyle()
{
m_searchBox->setFixedHeight(std::max(ApplicationSettings::getInstance()->getFontSize() + 11, 25));
m_searchButton->setFixedHeight(m_searchBox->height() + 5);
m_searchButton->setIcon(utility::colorizePixmap(
QPixmap("data/gui/search_view/images/search.png"),
ColorScheme::getInstance()->getColor("search/button/icon").c_str()
));
}
+39
View File
@@ -0,0 +1,39 @@
#ifndef QT_SEARCH_BAR_H
#define QT_SEARCH_BAR_H
#include <string>
#include <QAbstractItemView>
#include <QFrame>
#include "data/search/SearchMatch.h"
class QPushButton;
class QtSmartSearchBox;
class QtSearchBar
: public QFrame
{
Q_OBJECT
public:
QtSearchBar();
virtual ~QtSearchBar();
virtual QSize sizeHint() const;
void setMatches(const std::vector<SearchMatch>& matches);
void setFocus();
void setAutocompletionList(const std::vector<SearchMatch>& autocompletionList);
QAbstractItemView* getCompleterPopup();
void refreshStyle();
private:
QWidget* m_searchBoxContainer; // used for correct clipping inside the search box
QtSmartSearchBox* m_searchBox;
QPushButton* m_searchButton;
};
#endif // QT_SEARCH_BAR_H
+848
View File
@@ -0,0 +1,848 @@
#include "qt/element/QtSmartSearchBox.h"
#include <stdlib.h>
#include <QApplication>
#include <QClipboard>
#include <QKeyEvent>
#include "utility/logging/logging.h"
#include "utility/messaging/type/MessageSearch.h"
#include "utility/messaging/type/MessageSearchAutocomplete.h"
#include "utility/text/TextAccess.h"
#include "utility/utility.h"
#include "utility/utilityString.h"
#include "component/view/GraphViewStyle.h"
#include "qt/element/QtAutocompletionList.h"
#include "settings/ColorScheme.h"
QtSearchElement::QtSearchElement(const QString& text, QWidget* parent)
: QPushButton(text, parent)
{
show();
setCheckable(true);
connect(this, SIGNAL(clicked(bool)), this, SLOT(onChecked(bool)));
}
void QtSearchElement::onChecked(bool)
{
emit wasChecked(this);
}
void QtSmartSearchBox::search()
{
editTextToElement();
std::vector<SearchMatch> matches = utility::toVector(m_matches);
LOG_INFO_STREAM(<< "Search query: " << SearchMatch::searchMatchesToString(matches) << text().toStdString());
MessageSearch(matches).dispatch();
}
QtSmartSearchBox::QtSmartSearchBox(QWidget* parent)
: QLineEdit(parent)
, m_allowMultipleElements(false)
, m_allowTextChange(false)
, m_cursorIndex(0)
, m_shiftKeyDown(false)
, m_mousePressed(false)
{
m_highlightRect = new QWidget(this);
m_highlightRect->setGeometry(0, 0, 0, 0);
m_highlightRect->setObjectName("search_box_highlight");
connect(this, SIGNAL(textEdited(const QString&)), this, SLOT(onTextEdited(const QString&)));
connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(onTextChanged(const QString&)));
QCompleter* completer = new QtAutocompletionList(this);
setCompleter(completer);
updatePlaceholder();
}
QtSmartSearchBox::~QtSmartSearchBox()
{
}
void QtSmartSearchBox::setAutocompletionList(const std::vector<SearchMatch>& autocompletionList)
{
// Save the cursor position, because after activating the completer the cursor gets set to the end position.
int cursor = cursorPosition();
QtAutocompletionList* completer = dynamic_cast<QtAutocompletionList*>(this->completer());
completer->completeAt(QPoint(textMargins().left() + 3, height() + 3), autocompletionList);
setCursorPosition(cursor);
connect(completer, SIGNAL(matchHighlighted(const SearchMatch&)), this, SLOT(onAutocompletionHighlighted(const SearchMatch&)), Qt::DirectConnection);
connect(completer, SIGNAL(matchActivated(const SearchMatch&)), this, SLOT(onAutocompletionActivated(const SearchMatch&)), Qt::DirectConnection);
if (autocompletionList.size())
{
m_highlightedMatch = *completer->getSearchMatchAt(0);
}
}
void QtSmartSearchBox::setMatches(const std::vector<SearchMatch>& matches)
{
if (SearchMatch::searchMatchesToString(matches) == SearchMatch::searchMatchesToString(utility::toVector(m_matches)))
{
return;
}
clearLineEdit();
m_matches.clear();
m_matches.insert(m_matches.begin(), matches.begin(), matches.end());
m_cursorIndex = m_matches.size();
updateElements();
}
void QtSmartSearchBox::setFocus()
{
QLineEdit::setFocus(Qt::ShortcutFocusReason);
selectAllElementsWith(true);
layoutElements();
}
bool QtSmartSearchBox::event(QEvent *event)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Tab)
{
if (completer()->popup()->isVisible())
{
addMatchAndUpdate(m_highlightedMatch);
}
else if (m_allowMultipleElements)
{
requestAutoCompletions();
}
return true;
}
}
return QWidget::event(event);
}
void QtSmartSearchBox::resizeEvent(QResizeEvent* event)
{
QLineEdit::resizeEvent(event);
layoutElements();
}
void QtSmartSearchBox::keyPressEvent(QKeyEvent* event)
{
m_shiftKeyDown = event->modifiers() & Qt::ShiftModifier;
if (event->key() == Qt::Key_Return)
{
if (!completer()->popup()->isVisible())
{
search();
}
}
else if (event->key() == Qt::Key_Backspace)
{
if (hasSelectedElements())
{
deleteSelectedElements();
return;
}
else if (!hasSelectedText() && cursorPosition() == 0 && m_cursorIndex > 0)
{
m_elements[m_cursorIndex - 1]->setChecked(true);
deleteSelectedElements();
return;
}
}
else if (event->matches(QKeySequence::Delete))
{
if (hasSelectedElements())
{
deleteSelectedElements();
return;
}
else if (!hasSelectedText() && cursorPosition() == text().size() && m_cursorIndex < m_elements.size())
{
m_elements[m_cursorIndex]->setChecked(true);
deleteSelectedElements();
return;
}
}
else if (event->matches(QKeySequence::MoveToPreviousChar))
{
if (hasSelectedElements())
{
for (size_t i = 0; i < m_elements.size(); i++)
{
if (m_elements[i]->isChecked())
{
m_cursorIndex = i;
break;
}
}
selectAllElementsWith(false);
layoutElements();
}
else if (cursorPosition() == 0 && m_cursorIndex > 0 && !event->isAutoRepeat())
{
editTextToElement();
moveCursor(-1);
return;
}
}
else if (event->matches(QKeySequence::MoveToNextChar))
{
if (hasSelectedElements())
{
for (size_t i = m_elements.size(); i > 0; i--)
{
if (m_elements[i - 1]->isChecked())
{
m_cursorIndex = i;
break;
}
}
selectAllElementsWith(false);
layoutElements();
}
else if (cursorPosition() == text().size() && !event->isAutoRepeat())
{
if (completer()->popup()->isVisible())
{
addMatchAndUpdate(m_highlightedMatch);
}
else if (!editTextToElement())
{
moveCursor(1);
}
return;
}
}
else if (event->matches(QKeySequence::SelectPreviousChar))
{
if (cursorPosition() == 0 && m_cursorIndex > 0)
{
editTextToElement();
m_elements[m_cursorIndex - 1]->setChecked(!m_elements[m_cursorIndex - 1]->isChecked());
moveCursor(-1);
}
}
else if (event->matches(QKeySequence::SelectNextChar))
{
if (cursorPosition() == text().size() && m_cursorIndex < m_elements.size())
{
editTextToElement();
m_elements[m_cursorIndex]->setChecked(!m_elements[m_cursorIndex]->isChecked());
moveCursor(1);
}
}
else if (event->matches(QKeySequence::MoveToStartOfLine))
{
editTextToElement();
moveCursorTo(0);
return;
}
else if (event->matches(QKeySequence::MoveToEndOfLine))
{
if (m_cursorIndex < m_elements.size())
{
editTextToElement();
moveCursorTo(m_elements.size());
return;
}
}
else if (event->matches(QKeySequence::SelectAll))
{
if (m_elements.size())
{
editTextToElement();
selectAllElementsWith(true);
layoutElements();
return;
}
}
else if (event->matches(QKeySequence::Cut))
{
if (hasSelectedElements())
{
std::string str = getSelectedString();
deleteSelectedElements();
QApplication::clipboard()->setText(QString::fromStdString(str));
return;
}
}
else if (event->matches(QKeySequence::Copy))
{
if (hasSelectedElements())
{
std::string str = getSelectedString();
QApplication::clipboard()->setText(QString::fromStdString(str));
return;
}
}
else if (event->matches(QKeySequence::Paste))
{
setEditText(text() + QApplication::clipboard()->text());
onTextEdited(text());
m_allowTextChange = false;
return;
}
QLineEdit::keyPressEvent(event);
}
void QtSmartSearchBox::keyReleaseEvent(QKeyEvent* event)
{
m_shiftKeyDown = event->modifiers() & Qt::ShiftModifier;
}
void QtSmartSearchBox::mouseMoveEvent(QMouseEvent* event)
{
QLineEdit::mouseMoveEvent(event);
if (!m_mousePressed || !m_elements.size())
{
return;
}
int lo = event->x() < m_mouseX ? event->x() : m_mouseX;
int hi = event->x() > m_mouseX ? event->x() : m_mouseX;
for (size_t i = 0; i < m_elements.size(); i++)
{
int widgetX = m_elements[i]->x() + m_elements[i]->width() / 2;
m_elements[i]->setChecked(lo < widgetX && widgetX < hi);
}
editTextToElement();
layoutElements();
}
void QtSmartSearchBox::mousePressEvent(QMouseEvent* event)
{
QLineEdit::mousePressEvent(event);
m_mousePressed = true;
m_mouseX = event->x();
}
void QtSmartSearchBox::mouseReleaseEvent(QMouseEvent* event)
{
QLineEdit::mouseReleaseEvent(event);
m_mousePressed = false;
if (abs(event->x() - m_mouseX) > 5)
{
return;
}
int minDist = event->x();
int pos = 0;
for (size_t i = 0; i < m_elements.size(); i++)
{
int dist = m_elements[i]->x() + m_elements[i]->width() - event->x();
if (abs(dist) < abs(minDist))
{
pos = i + 1;
minDist = dist;
}
}
bool hasSelected = hasSelectedElements();
selectAllElementsWith(false);
if (pos - m_cursorIndex != 0)
{
moveCursor(pos - m_cursorIndex);
}
else if (hasSelected)
{
layoutElements();
}
}
void QtSmartSearchBox::onTextEdited(const QString& text)
{
m_allowTextChange = true;
deleteSelectedElements();
bool matchesChanged = false;
SearchMatch match;
std::deque<SearchMatch> matches = getMatchesForInput(text.toStdString());
while (matches.size())
{
match = matches.front();
matches.pop_front();
if (matches.size() || match.isValid())
{
addMatch(match);
match = SearchMatch();
matchesChanged = true;
}
}
if (match.nameHierarchy.size() && !m_allowMultipleElements)
{
if (m_matches.size())
{
matchesChanged = true;
}
clearMatches();
}
if (matchesChanged)
{
setEditText(QString::fromStdString(match.getFullName()));
updateElements();
}
else
{
layoutElements();
}
if (match.nameHierarchy.size() || m_elements.size())
{
requestAutoCompletions();
}
}
void QtSmartSearchBox::onTextChanged(const QString& text)
{
if (!m_allowTextChange)
{
setText(m_oldText);
}
else
{
m_oldText = text;
}
m_allowTextChange = false;
updatePlaceholder();
}
void QtSmartSearchBox::onAutocompletionHighlighted(const SearchMatch& match)
{
m_highlightedMatch = match;
}
void QtSmartSearchBox::onAutocompletionActivated(const SearchMatch& match)
{
addMatchAndUpdate(match);
if (match.nameHierarchy.size())
{
search();
}
}
void QtSmartSearchBox::onElementSelected(QtSearchElement* element)
{
if (!hasSelectedElements() && !m_shiftKeyDown)
{
editElement(element);
return;
}
size_t idx = 0;
bool checked = element->isChecked();
for (size_t i = 0; i < m_elements.size(); i++)
{
if (m_elements[i].get() == element)
{
idx = i;
break;
}
}
if (text().size())
{
if (m_cursorIndex <= idx)
{
idx++;
}
editTextToElement();
element = m_elements[idx].get();
element->setChecked(checked);
}
if (m_shiftKeyDown)
{
selectElementsTo(idx, checked);
}
else
{
selectAllElementsWith(false);
element->setChecked(true);
m_cursorIndex = idx + 1;
}
layoutElements();
}
void QtSmartSearchBox::moveCursor(int offset)
{
moveCursorTo(m_cursorIndex + offset);
}
void QtSmartSearchBox::moveCursorTo(int target)
{
if (target >= 0 && target <= static_cast<int>(m_elements.size()))
{
m_cursorIndex = target;
layoutElements();
hideAutoCompletions();
}
}
void QtSmartSearchBox::addMatch(const SearchMatch& match)
{
if (!match.nameHierarchy.size())
{
return;
}
const SearchMatch* matchPtr = &match;
if (completer()->popup()->isVisible())
{
const SearchMatch* mPtr = dynamic_cast<QtAutocompletionList*>(completer())->getSearchMatchAt(0);
if (mPtr && utility::equalsCaseInsensitive(match.getFullName(), mPtr->getFullName()))
{
matchPtr = mPtr;
}
}
if (!m_allowMultipleElements)
{
clearMatches();
}
m_matches.insert(m_matches.begin() + m_cursorIndex, *matchPtr);
m_cursorIndex++;
}
void QtSmartSearchBox::addMatchAndUpdate(const SearchMatch& match)
{
if (match.nameHierarchy.size())
{
m_oldText.clear();
clearLineEdit();
addMatch(match);
updateElements();
}
}
void QtSmartSearchBox::clearMatches()
{
m_matches.clear();
m_cursorIndex = 0;
}
void QtSmartSearchBox::setEditText(const QString& text)
{
m_allowTextChange = true;
setText(text);
}
bool QtSmartSearchBox::editTextToElement()
{
if (text().size())
{
addMatch(SearchMatch(text().toStdString()));
clearLineEdit();
updateElements();
return true;
}
return false;
}
void QtSmartSearchBox::editElement(QtSearchElement* element)
{
for (int i = m_elements.size() - 1; i >= 0; i--)
{
if (m_elements[i].get() == element)
{
m_cursorIndex = i;
break;
}
}
std::string name = m_matches[m_cursorIndex].getFullName();
m_matches.erase(m_matches.begin() + m_cursorIndex);
setEditText(QString::fromStdString(name));
updateElements();
requestAutoCompletions();
}
void QtSmartSearchBox::updateElements()
{
m_elements.clear();
ColorScheme* scheme = ColorScheme::getInstance().get();
std::string searchTextColor = scheme->getColor("search/field/text");
for (const SearchMatch& match : m_matches)
{
std::string name = match.getFullName();
name = utility::replace(name, "&", "&&");
std::shared_ptr<QtSearchElement> element = std::make_shared<QtSearchElement>(QString::fromStdString(name), this);
m_elements.push_back(element);
std::string color;
std::string hoverColor;
std::string textColor = searchTextColor;
std::string textHoverColor = searchTextColor;
if (match.searchType == SearchMatch::SEARCH_TOKEN)
{
element->setObjectName(QString::fromStdString("search_element_" + match.getNodeTypeAsString()));
color = GraphViewStyle::getNodeColor(Node::getTypeString(match.nodeType), false).fill;
hoverColor = GraphViewStyle::getNodeColor(Node::getTypeString(match.nodeType), true).fill;
textColor = GraphViewStyle::getNodeColor(Node::getTypeString(match.nodeType), false).text;
textHoverColor = GraphViewStyle::getNodeColor(Node::getTypeString(match.nodeType), true).text;
}
else
{
std::string typeName = match.getSearchTypeName();
element->setObjectName(QString::fromStdString("search_element_" + typeName));
color = scheme->getSearchTypeColor(typeName);
hoverColor = scheme->getSearchTypeColor(typeName, "hover");
}
std::stringstream css;
css << "QPushButton { border: none; padding: 0px 4px; background-color:" << color << "; color:" << textColor << ";} ";
css << "QPushButton:hover { background-color:" << hoverColor << "; color:" << textHoverColor << ";} ";
element->setStyleSheet(css.str().c_str());
connect(element.get(), SIGNAL(wasChecked(QtSearchElement*)), this, SLOT(onElementSelected(QtSearchElement*)));
}
updatePlaceholder();
hideAutoCompletions();
layoutElements();
}
void QtSmartSearchBox::layoutElements()
{
ensurePolished();
bool hasSelected = hasSelectedElements();
QString cursorText = text();
cursorText.resize(cursorPosition());
int x = 5;
int editX = x;
int cursorX = fontMetrics().width(cursorText) + x;
std::vector<int> elementX;
int highlightBegin = 0;
int highlightEnd = 0;
for (size_t i = 0; i <= m_elements.size(); i++)
{
if (!hasSelected && i == m_cursorIndex)
{
editX = x - 5;
cursorX += editX;
if (i != m_elements.size())
{
cursorX += 15;
}
x += fontMetrics().width(text());
}
if (i < m_elements.size())
{
QtSearchElement* button = m_elements[i].get();
if (button->isChecked() && !highlightBegin)
{
highlightBegin = x - 2;
}
elementX.push_back(x);
x += button->minimumSizeHint().width() + 5;
if (button->isChecked())
{
highlightEnd = x - 3;
}
}
}
int offsetX = 0;
if (cursorX > width())
{
offsetX = width() - cursorX;
}
for (size_t i = 0; i < elementX.size(); i++)
{
QtSearchElement* button = m_elements[i].get();
QSize size = button->minimumSizeHint();
int y = (rect().height() - size.height()) / 2.0;
button->setGeometry(elementX[i] + offsetX, y, size.width(), size.height());
}
if (hasSelected)
{
setTextMargins(width() + 10, 0, 0, 0);
m_highlightRect->setGeometry(highlightBegin + offsetX, 0, highlightEnd - highlightBegin, height());
}
else
{
QMargins margins = textMargins();
setTextMargins(editX + offsetX, margins.top(), margins.right(), margins.bottom());
m_highlightRect->setGeometry(0, 0, 0, 0);
}
}
bool QtSmartSearchBox::hasSelectedElements() const
{
for (const std::shared_ptr<QtSearchElement> element : m_elements)
{
if (element->isChecked())
{
return true;
}
}
return false;
}
std::string QtSmartSearchBox::getSelectedString() const
{
std::string str;
for (size_t i = 0; i < m_elements.size(); i++)
{
if (m_elements[i]->isChecked())
{
str += m_matches[i].getFullName();
}
}
return str;
}
void QtSmartSearchBox::selectAllElementsWith(bool selected)
{
for (const std::shared_ptr<QtSearchElement> element : m_elements)
{
element->setChecked(selected);
}
}
void QtSmartSearchBox::selectElementsTo(size_t idx, bool selected)
{
size_t low = idx < m_cursorIndex ? idx : m_cursorIndex;
size_t hi = idx > m_cursorIndex ? idx + 1 : m_cursorIndex;
while (low < hi)
{
m_elements[low]->setChecked(selected);
low++;
}
if (!selected)
{
m_elements[idx]->setChecked(true);
}
if (idx < m_cursorIndex)
{
m_cursorIndex = idx;
}
else
{
m_cursorIndex = idx + 1;
}
}
void QtSmartSearchBox::deleteSelectedElements()
{
if (!hasSelectedElements())
{
return;
}
for (size_t i = m_elements.size(); i > 0; i--)
{
if (m_elements[i - 1]->isChecked())
{
m_matches.erase(m_matches.begin() + (i - 1));
if ((i - 1) < m_cursorIndex)
{
m_cursorIndex--;
}
}
}
updateElements();
}
void QtSmartSearchBox::updatePlaceholder()
{
if (!text().size() && !m_elements.size())
{
setPlaceholderText("Search");
}
else
{
setPlaceholderText("");
}
}
void QtSmartSearchBox::clearLineEdit()
{
setEditText("");
hideAutoCompletions();
}
void QtSmartSearchBox::requestAutoCompletions() const
{
MessageSearchAutocomplete(text().toStdString()).dispatch();
}
void QtSmartSearchBox::hideAutoCompletions()
{
completer()->popup()->hide();
}
std::deque<SearchMatch> QtSmartSearchBox::getMatchesForInput(const std::string& text) const
{
std::deque<SearchMatch> matches;
if (text.size())
{
matches.push_back(SearchMatch(text));
}
return matches;
}
+112
View File
@@ -0,0 +1,112 @@
#ifndef QT_SMART_SEARCH_BOX_H
#define QT_SMART_SEARCH_BOX_H
#include <deque>
#include <memory>
#include <QLineEdit>
#include <QPushButton>
#include "data/search/SearchMatch.h"
class QtSearchElement
: public QPushButton
{
Q_OBJECT
signals:
void wasChecked(QtSearchElement*);
public:
QtSearchElement(const QString& text, QWidget* parent);
private slots:
void onChecked(bool);
};
class QtSmartSearchBox
: public QLineEdit
{
Q_OBJECT
public slots:
void search();
public:
QtSmartSearchBox(QWidget* parent);
virtual ~QtSmartSearchBox();
void setAutocompletionList(const std::vector<SearchMatch>& autocompletionList);
void setMatches(const std::vector<SearchMatch>& matches);
void setFocus();
protected:
virtual bool event(QEvent *event);
virtual void resizeEvent(QResizeEvent* event);
virtual void keyPressEvent(QKeyEvent* event);
virtual void keyReleaseEvent(QKeyEvent* event);
virtual void mouseMoveEvent(QMouseEvent* event);
virtual void mousePressEvent(QMouseEvent* event);
virtual void mouseReleaseEvent(QMouseEvent* event);
private slots:
void onTextEdited(const QString& text);
void onTextChanged(const QString& text);
void onAutocompletionHighlighted(const SearchMatch& match);
void onAutocompletionActivated(const SearchMatch& match);
void onElementSelected(QtSearchElement* element);
private:
void moveCursor(int offset);
void moveCursorTo(int goal);
void addMatch(const SearchMatch& match);
void addMatchAndUpdate(const SearchMatch& match);
void clearMatches();
void setEditText(const QString& text);
bool editTextToElement();
void editElement(QtSearchElement* element);
void updateElements();
void layoutElements();
bool hasSelectedElements() const;
std::string getSelectedString() const;
void selectAllElementsWith(bool selected);
void selectElementsTo(size_t idx, bool selected);
void deleteSelectedElements();
void updatePlaceholder();
void clearLineEdit();
void requestAutoCompletions() const;
void hideAutoCompletions();
std::deque<SearchMatch> getMatchesForInput(const std::string& text) const;
bool m_allowMultipleElements;
bool m_allowTextChange;
QString m_oldText;
std::deque<SearchMatch> m_matches;
std::vector<std::shared_ptr<QtSearchElement>> m_elements;
size_t m_cursorIndex;
SearchMatch m_highlightedMatch;
bool m_shiftKeyDown;
bool m_mousePressed;
int m_mouseX;
QWidget* m_highlightRect;
};
#endif // QT_SMART_SEARCH_BOX_H
+81
View File
@@ -0,0 +1,81 @@
#include "qt/element/QtStatusBar.h"
#include <QMovie>
#include "qt/utility/utilityQt.h"
#include "utility/messaging/type/MessageShowErrors.h"
QtStatusBar::QtStatusBar()
: m_text(this)
{
QMovie* movie = new QMovie("data/gui/statusbar_view/loader.gif");
// if movie doesn't loop forever, force it to.
if (movie->loopCount() != -1)
{
connect(movie, SIGNAL(finished()), movie, SLOT(start()));
}
movie->start();
m_loader.setMovie(movie);
m_loader.hide();
addWidget(&m_loader);
m_text.setText("");
addWidget(&m_text);
m_errorButton.hide();
m_errorButton.setFlat(true);
m_errorButton.setStyleSheet("QPushButton { color: #D00000; margin-right: 0; spacing: none; }");
m_errorButton.setIcon(utility::colorizePixmap(
QPixmap("data/gui/statusbar_view/octagon.png"),
"#D00000"
).scaledToHeight(10));
addPermanentWidget(&m_errorButton);
connect(&m_errorButton, SIGNAL(clicked()), this, SLOT(showErrors()));
}
QtStatusBar::~QtStatusBar()
{
}
void QtStatusBar::setText(const std::string& text, bool isError, bool showLoader)
{
if (isError)
{
m_text.setStyleSheet("QLabel { color: #D00000 }");
}
else
{
m_text.setStyleSheet("");
}
if (showLoader)
{
m_loader.show();
}
else
{
m_loader.hide();
}
m_text.setText(text.c_str());
}
void QtStatusBar::setErrorCount(size_t count)
{
if (count > 0)
{
m_errorButton.setText(QString::number(count) + " error(s)");
m_errorButton.show();
}
else
{
m_errorButton.hide();
}
}
void QtStatusBar::showErrors()
{
MessageShowErrors().dispatch();
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef QT_STATUS_BAR_H
#define QT_STATUS_BAR_H
#include <string>
#include <QPushButton>
#include <QLabel>
#include <QStatusBar>
class QtStatusBar
: public QStatusBar
{
Q_OBJECT
public:
QtStatusBar(void);
virtual ~QtStatusBar(void);
void setText(const std::string& text, bool isError, bool showLoader);
void setErrorCount(size_t count);
private slots:
void showErrors();
private:
QLabel m_text;
QLabel m_loader;
QPushButton m_errorButton;
};
#endif // QT_STATUS_BAR_H
+83
View File
@@ -0,0 +1,83 @@
#include "qt/element/QtUndoRedo.h"
#include <QPushButton>
#include <QHBoxLayout>
#include "utility/messaging/type/MessageUndo.h"
#include "utility/messaging/type/MessageRedo.h"
#include "qt/utility/utilityQt.h"
#include "settings/ApplicationSettings.h"
#include "settings/ColorScheme.h"
QtUndoRedo::QtUndoRedo()
{
setObjectName("undo_redo_bar");
m_undoButton = new QPushButton(this);
m_undoButton->setObjectName("undo_button");
m_undoButton->setToolTip("undo");
m_undoButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
m_undoButton->setEnabled(false);
m_redoButton = new QPushButton(this);
m_redoButton->setObjectName("redo_button");
m_redoButton->setToolTip("redo");
m_redoButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
m_redoButton->setEnabled(false);
QBoxLayout* layout = new QHBoxLayout();
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
layout->addWidget(m_undoButton);
layout->addWidget(m_redoButton);
connect(m_undoButton, SIGNAL(clicked()), this, SLOT(undo()));
connect(m_redoButton, SIGNAL(clicked()), this, SLOT(redo()));
refreshStyle();
}
QtUndoRedo::~QtUndoRedo()
{
}
void QtUndoRedo::undo()
{
MessageUndo().dispatch();
}
void QtUndoRedo::redo()
{
MessageRedo().dispatch();
}
void QtUndoRedo::setUndoButtonEnabled(bool enabled)
{
m_undoButton->setEnabled(enabled);
}
void QtUndoRedo::setRedoButtonEnabled(bool enabled)
{
m_redoButton->setEnabled(enabled);
}
void QtUndoRedo::refreshStyle()
{
float height = std::max(ApplicationSettings::getInstance()->getFontSize() + 16, 30);
m_undoButton->setFixedHeight(height);
m_redoButton->setFixedHeight(height);
m_undoButton->setIcon(utility::colorizePixmap(
QPixmap("data/gui/undoredo_view/images/arrow_left.png"),
ColorScheme::getInstance()->getColor("search/button/icon").c_str()
));
m_redoButton->setIcon(utility::colorizePixmap(
QPixmap("data/gui/undoredo_view/images/arrow_right.png"),
ColorScheme::getInstance()->getColor("search/button/icon").c_str()
));
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef QT_UNDO_REDO_H
#define QT_UNDO_REDO_H
#include <string>
#include <QFrame>
class QPushButton;
class QtUndoRedo
: public QFrame
{
Q_OBJECT
public:
QtUndoRedo();
~QtUndoRedo();
void setRedoButtonEnabled(bool enabled);
void setUndoButtonEnabled(bool enabled);
void refreshStyle();
private slots:
void undo();
void redo();
private:
QPushButton* m_undoButton;
QPushButton* m_redoButton;
};
#endif // QT_UNDO_REDO_H
@@ -0,0 +1,317 @@
#include "qt/graphics/QtAngledLineItem.h"
#include <cmath>
#include <QPainter>
#include "utility/math/Vector2.h"
QtAngledLineItem::QtAngledLineItem(QGraphicsItem* parent)
: QGraphicsLineItem(parent)
, m_onBack(false)
, m_horizontalIn(false)
{
this->setAcceptHoverEvents(true);
}
QtAngledLineItem::~QtAngledLineItem()
{
}
void QtAngledLineItem::updateLine(
Vec4i ownerRect, Vec4i targetRect,
Vec4i ownerParentRect, Vec4i targetParentRect,
GraphViewStyle::EdgeStyle style
){
prepareGeometryChange();
m_ownerRect = ownerRect;
m_targetRect = targetRect;
m_ownerParentRect = ownerParentRect;
m_targetParentRect = targetParentRect;
m_ownerRect.x = m_ownerRect.x - 1;
m_ownerRect.z = m_ownerRect.z + 1;
m_targetRect.x = m_targetRect.x - 1;
m_targetRect.z = m_targetRect.z + 1;
m_style = style;
this->setPen(QPen(QBrush(style.color.c_str()), style.width, Qt::SolidLine, Qt::RoundCap));
}
void QtAngledLineItem::setOnBack(bool back)
{
m_onBack = back;
}
void QtAngledLineItem::setHorizontalIn(bool horizontal)
{
m_horizontalIn = horizontal;
}
QPainterPath QtAngledLineItem::shape() const
{
int w = m_style.arrowWidth / 2 + 1;
QPainterPath path;
QPolygon poly = getPath();
for (int i = 0; i < poly.size() - 1; i++)
{
path.addRect(QRectF(poly.at(i), poly.at(i + 1)).normalized().adjusted(-w, -w, w, w));
}
return path;
}
void QtAngledLineItem::paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget)
{
painter->setPen(pen());
QPainterPath path;
QPolygon poly = getPath();
int i = poly.length() - 1;
path.moveTo(poly.at(i));
int radius = m_style.cornerRadius;
int dir = getDirection(poly.at(i), poly.at(i - 1));
while (i > 1)
{
i--;
QPointF a = poly.at(i);
QPointF b = poly.at(i - 1);
int newDir = getDirection(a, b);
int ar = radius;
int br = m_style.cornerRadius;
if (i != 1)
{
if (dir % 2 == 1 && std::abs(a.y() - b.y()) < 2 * br)
{
br = std::abs(a.y() - b.y()) / 2;
}
else if (dir % 2 == 0 && std::abs(a.x() - b.x()) < 2 * br)
{
br = std::abs(a.x() - b.x()) / 2;
}
}
switch (dir)
{
case 0: a.setY(a.y() + ar); break;
case 1: a.setX(a.x() - ar); break;
case 2: a.setY(a.y() - ar); break;
case 3: a.setX(a.x() + ar); break;
}
b = poly.at(i);
switch (newDir)
{
case 0: b.setY(b.y() - br); break;
case 1: b.setX(b.x() + br); break;
case 2: b.setY(b.y() + br); break;
case 3: b.setX(b.x() - br); break;
}
switch (dir)
{
case 0:
if (newDir == 1)
{
path.arcTo(a.x(), b.y(), 2 * br, 2 * ar, 180, -90);
}
else if (newDir == 3)
{
path.arcTo(b.x() - br, a.y() - ar, 2 * br, 2 * ar, 0, 90);
}
break;
case 1:
if (newDir == 0)
{
path.arcTo(a.x() - ar, b.y() - br, 2 * ar, 2 * br, -90, 90);
}
else if (newDir == 2)
{
path.arcTo(a.x() - ar, a.y(), 2 * ar, 2 * br, 90, -90);
}
break;
case 2:
if (newDir == 1)
{
path.arcTo(a.x(), a.y() - ar, 2 * br, 2 * ar, 180, 90);
}
else if (newDir == 3)
{
path.arcTo(b.x() - br, a.y() - ar, 2 * br, 2 * ar, 0, -90);
}
break;
case 3:
if (newDir == 0)
{
path.arcTo(b.x(), b.y() - br, 2 * ar, 2 * br, -90, -90);
}
else if (newDir == 2)
{
path.arcTo(b.x(), a.y(), 2 * ar, 2 * br, 90, 90);
}
break;
}
dir = newDir;
radius = br;
}
QPointF arrow = poly.at(0) + QPointF((poly.at(0).x() - poly.at(1).x() > 0 ? -1 : 1) * m_style.arrowLength, 0);
if (m_style.arrowClosed)
{
path.lineTo(arrow);
path.moveTo(poly.at(0));
}
else
{
path.lineTo(poly.at(0));
}
arrow.setY(arrow.y() - m_style.arrowWidth / 2);
path.lineTo(arrow);
arrow.setY(arrow.y() + m_style.arrowWidth);
if (m_style.arrowClosed)
{
path.lineTo(arrow);
}
else
{
path.moveTo(arrow);
}
path.lineTo(poly.at(0));
painter->drawPath(path);
}
QPolygon QtAngledLineItem::getPath() const
{
const Vec4i& oR = m_ownerRect;
const Vec4i& tR = m_targetRect;
Vec2f o[2] = { Vec2f(m_ownerParentRect.x, (2 * oR.y + oR.w) / 3), Vec2f(m_ownerParentRect.z, (2 * oR.y + oR.w) / 3) };
Vec2f t[2] = { Vec2f(m_targetParentRect.x, (tR.y + 2 * tR.w) / 3), Vec2f(m_targetParentRect.z, (tR.y + 2 * tR.w) / 3) };
int io = -1;
int it = -1;
float dist = -1;
if (m_onBack)
{
io = 1;
it = 1;
}
else
{
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
Vec2f diff = o[i] - t[j];
if (dist < 0 || diff.getLength() < dist)
{
dist = diff.getLength();
io = i;
it = j;
}
}
}
}
QPoint tp((it ? 1 : -1) * m_style.targetOffset.x + t[it].x, t[it].y + m_style.targetOffset.y);
QPoint op((io ? 1 : -1) * m_style.originOffset.x + o[io].x, o[io].y + m_style.originOffset.y);
if (it != io)
{
if (it && tp.x() < op.x())
{
io = 0;
op = QPoint(o[io].x - m_style.originOffset.x, o[io].y + m_style.originOffset.y);
}
else if (!it && tp.x() < op.x())
{
it = 1;
tp = QPoint(t[it].x + m_style.targetOffset.x, t[it].y + m_style.targetOffset.y);
}
else if (io && tp.x() > op.x())
{
io = 1;
op = QPoint(o[io].x + m_style.originOffset.x, o[io].y + m_style.originOffset.y);
}
else if (!io && tp.x() > op.x())
{
it = 0;
tp = QPoint(t[it].x - m_style.targetOffset.x, t[it].y + m_style.targetOffset.y);
}
}
if (it == io && ((it && tp.x() < op.x()) || (!it && tp.x() > op.x())))
{
tp.setX(op.x());
}
else if (it != io && m_horizontalIn)
{
tp.setX(op.x());
}
else
{
op.setX(tp.x());
}
o[0] = Vec2f(oR.x, (2 * oR.y + oR.w) / 3);
o[1] = Vec2f(oR.z, (2 * oR.y + oR.w) / 3);
t[0] = Vec2f(tR.x, (tR.y + 2 * tR.w) / 3);
t[1] = Vec2f(tR.z, (tR.y + 2 * tR.w) / 3);
if (o[io].y < t[it].y)
{
op.setX(op.x() + m_style.verticalOffset);
tp.setX(tp.x() + m_style.verticalOffset);
}
else
{
op.setX(op.x() - m_style.verticalOffset);
tp.setX(tp.x() - m_style.verticalOffset);
}
QPolygon poly;
poly << QPoint(t[it].x, t[it].y + m_style.targetOffset.y);
poly << tp;
poly << op;
poly << QPoint(o[io].x, o[io].y + m_style.originOffset.y);
return poly;
}
int QtAngledLineItem::getDirection(const QPointF& a, const QPointF& b) const
{
if (a.x() != b.x())
{
if (a.x() < b.x())
{
return 1;
}
else
{
return 3;
}
}
else
{
if (a.y() < b.y())
{
return 2;
}
else
{
return 0;
}
}
}
@@ -0,0 +1,44 @@
#ifndef QT_ANGLED_LINE_ITEM_H
#define QT_ANGLED_LINE_ITEM_H
#include <QGraphicsItem>
#include "utility/math/Vector4.h"
#include "component/view/GraphViewStyle.h"
class QtAngledLineItem
: public QGraphicsLineItem
{
public:
QtAngledLineItem(QGraphicsItem* parent);
virtual ~QtAngledLineItem();
void updateLine(
Vec4i ownerRect, Vec4i targetRect,
Vec4i ownerParentRect, Vec4i targetParentRect,
GraphViewStyle::EdgeStyle style);
void setOnBack(bool back);
void setHorizontalIn(bool horizontal);
virtual QPainterPath shape() const;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget);
private:
QPolygon getPath() const;
int getDirection(const QPointF& a, const QPointF& b) const;
Vec4i m_ownerRect;
Vec4i m_targetRect;
Vec4i m_ownerParentRect;
Vec4i m_targetParentRect;
GraphViewStyle::EdgeStyle m_style;
bool m_onBack;
bool m_horizontalIn;
};
#endif // QT_ANGLED_LINE_ITEM_H
@@ -0,0 +1,57 @@
#include "qt/graphics/QtCountCircleItem.h"
#include <QFont>
#include <QFontMetrics>
#include <QPen>
#include "component/view/GraphViewStyle.h"
QtCountCircleItem::QtCountCircleItem(QGraphicsItem* parent)
: QtRoundedRectItem(parent)
{
this->setRadius(100);
this->setAcceptHoverEvents(true);
QFont font;
font.setFamily(GraphViewStyle::getFontNameOfExpandToggleNode().c_str());
font.setPixelSize(GraphViewStyle::getFontSizeOfCountCircle());
font.setWeight(QFont::Normal);
m_number = new QGraphicsSimpleTextItem(this);
m_number->setFont(font);
}
QtCountCircleItem::~QtCountCircleItem()
{
}
void QtCountCircleItem::setPosition(const Vec2f& pos)
{
qreal radius = getRadius();
this->setRect(pos.x - radius, pos.y - radius, 2 * radius, 2 * radius);
m_number->setPos(
pos.x - radius + 5,
pos.y - QFontMetrics(m_number->font()).height() / 2
);
}
void QtCountCircleItem::setNumber(size_t number)
{
QString numberStr = QString::number(number);
m_number->setText(numberStr);
qreal radius = QFontMetrics(m_number->font()).width(numberStr) / 2 + 5;
this->setRadius(radius);
QPointF center = this->rect().center();
this->setPosition(Vec2f(center.x(), center.y()));
}
void QtCountCircleItem::setStyle(QColor color, QColor fontColor, QColor borderColor, size_t borderWidth)
{
this->setBrush(color);
this->setPen(QPen(borderColor, borderWidth));
m_number->setBrush(fontColor);
}
@@ -0,0 +1,23 @@
#ifndef QT_COUNT_CIRCLE_ITEM_H
#define QT_COUNT_CIRCLE_ITEM_H
#include "utility/math/Vector2.h"
#include "qt/graphics/QtRoundedRectItem.h"
class QtCountCircleItem
: public QtRoundedRectItem
{
public:
QtCountCircleItem(QGraphicsItem* parent);
virtual ~QtCountCircleItem();
void setPosition(const Vec2f& pos);
void setNumber(size_t number);
void setStyle(QColor color, QColor fontColor, QColor borderColor, size_t borderWidth);
private:
QGraphicsSimpleTextItem* m_number;
};
#endif // QT_COUNT_CIRCLE_ITEM_H
@@ -0,0 +1,52 @@
#include "qt/graphics/QtRoundedRectItem.h"
#include <QGraphicsDropShadowEffect>
#include <QPainter>
QtRoundedRectItem::QtRoundedRectItem(QGraphicsItem* parent)
: QGraphicsRectItem(parent)
, m_radius(0.0f)
{
this->setZValue(-1.0f);
}
QtRoundedRectItem::~QtRoundedRectItem()
{
}
void QtRoundedRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget)
{
painter->setPen(pen());
painter->setBrush(brush());
painter->setRenderHint(QPainter::Antialiasing);
painter->drawRoundedRect(this->rect(), m_radius, m_radius);
}
void QtRoundedRectItem::setShadow(QColor color, int blurRadius)
{
QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect();
effect->setColor(color);
effect->setBlurRadius(5);
effect->setOffset(0, 0);
this->setGraphicsEffect(effect);
}
void QtRoundedRectItem::setShadowEnabled(bool enabled)
{
if (this->graphicsEffect())
{
this->graphicsEffect()->setEnabled(enabled);
}
}
qreal QtRoundedRectItem::getRadius() const
{
return m_radius;
}
void QtRoundedRectItem::setRadius(qreal radius)
{
m_radius = radius;
}
@@ -0,0 +1,25 @@
#ifndef QT_GRAPHICS_ROUNDED_RECT_ITEM_H
#define QT_GRAPHICS_ROUNDED_RECT_ITEM_H
#include <QGraphicsRectItem>
class QtRoundedRectItem
: public QGraphicsRectItem
{
public:
QtRoundedRectItem(QGraphicsItem* parent);
virtual ~QtRoundedRectItem();
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget);
void setShadow(QColor color, int blurRadius);
void setShadowEnabled(bool enabled);
qreal getRadius() const;
void setRadius(qreal radius);
private:
qreal m_radius;
};
#endif // QT_GRAPHICS_ROUNDED_RECT_ITEM_H
@@ -0,0 +1,110 @@
#include "qt/graphics/QtStraightLineItem.h"
#include <QBrush>
#include <QPen>
#include "utility/math/Vector2.h"
#include "utility/utility.h"
#include "qt/graphics/QtCountCircleItem.h"
QtStraightLineItem::QtStraightLineItem(QGraphicsItem* parent)
: QGraphicsLineItem(parent)
{
this->setAcceptHoverEvents(true);
m_circle = new QtCountCircleItem(this);
m_arrowLeft = new QGraphicsLineItem(this);
m_arrowRight = new QGraphicsLineItem(this);
}
QtStraightLineItem::~QtStraightLineItem()
{
}
void QtStraightLineItem::updateLine(
Vec4i ownerRect, Vec4i targetRect, int number,
GraphViewStyle::EdgeStyle style, GraphViewStyle::NodeStyle countStyle, bool showArrow
){
prepareGeometryChange();
const Vec4i& o = ownerRect;
const Vec4i& t = targetRect;
Vec2f oc((o.x + o.z) / 2, (o.y + o.w) / 2);
Vec2f tc((t.x + t.z) / 2, (t.y + t.w) / 2);
Vec2f op;
Vec2f tp;
bool intersects = false;
for (int i = 0; !intersects && i < 4; i++)
{
switch (i)
{
case 0: intersects = utility::intersectionPoint(oc, tc, Vec2f(o.x, o.y), Vec2f(o.x, o.w), &op); break;
case 1: intersects = utility::intersectionPoint(oc, tc, Vec2f(o.x, o.y), Vec2f(o.z, o.y), &op); break;
case 2: intersects = utility::intersectionPoint(oc, tc, Vec2f(o.z, o.y), Vec2f(o.z, o.w), &op); break;
case 3: intersects = utility::intersectionPoint(oc, tc, Vec2f(o.x, o.w), Vec2f(o.z, o.w), &op); break;
}
}
if (!intersects)
{
op = oc;
}
intersects = false;
for (int i = 0; !intersects && i < 4; i++)
{
switch (i)
{
case 0: intersects = utility::intersectionPoint(oc, tc, Vec2f(t.x, t.y), Vec2f(t.x, t.w), &tp); break;
case 1: intersects = utility::intersectionPoint(oc, tc, Vec2f(t.x, t.y), Vec2f(t.z, t.y), &tp); break;
case 2: intersects = utility::intersectionPoint(oc, tc, Vec2f(t.z, t.y), Vec2f(t.z, t.w), &tp); break;
case 3: intersects = utility::intersectionPoint(oc, tc, Vec2f(t.x, t.w), Vec2f(t.z, t.w), &tp); break;
}
}
if (!intersects)
{
tp = tc;
}
this->setLine(oc.x, oc.y, tc.x, tc.y);
Vec2f mid = (op + tp) / 2;
m_circle->setPosition(mid);
m_circle->setNumber(number);
size_t radius = m_circle->getRadius();
if (showArrow)
{
Vec2f unit = (tp - op).normalize();
Vec2f nUnit(-unit.y, unit.x);
Vec2f arrow = mid + unit * (radius + 13);
Vec2f arrowSide = mid + unit * (radius + 6) + nUnit * 7;
m_arrowRight->setLine(arrow.x, arrow.y, arrowSide.x, arrowSide.y);
arrowSide -= nUnit * 14;
m_arrowLeft->setLine(arrow.x, arrow.y, arrowSide.x, arrowSide.y);
m_arrowLeft->show();
m_arrowRight->show();
}
else
{
m_arrowLeft->hide();
m_arrowRight->hide();
}
this->setPen(QPen(QBrush(style.color.c_str()), style.width, Qt::SolidLine, Qt::RoundCap));
m_circle->setStyle(countStyle.color.fill.c_str(), countStyle.color.text.c_str(), countStyle.color.border.c_str(), 1);
m_arrowLeft->setPen(QPen(QBrush(countStyle.color.border.c_str()), 1, Qt::SolidLine, Qt::RoundCap));
m_arrowRight->setPen(QPen(QBrush(countStyle.color.border.c_str()), 1, Qt::SolidLine, Qt::RoundCap));
}
@@ -0,0 +1,30 @@
#ifndef QT_STRAIGHT_LINE_ITEM_H
#define QT_STRAIGHT_LINE_ITEM_H
#include <QGraphicsItem>
#include "utility/math/Vector4.h"
#include "component/view/GraphViewStyle.h"
class QtCountCircleItem;
class QtStraightLineItem
: public QGraphicsLineItem
{
public:
QtStraightLineItem(QGraphicsItem* parent);
virtual ~QtStraightLineItem();
void updateLine(
Vec4i ownerRect, Vec4i targetRect, int number,
GraphViewStyle::EdgeStyle style, GraphViewStyle::NodeStyle countStyle, bool showArrow);
private:
QtCountCircleItem* m_circle;
QGraphicsLineItem* m_arrowLeft;
QGraphicsLineItem* m_arrowRight;
};
#endif // QT_STRAIGHT_LINE_ITEM_H
@@ -0,0 +1,23 @@
#include "QtIDECommunicationController.h"
#include <functional>
QtIDECommunicationController::QtIDECommunicationController(QObject* parent, StorageAccess* storageAccess)
: IDECommunicationController(storageAccess)
, m_tcpWrapper(parent)
{
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
m_tcpWrapper.setReadCallback(std::bind(&QtIDECommunicationController::handleIncomingMessage, this, std::placeholders::_1));
m_tcpWrapper.setServerPort(appSettings->getCoatiPort());
m_tcpWrapper.setClientPort(appSettings->getPluginPort());
m_tcpWrapper.startListening();
}
QtIDECommunicationController::~QtIDECommunicationController()
{}
void QtIDECommunicationController::sendMessage(const std::string& message) const
{
m_tcpWrapper.sendMessage(message);
}
@@ -0,0 +1,26 @@
#ifndef QT_IDE_COMMUNICATION_CONTROLLER
#define QT_IDE_COMMUNICATION_CONTROLLER
#include <qobject.h>
#include "QtTcpWrapper.h"
#include "component/controller/IDECommunicationController.h"
#include "settings/ApplicationSettings.h"
class StorageAccess;
class QtIDECommunicationController
: public IDECommunicationController
{
public:
QtIDECommunicationController(QObject* parent, StorageAccess* storageAccess);
~QtIDECommunicationController();
private:
virtual void sendMessage(const std::string& message) const;
QtTcpWrapper m_tcpWrapper;
};
#endif // QT_IDE_COMMUNICATION_CONTROLLER
@@ -0,0 +1,16 @@
#include "QtNetworkFactory.h"
#include "QtIDECommunicationController.h"
QtNetworkFactory::QtNetworkFactory()
{
}
QtNetworkFactory::~QtNetworkFactory()
{
}
std::shared_ptr<IDECommunicationController> QtNetworkFactory::createIDECommunicationController(StorageAccess* storageAccess) const
{
return std::make_shared<QtIDECommunicationController>(nullptr, storageAccess);
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef QT_NETWORK_FACTORY_H
#define QT_NETWORK_FACTORY_H
#include "component/controller/NetworkFactory.h"
class QtNetworkFactory : public NetworkFactory
{
public:
QtNetworkFactory();
virtual ~QtNetworkFactory();
virtual std::shared_ptr<IDECommunicationController> createIDECommunicationController(StorageAccess* storageAccess) const;
};
#endif // QT_NETWORK_FACTORY_H
+99
View File
@@ -0,0 +1,99 @@
#include "QtTcpWrapper.h"
#include "utility/logging/logging.h"
QtTcpWrapper::QtTcpWrapper(QObject* parent, const std::string& ip, const quint16 serverPort, const quint16 clientPort)
: QObject(parent)
, m_serverPort(serverPort)
, m_clientPort(clientPort)
, m_ip(ip)
{
}
void QtTcpWrapper::startListening()
{
QHostAddress address(m_ip.c_str());
m_tcpServer = new QTcpServer(this);
connect(m_tcpServer, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
if (!m_tcpServer->listen(QHostAddress::LocalHost, m_serverPort))
{
LOG_ERROR_STREAM(<< "TCP server failed to start with error: \"" + m_tcpServer->errorString().toStdString() + "\". Unable to listen for IDE plugin messages.");
}
}
QtTcpWrapper::~QtTcpWrapper()
{
if (m_tcpServer != NULL)
{
if (m_tcpServer->isListening())
{
m_tcpServer->close();
}
delete m_tcpServer;
}
}
void QtTcpWrapper::sendMessage(const std::string& message) const
{
QByteArray data;
data.append(message.c_str());
QTcpSocket socket;
socket.connectToHost(QHostAddress::LocalHost, 6666);
if (socket.waitForConnected())
{
socket.write(data);
socket.flush();
socket.waitForBytesWritten();
socket.close();
}
}
void QtTcpWrapper::setReadCallback(const std::function<void(const std::string&)>& callback)
{
m_readCallback = callback;
}
quint16 QtTcpWrapper::getServerPort() const
{
return m_serverPort;
}
void QtTcpWrapper::setServerPort(const quint16 serverPort)
{
m_serverPort = serverPort;
}
quint16 QtTcpWrapper::getClientPort() const
{
return m_clientPort;
}
void QtTcpWrapper::setClientPort(const quint16 clientPort)
{
m_clientPort = clientPort;
}
void QtTcpWrapper::acceptConnection()
{
m_tcpClient = m_tcpServer->nextPendingConnection();
connect(m_tcpClient, SIGNAL(readyRead()), this, SLOT(startRead()));
}
void QtTcpWrapper::startRead()
{
char buffer[1024] = { 0 };
m_tcpClient->read(buffer, m_tcpClient->bytesAvailable());
m_tcpClient->close();
if (m_readCallback != NULL)
{
m_readCallback(buffer);
}
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef QT_SOCKET_WRAPPER_H
#define QT_SOCKET_WRAPPER_H
#include <functional>
#include <qobject.h>
#include <qudpsocket.h>
#include <qtcpserver.h>
#include <qtcpsocket.h>
class QtTcpWrapper : public QObject
{
Q_OBJECT
public:
QtTcpWrapper(QObject* parent, const std::string& ip = "127.0.0.1", const quint16 serverPort = 6667, const quint16 clientPort = 6666);
~QtTcpWrapper();
void startListening();
void sendMessage(const std::string& message) const;
void setReadCallback(const std::function<void(const std::string&)>& callback);
quint16 getServerPort() const;
void setServerPort(const quint16 serverPort);
quint16 getClientPort() const;
void setClientPort(const quint16 clientPort);
signals:
public slots:
void acceptConnection();
void startRead();
private:
quint16 m_serverPort;
quint16 m_clientPort;
std::string m_ip;
std::function<void(const std::string&)> m_readCallback;
QTcpServer* m_tcpServer;
QTcpSocket* m_tcpClient;
};
#endif // QT_SOCKET_WRAPPER_H
@@ -0,0 +1,49 @@
#include "SocketTest.h"
#include "utility/logging/logging.h"
SocketTest::SocketTest(QObject* parent)
: QObject(parent)
, m_socket(NULL)
{
m_socket = new QUdpSocket(this);
QHostAddress address("127.0.0.1");
m_socket->bind(address, 6666);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
}
SocketTest::~SocketTest()
{
if(m_socket != NULL)
{
delete m_socket;
}
}
void SocketTest::sendTestMessage()
{
LOG_WARNING("SocketTest::sendTestMessage");
QByteArray Data;
Data.append("qt foo");
m_socket->writeDatagram(Data, QHostAddress::Any, 6666);
}
void SocketTest::readyRead()
{
LOG_WARNING("SocketTest::readyRead");
QByteArray buffer;
buffer.resize(m_socket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
m_socket->readDatagram(buffer.data(), buffer.size(), &sender, &senderPort);
std::string message = buffer.data();
LOG_WARNING(message);
}
@@ -0,0 +1,26 @@
#ifndef SOCKET_TEST_H
#define SOCKET_TEST_H
#include <qobject.h>
#include <qudpsocket.h>
class SocketTest : public QObject
{
Q_OBJECT
public:
SocketTest(QObject* parent);
~SocketTest();
void sendTestMessage();
signals:
public slots:
void readyRead();
private:
QUdpSocket* m_socket;
};
#endif // SOCKET_TEST_H
@@ -0,0 +1,50 @@
#include "qt/utility/QtDeviceScaledPixmap.h"
#include <QApplication>
qreal QtDeviceScaledPixmap::devicePixelRatio()
{
QApplication* app = dynamic_cast<QApplication*>(QCoreApplication::instance());
return app->devicePixelRatio();
}
QtDeviceScaledPixmap::QtDeviceScaledPixmap(QString filePath)
: m_pixmap(filePath)
{
m_pixmap.setDevicePixelRatio(devicePixelRatio());
}
QtDeviceScaledPixmap::~QtDeviceScaledPixmap() {}
const QPixmap& QtDeviceScaledPixmap::pixmap() const
{
return m_pixmap;
}
qreal QtDeviceScaledPixmap::width() const
{
return m_pixmap.width() / devicePixelRatio();
}
qreal QtDeviceScaledPixmap::height() const
{
return m_pixmap.height() / devicePixelRatio();
}
void QtDeviceScaledPixmap::scaleToWidth(int width)
{
m_pixmap = m_pixmap.scaledToWidth(width * devicePixelRatio(), Qt::SmoothTransformation);
m_pixmap.setDevicePixelRatio(devicePixelRatio());
}
void QtDeviceScaledPixmap::scaleToHeight(int height)
{
m_pixmap = m_pixmap.scaledToHeight(height * devicePixelRatio(), Qt::SmoothTransformation);
m_pixmap.setDevicePixelRatio(devicePixelRatio());
}
void QtDeviceScaledPixmap::mirror(bool horizontal, bool vertical)
{
m_pixmap = QPixmap::fromImage(m_pixmap.toImage().mirrored(horizontal, vertical));
m_pixmap.setDevicePixelRatio(devicePixelRatio());
}
@@ -0,0 +1,28 @@
#ifndef QT_DEVICE_SCALED_PIXMAP_H
#define QT_DEVICE_SCALED_PIXMAP_H
#include <QPixmap>
class QtDeviceScaledPixmap
{
public:
static qreal devicePixelRatio();
explicit QtDeviceScaledPixmap(QString filePath);
virtual ~QtDeviceScaledPixmap();
const QPixmap& pixmap() const;
qreal width() const;
qreal height() const;
void scaleToWidth(int width);
void scaleToHeight(int height);
void mirror(bool horizontal = false, bool vertical = true);
private:
QPixmap m_pixmap;
};
#endif // QT_DEVICE_SCALED_PIXMAP_H
+199
View File
@@ -0,0 +1,199 @@
#include "qt/utility/QtHighlighter.h"
#include <QTextCursor>
#include <QTextDocument>
#include "settings/ColorScheme.h"
QtHighlighter::QtHighlighter(QTextDocument *parent)
: QSyntaxHighlighter(parent)
{
QStringList keywordPatterns;
keywordPatterns
<< "break" << "case" << "const" << "continue" << "default"
<< "delete" << "do" << "else" << "explicit" << "false" << "for"
<< "friend" << "if" << "inline" << "new" << "NULL" << "nullptr" << "operator"
<< "private" << "protected" << "public" << "return" << "signals"
<< "slots" << "static" << "switch" << "template" << "true" << "typedef"
<< "typename" << "virtual" << "volatile" << "while";
QStringList typePatterns;
typePatterns
<< "bool" << "char" << "class" << "double"
<< "enum" << "float" << "int" << "long"
<< "namespace" << "short" << "signed" << "size_t"
<< "struct" << "union" << "unsigned" << "void";
QRegExp directiveRegExp = QRegExp("#[a-z]+\\b");
QRegExp numberRegExp = QRegExp("\\b[0-9]+\\b");
QRegExp functionRegExp = QRegExp("\\b[A-Za-z0-9_]+(?=\\()");
QRegExp quotationRegExp = QRegExp("\"([^\"]|\\\\.)*\"");
QRegExp quotation2RegExp = QRegExp(" <.*>");
QRegExp commentRegExp = QRegExp("//[^\n]*");
ColorScheme* scheme = ColorScheme::getInstance().get();
QColor directiveColor(scheme->getSyntaxColor("directive").c_str());
QColor keywordColor(scheme->getSyntaxColor("keyword").c_str());
QColor typeColor(scheme->getSyntaxColor("type").c_str());
QColor numberColor(scheme->getSyntaxColor("number").c_str());
QColor functionColor(scheme->getSyntaxColor("function").c_str());
QColor quotationColor(scheme->getSyntaxColor("quotation").c_str());
QColor commentColor = scheme->getSyntaxColor("comment").c_str();
foreach (const QString &pattern, keywordPatterns)
{
addHighlightingRule(keywordColor, QRegExp("\\b" + pattern + "\\b"));
}
foreach (const QString &pattern, typePatterns)
{
addHighlightingRule(typeColor, QRegExp("\\b" + pattern + "\\b"));
}
addHighlightingRule(directiveColor, directiveRegExp);
addHighlightingRule(numberColor, numberRegExp);
addHighlightingRule(functionColor, functionRegExp);
addHighlightingRule(quotationColor, quotation2RegExp);
m_quotationRule = HighlightingRule(quotationColor, quotationRegExp);
m_commentRule = HighlightingRule(commentColor, commentRegExp);
}
void QtHighlighter::highlightBlock(const QString& text)
{
if (currentBlock().blockNumber() == 0)
{
highlightDocument();
}
}
void QtHighlighter::highlightDocument()
{
QTextDocument* doc = document();
std::vector<std::pair<int, int>> ranges;
for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next())
{
formatBlock(it, m_quotationRule, &ranges, true);
}
for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next())
{
foreach (const HighlightingRule &rule, m_highlightingRules)
{
formatBlock(it, rule, &ranges, false);
}
}
highlightMultiLineComments(&ranges);
for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next())
{
formatBlock(it, m_commentRule, &ranges, true);
}
}
void QtHighlighter::highlightMultiLineComments(std::vector<std::pair<int, int>>* ranges)
{
QTextDocument* doc = document();
QRegExp commentStartExpression = QRegExp("(^([^/]|/[^/])*)/\\*");
QRegExp commentEndExpression = QRegExp("\\*/");
QTextCursor cursorStart(doc);
QTextCursor cursorEnd(doc);
while (true)
{
do
{
cursorStart = document()->find(commentStartExpression, cursorStart);
if (!cursorStart.isNull())
{
cursorStart.setPosition(cursorStart.selectionEnd() - 2);
}
}
while (isInRange(cursorStart.position(), *ranges));
if (cursorStart.isNull())
{
break;
}
cursorEnd = document()->find(commentEndExpression, cursorStart);
if (cursorEnd.isNull())
{
break;
}
applyFormat(cursorStart.selectionStart(), cursorEnd.position(), m_commentRule.format);
ranges->push_back(std::pair<int, int>(cursorStart.selectionStart(), cursorEnd.position()));
cursorStart = cursorEnd;
}
}
QtHighlighter::HighlightingRule::HighlightingRule()
{
}
QtHighlighter::HighlightingRule::HighlightingRule(const QColor& color, const QRegExp& regExp)
{
format.setForeground(color);
pattern = regExp;
}
void QtHighlighter::addHighlightingRule(const QColor& color, const QRegExp& regExp)
{
m_highlightingRules.append(HighlightingRule(color, regExp));
}
bool QtHighlighter::isInRange(int pos, const std::vector<std::pair<int, int>>& ranges) const
{
for (const std::pair<int, int> p : ranges)
{
if (pos >= p.first && pos <= p.second)
{
return true;
}
}
return false;
}
void QtHighlighter::formatBlock(
const QTextBlock& block, const HighlightingRule& rule, std::vector<std::pair<int, int>>* ranges, bool saveRange
){
QRegExp expression(rule.pattern);
int pos = block.position();
int index = expression.indexIn(block.text());
std::vector<std::pair<int, int>> newRanges;
while (index >= 0)
{
int length = expression.matchedLength();
if (!isInRange(pos + index, *ranges))
{
applyFormat(pos + index, pos + index + length, rule.format);
}
newRanges.push_back(std::pair<int, int>(pos + index, pos + index + length));
index = expression.indexIn(block.text(), index + length);
}
if (saveRange)
{
ranges->insert(ranges->end(), newRanges.begin(), newRanges.end());
}
}
void QtHighlighter::applyFormat(int startPosition, int endPosition, const QTextCharFormat& format)
{
QTextCursor cursor(document());
cursor.setPosition(startPosition);
cursor.setPosition(endPosition, QTextCursor::KeepAnchor);
cursor.setCharFormat(format);
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef QT_HIGHLIGHTER_H
#define QT_HIGHLIGHTER_H
#include <QSyntaxHighlighter>
#include <QTextCharFormat>
class QTextDocument;
class QtHighlighter
: public QSyntaxHighlighter
{
Q_OBJECT
public:
QtHighlighter(QTextDocument *parent = 0);
protected:
void highlightBlock(const QString& text);
private:
struct HighlightingRule
{
HighlightingRule();
HighlightingRule(const QColor& color, const QRegExp& regExp);
QRegExp pattern;
QTextCharFormat format;
};
void highlightDocument();
void highlightMultiLineComments(std::vector<std::pair<int, int>>* ranges);
void addHighlightingRule(const QColor& color, const QRegExp& regExp);
bool isInRange(int index, const std::vector<std::pair<int, int>>& ranges) const;
void formatBlock(const QTextBlock& block, const HighlightingRule& rule, std::vector<std::pair<int, int>>* ranges, bool saveRange);
void applyFormat(int startPosition, int endPosition, const QTextCharFormat& format);
QVector<HighlightingRule> m_highlightingRules;
HighlightingRule m_quotationRule;
HighlightingRule m_commentRule;
};
#endif // QT_HIGHLIGHTER_H
+122
View File
@@ -0,0 +1,122 @@
#ifndef QT_THREADED_FUCTOR_H
#define QT_THREADED_FUCTOR_H
#include <functional>
#include <QObject>
#include <QSemaphore>
class QtThreadedFunctorHelper: public QObject
{
Q_OBJECT
signals:
void signalExecution();
private slots:
void execute()
{
m_callback();
m_freeCallbacks.release();
}
public:
QtThreadedFunctorHelper()
: m_freeCallbacks(1)
{
QObject::connect(this, SIGNAL(signalExecution()), this, SLOT(execute()));
}
void operator()(std::function<void(void)> callback)
{
m_freeCallbacks.acquire();
m_callback = callback;
signalExecution();
}
private:
std::function<void(void)> m_callback;
QSemaphore m_freeCallbacks;
};
template <typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void>
class QtThreadedFunctor
{
public:
QtThreadedFunctor(std::function<void(T1, T2, T3, T4)> callback) : m_callback(callback) {}
void operator()(T1 p1, T2 p2, T3 p3, T4 p4)
{
m_helper(std::bind(m_callback, p1, p2, p3, p4));
}
private:
QtThreadedFunctorHelper m_helper;
std::function<void(T1, T2, T3, T4)> m_callback;
};
template <typename T1, typename T2, typename T3>
class QtThreadedFunctor<T1, T2, T3, void>
{
public:
QtThreadedFunctor(std::function<void(T1, T2, T3)> callback) : m_callback(callback) {}
void operator()(T1 p1, T2 p2, T3 p3)
{
m_helper(std::bind(m_callback, p1, p2, p3));
}
private:
QtThreadedFunctorHelper m_helper;
std::function<void(T1, T2, T3)> m_callback;
};
template <typename T1, typename T2>
class QtThreadedFunctor<T1, T2, void, void>
{
public:
QtThreadedFunctor(std::function<void(T1, T2)> callback) : m_callback(callback) {}
void operator()(T1 p1, T2 p2)
{
m_helper(std::bind(m_callback, p1, p2));
}
private:
QtThreadedFunctorHelper m_helper;
std::function<void(T1, T2)> m_callback;
};
template <typename T1>
class QtThreadedFunctor<T1, void, void, void>
{
public:
QtThreadedFunctor(std::function<void(T1)> callback) : m_callback(callback) {}
void operator()(T1 p1)
{
m_helper(std::bind(m_callback, p1));
}
private:
QtThreadedFunctorHelper m_helper;
std::function<void(T1)> m_callback;
};
template <>
class QtThreadedFunctor<void, void, void, void>
{
public:
QtThreadedFunctor(std::function<void(void)> callback) : m_callback(callback) {}
void operator()()
{
m_helper(m_callback);
}
private:
QtThreadedFunctorHelper m_helper;
std::function<void(void)> m_callback;
};
#endif // QT_THREADED_FUCTOR_H
+136
View File
@@ -0,0 +1,136 @@
#include "qt/utility/utilityQt.h"
#include <set>
#include <QFile>
#include <QFontDatabase>
#include <QPainter>
#include "utility/file/FileSystem.h"
#include "utility/logging/logging.h"
#include "utility/utilityString.h"
#include "utility/text/TextAccess.h"
#include "settings/ApplicationSettings.h"
#include "settings/ColorScheme.h"
namespace utility
{
void setWidgetBackgroundColor(QWidget* widget, const std::string& color)
{
QPalette palette = widget->palette();
palette.setColor(widget->backgroundRole(), QColor(color.c_str()));
widget->setPalette(palette);
widget->setAutoFillBackground(true);
}
void loadFontsFromDirectory(const std::string& path, const std::string& extension)
{
std::vector<std::string> extensions;
extensions.push_back(extension);
std::vector<std::string> fontFileNames = FileSystem::getFileNamesFromDirectory(path, extensions);
std::set<int> loadedFontIds;
for (const std::string& fontFileName: fontFileNames)
{
QFile file(fontFileName.c_str());
if (file.open(QIODevice::ReadOnly))
{
int id = QFontDatabase::addApplicationFontFromData(file.readAll());
if (id != -1)
{
loadedFontIds.insert(id);
}
}
}
for (int loadedFontId: loadedFontIds)
{
for (QString family: QFontDatabase::applicationFontFamilies(loadedFontId))
{
LOG_INFO("Loaded FontFamily: " + family.toStdString());
}
}
}
std::string getStyleSheet(const std::string& path)
{
std::string css = TextAccess::createFromFile(path)->getText();
size_t pos = 0;
while (pos != std::string::npos)
{
size_t posA = css.find('<', pos);
size_t posB = css.find('>', pos);
if (posA == std::string::npos || posB == std::string::npos)
{
break;
}
std::deque<std::string> seq = utility::split(css.substr(posA + 1, posB - posA - 1), ':');
if (seq.size() != 2)
{
LOG_ERROR("Syntax error in file: " + path);
return "";
}
std::string key = seq.front();
std::string val = seq.back();
if (key == "setting")
{
if (val == "font_size")
{
val = std::to_string(ApplicationSettings::getInstance()->getFontSize());
}
else if (val == "font_size+2")
{
val = std::to_string(ApplicationSettings::getInstance()->getFontSize() + 2);
}
else if (val == "font_size-2")
{
val = std::to_string(ApplicationSettings::getInstance()->getFontSize() - 2);
}
else if (val == "font_name")
{
val = ApplicationSettings::getInstance()->getFontName();
}
else
{
LOG_ERROR("Syntax error in file: " + path);
return "";
}
}
else if (key == "color")
{
val = ColorScheme::getInstance()->getColor(val);
}
else
{
LOG_ERROR("Syntax error in file: " + path);
return "";
}
css.replace(posA, posB - posA + 1, val);
pos = posA + val.size();
}
return css;
}
QPixmap colorizePixmap(const QPixmap& pixmap, QColor color)
{
QImage image = pixmap.toImage();
QImage colorImage(image.size(), image.format());
QPainter colorPainter(&colorImage);
colorPainter.fillRect(image.rect(), color);
QPainter painter(&image);
painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
painter.drawImage(0, 0, colorImage);
return QPixmap::fromImage(image);
}
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef UTILITY_QT_H
#define UTILITY_QT_H
#include <memory>
#include <qwidget.h>
namespace utility
{
void setWidgetBackgroundColor(QWidget* widget, const std::string& color);
void loadFontsFromDirectory(const std::string& path, const std::string& extension = ".otf");
std::string getStyleSheet(const std::string& path);
QPixmap colorizePixmap(const QPixmap& pixmap, QColor color);
}
# endif // UTILITY_QT_H
+177
View File
@@ -0,0 +1,177 @@
#include "qt/view/QtCodeView.h"
#include "utility/file/FileSystem.h"
#include "qt/utility/utilityQt.h"
#include "qt/element/QtCodeArea.h"
#include "qt/element/QtCodeFileList.h"
#include "qt/view/QtViewWidgetWrapper.h"
#include "settings/ColorScheme.h"
QtCodeView::QtCodeView(ViewLayout* viewLayout)
: CodeView(viewLayout)
, m_refreshViewFunctor(std::bind(&QtCodeView::doRefreshView, this))
, m_showCodeSnippetsFunctor(std::bind(&QtCodeView::doShowCodeSnippets, this, std::placeholders::_1))
, m_addCodeSnippetsFunctor(std::bind(&QtCodeView::doAddCodeSnippets, this, std::placeholders::_1, std::placeholders::_2))
, m_showCodeFileFunctor(std::bind(&QtCodeView::doShowCodeFile, this, std::placeholders::_1))
, m_doShowFirstActiveSnippetFunctor(std::bind(&QtCodeView::doShowFirstActiveSnippet, this))
, m_focusTokenIdsFunctor(std::bind(&QtCodeView::doFocusTokenIds, this, std::placeholders::_1))
, m_defocusTokenIdsFunctor(std::bind(&QtCodeView::doDefocusTokenIds, this))
, m_isExpanding(false)
{
m_widget = new QtCodeFileList();
setStyleSheet();
}
QtCodeView::~QtCodeView()
{
}
void QtCodeView::createWidgetWrapper()
{
setWidgetWrapper(std::make_shared<QtViewWidgetWrapper>(m_widget));
}
void QtCodeView::initView()
{
}
void QtCodeView::refreshView()
{
m_refreshViewFunctor();
}
void QtCodeView::setActiveTokenIds(const std::vector<Id>& activeTokenIds)
{
m_activeTokenIds = activeTokenIds;
}
void QtCodeView::setErrorMessages(const std::vector<std::string>& errorMessages)
{
m_errorMessages = errorMessages;
}
void QtCodeView::showCodeSnippets(const std::vector<CodeSnippetParams>& snippets)
{
m_showCodeSnippetsFunctor(snippets);
}
void QtCodeView::addCodeSnippets(const std::vector<CodeSnippetParams>& snippets, bool insert)
{
m_addCodeSnippetsFunctor(snippets, insert);
}
void QtCodeView::showCodeFile(const CodeSnippetParams& params)
{
m_showCodeFileFunctor(params);
}
void QtCodeView::showFirstActiveSnippet()
{
m_doShowFirstActiveSnippetFunctor();
}
void QtCodeView::focusTokenIds(const std::vector<Id>& focusedTokenIds)
{
m_focusTokenIdsFunctor(focusedTokenIds);
}
void QtCodeView::defocusTokenIds()
{
m_defocusTokenIdsFunctor();
}
void QtCodeView::doRefreshView()
{
setStyleSheet();
m_widget->clearCodeSnippets();
QtCodeArea::clearAnnotationColors();
}
void QtCodeView::doShowCodeSnippets(const std::vector<CodeSnippetParams>& snippets)
{
m_widget->clearCodeSnippets();
m_widget->setActiveTokenIds(m_activeTokenIds);
m_widget->setErrorMessages(m_errorMessages);
for (const CodeSnippetParams& params : snippets)
{
if (params.isCollapsed)
{
m_widget->addFile(params.locationFile, params.refCount, params.modificationTime);
}
else
{
m_widget->addCodeSnippet(
params.startLineNumber,
params.title,
params.titleId,
params.code,
params.locationFile,
params.refCount,
params.modificationTime
);
}
}
setStyleSheet(); // so property "isLast" of QtCodeSnippet is computed correctly
}
void QtCodeView::doAddCodeSnippets(const std::vector<CodeSnippetParams>& snippets, bool insert)
{
for (const CodeSnippetParams& params : snippets)
{
m_widget->addCodeSnippet(
params.startLineNumber,
params.title,
params.titleId,
params.code,
params.locationFile,
params.refCount,
params.modificationTime,
insert
);
}
setStyleSheet(); // so property "isLast" of QtCodeSnippet is computed correctly
if (m_isExpanding)
{
m_widget->scrollToFirstActiveSnippet();
m_isExpanding = false;
}
}
void QtCodeView::doShowCodeFile(const CodeSnippetParams& params)
{
m_widget->addCodeSnippet(1, params.title, 0, params.code, params.locationFile, -1, params.modificationTime);
}
void QtCodeView::doShowFirstActiveSnippet()
{
m_widget->setActiveTokenIds(m_activeTokenIds);
if (!m_widget->scrollToFirstActiveSnippet())
{
m_widget->expandActiveSnippetFile();
m_isExpanding = true;
}
}
void QtCodeView::doFocusTokenIds(const std::vector<Id>& focusedTokenIds)
{
m_widget->focusTokenIds(focusedTokenIds);
}
void QtCodeView::doDefocusTokenIds()
{
m_widget->defocusTokenIds();
}
void QtCodeView::setStyleSheet() const
{
utility::setWidgetBackgroundColor(m_widget, ColorScheme::getInstance()->getColor("code/background"));
m_widget->setStyleSheet(utility::getStyleSheet("data/gui/code_view/code_view.css").c_str());
}
+71
View File
@@ -0,0 +1,71 @@
#ifndef QT_CODE_VIEW_H
#define QT_CODE_VIEW_H
#include <memory>
#include <vector>
#include "utility/types.h"
#include "component/view/CodeView.h"
#include "qt/utility/QtThreadedFunctor.h"
class QFrame;
class QtCodeFileList;
class QWidget;
class QtCodeView
: public CodeView
{
public:
QtCodeView(ViewLayout* viewLayout);
~QtCodeView();
// View implementation
virtual void createWidgetWrapper();
virtual void initView();
virtual void refreshView();
// CodeView implementation
virtual void setActiveTokenIds(const std::vector<Id>& activeTokenIds);
virtual void setErrorMessages(const std::vector<std::string>& errorMessages);
virtual void showCodeSnippets(const std::vector<CodeSnippetParams>& snippets);
virtual void addCodeSnippets(const std::vector<CodeSnippetParams>& snippets, bool insert);
virtual void showCodeFile(const CodeSnippetParams& params);
virtual void showFirstActiveSnippet();
virtual void focusTokenIds(const std::vector<Id>& focusedTokenIds);
virtual void defocusTokenIds();
private:
void doRefreshView();
void doShowCodeSnippets(const std::vector<CodeSnippetParams>& snippets);
void doAddCodeSnippets(const std::vector<CodeSnippetParams>& snippets, bool insert);
void doShowCodeFile(const CodeSnippetParams& params);
void doShowFirstActiveSnippet();
void doFocusTokenIds(const std::vector<Id>& focusedTokenIds);
void doDefocusTokenIds();
void setStyleSheet() const;
QtThreadedFunctor<> m_refreshViewFunctor;
QtThreadedFunctor<const std::vector<CodeSnippetParams>&> m_showCodeSnippetsFunctor;
QtThreadedFunctor<const std::vector<CodeSnippetParams>&, bool> m_addCodeSnippetsFunctor;
QtThreadedFunctor<const CodeSnippetParams&> m_showCodeFileFunctor;
QtThreadedFunctor<> m_doShowFirstActiveSnippetFunctor;
QtThreadedFunctor<const std::vector<Id>&> m_focusTokenIdsFunctor;
QtThreadedFunctor<> m_defocusTokenIdsFunctor;
QtCodeFileList* m_widget;
std::vector<Id> m_activeTokenIds;
std::vector<std::string> m_errorMessages;
bool m_isExpanding;
};
# endif // QT_CODE_VIEW_H
+59
View File
@@ -0,0 +1,59 @@
#include "qt/view/QtCompositeView.h"
#include <QBoxLayout>
#include "qt/utility/utilityQt.h"
#include "qt/view/QtViewWidgetWrapper.h"
#include "settings/ColorScheme.h"
QtCompositeView::QtCompositeView(ViewLayout* viewLayout, CompositeDirection direction, const std::string& name)
: CompositeView(viewLayout, direction, name)
, m_refreshFunctor(std::bind(&QtCompositeView::doRefreshView, this))
{
QBoxLayout* layout;
if (getDirection() == CompositeView::DIRECTION_HORIZONTAL)
{
layout = new QHBoxLayout();
}
else
{
layout = new QVBoxLayout();
}
layout->setSpacing(5);
layout->setContentsMargins(8, 8, 8, 8);
layout->setAlignment(Qt::AlignTop);
m_widget = new QWidget();
m_widget->setLayout(layout);
doRefreshView();
}
QtCompositeView::~QtCompositeView()
{
}
void QtCompositeView::createWidgetWrapper()
{
setWidgetWrapper(std::make_shared<QtViewWidgetWrapper>(m_widget));
}
void QtCompositeView::initView()
{
}
void QtCompositeView::refreshView()
{
m_refreshFunctor();
}
void QtCompositeView::doRefreshView()
{
utility::setWidgetBackgroundColor(m_widget, ColorScheme::getInstance()->getColor("search/background"));
}
void QtCompositeView::addViewWidget(View* view)
{
m_widget->layout()->addWidget(QtViewWidgetWrapper::getWidgetOfView(view));
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef QT_COMPOSITE_VIEW
#define QT_COMPOSITE_VIEW
#include <QWidget>
#include "component/view/CompositeView.h"
#include "qt/utility/QtThreadedFunctor.h"
class QtCompositeView
: public CompositeView
{
public:
QtCompositeView(ViewLayout* viewLayout, CompositeDirection direction, const std::string& name);
~QtCompositeView();
// View implementation
virtual void createWidgetWrapper();
virtual void initView();
virtual void refreshView();
// CompositeView implementation
virtual void addViewWidget(View* view);
private:
void doRefreshView();
QtThreadedFunctor<void> m_refreshFunctor;
QWidget* m_widget;
};
#endif // QT_COMPOSITE_VIEW
+656
View File
@@ -0,0 +1,656 @@
#include "qt/view/QtGraphView.h"
#include <QBoxLayout>
#include <QFrame>
#include <QGraphicsScene>
#include <QMouseEvent>
#include <QPropertyAnimation>
#include <QParallelAnimationGroup>
#include <QScrollBar>
#include <QSequentialAnimationGroup>
#include "component/controller/helper/DummyEdge.h"
#include "component/controller/helper/DummyNode.h"
#include "component/controller/helper/GraphPostprocessor.h"
#include "component/view/GraphViewStyle.h"
#include "utility/messaging/type/MessageDeactivateEdge.h"
#include "qt/utility/utilityQt.h"
#include "qt/view/QtViewWidgetWrapper.h"
#include "qt/view/graphElements/nodeComponents/QtGraphNodeComponentClickable.h"
#include "qt/view/graphElements/nodeComponents/QtGraphNodeComponentMoveable.h"
#include "qt/view/graphElements/QtGraphEdge.h"
#include "qt/view/graphElements/QtGraphNodeAccess.h"
#include "qt/view/graphElements/QtGraphNodeBundle.h"
#include "qt/view/graphElements/QtGraphNodeData.h"
#include "qt/view/graphElements/QtGraphNodeExpandToggle.h"
#include "settings/ColorScheme.h"
QtGraphicsView::QtGraphicsView(QWidget* parent)
: QGraphicsView(parent)
{
}
void QtGraphicsView::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && !itemAt(event->pos()))
{
m_last = event->pos();
}
QGraphicsView::mousePressEvent(event);
}
void QtGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && !itemAt(event->pos()) && event->pos() == m_last)
{
emit emptySpaceClicked();
}
QGraphicsView::mouseReleaseEvent(event);
}
QtGraphView::QtGraphView(ViewLayout* viewLayout)
: GraphView(viewLayout)
, m_rebuildGraphFunctor(
std::bind(&QtGraphView::doRebuildGraph, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))
, m_clearFunctor(std::bind(&QtGraphView::doClear, this))
, m_resizeFunctor(std::bind(&QtGraphView::doResize, this))
, m_refreshFunctor(std::bind(&QtGraphView::doRefreshView, this))
, m_focusInFunctor(std::bind(&QtGraphView::doFocusIn, this, std::placeholders::_1))
, m_focusOutFunctor(std::bind(&QtGraphView::doFocusOut, this, std::placeholders::_1))
{
}
QtGraphView::~QtGraphView()
{
}
void QtGraphView::createWidgetWrapper()
{
setWidgetWrapper(std::make_shared<QtViewWidgetWrapper>(new QFrame()));
}
void QtGraphView::initView()
{
QWidget* widget = QtViewWidgetWrapper::getWidgetOfView(this);
QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
widget->setLayout(layout);
QGraphicsScene* scene = new QGraphicsScene(widget);
QGraphicsView* view = new QtGraphicsView(widget);
view->setScene(scene);
view->setDragMode(QGraphicsView::ScrollHandDrag);
view->setRenderHints(QPainter::Antialiasing);
widget->layout()->addWidget(view);
connect(view, SIGNAL(emptySpaceClicked()), this, SLOT(clickedInEmptySpace()));
doRefreshView();
}
void QtGraphView::refreshView()
{
m_refreshFunctor();
}
void QtGraphView::rebuildGraph(
std::shared_ptr<Graph> graph,
const std::vector<DummyNode>& nodes,
const std::vector<DummyEdge>& edges
){
m_rebuildGraphFunctor(graph, nodes, edges);
}
void QtGraphView::clear()
{
m_clearFunctor();
}
void QtGraphView::resizeView()
{
m_resizeFunctor();
}
Vec2i QtGraphView::getViewSize() const
{
QGraphicsView* view = getView();
return Vec2i(view->width(), view->height());
}
void QtGraphView::centerScrollBars()
{
QGraphicsView* view = getView();
QScrollBar* hb = view->horizontalScrollBar();
QScrollBar* vb = view->verticalScrollBar();
hb->setValue((hb->minimum() + hb->maximum()) / 2);
vb->setValue((vb->minimum() + vb->maximum()) / 2);
}
void QtGraphView::finishedTransition()
{
QGraphicsView* view = getView();
view->setInteractive(true);
switchToNewGraphData();
}
void QtGraphView::clickedInEmptySpace()
{
size_t activeEdgeCount = 0;
for (std::shared_ptr<QtGraphEdge> edge : m_oldEdges)
{
if (edge->getIsActive())
{
activeEdgeCount++;
}
}
if (activeEdgeCount == 1)
{
MessageDeactivateEdge().dispatch();
}
}
void QtGraphView::switchToNewGraphData()
{
m_oldGraph = m_graph;
for (const std::shared_ptr<QtGraphNode>& node : m_oldNodes)
{
node->hide();
}
for (const std::shared_ptr<QtGraphEdge>& edge : m_oldEdges)
{
edge->hide();
}
m_oldNodes = m_nodes;
m_oldEdges = m_edges;
m_nodes.clear();
m_edges.clear();
doResize();
// Manually hover the item below the mouse cursor.
QGraphicsView* view = getView();
QPointF point = view->mapToScene(view->mapFromGlobal(QCursor::pos()));
QGraphicsItem* item = view->scene()->itemAt(point, QTransform());
if (item)
{
QtGraphNode* node = dynamic_cast<QtGraphNode*>(item->parentItem());
if (node)
{
node->hoverEnter();
}
}
}
QGraphicsView* QtGraphView::getView() const
{
QWidget* widget = QtViewWidgetWrapper::getWidgetOfView(this);
QGraphicsView* view = widget->findChild<QGraphicsView*>("");
if (!view)
{
LOG_ERROR("Failed to get QGraphicsView");
}
return view;
}
void QtGraphView::doRebuildGraph(
std::shared_ptr<Graph> graph,
const std::vector<DummyNode>& nodes,
const std::vector<DummyEdge>& edges
){
if (m_transition && m_transition->currentTime() < m_transition->totalDuration())
{
m_transition->stop();
finishedTransition();
}
QGraphicsView* view = getView();
m_nodes.clear();
for (unsigned int i = 0; i < nodes.size(); i++)
{
std::shared_ptr<QtGraphNode> node = createNodeRecursive(view, NULL, nodes[i]);
if (node)
{
m_nodes.push_back(node);
}
}
QPointF center = itemsBoundingRect(m_nodes).center();
Vec2i o = GraphPostprocessor::alignOnRaster(Vec2i(center.x(), center.y()));
QPointF offset = QPointF(o.x, o.y);
m_sceneRectOffset = offset - center;
for (const std::shared_ptr<QtGraphNode>& node : m_nodes)
{
node->setPos(node->pos() - offset);
}
m_edges.clear();
for (unsigned int i = 0; i < edges.size(); i++)
{
std::shared_ptr<QtGraphEdge> edge = createEdge(view, edges[i]);
if (edge)
{
m_edges.push_back(edge);
}
}
if (graph)
{
m_graph = graph;
}
createTransition();
}
void QtGraphView::doClear()
{
m_nodes.clear();
m_edges.clear();
m_oldNodes.clear();
m_oldEdges.clear();
m_graph.reset();
m_oldGraph.reset();
}
void QtGraphView::doResize()
{
getView()->setSceneRect(getSceneRect(m_oldNodes));
}
void QtGraphView::doRefreshView()
{
doClear();
doResize();
std::string css = utility::getStyleSheet("data/gui/graph_view/graph_view.css");
getView()->setStyleSheet(css.c_str());
float zoomFactor = GraphViewStyle::getZoomFactor();
getView()->setTransform(QTransform(zoomFactor, 0, 0, zoomFactor, 0, 0));
}
std::shared_ptr<QtGraphNode> QtGraphView::findNodeRecursive(const std::list<std::shared_ptr<QtGraphNode>>& nodes, Id tokenId)
{
for (const std::shared_ptr<QtGraphNode>& node : nodes)
{
if (node->getTokenId() == tokenId)
{
return node;
}
std::shared_ptr<QtGraphNode> result = findNodeRecursive(node->getSubNodes(), tokenId);
if (result != NULL)
{
return result;
}
}
return std::shared_ptr<QtGraphNode>();
}
std::shared_ptr<QtGraphNode> QtGraphView::createNodeRecursive(
QGraphicsView* view, std::shared_ptr<QtGraphNode> parentNode, const DummyNode& node
){
if (!node.visible)
{
return NULL;
}
std::shared_ptr<QtGraphNode> newNode;
if (node.isGraphNode())
{
newNode = std::make_shared<QtGraphNodeData>(node.data, node.hasParent, node.childVisible);
}
else if (node.isAccessNode())
{
newNode = std::make_shared<QtGraphNodeAccess>(node.accessType);
}
else if (node.isExpandToggleNode())
{
newNode = std::make_shared<QtGraphNodeExpandToggle>(node.isExpanded(), node.invisibleSubNodeCount);
}
else if (node.isBundleNode())
{
newNode = std::make_shared<QtGraphNodeBundle>(node.tokenId, node.bundledNodes.size(), node.name);
}
newNode->setPosition(node.position);
newNode->setSize(node.size);
newNode->setIsActive(node.active);
newNode->addComponent(std::make_shared<QtGraphNodeComponentClickable>(newNode));
view->scene()->addItem(newNode.get());
if (parentNode)
{
newNode->setParent(parentNode);
}
else
{
newNode->addComponent(std::make_shared<QtGraphNodeComponentMoveable>(newNode));
}
for (unsigned int i = 0; i < node.subNodes.size(); i++)
{
std::shared_ptr<QtGraphNode> subNode = createNodeRecursive(view, newNode, node.subNodes[i]);
if (subNode)
{
newNode->addSubNode(subNode);
}
}
newNode->updateStyle();
return newNode;
}
std::shared_ptr<QtGraphEdge> QtGraphView::createEdge(QGraphicsView* view, const DummyEdge& edge)
{
if (!edge.visible)
{
return NULL;
}
std::shared_ptr<QtGraphNode> owner = findNodeRecursive(m_nodes, edge.ownerId);
std::shared_ptr<QtGraphNode> target = findNodeRecursive(m_nodes, edge.targetId);
if (owner != NULL && target != NULL)
{
std::shared_ptr<QtGraphEdge> qtEdge = std::make_shared<QtGraphEdge>(owner, target, edge.data, edge.getWeight());
qtEdge->setIsActive(edge.active);
qtEdge->setDirection(edge.getDirection());
owner->addOutEdge(qtEdge);
target->addInEdge(qtEdge);
view->scene()->addItem(qtEdge.get());
return qtEdge;
}
else
{
LOG_WARNING_STREAM(<< "Couldn't find owner or target node for edge: " << (edge.data ? edge.data->getName() : "<no data>"));
return NULL;
}
}
QRectF QtGraphView::itemsBoundingRect(const std::list<std::shared_ptr<QtGraphNode>>& items) const
{
QRectF boundingRect;
for (const std::shared_ptr<QtGraphNode>& item : items)
{
boundingRect |= item->sceneBoundingRect();
}
return boundingRect;
}
QRectF QtGraphView::getSceneRect(const std::list<std::shared_ptr<QtGraphNode>>& items) const
{
return itemsBoundingRect(items).adjusted(-25, -25, 25, 25).translated(m_sceneRectOffset);
}
void QtGraphView::compareNodesRecursive(
std::list<std::shared_ptr<QtGraphNode>> newSubNodes,
std::list<std::shared_ptr<QtGraphNode>> oldSubNodes,
std::list<QtGraphNode*>* appearingNodes,
std::list<QtGraphNode*>* vanishingNodes,
std::vector<std::pair<QtGraphNode*, QtGraphNode*>>* remainingNodes
){
for (std::list<std::shared_ptr<QtGraphNode>>::iterator it = newSubNodes.begin(); it != newSubNodes.end(); it++)
{
bool remains = false;
for (std::list<std::shared_ptr<QtGraphNode>>::iterator it2 = oldSubNodes.begin(); it2 != oldSubNodes.end(); it2++)
{
if (((*it)->isDataNode() && (*it2)->isDataNode() && (*it)->getTokenId() == (*it2)->getTokenId()) ||
((*it)->isAccessNode() && (*it2)->isAccessNode() &&
dynamic_cast<QtGraphNodeAccess*>((*it).get())->getAccessType() ==
dynamic_cast<QtGraphNodeAccess*>((*it2).get())->getAccessType()) ||
((*it)->isExpandToggleNode() && (*it2)->isExpandToggleNode()) ||
((*it)->isBundleNode() && (*it2)->isBundleNode() && (*it)->getTokenId() == (*it2)->getTokenId()))
{
remainingNodes->push_back(std::pair<QtGraphNode*, QtGraphNode*>((*it).get(), (*it2).get()));
compareNodesRecursive((*it)->getSubNodes(), (*it2)->getSubNodes(), appearingNodes, vanishingNodes, remainingNodes);
oldSubNodes.erase(it2);
remains = true;
break;
}
}
if (!remains)
{
appearingNodes->push_back((*it).get());
}
}
for (std::shared_ptr<QtGraphNode>& node : oldSubNodes)
{
vanishingNodes->push_back(node.get());
}
}
void QtGraphView::createTransition()
{
std::list<QtGraphNode*> appearingNodes;
std::list<QtGraphNode*> vanishingNodes;
std::vector<std::pair<QtGraphNode*, QtGraphNode*>> remainingNodes;
compareNodesRecursive(m_nodes, m_oldNodes, &appearingNodes, &vanishingNodes, &remainingNodes);
if (!vanishingNodes.size() && !appearingNodes.size())
{
bool nodesMoved = false;
for (const std::pair<QtGraphNode*, QtGraphNode*>& p : remainingNodes)
{
if (p.first->getPosition() != p.second->getPosition() && p.first->getSize() != p.second->getSize())
{
nodesMoved = true;
}
}
if (!nodesMoved)
{
switchToNewGraphData();
return;
}
}
QGraphicsView* view = getView();
view->setInteractive(false);
m_transition = std::make_shared<QSequentialAnimationGroup>();
// fade out
if (vanishingNodes.size() || m_oldEdges.size())
{
QParallelAnimationGroup* vanish = new QParallelAnimationGroup();
for (QtGraphNode* node : vanishingNodes)
{
QPropertyAnimation* anim = new QPropertyAnimation(node, "opacity");
anim->setDuration(300);
anim->setStartValue(1.0f);
anim->setEndValue(0.0f);
vanish->addAnimation(anim);
}
for (std::shared_ptr<QtGraphEdge> edge : m_oldEdges)
{
QPropertyAnimation* anim = new QPropertyAnimation(edge.get(), "opacity");
anim->setDuration(150);
anim->setStartValue(1.0f);
anim->setEndValue(0.0f);
vanish->addAnimation(anim);
}
m_transition->addAnimation(vanish);
}
// move and scale
{
QParallelAnimationGroup* remain = new QParallelAnimationGroup();
for (std::pair<QtGraphNode*, QtGraphNode*> p : remainingNodes)
{
QtGraphNode* newNode = p.first;
QtGraphNode* oldNode = p.second;
QPropertyAnimation* anim = new QPropertyAnimation(oldNode, "pos");
anim->setDuration(300);
anim->setStartValue(oldNode->pos());
anim->setEndValue(newNode->pos());
remain->addAnimation(anim);
connect(anim, SIGNAL(finished()), newNode, SLOT(showNode()));
connect(anim, SIGNAL(finished()), oldNode, SLOT(hideNode()));
newNode->hide();
anim = new QPropertyAnimation(oldNode, "size");
anim->setDuration(300);
anim->setStartValue(oldNode->size());
anim->setEndValue(newNode->size());
remain->addAnimation(anim);
if (newNode->isAccessNode() && newNode->getSubNodes().size() == 0 && oldNode->getSubNodes().size() > 0)
{
dynamic_cast<QtGraphNodeAccess*>(oldNode)->hideLabel();
}
}
QPropertyAnimation* anim = new QPropertyAnimation(view, "sceneRect");
anim->setStartValue(view->sceneRect());
anim->setEndValue(getSceneRect(m_nodes));
if (remainingNodes.size())
{
anim->setDuration(300);
}
else
{
anim->setDuration(300);
connect(anim, SIGNAL(finished()), this, SLOT(centerScrollBars()));
}
remain->addAnimation(anim);
m_transition->addAnimation(remain);
}
// fade in
if (appearingNodes.size() || m_edges.size())
{
QParallelAnimationGroup* appear = new QParallelAnimationGroup();
for (QtGraphNode* node : appearingNodes)
{
QPropertyAnimation* anim = new QPropertyAnimation(node, "opacity");
anim->setDuration(300);
anim->setStartValue(0.0f);
anim->setEndValue(1.0f);
appear->addAnimation(anim);
connect(anim, SIGNAL(finished()), node, SLOT(blendIn()));
node->blendOut();
}
for (std::shared_ptr<QtGraphEdge> edge : m_edges)
{
QPropertyAnimation* anim = new QPropertyAnimation(edge.get(), "opacity");
anim->setDuration(150);
anim->setStartValue(0.0f);
anim->setEndValue(1.0f);
appear->addAnimation(anim);
edge->setOpacity(0.0f);
}
m_transition->addAnimation(appear);
}
connect(m_transition.get(), SIGNAL(finished()), this, SLOT(finishedTransition()));
m_transition->start();
}
void QtGraphView::focusTokenIds(const std::vector<Id>& focusedTokenIds)
{
m_focusInFunctor(focusedTokenIds);
}
void QtGraphView::doFocusIn(const std::vector<Id>& tokenIds)
{
for (const Id& tokenId : tokenIds)
{
std::shared_ptr<QtGraphNode> node = findNodeRecursive(m_oldNodes, tokenId);
if (node && node->isDataNode())
{
node->focusIn();
continue;
}
for (std::shared_ptr<QtGraphEdge> edge : m_oldEdges)
{
if (edge->getData() && edge->getData()->getId() == tokenId)
{
edge->focusIn();
break;
}
}
}
}
void QtGraphView::defocusTokenIds(const std::vector<Id>& defocusedTokenIds)
{
m_focusOutFunctor(defocusedTokenIds);
}
void QtGraphView::doFocusOut(const std::vector<Id>& tokenIds)
{
for (const Id& tokenId : tokenIds)
{
std::shared_ptr<QtGraphNode> node = findNodeRecursive(m_oldNodes, tokenId);
if (node && node->isDataNode())
{
node->focusOut();
continue;
}
for (std::shared_ptr<QtGraphEdge> edge : m_oldEdges)
{
if (edge->getData() && edge->getData()->getId() == tokenId)
{
edge->focusOut();
break;
}
}
}
}
+117
View File
@@ -0,0 +1,117 @@
#ifndef QT_GRAPH_VIEW_H
#define QT_GRAPH_VIEW_H
#include <QGraphicsView>
#include <QPointF>
#include "component/view/GraphView.h"
#include "qt/utility/QtThreadedFunctor.h"
#include "utility/types.h"
struct DummyEdge;
struct DummyNode;
class QMouseEvent;
class QSequentialAnimationGroup;
class QtGraphEdge;
class QtGraphNode;
class QtGraphicsView
: public QGraphicsView
{
Q_OBJECT
public:
QtGraphicsView(QWidget* parent);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
signals:
void emptySpaceClicked();
private:
QPoint m_last;
};
class QtGraphView
: public QObject
, public GraphView
{
Q_OBJECT
public:
QtGraphView(ViewLayout* viewLayout);
virtual ~QtGraphView();
// View implementation
virtual void createWidgetWrapper();
virtual void initView();
virtual void refreshView();
virtual void rebuildGraph(std::shared_ptr<Graph> graph, const std::vector<DummyNode>& nodes, const std::vector<DummyEdge>& edges);
virtual void clear();
virtual void focusTokenIds(const std::vector<Id>& focusedTokenIds);
virtual void defocusTokenIds(const std::vector<Id>& defocusedTokenIds);
virtual void resizeView();
virtual Vec2i getViewSize() const;
private slots:
void centerScrollBars();
void finishedTransition();
void clickedInEmptySpace();
private:
void switchToNewGraphData();
QGraphicsView* getView() const;
void doRebuildGraph(std::shared_ptr<Graph> graph, const std::vector<DummyNode>& nodes, const std::vector<DummyEdge>& edges);
void doClear();
void doResize();
void doRefreshView();
void doFocusIn(const std::vector<Id>& tokenIds);
void doFocusOut(const std::vector<Id>& tokenIds);
std::shared_ptr<QtGraphNode> findNodeRecursive(const std::list<std::shared_ptr<QtGraphNode>>& nodes, Id tokenId);
std::shared_ptr<QtGraphNode> createNodeRecursive(
QGraphicsView* view, std::shared_ptr<QtGraphNode> parentNode, const DummyNode& node);
std::shared_ptr<QtGraphEdge> createEdge(QGraphicsView* view, const DummyEdge& edge);
QRectF itemsBoundingRect(const std::list<std::shared_ptr<QtGraphNode>>& items) const;
QRectF getSceneRect(const std::list<std::shared_ptr<QtGraphNode>>& items) const;
void compareNodesRecursive(
std::list<std::shared_ptr<QtGraphNode>> newSubNodes,
std::list<std::shared_ptr<QtGraphNode>> oldSubNodes,
std::list<QtGraphNode*>* appearingNodes,
std::list<QtGraphNode*>* vanishingNodes,
std::vector<std::pair<QtGraphNode*, QtGraphNode*>>* remainingNodes);
void createTransition();
QtThreadedFunctor<std::shared_ptr<Graph>, const std::vector<DummyNode>&, const std::vector<DummyEdge>&> m_rebuildGraphFunctor;
QtThreadedFunctor<void> m_clearFunctor;
QtThreadedFunctor<void> m_resizeFunctor;
QtThreadedFunctor<void> m_refreshFunctor;
QtThreadedFunctor<const std::vector<Id>&> m_focusInFunctor;
QtThreadedFunctor<const std::vector<Id>&> m_focusOutFunctor;
std::shared_ptr<Graph> m_graph;
std::shared_ptr<Graph> m_oldGraph;
std::list<std::shared_ptr<QtGraphEdge>> m_edges;
std::list<std::shared_ptr<QtGraphEdge>> m_oldEdges;
std::list<std::shared_ptr<QtGraphNode>> m_nodes;
std::list<std::shared_ptr<QtGraphNode>> m_oldNodes;
std::shared_ptr<QSequentialAnimationGroup> m_transition;
QPointF m_sceneRectOffset;
};
#endif // QT_GRAPH_VIEW_H
@@ -0,0 +1,28 @@
#include "qt/view/QtGraphViewStyleImpl.h"
#include <QFontMetrics>
#include <QSysInfo>
QtGraphViewStyleImpl::~QtGraphViewStyleImpl()
{
}
float QtGraphViewStyleImpl::getCharWidthForNodeType(Node::NodeType type)
{
return QFontMetrics(QtGraphNode::getFontForNodeType(type)).width("QtGraphNode::QtGraphNode::QtGraphNode") / 37.0f;
}
float QtGraphViewStyleImpl::getCharHeightForNodeType(Node::NodeType type)
{
return QFontMetrics(QtGraphNode::getFontForNodeType(type)).height();
}
float QtGraphViewStyleImpl::getGraphViewZoomDifferenceForPlatform()
{
if (QSysInfo::macVersion() == QSysInfo::MV_None)
{
return 1.25;
}
return 1;
}
@@ -0,0 +1,17 @@
#ifndef QT_GRAPH_VIEW_STYLE_IMPL_H
#define QT_GRAPH_VIEW_STYLE_IMPL_H
#include "component/view/GraphViewStyleImpl.h"
#include "qt/view/graphElements/QtGraphNode.h"
class QtGraphViewStyleImpl
: public GraphViewStyleImpl
{
public:
virtual ~QtGraphViewStyleImpl();
virtual float getCharWidthForNodeType(Node::NodeType type);
virtual float getCharHeightForNodeType(Node::NodeType type);
virtual float getGraphViewZoomDifferenceForPlatform();
};
#endif // QT_GRAPH_VIEW_STYLE_IMPL_H
+105
View File
@@ -0,0 +1,105 @@
#include "qt/view/QtMainView.h"
#include "utility/logging/logging.h"
#include "qt/window/QtMainWindow.h"
QtMainView::QtMainView()
: m_setTitleFunctor(std::bind(&QtMainView::doSetTitle, this, std::placeholders::_1))
, m_activateWindowFunctor(std::bind(&QtMainView::doActivateWindow, this))
, m_updateRecentProjectMenuFunctor(std::bind(&QtMainView::doUpdateRecentProjectMenu, this))
{
m_window = std::make_shared<QtMainWindow>();
m_window->show();
m_window->init();
}
QtMainView::~QtMainView()
{
}
void QtMainView::addView(View* view)
{
m_views.push_back(view);
m_window->addView(view);
}
void QtMainView::removeView(View* view)
{
std::vector<View*>::iterator it = std::find(m_views.begin(), m_views.end(), view);
if (it == m_views.end())
{
return;
}
m_window->removeView(view);
m_views.erase(it);
}
void QtMainView::showView(View* view)
{
m_window->showView(view);
}
void QtMainView::hideView(View* view)
{
m_window->hideView(view);
}
void QtMainView::loadLayout()
{
m_window->loadLayout();
}
void QtMainView::saveLayout()
{
m_window->saveLayout();
}
QStatusBar* QtMainView::getStatusBar()
{
return m_window->statusBar();
}
void QtMainView::setStatusBar(QStatusBar* statusbar)
{
m_window->setStatusBar(statusbar);
}
void QtMainView::hideStartScreen()
{
m_window->clearWindows();
}
void QtMainView::setTitle(const std::string& title)
{
m_setTitleFunctor(title);
}
void QtMainView::activateWindow()
{
m_activateWindowFunctor();
}
void QtMainView::updateRecentProjectMenu()
{
m_updateRecentProjectMenuFunctor();
}
void QtMainView::doUpdateRecentProjectMenu()
{
m_window->updateRecentProjectMenu();
}
void QtMainView::doSetTitle(const std::string& title)
{
m_window->setWindowTitle(QString::fromStdString(title));
}
void QtMainView::doActivateWindow()
{
// It's platform dependent which of these commands does the right thing, for now we just use them all at once.
m_window->activateWindow();
m_window->raise();
m_window->setFocus(Qt::ActiveWindowFocusReason);
}
+54
View File
@@ -0,0 +1,54 @@
#ifndef QT_MAIN_VIEW_H
#define QT_MAIN_VIEW_H
#include <memory>
#include <vector>
#include <QStatusBar>
#include "component/view/MainView.h"
#include "qt/utility/QtThreadedFunctor.h"
class QtMainWindow;
class View;
class QtMainView
: public MainView
{
public:
QtMainView();
virtual ~QtMainView();
// ViewLayout implementation
virtual void addView(View* view);
virtual void removeView(View* view);
virtual void showView(View* view);
virtual void hideView(View* view);
virtual void loadLayout();
virtual void saveLayout();
virtual QStatusBar* getStatusBar();
virtual void setStatusBar(QStatusBar* statusBar);
// MainView implementation
virtual void hideStartScreen();
virtual void setTitle(const std::string& title);
virtual void activateWindow();
virtual void updateRecentProjectMenu();
private:
void doSetTitle(const std::string& title);
void doActivateWindow();
void doUpdateRecentProjectMenu();
std::shared_ptr<QtMainWindow> m_window;
std::vector<View*> m_views;
QtThreadedFunctor<const std::string&> m_setTitleFunctor;
QtThreadedFunctor<> m_activateWindowFunctor;
QtThreadedFunctor<> m_updateRecentProjectMenuFunctor;
};
#endif // QT_MAIN_VIEW_H
+43
View File
@@ -0,0 +1,43 @@
#include "qt/view/QtRefreshView.h"
#include "qt/utility/utilityQt.h"
#include "component/controller/RefreshController.h"
#include "qt/view/QtViewWidgetWrapper.h"
QtRefreshView::QtRefreshView(ViewLayout* viewLayout)
: RefreshView(viewLayout)
, m_refreshViewFunctor(std::bind(&QtRefreshView::doRefreshView, this))
{
m_widget = new QtRefreshBar();
setStyleSheet();
}
QtRefreshView::~QtRefreshView()
{
}
void QtRefreshView::createWidgetWrapper()
{
setWidgetWrapper(std::make_shared<QtViewWidgetWrapper>(m_widget));
}
void QtRefreshView::initView()
{
}
void QtRefreshView::refreshView()
{
m_refreshViewFunctor();
}
void QtRefreshView::doRefreshView()
{
setStyleSheet();
m_widget->refreshStyle();
}
void QtRefreshView::setStyleSheet()
{
m_widget->setStyleSheet(utility::getStyleSheet("data/gui/refresh_view/refresh_view.css").c_str());
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef QT_REFRESH_VIEW_H
#define QT_REFRESH_VIEW_H
#include <QWidget>
#include "component/view/RefreshView.h"
#include "qt/element/QtRefreshBar.h"
#include "qt/utility/QtThreadedFunctor.h"
class QtRefreshView
: public RefreshView
{
public:
QtRefreshView(ViewLayout* viewLayout);
~QtRefreshView();
// View implementation
virtual void createWidgetWrapper();
virtual void initView();
virtual void refreshView();
// RefreshView implementation
private:
void doRefreshView();
void setStyleSheet();
QtThreadedFunctor<> m_refreshViewFunctor;
QtRefreshBar* m_widget;
};
# endif // QT_REFRESH_VIEW_H
+86
View File
@@ -0,0 +1,86 @@
#include "qt/view/QtSearchView.h"
#include "qt/utility/utilityQt.h"
#include "component/controller/SearchController.h"
#include "qt/view/QtViewWidgetWrapper.h"
QtSearchView::QtSearchView(ViewLayout* viewLayout)
: SearchView(viewLayout)
, m_refreshViewFunctor(std::bind(&QtSearchView::doRefreshView, this))
, m_setMatchesFunctor(std::bind(&QtSearchView::doSetMatches, this, std::placeholders::_1))
, m_setFocusFunctor(std::bind(&QtSearchView::doSetFocus, this))
, m_setAutocompletionListFunctor(std::bind(&QtSearchView::doSetAutocompletionList, this, std::placeholders::_1))
{
m_widget = new QtSearchBar();
setStyleSheet();
}
QtSearchView::~QtSearchView()
{
}
void QtSearchView::createWidgetWrapper()
{
setWidgetWrapper(std::make_shared<QtViewWidgetWrapper>(m_widget));
}
void QtSearchView::initView()
{
}
void QtSearchView::refreshView()
{
m_refreshViewFunctor();
}
void QtSearchView::setMatches(const std::vector<SearchMatch>& matches)
{
m_setMatchesFunctor(matches);
}
void QtSearchView::setFocus()
{
m_setFocusFunctor();
}
void QtSearchView::setAutocompletionList(const std::vector<SearchMatch>& autocompletionList)
{
m_setAutocompletionListFunctor(autocompletionList);
}
void QtSearchView::doRefreshView()
{
setStyleSheet();
m_widget->refreshStyle();
m_widget->setMatches(std::vector<SearchMatch>());
}
void QtSearchView::doSetMatches(const std::vector<SearchMatch>& matches)
{
m_widget->setMatches(matches);
}
void QtSearchView::doSetFocus()
{
getViewLayout()->showView(this);
m_widget->setFocus();
}
void QtSearchView::doSetAutocompletionList(const std::vector<SearchMatch>& autocompletionList)
{
m_widget->setAutocompletionList(autocompletionList);
setStyleSheet();
}
void QtSearchView::setStyleSheet()
{
std::string css = utility::getStyleSheet("data/gui/search_view/search_view.css");
m_widget->setStyleSheet(css.c_str());
if (m_widget->getCompleterPopup())
{
m_widget->getCompleterPopup()->setStyleSheet(css.c_str());
}
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef QT_SEARCH_VIEW_H
#define QT_SEARCH_VIEW_H
#include <vector>
#include "component/view/SearchView.h"
#include "qt/element/QtSearchBar.h"
#include "qt/utility/QtThreadedFunctor.h"
class QtSearchView: public SearchView
{
public:
QtSearchView(ViewLayout* viewLayout);
~QtSearchView();
// View implementation
virtual void createWidgetWrapper();
virtual void initView();
virtual void refreshView();
// SearchView implementation
virtual void setMatches(const std::vector<SearchMatch>& matches);
virtual void setFocus();
virtual void setAutocompletionList(const std::vector<SearchMatch>& autocompletionList);
private:
void doRefreshView();
void doSetMatches(const std::vector<SearchMatch>& matches);
void doSetFocus();
void doSetAutocompletionList(const std::vector<SearchMatch>& autocompletionList);
void setStyleSheet();
QtThreadedFunctor<> m_refreshViewFunctor;
QtThreadedFunctor<const std::vector<SearchMatch>&> m_setMatchesFunctor;
QtThreadedFunctor<> m_setFocusFunctor;
QtThreadedFunctor<const std::vector<SearchMatch>&> m_setAutocompletionListFunctor;
QtSearchBar* m_widget;
};
# endif // QT_SEARCH_VIEW_H
+56
View File
@@ -0,0 +1,56 @@
#include "qt/view/QtStatusBarView.h"
#include <QStatusBar>
#include "qt/view/QtMainView.h"
#include "qt/view/QtViewWidgetWrapper.h"
QtStatusBarView::QtStatusBarView(ViewLayout* viewLayout)
: StatusBarView(viewLayout)
, m_showMessageFunctor(std::bind(
&QtStatusBarView::doShowMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))
, m_setErrorCountFunctor(std::bind(&QtStatusBarView::doSetErrorCount, this, std::placeholders::_1))
{
m_widget = std::make_shared<QtStatusBar>();
m_widget->show();
QtMainView* mw = static_cast<QtMainView*>(viewLayout);
QStatusBar* sb = static_cast<QStatusBar*>(m_widget.get());
mw->setStatusBar(sb);
}
QtStatusBarView::~QtStatusBarView()
{
}
void QtStatusBarView::createWidgetWrapper()
{
}
void QtStatusBarView::initView()
{
}
void QtStatusBarView::refreshView()
{
}
void QtStatusBarView::showMessage(const std::string& message, bool isError, bool showLoader)
{
m_showMessageFunctor(message, isError, showLoader);
}
void QtStatusBarView::setErrorCount(size_t count)
{
m_setErrorCountFunctor(count);
}
void QtStatusBarView::doShowMessage(const std::string& message, bool isError, bool showLoader)
{
m_widget->setText(message, isError, showLoader);
}
void QtStatusBarView::doSetErrorCount(size_t count)
{
m_widget->setErrorCount(count);
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef QT_STATUS_BAR_VIEW_H
#define QT_STATUS_BAR_VIEW_H
#include <memory>
#include <string>
#include "component/view/StatusBarView.h"
#include "qt/element/QtStatusBar.h"
#include "qt/utility/QtThreadedFunctor.h"
class QtStatusBarView
: public StatusBarView
{
public:
QtStatusBarView(ViewLayout* viewLayout);
~QtStatusBarView();
// View implementation
virtual void createWidgetWrapper();
virtual void initView();
virtual void refreshView();
// StatusBar view implementation
virtual void showMessage(const std::string& message, bool isError, bool showLoader);
virtual void setErrorCount(size_t count);
private:
void doShowMessage(const std::string& message, bool isError, bool showLoader);
void doSetErrorCount(size_t count);
QtThreadedFunctor<const std::string&, bool, bool> m_showMessageFunctor;
QtThreadedFunctor<size_t> m_setErrorCountFunctor;
std::shared_ptr<QtStatusBar> m_widget;
};
#endif // !QT_STATUS_BAR_VIEW_H
+65
View File
@@ -0,0 +1,65 @@
#include "qt/view/QtUndoRedoView.h"
#include "qt/utility/utilityQt.h"
#include "qt/view/QtMainView.h"
#include "qt/view/QtViewWidgetWrapper.h"
QtUndoRedoView::QtUndoRedoView(ViewLayout* viewLayout)
: UndoRedoView(viewLayout)
, m_refreshFunctor(std::bind(&QtUndoRedoView::doRefreshView, this))
, m_setRedoButtonEnabledFunctor(std::bind(&QtUndoRedoView::doSetRedoButtonEnabled, this, std::placeholders::_1))
, m_setUndoButtonEnabledFunctor(std::bind(&QtUndoRedoView::doSetUndoButtonEnabled, this, std::placeholders::_1))
{
m_widget = new QtUndoRedo();
setStyleSheet();
}
QtUndoRedoView::~QtUndoRedoView()
{
}
void QtUndoRedoView::createWidgetWrapper()
{
setWidgetWrapper(std::make_shared<QtViewWidgetWrapper>(m_widget));
}
void QtUndoRedoView::initView()
{
}
void QtUndoRedoView::refreshView()
{
m_refreshFunctor();
}
void QtUndoRedoView::setStyleSheet()
{
m_widget->setStyleSheet(utility::getStyleSheet("data/gui/undoredo_view/undoredo_view.css").c_str());
}
void QtUndoRedoView::doRefreshView()
{
setStyleSheet();
m_widget->refreshStyle();
}
void QtUndoRedoView::doSetRedoButtonEnabled(bool enabled)
{
m_widget->setRedoButtonEnabled(enabled);
}
void QtUndoRedoView::doSetUndoButtonEnabled(bool enabled)
{
m_widget->setUndoButtonEnabled(enabled);
}
void QtUndoRedoView::setRedoButtonEnabled(bool enabled)
{
m_setRedoButtonEnabledFunctor(enabled);
}
void QtUndoRedoView::setUndoButtonEnabled(bool enabled)
{
m_setUndoButtonEnabledFunctor(enabled);
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef QT_UNDO_REDO_VIEW_H
#define QT_UNDO_REDO_VIEW_H
#include <memory>
#include <string>
#include "component/view/UndoRedoView.h"
#include "qt/element/QtUndoRedo.h"
#include "qt/utility/QtThreadedFunctor.h"
class QtUndoRedoView : public UndoRedoView
{
public:
QtUndoRedoView(ViewLayout* viewLayout);
~QtUndoRedoView();
// View implementation
virtual void createWidgetWrapper();
virtual void initView();
virtual void refreshView();
// UndoRedo view implementation
virtual void setRedoButtonEnabled(bool enabled);
virtual void setUndoButtonEnabled(bool enabled);
private:
void doRefreshView();
void doSetRedoButtonEnabled(bool enabled);
void doSetUndoButtonEnabled(bool enabled);
QtThreadedFunctor<void> m_refreshFunctor;
QtThreadedFunctor<bool> m_setRedoButtonEnabledFunctor;
QtThreadedFunctor<bool> m_setUndoButtonEnabledFunctor;
void setStyleSheet();
QtUndoRedo* m_widget;
};
#endif // !QT_UNDO_REDO_VIEW_H
+65
View File
@@ -0,0 +1,65 @@
#include "qt/view/QtViewFactory.h"
#include "component/view/GraphViewStyle.h"
#include "qt/view/QtCodeView.h"
#include "qt/view/QtCompositeView.h"
#include "qt/view/QtGraphView.h"
#include "qt/view/QtGraphViewStyleImpl.h"
#include "qt/view/QtMainView.h"
#include "qt/view/QtRefreshView.h"
#include "qt/view/QtSearchView.h"
#include "qt/view/QtStatusBarView.h"
#include "qt/view/QtUndoRedoView.h"
QtViewFactory::QtViewFactory()
{
}
QtViewFactory::~QtViewFactory()
{
}
std::shared_ptr<MainView> QtViewFactory::createMainView() const
{
return std::make_shared<QtMainView>();
}
std::shared_ptr<CompositeView> QtViewFactory::createCompositeView(
ViewLayout* viewLayout, CompositeView::CompositeDirection direction, const std::string& name
) const {
std::shared_ptr<CompositeView> ptr = std::make_shared<QtCompositeView>(viewLayout, direction, name);
ptr->init();
ptr->addToLayout();
return ptr;
}
std::shared_ptr<CodeView> QtViewFactory::createCodeView(ViewLayout* viewLayout) const
{
return View::createInitAndAddToLayout<QtCodeView>(viewLayout);
}
std::shared_ptr<GraphView> QtViewFactory::createGraphView(ViewLayout* viewLayout) const
{
GraphViewStyle::setImpl(std::make_shared<QtGraphViewStyleImpl>());
return View::createInitAndAddToLayout<QtGraphView>(viewLayout);
}
std::shared_ptr<RefreshView> QtViewFactory::createRefreshView(ViewLayout* viewLayout) const
{
return View::createInitAndAddToLayout<QtRefreshView>(viewLayout);
}
std::shared_ptr<SearchView> QtViewFactory::createSearchView(ViewLayout* viewLayout) const
{
return View::createInitAndAddToLayout<QtSearchView>(viewLayout);
}
std::shared_ptr<StatusBarView> QtViewFactory::createStatusBarView(ViewLayout* viewLayout) const
{
return View::createAndInit<QtStatusBarView>(viewLayout);
}
std::shared_ptr<UndoRedoView> QtViewFactory::createUndoRedoView(ViewLayout* viewLayout) const
{
return View::createInitAndAddToLayout<QtUndoRedoView>(viewLayout);
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef QT_VIEW_FACTORY_H
#define QT_VIEW_FACTORY_H
#include "component/view/ViewFactory.h"
class QtViewFactory: public ViewFactory
{
public:
QtViewFactory();
virtual ~QtViewFactory();
virtual std::shared_ptr<MainView> createMainView() const;
virtual std::shared_ptr<CompositeView> createCompositeView(
ViewLayout* viewLayout, CompositeView::CompositeDirection direction, const std::string& name) const;
virtual std::shared_ptr<CodeView> createCodeView(ViewLayout* viewLayout) const;
virtual std::shared_ptr<GraphView> createGraphView(ViewLayout* viewLayout) const;
virtual std::shared_ptr<RefreshView> createRefreshView(ViewLayout* viewLayout) const;
virtual std::shared_ptr<SearchView> createSearchView(ViewLayout* viewLayout) const;
virtual std::shared_ptr<StatusBarView> createStatusBarView(ViewLayout* viewLayout) const;
virtual std::shared_ptr<UndoRedoView> createUndoRedoView(ViewLayout* viewLayout) const;
};
#endif // QT_VIEW_FACTORY_H
@@ -0,0 +1,37 @@
#include "qt/view/QtViewWidgetWrapper.h"
#include "component/view/View.h"
#include "utility/logging/logging.h"
QWidget* QtViewWidgetWrapper::getWidgetOfView(const View* view)
{
QtViewWidgetWrapper* widgetWrapper = dynamic_cast<QtViewWidgetWrapper*>(view->getWidgetWrapper());
if (!widgetWrapper)
{
LOG_ERROR("Trying to get the qt widget of non qt view.");
return nullptr;
}
if (!widgetWrapper->getWidget())
{
LOG_ERROR("The QtViewWidgetWrapper is not holdling a QWidget.");
return nullptr;
}
return widgetWrapper->getWidget();
}
QtViewWidgetWrapper::QtViewWidgetWrapper(QWidget* widget)
: m_widget(widget)
{
}
QtViewWidgetWrapper::~QtViewWidgetWrapper()
{
}
QWidget* QtViewWidgetWrapper::getWidget()
{
return m_widget;
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef QT_VIEW_WIDGET_WRAPPER_H
#define QT_VIEW_WIDGET_WRAPPER_H
#include <QWidget>
#include "component/view/ViewWidgetWrapper.h"
class View;
class QtViewWidgetWrapper: public ViewWidgetWrapper
{
public:
static QWidget* getWidgetOfView(const View* view);
QtViewWidgetWrapper(QWidget* widget);
virtual ~QtViewWidgetWrapper();
QWidget* getWidget();
private:
QWidget* m_widget;
};
#endif // QT_VIEW_WIDGET_WRAPPER_H
@@ -0,0 +1,230 @@
#include "qt/view/graphElements/QtGraphEdge.h"
#include <QGraphicsSceneEvent>
#include "utility/messaging/type/MessageActivateEdge.h"
#include "utility/messaging/type/MessageFocusIn.h"
#include "utility/messaging/type/MessageFocusOut.h"
#include "utility/messaging/type/MessageGraphNodeBundleSplit.h"
#include "component/view/GraphViewStyle.h"
#include "data/graph/Edge.h"
#include "data/graph/token_component/TokenComponentAggregation.h"
#include "qt/graphics/QtAngledLineItem.h"
#include "qt/graphics/QtStraightLineItem.h"
#include "qt/view/graphElements/QtGraphNode.h"
QtGraphEdge::QtGraphEdge(
const std::weak_ptr<QtGraphNode>& owner, const std::weak_ptr<QtGraphNode>& target, const Edge* data, size_t weight
)
: m_data(data)
, m_owner(owner)
, m_target(target)
, m_child(nullptr)
, m_isActive(false)
, m_fromActive(false)
, m_toActive(false)
, m_weight(weight)
, m_direction(TokenComponentAggregation::DIRECTION_NONE)
, m_mousePos(0.0f, 0.0f)
, m_mouseMoved(false)
{
m_fromActive = m_owner.lock()->getIsActive();
m_toActive = m_target.lock()->getIsActive();
this->updateLine();
}
QtGraphEdge::~QtGraphEdge()
{
}
const Edge* QtGraphEdge::getData() const
{
return m_data;
}
std::weak_ptr<QtGraphNode> QtGraphEdge::getOwner()
{
return m_owner;
}
std::weak_ptr<QtGraphNode> QtGraphEdge::getTarget()
{
return m_target;
}
void QtGraphEdge::updateLine()
{
std::shared_ptr<QtGraphNode> owner = m_owner.lock();
std::shared_ptr<QtGraphNode> target = m_target.lock();
if (owner == NULL || target == NULL)
{
LOG_WARNING("Either the owner or the target node is null.");
return;
}
Edge::EdgeType type;
if (getData())
{
type = getData()->getType();
}
else
{
type = Edge::EDGE_AGGREGATION;
}
GraphViewStyle::EdgeStyle style = GraphViewStyle::getStyleForEdgeType(type, m_isActive, false);
if (style.isStraight)
{
if (!m_child)
{
m_child = new QtStraightLineItem(this);
}
bool showArrow = m_direction != TokenComponentAggregation::DIRECTION_NONE;
if (m_direction == TokenComponentAggregation::DIRECTION_BACKWARD)
{
owner.swap(target);
}
GraphViewStyle::NodeStyle countStyle = GraphViewStyle::getStyleOfCountCircle();
dynamic_cast<QtStraightLineItem*>(m_child)->updateLine(
owner->getBoundingRect(), target->getBoundingRect(), m_weight, style, countStyle, showArrow);
}
else
{
if (!m_child)
{
m_child = new QtAngledLineItem(this);
}
dynamic_cast<QtAngledLineItem*>(m_child)->updateLine(
owner->getBoundingRect(), target->getBoundingRect(),
owner->getParentBoundingRect(), target->getParentBoundingRect(),
style);
if (m_fromActive && owner->getLastParent() == target->getLastParent())
{
dynamic_cast<QtAngledLineItem*>(m_child)->setOnBack(true);
}
if (m_toActive)
{
dynamic_cast<QtAngledLineItem*>(m_child)->setHorizontalIn(true);
}
}
if (m_data)
{
m_child->setToolTip(QString::fromStdString(m_data->getTypeString()));
}
else
{
m_child->setToolTip(QString::fromStdString(Edge::getTypeString(Edge::EDGE_AGGREGATION)));
}
this->setZValue(style.zValue); // Used to draw edges always on top of nodes.
}
bool QtGraphEdge::getIsActive() const
{
return m_isActive;
}
void QtGraphEdge::setIsActive(bool isActive)
{
if (m_isActive != isActive)
{
m_isActive = isActive;
updateLine();
}
}
void QtGraphEdge::onClick()
{
if (!getData())
{
MessageGraphNodeBundleSplit(m_target.lock()->getTokenId()).dispatch();
}
else
{
MessageActivateEdge(
getData()->getId(),
getData()->getType(),
getData()->getFrom()->getNameHierarchy(),
getData()->getTo()->getNameHierarchy()
).dispatch();
}
}
void QtGraphEdge::focusIn()
{
bool isActive = m_isActive;
this->setIsActive(true);
m_isActive = isActive;
}
void QtGraphEdge::focusOut()
{
updateLine();
}
void QtGraphEdge::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
m_mousePos = Vec2i(event->scenePos().x(), event->scenePos().y());
m_mouseMoved = false;
}
void QtGraphEdge::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
Vec2i mousePos = Vec2i(event->scenePos().x(), event->scenePos().y());
if ((mousePos - m_mousePos).getLength() > 1.0f)
{
m_mouseMoved = true;
}
}
void QtGraphEdge::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
if (!m_mouseMoved)
{
this->onClick();
}
}
void QtGraphEdge::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
{
if (!getData())
{
focusIn();
return;
}
MessageFocusIn(std::vector<Id>(1, getData()->getId())).dispatch();
}
void QtGraphEdge::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
{
if (!getData())
{
focusOut();
return;
}
MessageFocusOut(std::vector<Id>(1, getData()->getId())).dispatch();
}
void QtGraphEdge::setDirection(TokenComponentAggregation::Direction direction)
{
if (m_direction != direction)
{
m_direction = direction;
updateLine();
}
}
@@ -0,0 +1,71 @@
#ifndef QT_GRAPH_EDGE_H
#define QT_GRAPH_EDGE_H
#include <memory>
#include <QGraphicsItem>
#include "utility/math/Vector2.h"
#include "data/graph/token_component/TokenComponentAggregation.h"
class Edge;
class QtGraphNode;
class QtGraphEdge
: public QObject
, public QGraphicsItemGroup
{
Q_OBJECT
Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity)
public:
QtGraphEdge(const std::weak_ptr<QtGraphNode>& owner, const std::weak_ptr<QtGraphNode>& target, const Edge* data, size_t weight);
virtual ~QtGraphEdge();
const Edge* getData() const;
std::weak_ptr<QtGraphNode> getOwner();
std::weak_ptr<QtGraphNode> getTarget();
void updateLine();
bool getIsActive() const;
void setIsActive(bool isActive);
void setFromAndToActive(bool fromActive, bool toActive);
void onClick();
void focusIn();
void focusOut();
void setDirection(TokenComponentAggregation::Direction direction);
protected:
virtual void mousePressEvent(QGraphicsSceneMouseEvent* event);
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event);
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent* event);
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event);
private:
const Edge* m_data;
std::weak_ptr<QtGraphNode> m_owner;
std::weak_ptr<QtGraphNode> m_target;
QGraphicsLineItem* m_child;
bool m_isActive;
bool m_fromActive;
bool m_toActive;
size_t m_weight;
TokenComponentAggregation::Direction m_direction;
Vec2i m_mousePos;
bool m_mouseMoved;
};
#endif // QT_GRAPH_EDGE_H
@@ -0,0 +1,401 @@
#include "qt/view/graphElements/QtGraphNode.h"
#include <QBrush>
#include <QFont>
#include <QGraphicsSceneEvent>
#include <QPen>
#include "component/controller/helper/GraphPostprocessor.h"
#include "qt/graphics/QtRoundedRectItem.h"
#include "qt/utility/QtDeviceScaledPixmap.h"
#include "qt/utility/utilityQt.h"
#include "qt/view/graphElements/nodeComponents/QtGraphNodeComponent.h"
#include "qt/view/graphElements/QtGraphEdge.h"
void QtGraphNode::blendIn()
{
setOpacity(1.0f);
}
void QtGraphNode::blendOut()
{
setOpacity(0.0f);
}
void QtGraphNode::showNode()
{
this->show();
}
void QtGraphNode::hideNode()
{
this->hide();
}
QFont QtGraphNode::getFontForNodeType(Node::NodeType type)
{
QFont font(GraphViewStyle::getFontNameForNodeType(type).c_str());
font.setPixelSize(GraphViewStyle::getFontSizeForNodeType(type));
return font;
}
QtGraphNode::QtGraphNode()
: m_undefinedRect(nullptr)
, m_icon(nullptr)
, m_isActive(false)
, m_isHovering(false)
{
this->setPen(QPen(Qt::transparent));
m_rect = new QtRoundedRectItem(this);
m_text = new QGraphicsSimpleTextItem(this);
}
QtGraphNode::~QtGraphNode()
{
}
QtGraphNode* QtGraphNode::getParent() const
{
return m_parentNode.lock().get();
}
QtGraphNode* QtGraphNode::getLastParent() const
{
QtGraphNode* node = const_cast<QtGraphNode*>(this);
while (true)
{
QtGraphNode* parent = dynamic_cast<QtGraphNode*>(node->parentItem());
if (!parent)
{
break;
}
node = parent;
}
return node;
}
void QtGraphNode::setParent(std::weak_ptr<QtGraphNode> parentNode)
{
m_parentNode = parentNode;
std::shared_ptr<QtGraphNode> parent = parentNode.lock();
if (parent != NULL)
{
QGraphicsRectItem::setParentItem(parent.get());
}
}
std::list<std::shared_ptr<QtGraphNode>> QtGraphNode::getSubNodes() const
{
return m_subNodes;
}
Vec2i QtGraphNode::getPosition() const
{
return Vec2i(this->scenePos().x(), this->scenePos().y());
}
bool QtGraphNode::setPosition(const Vec2i& position)
{
Vec2i currentPosition = getPosition();
Vec2i offset = position - currentPosition;
if (offset.getLength() > 0.0f)
{
this->moveBy(offset.x, offset.y);
notifyEdgesAfterMove();
return true;
}
return false;
}
Vec2i QtGraphNode::getSize() const
{
return m_size;
}
void QtGraphNode::setSize(const Vec2i& size)
{
m_size = size;
this->setRect(0, 0, size.x, size.y);
m_rect->setRect(0, 0, size.x, size.y);
if (m_undefinedRect)
{
m_undefinedRect->setRect(1, 1, size.x - 2, size.y - 2);
}
}
QSize QtGraphNode::size() const
{
return QSize(m_size.x, m_size.y);
}
void QtGraphNode::setSize(const QSize& size)
{
setSize(Vec2i(size.width(), size.height()));
}
Vec4i QtGraphNode::getBoundingRect() const
{
Vec2i pos = getPosition();
Vec2i size = getSize();
return Vec4i(pos.x, pos.y, pos.x + size.x, pos.y + size.y);
}
Vec4i QtGraphNode::getParentBoundingRect() const
{
return getLastParent()->getBoundingRect();
}
void QtGraphNode::addOutEdge(const std::shared_ptr<QtGraphEdge>& edge)
{
m_outEdges.push_back(edge);
}
void QtGraphNode::addInEdge(const std::weak_ptr<QtGraphEdge>& edge)
{
m_inEdges.push_back(edge);
}
size_t QtGraphNode::getOutEdgeCount() const
{
return m_outEdges.size();
}
size_t QtGraphNode::getInEdgeCount() const
{
return m_inEdges.size();
}
bool QtGraphNode::getIsActive() const
{
return m_isActive;
}
void QtGraphNode::setIsActive(bool isActive)
{
m_isActive = isActive;
updateStyle();
}
std::string QtGraphNode::getName() const
{
return m_text->text().toStdString();
}
void QtGraphNode::setName(const std::string& name)
{
m_text->setText(QString::fromStdString(name));
}
void QtGraphNode::addComponent(const std::shared_ptr<QtGraphNodeComponent>& component)
{
m_components.push_back(component);
}
void QtGraphNode::hoverEnter()
{
hoverEnterEvent(nullptr);
QtGraphNode* parent = getParent();
if (parent)
{
parent->hoverEnter();
}
}
void QtGraphNode::focusIn()
{
m_isHovering = true;
updateStyle();
}
void QtGraphNode::focusOut()
{
m_isHovering = false;
updateStyle();
}
bool QtGraphNode::isDataNode() const
{
return false;
}
bool QtGraphNode::isAccessNode() const
{
return false;
}
bool QtGraphNode::isExpandToggleNode() const
{
return false;
}
bool QtGraphNode::isBundleNode() const
{
return false;
}
Id QtGraphNode::getTokenId() const
{
return 0;
}
void QtGraphNode::addSubNode(const std::shared_ptr<QtGraphNode>& node)
{
m_subNodes.push_back(node);
}
void QtGraphNode::moved(const Vec2i& oldPosition)
{
setPosition(GraphPostprocessor::alignOnRaster(getPosition()));
}
void QtGraphNode::onClick()
{
}
void QtGraphNode::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
event->ignore();
for (std::shared_ptr<QtGraphNodeComponent> component : m_components)
{
component->nodeMousePressEvent(event);
}
if (!event->isAccepted())
{
QtGraphNode* parent = getParent();
if (parent)
{
parent->mousePressEvent(event);
}
}
}
void QtGraphNode::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
event->ignore();
for (std::shared_ptr<QtGraphNodeComponent> component : m_components)
{
component->nodeMouseMoveEvent(event);
}
if (!event->isAccepted())
{
QtGraphNode* parent = getParent();
if (parent)
{
parent->mouseMoveEvent(event);
}
}
}
void QtGraphNode::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
event->ignore();
for (std::shared_ptr<QtGraphNodeComponent> component : m_components)
{
component->nodeMouseReleaseEvent(event);
}
if (!event->isAccepted())
{
QtGraphNode* parent = getParent();
if (parent)
{
parent->mouseReleaseEvent(event);
}
}
}
void QtGraphNode::notifyEdgesAfterMove()
{
for (const std::shared_ptr<QtGraphEdge>& edge : m_outEdges)
{
edge->updateLine();
}
for (const std::weak_ptr<QtGraphEdge>& e : m_inEdges)
{
std::shared_ptr<QtGraphEdge> edge = e.lock();
if (edge)
{
edge->updateLine();
}
}
for (const std::shared_ptr<QtGraphNode>& node : m_subNodes)
{
node->notifyEdgesAfterMove();
}
}
void QtGraphNode::setStyle(const GraphViewStyle::NodeStyle& style)
{
QPen pen(Qt::transparent);
if (style.borderWidth > 0)
{
pen.setColor(style.color.border.c_str());
pen.setWidthF(style.borderWidth);
if (style.borderDashed)
{
pen.setStyle(Qt::DashLine);
}
}
m_rect->setPen(pen);
m_rect->setBrush(QBrush(style.color.fill.c_str()));
qreal radius = style.cornerRadius;
m_rect->setRadius(radius);
if (style.hasHatching)
{
QtDeviceScaledPixmap pattern("data/gui/graph_view/images/pattern.png");
pattern.scaleToHeight(10);
QPixmap pixmap = utility::colorizePixmap(pattern.pixmap(), style.color.hatching.c_str());
if (!m_undefinedRect)
{
m_undefinedRect = new QtRoundedRectItem(this);
setSize(getSize());
}
pen.setWidth(0);
pen.setColor(Qt::transparent);
m_undefinedRect->setPen(pen);
m_undefinedRect->setBrush(pixmap);
m_undefinedRect->setRadius(radius);
}
if (style.iconPath.size())
{
QtDeviceScaledPixmap pixmap(QString::fromStdString(style.iconPath));
pixmap.scaleToHeight(style.iconSize);
m_icon = new QGraphicsPixmapItem(utility::colorizePixmap(pixmap.pixmap(), style.color.icon.c_str()), this);
m_icon->setPos(style.iconOffset.x, style.iconOffset.y);
}
QFont font(style.fontName.c_str());
font.setPixelSize(style.fontSize);
if (style.fontBold)
{
font.setWeight(QFont::Bold);
}
m_text->setFont(font);
m_text->setBrush(QBrush(style.color.text.c_str()));
m_text->setPos(style.iconOffset.x + style.iconSize + style.textOffset.x, style.textOffset.y);
}
@@ -0,0 +1,117 @@
#ifndef QT_GRAPH_NODE_H
#define QT_GRAPH_NODE_H
#include <QGraphicsItem>
#include "utility/math/Vector4.h"
#include "component/view/GraphViewStyle.h"
class QFont;
class QtGraphEdge;
class QtRoundedRectItem;
class QtGraphNodeComponent;
class QtGraphNode
: public QObject
, public QGraphicsRectItem
{
Q_OBJECT
Q_PROPERTY(QPointF pos READ pos WRITE setPos)
Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity)
Q_PROPERTY(QSize size READ size WRITE setSize)
public slots:
void blendIn();
void blendOut();
void showNode();
void hideNode();
public:
static QFont getFontForNodeType(Node::NodeType type);
QtGraphNode();
virtual ~QtGraphNode();
QtGraphNode* getParent() const;
QtGraphNode* getLastParent() const;
void setParent(std::weak_ptr<QtGraphNode> parentNode);
std::list<std::shared_ptr<QtGraphNode>> getSubNodes() const;
Vec2i getPosition() const;
bool setPosition(const Vec2i& position);
Vec2i getSize() const;
void setSize(const Vec2i& size);
QSize size() const;
void setSize(const QSize& size);
Vec4i getBoundingRect() const;
Vec4i getParentBoundingRect() const;
void addOutEdge(const std::shared_ptr<QtGraphEdge>& edge);
void addInEdge(const std::weak_ptr<QtGraphEdge>& edge);
size_t getOutEdgeCount() const;
size_t getInEdgeCount() const;
bool getIsActive() const;
void setIsActive(bool isActive);
std::string getName() const;
void setName(const std::string& name);
void addComponent(const std::shared_ptr<QtGraphNodeComponent>& component);
void hoverEnter();
void focusIn();
void focusOut();
virtual bool isDataNode() const;
virtual bool isAccessNode() const;
virtual bool isExpandToggleNode() const;
virtual bool isBundleNode() const;
virtual Id getTokenId() const;
virtual void addSubNode(const std::shared_ptr<QtGraphNode>& node);
virtual void onClick();
virtual void moved(const Vec2i& oldPosition);
virtual void updateStyle() = 0;
protected:
virtual void mousePressEvent(QGraphicsSceneMouseEvent* event);
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event);
void notifyEdgesAfterMove();
void setStyle(const GraphViewStyle::NodeStyle& style);
std::list<std::shared_ptr<QtGraphEdge>> m_outEdges;
std::list<std::weak_ptr<QtGraphEdge>> m_inEdges;
std::weak_ptr<QtGraphNode> m_parentNode;
std::list<std::shared_ptr<QtGraphNode>> m_subNodes;
QGraphicsSimpleTextItem* m_text;
QtRoundedRectItem* m_rect;
QtRoundedRectItem* m_undefinedRect;
QGraphicsPixmapItem* m_icon;
Vec2i m_size;
bool m_isActive;
bool m_isHovering;
private:
std::list<std::shared_ptr<QtGraphNodeComponent>> m_components;
};
#endif // QT_GRAPH_NODE_H
@@ -0,0 +1,65 @@
#include "qt/view/graphElements/QtGraphNodeAccess.h"
#include <QBrush>
#include <QFontMetrics>
#include <QPen>
#include "component/view/GraphViewStyle.h"
#include "qt/graphics/QtRoundedRectItem.h"
#include "qt/utility/QtDeviceScaledPixmap.h"
#include "qt/utility/utilityQt.h"
QtGraphNodeAccess::QtGraphNodeAccess(TokenComponentAccess::AccessType accessType)
: QtGraphNode()
, m_access(accessType)
, m_accessIconSize(20)
{
std::string accessString = TokenComponentAccess::getAccessString(accessType);
this->setName(accessString);
m_text->hide();
QtDeviceScaledPixmap pixmap(QString::fromStdString("data/gui/graph_view/images/" + accessString + ".png"));
pixmap.scaleToHeight(m_accessIconSize);
m_accessIcon = new QGraphicsPixmapItem(pixmap.pixmap(), this);
}
QtGraphNodeAccess::~QtGraphNodeAccess()
{
}
TokenComponentAccess::AccessType QtGraphNodeAccess::getAccessType() const
{
return m_access;
}
bool QtGraphNodeAccess::isAccessNode() const
{
return true;
}
void QtGraphNodeAccess::addSubNode(const std::shared_ptr<QtGraphNode>& node)
{
QtGraphNode::addSubNode(node);
m_text->show();
}
void QtGraphNodeAccess::updateStyle()
{
GraphViewStyle::NodeStyle style = GraphViewStyle::getStyleOfAccessNode();
setStyle(style);
QFont font = m_text->font();
font.setCapitalization(QFont::AllUppercase);
m_text->setFont(font);
m_text->setPos(style.textOffset.x + m_accessIconSize + 3, style.textOffset.x + m_accessIconSize + 2 - style.fontSize);
m_accessIcon->setPos(style.textOffset.x, style.textOffset.y);
m_accessIcon->setPixmap(utility::colorizePixmap(m_accessIcon->pixmap(), style.color.icon.c_str()));
}
void QtGraphNodeAccess::hideLabel()
{
m_text->hide();
}
@@ -0,0 +1,31 @@
#ifndef QT_GRAPH_NODE_ACCESS_H
#define QT_GRAPH_NODE_ACCESS_H
#include "data/graph/token_component/TokenComponentAccess.h"
#include "qt/view/graphElements/QtGraphNode.h"
class QtGraphNodeAccess
: public QtGraphNode
{
public:
QtGraphNodeAccess(TokenComponentAccess::AccessType accessType);
virtual ~QtGraphNodeAccess();
TokenComponentAccess::AccessType getAccessType() const;
// QtGraphNode implementation
virtual bool isAccessNode() const;
virtual void addSubNode(const std::shared_ptr<QtGraphNode>& node);
virtual void updateStyle();
void hideLabel();
private:
TokenComponentAccess::AccessType m_access;
QGraphicsPixmapItem* m_accessIcon;
int m_accessIconSize;
};
#endif // QT_GRAPH_NODE_ACCESS_H
@@ -0,0 +1,69 @@
#include "qt/view/graphElements/QtGraphNodeBundle.h"
#include <QBrush>
#include <QPen>
#include "utility/messaging/type/MessageGraphNodeBundleSplit.h"
#include "component/view/GraphViewStyle.h"
#include "qt/graphics/QtCountCircleItem.h"
QtGraphNodeBundle::QtGraphNodeBundle(Id tokenId, size_t nodeCount, std::string name)
: QtGraphNode()
, m_tokenId(tokenId)
{
this->setName(name);
m_circle = new QtCountCircleItem(this);
m_circle->setNumber(nodeCount);
this->setAcceptHoverEvents(true);
this->setToolTip("bundle");
}
QtGraphNodeBundle::~QtGraphNodeBundle()
{
}
bool QtGraphNodeBundle::isBundleNode() const
{
return true;
}
Id QtGraphNodeBundle::getTokenId() const
{
return m_tokenId;
}
void QtGraphNodeBundle::onClick()
{
MessageGraphNodeBundleSplit(m_tokenId).dispatch();
}
void QtGraphNodeBundle::updateStyle()
{
GraphViewStyle::NodeStyle style = GraphViewStyle::getStyleOfBundleNode(m_isHovering);
setStyle(style);
m_circle->setPosition(Vec2f(m_rect->rect().right() - 3, m_rect->rect().top() + 3));
GraphViewStyle::NodeStyle accessStyle = GraphViewStyle::getStyleOfCountCircle();
m_circle->setStyle(
accessStyle.color.fill.c_str(),
accessStyle.color.text.c_str(),
accessStyle.color.border.c_str(),
style.borderWidth
);
}
void QtGraphNodeBundle::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
{
focusIn();
}
void QtGraphNodeBundle::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
{
focusOut();
}
@@ -0,0 +1,32 @@
#ifndef QT_GRAPH_NODE_BUNDLE_H
#define QT_GRAPH_NODE_BUNDLE_H
#include "qt/view/graphElements/QtGraphNode.h"
class QtCountCircleItem;
class QtGraphNodeBundle
: public QtGraphNode
{
public:
QtGraphNodeBundle(Id tokenId, size_t nodeCount, std::string name);
virtual ~QtGraphNodeBundle();
// QtGraphNode implementation
virtual bool isBundleNode() const;
virtual Id getTokenId() const;
virtual void onClick();
virtual void updateStyle();
protected:
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent* event);
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event);
private:
QtCountCircleItem* m_circle;
Id m_tokenId;
};
#endif // QT_GRAPH_NODE_BUNDLE_H
@@ -0,0 +1,91 @@
#include "qt/view/graphElements/QtGraphNodeData.h"
#include "utility/messaging/type/MessageActivateNodes.h"
#include "utility/messaging/type/MessageFocusIn.h"
#include "utility/messaging/type/MessageFocusOut.h"
#include "utility/messaging/type/MessageGraphNodeMove.h"
#include "data/graph/token_component/TokenComponentSignature.h"
QtGraphNodeData::QtGraphNodeData(const Node* data, bool hasParent, bool childVisible)
: m_data(data)
, m_childVisible(childVisible)
{
this->setAcceptHoverEvents(true);
if (!hasParent)
{
this->setName(data->getFullName());
}
else
{
this->setName(data->getName());
}
std::string toolTip = data->getTypeString();
if (!data->isDefined() && !data->isType(Node::NODE_UNDEFINED))
{
toolTip = "undefined " + toolTip;
}
if (data->isType(Node::NODE_FUNCTION | Node::NODE_METHOD))
{
TokenComponentSignature* sig = data->getComponent<TokenComponentSignature>();
if (sig)
{
toolTip += ": " + sig->getSignature();
}
}
this->setToolTip(QString::fromStdString(toolTip));
}
QtGraphNodeData::~QtGraphNodeData()
{
}
const Node* QtGraphNodeData::getData() const
{
return m_data;
}
bool QtGraphNodeData::isDataNode() const
{
return true;
}
Id QtGraphNodeData::getTokenId() const
{
return m_data->getId();
}
void QtGraphNodeData::onClick()
{
MessageActivateNodes message;
message.addNode(m_data->getId(), m_data->getType(), m_data->getNameHierarchy());
message.dispatch();
}
void QtGraphNodeData::moved(const Vec2i& oldPosition)
{
QtGraphNode::moved(oldPosition);
MessageGraphNodeMove(m_data->getId(), getPosition() - oldPosition).dispatch();
}
void QtGraphNodeData::updateStyle()
{
GraphViewStyle::NodeStyle style =
GraphViewStyle::getStyleForNodeType(m_data->getType(), m_data->isDefined(), m_isActive, m_isHovering, m_childVisible);
setStyle(style);
}
void QtGraphNodeData::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
{
MessageFocusIn(std::vector<Id>(1, m_data->getId())).dispatch();
}
void QtGraphNodeData::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
{
MessageFocusOut(std::vector<Id>(1, m_data->getId())).dispatch();
}
@@ -0,0 +1,33 @@
#ifndef QT_GRAPH_NODE_DATA_H
#define QT_GRAPH_NODE_DATA_H
#include "qt/view/graphElements/QtGraphNode.h"
class QtGraphNodeData
: public QtGraphNode
{
public:
QtGraphNodeData(const Node* data, bool hasParent, bool childVisible);
virtual ~QtGraphNodeData();
const Node* getData() const;
// QtGraphNode implementation
virtual bool isDataNode() const;
virtual Id getTokenId() const;
virtual void onClick();
virtual void moved(const Vec2i& oldPosition);
virtual void updateStyle();
protected:
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent* event);
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event);
private:
const Node* m_data;
bool m_childVisible;
};
#endif // QT_GRAPH_NODE_DATA_H
@@ -0,0 +1,77 @@
#include "qt/view/graphElements/QtGraphNodeExpandToggle.h"
#include <QFontMetrics>
#include "utility/logging/logging.h"
#include "utility/messaging/type/MessageGraphNodeExpand.h"
#include "qt/graphics/QtRoundedRectItem.h"
#include "qt/utility/QtDeviceScaledPixmap.h"
#include "qt/utility/utilityQt.h"
#include "qt/view/graphElements/QtGraphNodeData.h"
QtGraphNodeExpandToggle::QtGraphNodeExpandToggle(bool expanded, int invisibleSubNodeCount)
: m_invisibleSubNodeCount(invisibleSubNodeCount)
, m_expanded(expanded)
{
if (!expanded && !invisibleSubNodeCount)
{
LOG_ERROR("ExpandToggle shouldn't be visible");
return;
}
const int iconHeight = 4;
m_icon = new QGraphicsPixmapItem(this);
QtDeviceScaledPixmap pixmap("data/gui/graph_view/images/arrow.png");
pixmap.scaleToHeight(iconHeight);
if (invisibleSubNodeCount)
{
QString numberStr = QString::number(invisibleSubNodeCount);
m_text->setText(numberStr);
}
else
{
pixmap.mirror();
}
m_icon->setPixmap(pixmap.pixmap());
}
QtGraphNodeExpandToggle::~QtGraphNodeExpandToggle()
{
}
bool QtGraphNodeExpandToggle::isExpandToggleNode() const
{
return true;
}
void QtGraphNodeExpandToggle::onClick()
{
QtGraphNode* parent = getParent();
if (parent && parent->getTokenId())
{
MessageGraphNodeExpand(parent->getTokenId(), !m_expanded).dispatch();
}
}
void QtGraphNodeExpandToggle::updateStyle()
{
GraphViewStyle::NodeStyle style = GraphViewStyle::getStyleOfExpandToggleNode();
setStyle(style);
m_text->setPos(
(m_rect->rect().width() - QFontMetrics(m_text->font()).width(m_text->text())) / 2,
6
);
m_icon->setPos(
(m_rect->rect().width() - m_icon->pixmap().width() / QtDeviceScaledPixmap::devicePixelRatio()) / 2,
(m_invisibleSubNodeCount == 0 ? m_rect->rect().height() / 2 - 2 : m_rect->rect().height() - 7)
);
m_icon->setPixmap(utility::colorizePixmap(m_icon->pixmap(), style.color.icon.c_str()));
}
@@ -0,0 +1,27 @@
#ifndef QT_EXPAND_TOGGLE_H
#define QT_EXPAND_TOGGLE_H
#include <QGraphicsItem>
#include "qt/view/graphElements/QtGraphNode.h"
class QtGraphNodeExpandToggle
: public QtGraphNode
{
public:
QtGraphNodeExpandToggle(bool expanded, int invisibleSubNodeCount);
virtual ~QtGraphNodeExpandToggle();
// QtGraphNode implementation
virtual bool isExpandToggleNode() const;
virtual void onClick();
virtual void updateStyle();
private:
QGraphicsPixmapItem* m_icon;
bool m_invisibleSubNodeCount;
bool m_expanded;
};
#endif // QT_EXPAND_TOGGLE_H
@@ -0,0 +1,22 @@
#include "QtGraphNodeComponent.h"
QtGraphNodeComponent::QtGraphNodeComponent(const std::weak_ptr<QtGraphNode>& graphNode)
: m_graphNode(graphNode)
{
}
QtGraphNodeComponent::~QtGraphNodeComponent()
{
}
void QtGraphNodeComponent::nodeMousePressEvent(QGraphicsSceneMouseEvent* event)
{
}
void QtGraphNodeComponent::nodeMouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
}
void QtGraphNodeComponent::nodeMouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
}
@@ -0,0 +1,24 @@
#ifndef QT_GRAPH_NODE_COMPONENT_H
#define QT_GRAPH_NODE_COMPONENT_H
#include <memory>
#include <QGraphicsItem>
class QtGraphNode;
class QtGraphNodeComponent
{
public:
QtGraphNodeComponent(const std::weak_ptr<QtGraphNode>& graphNode);
virtual ~QtGraphNodeComponent();
virtual void nodeMousePressEvent(QGraphicsSceneMouseEvent* event);
virtual void nodeMouseMoveEvent(QGraphicsSceneMouseEvent* event);
virtual void nodeMouseReleaseEvent(QGraphicsSceneMouseEvent* event);
protected:
std::weak_ptr<QtGraphNode> m_graphNode;
};
#endif // QT_GRAPH_NODE_COMPONENT_H
@@ -0,0 +1,45 @@
#include "QtGraphNodeComponentClickable.h"
#include <QGraphicsSceneEvent>
#include "qt/view/graphElements/QtGraphNode.h"
QtGraphNodeComponentClickable::QtGraphNodeComponentClickable(const std::weak_ptr<QtGraphNode>& graphNode)
: QtGraphNodeComponent(graphNode)
, m_mousePos(0.0f, 0.0f)
, m_mouseMoved(false)
{
}
QtGraphNodeComponentClickable::~QtGraphNodeComponentClickable()
{
}
void QtGraphNodeComponentClickable::nodeMousePressEvent(QGraphicsSceneMouseEvent* event)
{
m_mousePos = Vec2i(event->scenePos().x(), event->scenePos().y());
m_mouseMoved = false;
}
void QtGraphNodeComponentClickable::nodeMouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
Vec2i mousePos = Vec2i(event->scenePos().x(), event->scenePos().y());
if ((mousePos - m_mousePos).getLength() > 1.0f)
{
m_mouseMoved = true;
}
}
void QtGraphNodeComponentClickable::nodeMouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
if (!m_mouseMoved)
{
std::shared_ptr<QtGraphNode> node = m_graphNode.lock();
if (node != NULL)
{
node->onClick();
event->accept();
}
}
}
@@ -0,0 +1,24 @@
#ifndef QT_GRAPH_NODE_COMPONENT_CLICKABLE
#define QT_GRAPH_NODE_COMPONENT_CLICKABLE
#include "QtGraphNodeComponent.h"
#include "utility/math/Vector2.h"
class QtGraphNodeComponentClickable
: public QtGraphNodeComponent
{
public:
QtGraphNodeComponentClickable(const std::weak_ptr<QtGraphNode>& graphNode);
virtual ~QtGraphNodeComponentClickable();
virtual void nodeMousePressEvent(QGraphicsSceneMouseEvent* event);
virtual void nodeMouseMoveEvent(QGraphicsSceneMouseEvent* event);
virtual void nodeMouseReleaseEvent(QGraphicsSceneMouseEvent* event);
private:
Vec2i m_mousePos;
bool m_mouseMoved;
};
#endif // QT_GRAPH_NODE_COMPONENT_CLICKABLE
@@ -0,0 +1,52 @@
#include "QtGraphNodeComponentMoveable.h"
#include <QGraphicsSceneEvent>
#include "qt/view/graphElements/QtGraphNode.h"
QtGraphNodeComponentMoveable::QtGraphNodeComponentMoveable(const std::weak_ptr<QtGraphNode>& graphNode)
: QtGraphNodeComponent(graphNode)
, m_mouseOffset(0.0f, 0.0f)
{
}
QtGraphNodeComponentMoveable::~QtGraphNodeComponentMoveable()
{
}
void QtGraphNodeComponentMoveable::nodeMousePressEvent(QGraphicsSceneMouseEvent* event)
{
std::shared_ptr<QtGraphNode> node = m_graphNode.lock();
if (node != NULL)
{
m_oldPos = node->getPosition();
m_mouseOffset.x = event->scenePos().x() - m_oldPos.x;
m_mouseOffset.y = event->scenePos().y() - m_oldPos.y;
event->accept();
}
}
void QtGraphNodeComponentMoveable::nodeMouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
std::shared_ptr<QtGraphNode> node = m_graphNode.lock();
if (node != NULL)
{
node->setPosition(Vec2i(event->scenePos().x() - m_mouseOffset.x, event->scenePos().y() - m_mouseOffset.y));
event->accept();
}
}
void QtGraphNodeComponentMoveable::nodeMouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
if (event->isAccepted())
{
return;
}
std::shared_ptr<QtGraphNode> node = m_graphNode.lock();
if (node != NULL)
{
node->moved(m_oldPos);
}
}
@@ -0,0 +1,24 @@
#ifndef QT_GRAPH_NODE_COMPONENT_MOVEABLE
#define QT_GRAPH_NODE_COMPONENT_MOVEABLE
#include "QtGraphNodeComponent.h"
#include "utility/math/Vector2.h"
class QtGraphNodeComponentMoveable
: public QtGraphNodeComponent
{
public:
QtGraphNodeComponentMoveable(const std::weak_ptr<QtGraphNode>& graphNode);
virtual ~QtGraphNodeComponentMoveable();
virtual void nodeMousePressEvent(QGraphicsSceneMouseEvent* event);
virtual void nodeMouseMoveEvent(QGraphicsSceneMouseEvent* event);
virtual void nodeMouseReleaseEvent(QGraphicsSceneMouseEvent* event);
private:
Vec2i m_mouseOffset;
Vec2i m_oldPos;
};
#endif // QT_GRAPH_NODE_COMPONENT_MOVEABLE
+112
View File
@@ -0,0 +1,112 @@
#include "qt/window/QtAbout.h"
#include <QFormLayout>
#include <QLineEdit>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include "qt/utility/QtDeviceScaledPixmap.h"
#include "qt/utility/utilityQt.h"
#include "utility/Version.h"
QtAbout::QtAbout(QWidget *parent)
: QtSettingsWindow(parent)
{
raise();
}
QSize QtAbout::sizeHint() const
{
return QSize(370, 550);
}
void QtAbout::setup()
{
m_window->setStyleSheet(
m_window->styleSheet() +
"#SettingWindow { "
"background: qlineargradient( x1:0 y1:0.4, x2:0 y2:1, stop:0 #2F3F86, stop:1 #1C7BBC );"
"border: none;"
"}"
);
setStyleSheet(utility::getStyleSheet("data/gui/about/about.css").c_str());
QtDeviceScaledPixmap coatiLogo("data/gui/about/logo.png");
coatiLogo.scaleToWidth(180);
QLabel* coatiLogoLabel = new QLabel(this);
coatiLogoLabel->setPixmap(coatiLogo.pixmap());
coatiLogoLabel->resize(coatiLogo.width(), coatiLogo.height());
coatiLogoLabel->move(8, 20);
QLabel* versionLabel = new QLabel(("Version " + Version::getApplicationVersion().toDisplayString()).c_str(), this);
versionLabel->move(210, 181);
QLabel* developerTitle = new QLabel("Developed by:", this);
developerTitle->move(30, 220);
QLabel* companyLabel = new QLabel(
"Coati Software OG\n"
"Schlossallee 7/1\n"
"5412 Puch bei Hallein\n"
"Austria\n"
"support@coati.io\n",
this
);
companyLabel->move(210, 250);
QLabel* developerLabel = new QLabel(
"Manuel Dobusch\n"
"Eberhard Gräther\n"
"Malte Langkabel\n"
"Viktoria Pfausler\n"
"Andreas Stallinger\n",
this
);
developerLabel->move(30, 250);
QLabel* acknowledgementsTitle = new QLabel("Acknowledgements:", this);
acknowledgementsTitle->setObjectName("small");
acknowledgementsTitle->move(30, 355);
QLabel* acknowledgementsLabel = new QLabel(
"Coati 0.1 was created in the context of education at",
this
);
acknowledgementsLabel->setObjectName("small");
acknowledgementsLabel->move(30, 385);
QtDeviceScaledPixmap fhsLogo("data/gui/about/logo_fhs.png");
fhsLogo.scaleToWidth(150);
QLabel* fhsLabel = new QLabel(this);
fhsLabel->setPixmap(fhsLogo.pixmap());
fhsLabel->resize(fhsLogo.width(), fhsLogo.height());
fhsLabel->move(115, 410);
QLabel* acknowledgementsLabel2 = new QLabel(
"Coati Software OG takes part in the Startup Salzburg\ninitiative.",
this
);
acknowledgementsLabel2->setObjectName("small");
acknowledgementsLabel2->move(30, 465);
QPushButton* closeButton = new QPushButton("X", this);
closeButton->setObjectName("closeButton");
closeButton->move(320, 20);
connect(closeButton, SIGNAL(clicked()), this, SLOT(handleCloseButtonPress()));
}
void QtAbout::handleCloseButtonPress()
{
emit finished();
}
void QtAbout::handleCancelButtonPress()
{
}
void QtAbout::handleUpdateButtonPress()
{
}
+27
View File
@@ -0,0 +1,27 @@
#ifndef QT_ABOUT_H
#define QT_ABOUT_H
#include <QPushButton>
#include <QWidget>
#include "qt/window/QtSettingsWindow.h"
class QtAbout
: public QtSettingsWindow
{
Q_OBJECT
public:
QtAbout(QWidget* parent = 0);
QSize sizeHint() const Q_DECL_OVERRIDE;
virtual void setup() override;
private slots:
void handleCloseButtonPress();
void handleCancelButtonPress();
void handleUpdateButtonPress();
};
#endif //QT_ABOUT_H
+65
View File
@@ -0,0 +1,65 @@
#include "qt/window/QtAboutLicense.h"
#include <QComboBox>
#include <QFormLayout>
#include <QLineEdit>
#include <QLabel>
#include <QTextBrowser>
#include <QTextBlock>
#include <QTextEdit>
#include "licenses.h"
QtAboutLicense::QtAboutLicense(QWidget *parent)
: QtSettingsWindow(parent)
{
raise();
}
QSize QtAboutLicense::sizeHint() const
{
return QSize(600,600);
}
void QtAboutLicense::setup()
{
setupForm();
updateTitle("3rd Party Licenses");
updateDoneButton("Ok");
hideCancelButton(true);
}
void QtAboutLicense::populateForm(QFormLayout* layout)
{
for(ThirdPartyLicense license : licenses3rdParties)
{
QLabel* licenseName = new QLabel();
licenseName->setText( QString::fromLatin1(license.name));
QFont _font = licenseName->font();
_font.setPixelSize(36);
licenseName->setFont(_font);
layout->addWidget(licenseName);
QLabel* licenseURL = new QLabel();
licenseURL->setText(QString::fromLatin1("(<a href=\"%1\">Website</a>)")
.arg(QString::fromLatin1(license.url)));
licenseURL->setOpenExternalLinks(true);
layout->addWidget(licenseURL);
QLabel* licenseText = new QLabel();
licenseText->setFixedWidth(450);
licenseText->setWordWrap(true);
licenseText->setText(QString::fromLatin1(license.license));
layout->addWidget(licenseText);
}
}
void QtAboutLicense::handleCancelButtonPress()
{
}
void QtAboutLicense::handleUpdateButtonPress()
{
emit finished();
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef QT_ABOUT_LICENSE_H
#define QT_ABOUT_LICENSE_H
#include <QPushButton>
#include <QWidget>
#include "qt/window/QtSettingsWindow.h"
class QtAboutLicense
: public QtSettingsWindow
{
Q_OBJECT
public:
QtAboutLicense(QWidget* parent = 0);
QSize sizeHint() const Q_DECL_OVERRIDE;
virtual void setup() override;
protected:
virtual void populateForm(QFormLayout* layout) override;
private slots:
void handleCancelButtonPress();
void handleUpdateButtonPress();
};
#endif //QT_ABOUT_LICENSE_H
@@ -0,0 +1,104 @@
#include "qt/window/QtApplicationSettingsScreen.h"
#include <QComboBox>
#include <QFormLayout>
#include <QLineEdit>
#include <QSysInfo>
#include "utility/messaging/type/MessageLoadProject.h"
#include "utility/messaging/type/MessageRefresh.h"
#include "settings/ApplicationSettings.h"
QtApplicationSettingsScreen::QtApplicationSettingsScreen(QWidget *parent)
: QtSettingsWindow(parent)
, m_frameworkPaths(nullptr)
{
raise();
}
QSize QtApplicationSettingsScreen::sizeHint() const
{
return QSize(600,600);
}
void QtApplicationSettingsScreen::setup()
{
setupForm();
updateTitle("PREFERENCES");
updateDoneButton("Save");
}
void QtApplicationSettingsScreen::load()
{
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
m_includePaths->setList(appSettings->getHeaderSearchPaths());
if (m_frameworkPaths)
{
m_frameworkPaths->setList(appSettings->getFrameworkSearchPaths());
}
}
void QtApplicationSettingsScreen::populateForm(QFormLayout* layout)
{
int minimumWidthForSecondCol = 360;
QPushButton* helpButton;
QWidget* includePathsWidget = createLabelWithHelpButton("Header\nSearch Paths", &helpButton);
connect(helpButton, SIGNAL(clicked()), this, SLOT(handleIncludePathHelpPress()));
m_includePaths = new QtDirectoryListBox(this);
m_includePaths->setMinimumWidth(minimumWidthForSecondCol);
layout->addRow(includePathsWidget, m_includePaths);
if (QSysInfo::macVersion() != QSysInfo::MV_None)
{
QWidget* frameworkPathsWidget = createLabelWithHelpButton("Framework\nSearch Paths", &helpButton);
connect(helpButton, SIGNAL(clicked()), this, SLOT(handleFrameworkPathHelpPress()));
m_frameworkPaths = new QtDirectoryListBox(this);
m_frameworkPaths->setMinimumWidth(minimumWidthForSecondCol);
layout->addRow(frameworkPathsWidget, m_frameworkPaths);
}
}
void QtApplicationSettingsScreen::handleCancelButtonPress()
{
emit canceled();
}
void QtApplicationSettingsScreen::handleUpdateButtonPress()
{
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
appSettings->setHeaderSearchPaths(m_includePaths->getList());
if (m_frameworkPaths)
{
appSettings->setFrameworkSearchPaths(m_frameworkPaths->getList());
}
appSettings->save();
MessageRefresh().dispatch();
emit finished();
}
void QtApplicationSettingsScreen::handleIncludePathHelpPress()
{
showHelpMessage(
"Header Search Paths define where additional headers, that your project depends on, are found. Usually they are "
"header files of frameworks or libraries that your project uses. These files won't be analysed, but Coati needs "
"them for correct analysis.\n\n"
"Header Search Paths defined here will be used for all projects."
);
}
void QtApplicationSettingsScreen::handleFrameworkPathHelpPress()
{
showHelpMessage(
"Framework Search Paths define where MacOS framework containers, that your project depends on, are found.\n\n"
"Framework Search Paths defined here will be used for all projects."
);
}
@@ -0,0 +1,43 @@
#ifndef QT_APPLICATION_SETTINGS_SCREEN_H
#define QT_APPLICATION_SETTINGS_SCREEN_H
#include <QPushButton>
#include <QWidget>
#include "utility/file/FilePath.h"
#include "qt/element/QtDirectoryListBox.h"
#include "qt/window/QtSettingsWindow.h"
class QtApplicationSettingsScreen
: public QtSettingsWindow
{
Q_OBJECT
public:
QtApplicationSettingsScreen(QWidget* parent = 0);
QSize sizeHint() const Q_DECL_OVERRIDE;
virtual void setup() override;
void load();
protected:
virtual void populateForm(QFormLayout* layout) override;
private slots:
void handleCancelButtonPress();
void handleUpdateButtonPress();
void handleIncludePathHelpPress();
void handleFrameworkPathHelpPress();
private:
QPushButton* m_cancelButton;
QPushButton* m_updateButton;
QtDirectoryListBox* m_includePaths;
QtDirectoryListBox* m_frameworkPaths;
};
#endif //QT_APPLICATION_SETTINGS_SCREEN_H
+553
View File
@@ -0,0 +1,553 @@
#include "qt/window/QtMainWindow.h"
#include <QApplication>
#include <QFileDialog>
#include <QDockWidget>
#include <QMenuBar>
#include <QMessageBox>
#include <QSettings>
#include <QSysInfo>
#include "component/view/View.h"
#include "component/view/CompositeView.h"
#include "qt/view/QtViewWidgetWrapper.h"
#include "settings/ApplicationSettings.h"
#include "utility/file/FileSystem.h"
#include "utility/logging/logging.h"
#include "utility/messaging/type/MessageFind.h"
#include "utility/messaging/type/MessageInterruptTasks.h"
#include "utility/messaging/type/MessageLoadProject.h"
#include "utility/messaging/type/MessageRedo.h"
#include "utility/messaging/type/MessageRefresh.h"
#include "utility/messaging/type/MessageSaveProject.h"
#include "utility/messaging/type/MessageSwitchColorScheme.h"
#include "utility/messaging/type/MessageUndo.h"
#include "utility/messaging/type/MessageWindowFocus.h"
#include "utility/messaging/type/MessageZoom.h"
#include "version.h"
std::string QtMainWindow::m_windowSettingsPath = "data/window_settings.ini";
QtViewToggle::QtViewToggle(View* view, QWidget *parent)
: QWidget(parent)
, m_view(view)
{
}
void QtViewToggle::toggledByAction()
{
dynamic_cast<QtMainWindow*>(parent())->toggleView(m_view, true);
}
void QtViewToggle::toggledByUI()
{
dynamic_cast<QtMainWindow*>(parent())->toggleView(m_view, false);
}
QtMainWindow::QtMainWindow()
{
setObjectName("QtMainWindow");
setCentralWidget(nullptr);
setDockNestingEnabled(true);
setWindowIcon(QIcon("./data/gui/icon/logo_1024_1024.png"));
setWindowFlags(Qt::Widget);
QApplication::setOverrideCursor(Qt::ArrowCursor);
m_recentProjectAction = new QAction*[ApplicationSettings::MaximalAmountOfRecentProjects];
setupProjectMenu();
setupEditMenu();
setupViewMenu();
setupHelpMenu();
setupShortcuts();
// Need to call loadLayout here for right DockWidget size on Linux
// Seconde call is in Application.cpp
loadLayout();
}
void QtMainWindow::init()
{
showStartScreen();
}
QtMainWindow::~QtMainWindow()
{
if (m_recentProjectAction)
{
delete [] m_recentProjectAction;
}
}
void QtMainWindow::addView(View* view)
{
QDockWidget* dock = new QDockWidget(tr(view->getName().c_str()), this);
dock->setWidget(QtViewWidgetWrapper::getWidgetOfView(view));
dock->setObjectName(QString::fromStdString("Dock" + view->getName()));
//dock->setFeatures(QDockWidget::NoDockWidgetFeatures);
//dock->setTitleBarWidget(new QWidget());
addDockWidget(Qt::TopDockWidgetArea, dock);
QtViewToggle* toggle = new QtViewToggle(view, this);
connect(dock, SIGNAL(visibilityChanged(bool)), toggle, SLOT(toggledByUI()));
QAction* action = new QAction(tr((view->getName() + " Window").c_str()), this);
action->setCheckable(true);
connect(action, SIGNAL(triggered()), toggle, SLOT(toggledByAction()));
m_viewMenu->insertAction(m_viewSeparator, action);
DockWidget dockWidget;
dockWidget.widget = dock;
dockWidget.view = view;
dockWidget.action = action;
dockWidget.toggle = toggle;
m_dockWidgets.push_back(dockWidget);
}
void QtMainWindow::removeView(View* view)
{
for (size_t i = 0; i < m_dockWidgets.size(); i++)
{
if (m_dockWidgets[i].view == view)
{
removeDockWidget(m_dockWidgets[i].widget);
m_dockWidgets.erase(m_dockWidgets.begin() + i);
return;
}
}
}
void QtMainWindow::showView(View* view)
{
getDockWidgetForView(view)->widget->setHidden(false);
}
void QtMainWindow::hideView(View* view)
{
getDockWidgetForView(view)->widget->setHidden(true);
}
void QtMainWindow::loadLayout()
{
QSettings settings(m_windowSettingsPath.c_str(), QSettings::IniFormat);
settings.beginGroup("MainWindow");
resize(settings.value("size", QSize(600, 400)).toSize());
move(settings.value("position", QPoint(200, 200)).toPoint());
if (settings.value("maximized", false).toBool())
{
showMaximized();
}
settings.endGroup();
this->restoreState(settings.value("DOCK_LOCATIONS").toByteArray());
for (DockWidget dock : m_dockWidgets)
{
dock.action->setChecked(!dock.widget->isHidden());
}
}
void QtMainWindow::saveLayout()
{
QSettings settings(m_windowSettingsPath.c_str(), QSettings::IniFormat);
settings.beginGroup("MainWindow");
settings.setValue("maximized", isMaximized());
if (!isMaximized())
{
settings.setValue("size", size());
settings.setValue("position", pos());
}
settings.endGroup();
settings.setValue("DOCK_LOCATIONS", this->saveState());
}
bool QtMainWindow::event(QEvent* event)
{
if (event->type() == QEvent::WindowActivate)
{
MessageWindowFocus().dispatch();
}
return QMainWindow::event(event);
}
void QtMainWindow::pushWindow(QWidget* window)
{
if (m_windowStack.size())
{
m_windowStack.back()->hide();
}
window->show();
m_windowStack.push_back(window);
}
void QtMainWindow::popWindow()
{
if (m_windowStack.size())
{
m_windowStack.back()->hide();
m_windowStack.pop_back();
}
if (m_windowStack.size())
{
m_windowStack.back()->show();
}
}
void QtMainWindow::clearWindows()
{
if (m_windowStack.size())
{
m_windowStack.back()->hide();
}
m_windowStack.clear();
}
void QtMainWindow::about()
{
if (!m_aboutWindow)
{
m_aboutWindow = std::make_shared<QtAbout>(this);
m_aboutWindow->setup();
connect(m_aboutWindow.get(), SIGNAL(finished()), this, SLOT(popWindow()));
}
pushWindow(m_aboutWindow.get());
}
void QtMainWindow::openSettings()
{
if (!m_applicationSettingsScreen)
{
m_applicationSettingsScreen = std::make_shared<QtApplicationSettingsScreen>(this);
m_applicationSettingsScreen->setup();
connect(m_applicationSettingsScreen.get(), SIGNAL(finished()), this, SLOT(popWindow()));
connect(m_applicationSettingsScreen.get(), SIGNAL(canceled()), this, SLOT(popWindow()));
}
m_applicationSettingsScreen->load();
pushWindow(m_applicationSettingsScreen.get());
}
void QtMainWindow::showLicenses()
{
if (!m_licenseWindow)
{
m_licenseWindow = std::make_shared<QtAboutLicense>(this);
m_licenseWindow->setup();
connect(m_licenseWindow.get(), SIGNAL(finished()), this, SLOT(popWindow()));
}
pushWindow(m_licenseWindow.get());
}
void QtMainWindow::showStartScreen()
{
if (!m_startScreen)
{
m_startScreen = std::make_shared<QtStartScreen>(this);
m_startScreen->setup();
connect(m_startScreen.get(), SIGNAL(finished()), this, SLOT(popWindow()));
connect(m_startScreen.get(), SIGNAL(canceled()), this, SLOT(popWindow()));
connect(m_startScreen.get(), SIGNAL(openOpenProjectDialog()), this, SLOT(openProject()));
connect(m_startScreen.get(), SIGNAL(openNewProjectDialog()), this, SLOT(newProject()));
}
pushWindow(m_startScreen.get());
}
void QtMainWindow::newProject()
{
if (!m_newProjectDialog)
{
m_newProjectDialog = std::make_shared<QtProjectSetupScreen>(this);
m_newProjectDialog->setup();
connect(m_newProjectDialog.get(), SIGNAL(finished()), this, SLOT(clearWindows()));
connect(m_newProjectDialog.get(), SIGNAL(canceled()), this, SLOT(popWindow()));
connect(m_newProjectDialog.get(), SIGNAL(showPreferences()), this, SLOT(openSettings()));
}
m_newProjectDialog->loadEmpty();
pushWindow(m_newProjectDialog.get());
}
void QtMainWindow::openProject(const QString &path)
{
QString fileName = path;
if (fileName.isNull())
{
fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", "Coati Project Files (*.coatiproject)");
}
if (!fileName.isEmpty())
{
MessageLoadProject(fileName.toStdString()).dispatch();
clearWindows();
}
}
void QtMainWindow::editProject()
{
newProject();
m_newProjectDialog->loadProjectSettings();
}
void QtMainWindow::find()
{
MessageFind().dispatch();
}
void QtMainWindow::closeWindow()
{
QApplication* app = dynamic_cast<QApplication*>(QCoreApplication::instance());
QWidget* activeWindow = app->activeWindow();
if (activeWindow)
{
activeWindow->close();
}
}
void QtMainWindow::refresh()
{
MessageRefresh().dispatch();
}
void QtMainWindow::forceRefresh()
{
MessageRefresh().refreshAll().dispatch();
}
void QtMainWindow::saveProject()
{
MessageSaveProject("").dispatch();
}
void QtMainWindow::saveAsProject()
{
QString filename = "";
filename = QFileDialog::getSaveFileName(this, "Save File as", "", "Coati Project Files(*.coatiproject)");
if(!filename.isEmpty())
{
MessageSaveProject(filename.toStdString()).dispatch();
}
}
void QtMainWindow::undo()
{
MessageUndo().dispatch();
}
void QtMainWindow::redo()
{
MessageRedo().dispatch();
}
void QtMainWindow::zoomIn()
{
MessageZoom(true).dispatch();
}
void QtMainWindow::zoomOut()
{
MessageZoom(false).dispatch();
}
void QtMainWindow::switchColorScheme()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "./data/color_schemes", "XML Files (*.xml)");
if (!fileName.isEmpty())
{
MessageSwitchColorScheme(fileName.toStdString()).dispatch();
}
}
void QtMainWindow::toggleView(View* view, bool fromMenu)
{
DockWidget* dock = getDockWidgetForView(view);
if (fromMenu)
{
dock->widget->setVisible(dock->action->isChecked());
}
else
{
dock->action->setChecked(dock->widget->isVisible());
}
}
void QtMainWindow::handleEscapeShortcut()
{
popWindow();
MessageInterruptTasks().dispatch();
}
void QtMainWindow::setupProjectMenu()
{
QMenu *menu = new QMenu(tr("&Project"), this);
menuBar()->addMenu(menu);
menu->addAction(tr("&New Project..."), this, SLOT(newProject()), QKeySequence::New);
menu->addAction(tr("&Open Project..."), this, SLOT(openProject()), QKeySequence::Open);
menu->addAction(tr("&Edit Project..."), this, SLOT(editProject()));
menu->addSeparator();
menu->addAction(tr("&Save Project"), this, SLOT(saveProject()), QKeySequence::Save);
menu->addAction(tr("Save Project as..."), this, SLOT(saveAsProject()), QKeySequence::SaveAs);
menu->addSeparator();
QMenu *recentProjectMenu = new QMenu(tr("Recent Projects"));
menu->addMenu(recentProjectMenu);
for (int i = 0; i < ApplicationSettings::MaximalAmountOfRecentProjects; ++i)
{
m_recentProjectAction[i] = new QAction(this);
m_recentProjectAction[i]->setVisible(false);
connect(m_recentProjectAction[i], SIGNAL(triggered()),
this, SLOT(openRecentProject()));
recentProjectMenu->addAction(m_recentProjectAction[i]);
}
updateRecentProjectMenu();
menu->addMenu(recentProjectMenu);
menu->addSeparator();
menu->addAction(tr("E&xit"), QCoreApplication::instance(), SLOT(quit()), QKeySequence::Quit);
}
void QtMainWindow::openRecentProject()
{
QAction *action = qobject_cast<QAction *>(sender());
if (action)
{
openProject(action->data().toString());
}
}
void QtMainWindow::updateRecentProjectMenu()
{
std::vector<FilePath> recentProjects = ApplicationSettings::getInstance()->getRecentProjects();
for (size_t i = 0; i < ApplicationSettings::MaximalAmountOfRecentProjects; i++)
{
if(i < recentProjects.size())
{
FilePath project = recentProjects[i];
m_recentProjectAction[i]->setVisible(true);
m_recentProjectAction[i]->setText(FileSystem::fileName(project.str()).c_str());
m_recentProjectAction[i]->setData(project.str().c_str());
}
else
{
m_recentProjectAction[i]->setVisible(false);
}
}
}
void QtMainWindow::setWindowSettingsPath(const std::string& windowSettingsPath)
{
m_windowSettingsPath = windowSettingsPath;
}
void QtMainWindow::setupEditMenu()
{
QMenu *menu = new QMenu(tr("&Edit"), this);
menuBar()->addMenu(menu);
menu->addAction(tr("Undo"), this, SLOT(undo()), QKeySequence::Undo);
menu->addAction(tr("Redo"), this, SLOT(redo()), QKeySequence::Redo);
menu->addSeparator();
menu->addAction(tr("&Refresh"), this, SLOT(refresh()), QKeySequence::Refresh);
if (QSysInfo::windowsVersion() != QSysInfo::WV_None)
{
menu->addAction(tr("&Force Refresh"), this, SLOT(forceRefresh()), QKeySequence(Qt::SHIFT + Qt::Key_F5));
}
else
{
menu->addAction(tr("&Force Refresh"), this, SLOT(forceRefresh()), QKeySequence(Qt::SHIFT + Qt::CTRL + Qt::Key_R));
}
menu->addAction(tr("&Find"), this, SLOT(find()), QKeySequence::Find);
}
void QtMainWindow::setupViewMenu()
{
QMenu *menu = new QMenu(tr("&View"), this);
menuBar()->addMenu(menu);
m_viewSeparator = menu->addSeparator();
menu->addAction(tr("Larger font"), this, SLOT(zoomIn()), QKeySequence::ZoomIn);
menu->addAction(tr("Smaller font"), this, SLOT(zoomOut()), QKeySequence::ZoomOut);
menu->addAction(tr("Switch Color Scheme..."), this, SLOT(switchColorScheme()));
m_viewMenu = menu;
}
void QtMainWindow::setupHelpMenu()
{
QMenu *menu = new QMenu(tr("&Help"), this);
menuBar()->addMenu(menu);
menu->addAction(tr("&About"), this, SLOT(about()));
menu->addAction(tr("Licences"), this, SLOT(showLicenses()));
menu->addAction(tr("Preferences..."), this, SLOT(openSettings()));
}
void QtMainWindow::setupShortcuts()
{
m_escapeShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
connect(m_escapeShortcut, SIGNAL(activated()), SLOT(handleEscapeShortcut()));
}
QtMainWindow::DockWidget* QtMainWindow::getDockWidgetForView(View* view)
{
for (DockWidget& dock : m_dockWidgets)
{
if (dock.view == view)
{
return &dock;
}
const CompositeView* compositeView = dynamic_cast<const CompositeView*>(dock.view);
if (compositeView)
{
for (const View* v : compositeView->getViews())
{
if (v == view)
{
return &dock;
}
}
}
}
LOG_ERROR("DockWidget was not found for view.");
return nullptr;
}
+132
View File
@@ -0,0 +1,132 @@
#ifndef QT_MAIN_WINDOW_H
#define QT_MAIN_WINDOW_H
#include <memory>
#include <utility>
#include <vector>
#include <QMainWindow>
#include <QShortcut>
#include "qt/window/QtApplicationSettingsScreen.h"
#include "qt/window/QtStartScreen.h"
#include "qt/window/QtProjectSetupScreen.h"
#include "qt/window/QtAboutLicense.h"
#include "qt/window/QtAbout.h"
class QDockWidget;
class View;
class QtViewToggle
: public QWidget
{
Q_OBJECT
public:
QtViewToggle(View* view, QWidget *parent = nullptr);
public slots:
void toggledByAction();
void toggledByUI();
private:
View* m_view;
};
class QtMainWindow: public QMainWindow
{
Q_OBJECT
public:
QtMainWindow();
~QtMainWindow();
void init();
void addView(View* view);
void removeView(View* view);
void showView(View* view);
void hideView(View* view);
void loadLayout();
void saveLayout();
protected:
bool event(QEvent* event);
public slots:
void pushWindow(QWidget* window);
void popWindow();
void clearWindows();
void about();
void openSettings();
void showLicenses();
void showStartScreen();
void newProject();
void openProject(const QString &path = QString());
void editProject();
void openRecentProject();
void find();
void closeWindow();
void refresh();
void forceRefresh();
void saveProject();
void saveAsProject();
void undo();
void redo();
void zoomIn();
void zoomOut();
void switchColorScheme();
void toggleView(View* view, bool fromMenu);
void handleEscapeShortcut();
void updateRecentProjectMenu();
static void setWindowSettingsPath(const std::string& windowSettingsPath);
private:
struct DockWidget
{
QDockWidget* widget;
View* view;
QAction* action;
QtViewToggle* toggle;
};
void setupEditMenu();
void setupProjectMenu();
void setupViewMenu();
void setupHelpMenu();
void setupShortcuts();
DockWidget* getDockWidgetForView(View* view);
std::vector<DockWidget> m_dockWidgets;
QMenu* m_viewMenu;
QAction* m_viewSeparator;
QAction** m_recentProjectAction;
std::shared_ptr<QtApplicationSettingsScreen> m_applicationSettingsScreen;
std::shared_ptr<QtStartScreen> m_startScreen;
std::shared_ptr<QtProjectSetupScreen> m_newProjectDialog;
std::shared_ptr<QtAboutLicense> m_licenseWindow;
std::shared_ptr<QtAbout> m_aboutWindow;
std::vector<QWidget*> m_windowStack;
QShortcut* m_escapeShortcut;
static std::string m_windowSettingsPath;
};
#endif // QT_MAIN_WINDOW_H
@@ -0,0 +1,247 @@
#include "qt/window/QtProjectSetupScreen.h"
#include <QComboBox>
#include <QFileDialog>
#include <QFormLayout>
#include <QLineEdit>
#include <QMessageBox>
#include <QSysInfo>
#include "utility/messaging/type/MessageLoadProject.h"
#include "settings/ProjectSettings.h"
QtTextLine::QtTextLine(QWidget *parent)
: QWidget(parent)
{
QBoxLayout* layout = new QHBoxLayout();
layout->setSpacing(0);
layout->setContentsMargins(1, 1, 1, 1);
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
m_data = new QtLineEdit(this);
m_data->setAttribute(Qt::WA_MacShowFocusRect, 0);
m_data->setObjectName("locationField");
m_button = new QPushButton("...");
m_button->setObjectName("moreButton");
layout->addWidget(m_data);
layout->addWidget(m_button);
connect(m_button, SIGNAL(clicked()), this, SLOT(handleButtonPress()));
}
QString QtTextLine::getText()
{
return m_data->text();
}
void QtTextLine::setText(QString text)
{
m_data->setText(text);
}
void QtTextLine::handleButtonPress()
{
QString file = QFileDialog::getExistingDirectory(this, tr("Select Directory"), "");
if (!file.isEmpty())
{
m_data->setText(file);
}
}
QtProjectSetupScreen::QtProjectSetupScreen(QWidget *parent)
: QtSettingsWindow(parent)
, m_frameworkPaths(nullptr)
{
raise();
}
QSize QtProjectSetupScreen::sizeHint() const
{
return QSize(600,600);
}
void QtProjectSetupScreen::clear()
{
m_projectName->setText("");
m_projectFileLocation->setText("");
m_sourcePaths->clear();
m_includePaths->clear();
if (m_frameworkPaths)
{
m_frameworkPaths->clear();
}
}
void QtProjectSetupScreen::setup()
{
setupForm();
QPushButton* preferencesButton = new QPushButton("Preferences");
preferencesButton->setObjectName("windowButton");
connect(preferencesButton, SIGNAL(clicked()), this, SLOT(handlePreferencesButtonPress()));
m_buttonsLayout->insertWidget(2, preferencesButton);
m_buttonsLayout->insertStretch(3);
}
void QtProjectSetupScreen::loadEmpty()
{
updateTitle("NEW PROJECT");
updateDoneButton("Create");
}
void QtProjectSetupScreen::loadProjectSettings()
{
updateTitle("EDIT PROJECT");
updateDoneButton("Save");
ProjectSettings* projSettings = ProjectSettings::getInstance().get();
m_projectName->setText(QString::fromStdString(projSettings->getFilePath().withoutExtension().fileName()));
m_projectFileLocation->setText(QString::fromStdString(projSettings->getFilePath().parentDirectory().str()));
m_sourcePaths->setList(projSettings->getSourcePaths());
m_includePaths->setList(projSettings->getHeaderSearchPaths());
if (m_frameworkPaths)
{
m_frameworkPaths->setList(projSettings->getFrameworkSearchPaths());
}
}
void QtProjectSetupScreen::populateForm(QFormLayout* layout)
{
int minimumWidthForSecondCol = 360;
QLabel* nameLabel = new QLabel("Name");
m_projectName = new QLineEdit();
m_projectName->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
m_projectName->setMinimumWidth(minimumWidthForSecondCol);
m_projectName->setAttribute(Qt::WA_MacShowFocusRect, 0);
layout->addRow(nameLabel, m_projectName);
QLabel* locationLabel = new QLabel("Location");
m_projectFileLocation = new QtTextLine(this);
m_projectFileLocation->setMinimumWidth(minimumWidthForSecondCol);
layout->addRow(locationLabel, m_projectFileLocation);
QLabel* languageLabel = new QLabel("Language");
QComboBox* language = new QComboBox();
language->insertItem(0, "C++");
layout->addRow(languageLabel, language);
QPushButton* helpButton;
QWidget* sourcePathsWidget = createLabelWithHelpButton("Source Paths", &helpButton);
connect(helpButton, SIGNAL(clicked()), this, SLOT(handleSourcePathHelpPress()));
m_sourcePaths = new QtDirectoryListBox(this);
m_sourcePaths->setMinimumWidth(minimumWidthForSecondCol);
layout->addRow(sourcePathsWidget, m_sourcePaths);
QWidget* includePathsWidget = createLabelWithHelpButton("Header\nSearch Paths", &helpButton);
connect(helpButton, SIGNAL(clicked()), this, SLOT(handleIncludePathHelpPress()));
m_includePaths = new QtDirectoryListBox(this);
m_includePaths->setMinimumWidth(minimumWidthForSecondCol);
layout->addRow(includePathsWidget, m_includePaths);
if (QSysInfo::macVersion() != QSysInfo::MV_None)
{
QWidget* frameworkPathsWidget = createLabelWithHelpButton("Framework\nSearch Paths", &helpButton);
connect(helpButton, SIGNAL(clicked()), this, SLOT(handleFrameworkPathHelpPress()));
m_frameworkPaths = new QtDirectoryListBox(this);
m_frameworkPaths->setMinimumWidth(minimumWidthForSecondCol);
layout->addRow(frameworkPathsWidget, m_frameworkPaths);
}
}
void QtProjectSetupScreen::handleCancelButtonPress()
{
emit canceled();
}
void QtProjectSetupScreen::handleUpdateButtonPress()
{
if (m_projectName->text().isEmpty())
{
QMessageBox msgBox;
msgBox.setText("Please enter a project name.");
msgBox.exec();
return;
}
if (m_projectFileLocation->getText().isEmpty())
{
QMessageBox msgBox;
msgBox.setText("Please define the location of the project file.");
msgBox.exec();
return;
}
if (!m_sourcePaths->getList().size())
{
QMessageBox msgBox;
msgBox.setText("Please add at least one source path to your project.");
msgBox.exec();
return;
}
ProjectSettings* projSettings = ProjectSettings::getInstance().get();
projSettings->clear();
projSettings->setSourcePaths(m_sourcePaths->getList());
projSettings->setHeaderSearchPaths(m_includePaths->getList());
if (m_frameworkPaths)
{
projSettings->setFrameworkSearchPaths(m_frameworkPaths->getList());
}
std::string projectFile =
m_projectFileLocation->getText().toStdString() + "/" + m_projectName->text().toStdString() + ".coatiproject";
projSettings->save(projectFile);
MessageLoadProject(projectFile).dispatch();
clear();
emit finished();
}
void QtProjectSetupScreen::handleSourcePathHelpPress()
{
showHelpMessage(
"Source Paths define the files and directories that will be analysed by Coati. Usually these are the source "
"files of your project or a subset of them."
);
}
void QtProjectSetupScreen::handleIncludePathHelpPress()
{
showHelpMessage(
"Header Search Paths define where additional headers, that your project depends on, are found. Usually they are "
"header files of frameworks or libraries that your project uses. These files won't be analysed, but Coati needs "
"them for correct analysis.\n\n"
"Please note that you can define Header Search Paths for all your projects in Coati's preferences."
);
}
void QtProjectSetupScreen::handleFrameworkPathHelpPress()
{
showHelpMessage(
"Framework Search Paths define where MacOS framework containers, that your project depends on, are found.\n\n"
"Please note that you can define Framework Search Paths for all your projects in Coati's preferences."
);
}
void QtProjectSetupScreen::handlePreferencesButtonPress()
{
emit showPreferences();
}
@@ -0,0 +1,77 @@
#ifndef QT_PROJECT_SETUP_SCREEN_H
#define QT_PROJECT_SETUP_SCREEN_H
#include <QPushButton>
#include <QWidget>
#include "utility/file/FilePath.h"
#include "qt/element/QtDirectoryListBox.h"
#include "qt/element/QtLineEdit.h"
#include "qt/window/QtSettingsWindow.h"
class QtTextLine
: public QWidget
{
Q_OBJECT
public:
QtTextLine(QWidget *parent);
QString getText();
void setText(QString text);
private slots:
void handleButtonPress();
private:
QPushButton* m_button;
QtLineEdit* m_data;
};
class QtProjectSetupScreen
: public QtSettingsWindow
{
Q_OBJECT
public:
QtProjectSetupScreen(QWidget* parent = 0);
QSize sizeHint() const Q_DECL_OVERRIDE;
void clear();
virtual void setup() override;
void loadEmpty();
void loadProjectSettings();
void projectSetupScreen();
signals:
void showPreferences();
protected:
virtual void populateForm(QFormLayout* layout) override;
private slots:
void handleCancelButtonPress();
void handleUpdateButtonPress();
void handleSourcePathHelpPress();
void handleIncludePathHelpPress();
void handleFrameworkPathHelpPress();
void handlePreferencesButtonPress();
private:
QLineEdit* m_projectName;
QtTextLine* m_projectFileLocation;
QtDirectoryListBox* m_includePaths;
QtDirectoryListBox* m_sourcePaths;
QtDirectoryListBox* m_frameworkPaths;
QPushButton* m_preferencesButton;
};
#endif //QT_PROJECT_SETUP_SCREEN_H
+229
View File
@@ -0,0 +1,229 @@
#include "qt/window/QtSettingsWindow.h"
#include <QFormLayout>
#include <QGraphicsDropShadowEffect>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <QScrollArea>
#include <QSysInfo>
#include "qt/utility/QtDeviceScaledPixmap.h"
#include "qt/utility/utilityQt.h"
#include "utility/messaging/type/MessageInterruptTasks.h"
QtSettingsWindow::QtSettingsWindow(QWidget *parent, int displacement)
: QWidget(parent, Qt::Dialog | Qt::FramelessWindowHint)
, m_title(nullptr)
, m_cancelButton(nullptr)
, m_doneButton(nullptr)
, m_mousePressedInWindow(false)
{
QSize windowSize = sizeHint();
move(parent->pos().x() + parent->width() / 2 - 250, parent->pos().y() + parent->height() / 2 - 250);
setAttribute(Qt::WA_TranslucentBackground, true);
m_displacment = displacement;
m_window = new QWidget(this);
windowSize.setHeight(windowSize.height() - displacement - 10);
windowSize.setWidth(windowSize.width() - 10);
m_window->move(0, displacement);
m_window->resize(windowSize);
std::string frameStyle =
"#SettingWindow {"
"font-size: 17pt; "
"border: 1px solid lightgray;"
"border-radius: 15px; "
"background: white; "
"}";
m_window->setStyleSheet(frameStyle.c_str());
m_window->setObjectName("SettingWindow");
// window shadow
if (QSysInfo::macVersion() == QSysInfo::MV_None)
{
QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect;
effect->setBlurRadius(5);
effect->setXOffset(2);
effect->setYOffset(2);
effect->setColor(Qt::darkGray);
m_window->setGraphicsEffect(effect);
}
this->raise();
}
QSize QtSettingsWindow::sizeHint() const
{
return QSize(500, 500);
}
void QtSettingsWindow::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape)
{
emit canceled();
}
}
void QtSettingsWindow::resizeEvent(QResizeEvent *event)
{
QSize windowSize = event->size()-QSize(10, 10 + m_displacment);
m_window->resize(windowSize);
m_window->move(0, m_displacment);
}
void QtSettingsWindow::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton && m_mousePressedInWindow)
{
move(event->globalPos() - m_dragPosition);
event->accept();
}
}
void QtSettingsWindow::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_dragPosition = event->globalPos() - frameGeometry().topLeft();
event->accept();
m_mousePressedInWindow = true;
}
}
void QtSettingsWindow::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_dragPosition = event->globalPos() - frameGeometry().topLeft();
event->accept();
m_mousePressedInWindow = false;
}
}
void QtSettingsWindow::setupForm()
{
QtDeviceScaledPixmap coati_logo("data/gui/startscreen/logo_blurry.png");
coati_logo.scaleToWidth(400);
QLabel* coatiLogoLabel = new QLabel(m_window);
coatiLogoLabel->setPixmap(coati_logo.pixmap());
coatiLogoLabel->resize(coati_logo.width(), coati_logo.height());
coatiLogoLabel->move(100, 100);
setStyleSheet(utility::getStyleSheet("data/gui/setting_window/window.css").c_str());
QVBoxLayout* windowLayout = new QVBoxLayout();
windowLayout->setContentsMargins(25, 30, 25, 20);
m_title = new QLabel();
m_title->setObjectName("titleLabel");
windowLayout->addWidget(m_title);
windowLayout->addSpacing(30);
QScrollArea* scrollArea = new QScrollArea();
scrollArea->setObjectName("formArea");
scrollArea->setFrameShadow(QFrame::Plain);
scrollArea->setWidgetResizable(true);
QWidget* form = new QWidget();
form->setObjectName("form");
scrollArea->setWidget(form);
QFormLayout* layout = new QFormLayout();
layout->setContentsMargins(10, 10, 10, 10);
layout->setHorizontalSpacing(20);
populateForm(layout);
form->setLayout(layout);
m_cancelButton = new QPushButton("Cancel");
m_cancelButton->setObjectName("windowButton");
m_doneButton = new QPushButton("Done");
m_doneButton->setObjectName("windowButton");
connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(handleCancelButtonPress()));
connect(m_doneButton, SIGNAL(clicked()), this, SLOT(handleUpdateButtonPress()));
QHBoxLayout* buttons = new QHBoxLayout();
buttons->addWidget(m_cancelButton);
buttons->addStretch();
buttons->addWidget(m_doneButton);
m_buttonsLayout = buttons;
windowLayout->addWidget(scrollArea);
windowLayout->addSpacing(20);
windowLayout->addLayout(buttons);
m_window->setLayout(windowLayout);
resize(QSize(600, 620));
scrollArea->raise();
}
void QtSettingsWindow::populateForm(QFormLayout* layout)
{
}
void QtSettingsWindow::updateTitle(QString title)
{
if (m_title)
{
m_title->setText(title);
}
}
void QtSettingsWindow::updateDoneButton(QString text)
{
if (m_doneButton)
{
m_doneButton->setText(text);
}
}
void QtSettingsWindow::hideCancelButton(bool hidden)
{
if(m_cancelButton)
{
m_cancelButton->setVisible(!hidden);
}
}
QWidget* QtSettingsWindow::createLabelWithHelpButton(QString name, QPushButton** helpButton)
{
QWidget* widget = new QWidget();
QVBoxLayout* layout = new QVBoxLayout();
layout->setContentsMargins(0, 5, 0, 5);
layout->setSpacing(5);
QLabel* label = new QLabel(name);
label->setAlignment(Qt::AlignRight);
layout->addWidget(label);
QPushButton* button = new QPushButton("?");
button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
button->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
button->setObjectName("help");
layout->addWidget(button, 0, Qt::AlignRight);
layout->addStretch();
widget->setLayout(layout);
*helpButton = button;
return widget;
}
void QtSettingsWindow::showHelpMessage(const QString& msg)
{
QMessageBox msgBox;
msgBox.setText("Help");
msgBox.setInformativeText(msg);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
int ret = msgBox.exec();
}
+61
View File
@@ -0,0 +1,61 @@
#ifndef QT_SETTINGS_WINDOW_H
#define QT_SETTINGS_WINDOW_H
#include <QHBoxLayout>
#include <QResizeEvent>
#include <QWidget>
class QFormLayout;
class QLabel;
class QPushButton;
class QtSettingsWindow
: public QWidget
{
Q_OBJECT
public:
QtSettingsWindow(QWidget* parent = 0, int displacement = 0);
QSize sizeHint() const Q_DECL_OVERRIDE;
virtual void setup() = 0;
signals:
void finished();
void canceled();
protected:
void keyPressEvent(QKeyEvent* event) Q_DECL_OVERRIDE;
void resizeEvent(QResizeEvent* event) Q_DECL_OVERRIDE;
void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void setupForm();
virtual void populateForm(QFormLayout* layout);
void updateTitle(QString title);
void updateDoneButton(QString text);
void hideCancelButton(bool hidden);
QWidget* createLabelWithHelpButton(QString name, QPushButton** helpButton);
void showHelpMessage(const QString& msg);
QWidget* m_window;
QLabel* m_title;
QPushButton* m_cancelButton;
QPushButton* m_doneButton;
QHBoxLayout* m_buttonsLayout;
private:
int m_displacment;
QPoint m_dragPosition;
bool m_mousePressedInWindow;
};
#endif //QT_SETTINGS_WINDOW_H
+102
View File
@@ -0,0 +1,102 @@
#include "qt/window/QtSplashScreen.h"
#include <QApplication>
#include <QThread>
#include <QTimer>
#include "qt/utility/QtDeviceScaledPixmap.h"
namespace
{
class InitThread : public QThread
{
public:
void run(void)
{
// Mininmum time the SplashScreen gets displayed.
QThread::msleep(5000);
}
};
}
QtSplashScreen::QtSplashScreen(const QPixmap &pixmap, Qt::WindowFlags f)
: QSplashScreen(pixmap, f)
, m_state(0)
{
QtDeviceScaledPixmap foreground("data/gui/splash_white.png");
foreground.scaleToHeight(pixmap.size().height() * 0.8);
m_foreground = foreground.pixmap();
QtDeviceScaledPixmap background("data/gui/splash_blue.png");
background.scaleToHeight(pixmap.size().height() * 0.9);
m_background = background.pixmap();
}
QtSplashScreen::~QtSplashScreen()
{
}
void QtSplashScreen::exec(QApplication& app)
{
m_state = 0;
QTimer* timer = new QTimer(this);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(animate()));
timer->start(150);
app.processEvents();
show();
repaint();
app.processEvents();
// Eventloop for the SplashScreen
// QEventLoop loop;
// InitThread* initThread = new InitThread();
// QObject::connect(initThread, SIGNAL(finished()), &loop, SLOT(quit()));
// initThread->start();
// loop.exec();
}
void QtSplashScreen::setMessage(const QString &str)
{
m_string = str;
repaint();
}
void QtSplashScreen::setVersion(const QString &str)
{
m_version = str;
repaint();
}
void QtSplashScreen::animate()
{
m_state = (m_state + 2) % 120;
repaint();
}
void QtSplashScreen::drawContents(QPainter *painter)
{
painter->save();
painter->translate(rect().width() / 2, rect().height() / 2);
painter->rotate(m_state * 3);
painter->drawPixmap(-rect().width() * 0.9 / 2, -rect().height() * 0.9 / 2, m_background);
painter->restore();
painter->drawPixmap(rect().width() * 0.1, rect().height() * 0.1, m_foreground);
QRect r = rect();
r.setRect(r.x() + 5, r.height() - 20, r.width() - 10, 20);
painter->drawText(r, Qt::AlignRight, QString("Coati v").append(m_version));
// Draw message at given position, limited to 43 chars
// If message is too long, string is truncated
if (m_string.length() > 40)
{
m_string.truncate(39);
m_string += "...";
}
painter->drawText(r, Qt::AlignLeft, m_string);
}

Some files were not shown because too many files have changed in this diff Show More