1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File: QtxWebBrowser.cxx
24 // Author: Roman NIKOLAEV
26 #include "QtxWebBrowser.h"
27 #include "QtxResourceMgr.h"
28 #include "QtxSearchTool.h"
30 #include <QApplication>
31 #include <QButtonGroup>
33 #include <QFileDialog>
35 #include <QGridLayout>
36 #include <QHBoxLayout>
40 #include <QMessageBox>
41 #include <QPushButton>
42 #include <QRadioButton>
45 #include <QVBoxLayout>
51 bool isLocalFile( const QUrl& url )
53 QFileInfo fi( url.path() );
59 \class QtxWebBrowser::Searcher
60 \brief A class is used with QtxSearchTool in order to search text within the web page
64 class QtxWebBrowser::Searcher : public QtxSearchTool::Searcher
67 Searcher( QWebView* );
70 bool find( const QString&, QtxSearchTool* );
71 bool findNext( const QString&, QtxSearchTool* );
72 bool findPrevious( const QString&, QtxSearchTool* );
73 bool findFirst( const QString&, QtxSearchTool* );
74 bool findLast( const QString&, QtxSearchTool* );
85 QtxWebBrowser::Searcher::Searcher( QWebView* view ) : myView( view )
93 QtxWebBrowser::Searcher::~Searcher()
98 \brief Find specified text
99 \param text text being searched
100 \param st search tool
101 \return \c true if text has been found or \c false otherwise
104 bool QtxWebBrowser::Searcher::find( const QString& text, QtxSearchTool* st )
106 QWebPage::FindFlags fl = 0;
107 if ( st->isCaseSensitive() ) fl = fl | QWebPage::FindCaseSensitively;
108 if ( st->isSearchWrapped() ) fl = fl | QWebPage::FindWrapsAroundDocument;
109 return myView->findText( text, fl );
113 \brief Find next entry of specified text starting from the current position
114 \param text text being searched
115 \param st search tool
116 \return \c true if text has been found or \c false otherwise
119 bool QtxWebBrowser::Searcher::findNext( const QString& text, QtxSearchTool* st )
121 return find( text, st );
125 \brief Find previous entry of specified text starting from the current position
126 \param text text being searched
127 \param st search tool
128 \return \c true if text has been found or \c false otherwise
131 bool QtxWebBrowser::Searcher::findPrevious( const QString& text, QtxSearchTool* st )
133 QWebPage::FindFlags fl = QWebPage::FindBackward;
134 if ( st->isCaseSensitive() ) fl = fl | QWebPage::FindCaseSensitively;
135 if ( st->isSearchWrapped() ) fl = fl | QWebPage::FindWrapsAroundDocument;
136 return myView->findText( text, fl );
140 \brief Find first entry of specified text; does nothing in this implementation
141 \param text text being searched
142 \param st search tool
143 \return \c true if text has been found or \c false otherwise
146 bool QtxWebBrowser::Searcher::findFirst( const QString& /*text*/, QtxSearchTool* /*st*/ )
152 \brief Find last entry of specified text; does nothing in this implementation
153 \param text text being searched
154 \param st search tool
155 \return \c true if text has been found or \c false otherwise
158 bool QtxWebBrowser::Searcher::findLast( const QString& /*text*/, QtxSearchTool* /*st*/)
165 \class QtxWebBrowser::Downloader
166 \brief A dialog box that is used to process file links
172 \param fileName name of the file being opened
173 \param action default action to be used for the file
174 \param program default program to be used to open the file
175 \param parent parent widget
178 QtxWebBrowser::Downloader::Downloader( const QString& fileName, int action, const QString& program, QWidget* parent )
179 : QDialog( parent ), myProgram( program )
182 setWindowTitle( QtxWebBrowser::tr( "Open URL" ) );
183 setSizeGripEnabled( true );
185 myFileName = new QLabel( this );
186 QRadioButton* rbOpen = new QRadioButton( QtxWebBrowser::tr( "Open in" ), this );
187 QRadioButton* rbSave = new QRadioButton( QtxWebBrowser::tr( "Save file" ), this );
188 myBrowse = new QPushButton( QtxWebBrowser::tr( "&Browse..." ), this );
189 myRepeat = new QCheckBox( QtxWebBrowser::tr( "Use this program for all files of this type" ), this );
191 myAction = new QButtonGroup( this );
192 myAction->addButton( rbOpen, mOpen );
193 myAction->addButton( rbSave, mSave );
195 QPushButton* btnOk = new QPushButton( QtxWebBrowser::tr( "&OK" ), this );
196 QPushButton* btnCancel = new QPushButton( QtxWebBrowser::tr( "&Cancel" ), this );
198 QFont f = myFileName->font(); f.setBold( true ); myFileName->setFont( f );
200 QHBoxLayout* btnLayout = new QHBoxLayout;
201 btnLayout->addWidget( btnOk );
202 btnLayout->addStretch();
203 btnLayout->addWidget( btnCancel );
205 QGridLayout* l = new QGridLayout( this );
206 l->addWidget( new QLabel( QtxWebBrowser::tr( "You are opening the file" ), this ),
208 l->addWidget( myFileName, 1, 1, 1, 3 );
209 l->addWidget( new QLabel( QtxWebBrowser::tr( "Please choose the action to be done" ), this ),
211 l->addWidget( rbOpen, 4, 1, 1, 1 );
212 l->addWidget( myBrowse, 4, 2, 1, 1 );
213 l->addWidget( rbSave, 5, 1, 1, 3 );
214 l->addWidget( myRepeat, 6, 1, 1, 3 );
215 l->addLayout( btnLayout, 7, 0, 1, 4 );
216 l->setRowMinimumHeight( 2, 10 );
218 connect( myAction, SIGNAL( buttonClicked( int ) ), this, SLOT( setAction( int ) ) );
219 connect( myBrowse, SIGNAL( clicked() ), this, SLOT( browse() ) );
220 connect( btnOk, SIGNAL( clicked() ), this, SLOT( accept() ) );
221 connect( btnCancel, SIGNAL( clicked() ), this, SLOT( reject() ) );
223 myFileName->setText( QFileInfo( fileName ).fileName() );
224 myAction->button( action )->click();
230 QtxWebBrowser::Downloader::~Downloader()
235 \brief Get action selected by the user
236 \return action being selected:
240 int QtxWebBrowser::Downloader::action() const
242 return myAction->checkedId();
246 \brief Get "repeat action for all such files" flag status
247 \return \c true if chosen action should be automatically done for all files of given type
248 or \c false otherwise
250 bool QtxWebBrowser::Downloader::isRepeatAction() const
252 return myRepeat->isChecked();
256 \brief Get program to be used to open chosen file
257 \return path to the program
259 QString QtxWebBrowser::Downloader::program() const
265 \brief Set current action
266 \param action action to be done for the file:
270 void QtxWebBrowser::Downloader::setAction( int action )
272 myBrowse->setEnabled( action == mOpen );
276 \brief Browse program to be used to open the file
278 void QtxWebBrowser::Downloader::browse()
280 QString program = QFileDialog::getOpenFileName( this, QtxWebBrowser::tr( "Choose program" ), myProgram );
281 if ( !program.isEmpty() ) myProgram = program;
288 \brief The QtxWebBrowser provides a window that can display html pages from local file system.
290 Only one instance of the QtxWebBrowser class can be created. To access the browser
291 window, use static method QtxWebBrowser::webBrowser(), which creates an
292 instance of the QtxWebBrowser widget (if it is not yet created) and returns a
295 You should not destroy this instance - it is done automatically after
296 closing of the browser window. To close window programmatically use
299 Optionally resource manager can be specified to automatically store
300 action (open/save) and program to be used to download files in the
301 application preferences.
303 The following sample demonstrates how to use web browser.
304 In this code the browser window is created, /data/index.html file is opened
305 and scrolled to the "anchor1" anchor on this page.
308 // initialize application
309 // - set resource manager
310 QtxWebBrowser::setResourceMgr(myResourceMgr);
313 QtxWebBrowser::loadUrl("file:///data/index.html", "anchor1");
317 //! The only one instance of web browser
318 QtxWebBrowser* QtxWebBrowser::myBrowser = 0;
320 //! Resources manager
321 QtxResourceMgr* QtxWebBrowser::myResourceMgr = 0;
325 Construct the web browser.
327 QtxWebBrowser::QtxWebBrowser( ) : QMainWindow( 0 )
329 Q_INIT_RESOURCE( Qtx );
331 setAttribute( Qt::WA_DeleteOnClose );
334 QWidget* frame = new QWidget( this );
336 myWebView = new QWebView( frame );
338 myWebView->pageAction( QWebPage::Copy )->setShortcut( QKeySequence::Copy );
339 myWebView->addAction( myWebView->pageAction( QWebPage::Copy ) );
340 myWebView->pageAction( QWebPage::OpenLinkInNewWindow )->setVisible( false );
341 myWebView->pageAction( QWebPage::Back )->setText( tr( "Go Back" ) );
342 myWebView->pageAction( QWebPage::Forward )->setText( tr( "Go Forward" ) );
343 myWebView->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks );
345 myFindPanel = new QtxSearchTool( frame, myWebView,
346 QtxSearchTool::Basic | QtxSearchTool::Case | QtxSearchTool::Wrap,
348 myFindPanel->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
349 myFindPanel->setActivators( QtxSearchTool::SlashKey );
350 myFindPanel->setSearcher( new Searcher( myWebView ) );
351 myFindPanel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
353 QToolBar* toolbar = addToolBar( tr( "Navigation" ) );
354 toolbar->addAction( myWebView->pageAction( QWebPage::Back ) );
355 toolbar->addAction( myWebView->pageAction( QWebPage::Forward ) );
357 QMenu* fileMenu = menuBar()->addMenu( tr( "&File" ) );
358 fileMenu->addAction( QPixmap( ":/images/open.png" ), tr( "&Open..." ),
359 this, SLOT( open() ),
360 QKeySequence( QKeySequence::Open ) );
361 fileMenu->addSeparator();
362 fileMenu->addAction( tr( "&Find in text..." ),
363 myFindPanel, SLOT( find() ),
364 QKeySequence( QKeySequence::Find ) );
365 fileMenu->addAction( tr( "&Find next" ),
366 myFindPanel, SLOT( findNext() ),
367 QKeySequence( QKeySequence::FindNext ) );
368 fileMenu->addAction( tr( "&Find previous" ),
369 myFindPanel, SLOT( findPrevious() ),
370 QKeySequence( QKeySequence::FindPrevious ) );
371 fileMenu->addSeparator();
372 fileMenu->addAction( QPixmap( ":/images/close.png" ), tr( "&Close" ),
373 this, SLOT( close() ) );
375 QMenu* helpMenu = menuBar()->addMenu( tr( "&Help" ) );
376 helpMenu->addAction( tr( "&About..." ),
377 this, SLOT( about() ) );
379 QVBoxLayout* main = new QVBoxLayout( frame );
380 main->addWidget( myWebView );
381 main->addWidget( myFindPanel );
382 main->setMargin( 0 );
383 main->setSpacing( 3 );
385 connect( myWebView, SIGNAL( titleChanged( QString ) ), SLOT( adjustTitle() ) );
386 connect( myWebView, SIGNAL( loadFinished( bool ) ), SLOT( finished( bool ) ) );
387 connect( myWebView, SIGNAL( linkClicked( QUrl ) ), SLOT( linkClicked( QUrl ) ) );
388 connect( myWebView->page(), SIGNAL( linkHovered( QString, QString, QString ) ),
389 SLOT( linkHovered( QString, QString, QString ) ) );
390 connect( myWebView->pageAction( QWebPage::DownloadLinkToDisk ), SIGNAL( activated() ),
391 SLOT( linkAction() ) );
392 disconnect( myWebView->pageAction( QWebPage::OpenLink ), 0, 0, 0 );
393 connect( myWebView->pageAction( QWebPage::OpenLink ), SIGNAL( activated() ),
394 SLOT( linkAction() ) );
396 setCentralWidget( frame );
397 setFocusProxy( myWebView );
398 setWindowIcon( QPixmap( ":/images/appicon.png" ) );
405 QtxWebBrowser::~QtxWebBrowser()
411 \brief Return the only instance of the QtxWebBrowser
412 \return instance of the QtxWebBrowser
414 QtxWebBrowser* QtxWebBrowser::webBrowser()
417 myBrowser = new QtxWebBrowser();
422 \brief Load given url address and optional scroll to the specified anchor
423 \param url an url address to load
424 \param anchor an anchor to scroll page to
426 void QtxWebBrowser::loadUrl( const QString& url, const QString& anchor )
429 if( !anchor.isEmpty() ) anUrl += "#" + anchor;
431 Qtx::alignWidget( webBrowser(), (QWidget*)QApplication::desktop(), Qtx::AlignCenter );
433 QtxWebBrowser* browser = webBrowser();
435 browser->load( anUrl );
437 browser->activateWindow();
442 \brief Shutdown help browser
444 void QtxWebBrowser::shutdown()
451 \brief Set resource manager
452 \param resMgr resource manager
454 void QtxWebBrowser::setResourceMgr( QtxResourceMgr* resMgr )
456 myResourceMgr = resMgr;
460 \brief Get resource manager
461 \return resource manager
463 QtxResourceMgr* QtxWebBrowser::resourceMgr() const
465 return myResourceMgr;
469 Shows About dialog box
471 void QtxWebBrowser::about()
473 QMessageBox::about( this, tr( "About %1" ).arg( tr( "Help Browser" ) ),
474 QString( "SALOME %1" ).arg( tr( "Help Browser" ) ) );
478 \brief Called when users activated any link at the page
479 \param url URL being clicked
482 void QtxWebBrowser::linkClicked( const QUrl& url )
484 myWebView->page()->setLinkDelegationPolicy( QWebPage::DontDelegateLinks );
485 myWebView->load( url );
486 myWebView->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks );
490 \brief Called when link is hovered
491 \param link link being hovered
492 \param title link title (if it is specified in the markup)
493 \param content provides text within the link element, e.g., text inside an HTML anchor tag
496 void QtxWebBrowser::linkHovered( const QString& link, const QString& /*title*/, const QString& /*context*/ )
499 if ( !link.isEmpty() && isLocalFile( url ) ) myLastUrl = url;
500 statusBar()->showMessage( link );
504 \brief Update title of the window
507 void QtxWebBrowser::adjustTitle()
509 QString title = tr( "Help Browser" );
510 if ( !myWebView->title().isEmpty() ) title += QString( " [%1]" ).arg( myWebView->title() );
511 setWindowTitle( title );
515 \brief Called when link is processed by browser
516 \param ok operation status: \c true is URL is correctly processed, \c false otherwise
518 void QtxWebBrowser::finished( bool ok )
520 if ( !ok && !myLastUrl.isEmpty() ) {
521 if ( isLocalFile( myLastUrl ) ) {
522 QString filename = myLastUrl.path();
523 QString extension = QFileInfo( filename ).suffix();
524 if ( extension == "html" || extension == "htm" ) return;
525 openLink( filename );
531 \brief Called when link is processed from browser via popup menu actions
533 void QtxWebBrowser::linkAction()
535 QObject* s = sender();
536 if ( s == myWebView->pageAction( QWebPage::DownloadLinkToDisk ) ) {
537 saveLink( myLastUrl.path() );
539 else if ( s == myWebView->pageAction( QWebPage::OpenLink ) ) {
540 QString fileName = myLastUrl.path();
541 QString extension = QFileInfo( fileName ).suffix();
542 if ( extension != "html" && extension != "htm" ) {
543 openLink( fileName, true );
546 linkClicked( myLastUrl );
553 \param fileName link to the file being opened
554 Opens dialog box to allow the user to choose the program to be used to open the file.
556 void QtxWebBrowser::openLink( const QString& fileName, bool force )
558 QString extension = QFileInfo( fileName ).suffix();
559 int defAction = Downloader::mOpen;
560 bool defRepeat = false;
562 QString resSection = QString( "%1:%2" ).arg( "web_browser" ).arg( extension );
563 QString actionParam = "action";
564 QString programParam = "program";
565 QString repeatParam = "repeat";
567 if ( !extension.isEmpty() && myResourceMgr ) {
568 defAction = myResourceMgr->integerValue( resSection, actionParam, defAction );
569 defRepeat = myResourceMgr->booleanValue( resSection, repeatParam, defRepeat );
570 defProgram = myResourceMgr->stringValue( resSection, programParam, defProgram );
573 if ( force || !defRepeat || ( defAction == Downloader::mOpen && defProgram.isEmpty() ) ) {
574 Downloader downloader( fileName, defAction, defProgram, this );
575 if ( !downloader.exec() ) return;
576 defAction = downloader.action();
577 defRepeat = downloader.isRepeatAction();
578 defProgram = downloader.program();
579 if ( myResourceMgr ) {
580 myResourceMgr->setValue( resSection, actionParam, defAction );
581 myResourceMgr->setValue( resSection, repeatParam, defRepeat );
582 if ( defAction == Downloader::mOpen )
583 myResourceMgr->setValue( resSection, programParam, defProgram );
586 switch( defAction ) {
587 case Downloader::mOpen:
588 if ( !defProgram.isEmpty() ) {
589 QStringList parameters;
591 QString cmd = defProgram;
593 // If Salome Qt version is lower than the system one, on KDE an unresolved symbol is raised
594 // In this case, we can try to launch the pdf viewer after unsetting the LD_LIBRARY_PATH environnement variable
596 parameters << "LD_LIBRARY_PATH=/usr/lib:/usr/lib64";
597 parameters << defProgram;
599 parameters << QFileInfo( myLastUrl.path() ).absoluteFilePath();
600 QProcess::startDetached( cmd, parameters );
603 case Downloader::mSave:
605 saveLink( fileName );
615 \param url path to the file to be opened in the browser
617 void QtxWebBrowser::load( const QString& url )
621 myWebView->load( QUrl( u.replace('\\', '/') ) );
626 \param fileName link to the file being saved
627 Shows "Save file" standard dialog box to allow user to choose where to save the file.
629 void QtxWebBrowser::saveLink( const QString& fileName )
631 QString newFileName = QFileDialog::getSaveFileName( this, tr( "Save file" ), fileName,
632 QString( "*.%1" ).arg( QFileInfo( fileName ).suffix() ) );
633 if ( !newFileName.isEmpty() &&
634 QFileInfo( newFileName ).canonicalFilePath() != QFileInfo( fileName ).canonicalFilePath() ) {
635 QFile toFile( newFileName );
636 QFile fromFile( fileName );
637 if ( toFile.exists() && !toFile.remove() || !fromFile.copy( newFileName ) )
638 QMessageBox::warning( this, tr( "Error"), tr( "Can't save file:\n%1" ).arg( newFileName ) );
644 Shows "Open file" standard dialog box to allow user to choose file to open.
646 void QtxWebBrowser::open()
649 if ( isLocalFile( myWebView->url() ) ) url = myWebView->url().path();
650 url = QFileDialog::getOpenFileName( this, tr( "Open file" ), url, "HTML files (*.html *.htm);; All files (*)" );
651 if ( !url.isEmpty() ) load( url );