Salome HOME
d49d08f18519d9e2954e2ab5c18f45ea0f91c12b
[modules/gui.git] / src / Qtx / QtxWebBrowser.cxx
1 // Copyright (C) 2007-2012  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
23 // File:      QtxWebBrowser.cxx
24 // Author:    Roman NIKOLAEV
25 //
26 #include "QtxWebBrowser.h"
27 #include "QtxSearchTool.h"
28
29 #include <QApplication>
30 #include <QFileInfo>
31 #include <QWebView>
32 #include <QMenuBar>
33 #include <QMessageBox>
34 #include <QToolBar>
35 #include <QMenu>
36 #include <QStatusBar>
37 #include <QVBoxLayout>
38
39 /*!
40   \class WebViewSearcher
41   \brief A class is used with QtxSearchTool in order to search text within the web page 
42   \internal
43 */
44 class WebViewSearcher : public QtxSearchTool::Searcher
45 {
46 public:
47   WebViewSearcher( QWebView* );
48   ~WebViewSearcher();
49
50   bool find( const QString&, QtxSearchTool* );
51   bool findNext( const QString&, QtxSearchTool* );
52   bool findPrevious( const QString&, QtxSearchTool* );
53   bool findFirst( const QString&, QtxSearchTool* );
54   bool findLast( const QString&, QtxSearchTool* );
55
56 private:
57   QWebView* myView;
58 };
59
60 WebViewSearcher::WebViewSearcher( QWebView* view ) : myView( view )
61 {
62 }
63
64 WebViewSearcher::~WebViewSearcher()
65 {
66 }
67
68 bool WebViewSearcher::find( const QString& text, QtxSearchTool* st )
69 {
70   QWebPage::FindFlags fl = 0;
71   if ( st->isCaseSensitive() ) fl = fl | QWebPage::FindCaseSensitively;
72   if ( st->isSearchWrapped() ) fl = fl | QWebPage::FindWrapsAroundDocument;
73   return myView->findText( text, fl );
74 }
75
76 bool WebViewSearcher::findNext( const QString& text, QtxSearchTool* st )
77 {
78   return find( text, st );
79 }
80
81 bool WebViewSearcher::findPrevious( const QString& text, QtxSearchTool* st )
82 {
83   QWebPage::FindFlags fl = QWebPage::FindBackward;
84   if ( st->isCaseSensitive() ) fl = fl | QWebPage::FindCaseSensitively;
85   if ( st->isSearchWrapped() ) fl = fl | QWebPage::FindWrapsAroundDocument;
86   return myView->findText( text, fl );
87 }
88
89 bool WebViewSearcher::findFirst( const QString&, QtxSearchTool* )
90 {
91   return false;
92 }
93
94 bool WebViewSearcher::findLast( const QString&, QtxSearchTool* )
95 {
96   return false;
97 }
98
99 /*!
100   \class QtxWebBrowser
101
102   \brief The QtxWebBrowser provides a window that can display html pages.
103   
104   Only one instance of the QtxWebBrowser class can be created. To access the browser 
105   window, use static method QtxWebBrowser::webBrowser(), which creates an
106   instance of the QtxWebBrowser widget (if it is not yet created) and returns a
107   pointer to it.
108
109   You should not destroy this instance - it is done automatically after
110   closing of the browser window. To close window programmatically use 
111   method close().
112
113   To set visual properties of the browser use static method setData().
114
115   The following sample demonstrates how to use web browser.
116   In this code the browser window is created, /data/index.html file is opened
117   and scrolled to the "anchor1" anchor on this page.
118
119   \code
120   int main(int argc, char *argv[])
121   {
122     QApplication app(argc, argv);    
123
124     // set icon, title and menu items.
125     QtxWebBrowser::setData("browser:title",      tr("Web Browser"));
126     QtxWebBrowser::setData("browser:icon",       QPixmap(":/icon.png"));
127     QtxWebBrowser::setData("menu:file:title",    tr("&File"));
128     QtxWebBrowser::setData("action:close:title", tr("&Close"));
129
130     // show HTML page
131     QtxWebBrowser::loadUrl("file:///data/index.html", "anchor1");
132     
133     return app.exec();
134   }
135   \endcode
136
137 */
138
139 //! The only one instance of web browser
140 QtxWebBrowser* QtxWebBrowser::myBrowser = 0;
141
142 //! Internal data map to store resources of the browser.
143 QMap<QString, QVariant> QtxWebBrowser::myData;
144
145 /*!
146   \brief Constructor.
147  
148   Construct the web browser.
149 */
150 QtxWebBrowser::QtxWebBrowser() : QMainWindow( 0 )
151 {
152   setAttribute( Qt::WA_DeleteOnClose );
153   statusBar();
154
155   QWidget* frame = new QWidget( this );
156
157   myWebView = new QWebView( frame );
158
159   QAction *copyAction = myWebView->pageAction(QWebPage::Copy);
160   copyAction->setShortcut(QKeySequence::Copy);
161   myWebView->addAction(copyAction);
162
163
164   myWebView->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks );
165   myFindPanel = new QtxSearchTool( frame, myWebView,
166                                    QtxSearchTool::Basic | QtxSearchTool::Case | QtxSearchTool::Wrap, 
167                                    Qt::Horizontal );
168   myFindPanel->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
169   myFindPanel->setActivators( QtxSearchTool::SlashKey );
170   myFindPanel->setSearcher( new WebViewSearcher( myWebView ) );
171   myFindPanel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
172
173   myToolbar = addToolBar( tr( "Navigation" ) );
174   myToolbar->addAction( myWebView->pageAction( QWebPage::Back ) );
175   myToolbar->addAction( myWebView->pageAction( QWebPage::Forward ) );
176
177   myMenus[ File ]        = menuBar()->addMenu( tr( "&File" ) );
178   myActions[ Find ]      = myMenus[ File ]->addAction( tr( "&Find in text..." ), myFindPanel, SLOT( find() ),         QKeySequence( QKeySequence::Find ) );
179   myActions[ FindNext ]  = myMenus[ File ]->addAction( tr( "&Find next" ),       myFindPanel, SLOT( findNext() ),     QKeySequence( QKeySequence::FindNext ) );
180   myActions[ FindPrev ]  = myMenus[ File ]->addAction( tr( "&Find previous" ),   myFindPanel, SLOT( findPrevious() ), QKeySequence( QKeySequence::FindPrevious ) );
181   myMenus[ File ]->addSeparator();
182   myActions[ Close ]     = myMenus[ File ]->addAction( tr( "&Close" ),           this, SLOT( close() ) );
183
184   QVBoxLayout* main = new QVBoxLayout( frame );
185   main->addWidget( myWebView );
186   main->addWidget( myFindPanel );
187   main->setMargin( 0 );
188   main->setSpacing( 3 );
189
190   connect( myWebView, SIGNAL( titleChanged( QString ) ), SLOT( adjustTitle() ) ); 
191   connect( myWebView, SIGNAL( linkClicked( QUrl ) ),     SLOT( linkClicked( QUrl ) ) ); 
192   connect( myWebView->page(), SIGNAL( linkHovered( QString, QString, QString ) ), SLOT( linkHovered( QString, QString, QString ) ) ); 
193   
194   setCentralWidget( frame );
195   setFocusProxy( myWebView );
196   updateData();
197   qAddPostRoutine( QtxWebBrowser::clearData );
198 }
199
200 /*!
201   \brief Destructor.
202 */
203 QtxWebBrowser::~QtxWebBrowser()
204 {
205   myBrowser = 0;
206 }
207
208 /*!
209   \brief Return the only instance of the QtxWebBrowser
210   \return instance of the QtxWebBrowser
211 */
212 QtxWebBrowser* QtxWebBrowser::webBrowser()
213 {
214   if ( !myBrowser )
215     myBrowser = new QtxWebBrowser();
216   return myBrowser;
217 }
218
219 /*!
220   \brief Load given url address and optional scroll to the specified anchor
221   \param url an url address to load
222   \param anchor an anchor to scroll page to
223 */
224 void QtxWebBrowser::loadUrl( const QString& url, const QString& anchor )
225 {
226   QString anUrl = url;
227   if( !anchor.isEmpty() ) anUrl += "#" + anchor;
228   anUrl.replace('\\', '/');
229
230   Qtx::alignWidget( webBrowser(), (QWidget*)QApplication::desktop(), Qtx::AlignCenter );
231
232   webBrowser()->show();
233   webBrowser()->myWebView->load( QUrl( anUrl ) );
234   webBrowser()->setFocus();
235   webBrowser()->activateWindow();
236   webBrowser()->raise();
237 }
238
239 /*!
240   \brief  Set browser settings from.
241
242   This method can be used to setup the browser properties.
243   - \c "browser:title"         : title of the browser window
244   - \c "browser:icon"          : icon of the browser window
245   - \c "toolbar:title"         : title of the toolbar
246   - \c "menu:file:title"       : File menu of the browser
247   - \c "action:close:title"    : File/Close menu item title
248   - \c "action:close:icon"     : File/Close menu item icon
249   - \c "action:back:title"     : Navigation/Back menu item title
250   - \c "action:back:icon"      : Navigation/Back menu item icon
251   - \c "action:forward:title"  : Navigation/Forward menu item title
252   - \c "action:forward:icon"   : Navigation/Forward menu item icon
253   - \c "action:find:title"     : File/Find menu item title
254   - \c "action:find:icon"      : File/Find menu item icon
255   - \c "action:findnext:title" : File/Find Next menu item title
256   - \c "action:findnext:icon"  : File/Find Next menu item icon
257   - \c "action:findprev:title" : File/Find Previous menu item title
258   - \c "action:findprev:icon"  : File/Find Previous menu item icon
259   
260   \param key name of the property
261   \param val value of the property
262   
263 */
264 void QtxWebBrowser::setData( const QString& key, const QVariant& val )
265 {
266   myData.insert( key, val );
267   if ( myBrowser ) myBrowser->updateData();
268 }
269
270 /*!
271   \brief Get string value by key from the internal data map
272   \param key data key identifier
273   \return string value assigned to the key (null string if data is not assigned to the key)
274   \internal
275 */
276 QString QtxWebBrowser::getStringValue( const QString& key )
277 {
278   QString val;
279   if ( myData.contains( key ) && myData[key].canConvert( QVariant::String ) )
280     val = myData[key].toString();
281   return val;
282 }
283
284 /*!
285   \brief Get icon value by key from the internal data map
286   \param key data key identifier
287   \return icon assigned to the key (null icon if data is not assigned to the key)
288   \internal
289 */
290 QIcon QtxWebBrowser::getIconValue(const QString& key)
291 {
292   QIcon val;
293   if ( myData.contains( key ) ) {
294     if ( myData[key].canConvert( QVariant::Pixmap ) )
295       val = myData[key].value<QPixmap>();
296     else if ( myData[key].canConvert( QVariant::Icon ) )
297       val = myData[key].value<QIcon>();
298   }
299   return val;
300 }
301
302 /*!
303   \brief Update web browser properties from internal data map
304 */
305 void QtxWebBrowser::updateData()
306 {
307   // main title
308   adjustTitle();
309
310   // window icon
311   QIcon icon = getIconValue( "browser:icon" );
312   if ( !icon.isNull() )
313     setWindowIcon( icon );
314
315   // toolbar title
316   QString tbTitle = getStringValue( "toolbar:title" );
317   if ( myToolbar && !tbTitle.isEmpty() )
318     myToolbar->setWindowTitle( tbTitle );
319
320   // File menu
321   QString fmenu = getStringValue( "menu:file:title" );
322   if ( myMenus.contains( File ) && !fmenu.isEmpty() )
323     myMenus[ File ]->setTitle( fmenu );
324
325   // File/Close menu
326   QString closeTlt = getStringValue( "action:close:title" );
327   QIcon closeIco = getIconValue( "action:close:icon" );
328   if ( myActions.contains( Close ) ) {
329     if ( !closeTlt.isEmpty() )
330       myActions[ Close ]->setText( closeTlt );
331     if ( !closeIco.isNull() )
332       myActions[ Close ]->setIcon( closeIco );
333   }
334
335   // Navigation/Go Back menu
336   QString backTlt = getStringValue( "action:back:title" );
337   QIcon backIco = getIconValue( "action:back:icon" );
338   if ( !backTlt.isEmpty() )
339     myWebView->pageAction( QWebPage::Back )->setText( backTlt );
340   if ( !backIco.isNull() )
341     myWebView->pageAction( QWebPage::Back )->setIcon( backIco );
342
343   // Navigation/Go Forward menu
344   QString fwdTlt = getStringValue( "action:forward:title" );
345   QIcon fwdIco = getIconValue( "action:forward:icon" );
346   if ( !fwdTlt.isEmpty() )
347     myWebView->pageAction( QWebPage::Forward )->setText( fwdTlt );
348   if ( !fwdIco.isNull() )
349     myWebView->pageAction( QWebPage::Forward )->setIcon( fwdIco );
350
351   // File/Find menu
352   QString findTlt = getStringValue( "action:find:title" );
353   QIcon findIco = getIconValue( "action:find:icon" );
354   if ( myActions.contains( Find ) ) {
355     if ( !findTlt.isEmpty() )
356       myActions[ Find ]->setText( findTlt );
357     if ( !findIco.isNull() )
358       myActions[ Find ]->setIcon( findIco );
359   }
360
361   // File/Find Next menu
362   QString findNextTlt = getStringValue( "action:findnext:title" );
363   QIcon findNextIco = getIconValue( "action:findnext:icon" );
364   if ( myActions.contains( FindNext ) ) {
365     if ( !findNextTlt.isEmpty() )
366       myActions[ FindNext ]->setText( findNextTlt );
367     if ( !findNextIco.isNull() )
368       myActions[ FindNext ]->setIcon( findNextIco );
369   }
370
371   // File/Find Previous menu
372   QString findPrevTlt = getStringValue( "action:findprev:title" );
373   QIcon findPrevIco = getIconValue( "action:findprev:icon" );
374   if ( myActions.contains( FindPrev ) ) {
375     if ( !findPrevTlt.isEmpty() )
376       myActions[ FindPrev ]->setText( findPrevTlt );
377     if ( !findPrevIco.isNull() )
378       myActions[ FindPrev ]->setIcon( findPrevIco );
379   }
380 }
381
382 /*!
383   \brief Clear internal data map
384   \internal
385 */
386 void QtxWebBrowser::clearData()
387 {
388   myData.clear();
389 }
390
391 /*!
392   \brief Called when users activated any link at the page
393   \param url URL being clicked
394   \internal
395 */
396 void QtxWebBrowser::linkClicked( const QUrl& url )
397 {
398   myWebView->page()->setLinkDelegationPolicy( QWebPage::DontDelegateLinks );
399   myWebView->load( url );
400   if ( url.scheme() == "file" ) {
401     QString filename = url.toLocalFile();
402     if ( QFileInfo( filename ).suffix().toLower() == "pdf" ) {
403       int i = -1;
404 #ifdef WIN32
405       i = ::system( QString( "start %2" ).arg( filename ).toLatin1().constData() );
406 #else
407       // special processing of PDF files
408       QStringList readers;
409       readers << "xdg-open" << "acroread"<< "okular" << "evince" << "kpdf" << "kghostview" << "xpdf";
410       foreach ( QString r, readers ) {
411         QString reader = QString( "/usr/bin/%1" ).arg( r );
412         if ( QFileInfo( reader ).exists() ) {
413           // Warning: the test on the return value of ::system does not work if the command ends with '&'
414           i = ::system( QString( "%1 %2" ).arg( reader ).arg( url.toLocalFile() ).toLatin1().constData() );
415           if (i != 0) {
416             // If Salome Qt version is lower than the system one, on KDE an unresolved symbol is raised
417             // In this case, we can try to launch the pdf viewer after unsetting the LD_LIBRARY_PATH environnement variable
418             i = ::system( QString( "unset LD_LIBRARY_PATH ; %1 %2" ).arg( reader ).arg( url.toLocalFile() ).toLatin1().constData() );
419           }
420           if (i == 0) {
421             break;
422           }
423         }
424       }
425 #endif // WIN32
426       if (i != 0) {
427         QMessageBox::warning(this, tr("Opening pdf file"), tr("Impossible to open the pdf file: no viewer found or compatible."));
428       }
429     }
430   }
431   myWebView->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks );
432 }
433
434 /*!
435   \brief Called when link is hovered
436   \param link link being hovered
437   \param title link title (if it is specified in the markup)
438   \param content provides text within the link element, e.g., text inside an HTML anchor tag
439   \internal
440 */
441 void QtxWebBrowser::linkHovered( const QString& link, const QString& /*title*/, const QString& /*context*/ )
442 {
443   statusBar()->showMessage( link );
444 }
445
446 /*!
447   \brief Update title of the window
448   \internal
449 */
450 void QtxWebBrowser::adjustTitle()
451 {
452   QString title = getStringValue( "browser:title" );
453   setWindowTitle( title.isEmpty() ? myWebView->title() : title + QString( " [%1]" ).arg( myWebView->title() ) );
454 }