LogTable.cpp
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 #include "LogTable.h"
23 
24 #include <filesystem>
25 
26 #include <QApplication>
27 #include <QHeaderView>
28 #include <QScrollBar>
29 #include <QTimer>
30 
31 #include "LogMessageDelegate.h"
32 #include "LogTableModel.h"
33 
34 namespace armarx
35 {
36 #define MAX_BUFFER_SIZE 10000
37 #define BUFFER_SIZE_FACTOR 1.3
38 
39  LogTable::LogTable(QWidget* parent) :
40  QTableView(parent), newMessageCount(0), maxNewLogLevelType(eUNDEFINED)
41  {
42  autoscrollActive = true;
44 
45  this->setVerticalScrollMode(ScrollMode::ScrollPerPixel);
46 
47  setObjectName(QString::fromUtf8("tableLog"));
48  QSizePolicy sizePolicy2(QSizePolicy::Expanding, QSizePolicy::Expanding);
49  sizePolicy2.setHorizontalStretch(10);
50  sizePolicy2.setVerticalStretch(10);
51  sizePolicy2.setHeightForWidth(sizePolicy().hasHeightForWidth());
52  setSizePolicy(sizePolicy2);
53  setSizeIncrement(QSize(1, 0));
54  setEditTriggers(QAbstractItemView::DoubleClicked); //QAbstractItemView::NoEditTriggers
55  setAlternatingRowColors(true);
56  setShowGrid(true);
57  setGridStyle(Qt::SolidLine);
58  setSortingEnabled(false);
59  setWordWrap(true);
60  setCornerButtonEnabled(true);
61 
62  setSelectionMode(QAbstractItemView::SingleSelection);
63  setSelectionBehavior(QAbstractItemView::SelectRows);
64 
65  horizontalHeader()->setVisible(true);
66  horizontalHeader()->setCascadingSectionResizes(true);
67  horizontalHeader()->setDefaultSectionSize(100);
68  horizontalHeader()->setMinimumSectionSize(20);
69  horizontalHeader()->setStretchLastSection(true);
70  verticalHeader()->setVisible(false);
71  verticalHeader()->setDefaultSectionSize(20);
72 
73  // verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
74 
75  setModel(new LogTableModel(this));
76  //connect(model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChanged(QModelIndex,QModelIndex)));
77  setColumnWidth(0, 90);
78  setColumnWidth(1, 90);
79  setColumnWidth(2, 90);
80  setColumnWidth(3, 60);
81  setColumnWidth(4, 700);
82  setColumnWidth(5, 150);
83  setColumnWidth(6, 200);
84  hideColumn(7);
85 
86  QFont font;
87  font.setPointSize(8);
88  setFont(font);
89 
90 
91  setItemDelegateForColumn(getModel()->getColumn(ARMARX_LOG_MESSAGESTR),
92  new LogMessageDelegate());
93 
94  QAbstractItemModel* absmodel = qobject_cast<QAbstractItemModel*>(model());
95  connect(absmodel,
96  SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)),
97  this,
98  SLOT(checkAutoScroll(QModelIndex, int, int)));
99  connect(
100  this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(doubleClickOnCell(QModelIndex)));
101  connect(absmodel,
102  SIGNAL(dataChanged(QModelIndex, QModelIndex)),
103  this,
104  SLOT(itemsAdded(QModelIndex, QModelIndex)));
105  connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(checkAutoScroll()));
106 
107  // connect(this, SIGNAL(scrollToEnd()), this, SLOT(scrollToBottom()));
108  }
109 
111  {
112  }
113 
114  QString
116  {
117  return currentLiveFilter;
118  }
119 
120  void
121  LogTable::liveFilterRow(const QString& filterStr, int row)
122  {
123  LogTableModel* logModel = getModel();
124  bool contains = logModel->rowContainsString(row, filterStr);
125  if (!isRowHidden(row) && !contains)
126  {
127  setRowHidden(row, true);
128  }
129  else if (isRowHidden(row) && contains)
130  {
131  setRowHidden(row, false);
132  }
133  }
134 
135  void
136  LogTable::liveFilter(const QString& filterStr, int startRow)
137  {
138  LogTableModel* logModel = getModel();
139  currentLiveFilter = filterStr;
140  if (filterStr.length() && filterStr.contains(lastLiveFilter))
141  {
142  // incremental filter - Only remove not fitting entries
143  int rowCount = model()->rowCount();
144 
145  for (int i = startRow; i < rowCount; i++)
146  {
147  if (!isRowHidden(i) && !logModel->rowContainsString(i, filterStr))
148  {
149  setRowHidden(i, true);
150  }
151  if (i % 1000 == 0)
152  {
153  qApp->processEvents();
154  }
155  if (filterStr != currentLiveFilter)
156  {
157  break; // filterstring already changed again -> cancel
158  }
159  }
160  }
161  else
162  {
163  // filter from scratch
164  // clear();
165  // setRowCount(0);
166  // QList<QTableWidgetItem*>results = findItems(filterStr,Qt::MatchContains);
167  // foreach(QTableWidgetItem*item, results)
168  // {
169  // if(applyFilters(item))
170  // item->
171  // }
172  int rowCount = model()->rowCount();
173 
174  for (int i = startRow; i < rowCount; i++)
175  {
176  if (isRowHidden(i))
177  {
178  if (logModel->rowContainsString(i, filterStr))
179  {
180  setRowHidden(i, false);
181  }
182  }
183  else if (!logModel->rowContainsString(i, filterStr))
184  {
185  setRowHidden(i, true);
186  }
187  if (i % 1000 == 0)
188  {
189  qApp->processEvents();
190  }
191  if (filterStr != currentLiveFilter)
192  {
193  break; // filterstring already changed again -> cancel
194  }
195  }
196 
197  // std::cout << "logBuffer: " << logBuffer.size() << std::endl;
198  // for(unsigned int i=0; i < logBuffer.size(); i++)
199  // {
200  // if(msgContainsString(logBuffer[i], filterStr) && applyFilters(logBuffer[i]) )
201  // addEntry(logBuffer[i], true);
202  // }
203  }
204 
205  lastLiveFilter = filterStr;
206  }
207 
208  bool
209  LogTable::liveSearch(const QString& search)
210  {
211  getModel()->search(search);
212  // scrollToBottom();
213  clearSelection();
214  return selectNextSearchResult(true, true);
215  }
216 
217  void
219  {
220  // ARMARX_WARNING_S << "LiveFilterReseted";
221  selectedSearchIndex = -1;
222  lastLiveFilter = "";
223  liveFilter("");
224  }
225 
226  void
228  {
229  getModel()->search("");
230  // repaint();
231  }
232 
235  {
236  return dynamic_cast<LogTableModel*>(model());
237  }
238 
239  bool
240  LogTable::checkAutoScroll(const QModelIndex& parent, int start, int end)
241  {
242  return checkAutoScroll();
243  }
244 
245  bool
247  {
248  if (verticalScrollBar()->value() == verticalScrollBar()->maximum())
249  {
250  autoscrollActive = true;
251  }
252  else
253  {
254  autoscrollActive = false;
255  }
256 
257 
258  return autoscrollActive;
259  }
260 
261  void
262  LogTable::itemsAdded(QModelIndex leftTop, QModelIndex bottomRight)
263  {
264  }
265 
266  void
267  LogTable::showEvent(QShowEvent* event)
268  {
270 
271  // verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
272  // resizeRowsToContents();
273  // verticalHeader()->setResizeMode(QHeaderView::Fixed);
274  if (autoscrollActive)
275  {
276  QTimer::singleShot(
277  50,
278  this,
279  SLOT(
280  scrollToBottom())); // delayed because something is inserting one line after this function or something
281  }
282  }
283 
284  void
285  LogTable::hideEvent(QHideEvent*)
286  {
287  if (verticalScrollBar()->value() == verticalScrollBar()->maximum())
288  {
289  autoscrollActive = true;
290  }
291  else
292  {
293  autoscrollActive = false;
294  }
295  }
296 
297  void
298  LogTable::rowsInserted(const QModelIndex& parent, int start, int end)
299  {
300  auto logModel = getModel();
301  auto fontHeight = QFontMetrics(font()).height();
302  // ARMARX_INFO << "Adjusting height for " << start << " to " << end << " count: " << logModel->rowCount();
303  for (int i = start; i <= end && i < logModel->rowCount(); ++i)
304  {
305  // auto stringRows = armarx::Split(logModel->getLogEntry(i).what, "\n", true, true);
306  auto index = model()->index(i, 4, parent);
307  auto stringRows = model()->data(index).toString().split("\n").size();
308  if (stringRows > 1)
309  {
310  setRowHeight(i, fontHeight * stringRows + 1);
311  }
312  }
313 
314  if (!isVisible())
315  {
316  newMessageCount += end - start + 1;
317 
319  {
321  }
322 
323  // LogTableModel * logModel = getModel();
324  // if(start> end)
325  // std::swap(start, end);
326  // if(lastLiveFilter.length() > 0)
327  // {
328  // for (int i = start; i <= end; ++i) {
329  // if(!logModel->rowContainsString(i, lastLiveFilter))
330  // setRowHidden(i, true);
331  // }
332  // }
333  }
334  // resizeRowsToContents();
335  else
336  {
337  // verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
338 
339  // for(int i = start; i < end; i++)
340  // resizeRowToContents(i);
341  // verticalHeader()->setResizeMode(QHeaderView::Fixed);
342  }
343 
344  if (autoscrollActive)
345  {
346  scrollToBottom();
347  }
348  }
349 
350  void
351  LogTable::rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end)
352  {
353  if (end - start >= model()->rowCount() - 1)
354  {
356  }
357  }
358 
359  bool
360  LogTable::selectNextSearchResult(bool backwards, bool keepSelectionIfPossible)
361  {
362 
363  int checkCounter = 0; // just a counter for avoiding inifite loops
364  int tempSelectedSearchIndex = indexAt(QPoint(10, 10)).row();
365 
366  if (selectedIndexes().size() > 0)
367  {
368  tempSelectedSearchIndex = selectedIndexes()[0].row();
369  }
370 
371  int oldSelectedSearchIndex = tempSelectedSearchIndex;
372 
373  do // search until we reach old line again
374  {
375 
376  if ((tempSelectedSearchIndex != oldSelectedSearchIndex || keepSelectionIfPossible) &&
377  getModel()->rowContainsString(tempSelectedSearchIndex,
378  getModel()->getCurrentSearchStr()))
379  {
380  selectRow(tempSelectedSearchIndex);
381  return true;
382  }
383 
384  if (backwards)
385  {
386  tempSelectedSearchIndex--;
387  }
388  else
389  {
390  tempSelectedSearchIndex++;
391  }
392 
393  if (tempSelectedSearchIndex >= model()->rowCount())
394  {
395  tempSelectedSearchIndex = 0;
396  }
397 
398  if (tempSelectedSearchIndex < 0)
399  {
400  tempSelectedSearchIndex = model()->rowCount() - 1;
401  }
402 
403 
404  checkCounter++;
405 
406  if (checkCounter > model()->rowCount())
407  {
408  break;
409  }
410  } while (tempSelectedSearchIndex != oldSelectedSearchIndex);
411 
412  return false;
413  }
414 
415  void
416  LogTable::doubleClickOnCell(const QModelIndex& index)
417  {
418  if (index.column() != getModel()->getColumn(ARMARX_LOG_FILESTR))
419  {
420  return;
421  }
422 
423  QString fileWithLineNumber = model()->data(index).toString();
424  std::string file = fileWithLineNumber.toStdString();
425  file.erase(file.rfind(':'));
426  std::string line = fileWithLineNumber.toStdString();
427  line = line.erase(0, line.rfind(':') + 1);
428 
429  if (!std::filesystem::exists(file))
430  {
431  ARMARX_INFO << "File '" << file << "' does not exists - cannot open it.";
432  return;
433  }
434 
435  fileOpener.openFileWithDefaultEditor(file, atoi(line.c_str()));
436  // std::string command = "qtcreator -client " + fileWithLineNumber.toStdString() + "&";
437  // if(system(command.c_str())){}
438  }
439 } // namespace armarx
armarx::LogTable::selectNextSearchResult
bool selectNextSearchResult(bool backwards=true, bool keepSelectionIfPossible=false)
Definition: LogTable.cpp:360
armarx::LogTable::getMaxNewLogLevelType
MessageType getMaxNewLogLevelType()
Definition: LogTable.h:76
armarx::LogTableModel::getMaxNewLogLevelType
MessageType getMaxNewLogLevelType()
Definition: LogTableModel.h:70
armarx::LogTable::newMessageCount
int newMessageCount
Definition: LogTable.h:102
index
uint8_t index
Definition: EtherCATFrame.h:59
armarx::LogTable::lastLiveFilter
QString lastLiveFilter
Definition: LogTable.h:106
LogTableModel.h
armarx::LogTable::itemsAdded
void itemsAdded(QModelIndex leftTop, QModelIndex bottomRight)
Definition: LogTable.cpp:262
armarx::LogTable::getModel
LogTableModel * getModel()
Definition: LogTable.cpp:234
armarx::LogTable::resetNewMessageCount
void resetNewMessageCount()
Definition: LogTable.h:62
armarx::LogTable::liveFilterRow
void liveFilterRow(const QString &filterStr, int row)
Definition: LogTable.cpp:121
ARMARX_LOG_FILESTR
#define ARMARX_LOG_FILESTR
Definition: LogTable.h:44
armarx::LogTableModel
Definition: LogTableModel.h:38
armarx::LogTable::rowsAboutToBeRemoved
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override
Definition: LogTable.cpp:351
armarx::armem::contains
bool contains(const MemoryID &general, const MemoryID &specific)
Indicates whether general is "less specific" than, or equal to, specific, i.e.
Definition: MemoryID.cpp:558
armarx::LogTableModel::search
void search(const QString &searchStr)
Definition: LogTableModel.cpp:398
armarx::LogTable::selectedSearchIndex
int selectedSearchIndex
Definition: LogTable.h:107
armarx::LogTable::liveSearch
bool liveSearch(const QString &search)
Definition: LogTable.cpp:209
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:926
ARMARX_LOG_MESSAGESTR
#define ARMARX_LOG_MESSAGESTR
Definition: LogTable.h:43
armarx::LogTable::showEvent
void showEvent(QShowEvent *event) override
Definition: LogTable.cpp:267
armarx::LogTable::doubleClickOnCell
void doubleClickOnCell(const QModelIndex &index)
Definition: LogTable.cpp:416
LogTable.h
armarx::LogTable::checkAutoScroll
bool checkAutoScroll(const QModelIndex &parent, int start, int end)
Definition: LogTable.cpp:240
armarx::LogTable::resetLiveFilter
void resetLiveFilter()
Definition: LogTable.cpp:218
armarx::LogTable::currentLiveFilter
QString currentLiveFilter
Definition: LogTable.h:106
LogMessageDelegate.h
armarx::LogTable::hideEvent
void hideEvent(QHideEvent *) override
Definition: LogTable.cpp:285
armarx::LogMessageDelegate
Definition: LogMessageDelegate.h:33
armarx::LogTable::~LogTable
~LogTable() override
Definition: LogTable.cpp:110
armarx::LogTable::LogTable
LogTable(QWidget *parent=0)
Definition: LogTable.cpp:39
armarx::LogTable::resetLiveSearch
void resetLiveSearch()
Definition: LogTable.cpp:227
armarx::LogTable::maxNewLogLevelType
MessageType maxNewLogLevelType
Definition: LogTable.h:103
armarx::LogTable::rowsInserted
void rowsInserted(const QModelIndex &parent, int start, int end) override
Definition: LogTable.cpp:298
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
armarx::LogTable::getCurrentLiveFilter
QString getCurrentLiveFilter() const
Definition: LogTable.cpp:115
armarx::LogTableModel::rowContainsString
bool rowContainsString(int row, const QString &searchStr) const
Definition: LogTableModel.cpp:298
armarx::EditorFileOpener::openFileWithDefaultEditor
void openFileWithDefaultEditor(const std::string &filepath, int lineNumber=0)
The default editor can be specified by the environment variable $ARMARX_EDITOR.
Definition: editorfileopener.cpp:124
armarx::LogTable::liveFilter
void liveFilter(const QString &search, int startRow=0)
Definition: LogTable.cpp:136
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
armarx::LogTable::autoscrollActive
bool autoscrollActive
Definition: LogTable.h:101
armarx::LogTable::fileOpener
EditorFileOpener fileOpener
Definition: LogTable.h:108