Utility functions to sort text messages by timestamp (ascending/descending)

* compare function for text message
* resort function
* text message edit can display HTML text messages with ascending/descending timestamp
* made CTextMessageListModel -> CListModelTimestampObject
This commit is contained in:
Klaus Basan
2019-09-02 22:58:58 +02:00
committed by Mat Sutcliffe
parent 25eb13a83f
commit e12dc3a73a
16 changed files with 113 additions and 31 deletions

View File

@@ -502,6 +502,13 @@ namespace BlackGui
this->sort(this->getSortColumn(), this->getSortOrder());
}
template<typename T, bool UseCompare>
void CListModelBase<T, UseCompare>::resort()
{
// sort the values
this->updateContainerMaybeAsync(m_container, true);
}
template <typename T, bool UseCompare>
void CListModelBase<T, UseCompare>::sort(int column, Qt::SortOrder order)
{

View File

@@ -107,6 +107,10 @@ namespace BlackGui
//! Sort by given sort order \sa getSortColumn() \sa getSortOrder()
void sort();
//! Sort by given sort order \sa getSortColumn() \sa getSortOrder()
//! \remark always sorts, even if columns did no change
void resort();
//! Truncate to given number
void truncate(int maxNumber, bool forceSort = false);

View File

@@ -16,7 +16,7 @@ namespace BlackGui
// https://isocpp.org/wiki/faq/templates#separate-template-fn-defn-from-decl
template class CListModelBase<BlackMisc::Network::CServerList, true>;
template class CListModelBase<BlackMisc::Network::CUserList, true>;
template class CListModelBase<BlackMisc::Network::CTextMessageList, false>;
template class CListModelBase<BlackMisc::Network::CTextMessageList, true>;
template class CListModelBase<BlackMisc::Network::CClientList, false>;
} // namespace

View File

