1 // Copyright (C) 2007-2015 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->pageAction( QWebPage::Reload )->setText( tr( "Refresh" ) );
345 myWebView->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks );
347 myFindPanel = new QtxSearchTool( frame, myWebView,
348 QtxSearchTool::Basic | QtxSearchTool::Case | QtxSearchTool::Wrap,
350 myFindPanel->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
351 myFindPanel->setActivators( QtxSearchTool::SlashKey );
352 myFindPanel->setSearcher( new Searcher( myWebView ) );
353 myFindPanel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
355 QToolBar* toolbar = addToolBar( tr( "Navigation" ) );
356 toolbar->addAction( myWebView->pageAction( QWebPage::Back ) );
357 toolbar->addAction( myWebView->pageAction( QWebPage::Forward ) );
358 toolbar->addAction( myWebView->pageAction( QWebPage::Reload ) );
360 QMenu* fileMenu = menuBar()->addMenu( tr( "&File" ) );
361 fileMenu->addAction( QPixmap( ":/images/open.png" ), tr( "&Open..." ),
362 this, SLOT( open() ),
363 QKeySequence( QKeySequence::Open ) );
364 fileMenu->addSeparator();
365 fileMenu->addAction( myWebView->pageAction( QWebPage::Back ) );
366 fileMenu->addAction( myWebView->pageAction( QWebPage::Forward ) );
367 fileMenu->addAction( myWebView->pageAction( QWebPage::Reload ) );
368 fileMenu->addSeparator();
369 fileMenu->addAction( tr( "&Find in text..." ),
370 myFindPanel, SLOT( find() ),
371 QKeySequence( QKeySequence::Find ) );
372 fileMenu->addAction( tr( "&Find next" ),
373 myFindPanel, SLOT( findNext() ),
374 QKeySequence( QKeySequence::FindNext ) );
375 fileMenu->addAction( tr( "&Find previous" ),
376 myFindPanel, SLOT( findPrevious() ),
377 QKeySequence( QKeySequence::FindPrevious ) );
378 fileMenu->addSeparator();
379 fileMenu->addAction( QPixmap( ":/images/close.png" ), tr( "&Close" ),
380 this, SLOT( close() ) );
382 QMenu* helpMenu = menuBar()->addMenu( tr( "&Help" ) );
383 helpMenu->addAction( tr( "&About..." ),
384 this, SLOT( about() ) );
386 QVBoxLayout* main = new QVBoxLayout( frame );
387 main->addWidget( myWebView );
388 main->addWidget( myFindPanel );
389 main->setMargin( 0 );
390 main->setSpacing( 3 );
392 connect( myWebView, SIGNAL( titleChanged( QString ) ), SLOT( adjustTitle() ) );
393 connect( myWebView, SIGNAL( loadFinished( bool ) ), SLOT( finished( bool ) ) );
394 connect( myWebView, SIGNAL( linkClicked( QUrl ) ), SLOT( linkClicked( QUrl ) ) );
395 connect( myWebView->page(), SIGNAL( linkHovered( QString, QString, QString ) ),
396 SLOT( linkHovered( QString, QString, QString ) ) );
397 connect( myWebView->pageAction( QWebPage::DownloadLinkToDisk ), SIGNAL( triggered() ),
398 SLOT( linkAction() ) );
399 disconnect( myWebView->pageAction( QWebPage::OpenLink ), 0, 0, 0 );
400 connect( myWebView->pageAction( QWebPage::OpenLink ), SIGNAL( triggered() ),
401 SLOT( linkAction() ) );
403 setCentralWidget( frame );
404 setFocusProxy( myWebView );
405 setWindowIcon( QPixmap( ":/images/appicon.png" ) );
412 QtxWebBrowser::~QtxWebBrowser()
418 \brief Return the only instance of the QtxWebBrowser
419 \return instance of the QtxWebBrowser
421 QtxWebBrowser* QtxWebBrowser::webBrowser()
424 myBrowser = new QtxWebBrowser();
429 \brief Load given url address and optional scroll to the specified anchor
430 \param url an url address to load
431 \param anchor an anchor to scroll page to
433 void QtxWebBrowser::loadUrl( const QString& url, const QString& anchor )
436 if( !anchor.isEmpty() ) anUrl += "#" + anchor;
438 Qtx::alignWidget( webBrowser(), (QWidget*)QApplication::desktop(), Qtx::AlignCenter );
440 QtxWebBrowser* browser = webBrowser();
442 browser->load( anUrl );
444 browser->activateWindow();
449 \brief Shutdown help browser
451 void QtxWebBrowser::shutdown()
458 \brief Set resource manager
459 \param resMgr resource manager
461 void QtxWebBrowser::setResourceMgr( QtxResourceMgr* resMgr )
463 myResourceMgr = resMgr;
467 \brief Get resource manager
468 \return resource manager
470 QtxResourceMgr* QtxWebBrowser::resourceMgr() const
472 return myResourceMgr;
476 Shows About dialog box
478 void QtxWebBrowser::about()
480 QMessageBox::about( this, tr( "About %1" ).arg( tr( "Help Browser" ) ),
481 QString( "SALOME %1" ).arg( tr( "Help Browser" ) ) );
485 \brief Called when users activated any link at the page
486 \param url URL being clicked
489 void QtxWebBrowser::linkClicked( const QUrl& url )
491 myWebView->page()->setLinkDelegationPolicy( QWebPage::DontDelegateLinks );
492 myWebView->load( url );
493 myWebView->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks );
497 \brief Called when link is hovered
498 \param link link being hovered
499 \param title link title (if it is specified in the markup)
500 \param content provides text within the link element, e.g., text inside an HTML anchor tag
503 void QtxWebBrowser::linkHovered( const QString& link, const QString& /*title*/, const QString& /*context*/ )
506 if ( !link.isEmpty() && isLocalFile( url ) ) myLastUrl = url;
507 statusBar()->showMessage( link );
511 \brief Update title of the window
514 void QtxWebBrowser::adjustTitle()
516 QString title = tr( "Help Browser" );
517 if ( !myWebView->title().isEmpty() ) title += QString( " [%1]" ).arg( myWebView->title() );
518 setWindowTitle( title );
522 \brief Called when link is processed by browser
523 \param ok operation status: \c true is URL is correctly processed, \c false otherwise
525 void QtxWebBrowser::finished( bool ok )
527 if ( !ok && !myLastUrl.isEmpty() ) {
528 if ( isLocalFile( myLastUrl ) ) {
529 QString filename = myLastUrl.path();
530 QString extension = QFileInfo( filename ).suffix();
531 if ( extension == "html" || extension == "htm" ) return;
532 openLink( filename );
538 \brief Called when link is processed from browser via popup menu actions
540 void QtxWebBrowser::linkAction()
542 QObject* s = sender();
543 if ( s == myWebView->pageAction( QWebPage::DownloadLinkToDisk ) ) {
544 saveLink( myLastUrl.path() );
546 else if ( s == myWebView->pageAction( QWebPage::OpenLink ) ) {
547 QString fileName = myLastUrl.path();
548 QString extension = QFileInfo( fileName ).suffix();
549 if ( extension != "html" && extension != "htm" ) {
550 openLink( fileName, true );
553 linkClicked( myLastUrl );
560 \param fileName link to the file being opened
561 Opens dialog box to allow the user to choose the program to be used to open the file.
563 void QtxWebBrowser::openLink( const QString& fileName, bool force )
565 QString extension = QFileInfo( fileName ).suffix();
566 int defAction = Downloader::mOpen;
567 bool defRepeat = false;
569 QString resSection = QString( "%1:%2" ).arg( "web_browser" ).arg( extension );
570 QString actionParam = "action";
571 QString programParam = "program";
572 QString repeatParam = "repeat";
574 if ( !extension.isEmpty() && myResourceMgr ) {
575 defAction = myResourceMgr->integerValue( resSection, actionParam, defAction );
576 defRepeat = myResourceMgr->booleanValue( resSection, repeatParam, defRepeat );
577 defProgram = myResourceMgr->stringValue( resSection, programParam, defProgram );
580 if ( force || !defRepeat || ( defAction == Downloader::mOpen && defProgram.isEmpty() ) ) {
581 Downloader downloader( fileName, defAction, defProgram, this );
582 if ( !downloader.exec() ) return;
583 defAction = downloader.action();
584 defRepeat = downloader.isRepeatAction();
585 defProgram = downloader.program();
586 if ( myResourceMgr ) {
587 myResourceMgr->setValue( resSection, actionParam, defAction );
588 myResourceMgr->setValue( resSection, repeatParam, defRepeat );
589 if ( defAction == Downloader::mOpen )
590 myResourceMgr->setValue( resSection, programParam, defProgram );
593 switch( defAction ) {
594 case Downloader::mOpen:
595 if ( !defProgram.isEmpty() ) {
596 QStringList parameters;
598 QString cmd = defProgram;
600 // If Salome Qt version is lower than the system one, on KDE an unresolved symbol is raised
601 // In this case, we can try to launch the pdf viewer after unsetting the LD_LIBRARY_PATH environnement variable
603 parameters << "LD_LIBRARY_PATH=/usr/lib:/usr/lib64";
604 parameters << defProgram;
606 parameters << QFileInfo( myLastUrl.path() ).absoluteFilePath();
607 QProcess::startDetached( cmd, parameters );
610 case Downloader::mSave:
612 saveLink( fileName );
622 \param url path to the file to be opened in the browser
624 void QtxWebBrowser::load( const QString& link )
626 QString linkPath = link;
627 linkPath.replace('\\', '/');
629 if ( !url.isEmpty() ) {
630 if ( url.scheme().isEmpty() ) url.setScheme( "file" );
631 myWebView->load( url );
637 \param fileName link to the file being saved
638 Shows "Save file" standard dialog box to allow user to choose where to save the file.
640 void QtxWebBrowser::saveLink( const QString& fileName )
642 QString newFileName = QFileDialog::getSaveFileName( this, tr( "Save file" ), fileName,
643 QString( "*.%1" ).arg( QFileInfo( fileName ).suffix() ) );
644 if ( !newFileName.isEmpty() &&
645 QFileInfo( newFileName ).canonicalFilePath() != QFileInfo( fileName ).canonicalFilePath() ) {
646 QFile toFile( newFileName );
647 QFile fromFile( fileName );
648 if ( toFile.exists() && !toFile.remove() || !fromFile.copy( newFileName ) )
649 QMessageBox::warning( this, tr( "Error"), tr( "Can't save file:\n%1" ).arg( newFileName ) );
655 Shows "Open file" standard dialog box to allow user to choose file to open.
657 void QtxWebBrowser::open()
660 if ( isLocalFile( myWebView->url() ) ) url = myWebView->url().path();
661 url = QFileDialog::getOpenFileName( this, tr( "Open file" ), url, "HTML files (*.html *.htm);; All files (*)" );
662 if ( !url.isEmpty() ) load( url );