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