mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-28 05:00:20 +00:00
Added a custom widget for tagging dives
A custom tag widget has been added to MainTab. Tags are seperated by a comma ",". The implementation supports escaping a comma by using "\,". While typing, the widget supports the user by suggesting tags using a QCompleter. Signed-off-by: Maximilian Güntner <maximilian.guentner@gmail.com>
This commit is contained in:
parent
6fe8cb6521
commit
04cdfce782
10 changed files with 582 additions and 50 deletions
|
@ -12,6 +12,7 @@ CREATE_SINGLETON(BuddyCompletionModel);
|
|||
CREATE_SINGLETON(DiveMasterCompletionModel);
|
||||
CREATE_SINGLETON(LocationCompletionModel);
|
||||
CREATE_SINGLETON(SuitCompletionModel);
|
||||
CREATE_SINGLETON(TagCompletionModel);
|
||||
|
||||
#undef CREATE_SINGLETON
|
||||
|
||||
|
@ -35,3 +36,15 @@ CREATE_UPDATE_METHOD(DiveMasterCompletionModel, divemaster);
|
|||
CREATE_UPDATE_METHOD(LocationCompletionModel, location);
|
||||
CREATE_UPDATE_METHOD(SuitCompletionModel, suit);
|
||||
|
||||
void TagCompletionModel::updateModel()
|
||||
{
|
||||
if(g_tag_list == NULL)
|
||||
return;
|
||||
QStringList list;
|
||||
struct tag_entry *current_tag_entry = g_tag_list->next;
|
||||
while (current_tag_entry != NULL) {
|
||||
list.append(QString(current_tag_entry->tag->name));
|
||||
current_tag_entry = current_tag_entry->next;
|
||||
}
|
||||
setStringList(list);
|
||||
}
|
||||
|
|
|
@ -31,4 +31,11 @@ public:
|
|||
void updateModel();
|
||||
};
|
||||
|
||||
class TagCompletionModel : public QStringListModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static TagCompletionModel* instance();
|
||||
void updateModel();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
204
qt-ui/groupedlineedit.cpp
Normal file
204
qt-ui/groupedlineedit.cpp
Normal file
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* This file is part of the Nepomuk widgets collection
|
||||
* Copyright (c) 2013 Denis Steckelmacher <steckdenis@yahoo.fr>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License version 2.1 as published by the Free Software Foundation,
|
||||
* or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public License
|
||||
* along with this library; see the file COPYING.LIB. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "groupedlineedit.h"
|
||||
|
||||
#include <QtGui/QStyleOptionFrameV3>
|
||||
#include <QtGui/QFontMetrics>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QScrollBar>
|
||||
#include <QtGui/QTextDocument>
|
||||
#include <QtGui/QTextBlock>
|
||||
#include <QtGui/QTextLayout>
|
||||
#include <QtGui/QTextLine>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QPainterPath>
|
||||
#include <QtGui/QBrush>
|
||||
#include <QtGui/QColor>
|
||||
#include <QtGui/QPalette>
|
||||
|
||||
struct GroupedLineEdit::Private
|
||||
{
|
||||
struct Block {
|
||||
int start;
|
||||
int end;
|
||||
QString text;
|
||||
};
|
||||
QVector<Block> blocks;
|
||||
QVector<QColor> colors;
|
||||
};
|
||||
|
||||
GroupedLineEdit::GroupedLineEdit(QWidget* parent)
|
||||
: QPlainTextEdit(parent),
|
||||
d(new Private)
|
||||
{
|
||||
setWordWrapMode(QTextOption::NoWrap);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
document()->setMaximumBlockCount(1);
|
||||
}
|
||||
|
||||
|
||||
GroupedLineEdit::~GroupedLineEdit()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QString GroupedLineEdit::text() const
|
||||
{
|
||||
// Remove the block crosses from the text
|
||||
return toPlainText();
|
||||
}
|
||||
|
||||
int GroupedLineEdit::cursorPosition() const
|
||||
{
|
||||
return textCursor().positionInBlock();
|
||||
}
|
||||
|
||||
void GroupedLineEdit::addBlock(int start, int end)
|
||||
{
|
||||
Private::Block block;
|
||||
|
||||
block.start = start;
|
||||
block.end = end;
|
||||
block.text = text().mid(start, end-start+1).trimmed();
|
||||
d->blocks.append(block);
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
void GroupedLineEdit::addColor(QColor color)
|
||||
{
|
||||
d->colors.append(color);
|
||||
}
|
||||
|
||||
void GroupedLineEdit::removeAllColors()
|
||||
{
|
||||
d->colors.clear();
|
||||
}
|
||||
|
||||
QStringList GroupedLineEdit::getBlockStringList()
|
||||
{
|
||||
QStringList retList;
|
||||
Private::Block block;
|
||||
foreach(block, d->blocks)
|
||||
retList.append(block.text);
|
||||
return retList;
|
||||
}
|
||||
|
||||
void GroupedLineEdit::setCursorPosition(int position)
|
||||
{
|
||||
QTextCursor c = textCursor();
|
||||
|
||||
c.setPosition(position, QTextCursor::MoveAnchor);
|
||||
|
||||
setTextCursor(c);
|
||||
}
|
||||
|
||||
void GroupedLineEdit::setText(const QString &text)
|
||||
{
|
||||
setPlainText(text);
|
||||
}
|
||||
|
||||
void GroupedLineEdit::clear()
|
||||
{
|
||||
QPlainTextEdit::clear();
|
||||
removeAllBlocks();
|
||||
}
|
||||
|
||||
void GroupedLineEdit::selectAll()
|
||||
{
|
||||
QTextCursor c = textCursor();
|
||||
|
||||
c.select(QTextCursor::LineUnderCursor);
|
||||
|
||||
setTextCursor(c);
|
||||
}
|
||||
|
||||
void GroupedLineEdit::removeAllBlocks()
|
||||
{
|
||||
d->blocks.clear();
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
QSize GroupedLineEdit::sizeHint() const
|
||||
{
|
||||
QSize rs(
|
||||
40,
|
||||
document()->findBlock(0).layout()->lineAt(0).height() +
|
||||
document()->documentMargin() * 2 +
|
||||
frameWidth() * 2
|
||||
);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
QSize GroupedLineEdit::minimumSizeHint() const
|
||||
{
|
||||
return sizeHint();
|
||||
}
|
||||
|
||||
void GroupedLineEdit::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
switch (e->key()) {
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
emit editingFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
QPlainTextEdit::keyPressEvent(e);
|
||||
}
|
||||
|
||||
void GroupedLineEdit::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
|
||||
QTextLine line = document()->findBlock(0).layout()->lineAt(0);
|
||||
QPainter painter(viewport());
|
||||
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
|
||||
|
||||
painter.fillRect(0, 0, viewport()->width(), viewport()->height(), palette().base());
|
||||
|
||||
QVectorIterator<QColor> i(d->colors);
|
||||
i.toFront();
|
||||
foreach (const Private::Block &block, d->blocks) {
|
||||
qreal start_x = line.cursorToX(block.start, QTextLine::Trailing);
|
||||
qreal end_x = line.cursorToX(block.end + 1, QTextLine::Leading);
|
||||
QPainterPath path;
|
||||
QRectF rectangle(
|
||||
start_x - 1.0 - double(horizontalScrollBar()->value()),
|
||||
1.0,
|
||||
end_x - start_x + 2.0,
|
||||
double(viewport()->height() - 2)
|
||||
);
|
||||
if (! i.hasNext())
|
||||
i.toFront();
|
||||
path.addRoundedRect(rectangle, 5.0, 5.0);
|
||||
painter.setPen(i.peekNext());
|
||||
painter.setBrush(i.next().lighter(180));
|
||||
painter.drawPath(path);
|
||||
}
|
||||
|
||||
QPlainTextEdit::paintEvent(e);
|
||||
}
|
66
qt-ui/groupedlineedit.h
Normal file
66
qt-ui/groupedlineedit.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* Original License:
|
||||
*
|
||||
* This file is part of the Nepomuk widgets collection
|
||||
* Copyright (c) 2013 Denis Steckelmacher <steckdenis@yahoo.fr>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License version 2.1 as published by the Free Software Foundation,
|
||||
* or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public License
|
||||
* along with this library; see the file COPYING.LIB. If not, write to
|
||||
*
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GROUPEDLINEEDIT_H__
|
||||
#define __GROUPEDLINEEDIT_H__
|
||||
|
||||
#include <QtGui/QPlainTextEdit>
|
||||
#include <QStringList>
|
||||
|
||||
class GroupedLineEdit : public QPlainTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GroupedLineEdit(QWidget *parent = 0);
|
||||
virtual ~GroupedLineEdit();
|
||||
|
||||
QString text() const;
|
||||
|
||||
int cursorPosition() const;
|
||||
void setCursorPosition(int position);
|
||||
void setText(const QString &text);
|
||||
void clear();
|
||||
void selectAll();
|
||||
|
||||
void removeAllBlocks();
|
||||
void addBlock(int start, int end);
|
||||
QStringList getBlockStringList();
|
||||
|
||||
void addColor(QColor color);
|
||||
void removeAllColors();
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
virtual QSize minimumSizeHint() const;
|
||||
|
||||
signals:
|
||||
void editingFinished();
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *e);
|
||||
virtual void keyPressEvent(QKeyEvent *e);
|
||||
|
||||
private:
|
||||
struct Private;
|
||||
Private *d;
|
||||
};
|
||||
#endif
|
|
@ -58,6 +58,7 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent),
|
|||
ui.airtemp->installEventFilter(this);
|
||||
ui.watertemp->installEventFilter(this);
|
||||
ui.dateTimeEdit->installEventFilter(this);
|
||||
ui.tagWidget->installEventFilter(this);
|
||||
|
||||
QList<QObject *> statisticsTabWidgets = ui.statisticsTab->children();
|
||||
Q_FOREACH(QObject* obj, statisticsTabWidgets) {
|
||||
|
@ -87,10 +88,12 @@ MainTab::MainTab(QWidget *parent) : QTabWidget(parent),
|
|||
completers.divemaster = new QCompleter(DiveMasterCompletionModel::instance(), ui.divemaster);
|
||||
completers.location = new QCompleter(LocationCompletionModel::instance(), ui.location);
|
||||
completers.suit = new QCompleter(SuitCompletionModel::instance(), ui.suit);
|
||||
completers.tags = new QCompleter(TagCompletionModel::instance(), ui.tagWidget);
|
||||
ui.buddy->setCompleter(completers.buddy);
|
||||
ui.divemaster->setCompleter(completers.divemaster);
|
||||
ui.location->setCompleter(completers.location);
|
||||
ui.suit->setCompleter(completers.suit);
|
||||
ui.tagWidget->setCompleter(completers.tags);
|
||||
|
||||
setMinimumHeight(0);
|
||||
setMinimumWidth(0);
|
||||
|
@ -161,6 +164,9 @@ void MainTab::enableEdition(EditMode newEditMode)
|
|||
notesBackup[mydive].airtemp = get_temperature_string(mydive->airtemp, true);
|
||||
notesBackup[mydive].watertemp = get_temperature_string(mydive->watertemp, true);
|
||||
notesBackup[mydive].datetime = QDateTime::fromTime_t(mydive->when - gettimezoneoffset()).toString(QString("M/d/yy h:mm"));
|
||||
char buf[1024];
|
||||
taglist_get_tagstring(mydive->tag_list, buf, 1024);
|
||||
notesBackup[mydive].tags = QString(buf);
|
||||
|
||||
// maybe this is a place for memset?
|
||||
for (int i = 0; i < MAX_CYLINDERS; i++) {
|
||||
|
@ -182,7 +188,9 @@ bool MainTab::eventFilter(QObject* object, QEvent* event)
|
|||
enableEdition();
|
||||
}
|
||||
|
||||
if (isEnabled() && event->type() == QEvent::FocusIn && (object == ui.rating || object == ui.visibility)) {
|
||||
if (isEnabled() && event->type() == QEvent::FocusIn && (object == ui.rating ||
|
||||
object == ui.visibility ||
|
||||
object == ui.tagWidget)) {
|
||||
tabBar()->setTabIcon(currentIndex(), QIcon(":warning"));
|
||||
enableEdition();
|
||||
}
|
||||
|
@ -215,6 +223,7 @@ void MainTab::clearInfo()
|
|||
ui.airTemperatureText->clear();
|
||||
ui.airPressureText->clear();
|
||||
ui.salinityText->clear();
|
||||
ui.tagWidget->clear();
|
||||
}
|
||||
|
||||
void MainTab::clearStats()
|
||||
|
@ -356,6 +365,11 @@ void MainTab::updateDiveInfo(int dive)
|
|||
ui.timeLimits->setMaximum(get_time_string(stats_selection.longest_time.seconds, 0));
|
||||
ui.timeLimits->setMinimum(get_time_string(stats_selection.shortest_time.seconds, 0));
|
||||
|
||||
|
||||
char buf[1024];
|
||||
taglist_get_tagstring(d->tag_list, buf, 1024);
|
||||
ui.tagWidget->setText(QString(buf));
|
||||
|
||||
multiEditEquipmentPlaceholder = *d;
|
||||
cylindersModel->setDive(&multiEditEquipmentPlaceholder);
|
||||
weightModel->setDive(&multiEditEquipmentPlaceholder);
|
||||
|
@ -393,6 +407,7 @@ void MainTab::reload()
|
|||
BuddyCompletionModel::instance()->updateModel();
|
||||
LocationCompletionModel::instance()->updateModel();
|
||||
DiveMasterCompletionModel::instance()->updateModel();
|
||||
TagCompletionModel::instance()->updateModel();
|
||||
}
|
||||
|
||||
void MainTab::acceptChanges()
|
||||
|
@ -423,7 +438,8 @@ void MainTab::acceptChanges()
|
|||
notesBackup[curr].airtemp != ui.airtemp->text() ||
|
||||
notesBackup[curr].watertemp != ui.watertemp->text() ||
|
||||
notesBackup[curr].datetime != ui.dateTimeEdit->dateTime().toString(QString("M/d/yy h:mm")) ||
|
||||
notesBackup[curr].visibility != ui.rating->currentStars()) {
|
||||
notesBackup[curr].visibility != ui.rating->currentStars() ||
|
||||
notesBackup[curr].tags != ui.tagWidget->text()) {
|
||||
mark_divelist_changed(TRUE);
|
||||
}
|
||||
if (notesBackup[curr].location != ui.location->text() ||
|
||||
|
@ -431,6 +447,9 @@ void MainTab::acceptChanges()
|
|||
mainWindow()->globe()->reload();
|
||||
}
|
||||
|
||||
if (notesBackup[curr].tags != ui.tagWidget->text())
|
||||
saveTags();
|
||||
|
||||
if (cylindersModel->changed) {
|
||||
mark_divelist_changed(TRUE);
|
||||
Q_FOREACH (dive *d, notesBackup.keys()) {
|
||||
|
@ -480,6 +499,7 @@ void MainTab::resetPallete()
|
|||
ui.airtemp->setPalette(p);
|
||||
ui.watertemp->setPalette(p);
|
||||
ui.dateTimeEdit->setPalette(p);
|
||||
ui.tagWidget->setPalette(p);
|
||||
}
|
||||
|
||||
#define EDIT_TEXT2(what, text) \
|
||||
|
@ -522,6 +542,7 @@ void MainTab::rejectChanges()
|
|||
ui.airtemp->setText(notesBackup[curr].airtemp);
|
||||
ui.watertemp->setText(notesBackup[curr].watertemp);
|
||||
ui.dateTimeEdit->setDateTime(QDateTime::fromString(notesBackup[curr].datetime, QString("M/d/y h:mm")));
|
||||
ui.tagWidget->setText(notesBackup[curr].tags);
|
||||
|
||||
struct dive *mydive;
|
||||
for (int i = 0; i < dive_table.nr; i++) {
|
||||
|
@ -628,6 +649,21 @@ void MainTab::on_dateTimeEdit_dateTimeChanged(const QDateTime& datetime)
|
|||
markChangedWidget(ui.dateTimeEdit);
|
||||
}
|
||||
|
||||
void MainTab::saveTags()
|
||||
{
|
||||
EDIT_SELECTED_DIVES(
|
||||
QString tag;
|
||||
taglist_clear(mydive->tag_list);
|
||||
foreach (tag, ui.tagWidget->getBlockStringList())
|
||||
taglist_add_tag(mydive->tag_list, tag.toAscii().data());
|
||||
);
|
||||
}
|
||||
|
||||
void MainTab::on_tagWidget_textChanged()
|
||||
{
|
||||
markChangedWidget(ui.tagWidget);
|
||||
}
|
||||
|
||||
void MainTab::on_location_textChanged(const QString& text)
|
||||
{
|
||||
if (editMode == NONE)
|
||||
|
|
|
@ -31,6 +31,7 @@ struct NotesBackup{
|
|||
int rating;
|
||||
int visibility;
|
||||
QString divemaster;
|
||||
QString tags;
|
||||
cylinder_t cylinders[MAX_CYLINDERS];
|
||||
weightsystem_t weightsystem[MAX_WEIGHTSYSTEMS ];
|
||||
};
|
||||
|
@ -40,6 +41,7 @@ struct Completers{
|
|||
QCompleter *divemaster;
|
||||
QCompleter *buddy;
|
||||
QCompleter *suit;
|
||||
QCompleter *tags;
|
||||
};
|
||||
|
||||
class MainTab : public QTabWidget
|
||||
|
@ -73,6 +75,7 @@ public slots:
|
|||
void on_dateTimeEdit_dateTimeChanged(const QDateTime& datetime);
|
||||
void on_rating_valueChanged(int value);
|
||||
void on_visibility_valueChanged(int value);
|
||||
void on_tagWidget_textChanged();
|
||||
void editCylinderWidget(const QModelIndex& index);
|
||||
void editWeightWidget(const QModelIndex& index);
|
||||
void addDiveStarted();
|
||||
|
@ -94,6 +97,7 @@ private:
|
|||
|
||||
Completers completers;
|
||||
void resetPallete();
|
||||
void saveTags();
|
||||
QString printGPSCoords(int lat, int lon);
|
||||
};
|
||||
|
||||
|
|
127
qt-ui/maintab.ui
127
qt-ui/maintab.ui
|
@ -37,8 +37,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>513</width>
|
||||
<height>468</height>
|
||||
<width>501</width>
|
||||
<height>535</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
|
@ -102,6 +102,13 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="location">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="LocationLabel">
|
||||
<property name="text">
|
||||
|
@ -109,8 +116,22 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="location">
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="TagLabel">
|
||||
<property name="text">
|
||||
<string>Tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="coordinates">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLineEdit" name="divemaster">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
|
@ -123,8 +144,15 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="coordinates">
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="BuddyLabel">
|
||||
<property name="text">
|
||||
<string>Buddy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QLineEdit" name="buddy">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
|
@ -137,22 +165,8 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="BuddyLabel">
|
||||
<property name="text">
|
||||
<string>Buddy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLineEdit" name="divemaster">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QLineEdit" name="buddy">
|
||||
<item row="10" column="1">
|
||||
<widget class="QLineEdit" name="suit">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
|
@ -176,6 +190,13 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="14" column="0" colspan="2">
|
||||
<widget class="QTextEdit" name="notes">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QLabel" name="SuitLabel">
|
||||
<property name="text">
|
||||
|
@ -193,34 +214,45 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QLineEdit" name="suit">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="NotesLabel">
|
||||
<property name="text">
|
||||
<string>Notes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0" colspan="2">
|
||||
<widget class="QTextEdit" name="notes">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0" colspan="2">
|
||||
<item row="15" column="0" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="notesButtonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0" colspan="2">
|
||||
<widget class="TagWidget" name="tagWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="lineWrapMode">
|
||||
<enum>QPlainTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
|
@ -248,8 +280,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>513</width>
|
||||
<height>468</height>
|
||||
<width>515</width>
|
||||
<height>473</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
|
@ -335,8 +367,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>513</width>
|
||||
<height>468</height>
|
||||
<width>515</width>
|
||||
<height>473</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
|
@ -584,7 +616,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QGroupBox">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Salinity</string>
|
||||
</property>
|
||||
|
@ -642,8 +674,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>513</width>
|
||||
<height>468</height>
|
||||
<width>515</width>
|
||||
<height>473</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
|
@ -802,6 +834,11 @@
|
|||
<header>tableview.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>TagWidget</class>
|
||||
<extends>QPlainTextEdit</extends>
|
||||
<header>qt-ui/tagwidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
|
135
qt-ui/tagwidget.cpp
Normal file
135
qt-ui/tagwidget.cpp
Normal file
|
@ -0,0 +1,135 @@
|
|||
#include "tagwidget.h"
|
||||
#include <QPair>
|
||||
#include <QDebug>
|
||||
|
||||
TagWidget::TagWidget(QWidget *parent) : GroupedLineEdit(parent), m_completer(NULL)
|
||||
{
|
||||
connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(reparse()));
|
||||
|
||||
addColor(QColor(0x00, 0xAE, 0xFF));
|
||||
addColor(QColor(0x00, 0x78, 0xB0));
|
||||
}
|
||||
|
||||
void TagWidget::setCompleter(QCompleter *completer)
|
||||
{
|
||||
m_completer = completer;
|
||||
m_completer->setWidget(this);
|
||||
connect(m_completer, SIGNAL(activated(QString)), this, SLOT(completionSelected(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 QPair<int,int>(start,end);
|
||||
}
|
||||
|
||||
enum ParseState {FINDSTART, FINDEND};
|
||||
|
||||
void TagWidget::highlight() {
|
||||
int i = 0, start = 0, end = 0;
|
||||
ParseState state = FINDEND;
|
||||
removeAllBlocks();
|
||||
|
||||
while(i < text().length()) {
|
||||
if (text().at(i) == ',') {
|
||||
if (state == FINDSTART) {
|
||||
/* Detect empty tags */
|
||||
} else if (state == FINDEND) {
|
||||
/* Found end of tag */
|
||||
if (i > 1) {
|
||||
if(text().at(i-1) != '\\') {
|
||||
addBlock(start, end);
|
||||
state = FINDSTART;
|
||||
}
|
||||
} else {
|
||||
state = FINDSTART;
|
||||
}
|
||||
}
|
||||
} else if (text().at(i) == ' ') {
|
||||
/* Handled */
|
||||
} else {
|
||||
/* Found start of tag */
|
||||
if (state == FINDSTART) {
|
||||
state = FINDEND;
|
||||
start = i;
|
||||
} else if (state == FINDEND) {
|
||||
end = i;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (state == FINDEND) {
|
||||
if (end < start)
|
||||
end = text().length()-1;
|
||||
if (text().length() > 0)
|
||||
addBlock(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
else
|
||||
currentText = "";
|
||||
if (m_completer) {
|
||||
m_completer->setCompletionPrefix(currentText);
|
||||
m_completer->complete();
|
||||
}
|
||||
}
|
||||
|
||||
void TagWidget::completionSelected(QString completion) {
|
||||
QPair <int,int> pos;
|
||||
pos = getCursorTagPosition();
|
||||
if (pos.first >= 0 && pos.second > 0) {
|
||||
setText(text().remove(pos.first, pos.second-pos.first).insert(pos.first, completion));
|
||||
setCursorPosition(pos.first+completion.length());
|
||||
}
|
||||
else {
|
||||
setText(completion.append(", "));
|
||||
setCursorPosition(text().length());
|
||||
}
|
||||
}
|
||||
|
||||
void TagWidget::setCursorPosition(int position) {
|
||||
blockSignals(true);
|
||||
GroupedLineEdit::setCursorPosition(position);
|
||||
blockSignals(false);
|
||||
}
|
||||
|
||||
void TagWidget::setText(QString text) {
|
||||
blockSignals(true);
|
||||
GroupedLineEdit::setText(text);
|
||||
blockSignals(false);
|
||||
highlight();
|
||||
}
|
||||
|
||||
void TagWidget::clear() {
|
||||
blockSignals(true);
|
||||
GroupedLineEdit::clear();
|
||||
blockSignals(false);
|
||||
}
|
26
qt-ui/tagwidget.h
Normal file
26
qt-ui/tagwidget.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef __TAGWIDGET_H
|
||||
#define __TAGWIDGET_H
|
||||
|
||||
#include "groupedlineedit.h"
|
||||
#include <QCompleter>
|
||||
#include <QPair>
|
||||
|
||||
class TagWidget : public GroupedLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TagWidget(QWidget *parent = 0);
|
||||
void setCompleter(QCompleter *completer);
|
||||
QPair<int, int> getCursorTagPosition();
|
||||
void highlight();
|
||||
void setText(QString text);
|
||||
void clear();
|
||||
void setCursorPosition(int position);
|
||||
public slots:
|
||||
void reparse();
|
||||
void completionSelected(QString);
|
||||
private:
|
||||
QCompleter *m_completer;
|
||||
};
|
||||
|
||||
#endif /* __TAGWIDGET_H */
|
|
@ -56,7 +56,9 @@ HEADERS = \
|
|||
subsurfacestartup.h \
|
||||
uemis.h \
|
||||
webservice.h \
|
||||
qt-ui/csvimportdialog.h
|
||||
qt-ui/csvimportdialog.h \
|
||||
qt-ui/tagwidget.h \
|
||||
qt-ui/groupedlineedit.h
|
||||
|
||||
SOURCES = \
|
||||
deco.c \
|
||||
|
@ -103,7 +105,9 @@ SOURCES = \
|
|||
time.c \
|
||||
uemis.c \
|
||||
uemis-downloader.c \
|
||||
qt-ui/csvimportdialog.cpp
|
||||
qt-ui/csvimportdialog.cpp \
|
||||
qt-ui/tagwidget.cpp \
|
||||
qt-ui/groupedlineedit.cpp
|
||||
|
||||
linux*: SOURCES += linux.c
|
||||
mac: SOURCES += macos.c
|
||||
|
@ -121,7 +125,7 @@ FORMS = \
|
|||
qt-ui/renumber.ui \
|
||||
qt-ui/webservices.ui \
|
||||
qt-ui/tableview.ui \
|
||||
qt-ui/csvimportdialog.ui
|
||||
qt-ui/csvimportdialog.ui
|
||||
|
||||
RESOURCES = subsurface.qrc
|
||||
|
||||
|
|
Loading…
Reference in a new issue