Salome HOME
Updated copyright comment
[modules/gui.git] / src / TOOLSGUI / ToolsGUI_RegWidget.cxx
1 // Copyright (C) 2007-2024  CEA, EDF, 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 # include "ToolsGUI_RegWidget.h"
24
25 #include <QApplication>
26 #include <QInputDialog>
27 #include <QMenuBar>
28 #include <QStatusBar>
29 #include <QTabWidget>
30 #include <QTextEdit>
31 #include <QTimer>
32 #include <QToolBar>
33 #include <QTreeWidget>
34 #include <QVBoxLayout>
35
36 #include <Qtx.h>
37
38 #include <SALOME_NamingService.hxx>
39 #include <Utils_SINGLETON.hxx>
40 #include <Utils_CommException.hxx>
41
42 #define MARGIN_SIZE      11
43 #define SPACING_SIZE      6
44 #define MIN_SPIN_WIDTH  100 
45
46 #define BOLD( text ) QString( "<b>%1</b>" ).arg( QString( text ) )
47
48 static const char* const time_data[] = { 
49 "16 16 6 1",
50 ". c None",
51 "b c None",
52 "# c #000000",
53 "a c #4c4c4c",
54 "d c #878787",
55 "c c #ffffff",
56 ".....#####ab....",
57 "...##cc#dc##ab..",
58 "..#ccc###dcc#ab.",
59 ".#ccccc#dcccc#a.",
60 ".#ccccc#dcccc#ab",
61 "#cccccc#dccccc#a",
62 "#cccccc#dccc#c#a",
63 "#c##ccc########a",
64 "#ccddcccdddd#d#a",
65 "#cccccccccccdc#a",
66 ".#ccccccccccc#aa",
67 ".#ccccc#ccccc#a.",
68 "..#cccc#dccc#aa.",
69 "...##cccdc##aa..",
70 ".....#####aaa...",
71 "......aaaaa....."};
72
73 static const char* const close_data[] = { 
74 "16 16 6 1",
75 "d c None",
76 ". c None",
77 "# c #000000",
78 "a c #4c4c4c",
79 "c c #5b5b5b",
80 "b c #ffffff",
81 ".....#####a.....",
82 "...##bbbbb##a...",
83 "..#bbbbbbbbb#a..",
84 ".#b#cbbbbbb#d#a.",
85 ".#bc#cbbbb#cb#a.",
86 "#bbbc#cbb#cbbb#a",
87 "#bbbbc#c#cbbbb#a",
88 "#bbbbbc#cbbbbb#a",
89 "#bbbbc#c#cbbbb#a",
90 "#bbb#ccbb##bbb#a",
91 ".#b#c#bbbbc#b#aa",
92 ".#bc#bbbbbb#c#a.",
93 "..#bbbbbbbbb#aa.",
94 "...##bbbbb##aa..",
95 ".....#####aaa...",
96 "......aaaaa....."};
97
98 static const char* const refresh_data[] = { 
99 "16 16 5 1",
100 ". c None",
101 "# c #000000",
102 "a c #4c4c4c",
103 "c c #878787",
104 "b c #ffffff",
105 ".....#####a.....",
106 "...##bb#bb##a...",
107 "..#bbbbc#bbb#a..",
108 ".#bbbb####cbb#a.",
109 ".#bbb#cc#cbbb#a.",
110 "#bbb#cb#cbbbbb#a",
111 "#bb#cbbbbbb#bb#a",
112 "#bb#cbbbbbb#cb#a",
113 "#bb#cbbbbbb#cb#a",
114 "#bbbbbb#bb#cbb#a",
115 ".#bbbb#cb#cbb#aa",
116 ".#bbb####cbbb#a.",
117 "..#bbb#cbbbb#aa.",
118 "...##bb#cb##aa..",
119 ".....#####aaa...",
120 "......aaaaa....."};
121
122 /*!
123   \brief Get access to the Registry service
124   \internal
125   \param orb CORBA ORB reference
126   \return reference to the Registry service
127 */
128 static Registry::Components_ptr GetRegistry( CORBA::ORB_ptr orb )
129 {
130   static const char* registryName = "Registry";
131   Registry::Components_var aRegistry;
132   
133   SALOME_NamingService& naming = *SINGLETON_<SALOME_NamingService>::Instance();
134   naming.init_orb( orb );
135   
136   CORBA::Object_var object = 0;
137   try
138   {
139     object = naming.Resolve( registryName );
140     if ( CORBA::is_nil( object ) ) throw CommException( "Unable to find the Registry service" );
141     aRegistry = Registry::Components::_narrow( object );
142   }
143   catch( const CORBA::Exception& /*ex*/ ) //!< TODO: unused variable
144   {
145     MESSAGE( "Error: can't access Registry server" );
146   }
147
148   return aRegistry._retn();
149 }
150
151 /*!
152   \class ToolsGUI_RegWidget
153   \brief SALOME Registry tool window.
154 */
155
156 //! The only instance of Registry window
157 ToolsGUI_RegWidget* ToolsGUI_RegWidget::myRegWidgetPtr = 0;
158
159 /*!
160   \brief Create/get the only instance of the Registry window.
161   \param orb CORBA ORB reference
162   \param parent parent widget
163 */
164 ToolsGUI_RegWidget* ToolsGUI_RegWidget::GetRegWidget( CORBA::ORB_ptr orb,
165                                                       QWidget* parent )
166 {
167   if ( !myRegWidgetPtr ) 
168     myRegWidgetPtr = new ToolsGUI_RegWidget( orb, parent );
169   return myRegWidgetPtr;
170 }
171
172 /*!
173   \brief Constructor
174   \param orb CORBA ORB reference
175   \param parent parent widget
176 */
177 ToolsGUI_RegWidget::ToolsGUI_RegWidget( CORBA::ORB_ptr orb, QWidget* parent ) 
178 : QMainWindow( parent )
179 {
180   myOrb = CORBA::ORB::_duplicate( orb );
181
182   // set window attributes
183   setAttribute( Qt::WA_DeleteOnClose );
184   setWindowTitle( tr( "TLT_REGISTRY" ) );
185
186   // show status bar
187   statusBar();
188
189   // get main menu bar
190   QMenuBar* mainMenu = menuBar();
191   
192   // add 'Actions' menu
193   QMenu* m = mainMenu->addMenu( tr( "MNU_ACTIONS" ) );
194   // add 'Actions' toolbar
195   QToolBar* tb = addToolBar( tr( "TB_ACTIONS" ) );
196
197   // create actions
198   myActions[Refresh] = new QAction( QPixmap( refresh_data ), tr( "MEN_REFRESH" ), this );
199   myActions[Refresh]->setStatusTip( tr( "STB_REFRESH" ) );
200   connect( myActions[Refresh], SIGNAL( triggered() ), this, SLOT( refresh() ) );
201   m->addAction( myActions[Refresh] );
202   tb->addAction( myActions[Refresh] );
203   
204   myActions[Interval] = new QAction( QPixmap( time_data ), tr( "MEN_INTERVAL" ), this );
205   myActions[Interval]->setStatusTip( tr( "STB_INTERVAL" ) );
206   connect( myActions[Interval], SIGNAL( triggered() ), this, SLOT( refreshInterval() ) );
207   m->addAction( myActions[Interval] );
208   tb->addAction( myActions[Interval] );
209   
210   m->addSeparator();
211   tb->addSeparator();
212
213   myActions[Close] = new QAction( QPixmap( close_data ), tr( "MEN_CLOSE" ), this );
214   myActions[Close]->setStatusTip( tr( "STB_CLOSE" ) );
215   connect( myActions[Close], SIGNAL( triggered() ), this, SLOT( close() ) );
216   m->addAction( myActions[Close] );
217   tb->addAction( myActions[Close] );
218
219   // central widget
220   setCentralWidget( new QWidget( this ) );
221
222   // Create tab widget: SALOME serives list (running and history)
223   QTabWidget* tabWidget = new QTabWidget( centralWidget() );
224
225   myViews[Clients]   = new QTreeWidget( tabWidget );
226   myViews[Clients]->setColumnCount( 6 );
227   myViews[Clients]->setAllColumnsShowFocus( true );
228   myViews[Clients]->setRootIsDecorated( false );
229   QStringList runningLabels;
230   runningLabels << tr( "HDR_COMPONENT" ) << tr( "HDR_PID" )     << tr( "HDR_USERNAME" )
231                 << tr( "HDR_HOSTNAME" )  << tr( "HDR_STARTED" ) << tr( "HDR_HELLO" );
232   myViews[Clients]->setHeaderLabels( runningLabels );
233   tabWidget->addTab( myViews[Clients], tr( "TAB_RUNNING" ) );
234
235   myViews[History]   = new QTreeWidget( tabWidget );
236   myViews[History]->setColumnCount(6);
237   myViews[History]->setAllColumnsShowFocus( true );
238   myViews[History]->setRootIsDecorated( false );
239   QStringList historyLabels;
240   historyLabels << tr( "HDR_COMPONENT" ) << tr( "HDR_PID" )     << tr( "HDR_USERNAME" )
241                 << tr( "HDR_HOSTNAME" )  << tr( "HDR_STARTED" ) << tr( "HDR_FINISHED" );
242   myViews[History]->setHeaderLabels( historyLabels );
243   tabWidget->addTab( myViews[History], tr( "TAB_HISTORY" ) );
244
245   connect( tabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( refresh() ) );
246   connect( myViews[Clients], SIGNAL( itemActivated( QTreeWidgetItem*, int ) ), 
247            this,             SLOT( showDetails( QTreeWidgetItem*, int ) ) );
248   connect( myViews[History], SIGNAL( itemActivated( QTreeWidgetItem*, int ) ),
249            this,             SLOT( showDetails( QTreeWidgetItem*, int ) ) );
250
251   // create information window
252   myDetails = new QTextEdit( centralWidget() );
253   myDetails->setReadOnly( true );
254   myDetails->setMinimumHeight( 100 );
255
256   // layout widgets
257   QVBoxLayout* topLayout = new QVBoxLayout( centralWidget() );
258   topLayout->setMargin( 0 );
259   topLayout->setSpacing( SPACING_SIZE );
260   topLayout->addWidget( tabWidget );
261   topLayout->addWidget( myDetails );
262   
263   // install auto-update timer
264   myTimer = new QTimer( this );
265   connect( myTimer, SIGNAL( timeout() ), this, SLOT( refresh() ) );
266   myTimer->start( 10000 ); // 10 seconds by default
267   
268   // resize window and set its position
269   resize( 800, 400 );
270   Qtx::alignWidget( (QWidget*)this, (QWidget*)QApplication::desktop(), Qtx::AlignCenter );
271
272   // refresh registry information
273   refresh();
274 }
275
276 /*!
277   \brief Destructor
278 */
279 ToolsGUI_RegWidget::~ToolsGUI_RegWidget()
280 {
281   myRegWidgetPtr = 0;
282 }
283
284 /*!
285   \brief Get description text, containing information about the service.
286   \param c_info client info data
287   \return formatted client description
288 */
289 QString ToolsGUI_RegWidget::getDetails( const Registry::Infos& c_info )
290 {
291   QString a;
292   if ( c_info.name != NULL ) {
293     time_t aStarted( c_info.tc_start );
294     time_t aLastPing( c_info.tc_hello );
295     time_t aFinished( c_info.tc_end );
296
297     a.append( BOLD( tr( "INFO_SERVICE" ).arg( QString( c_info.name ) ) ) );
298     a.append( "<br>" );
299     a.append( "<br>" );
300     a.append( tr( "INFO_PROCESS" ).arg( BOLD( QString::number( c_info.pid ) ),
301                                         BOLD( c_info.machine ),
302                                         BOLD( c_info.adip ),
303                                         BOLD( c_info.pwname ),
304                                         BOLD( QString::number( c_info.uid ) ),
305                                         BOLD( c_info.cdir ) ) );
306     a.append( "<br>" );
307     a.append( "<br>" );
308     a.append( tr( "INFO_STARTED" ).arg( BOLD( QString( ctime( &aStarted ) ).trimmed() ) ) );
309     a.append( "<br>" );
310     if ( c_info.tc_hello != 0 ) {
311       a.append( tr( "INFO_LAST_PING" ).arg( BOLD( QString( ctime( &aLastPing ) ).trimmed() ) ) );
312       a.append( "<br>" );
313     }
314     if ( c_info.tc_end - c_info.difftime != 0 ) {
315       a.append( tr( "INFO_FINISHED" ).arg( BOLD( QString( ctime( &aFinished ) ).trimmed() ) ) );
316       a.append( "<br>" );
317     }
318     else {
319       a.append( tr( "INFO_RUNNING" ) );
320       a.append( "<br>" );
321     }
322     if ( c_info.difftime != 0 ) {
323       a.append( tr( "INFO_TIME_DIFF" ).arg( BOLD( c_info.machine ), BOLD( QString::number( c_info.difftime ) ) ) ); 
324       a.append( "<br>" );
325     }
326     a.append( "</code>" ); // ASV: 28.07.06 : added <code> tags to make the text font be 
327                            // fixed width (looks much better on Windows)
328   }
329   return a;
330 }
331
332 /*!
333   \brief Refresh registry information
334 */
335 void ToolsGUI_RegWidget::refresh()
336 {
337   try {
338     // get reference to the Registry service
339     Registry::Components_var aRegistry = GetRegistry( myOrb );
340     if ( aRegistry->_is_nil() ) {
341       myActions[Interval]->setDisabled( true );
342       myActions[Refresh]->setDisabled( true );
343       myTimer->stop();
344       MESSAGE( "Sorry, no more Registry Server" );
345       statusBar()->showMessage( tr( "ERR_NO_REGISTRY" ) );
346       return;
347     }
348
349     myData[Clients] = aRegistry->getall();
350     myData[History] = aRegistry->history();
351
352     // update current services list
353     myViews[Clients]->clear();
354     for ( int i = 0; i < (int)myData[Clients]->length(); i++ ) { //!< TODO: mismatch signed/unsigned
355       const Registry::Infos& c_info = (*myData[Clients])[i];
356       time_t aStarted  = time_t( c_info.tc_start );
357       time_t aLastPing = time_t( c_info.tc_hello );
358       QStringList aData;
359       aData << QString( c_info.name )
360             << QString::number( c_info.pid )
361             << QString( c_info.pwname )
362             << QString( c_info.machine )
363             << QString( ctime( &aStarted ) ).trimmed()
364             << QString( ctime( &aLastPing ) ).trimmed();
365       myViews[Clients]->addTopLevelItem( new QTreeWidgetItem( aData ) );
366     }
367
368     // update history
369     myViews[History]->clear();
370     for ( int i = 0; i < (int)myData[History]->length(); i++ ) {  //!< TODO: mismatch signed/unsigned     
371       const Registry::Infos& c_info = (*myData[History])[i];
372       time_t aStarted  = time_t( c_info.tc_start );
373       time_t aFinished = time_t( c_info.tc_end );
374       QStringList aData;
375       aData << QString( c_info.name )
376             << QString::number( c_info.pid )
377             << QString( c_info.pwname )
378             << QString( c_info.machine )
379             << QString( ctime( &aStarted ) ).trimmed()
380             << QString( ctime( &aFinished ) ).trimmed();
381       myViews[History]->addTopLevelItem( new QTreeWidgetItem( aData ) );
382     }
383   }
384   catch( ... ) {
385     myActions[Interval]->setDisabled( true );
386     myActions[Refresh]->setDisabled( true );
387     myTimer->stop();
388     MESSAGE( "Sorry, no more Registry Server" );
389     statusBar()->showMessage( tr( "ERR_NO_REGISTRY" ) );
390   }
391 }
392
393 /*!
394   \brief Called when \c Interval button is clicked (open dialog box to 
395   change refresh interval).
396 */
397 void ToolsGUI_RegWidget::refreshInterval()
398 {
399   bool ok;
400   int sec = QInputDialog::getInt( this, tr( "TLT_REFRESH_INTERVAL" ), tr( "LAB_REFRESH_INTERVAL" ), 
401                                   myTimer->interval() / 1000, 1, 24 * 60 * 60, 1, &ok );
402   if ( ok )
403     myTimer->start( sec * 1000 );
404 }
405
406 /*!
407   \brief Show details about the chosen service.
408   \param item item activated by the user
409   \param column column index
410 */
411 void ToolsGUI_RegWidget::showDetails( QTreeWidgetItem* item, int column )
412 {
413   if ( !item || column < 0 ) return;
414   int i = sender() == myViews[Clients] ? Clients : History;
415   int idx  = myViews[i]->indexOfTopLevelItem( item );
416   int size = myData[i]->length();
417   if ( idx < 0 || idx > size-1 ) return;
418   const Registry::Infos& c_info = (*myData[i])[idx];
419   myDetails->setText( getDetails( c_info ) );
420 }