Developer Documentation
loggerWidget.cc
1/*===========================================================================*\
2* *
3* OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39* *
40\*===========================================================================*/
41
42
43
44
45
46
47#include "loggerWidget.hh"
48
50
52
53LoggerWidget::LoggerWidget( QWidget *parent)
54 : QWidget(parent),
55 newData_(true)
56{
57 // Don't delete this widget on close actions
58 // since it may be embedded in different widget
59 // containers at the same time
60 setAttribute(Qt::WA_DeleteOnClose, false);
61
62 QVBoxLayout* vlayout = new QVBoxLayout();
63 QHBoxLayout* hlayout = new QHBoxLayout();
64
65 list_ = new QListWidget();
66
67 list_->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
68 list_->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
69 list_->setFocusPolicy(Qt::NoFocus);
70 list_->setSelectionMode(QAbstractItemView::ExtendedSelection);
71 list_->setUniformItemSizes(true);
72
73 QString path = OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator();
74
75 // ============================
76 // Context Menu
77 // ============================
78 context_ = new QMenu(tr("Log Viewer"));
79
80 QAction* copyAction = new QAction(QIcon(path + "edit-copy.png"), tr("Copy"),0);
81 copyAction->setShortcut( QKeySequence("Ctrl+C") );
82 QAction* selectAction = new QAction(tr("Select All"),0);
83 selectAction->setShortcut( QKeySequence("Ctrl+A") );
84
85 connect (copyAction, SIGNAL(triggered()), this, SLOT(copySelected()));
86 connect (selectAction, SIGNAL(triggered()), list_, SLOT(selectAll()));
87
88 context_->addAction(copyAction);
89 context_->addSeparator();
90 context_->addAction(selectAction);
91
92
93 // ============================
94 // Filters Menu
95 // ============================
96 filterMenu_ = new QMenu(tr("Log Viewer"));
97
98 openMeshFilterAction_ = new QAction(QIcon(path + "edit-copy.png"), tr("Enable OpenMesh error messages"),0);
99 openMeshFilterAction_->setCheckable(true);
100
101
102 if ( OpenFlipperSettings().value("Core/Gui/LogWindow/OpenMeshErrors",true).toBool() ) {
103 openMeshFilterAction_->setChecked( true );
104 omerr().enable();
105 } else {
106 openMeshFilterAction_->setChecked( false );
107 omerr().disable();
108 }
109
110 filterMenu_->addAction(openMeshFilterAction_);
111
112 // ============================
113 // Scrollbar
114 // ============================
115 blockNext_ = false;
116
117 connect (&loggerUpdateTimer_, SIGNAL(timeout ()), this, SLOT(slotScrollUpdate()));
118
119 // Single shot timer every 500 msecs
120 loggerUpdateTimer_.setSingleShot(true);
121 loggerUpdateTimer_.setInterval(500);
122
123 allButton_ = new QPushButton(QIcon(path + "status_all.png"),tr("All Messages"));
124 allButton_->setCheckable(true);
125 allButton_->setAutoExclusive(true);
126 infoButton_ = new QPushButton(QIcon(path + "status_green.png"),tr("Information"));
127 infoButton_->setCheckable(true);
128 infoButton_->setAutoExclusive(true);
129 warnButton_ = new QPushButton(QIcon(path + "status_yellow.png"),tr("Warnings"));
130 warnButton_->setCheckable(true);
131 warnButton_->setAutoExclusive(true);
132 errorButton_ = new QPushButton(QIcon(path + "status_red.png"),tr("Errors"));
133 errorButton_->setCheckable(true);
134 errorButton_->setAutoExclusive(true);
135
136 filterButton_ = new QPushButton(QIcon(path + "status_filter.png"),tr("Set Filters"));
137 filterButton_->setCheckable(false);
138
139 allButton_->setChecked(true);
140
141 connect(allButton_, SIGNAL(clicked()), this, SLOT(updateList()));
142 connect(infoButton_, SIGNAL(clicked()), this, SLOT(updateList()));
143 connect(warnButton_, SIGNAL(clicked()), this, SLOT(updateList()));
144 connect(errorButton_, SIGNAL(clicked()), this, SLOT(updateList()));
145 connect(filterButton_,SIGNAL(clicked()), this, SLOT(slotFilterMenu()));
146
147 clearButton_ = new QPushButton(QIcon(path + "edit-clear.png"),tr("Clear Messages"));
148 connect(clearButton_, SIGNAL(clicked()), list_, SLOT(clear()));
149
150 hlayout->addWidget( allButton_ );
151 hlayout->addWidget( infoButton_ );
152 hlayout->addWidget( warnButton_ );
153 hlayout->addWidget( errorButton_ );
154 hlayout->addStretch();
155 hlayout->addWidget( filterButton_ );
156 hlayout->addStretch();
157 hlayout->addWidget( clearButton_ );
158
159 hlayout->setSpacing(0);
160 hlayout->setContentsMargins (0,0,0,0);
161 vlayout->setSpacing(0);
162 vlayout->setContentsMargins (0,0,0,0);
163
164 vlayout->addWidget(list_);
165 vlayout->addLayout( hlayout );
166
167 setLayout( vlayout );
168}
169
170LoggerWidget::~LoggerWidget()
171{
172 delete clearButton_;
173 delete errorButton_;
174 delete warnButton_;
175 delete infoButton_;
176 delete allButton_;
177 delete context_;
178 delete list_;
179}
180
181
182//-------------------------------------------------------------------------------------
183
185void LoggerWidget::append(const QString& _text, Logtype _type){
186
187 list_->addItem(_text);
188
189 QListWidgetItem* item = list_->item( list_->count()-1 );
190
191 if ( allButton_->isChecked() )
192 item->setHidden(false);
193 else
194 item->setHidden(true);
195
196 switch (_type) {
197 case LOGINFO:
198 item->setForeground( QBrush(QColor(Qt::darkGreen)) );
199 item->setBackground( QBrush(QColor(225,255,225), Qt::SolidPattern) );
200
201 if ( infoButton_->isChecked() )
202 item->setHidden(false);
203 break;
204 case LOGOUT:
205 item->setForeground( QPalette{}.windowText() );
206 break;
207 case LOGWARN:
208 item->setForeground( QBrush(QColor(160,160,0)) );
209 item->setBackground( QBrush(QColor(255,240,200),Qt::SolidPattern) );
210
211 if ( warnButton_->isChecked() )
212 item->setHidden(false);
213 break;
214 case LOGERR:
215 item->setForeground( QBrush(QColor(Qt::red)) );
216 item->setBackground( QBrush(QColor(255,225,225),Qt::SolidPattern) );
217
218 if ( errorButton_->isChecked() )
219 item->setHidden(false);
220 break;
221 case LOGSTATUS:
222 item->setForeground( QBrush(QColor(Qt::blue)) );
223 item->setBackground( QBrush(QColor(255,225,225),Qt::SolidPattern) );
224
225 if ( errorButton_->isChecked() )
226 item->setHidden(false);
227 break;
228 }
229
230 // If the logger is hidden, we just ignore the update ... done by showEvent later
231 if ( isHidden() )
232 return;
233
234 // Remember that we have new logs to show
235 newData_ = true;
236
237 // Check if we already have a running timer.
238 // If so, the timeout of that timer will trigger the redraw.
239 // Otherwise, we redraw and start the timer to block concurrent redraws.
240 // Only if new data is available, the redraw at the timers timeout will be done.
241 if ( ! loggerUpdateTimer_.isActive() ) {
242 // Update the logger
243 list_->scrollToBottom();
244
245 // Remember that there is no new data now.
246 // This might change again on a call to this function, while the timer is active.
247 newData_ = false;
248
249 // start the timer
250 loggerUpdateTimer_.start();
251 }
252
253}
254
255//-------------------------------------------------------------------------------------
256
258
259 // If there is data to show, do it.
260 if ( newData_ ) {
261 list_->scrollToBottom();
262 newData_ = false;
263 }
264
265}
266
267//-------------------------------------------------------------------------------------
268
271
272 QColor color;
273
274 if ( infoButton_->isChecked() )
275 color = QColor(Qt::darkGreen);
276 else if ( warnButton_->isChecked() )
277 color = QColor(160,160,0);
278 else if ( errorButton_->isChecked() )
279 color = QColor(Qt::red);
280 else
281 color = QColor(Qt::black);
282
283 if (color == QColor(Qt::black)){
284
285 for (int i=0; i < list_->count(); i++)
286 list_->item( i )->setHidden(false);
287
288 } else {
289
290 for (int i=0; i < list_->count(); i++)
291 if ( list_->item(i)->foreground().color() == color )
292 list_->item( i )->setHidden(false);
293 else
294 list_->item( i )->setHidden(true);
295 }
296
297 list_->scrollToBottom();
298}
299
300//-------------------------------------------------------------------------------------
301void LoggerWidget::showEvent ( QShowEvent * /*event*/ ) {
302 list_->scrollToBottom();
303}
304
305//-------------------------------------------------------------------------------------
306
308void LoggerWidget::keyPressEvent (QKeyEvent * _event ) {
309 // Return key event to parent if not one of the standard key combinations ( ... Core )
310 if ( (_event->modifiers() & Qt::ControlModifier ) && ( _event->key() == Qt::Key_C ) )
311 copySelected();
312
313 else if ( (_event->modifiers() & Qt::ControlModifier ) && ( _event->key() == Qt::Key_A ) )
314 list_->selectAll();
315
316 else
317 _event->ignore();
318}
319
320//-------------------------------------------------------------------------------------
321
323void LoggerWidget::contextMenuEvent ( QContextMenuEvent * event ){
324
325 QPoint p = list_->mapToGlobal( event->pos() );
326
327 context_->popup( p );
328
329}
330
331//-------------------------------------------------------------------------------------
332
335
336 QString str = "";
337
338 for (int i=0; i < list_->selectedItems().count(); i++)
339 str += (list_->selectedItems()[i])->text() + "\n";
340
341 QClipboard *clipboard = QApplication::clipboard();
342
343 clipboard->setText(str);
344}
345
346//-------------------------------------------------------------------------------------
347
349 filterMenu_->popup( list_->mapToGlobal(filterButton_->pos()) );
350}
351
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
Logtype
Log types for Message Window.
@ LOGERR
@ LOGWARN
@ LOGSTATUS
@ LOGINFO
@ LOGOUT
void updateList()
update the list if a button was pressed
void append(const QString &_text, Logtype _type)
Append a new logmessage to log viewer.
void copySelected()
copy Selected rows to clipboard
void slotScrollUpdate()
Called when we want to scroll to the bottom.
void slotFilterMenu()
Called when filter button is pressed.
void keyPressEvent(QKeyEvent *_event)
Grab key events.
void showEvent(QShowEvent *event)
Called when the widget is shown.
void contextMenuEvent(QContextMenuEvent *event)
Show context menu.