LogTableModel.h
Go to the documentation of this file.
1/*
2* This file is part of ArmarX.
3*
4* ArmarX is free software; you can redistribute it and/or modify
5* it under the terms of the GNU General Public License version 2 as
6* published by the Free Software Foundation.
7*
8* ArmarX is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16* @package ArmarX::
17* @author Mirko Waechter ( mirko.waechter at kit dot edu)
18* @date 2012
19* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20* GNU General Public License
21*/
22
23#pragma once
24
25#include <QAbstractTableModel>
26#include <QColor>
27#include <QString>
28
29// ArmarX
32#include <ArmarXCore/interface/core/Log.h>
33
34#include "LogMarkerRegistry.h"
35#include "LogStore.h"
36
37// C++
38#include <mutex>
39#include <vector>
40
41namespace armarx
42{
43 // Identifies a filterable log column. The integer values match the model's column
44 // indices (see data() / headerData()).
45 enum class LogColumn : int
46 {
47 Time = 0,
49 Tag = 2,
52 File = 5,
54 Group = 7,
56 };
57
58 // How a filter value is compared against a column: as a substring (for manual,
59 // user-typed filters) or as a whole-value match (for auto-generated per-component /
60 // per-group filters, which must isolate exactly one component/group).
61 enum class MatchMode
62 {
65 };
66
67 // A single active filter criterion: which column, the value to match against, and how.
68 // The QString / int forms of the value are derived once when the filter is created,
69 // because applyFilter() runs per message per filter and used to rebuild them on every
70 // single call.
71 struct LogFilter
72 {
74 std::string value;
75 QString qValue; //!< value as QString, for substring (Contains) matching
76 int intValue = 0; //!< value as int, for the verbosity / file-line comparisons
78 };
79
80 /*!
81 * \brief A filtered view onto the shared LogStore.
82 *
83 * The model does not own any log message. It keeps a vector of LogSeq -- one per
84 * displayed row -- into the store owned by the LogViewer, plus the little per-filter
85 * state that genuinely differs between filters (search match, pin color, and whether
86 * the row is an injected pin rather than a row this filter accepted).
87 *
88 * A model is *materialised* only while its table is visible. A hidden filter keeps
89 * counting the messages it accepts (for the new-message badge) but builds no rows at
90 * all, which is what keeps ingestion independent of how many filters exist. Rows are
91 * rebuilt from the store when the table is shown again.
92 */
93 class LogTableModel : public QAbstractTableModel
94 {
95 Q_OBJECT
96 public:
97 enum class UserRoles : int
98 {
99 FullMsgRole = Qt::UserRole + 1
100 };
101
102 explicit LogTableModel(QObject* parent = 0);
103 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
104 int columnCount(const QModelIndex& parent = QModelIndex()) const override;
105 QVariant data(const QModelIndex& index, int role) const override;
106 QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
107 bool setData(const QModelIndex& index, const QVariant& value, int role) override;
108 Qt::ItemFlags flags(const QModelIndex& index) const override;
109
110 //! Attach the shared backing store. Must be called before any ingestion.
111 void setStore(const LogStore* store);
112
113 void addFilter(const std::string& columnName,
114 const std::string& filter,
116 void reapplyAllFilters();
117 void resetFilters();
118 bool rowContainsString(int row, const QString& searchStr) const;
119 bool msgContainsString(const LogMessage& logMsg, QString searchStr) const;
120
121 void search(const QString& searchStr);
122
123 QString
125 {
126 return activeSearchStr;
127 }
128
129 MessageType
131 {
132 return maxNewLogLevelType;
133 }
134
135 int getColumn(const std::string& columnName) const;
136 int clearData();
137
138 //! Upper bound on displayed rows. 0 disables the bound. The store keeps more
139 //! history than this so that a quiet filter can still fill its window; this bounds
140 //! what any single table has to lay out and paint.
141 void setMaxEntries(std::size_t maxEntries);
142
143 const std::vector<LogFilter>&
145 {
146 return activeFilters;
147 }
148
149 //! Append those of \p seqs that pass this model's filters, in one insertion. The
150 //! messages themselves are read from the shared store. Returns how many were
151 //! accepted -- which is counted even while the model is not materialised, so the
152 //! new-message badge of a hidden filter stays correct. \p batchMaxLevelOut, if
153 //! given, receives the highest severity among the accepted messages.
154 int addEntries(const std::vector<LogSeq>& seqs, MessageType* batchMaxLevelOut = nullptr);
155
156 //! Build rows (materialised) or drop them and only keep counting (not).
157 void setMaterialised(bool materialised);
158
159 bool
161 {
162 return materialised;
163 }
164
165 //! Discard rows whose store entry has been dropped. Called after the store trims.
166 void dropRowsBefore(LogSeq firstSeq);
167
168 //! Store sequence number of the given display row, or 0 if the row is invalid.
169 LogSeq seqAt(int row) const;
170
171 //! Display row showing \p seq, or -1 if it is not shown.
172 int rowForSeq(LogSeq seq) const;
173
174 //! Number of display lines of the message column for the given row.
175 int lineCountAt(int row) const;
176
177 //! Attach the shared pin registry. The model then shows registry markers that are
178 //! not already present as rows of its own (injected, in time position), colors
179 //! pinned rows, and refreshes whenever the registry changes.
180 void setMarkerRegistry(LogMarkerRegistry* registry);
181
182 //! Whether the given display row is currently pinned (has a label color).
183 bool isRowMarked(int row) const;
184
185 //! The message shown in the given row. Only valid while the row exists.
186 const LogMessage& getLogEntry(size_t row) const;
187
188 public slots:
189 //! Rebuild the set of injected pin rows and re-color rows (full reset).
190 void refreshMarkers();
191
192 protected:
193 bool applyFilter(const LogFilter& filter, const LogMessage& logMsg);
194 bool applyFilters(const LogMessage& logMsg);
195 //! Trim the oldest rows once the display window is exceeded.
196 void enforceMaxEntries();
197
198 private:
199 //! One displayed row: a reference into the shared store plus the per-filter state.
200 struct Row
201 {
202 LogSeq seq = 0;
203 bool matchesSearch = false; //!< whether the entry matches the active search
204 bool injected = false; //!< true if this is an injected pin, not a match
205 QColor markerColor; //!< valid iff pinned; the pin's row background
206 };
207
208 //! Rebuild rows from the store, newest first up to maxEntries, honouring the
209 //! clear watermark. Caller must bracket this with begin/endResetModel.
210 void rebuildRowsFromStore();
211
212 //! Re-derive markerColor / injected rows from the registry. Caller must bracket
213 //! this with begin/endResetModel.
214 void applyMarkersLocked();
215
216 //! The store entry behind a row, or nullptr if it is no longer retained.
217 const StoredLogEntry* entryAt(int row) const;
218
219 QString activeSearchStr;
220 MessageType maxNewLogLevelType;
221 std::vector<LogFilter> activeFilters;
222
223 //! Display-window bound; 0 disables it.
224 std::size_t maxEntries = 10000;
225
226 const LogStore* store = nullptr;
227
228 //! Rows are only built while the table is visible. A freshly constructed table is
229 //! not visible yet, so it starts out dematerialised and LogTable::showEvent brings
230 //! it up.
231 bool materialised = false;
232
233 //! Sequence numbers below this were cleared from *this* filter ("Clear log") and
234 //! must not come back when the rows are rebuilt from the store.
235 LogSeq clearedBeforeSeq = 0;
236
237 std::vector<Row> rows;
238 mutable std::mutex rowsMutex;
239
240 //! Shared pin registry (non-owning); nullptr until setMarkerRegistry().
241 LogMarkerRegistry* markerRegistry = nullptr;
242
244 };
245} // namespace armarx
uint8_t index
Baseclass for all ArmarX ManagedIceObjects requiring properties.
Definition Component.h:94
Shared, session-only store of pinned ("labeled") log lines.
The single bounded buffer holding every log line the viewer retains.
Definition LogStore.h:63
void setMaterialised(bool materialised)
Build rows (materialised) or drop them and only keep counting (not).
MessageType getMaxNewLogLevelType()
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
void setMarkerRegistry(LogMarkerRegistry *registry)
Attach the shared pin registry.
bool isMaterialised() const
void dropRowsBefore(LogSeq firstSeq)
Discard rows whose store entry has been dropped. Called after the store trims.
void addFilter(const std::string &columnName, const std::string &filter, MatchMode mode=MatchMode::Contains)
bool applyFilters(const LogMessage &logMsg)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Qt::ItemFlags flags(const QModelIndex &index) const override
LogTableModel(QObject *parent=0)
bool isRowMarked(int row) const
Whether the given display row is currently pinned (has a label color).
bool setData(const QModelIndex &index, const QVariant &value, int role) override
bool applyFilter(const LogFilter &filter, const LogMessage &logMsg)
int lineCountAt(int row) const
Number of display lines of the message column for the given row.
void setMaxEntries(std::size_t maxEntries)
Upper bound on displayed rows.
int rowForSeq(LogSeq seq) const
Display row showing seq, or -1 if it is not shown.
int addEntries(const std::vector< LogSeq > &seqs, MessageType *batchMaxLevelOut=nullptr)
Append those of seqs that pass this model's filters, in one insertion.
const LogMessage & getLogEntry(size_t row) const
The message shown in the given row. Only valid while the row exists.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
LogSeq seqAt(int row) const
Store sequence number of the given display row, or 0 if the row is invalid.
void enforceMaxEntries()
Trim the oldest rows once the display window is exceeded.
int getColumn(const std::string &columnName) const
bool msgContainsString(const LogMessage &logMsg, QString searchStr) const
const std::vector< LogFilter > & getFilters() const
bool rowContainsString(int row, const QString &searchStr) const
void refreshMarkers()
Rebuild the set of injected pin rows and re-color rows (full reset).
void setStore(const LogStore *store)
Attach the shared backing store. Must be called before any ingestion.
void search(const QString &searchStr)
IceUtil::Handle< RunningTask< T > > pointer_type
Shared pointer type for convenience.
This file offers overloads of toIce() and fromIce() functions for STL container types.
quint64 LogSeq
Identifies a stored log entry for as long as it is retained.
Definition LogStore.h:37
bool Contains(const ContainerType &container, const ElementType &searchElement)
Definition algorithm.h:330
int intValue
value as int, for the verbosity / file-line comparisons
std::string value
QString qValue
value as QString, for substring (Contains) matching