|
|
|
@@ -4,8 +4,10 @@
|
|
|
|
|
#include <QScrollBar>
|
|
|
|
|
|
|
|
|
|
#include "component/view/GraphViewStyle.h"
|
|
|
|
|
#include "qt/utility/QtDeviceScaledPixmap.h"
|
|
|
|
|
#include "settings/ApplicationSettings.h"
|
|
|
|
|
#include "settings/ColorScheme.h"
|
|
|
|
|
#include "utility/ResourcePaths.h"
|
|
|
|
|
|
|
|
|
|
QtAutocompletionModel::QtAutocompletionModel(QObject* parent)
|
|
|
|
|
: QAbstractTableModel(parent)
|
|
|
|
@@ -30,7 +32,7 @@ int QtAutocompletionModel::rowCount(const QModelIndex &parent) const
|
|
|
|
|
int QtAutocompletionModel::columnCount(const QModelIndex &parent) const
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(parent);
|
|
|
|
|
return 4;
|
|
|
|
|
return 6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant QtAutocompletionModel::data(const QModelIndex &index, int role) const
|
|
|
|
@@ -45,10 +47,14 @@ QVariant QtAutocompletionModel::data(const QModelIndex &index, int role) const
|
|
|
|
|
switch (index.column())
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
return QString::fromStdString(match.getFullName());
|
|
|
|
|
return QString::fromStdString(match.name);
|
|
|
|
|
case 1:
|
|
|
|
|
return QString::fromStdString(match.typeName);
|
|
|
|
|
return QString::fromStdString(match.text);
|
|
|
|
|
case 2:
|
|
|
|
|
return QString::fromStdString(match.subtext);
|
|
|
|
|
case 3:
|
|
|
|
|
return QString::fromStdString(match.typeName);
|
|
|
|
|
case 4:
|
|
|
|
|
{
|
|
|
|
|
QList<QVariant> indices;
|
|
|
|
|
for (const size_t idx : match.indices)
|
|
|
|
@@ -57,7 +63,7 @@ QVariant QtAutocompletionModel::data(const QModelIndex &index, int role) const
|
|
|
|
|
}
|
|
|
|
|
return indices;
|
|
|
|
|
}
|
|
|
|
|
case 3:
|
|
|
|
|
case 5:
|
|
|
|
|
return match.nodeType;
|
|
|
|
|
default:
|
|
|
|
|
return QVariant();
|
|
|
|
@@ -73,10 +79,52 @@ const SearchMatch* QtAutocompletionModel::getSearchMatchAt(int idx) const
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QtAutocompletionDelegate::QtAutocompletionDelegate(QObject* parent)
|
|
|
|
|
: QStyledItemDelegate(parent)
|
|
|
|
|
QString QtAutocompletionModel::longestText() const
|
|
|
|
|
{
|
|
|
|
|
std::string str;
|
|
|
|
|
for (const SearchMatch& match : m_matchList)
|
|
|
|
|
{
|
|
|
|
|
if (match.text.size() > str.size())
|
|
|
|
|
{
|
|
|
|
|
str = match.text;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return QString::fromStdString(str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString QtAutocompletionModel::longestSubText() const
|
|
|
|
|
{
|
|
|
|
|
std::string str;
|
|
|
|
|
for (const SearchMatch& match : m_matchList)
|
|
|
|
|
{
|
|
|
|
|
if (match.subtext.size() > str.size())
|
|
|
|
|
{
|
|
|
|
|
str = match.subtext;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return QString::fromStdString(str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString QtAutocompletionModel::longestType() const
|
|
|
|
|
{
|
|
|
|
|
std::string str;
|
|
|
|
|
for (const SearchMatch& match : m_matchList)
|
|
|
|
|
{
|
|
|
|
|
if (match.typeName.size() > str.size())
|
|
|
|
|
{
|
|
|
|
|
str = match.typeName;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return QString::fromStdString(str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QtAutocompletionDelegate::QtAutocompletionDelegate(QtAutocompletionModel* model, QObject* parent)
|
|
|
|
|
: QStyledItemDelegate(parent)
|
|
|
|
|
, m_model(model)
|
|
|
|
|
, m_arrow()
|
|
|
|
|
{
|
|
|
|
|
resetCharSizes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QtAutocompletionDelegate::~QtAutocompletionDelegate()
|
|
|
|
@@ -87,108 +135,219 @@ void QtAutocompletionDelegate::paint(QPainter* painter, const QStyleOptionViewIt
|
|
|
|
|
{
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get data
|
|
|
|
|
QString name = index.data().toString();
|
|
|
|
|
QString text = index.sibling(index.row(), index.column() + 1).data().toString();
|
|
|
|
|
QString subtext = index.sibling(index.row(), index.column() + 2).data().toString();
|
|
|
|
|
QString type = index.sibling(index.row(), index.column() + 3).data().toString();
|
|
|
|
|
QList<QVariant> indices = index.sibling(index.row(), index.column() + 4).data().toList();
|
|
|
|
|
Node::NodeType nodeType = static_cast<Node::NodeType>(index.sibling(index.row(), index.column() + 5).data().toInt());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QString type = index.sibling(index.row(), index.column() + 1).data().toString();
|
|
|
|
|
QColor color("#FFFFFF");
|
|
|
|
|
// define highlight colors
|
|
|
|
|
ColorScheme* scheme = ColorScheme::getInstance().get();
|
|
|
|
|
QColor fillColor("#FFFFFF");
|
|
|
|
|
QColor textColor("#000000");
|
|
|
|
|
|
|
|
|
|
Node::NodeType nodeType = static_cast<Node::NodeType>(index.sibling(index.row(), index.column() + 3).data().toInt());
|
|
|
|
|
if (type.size() && type != "command")
|
|
|
|
|
{
|
|
|
|
|
const GraphViewStyle::NodeColor& nodeColor = GraphViewStyle::getNodeColor(Node::getTypeString(nodeType), false);
|
|
|
|
|
color = QColor(nodeColor.fill.c_str());
|
|
|
|
|
fillColor = QColor(nodeColor.fill.c_str());
|
|
|
|
|
textColor = QColor(nodeColor.text.c_str());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
color = QColor(scheme->getSearchTypeColor(SearchMatch::getSearchTypeName(SearchMatch::SEARCH_COMMAND), "fill").c_str());
|
|
|
|
|
fillColor = QColor(scheme->getSearchTypeColor(SearchMatch::getSearchTypeName(SearchMatch::SEARCH_COMMAND), "fill").c_str());
|
|
|
|
|
textColor = QColor(scheme->getSearchTypeColor(SearchMatch::getSearchTypeName(SearchMatch::SEARCH_COMMAND), "text").c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float charWidth = option.fontMetrics.width(
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
) / 500.0f;
|
|
|
|
|
int top1 = 6;
|
|
|
|
|
int top2 = m_charHeight1 + 3;
|
|
|
|
|
|
|
|
|
|
QString highlightName(name.size(), ' ');
|
|
|
|
|
// draw background
|
|
|
|
|
QColor backgroundColor = option.palette.color((option.state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base));
|
|
|
|
|
painter->fillRect(option.rect, backgroundColor);
|
|
|
|
|
|
|
|
|
|
QList<QVariant> indices = index.sibling(index.row(), index.column() + 2).data().toList();
|
|
|
|
|
// draw highlights at indices
|
|
|
|
|
QString highlightText(text.size(), ' ');
|
|
|
|
|
if (indices.size())
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < indices.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
int idx = indices[i].toInt();
|
|
|
|
|
int idx = indices[i].toInt() - (name.size() - text.size());
|
|
|
|
|
if (idx < 0)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QRect rect = option.rect.adjusted(charWidth * (idx + 1) + 2, 2, 0, -1);
|
|
|
|
|
rect.setWidth(charWidth + 1);
|
|
|
|
|
painter->fillRect(rect, color);
|
|
|
|
|
QRect rect(
|
|
|
|
|
option.rect.left() + m_charWidth1 * (idx + 1) + 2,
|
|
|
|
|
option.rect.top() + top1 - 1,
|
|
|
|
|
m_charWidth1 + 1,
|
|
|
|
|
m_charHeight1 - 1
|
|
|
|
|
);
|
|
|
|
|
painter->fillRect(rect, fillColor);
|
|
|
|
|
|
|
|
|
|
highlightName[idx] = name.at(idx);
|
|
|
|
|
name[idx] = ' ';
|
|
|
|
|
highlightText[idx] = text.at(idx);
|
|
|
|
|
text[idx] = ' ';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
QRect rect = option.rect.adjusted(0, 2, 0, -1);
|
|
|
|
|
rect.setWidth(charWidth - 1);
|
|
|
|
|
painter->fillRect(rect, color);
|
|
|
|
|
QRect rect(option.rect.left(), option.rect.top() + top1, m_charWidth1 - 1, m_charHeight1 - 2);
|
|
|
|
|
painter->fillRect(rect, fillColor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
painter->drawText(option.rect.adjusted(charWidth + 2, -1, 0, 0), Qt::AlignLeft, name);
|
|
|
|
|
// draw text normal
|
|
|
|
|
painter->drawText(option.rect.adjusted(m_charWidth1 + 2, top1 - 3, 0, 0), Qt::AlignLeft, text);
|
|
|
|
|
|
|
|
|
|
// draw text highlighted
|
|
|
|
|
painter->save();
|
|
|
|
|
QPen highlightPen = painter->pen();
|
|
|
|
|
highlightPen.setColor(textColor);
|
|
|
|
|
painter->setPen(highlightPen);
|
|
|
|
|
painter->drawText(option.rect.adjusted(charWidth + 2, -1, 0, 0), Qt::AlignLeft, highlightName);
|
|
|
|
|
painter->drawText(option.rect.adjusted(m_charWidth1 + 2, top1 - 3, 0, 0), Qt::AlignLeft, highlightText);
|
|
|
|
|
painter->restore();
|
|
|
|
|
|
|
|
|
|
if (type.size())
|
|
|
|
|
// draw subtext
|
|
|
|
|
if (subtext.size())
|
|
|
|
|
{
|
|
|
|
|
QFont font = painter->font();
|
|
|
|
|
font.setPixelSize(ApplicationSettings::getInstance()->getFontSize() - 4);
|
|
|
|
|
painter->setFont(font);
|
|
|
|
|
// draw arrow icon
|
|
|
|
|
painter->drawPixmap(
|
|
|
|
|
option.rect.left() + m_charWidth2 * 2,
|
|
|
|
|
option.rect.top() + top2 + 1 + (m_charHeight2 - m_arrow.height()) / 2,
|
|
|
|
|
m_arrow.pixmap()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
painter->setFont(m_font2);
|
|
|
|
|
|
|
|
|
|
QString highlightSubtext(subtext.size(), ' ');
|
|
|
|
|
if (indices.size())
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < indices.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
int idx = indices[i].toInt();
|
|
|
|
|
if (idx >= subtext.size())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QRect rect(
|
|
|
|
|
option.rect.left() + m_charWidth2 * (idx + 3) + 2,
|
|
|
|
|
option.rect.top() + top2 + 1,
|
|
|
|
|
m_charWidth2 + 1,
|
|
|
|
|
m_charHeight2
|
|
|
|
|
);
|
|
|
|
|
painter->fillRect(rect, fillColor);
|
|
|
|
|
|
|
|
|
|
highlightSubtext[idx] = subtext.at(idx);
|
|
|
|
|
subtext[idx] = ' ';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
// draw subtext normal
|
|
|
|
|
painter->drawText(option.rect.adjusted((3 * m_charWidth2) + 2, top2, 0, 0), Qt::AlignLeft, subtext);
|
|
|
|
|
|
|
|
|
|
// draw subtext highlighted
|
|
|
|
|
painter->save();
|
|
|
|
|
QPen highlightPen = painter->pen();
|
|
|
|
|
highlightPen.setColor(textColor);
|
|
|
|
|
painter->setPen(highlightPen);
|
|
|
|
|
painter->drawText(option.rect.adjusted((3 * m_charWidth2) + 2, top2, 0, 0), Qt::AlignLeft, highlightSubtext);
|
|
|
|
|
painter->restore();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// draw type
|
|
|
|
|
if (type.size())
|
|
|
|
|
{
|
|
|
|
|
painter->setFont(m_font2);
|
|
|
|
|
|
|
|
|
|
QPen typePen = painter->pen();
|
|
|
|
|
typePen.setColor(scheme->getColor("search/popup/by_text").c_str());
|
|
|
|
|
painter->setPen(typePen);
|
|
|
|
|
|
|
|
|
|
int width = m_charWidth2 * type.size();
|
|
|
|
|
int x = painter->viewport().right() - width - m_charWidth2;
|
|
|
|
|
int y = option.rect.top() + top2;
|
|
|
|
|
|
|
|
|
|
painter->fillRect(QRect(x - m_charWidth2, y, width + m_charWidth2 * 3, m_charHeight2 + 2), backgroundColor);
|
|
|
|
|
painter->drawText(QRect(x, y, width, m_charHeight2), Qt::AlignRight, type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// draw bottom line
|
|
|
|
|
QRect rect(0, option.rect.bottom(), option.rect.width(), 1);
|
|
|
|
|
painter->fillRect(rect, scheme->getColor("search/popup/line").c_str());
|
|
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
const_cast<QtAutocompletionDelegate*>(this)->calculateCharSizes(option.font);
|
|
|
|
|
|
|
|
|
|
QString text = m_model->longestText();
|
|
|
|
|
QString subtext = m_model->longestSubText();
|
|
|
|
|
QString type = m_model->longestType();
|
|
|
|
|
|
|
|
|
|
return QSize(
|
|
|
|
|
std::max((text.size() + 2) * m_charWidth1, (subtext.size() + type.size() + 6) * m_charWidth2),
|
|
|
|
|
m_charHeight1 * 2 + 3
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QtAutocompletionDelegate::calculateCharSizes(QFont font)
|
|
|
|
|
{
|
|
|
|
|
if (m_charWidth1 > 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_font1 = font;
|
|
|
|
|
|
|
|
|
|
QFontMetrics metrics1(font);
|
|
|
|
|
m_charWidth1 = metrics1.width(
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
) / 500.0f;
|
|
|
|
|
m_charHeight1 = metrics1.height();
|
|
|
|
|
|
|
|
|
|
font.setPixelSize(ApplicationSettings::getInstance()->getFontSize() - 3);
|
|
|
|
|
m_font2 = font;
|
|
|
|
|
|
|
|
|
|
QFontMetrics metrics2(font);
|
|
|
|
|
m_charWidth2 = metrics2.width(
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
"----------------------------------------------------------------------------------------------------"
|
|
|
|
|
) / 500.0f;
|
|
|
|
|
m_charHeight2 = metrics2.height();
|
|
|
|
|
|
|
|
|
|
m_arrow = QtDeviceScaledPixmap(QString::fromStdString(ResourcePaths::getGuiPath() + "search_view/images/arrow.png"));
|
|
|
|
|
m_arrow.scaleToWidth(m_charWidth2);
|
|
|
|
|
m_arrow.colorize(ColorScheme::getInstance()->getColor("search/popup/by_text").c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QtAutocompletionDelegate::resetCharSizes()
|
|
|
|
|
{
|
|
|
|
|
m_charWidth1 = m_charHeight1 = m_charWidth2 = m_charHeight2 = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QtAutocompletionList::QtAutocompletionList(QWidget* parent)
|
|
|
|
|
: QCompleter(parent)
|
|
|
|
|
{
|
|
|
|
|
m_model = std::make_shared<QtAutocompletionModel>(this);
|
|
|
|
|
setModel(m_model.get());
|
|
|
|
|
|
|
|
|
|
m_delegate = std::make_shared<QtAutocompletionDelegate>(this);
|
|
|
|
|
m_delegate = std::make_shared<QtAutocompletionDelegate>(m_model.get(), this);
|
|
|
|
|
|
|
|
|
|
QListView* list = new QListView(parent);
|
|
|
|
|
list->setItemDelegateForColumn(0, m_delegate.get());
|
|
|
|
@@ -201,7 +360,7 @@ QtAutocompletionList::QtAutocompletionList(QWidget* parent)
|
|
|
|
|
setCompletionMode(QCompleter::UnfilteredPopupCompletion);
|
|
|
|
|
setModelSorting(QCompleter::UnsortedModel);
|
|
|
|
|
setCompletionPrefix("");
|
|
|
|
|
setMaxVisibleItems(20);
|
|
|
|
|
setMaxVisibleItems(8);
|
|
|
|
|
|
|
|
|
|
m_scrollSpeedChangeListenerHorizontal.setScrollBar(list->horizontalScrollBar());
|
|
|
|
|
m_scrollSpeedChangeListenerVertical.setScrollBar(list->verticalScrollBar());
|
|
|
|
@@ -222,6 +381,8 @@ void QtAutocompletionList::completeAt(const QPoint& pos, const std::vector<Searc
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_delegate->resetCharSizes();
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|