Salome HOME
API modif of vtkOpenGLTexture::ResampleToPowerOfTwo
[modules/gui.git] / src / LogWindow / LogWindow.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  KERNEL SALOME_Event : Define event posting mechanism
24 // File   : LogWindow.cxx
25 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
26 //
27 #include "LogWindow.h"
28
29 #include <QAction>
30 #include <QApplication>
31 #include <QDate>
32 #include <QFile>
33 #include <QMenu>
34 #include <QTextEdit>
35 #include <QTextStream>
36 #include <QTime>
37 #include <QVBoxLayout>
38
39 #include <SUIT_MessageBox.h>
40 #include <SUIT_ResourceMgr.h>
41 #include <SUIT_Session.h>
42 #include <SUIT_Tools.h>
43
44 #define DEFAULT_SEPARATOR "***"
45
46 /*!
47   \brief Convert rich text to plain text.
48   \internal
49   \param richText rich text string
50   \return converted plain text string
51 */
52 static QString plainText( const QString& richText )
53 {
54   QString aText = richText;
55   int startTag = aText.indexOf( '<' );
56   while ( true )
57   {
58     if ( startTag < 0 )
59       break;
60
61     int finishTag = aText.indexOf( '>', startTag );
62     if ( finishTag < 0 )
63       break;
64
65     aText = aText.remove( startTag, finishTag - startTag + 1 );
66     startTag = aText.indexOf( '<' );
67   }
68   return aText;
69 }
70
71 /*!
72   \class LogWindow
73   \brief Widget, displaying log messages.
74
75   The log messages window provides operations like:
76   - show messages
77   - display timestamps at the message beginning
78   - color messages according to their purposes (e.g., errors/warning)
79   - clear log output
80   - copy messages to clipvoard
81   - save message log to to the text file
82 */
83
84 /*!
85   \brief Constructor.
86
87   Creates new messages log window widget.
88   \param parent parent widget
89 */
90 LogWindow::LogWindow( QWidget* parent )
91 : QWidget( parent ),
92   SUIT_PopupClient()
93 {
94   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
95
96   QString fntSet = resMgr ? resMgr->stringValue( "Log Window", "font", QString() ) : QString();
97
98   setFont( SUIT_Tools::stringToFont( fntSet ) );
99
100   myView = new QTextEdit( this );
101   myView->setReadOnly( true );
102   myView->viewport()->installEventFilter( this );
103
104   QVBoxLayout* main = new QVBoxLayout( this );
105   main->setMargin( 0 );
106   main->addWidget( myView );
107
108   myBannerSize = 0;
109   myBanner = "<b>Message Log</b>\n********************";
110   mySeparator = DEFAULT_SEPARATOR;
111
112   clear();
113
114   createActions();
115 }
116
117 /*!
118   \brief Destructor.
119
120   Does nothing for the moment.
121 */
122 LogWindow::~LogWindow()
123 {
124 }
125
126 /*!
127   \brief Get current banner (message log window header text).
128   \return string representing the current banner
129 */
130 QString LogWindow::banner() const
131 {
132   return myBanner;
133 }
134
135 /*!
136   \brief Get current separator (text which is printed between messages).
137   \return string representing the current separator
138 */
139 QString LogWindow::separator() const
140 {
141   return mySeparator;
142 }
143
144 /*!
145   \brief Set current banner (message log window header text).
146   \param banner new banner
147 */
148 void LogWindow::setBanner( const QString& banner )
149 {
150   myBanner = banner;
151
152   clear( false );
153 }
154
155 /*!
156   Set current separator (text which is printed between messages).
157   \param separator new separator
158 */
159 void LogWindow::setSeparator( const QString& separator )
160 {
161   mySeparator = separator;
162
163   clear( false );
164 }
165
166 /*!
167   \brief Custom event handler.
168
169   Process context popup menu request event.
170   
171   \param o object
172   \param e event
173   \return True if the event is processed and further processing should be stopped
174 */
175 bool LogWindow::eventFilter( QObject* o, QEvent* e )
176 {
177   if ( o == myView->viewport() && e->type() == QEvent::ContextMenu )
178   {
179     contextMenuRequest( (QContextMenuEvent*)e );
180     return true;
181   }
182   return QWidget::eventFilter( o, e );
183 }
184
185 /*!
186   \brief Put new message to the log window.
187   \param message text of the message
188   \param flags ORed flags which define how the message should be printed
189 */
190 void LogWindow::putMessage( const QString& message, const int flags )
191 {
192   putMessage( message, QColor(), flags );
193 }
194
195 /*!
196   \brief Put new message to the log window.
197   \param message text of the message
198   \param color text color of the message
199   \param flags ORed flags which define how the message should be printed
200 */
201 void LogWindow::putMessage( const QString& message, const QColor& color, const int flags )
202 {
203   QString msg = message;
204   if ( msg.isEmpty() )
205     return;
206
207   bool noColor = flags & DisplayNoColor;
208
209   if ( color.isValid() )
210     msg = QString( "<font color=\"%1\">%2</font>" ).arg( color.name() ).arg( msg );
211
212   QString dStr;
213   if ( flags & DisplayDate )
214   {
215     dStr = QDate::currentDate().toString( Qt::SystemLocaleDate );
216     if ( !noColor )
217       dStr = QString( "<font color=\"#003380\">%1</font>" ).arg( dStr );
218   }
219
220   QString tStr;
221   if ( flags & DisplayTime )
222   {
223     tStr = QTime::currentTime().toString( Qt::SystemLocaleDate );
224     if ( !noColor )
225       tStr = QString( "<font color=\"#008033\">%1</font>" ).arg( tStr );
226   }
227
228   QString dateTime = QString( "%1 %2" ).arg( dStr ).arg( tStr ).trimmed();
229   if ( !dateTime.isEmpty() )
230     msg = QString( "[%1] %2" ).arg( dateTime ).arg( msg );
231
232   myView->append( msg );
233   myHistory.append( plainText( message ) );
234
235   if ( flags & DisplaySeparator && !mySeparator.isEmpty() )
236   {
237     myView->append( mySeparator );   // add separator
238     myHistory.append( plainText( mySeparator ) );
239   }
240   myView->moveCursor( QTextCursor::End );
241 }
242
243 /*!
244   \brief Clear message log.
245   \param clearHistory if True, clear also the messages history
246 */
247 void LogWindow::clear( bool clearHistory )
248 {
249   myView->clear();
250   if ( clearHistory )
251     myHistory.clear();
252
253   if ( !myBanner.isEmpty() )
254   {
255     myView->append( myBanner );
256     myBannerSize = myView->document()->blockCount();
257   }
258   else
259     myBannerSize = 0;
260 }
261
262 /*!
263   \brief Save messages log to the file.
264   \param fileName name of the file
265   \return \c true on success and \c false on error
266 */
267 bool LogWindow::saveLog( const QString& fileName )
268 {
269   QFile file( fileName );
270   if ( !file.open( QFile::WriteOnly ) )
271     return false;
272
273   QTextStream stream( &file );
274
275   stream << "*****************************************"   << endl;
276   stream << "Message Log"                                 << endl;
277   stream << QDate::currentDate().toString( "dd.MM:yyyy" ) << "  ";
278   stream << QTime::currentTime().toString( "hh:mm:ss" )   << endl;
279   stream << "*****************************************"   << endl;
280
281   for ( int i = 0; i < myHistory.count(); i++ )
282     stream << myHistory[ i ] << endl;
283
284   file.close();
285   return true;
286 }
287
288 /*!
289   \brief Create context popup menu actions.
290 */
291 void LogWindow::createActions()
292 {
293   QAction* a = new QAction( tr( "EDIT_COPY_CMD" ), this );
294   a->setStatusTip( tr( "EDIT_COPY_CMD" ) );
295   connect( a, SIGNAL( triggered( bool ) ), SLOT( onCopy() ) );
296   myActions.insert( CopyId, a );
297
298   a = new QAction( tr( "EDIT_CLEAR_CMD" ), this );
299   a->setStatusTip( tr( "EDIT_CLEAR_CMD" ) );
300   connect( a, SIGNAL( triggered( bool ) ), SLOT( onClear() ) );
301   myActions.insert( ClearId, a );
302
303   a = new QAction( tr( "EDIT_SELECTALL_CMD" ), this );
304   a->setStatusTip( tr( "EDIT_SELECTALL_CMD" ) );
305   connect( a, SIGNAL( triggered( bool ) ), SLOT( onSelectAll() ) );
306   myActions.insert( SelectAllId, a );
307
308   a = new QAction( tr( "EDIT_SAVETOFILE_CMD" ), this );
309   a->setStatusTip( tr( "EDIT_SAVETOFILE_CMD" ) );
310   connect( a, SIGNAL( triggered( bool ) ), SLOT( onSaveToFile() ) );
311   myActions.insert( SaveToFileId, a );
312 }
313
314 /*!
315   \brief Create the context popup menu.
316
317   Fill in the popup menu with the commands.
318
319   \param menu context popup menu
320 */
321 void LogWindow::contextMenuPopup( QMenu* popup )
322 {
323   popup->addAction( myActions[ CopyId ] );
324   popup->addAction( myActions[ ClearId ] );
325   popup->addSeparator();
326   popup->addAction( myActions[ SelectAllId ] );
327   popup->addSeparator();
328   popup->addAction( myActions[ SaveToFileId ] );
329
330   Qtx::simplifySeparators( popup );
331
332   updateActions();
333 }
334
335 /*!
336   \brief Update menu actions.
337
338   Update context popup menu action state.
339 */
340 void LogWindow::updateActions()
341 {
342   myActions[CopyId]->setEnabled( myView->textCursor().hasSelection() );
343   myActions[ ClearId ]->setEnabled( myView->document()->blockCount() > myBannerSize );
344   myActions[SelectAllId]->setEnabled( !myView->document()->isEmpty() );
345   myActions[ SaveToFileId ]->setEnabled( myHistory.count() > 0 );
346 }
347
348 /*!
349   \brief Called when user selects "Save To File" command in the popup menu.
350 */
351 void LogWindow::onSaveToFile()
352 {
353   SUIT_Application* app = SUIT_Session::session()->activeApplication();
354   if ( !app )
355     return;
356
357   // call application-specific "Save file" dialog box
358   QString aName = app->getFileName( false, QString(), QString( "*.log" ), QString(), 0 );
359   if ( aName.isNull() )
360     return;
361
362   QApplication::setOverrideCursor( Qt::WaitCursor );
363
364   bool bOk = saveLog( aName );
365
366   QApplication::restoreOverrideCursor();
367
368   if ( !bOk )
369     SUIT_MessageBox::critical( this, tr( "ERR_ERROR" ), tr( "ERR_CANT_SAVE_FILE" ) );
370 }
371
372 /*!
373   \brief Called when user selects "Select all" command in the popup menu.
374 */
375 void LogWindow::onSelectAll()
376 {
377   if ( myView )
378     myView->selectAll();
379 }
380
381 /*!
382   \brief Called when user click "Clear" command in the popup menu.
383 */
384 void LogWindow::onClear()
385 {
386   clear( false );
387 }
388
389 /*!
390   \brief Called when user click "Copy" command in the popup menu.
391 */
392 void LogWindow::onCopy()
393 {
394   if ( myView )
395     myView->copy();
396 }
397
398 /*!
399   \brief Set actions to be visible in the context popup menu.
400   
401   Actions, which IDs are set in \a flags parameter, will be shown in the 
402   context popup menu. Other actions will not be shown.
403
404   \param flags ORed together actions flags
405 */
406 void LogWindow::setMenuActions( const int flags )
407 {
408   myActions[CopyId]->setVisible( flags & CopyId );
409   myActions[ClearId]->setVisible( flags & ClearId );
410   myActions[SelectAllId]->setVisible( flags & SelectAllId );
411   myActions[SaveToFileId]->setVisible( flags & SaveToFileId );
412 }
413
414 /*!
415   \brief Get menu actions which are currently visible in the context popup menu.
416   \return ORed together actions flags
417   \sa setMenuActions()
418 */
419 int LogWindow::menuActions() const
420 {
421   int ret = 0;
422   ret = ret | ( myActions[CopyId]->isVisible() ? CopyId : 0 );
423   ret = ret | ( myActions[ClearId]->isVisible() ? ClearId : 0 );
424   ret = ret | ( myActions[SelectAllId]->isVisible() ? SelectAllId : 0 );
425   ret = ret | ( myActions[SaveToFileId]->isVisible() ? SaveToFileId : 0 );
426   return ret;
427 }
428
429 /*!
430   \fn virtual QString LogWindow::popupClientType() const;
431   \brief Get popup client symbolic name, used in popup menu management system.
432   \return symbolic name
433 */