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