summaryrefslogtreecommitdiffstats
path: root/desktop-widgets/tagwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'desktop-widgets/tagwidget.cpp')
-rw-r--r--desktop-widgets/tagwidget.cpp210
1 files changed, 210 insertions, 0 deletions
diff --git a/desktop-widgets/tagwidget.cpp b/desktop-widgets/tagwidget.cpp
new file mode 100644
index 000000000..3b61b492a
--- /dev/null
+++ b/desktop-widgets/tagwidget.cpp
@@ -0,0 +1,210 @@
+#include "tagwidget.h"
+#include "mainwindow.h"
+#include "maintab.h"
+#include <QCompleter>
+
+TagWidget::TagWidget(QWidget *parent) : GroupedLineEdit(parent), m_completer(NULL), lastFinishedTag(false)
+{
+ connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(reparse()));
+ connect(this, SIGNAL(textChanged()), this, SLOT(reparse()));
+
+ QColor textColor = palette().color(QPalette::Text);
+ qreal h, s, l, a;
+ textColor.getHslF(&h, &s, &l, &a);
+ // I use dark themes
+ 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));
+ } else if (l <= 0.6) { // moderated dark text. get a somewhat bright background
+ addColor(QColor(Qt::red).lighter(60));
+ addColor(QColor(Qt::green).lighter(60));
+ addColor(QColor(Qt::blue).lighter(60));
+ } else {
+ addColor(QColor(Qt::red).darker(120));
+ addColor(QColor(Qt::green).darker(120));
+ addColor(QColor(Qt::blue).darker(120));
+ } // light text. get a dark background.
+ setFocusPolicy(Qt::StrongFocus);
+}
+
+void TagWidget::setCompleter(QCompleter *completer)
+{
+ m_completer = completer;
+ m_completer->setWidget(this);
+ connect(m_completer, SIGNAL(activated(QString)), this, SLOT(completionSelected(QString)));
+ connect(m_completer, SIGNAL(highlighted(QString)), this, SLOT(completionHighlighted(QString)));
+}
+
+QPair<int, int> TagWidget::getCursorTagPosition()
+{
+ int i = 0, start = 0, end = 0;
+ /* Parse string near cursor */
+ i = cursorPosition();
+ while (--i > 0) {
+ if (text().at(i) == ',') {
+ if (i > 0 && text().at(i - 1) != '\\') {
+ i++;
+ break;
+ }
+ }
+ }
+ start = i;
+ while (++i < text().length()) {
+ if (text().at(i) == ',') {
+ if (i > 0 && text().at(i - 1) != '\\')
+ break;
+ }
+ }
+ end = i;
+ if (start < 0 || end < 0) {
+ start = 0;
+ end = 0;
+ }
+ return qMakePair(start, end);
+}
+
+void TagWidget::highlight()
+{
+ removeAllBlocks();
+ int lastPos = 0;
+ Q_FOREACH (const QString& s, text().split(QChar(','), QString::SkipEmptyParts)) {
+ QString trimmed = s.trimmed();
+ if (trimmed.isEmpty())
+ continue;
+ int start = text().indexOf(trimmed, lastPos);
+ addBlock(start, trimmed.size() + start);
+ lastPos = trimmed.size() + start;
+ }
+}
+
+void TagWidget::reparse()
+{
+ highlight();
+ QPair<int, int> pos = getCursorTagPosition();
+ QString currentText;
+ if (pos.first >= 0 && pos.second > 0)
+ currentText = text().mid(pos.first, pos.second - pos.first).trimmed();
+
+ /*
+ * Do not show the completer when not in edit mode - basically
+ * this returns when we are accepting or discarding the changes.
+ */
+ if (MainWindow::instance()->information()->isEditing() == false || currentText.length() == 0) {
+ return;
+ }
+
+ if (m_completer) {
+ m_completer->setCompletionPrefix(currentText);
+ if (m_completer->completionCount() == 1) {
+ if (m_completer->currentCompletion() == currentText) {
+ QAbstractItemView *popup = m_completer->popup();
+ if (popup)
+ popup->hide();
+ } else {
+ m_completer->complete();
+ }
+ } else {
+ m_completer->complete();
+ }
+ }
+}
+
+void TagWidget::completionSelected(const QString &completion)
+{
+ completionHighlighted(completion);
+ emit textChanged();
+}
+
+void TagWidget::completionHighlighted(const QString &completion)
+{
+ QPair<int, int> pos = getCursorTagPosition();
+ setText(text().remove(pos.first, pos.second - pos.first).insert(pos.first, completion));
+ setCursorPosition(pos.first + completion.length());
+}
+
+void TagWidget::setCursorPosition(int position)
+{
+ blockSignals(true);
+ GroupedLineEdit::setCursorPosition(position);
+ blockSignals(false);
+}
+
+void TagWidget::setText(const QString &text)
+{
+ blockSignals(true);
+ GroupedLineEdit::setText(text);
+ blockSignals(false);
+ highlight();
+}
+
+void TagWidget::clear()
+{
+ blockSignals(true);
+ GroupedLineEdit::clear();
+ blockSignals(false);
+}
+
+void TagWidget::keyPressEvent(QKeyEvent *e)
+{
+ QPair<int, int> pos;
+ QAbstractItemView *popup;
+ bool finishedTag = false;
+ switch (e->key()) {
+ 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);
+ }
+ popup = m_completer->popup();
+ if (popup)
+ popup->hide();
+ return;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ case Qt::Key_Tab:
+ /*
+ * Fake the QLineEdit behaviour by simply
+ * closing the QAbstractViewitem
+ */
+ if (m_completer) {
+ popup = m_completer->popup();
+ if (popup)
+ popup->hide();
+ }
+ finishedTag = true;
+ 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;
+ }
+ }
+ }
+ if (e->key() == Qt::Key_Tab && lastFinishedTag) { // if we already end in comma, go to next/prev field
+ MainWindow::instance()->information()->nextInputField(e); // by sending the key event to the MainTab widget
+ } else if (e->key() == Qt::Key_Tab || e->key() == Qt::Key_Return) { // otherwise let's pretend this is a comma instead
+ QKeyEvent fakeEvent(e->type(), Qt::Key_Comma, e->modifiers(), QString(","));
+ keyPressEvent(&fakeEvent);
+ } else {
+ GroupedLineEdit::keyPressEvent(e);
+ }
+ lastFinishedTag = finishedTag;
+}
+
+void TagWidget::wheelEvent(QWheelEvent *event)
+{
+ if (hasFocus()) {
+ GroupedLineEdit::wheelEvent(event);
+ }
+}
+
+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());
+ }
+}