2017-04-27 18:26:05 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2013-11-02 01:20:02 +00:00
|
|
|
#include "tagwidget.h"
|
2014-05-16 06:12:46 +00:00
|
|
|
#include "mainwindow.h"
|
2017-04-04 17:21:30 +00:00
|
|
|
#include "tab-widgets/maintab.h"
|
2015-01-17 09:43:52 +00:00
|
|
|
#include <QCompleter>
|
2013-11-02 01:20:02 +00:00
|
|
|
|
2014-05-16 06:12:46 +00:00
|
|
|
TagWidget::TagWidget(QWidget *parent) : GroupedLineEdit(parent), m_completer(NULL), lastFinishedTag(false)
|
2013-11-02 01:20:02 +00:00
|
|
|
{
|
|
|
|
connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(reparse()));
|
2013-11-02 16:04:18 +00:00
|
|
|
connect(this, SIGNAL(textChanged()), this, SLOT(reparse()));
|
2013-11-02 01:20:02 +00:00
|
|
|
|
2013-12-19 19:16:57 +00:00
|
|
|
QColor textColor = palette().color(QPalette::Text);
|
|
|
|
qreal h, s, l, a;
|
|
|
|
textColor.getHslF(&h, &s, &l, &a);
|
|
|
|
// I use dark themes
|
2014-02-28 04:09:57 +00:00
|
|
|
if (l <= 0.3) { // very dark text. get a brigth background
|
|
|
|
addColor(QColor(Qt::red).lighter(120));
|
|
|
|
addColor(QColor(Qt::green).lighter(120));
|
|
|
|
addColor(QColor(Qt::blue).lighter(120));
|
2014-07-11 17:39:03 +00:00
|
|
|
} else if (l <= 0.6) { // moderated dark text. get a somewhat bright background
|
2014-02-28 04:09:57 +00:00
|
|
|
addColor(QColor(Qt::red).lighter(60));
|
|
|
|
addColor(QColor(Qt::green).lighter(60));
|
|
|
|
addColor(QColor(Qt::blue).lighter(60));
|
2014-01-16 04:50:56 +00:00
|
|
|
} else {
|
2014-02-28 04:09:57 +00:00
|
|
|
addColor(QColor(Qt::red).darker(120));
|
|
|
|
addColor(QColor(Qt::green).darker(120));
|
|
|
|
addColor(QColor(Qt::blue).darker(120));
|
2013-12-19 19:16:57 +00:00
|
|
|
} // light text. get a dark background.
|
2018-10-12 20:07:25 +00:00
|
|
|
setTabChangesFocus(true);
|
2014-01-19 15:33:24 +00:00
|
|
|
setFocusPolicy(Qt::StrongFocus);
|
2013-11-02 01:20:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TagWidget::setCompleter(QCompleter *completer)
|
|
|
|
{
|
|
|
|
m_completer = completer;
|
|
|
|
m_completer->setWidget(this);
|
|
|
|
connect(m_completer, SIGNAL(activated(QString)), this, SLOT(completionSelected(QString)));
|
2014-03-19 16:24:53 +00:00
|
|
|
connect(m_completer, SIGNAL(highlighted(QString)), this, SLOT(completionHighlighted(QString)));
|
2013-11-02 01:20:02 +00:00
|
|
|
}
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
QPair<int, int> TagWidget::getCursorTagPosition()
|
|
|
|
{
|
2013-11-02 01:20:02 +00:00
|
|
|
int i = 0, start = 0, end = 0;
|
|
|
|
/* Parse string near cursor */
|
|
|
|
i = cursorPosition();
|
|
|
|
while (--i > 0) {
|
|
|
|
if (text().at(i) == ',') {
|
2014-02-28 04:09:57 +00:00
|
|
|
if (i > 0 && text().at(i - 1) != '\\') {
|
2013-11-02 01:20:02 +00:00
|
|
|
i++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
start = i;
|
|
|
|
while (++i < text().length()) {
|
|
|
|
if (text().at(i) == ',') {
|
2014-02-28 04:09:57 +00:00
|
|
|
if (i > 0 && text().at(i - 1) != '\\')
|
2013-11-02 01:20:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end = i;
|
|
|
|
if (start < 0 || end < 0) {
|
|
|
|
start = 0;
|
|
|
|
end = 0;
|
|
|
|
}
|
2014-02-28 04:09:57 +00:00
|
|
|
return qMakePair(start, end);
|
2013-11-02 01:20:02 +00:00
|
|
|
}
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
void TagWidget::highlight()
|
|
|
|
{
|
2013-11-02 01:20:02 +00:00
|
|
|
removeAllBlocks();
|
2014-05-27 23:06:24 +00:00
|
|
|
int lastPos = 0;
|
2019-04-01 20:15:19 +00:00
|
|
|
const auto l = text().split(QChar(','), QString::SkipEmptyParts);
|
|
|
|
for (const QString &s: l) {
|
2014-05-27 23:06:24 +00:00
|
|
|
QString trimmed = s.trimmed();
|
|
|
|
if (trimmed.isEmpty())
|
|
|
|
continue;
|
|
|
|
int start = text().indexOf(trimmed, lastPos);
|
|
|
|
addBlock(start, trimmed.size() + start);
|
|
|
|
lastPos = trimmed.size() + start;
|
2013-11-02 01:20:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TagWidget::reparse()
|
|
|
|
{
|
|
|
|
highlight();
|
2014-02-28 04:09:57 +00:00
|
|
|
QPair<int, int> pos = getCursorTagPosition();
|
2013-11-02 01:20:02 +00:00
|
|
|
QString currentText;
|
|
|
|
if (pos.first >= 0 && pos.second > 0)
|
2014-02-28 04:09:57 +00:00
|
|
|
currentText = text().mid(pos.first, pos.second - pos.first).trimmed();
|
2014-03-19 18:36:09 +00:00
|
|
|
|
2013-11-02 01:20:02 +00:00
|
|
|
if (m_completer) {
|
|
|
|
m_completer->setCompletionPrefix(currentText);
|
2013-11-02 16:04:18 +00:00
|
|
|
if (m_completer->completionCount() == 1) {
|
|
|
|
if (m_completer->currentCompletion() == currentText) {
|
|
|
|
QAbstractItemView *popup = m_completer->popup();
|
|
|
|
if (popup)
|
|
|
|
popup->hide();
|
2014-01-16 04:50:56 +00:00
|
|
|
} else {
|
2013-11-02 16:04:18 +00:00
|
|
|
m_completer->complete();
|
2014-01-16 04:50:56 +00:00
|
|
|
}
|
2013-11-02 16:04:18 +00:00
|
|
|
} else {
|
|
|
|
m_completer->complete();
|
|
|
|
}
|
2013-11-02 01:20:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-22 18:40:22 +00:00
|
|
|
void TagWidget::completionSelected(const QString &completion)
|
2014-02-28 04:09:57 +00:00
|
|
|
{
|
2014-03-19 18:23:58 +00:00
|
|
|
completionHighlighted(completion);
|
|
|
|
emit textChanged();
|
2013-11-02 01:20:02 +00:00
|
|
|
}
|
|
|
|
|
2014-05-22 18:40:22 +00:00
|
|
|
void TagWidget::completionHighlighted(const QString &completion)
|
2014-03-19 16:24:53 +00:00
|
|
|
{
|
2014-03-19 19:30:13 +00:00
|
|
|
QPair<int, int> pos = getCursorTagPosition();
|
2014-04-23 08:06:45 +00:00
|
|
|
setText(text().remove(pos.first, pos.second - pos.first).insert(pos.first, completion));
|
|
|
|
setCursorPosition(pos.first + completion.length());
|
2014-03-19 16:24:53 +00:00
|
|
|
}
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
void TagWidget::setCursorPosition(int position)
|
|
|
|
{
|
2013-11-02 01:20:02 +00:00
|
|
|
blockSignals(true);
|
|
|
|
GroupedLineEdit::setCursorPosition(position);
|
|
|
|
blockSignals(false);
|
|
|
|
}
|
|
|
|
|
2014-05-22 18:40:22 +00:00
|
|
|
void TagWidget::setText(const QString &text)
|
2014-02-28 04:09:57 +00:00
|
|
|
{
|
2013-11-02 01:20:02 +00:00
|
|
|
blockSignals(true);
|
|
|
|
GroupedLineEdit::setText(text);
|
|
|
|
blockSignals(false);
|
|
|
|
highlight();
|
|
|
|
}
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
void TagWidget::clear()
|
|
|
|
{
|
2013-11-02 01:20:02 +00:00
|
|
|
blockSignals(true);
|
|
|
|
GroupedLineEdit::clear();
|
|
|
|
blockSignals(false);
|
|
|
|
}
|
2013-11-02 16:04:18 +00:00
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
void TagWidget::keyPressEvent(QKeyEvent *e)
|
|
|
|
{
|
2014-03-20 15:04:29 +00:00
|
|
|
QPair<int, int> pos;
|
|
|
|
QAbstractItemView *popup;
|
2014-05-16 06:12:46 +00:00
|
|
|
bool finishedTag = false;
|
2013-11-02 16:04:18 +00:00
|
|
|
switch (e->key()) {
|
2014-03-20 15:04:29 +00:00
|
|
|
case Qt::Key_Escape:
|
|
|
|
pos = getCursorTagPosition();
|
|
|
|
if (pos.first >= 0 && pos.second > 0) {
|
|
|
|
setText(text().remove(pos.first, pos.second - pos.first));
|
|
|
|
setCursorPosition(pos.first);
|
|
|
|
}
|
2014-05-22 18:40:22 +00:00
|
|
|
popup = m_completer->popup();
|
2014-03-20 15:04:29 +00:00
|
|
|
if (popup)
|
|
|
|
popup->hide();
|
|
|
|
return;
|
2013-11-02 16:04:18 +00:00
|
|
|
case Qt::Key_Return:
|
|
|
|
case Qt::Key_Enter:
|
2013-11-07 04:40:57 +00:00
|
|
|
case Qt::Key_Tab:
|
2013-11-02 16:04:18 +00:00
|
|
|
/*
|
|
|
|
* Fake the QLineEdit behaviour by simply
|
|
|
|
* closing the QAbstractViewitem
|
|
|
|
*/
|
|
|
|
if (m_completer) {
|
2014-03-20 15:04:29 +00:00
|
|
|
popup = m_completer->popup();
|
2013-11-02 16:04:18 +00:00
|
|
|
if (popup)
|
|
|
|
popup->hide();
|
|
|
|
}
|
2014-05-16 06:12:46 +00:00
|
|
|
finishedTag = true;
|
2014-07-10 16:19:07 +00:00
|
|
|
break;
|
|
|
|
case Qt::Key_Comma: { /* if this is the last key, and the previous string is empty, ignore the comma. */
|
|
|
|
QString temp = text();
|
|
|
|
if (temp.split(QChar(',')).last().trimmed().isEmpty()){
|
|
|
|
e->ignore();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2013-11-02 16:04:18 +00:00
|
|
|
}
|
2014-05-22 18:40:22 +00:00
|
|
|
if (e->key() == Qt::Key_Tab && lastFinishedTag) { // if we already end in comma, go to next/prev field
|
2018-10-12 14:13:42 +00:00
|
|
|
MainWindow::instance()->mainTab->nextInputField(e); // by sending the key event to the MainTab widget
|
2014-05-16 06:12:46 +00:00
|
|
|
} else if (e->key() == Qt::Key_Tab || e->key() == Qt::Key_Return) { // otherwise let's pretend this is a comma instead
|
2013-12-19 20:56:43 +00:00
|
|
|
QKeyEvent fakeEvent(e->type(), Qt::Key_Comma, e->modifiers(), QString(","));
|
2014-07-10 16:19:58 +00:00
|
|
|
keyPressEvent(&fakeEvent);
|
2013-11-07 04:40:57 +00:00
|
|
|
} else {
|
|
|
|
GroupedLineEdit::keyPressEvent(e);
|
|
|
|
}
|
2014-05-16 06:12:46 +00:00
|
|
|
lastFinishedTag = finishedTag;
|
2013-11-02 16:04:18 +00:00
|
|
|
}
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
void TagWidget::wheelEvent(QWheelEvent *event)
|
|
|
|
{
|
2014-01-19 15:33:24 +00:00
|
|
|
if (hasFocus()) {
|
|
|
|
GroupedLineEdit::wheelEvent(event);
|
|
|
|
}
|
|
|
|
}
|
2014-11-17 01:28:48 +00:00
|
|
|
|
|
|
|
void TagWidget::fixPopupPosition(int delta)
|
|
|
|
{
|
|
|
|
if(m_completer->popup()->isVisible()){
|
|
|
|
QRect toGlobal = m_completer->popup()->geometry();
|
|
|
|
m_completer->popup()->setGeometry(toGlobal.x(), toGlobal.y() + delta +10, toGlobal.width(), toGlobal.height());
|
|
|
|
}
|
|
|
|
}
|
2019-02-07 18:59:34 +00:00
|
|
|
|
|
|
|
// Since we capture enter / return / tab, we never send an editingFinished() signal.
|
|
|
|
// Therefore, override the focusOutEvent()
|
|
|
|
void TagWidget::focusOutEvent(QFocusEvent *ev)
|
|
|
|
{
|
|
|
|
GroupedLineEdit::focusOutEvent(ev);
|
|
|
|
emit editingFinished();
|
|
|
|
}
|