@@ -19,11 +19,18 @@ namespace BlackGui
{
namespace Models
{
template <typename T, bool UseCompare>
template<typename T, bool UseCompare>
CListModelTimestampObjects<T, UseCompare>::CListModelTimestampObjects(const QString &translationContext, QObject *parent) :
CListModelBase<ContainerType, UseCompare>(translationContext, parent)
{ }
template<typename T, bool UseCompare>
bool CListModelTimestampObjects<T, UseCompare>::isSortedByTimestampProperty() const
{
const CPropertyIndex pi = this->getSortProperty();
return ITimestampBased::canHandleIndex(pi);
}
template<typename T, bool UseCompare>
void CListModelTimestampObjects<T, UseCompare>::addTimestampColumns()
{
@@ -32,6 +39,7 @@ namespace BlackGui
}
template class CListModelTimestampObjects<BlackMisc::CStatusMessageList, true>;
template class CListModelTimestampObjects<BlackMisc::Network::CTextMessageList, true>;
template class CListModelTimestampObjects<BlackMisc::Aviation::CAircraftPartsList, true>;
template class CListModelTimestampObjects<BlackMisc::Aviation::CAircraftSituationList, true>;
template class CListModelTimestampObjects<BlackMisc::Aviation::CAircraftSituationChangeList, true>;

View File

@@ -35,6 +35,9 @@ namespace BlackGui
//! Container element type
using ObjectType = typename T::value_type;
//! Sorted by one of the timestamp columns?
bool isSortedByTimestampProperty() const;
protected:
//! Constructor
CListModelTimestampObjects(const QString &translationContext, QObject *parent = nullptr);

View File

@@ -27,7 +27,7 @@ namespace BlackGui
namespace Models
{
CTextMessageListModel::CTextMessageListModel(TextMessageMode mode, QObject *parent) :
CListModelBase("ModelTextMessageList", parent), m_textMessageMode(NotSet)
CListModelTimestampObjects("ModelTextMessageList", parent), m_textMessageMode(NotSet)
{
this->setTextMessageMode(mode);

View File

@@ -11,8 +11,8 @@
#ifndef BLACKGUI_MODELS_TEXTMESSAGELISTMODEL_H
#define BLACKGUI_MODELS_TEXTMESSAGELISTMODEL_H
#include "blackgui/models/listmodeltimestampobjects.h"
#include "blackgui/blackguiexport.h"
#include "blackgui/models/listmodelbase.h"
#include "blackmisc/network/textmessagelist.h"
class QObject;
@@ -23,7 +23,8 @@ namespace BlackGui
namespace Models
{
//! Text message list model
class BLACKGUI_EXPORT CTextMessageListModel : public CListModelBase<BlackMisc::Network::CTextMessageList>
class BLACKGUI_EXPORT CTextMessageListModel :
public CListModelTimestampObjects<BlackMisc::Network::CTextMessageList, true>
{
Q_OBJECT
@@ -40,7 +41,7 @@ namespace BlackGui
explicit CTextMessageListModel(TextMessageMode stationMode, QObject *parent = nullptr);
//! Destructor
virtual ~CTextMessageListModel() {}
virtual ~CTextMessageListModel() override {}
//! Set mode
void setTextMessageMode(TextMessageMode mode);
@@ -56,4 +57,5 @@ namespace BlackGui
};
} // ns
} // ns
#endif // guard

View File

@@ -45,12 +45,12 @@ namespace BlackGui
m_actionWordWrap->setCheckable(true);
connect(m_actionClearTextEdit, &QAction::triggered, this, &CTextMessageTextEdit::clear);
connect(m_actionAll, &QAction::triggered, this, &CTextMessageTextEdit::keepLastNMessages);
connect(m_actionLast10, &QAction::triggered, this, &CTextMessageTextEdit::keepLastNMessages);
connect(m_actionLast25, &QAction::triggered, this, &CTextMessageTextEdit::keepLastNMessages);
connect(m_actionWithSender, &QAction::triggered, this, &CTextMessageTextEdit::setVisibleFields);
connect(m_actionAll, &QAction::triggered, this, &CTextMessageTextEdit::keepLastNMessages);
connect(m_actionLast10, &QAction::triggered, this, &CTextMessageTextEdit::keepLastNMessages);
connect(m_actionLast25, &QAction::triggered, this, &CTextMessageTextEdit::keepLastNMessages);
connect(m_actionWithSender, &QAction::triggered, this, &CTextMessageTextEdit::setVisibleFields);
connect(m_actionWithRecipient, &QAction::triggered, this, &CTextMessageTextEdit::setVisibleFields);
connect(m_actionWordWrap, &QAction::triggered, this, &CTextMessageTextEdit::setWordWrap);
connect(m_actionWordWrap, &QAction::triggered, this, &CTextMessageTextEdit::setWordWrap);
connect(this, &QTextEdit::customContextMenuRequested, this, &CTextMessageTextEdit::showContextMenuForTextEdit);
}
@@ -63,14 +63,13 @@ namespace BlackGui
if (maxMessages < 0 && m_keepMaxMessages >= 0) { maxMessages = m_keepMaxMessages; }
if (maxMessages >= 0)
{
m_messages.push_frontMaxElements(textMessage, maxMessages);
m_messages.push_backMaxElements(textMessage, maxMessages);
}
else
{
m_messages.push_front(textMessage);
m_messages.push_back(textMessage);
}
const QString html(toHtml(m_messages, m_withSender, m_withRecipient));
m_textDocument.setHtml(html);
this->redrawHtml();
}
int CTextMessageTextEdit::count() const
@@ -86,8 +85,14 @@ namespace BlackGui
void CTextMessageTextEdit::redrawHtml()
{
const QString html(toHtml(m_messages, m_withSender, m_withRecipient));
const QString html(
this->toHtml(
m_latestFirst ? m_messages.reversed() : m_messages,
m_withSender,
m_withRecipient)
);
m_textDocument.setHtml(html);
this->moveCursor(m_latestFirst ? QTextCursor::Start : QTextCursor::End);
}
void CTextMessageTextEdit::setStyleSheetForContent(const QString &styleSheet)

View File

@@ -35,7 +35,7 @@ namespace BlackGui
CTextMessageTextEdit(QWidget *parent = nullptr);
//! Destructor
virtual ~CTextMessageTextEdit();
virtual ~CTextMessageTextEdit() override;
//! Insert a message
void insertTextMessage(const BlackMisc::Network::CTextMessage &textMessage, int maxMessages = -1);
@@ -55,6 +55,12 @@ namespace BlackGui
//! Redraw HTML
void redrawHtml();
//! Order latest first/latest last
void setLatestFirst(bool latestFirst) { m_latestFirst = latestFirst; }
//! Lastest first
bool isLatestFirst() const { return m_latestFirst; }
private:
//! Context menu
void showContextMenuForTextEdit(const QPoint &pt);
@@ -77,9 +83,10 @@ namespace BlackGui
BlackMisc::Network::CTextMessageList m_messages;
QTextDocument m_textDocument;
int m_keepMaxMessages = -1; //!< max number of messages to keep, or -1 to keep all messages
bool m_withSender = true;
bool m_latestFirst = false;
bool m_withSender = true;
bool m_withRecipient = false;
bool m_wordWrap = true;
bool m_wordWrap = true;
QAction *m_actionClearTextEdit = nullptr;
QAction *m_actionLast10 = nullptr;

View File

@@ -21,15 +21,19 @@ namespace BlackGui
CTextMessageView::CTextMessageView(QWidget *parent) : CViewBase(parent)
{
this->standardInit(new CTextMessageListModel(CTextMessageListModel::FromTo, this));
this->m_menus |= MenuClear;
m_menus |= MenuClear;
}
void CTextMessageView::setTextMessageMode(CTextMessageListModel::TextMessageMode mode)
{
Q_ASSERT(this->m_model);
this->m_model->setTextMessageMode(mode);
Q_ASSERT(m_model);
m_model->setTextMessageMode(mode);
this->setSortIndicator();
}
}
bool CTextMessageView::isSortedByTimestampProperty() const
{
return m_model->isSortedByTimestampProperty();
}
} // namespace
} // namespace

