build: trial version target
builds now app and trail target, lib_gui added, istrail function
This commit is contained in:
@@ -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
|
||||
@@ -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()));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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("");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user