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