View File

@@ -32,7 +32,11 @@ namespace BlackGui
//! Set display mode
void setTextMessageMode(BlackGui::Models::CTextMessageListModel::TextMessageMode mode);
//! Sorted by a timestamp property
bool isSortedByTimestampProperty() const;
};
}
}
} // namespace
} // namespace
#endif // guard

View File

@@ -107,8 +107,8 @@ namespace BlackGui
Q_UNUSED(sort);
ModelClass *model = this->derivedModel();
auto sortColumn = model->getSortColumn();
auto sortOrder = model->getSortOrder();
const auto sortColumn = model->getSortColumn();
const auto sortOrder = model->getSortOrder();
this->showLoadIndicator(container.size());
CWorker *worker = CWorker::fromTask(this, "ViewSort", [model, container, sortColumn, sortOrder]()
{
@@ -300,7 +300,7 @@ namespace BlackGui
if (!hasSelection()) { return 0; }
int c = 0;
int lastUpdatedRow = -1;
int lastUpdatedRow = -1;
int firstUpdatedRow = -1;
const CPropertyIndexList propertyIndexes(vm.indexes());
const QModelIndexList indexes = this->selectedRows();
@@ -503,6 +503,18 @@ namespace BlackGui
m_model->sortByPropertyIndex(propertyIndex, order);
}
template<class T>
void CViewBase<T>::sort()
{
m_model->sort();
}
template<class T>
void CViewBase<T>::resort()
{
m_model->resort();
}
template <class T>
QJsonObject CViewBase<T>::toJson(bool selectedOnly) const
{

View File

@@ -750,6 +750,12 @@ namespace BlackGui
virtual Qt::SortOrder getSortOrder() const override { return m_model->getSortOrder(); }
//! @}
//! Sort if columns or order changed
void sort();
//! Resort ("forced sorting")
void resort();
//! Column count
int columnCount() const;

View File

@@ -277,7 +277,7 @@ namespace BlackMisc
const ColumnIndex i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexSenderCallsign: return m_senderCallsign.propertyByIndex(index.copyFrontRemoved());
case IndexSenderCallsign: return m_senderCallsign.propertyByIndex(index.copyFrontRemoved());
case IndexRecipientCallsign: return m_recipientCallsign.propertyByIndex(index.copyFrontRemoved());
case IndexRecipientCallsignOrFrequency: return CVariant::fromValue(this->getRecipientCallsignOrFrequency());
case IndexMessage: return CVariant::fromValue(m_message);
@@ -293,11 +293,28 @@ namespace BlackMisc
const ColumnIndex i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexSenderCallsign: m_senderCallsign.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
case IndexSenderCallsign: m_senderCallsign.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
case IndexRecipientCallsign: m_recipientCallsign.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
case IndexMessage: m_message = variant.value<QString>(); break;
default: CValueObject::setPropertyByIndex(index, variant); break;
}
}
int CTextMessage::comparePropertyByIndex(const CPropertyIndex &index, const CTextMessage &compareValue) const
{
if (ITimestampBased::canHandleIndex(index)) { return ITimestampBased::comparePropertyByIndex(index, compareValue); }
const ColumnIndex i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexSenderCallsign: return m_senderCallsign.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getSenderCallsign());
case IndexRecipientCallsign: return m_recipientCallsign.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getRecipientCallsign());
case IndexRecipientCallsignOrFrequency:
if (this->isRadioMessage()) { return this->getFrequency().compare(compareValue.getFrequency()); }
return m_recipientCallsign.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getRecipientCallsign());
default: return CValueObject::comparePropertyByIndex(index, *this);
}
Q_ASSERT_X(false, Q_FUNC_INFO, "No comparison");
return 0;
}
} // namespace
} // namespace

View File

@@ -180,6 +180,9 @@ namespace BlackMisc
//! \copydoc BlackMisc::Mixin::Index::setPropertyByIndex
void setPropertyByIndex(const BlackMisc::CPropertyIndex &index, const CVariant &variant);
//! \copydoc BlackMisc::Mixin::Index::comparePropertyByIndex
int comparePropertyByIndex(const CPropertyIndex &index, const CTextMessage &compareValue) const;
//! \copydoc BlackMisc::Mixin::String::toQString
QString convertToQString(bool i18n = false) const;

View File

@@ -138,10 +138,10 @@ namespace BlackMisc
//! Any of the timestamp indexes
static bool isAnyTimestampIndex(int index);
protected:
//! Can given index be handled
static bool canHandleIndex(const CPropertyIndex &index);
protected:
//! Constructor
ITimestampBased();