Formula Editor Completer

.. edit formulas on LTM tool with autocompletion
   but not when in comments.
This commit is contained in:
Mark Liversedge
2015-08-13 13:53:18 +01:00
parent 480c9d0d04
commit d3411420cc
4 changed files with 176 additions and 3 deletions

View File

@@ -22,6 +22,8 @@
#include "Athlete.h"
#include "Settings.h"
#include "Units.h"
#include "Tab.h"
#include "RideNavigator.h"
#include "HelpWhatsThis.h"
#include <QApplication>
#include <QtGui>
@@ -1502,6 +1504,12 @@ EditMetricDetailDialog::estimateName()
/*----------------------------------------------------------------------
* EDIT METRIC DETAIL DIALOG
*--------------------------------------------------------------------*/
static bool insensitiveLessThan(const QString &a, const QString &b)
{
return a.toLower() < b.toLower();
}
EditMetricDetailDialog::EditMetricDetailDialog(Context *context, LTMTool *ltmTool, MetricDetail *metricDetail) :
QDialog(context->mainWindow, Qt::Dialog), context(context), ltmTool(ltmTool), metricDetail(metricDetail)
{
@@ -1692,12 +1700,43 @@ EditMetricDetailDialog::EditMetricDetailDialog(Context *context, LTMTool *ltmToo
//formulaWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QVBoxLayout *formulaLayout = new QVBoxLayout(formulaWidget);
formulaLayout->addStretch();
formulaEdit = new QTextEdit(this);
formulaEdit = new DataFilterEdit(this);
//formulaEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
formulaLayout->addWidget(formulaEdit);
formulaLayout->addStretch();
formulaEdit->setText(metricDetail->formula);
// get suitably formated list
QList<QString> list;
QString last;
SpecialFields sp;
// get sorted list
QStringList names = context->tab->rideNavigator()->logicalHeadings;
qSort(names.begin(), names.end(), insensitiveLessThan);
foreach(QString name, names) {
// handle dups
if (last == name) continue;
last = name;
// Handle bikescore tm
if (name.startsWith("BikeScore")) name = QString("BikeScore");
// Always use the "internalNames" in Filter expressions
name = sp.internalName(name);
// we do very little to the name, just space to _ and lower case it for now...
name.replace(' ', '_');
list << name;
}
// set new list
// create an empty completer, configchanged will fix it
DataFilterCompleter *completer = new DataFilterCompleter(list, this);
formulaEdit->setCompleter(completer);
// stress selection
stressTypeSelect = new QComboBox(this);
stressTypeSelect->addItem(tr("Short Term Stress (STS/ATL)"), STRESS_STS);
@@ -2259,4 +2298,110 @@ LTMTool::setFilter(QStringList files)
filenames = files;
emit filterChanged();
}
DataFilterEdit::DataFilterEdit(QWidget *parent)
: QTextEdit(parent), c(0)
{
}
DataFilterEdit::~DataFilterEdit()
{
}
void DataFilterEdit::setCompleter(QCompleter *completer)
{
if (c)
QObject::disconnect(c, 0, this, 0);
c = completer;
if (!c)
return;
c->setWidget(this);
c->setCompletionMode(QCompleter::PopupCompletion);
c->setCaseSensitivity(Qt::CaseInsensitive);
QObject::connect(c, SIGNAL(activated(QString)),
this, SLOT(insertCompletion(QString)));
}
QCompleter *DataFilterEdit::completer() const
{
return c;
}
void DataFilterEdit::insertCompletion(const QString& completion)
{
if (c->widget() != this)
return;
QTextCursor tc = textCursor();
int extra = completion.length() - c->completionPrefix().length();
tc.movePosition(QTextCursor::Left);
tc.movePosition(QTextCursor::EndOfWord);
tc.insertText(completion.right(extra));
setTextCursor(tc);
}
QString DataFilterEdit::textUnderCursor() const
{
QTextCursor tc = textCursor();
tc.select(QTextCursor::WordUnderCursor);
return tc.selectedText();
}
void DataFilterEdit::focusInEvent(QFocusEvent *e)
{
if (c) c->setWidget(this);
QTextEdit::focusInEvent(e);
}
void DataFilterEdit::keyPressEvent(QKeyEvent *e)
{
if (c && c->popup()->isVisible()) {
// The following keys are forwarded by the completer to the widget
switch (e->key()) {
case Qt::Key_Enter:
case Qt::Key_Return:
case Qt::Key_Escape:
case Qt::Key_Tab:
case Qt::Key_Backtab:
e->ignore();
return; // let the completer do default behavior
default:
break;
}
}
bool isShortcut = ((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_E); // CTRL+E
if (!c || !isShortcut) // do not process the shortcut when we have a completer
QTextEdit::keyPressEvent(e);
const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
if (!c || (ctrlOrShift && e->text().isEmpty()))
return;
static QString eow("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="); // end of word
bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift;
QString completionPrefix = textUnderCursor();
// are we in a comment ?
QString line = textCursor().block().text().trimmed();
for(int i=textCursor().positionInBlock(); i>=0; i--)
if (line[i]=='#') return;
if (!isShortcut && (hasModifier || e->text().isEmpty()|| completionPrefix.length() < 1
|| eow.contains(e->text().right(1)))) {
c->popup()->hide();
return;
}
if (completionPrefix != c->completionPrefix()) {
c->setCompletionPrefix(completionPrefix);
c->popup()->setCurrentIndex(c->completionModel()->index(0, 0));
}
QRect cr = cursorRect();
cr.setWidth(c->popup()->sizeHintForColumn(0)
+ c->popup()->verticalScrollBar()->sizeHint().width());
c->complete(cr); // popup it up!
}

View File

@@ -48,6 +48,7 @@
#define SYS_DATE 1
#define USER_DATE 2
class DataFilterEdit;
class LTMTool : public QWidget
{
@@ -205,7 +206,7 @@ class EditMetricDetailDialog : public QDialog
QComboBox *stressTypeSelect; // STS, LTS, SB, RR et al
// formula
QTextEdit *formulaEdit; // edit your formula
DataFilterEdit *formulaEdit; // edit your formula
QComboBox *curveStyle,
*curveSymbol;
@@ -227,5 +228,29 @@ class EditMetricDetailDialog : public QDialog
QList<RideFile::SeriesType> seriesList;
};
#endif // _GC_LTMTool_h
class DataFilterEdit : public QTextEdit
{
Q_OBJECT
public:
DataFilterEdit(QWidget *parent = 0);
~DataFilterEdit();
void setCompleter(QCompleter *c);
QCompleter *completer() const;
protected:
void keyPressEvent(QKeyEvent *e);
void focusInEvent(QFocusEvent *e);
private slots:
void insertCompletion(const QString &completion);
private:
QString textUnderCursor() const;
private:
QCompleter *c;
};
#endif // _GC_LTMTool_h

View File

@@ -45,6 +45,7 @@ class DataFilter;
class GcMiniCalendar;
class SearchBox;
class RideTreeView;
class EditMetricDetailDialog;
//
// The RideNavigator
@@ -71,6 +72,7 @@ class RideNavigator : public GcWindow
friend class ::GcMiniCalendar;
friend class ::DataFilter;
friend class ::SearchBox;
friend class ::EditMetricDetailDialog;
public:
RideNavigator(Context *, bool mainwindow = false);

View File

@@ -127,6 +127,7 @@ public:
inline DataFilterCompleter(const QStringList& words, QObject * parent) :
QCompleter(parent), m_list(words), m_model()
{
m_model.setStringList(words);
setModel(&m_model);
}