Salome HOME
Merge from V6_main_20120808 08Aug12
[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   myWebView->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks );
158   myFindPanel = new QtxSearchTool( frame, myWebView,
159                                    QtxSearchTool::Basic | QtxSearchTool::Case | QtxSearchTool::Wrap, 
160                                    Qt::Horizontal );
161   myFindPanel->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
162   myFindPanel->setActivators( QtxSearchTool::SlashKey );
163   myFindPanel->setSearcher( new WebViewSearcher( myWebView ) );
164   myFindPanel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
165
166   myToolbar = addToolBar( tr( "Navigation" ) );
167   myToolbar->addAction( myWebView->pageAction( QWebPage::Back ) );
168   myToolbar->addAction( myWebView->pageAction( QWebPage::Forward ) );
169
170   myMenus[ File ]        = menuBar()->addMenu( tr( "&File" ) );
171   myActions[ Find ]      = myMenus[ File ]->addAction( tr( "&Find in text..." ), myFindPanel, SLOT( find() ),         QKeySequence( QKeySequence::Find ) );
172   myActions[ FindNext ]  = myMenus[ File ]->addAction( tr( "&Find next" ),       myFindPanel, SLOT( findNext() ),     QKeySequence( QKeySequence::FindNext ) );
173   myActions[ FindPrev ]  = myMenus[ File ]->addAction( tr( "&Find previous" ),   myFindPanel, SLOT( findPrevious() ), QKeySequence( QKeySequence::FindPrevious ) );
174   myMenus[ File ]->addSeparator();
175   myActions[ Close ]     = myMenus[ File ]->addAction( tr( "&Close" ),           this, SLOT( close() ) );
176
177   QVBoxLayout* main = new QVBoxLayout( frame );
178   main->addWidget( myWebView );
179   main->addWidget( myFindPanel );
180   main->setMargin( 0 );
181   main->setSpacing( 3 );
182
183   connect( myWebView, SIGNAL( titleChanged( QString ) ), SLOT( adjustTitle() ) ); 
184   connect( myWebView, SIGNAL( linkClicked( QUrl ) ),     SLOT( linkClicked( QUrl ) ) ); 
185   connect( myWebView->page(), SIGNAL( linkHovered( QString, QString, QString ) ), SLOT( linkHovered( QString, QString, QString ) ) ); 
186   
187   setCentralWidget( frame );
188   setFocusProxy( myWebView );
189   updateData();
190   qAddPostRoutine( QtxWebBrowser::clearData );
191 }
192
193 /*!
194   \brief Destructor.
195 */
196 QtxWebBrowser::~QtxWebBrowser()
197 {
198   myBrowser = 0;
199 }
200
201 /*!
202   \brief Return the only instance of the QtxWebBrowser
203   \return instance of the QtxWebBrowser
204 */
205 QtxWebBrowser* QtxWebBrowser::webBrowser()
206 {
207   if ( !myBrowser )
208     myBrowser = new QtxWebBrowser();
209   return myBrowser;
210 }
211
212 /*!
213   \brief Load given url address and optional scroll to the specified anchor
214   \param url an url address to load
215   \param anchor an anchor to scroll page to
216 */
217 void QtxWebBrowser::loadUrl( const QString& url, const QString& anchor )
218 {
219   QString anUrl = url;
220   if( !anchor.isEmpty() ) anUrl += "#" + anchor;
221   anUrl.replace('\\', '/');
222
223   Qtx::alignWidget( webBrowser(), (QWidget*)QApplication::desktop(), Qtx::AlignCenter );
224
225   webBrowser()->show();
226   webBrowser()->myWebView->load( QUrl( anUrl ) );
227   webBrowser()->setFocus();
228   webBrowser()->activateWindow();
229   webBrowser()->raise();
230 }
231
232 /*!
233   \brief  Set browser settings from.
234
235   This method can be used to setup the browser properties.
236   - \c "browser:title"         : title of the browser window
237   - \c "browser:icon"          : icon of the browser window
238   - \c "toolbar:title"         : title of the toolbar
239   - \c "menu:file:title"       : File menu of the browser
240   - \c "action:close:title"    : File/Close menu item title
241   - \c "action:close:icon"     : File/Close menu item icon
242   - \c "action:back:title"     : Navigation/Back menu item title
243   - \c "action:back:icon"      : Navigation/Back menu item icon
244   - \c "action:forward:title"  : Navigation/Forward menu item title
245   - \c "action:forward:icon"   : Navigation/Forward menu item icon
246   - \c "action:find:title"     : File/Find menu item title
247   - \c "action:find:icon"      : File/Find menu item icon
248   - \c "action:findnext:title" : File/Find Next menu item title
249   - \c "action:findnext:icon"  : File/Find Next menu item icon
250   - \c "action:findprev:title" : File/Find Previous menu item title
251   - \c "action:findprev:icon"  : File/Find Previous menu item icon
252   
253   \param key name of the property
254   \param val value of the property
255   
256 */
257 void QtxWebBrowser::setData( const QString& key, const QVariant& val )
258 {
259   myData.insert( key, val );
260   if ( myBrowser ) myBrowser->updateData();
261 }
262
263 /*!
264   \brief Get string value by key from the internal data map
265   \param key data key identifier
266   \return string value assigned to the key (null string if data is not assigned to the key)
267   \internal
268 */
269 QString QtxWebBrowser::getStringValue( const QString& key )
270 {
271   QString val;
272   if ( myData.contains( key ) && myData[key].canConvert( QVariant::String ) )
273     val = myData[key].toString();
274   return val;
275 }
276
277 /*!
278   \brief Get icon value by key from the internal data map
279   \param key data key identifier
280   \return icon assigned to the key (null icon if data is not assigned to the key)
281   \internal
282 */
283 QIcon QtxWebBrowser::getIconValue(const QString& key)
284 {
285   QIcon val;
286   if ( myData.contains( key ) ) {
287     if ( myData[key].canConvert( QVariant::Pixmap ) )
288       val = myData[key].value<QPixmap>();
289     else if ( myData[key].canConvert( QVariant::Icon ) )
290       val = myData[key].value<QIcon>();
291   }
292   return val;
293 }
294
295 /*!
296   \brief Update web browser properties from internal data map
297 */
298 void QtxWebBrowser::updateData()
299 {
300   // main title
301   adjustTitle();
302
303   // window icon
304   QIcon icon = getIconValue( "browser:icon" );
305   if ( !icon.isNull() )
306     setWindowIcon( icon );
307
308   // toolbar title
309   QString tbTitle = getStringValue( "toolbar:title" );
310   if ( myToolbar && !tbTitle.isEmpty() )
311     myToolbar->setWindowTitle( tbTitle );
312
313   // File menu
314   QString fmenu = getStringValue( "menu:file:title" );
315   if ( myMenus.contains( File ) && !fmenu.isEmpty() )
316     myMenus[ File ]->setTitle( fmenu );
317
318   // File/Close menu
319   QString closeTlt = getStringValue( "action:close:title" );
320   QIcon closeIco = getIconValue( "action:close:icon" );
321   if ( myActions.contains( Close ) ) {
322     if ( !closeTlt.isEmpty() )
323       myActions[ Close ]->setText( closeTlt );
324     if ( !closeIco.isNull() )
325       myActions[ Close ]->setIcon( closeIco );
326   }
327
328   // Navigation/Go Back menu
329   QString backTlt = getStringValue( "action:back:title" );
330   QIcon backIco = getIconValue( "action:back:icon" );
331   if ( !backTlt.isEmpty() )
332     myWebView->pageAction( QWebPage::Back )->setText( backTlt );
333   if ( !backIco.isNull() )
334     myWebView->pageAction( QWebPage::Back )->setIcon( backIco );
335
336   // Navigation/Go Forward menu
337   QString fwdTlt = getStringValue( "action:forward:title" );
338   QIcon fwdIco = getIconValue( "action:forward:icon" );
339   if ( !fwdTlt.isEmpty() )
340     myWebView->pageAction( QWebPage::Forward )->setText( fwdTlt );
341   if ( !fwdIco.isNull() )
342     myWebView->pageAction( QWebPage::Forward )->setIcon( fwdIco );
343
344   // File/Find menu
345   QString findTlt = getStringValue( "action:find:title" );
346   QIcon findIco = getIconValue( "action:find:icon" );
347   if ( myActions.contains( Find ) ) {
348     if ( !findTlt.isEmpty() )
349       myActions[ Find ]->setText( findTlt );
350     if ( !findIco.isNull() )
351       myActions[ Find ]->setIcon( findIco );
352   }
353
354   // File/Find Next menu
355   QString findNextTlt = getStringValue( "action:findnext:title" );
356   QIcon findNextIco = getIconValue( "action:findnext:icon" );
357   if ( myActions.contains( FindNext ) ) {
358     if ( !findNextTlt.isEmpty() )
359       myActions[ FindNext ]->setText( findNextTlt );
360     if ( !findNextIco.isNull() )
361       myActions[ FindNext ]->setIcon( findNextIco );
362   }
363
364   // File/Find Previous menu
365   QString findPrevTlt = getStringValue( "action:findprev:title" );
366   QIcon findPrevIco = getIconValue( "action:findprev:icon" );
367   if ( myActions.contains( FindPrev ) ) {
368     if ( !findPrevTlt.isEmpty() )
369       myActions[ FindPrev ]->setText( findPrevTlt );
370     if ( !findPrevIco.isNull() )
371       myActions[ FindPrev ]->setIcon( findPrevIco );
372   }
373 }
374
375 /*!
376   \brief Clear internal data map
377   \internal
378 */
379 void QtxWebBrowser::clearData()
380 {
381   myData.clear();
382 }
383
384 /*!
385   \brief Called when users activated any link at the page
386   \param url URL being clicked
387   \internal
388 */
389 void QtxWebBrowser::linkClicked( const QUrl& url )
390 {
391   myWebView->page()->setLinkDelegationPolicy( QWebPage::DontDelegateLinks );
392   myWebView->load( url );
393   if ( url.scheme() == "file" ) {
394     QString filename = url.toLocalFile();
395     if ( QFileInfo( filename ).suffix().toLower() == "pdf" ) {
396 #ifdef WIN32
397       ::system( QString( "start %2" ).arg( filename ).toLatin1().constData() );
398 #else
399       // special processing of PDF files
400       QStringList readers;
401       readers << "xdg-open" << "acroread" << "kpdf" << "kghostview" << "xpdf";
402       foreach ( QString r, readers ) {
403         QString reader = QString( "/usr/bin/%1" ).arg( r );
404         if ( QFileInfo( reader ).exists() ) {
405           ::system( QString( "unset LD_LIBRARY_PATH; %1 %2 &" ).arg( reader ).arg( url.toLocalFile() ).toLatin1().constData() );
406           break;
407         }
408       }
409 #endif // WIN32
410     }
411   }
412   myWebView->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks );
413 }
414
415 /*!
416   \brief Called when link is hovered
417   \param link link being hovered
418   \param title link title (if it is specified in the markup)
419   \param content provides text within the link element, e.g., text inside an HTML anchor tag
420   \internal
421 */
422 void QtxWebBrowser::linkHovered( const QString& link, const QString& /*title*/, const QString& /*context*/ )
423 {
424   statusBar()->showMessage( link );
425 }
426
427 /*!
428   \brief Update title of the window
429   \internal
430 */
431 void QtxWebBrowser::adjustTitle()
432 {
433   QString title = getStringValue( "browser:title" );
434   setWindowTitle( title.isEmpty() ? myWebView->title() : title + QString( " [%1]" ).arg( myWebView->title() ) );
435 }