Salome HOME
updated copyright message
[modules/gui.git] / src / Qtx / QtxWebBrowser.cxx
1 // Copyright (C) 2007-2023  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 // File:      QtxWebBrowser.cxx
24 // Author:    Roman NIKOLAEV
25
26 #include "QtxWebBrowser.h"
27 #include "QtxResourceMgr.h"
28 #include "QtxSearchTool.h"
29
30 #include <QApplication>
31 #include <QButtonGroup>
32 #include <QCheckBox>
33 #include <QFileDialog>
34 #include <QFileInfo>
35 #include <QGridLayout>
36 #include <QHBoxLayout>
37 #include <QLabel>
38 #include <QMenu>
39 #include <QMenuBar>
40 #include <QMessageBox>
41 #include <QPushButton>
42 #include <QRadioButton>
43 #include <QStatusBar>
44 #include <QToolBar>
45 #include <QVBoxLayout>
46 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
47   #include <QWebView>
48 #else
49   #include <QWebEngineView>
50 #endif
51 #include <QProcess>
52
53 // RNV:
54 // Since from Qt 5.6.0 version QtWebKit tool was removed,
55 // QtxWebBroswer is ported on QtWebEngine. So if it is built with Qt-5.6.0
56 // and newer, it uses QtWebEngine. But for Qt-5.5.1 and Qt4 QtWebKit tool
57 // is used, to provide backward compatibility.
58
59 namespace
60 {
61   bool isLocalFile( const QUrl& url )
62   {
63     QFileInfo fi( url.path() );
64     return fi.exists();
65   }
66 }
67
68 /*!
69   \class QtxWebBrowser::Searcher
70   \brief A class is used with QtxSearchTool in order to search text within the web page 
71   \internal
72 */
73
74 class QtxWebBrowser::Searcher : public QtxSearchTool::Searcher
75 {
76 public:
77   Searcher( WebView* );
78   ~Searcher();
79
80   bool find( const QString&, QtxSearchTool* );
81   bool findNext( const QString&, QtxSearchTool* );
82   bool findPrevious( const QString&, QtxSearchTool* );
83   bool findFirst( const QString&, QtxSearchTool* );
84   bool findLast( const QString&, QtxSearchTool* );
85
86 private:
87   WebView* myView;
88 };
89
90 /*!
91   \brief Constructor
92   \param view web view
93   \internal
94 */
95 QtxWebBrowser::Searcher::Searcher( WebView* view ) : myView( view )
96 {
97 }
98
99 /*!
100   \brief Destructor
101   \internal
102 */
103 QtxWebBrowser::Searcher::~Searcher()
104 {
105 }
106
107 /*!
108   \brief Find specified text
109   \param text text being searched
110   \param st search tool
111   \return \c true if text has been found or \c false otherwise
112   \internal
113 */
114 bool QtxWebBrowser::Searcher::find( const QString& text, QtxSearchTool* st )
115 {
116   WebPage::FindFlags fl = 0;
117   if ( st->isCaseSensitive() ) fl = fl | WebPage::FindCaseSensitively;
118 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0) 
119   if ( st->isSearchWrapped() ) fl = fl | WebPage::FindWrapsAroundDocument;
120   return myView->findText( text, fl );
121 #else
122   bool textFound;
123   myView->findText( text, fl, [&](bool found) { textFound = found; });
124   return textFound;
125 #endif    
126 }
127
128 /*!
129   \brief Find next entry of specified text starting from the current position
130   \param text text being searched
131   \param st search tool
132   \return \c true if text has been found or \c false otherwise
133   \internal
134 */
135 bool QtxWebBrowser::Searcher::findNext( const QString& text, QtxSearchTool* st )
136 {
137   return find( text, st );
138 }
139
140 /*!
141   \brief Find previous entry of specified text starting from the current position
142   \param text text being searched
143   \param st search tool
144   \return \c true if text has been found or \c false otherwise
145   \internal
146 */
147 bool QtxWebBrowser::Searcher::findPrevious( const QString& text, QtxSearchTool* st )
148 {
149   WebPage::FindFlags fl = WebPage::FindBackward;
150   if ( st->isCaseSensitive() ) fl = fl | WebPage::FindCaseSensitively;
151 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0) 
152   if ( st->isSearchWrapped() ) fl = fl | WebPage::FindWrapsAroundDocument;
153   return myView->findText( text, fl );
154 #else
155   bool textFound;
156   myView->findText( text, fl, [&](bool found) { textFound = found; });
157   return textFound;
158 #endif 
159 }
160
161 /*!
162   \brief Find first entry of specified text; does nothing in this implementation
163   \param text text being searched
164   \param st search tool
165   \return \c true if text has been found or \c false otherwise
166   \internal
167 */
168 bool QtxWebBrowser::Searcher::findFirst( const QString& /*text*/, QtxSearchTool* /*st*/ )
169 {
170   return false;
171 }
172
173 /*!
174   \brief Find last entry of specified text; does nothing in this implementation
175   \param text text being searched
176   \param st search tool
177   \return \c true if text has been found or \c false otherwise
178   \internal
179 */
180 bool QtxWebBrowser::Searcher::findLast( const QString& /*text*/, QtxSearchTool* /*st*/)
181 {
182   return false;
183 }
184
185
186 /*!
187   \class QtxWebBrowser::Downloader
188   \brief A dialog box that is used to process file links
189   \internal
190 */
191
192 /*!
193   \brief Constructor
194   \param fileName name of the file being opened
195   \param action default action to be used for the file
196   \param program default program to be used to open the file
197   \param parent parent widget
198   \internal
199 */
200 QtxWebBrowser::Downloader::Downloader( const QString& fileName, int action, const QString& program, QWidget* parent )
201   : QDialog( parent ), myProgram( program )
202 {
203   setModal( true );
204   setWindowTitle( QtxWebBrowser::tr( "Open URL" ) );
205   setSizeGripEnabled( true );
206
207   myFileName = new QLabel( this );
208   QRadioButton* rbOpen = new QRadioButton( QtxWebBrowser::tr( "Open in" ), this );
209   QRadioButton* rbSave = new QRadioButton( QtxWebBrowser::tr( "Save file" ), this );
210   myBrowse = new QPushButton( QtxWebBrowser::tr( "&Browse..." ),     this );
211   myRepeat = new QCheckBox( QtxWebBrowser::tr( "Use this program for all files of this type" ), this );
212
213   myAction = new QButtonGroup( this );
214   myAction->addButton( rbOpen, mOpen );
215   myAction->addButton( rbSave, mSave );
216
217   QPushButton* btnOk     = new QPushButton( QtxWebBrowser::tr( "&OK" ),     this );
218   QPushButton* btnCancel = new QPushButton( QtxWebBrowser::tr( "&Cancel" ), this );
219
220   QFont f = myFileName->font(); f.setBold( true ); myFileName->setFont( f );
221
222   QHBoxLayout* btnLayout = new QHBoxLayout;
223   btnLayout->addWidget( btnOk );
224   btnLayout->addStretch();
225   btnLayout->addWidget( btnCancel );
226
227   QGridLayout* l = new QGridLayout( this );
228   l->addWidget( new QLabel( QtxWebBrowser::tr( "You are opening the file" ), this ), 
229                             0, 0, 1, 4 );
230   l->addWidget( myFileName, 1, 1, 1, 3 );
231   l->addWidget( new QLabel( QtxWebBrowser::tr( "Please choose the action to be done" ), this ), 
232                             3, 0, 1, 4 );
233   l->addWidget( rbOpen,     4, 1, 1, 1 );
234   l->addWidget( myBrowse,   4, 2, 1, 1 );
235   l->addWidget( rbSave,     5, 1, 1, 3 );
236   l->addWidget( myRepeat,   6, 1, 1, 3 );
237   l->addLayout( btnLayout,  7, 0, 1, 4 );
238   l->setRowMinimumHeight( 2, 10 );
239
240   connect( myAction,  SIGNAL( buttonClicked( int ) ), this, SLOT( setAction( int ) ) );
241   connect( myBrowse,  SIGNAL( clicked() ), this, SLOT( browse() ) );
242   connect( btnOk,     SIGNAL( clicked() ), this, SLOT( accept() ) );
243   connect( btnCancel, SIGNAL( clicked() ), this, SLOT( reject() ) );
244
245   myFileName->setText( QFileInfo( fileName ).fileName() );
246   myAction->button( action )->click();
247 }
248
249 /*!
250   \brief Destructor
251 */
252 QtxWebBrowser::Downloader::~Downloader()
253 {
254 }
255
256 /*!
257   \brief Get action selected by the user
258   \return action being selected:
259   - 0: open file
260   - 1: save file
261 */
262 int QtxWebBrowser::Downloader::action() const
263 {
264   return myAction->checkedId();
265 }
266
267 /*!
268   \brief Get "repeat action for all such files" flag status
269   \return \c true if chosen action should be automatically done for all files of given type
270   or \c false otherwise
271 */
272 bool QtxWebBrowser::Downloader::isRepeatAction() const
273 {
274   return myRepeat->isChecked();
275 }
276
277 /*!
278   \brief Get program to be used to open chosen file
279   \return path to the program
280 */
281 QString QtxWebBrowser::Downloader::program() const
282 {
283   return myProgram;
284 }
285
286 /*!
287   \brief Set current action
288   \param action action to be done for the file:
289   - 0: open file
290   - 1: save file
291 */
292 void QtxWebBrowser::Downloader::setAction( int action )
293 {
294   myBrowse->setEnabled( action == mOpen );
295 }
296
297 /*!
298   \brief Browse program to be used to open the file
299 */
300 void QtxWebBrowser::Downloader::browse()
301 {
302   QString program = QFileDialog::getOpenFileName( this, QtxWebBrowser::tr( "Choose program" ), myProgram );
303   if ( !program.isEmpty() ) myProgram = program;
304 }
305
306
307 /*!
308   \class QtxWebBrowser
309
310   \brief The QtxWebBrowser provides a window that can display html pages from local file system.
311   
312   Only one instance of the QtxWebBrowser class can be created. To access the browser 
313   window, use static method QtxWebBrowser::webBrowser(), which creates an
314   instance of the QtxWebBrowser widget (if it is not yet created) and returns a
315   pointer to it.
316
317   You should not destroy this instance - it is done automatically after
318   closing of the browser window. To close window programmatically use 
319   method close().
320
321   Optionally resource manager can be specified to automatically store
322   action (open/save) and program to be used to download files in the
323   application preferences.
324
325   The following sample demonstrates how to use web browser.
326   In this code the browser window is created, /data/index.html file is opened
327   and scrolled to the "anchor1" anchor on this page.
328
329   \code
330   // initialize application
331   // - set resource manager
332   QtxWebBrowser::setResourceMgr(myResourceMgr);
333   // ...
334   // show HTML page
335   QtxWebBrowser::loadUrl("file:///data/index.html", "anchor1");
336   \endcode
337 */
338
339 //! The only one instance of web browser
340 QtxWebBrowser* QtxWebBrowser::myBrowser = 0;
341
342 //! Resources manager
343 QtxResourceMgr* QtxWebBrowser::myResourceMgr = 0;
344
345 /*!
346   \brief Constructor.
347   Construct the web browser.
348 */
349 QtxWebBrowser::QtxWebBrowser( ) : QMainWindow( 0 )
350 {
351   Q_INIT_RESOURCE( Qtx );
352
353   setAttribute( Qt::WA_DeleteOnClose );
354   statusBar();
355
356   QWidget* frame = new QWidget( this );
357
358   myWebView = new WebView( frame );
359
360   myWebView->pageAction( WebPage::Copy )->setShortcut( QKeySequence::Copy );
361   myWebView->addAction( myWebView->pageAction( WebPage::Copy ) );
362 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
363   myWebView->pageAction( WebPage::OpenLinkInNewWindow )->setVisible( false );
364 #endif  
365   myWebView->pageAction( WebPage::Back )->setText( tr( "Go Back" ) );
366   myWebView->pageAction( WebPage::Forward )->setText( tr( "Go Forward" ) );
367   myWebView->pageAction( WebPage::Reload )->setText( tr( "Refresh" ) );
368 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
369   myWebView->page()->setLinkDelegationPolicy( WebPage::DelegateAllLinks );
370 #endif
371   
372   myFindPanel = new QtxSearchTool( frame, myWebView,
373 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
374                                    QtxSearchTool::Basic | QtxSearchTool::Case | QtxSearchTool::Wrap,
375 #else
376                                    QtxSearchTool::Basic | QtxSearchTool::Case,
377 #endif                             
378                                    Qt::Horizontal );
379   myFindPanel->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
380   myFindPanel->setActivators( QtxSearchTool::SlashKey );
381   myFindPanel->setSearcher( new Searcher( myWebView ) );
382   myFindPanel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
383
384   QToolBar* toolbar = addToolBar( tr( "Navigation" ) );
385   toolbar->addAction( myWebView->pageAction( WebPage::Back ) );
386   toolbar->addAction( myWebView->pageAction( WebPage::Forward ) );
387   toolbar->addAction( myWebView->pageAction( WebPage::Reload ) );
388
389   QMenu* fileMenu = menuBar()->addMenu( tr( "&File" ) );
390   fileMenu->addAction( QPixmap( ":/images/open.png" ), tr( "&Open..." ), 
391                        this, SLOT( open() ),
392                        QKeySequence( QKeySequence::Open ) );
393   fileMenu->addSeparator();
394   fileMenu->addAction( myWebView->pageAction( WebPage::Back ) );
395   fileMenu->addAction( myWebView->pageAction( WebPage::Forward ) );
396   fileMenu->addAction( myWebView->pageAction( WebPage::Reload ) );
397   fileMenu->addSeparator();
398   fileMenu->addAction( tr( "&Find in text..." ),
399                        myFindPanel, SLOT( find() ),
400                        QKeySequence( QKeySequence::Find ) );
401   fileMenu->addAction( tr( "&Find next" ),
402                        myFindPanel, SLOT( findNext() ),
403                        QKeySequence( QKeySequence::FindNext ) );
404   fileMenu->addAction( tr( "&Find previous" ),
405                        myFindPanel, SLOT( findPrevious() ),
406                        QKeySequence( QKeySequence::FindPrevious ) );
407   fileMenu->addSeparator();
408   fileMenu->addAction( QPixmap( ":/images/close.png" ), tr( "&Close" ),
409                        this, SLOT( close() ) );
410
411   QMenu* helpMenu = menuBar()->addMenu( tr( "&Help" ) );
412   helpMenu->addAction( tr( "&About..." ),
413                        this, SLOT( about() ) );
414   
415   QVBoxLayout* main = new QVBoxLayout( frame );
416   main->addWidget( myWebView );
417   main->addWidget( myFindPanel );
418   main->setMargin( 0 );
419   main->setSpacing( 3 );
420
421   connect( myWebView, SIGNAL( titleChanged( QString ) ), SLOT( adjustTitle() ) ); 
422   connect( myWebView, SIGNAL( loadFinished( bool ) ),    SLOT( finished( bool ) ) );
423   
424   connect( myWebView->pageAction( WebPage::DownloadLinkToDisk ), SIGNAL( triggered() ),
425            SLOT( linkAction() ) );
426 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
427   //QtWebKit case:
428   connect( myWebView, SIGNAL( linkClicked( QUrl ) ),     SLOT( linkClicked( QUrl ) ) );
429   connect( myWebView->page(), SIGNAL( linkHovered( QString, QString, QString ) ), 
430            SLOT( linkHovered( QString, QString, QString ) ) ); 
431   disconnect( myWebView->pageAction( WebPage::OpenLink ), 0, 0, 0 );
432   connect( myWebView->pageAction( WebPage::OpenLink ), SIGNAL( triggered() ),
433            SLOT( linkAction() ) );
434 #else
435   //QtWebEngine (Qt-5.6.0) case:
436   connect( myWebView->page(), SIGNAL( linkHovered( QString ) ), 
437            SLOT( linkHovered( QString ) ) );
438   disconnect( myWebView->pageAction( WebPage::OpenLinkInThisWindow ), 0, 0, 0 );
439   connect( myWebView->pageAction( WebPage::OpenLinkInThisWindow ), SIGNAL( triggered() ),
440            SLOT( linkAction() ) );
441 #endif  
442   setCentralWidget( frame );
443   setFocusProxy( myWebView );
444   setWindowIcon( QPixmap( ":/images/appicon.png" ) );
445   adjustTitle();
446 }
447
448 /*!
449   \brief Destructor.
450 */
451 QtxWebBrowser::~QtxWebBrowser()
452 {
453   myBrowser = 0;
454 }
455
456 /*!
457   \brief Return the only instance of the QtxWebBrowser
458   \return instance of the QtxWebBrowser
459 */
460 QtxWebBrowser* QtxWebBrowser::webBrowser()
461 {
462   if ( !myBrowser )
463     myBrowser = new QtxWebBrowser();
464   return myBrowser;
465 }
466
467 /*!
468   \brief Load given url address and optional scroll to the specified anchor
469   \param url an url address to load
470   \param anchor an anchor to scroll page to
471 */
472 void QtxWebBrowser::loadUrl( const QString& url, const QString& anchor )
473 {
474   QString anUrl = url;
475   if( !anchor.isEmpty() ) anUrl += "#" + anchor;
476
477   Qtx::alignWidget( webBrowser(), (QWidget*)QApplication::desktop(), Qtx::AlignCenter );
478
479   QtxWebBrowser* browser = webBrowser();
480   browser->show();
481   browser->load( anUrl );
482   browser->setFocus();
483   browser->activateWindow();
484   browser->raise();
485 }
486
487 /*!
488   \brief Shutdown help browser
489 */
490 void QtxWebBrowser::shutdown()
491 {
492   if ( myBrowser )
493     myBrowser->close();
494 }
495
496 /*!
497   \brief Set resource manager
498   \param resMgr resource manager
499 */
500 void QtxWebBrowser::setResourceMgr( QtxResourceMgr* resMgr )
501 {
502   myResourceMgr = resMgr;
503 }
504
505 /*!
506   \brief Get resource manager
507   \return resource manager
508 */
509 QtxResourceMgr* QtxWebBrowser::resourceMgr() const
510 {
511   return myResourceMgr;
512 }
513
514 /*!
515   Shows About dialog box
516 */
517 void QtxWebBrowser::about()
518 {
519   QMessageBox::about( this, tr( "About %1" ).arg( tr( "Help Browser" ) ),
520                       QString( "SALOME %1" ).arg( tr( "Help Browser" ) ) );
521 }
522
523 /*!
524   \brief Called when users activated any link at the page
525   \param url URL being clicked
526   \internal
527 */
528 void QtxWebBrowser::linkClicked( const QUrl& url )
529 {
530 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
531   myWebView->page()->setLinkDelegationPolicy( WebPage::DontDelegateLinks );
532 #endif  
533   myWebView->load( url );
534 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)  
535   myWebView->page()->setLinkDelegationPolicy( WebPage::DelegateAllLinks );
536 #endif  
537 }
538
539 /*!
540   \brief Called when link is hovered
541   \param link link being hovered
542   \param title link title (if it is specified in the markup)
543   \param content provides text within the link element, e.g., text inside an HTML anchor tag
544   \internal
545 */
546
547 void QtxWebBrowser::linkHovered( const QString& link, const QString& /*title*/, const QString& /*context*/ )
548 {
549   linkHovered(link);
550 }
551
552 void QtxWebBrowser::linkHovered( const QString& link)
553 {
554   QUrl url = link;
555   if ( !link.isEmpty() && isLocalFile( url ) ) myLastUrl = url;
556   statusBar()->showMessage( link );  
557 }
558
559 /*!
560   \brief Update title of the window
561   \internal
562 */
563 void QtxWebBrowser::adjustTitle()
564 {
565   QString title = tr( "Help Browser" );
566   if ( !myWebView->title().isEmpty() ) title += QString( " [%1]" ).arg( myWebView->title() );
567   setWindowTitle( title );
568 }
569
570 /*
571   \brief Called when link is processed by browser
572   \param ok operation status: \c true is URL is correctly processed, \c false otherwise
573 */
574 void QtxWebBrowser::finished( bool ok )
575 {
576   if ( !ok && !myLastUrl.isEmpty() ) {
577     if ( isLocalFile( myLastUrl ) ) {
578       QString filename = myLastUrl.path();
579       QString extension = QFileInfo( filename ).suffix();
580       if ( extension == "html" || extension == "htm" ) return;
581       openLink( filename );
582     }
583   }
584 }
585
586 /*
587   \brief Called when link is processed from browser via popup menu actions
588 */
589 void QtxWebBrowser::linkAction()
590 {
591   QObject* s = sender();
592   if ( s == myWebView->pageAction( WebPage::DownloadLinkToDisk ) ) {
593     saveLink( myLastUrl.path() );
594   }
595 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
596   if ( s == myWebView->pageAction( WebPage::OpenLink ) ) {
597 #else
598   if ( s == myWebView->pageAction( WebPage::OpenLinkInThisWindow ) ) {  
599 #endif    
600     QString fileName  = myLastUrl.path();
601     QString extension = QFileInfo( fileName ).suffix();
602     if ( extension != "html" && extension != "htm" ) {
603       openLink( fileName, true );
604     }
605     else {
606       linkClicked( myLastUrl );
607     }
608   }
609 }
610
611 /*!
612   \brief Open file
613   \param fileName link to the file being opened
614   Opens dialog box to allow the user to choose the program to be used to open the file.
615 */
616 void QtxWebBrowser::openLink( const QString& fileName, bool force )
617 {
618   QString extension = QFileInfo( fileName ).suffix();
619   int defAction = Downloader::mOpen;
620   bool defRepeat = false;
621   QString defProgram;
622   QString resSection   = QString( "%1:%2" ).arg( "web_browser" ).arg( extension );
623   QString actionParam  = "action";
624   QString programParam = "program";
625   QString repeatParam  = "repeat";
626   
627   if ( !extension.isEmpty() && myResourceMgr ) {
628     defAction  = myResourceMgr->integerValue( resSection, actionParam, defAction );
629     defRepeat  = myResourceMgr->booleanValue( resSection, repeatParam, defRepeat );
630     defProgram = myResourceMgr->stringValue( resSection, programParam, defProgram );
631   }
632   
633   if ( force || !defRepeat || ( defAction == Downloader::mOpen && defProgram.isEmpty() ) ) {
634     Downloader downloader( fileName, defAction, defProgram, this );
635     if ( !downloader.exec() ) return;
636     defAction  = downloader.action();
637     defRepeat  = downloader.isRepeatAction();
638     defProgram = downloader.program();
639     if ( myResourceMgr ) {
640       myResourceMgr->setValue( resSection, actionParam, defAction );
641       myResourceMgr->setValue( resSection, repeatParam, defRepeat );
642       if ( defAction == Downloader::mOpen )
643         myResourceMgr->setValue( resSection, programParam, defProgram );
644     }
645   }
646   switch( defAction ) {
647   case Downloader::mOpen:
648     if ( !defProgram.isEmpty() ) {
649       QStringList parameters;
650 #ifdef WIN32
651       QString cmd = defProgram;
652 #else
653       // If Salome Qt version is lower than the system one, on KDE an unresolved symbol is raised
654       // In this case, we can try to launch the pdf viewer after unsetting the LD_LIBRARY_PATH environnement variable
655       QString cmd = "env";
656       parameters << "LD_LIBRARY_PATH=/usr/lib:/usr/lib64";
657       parameters << defProgram;
658 #endif
659       parameters << QFileInfo( myLastUrl.path() ).absoluteFilePath();
660       QProcess::startDetached( cmd, parameters );
661     }
662     break;
663   case Downloader::mSave:
664     {
665       saveLink( fileName );
666     }
667     break;
668   default:
669     break;
670   }
671 }
672
673 /*!
674   \brief Load URL
675   \param url path to the file to be opened in the browser
676 */
677 void QtxWebBrowser::load( const QString& link )
678 {
679   QString linkPath = link;
680   linkPath.replace('\\', '/');
681   QUrl url = linkPath;
682   if ( !url.isEmpty() ) {
683     if ( url.scheme().isEmpty() ) url.setScheme( "file" );
684     myWebView->load( url );
685   }
686 }
687
688 /*!
689   \brief Save file
690   \param fileName link to the file being saved
691   Shows "Save file" standard dialog box to allow user to choose where to save the file.
692 */
693 void QtxWebBrowser::saveLink( const QString& fileName )
694 {
695   QString newFileName = QFileDialog::getSaveFileName( this, tr( "Save file" ), fileName, 
696                                                       QString( "*.%1" ).arg( QFileInfo( fileName ).suffix() ) );
697   if ( !newFileName.isEmpty() && 
698        QFileInfo( newFileName ).canonicalFilePath() != QFileInfo( fileName ).canonicalFilePath() ) {
699     QFile toFile( newFileName );
700     QFile fromFile( fileName );
701     if (( toFile.exists() && !toFile.remove() ) ||
702         ( !fromFile.copy( newFileName ) ))
703       QMessageBox::warning( this, tr( "Error"), tr( "Can't save file:\n%1" ).arg( newFileName ) );
704   }
705 }
706
707 /*!
708   \brief Open file
709   Shows "Open file" standard dialog box to allow user to choose file to open.
710 */
711 void QtxWebBrowser::open()
712 {
713   QString url;
714   if ( isLocalFile( myWebView->url() ) ) url = myWebView->url().path();
715   url = QFileDialog::getOpenFileName( this, tr( "Open file" ), url, "HTML files (*.html *.htm);; All files (*)" );
716   if ( !url.isEmpty() ) load( url );
717 }