1 // Copyright (C) 2007-2016 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>
46 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
49 #include <QWebEngineView>
54 // Since from Qt 5.6.0 version QtWebKit tool was removed,
55 // QtxWebBroswer is ported on QtWebEngine. So if it is built with Qt-5.6.0
56 // and newer, it uses QtWebEngine. But for Qt-5.5.1 and Qt4 QtWebKit tool
57 // is used, to provide backward compatibility.
61 bool isLocalFile( const QUrl& url )
63 QFileInfo fi( url.path() );
69 \class QtxWebBrowser::Searcher
70 \brief A class is used with QtxSearchTool in order to search text within the web page
74 class QtxWebBrowser::Searcher : public QtxSearchTool::Searcher
80 bool find( const QString&, QtxSearchTool* );
81 bool findNext( const QString&, QtxSearchTool* );
82 bool findPrevious( const QString&, QtxSearchTool* );
83 bool findFirst( const QString&, QtxSearchTool* );
84 bool findLast( const QString&, QtxSearchTool* );
95 QtxWebBrowser::Searcher::Searcher( WebView* view ) : myView( view )
103 QtxWebBrowser::Searcher::~Searcher()
108 \brief Find specified text
109 \param text text being searched
110 \param st search tool
111 \return \c true if text has been found or \c false otherwise
114 bool QtxWebBrowser::Searcher::find( const QString& text, QtxSearchTool* st )
116 WebPage::FindFlags fl = 0;
117 if ( st->isCaseSensitive() ) fl = fl | WebPage::FindCaseSensitively;
118 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
119 if ( st->isSearchWrapped() ) fl = fl | WebPage::FindWrapsAroundDocument;
120 return myView->findText( text, fl );
122 myView->findText( text, fl, [this](bool found) { return found; });
127 \brief Find next entry of specified text starting from the current position
128 \param text text being searched
129 \param st search tool
130 \return \c true if text has been found or \c false otherwise
133 bool QtxWebBrowser::Searcher::findNext( const QString& text, QtxSearchTool* st )
135 return find( text, st );
139 \brief Find previous entry of specified text starting from the current position
140 \param text text being searched
141 \param st search tool
142 \return \c true if text has been found or \c false otherwise
145 bool QtxWebBrowser::Searcher::findPrevious( const QString& text, QtxSearchTool* st )
147 WebPage::FindFlags fl = WebPage::FindBackward;
148 if ( st->isCaseSensitive() ) fl = fl | WebPage::FindCaseSensitively;
149 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
150 if ( st->isSearchWrapped() ) fl = fl | WebPage::FindWrapsAroundDocument;
151 return myView->findText( text, fl );
153 myView->findText( text, fl, [this](bool found) { return found; });
158 \brief Find first entry of specified text; does nothing in this implementation
159 \param text text being searched
160 \param st search tool
161 \return \c true if text has been found or \c false otherwise
164 bool QtxWebBrowser::Searcher::findFirst( const QString& /*text*/, QtxSearchTool* /*st*/ )
170 \brief Find last entry of specified text; does nothing in this implementation
171 \param text text being searched
172 \param st search tool
173 \return \c true if text has been found or \c false otherwise
176 bool QtxWebBrowser::Searcher::findLast( const QString& /*text*/, QtxSearchTool* /*st*/)
183 \class QtxWebBrowser::Downloader
184 \brief A dialog box that is used to process file links
190 \param fileName name of the file being opened
191 \param action default action to be used for the file
192 \param program default program to be used to open the file
193 \param parent parent widget
196 QtxWebBrowser::Downloader::Downloader( const QString& fileName, int action, const QString& program, QWidget* parent )
197 : QDialog( parent ), myProgram( program )
200 setWindowTitle( QtxWebBrowser::tr( "Open URL" ) );
201 setSizeGripEnabled( true );
203 myFileName = new QLabel( this );
204 QRadioButton* rbOpen = new QRadioButton( QtxWebBrowser::tr( "Open in" ), this );
205 QRadioButton* rbSave = new QRadioButton( QtxWebBrowser::tr( "Save file" ), this );
206 myBrowse = new QPushButton( QtxWebBrowser::tr( "&Browse..." ), this );
207 myRepeat = new QCheckBox( QtxWebBrowser::tr( "Use this program for all files of this type" ), this );
209 myAction = new QButtonGroup( this );
210 myAction->addButton( rbOpen, mOpen );
211 myAction->addButton( rbSave, mSave );
213 QPushButton* btnOk = new QPushButton( QtxWebBrowser::tr( "&OK" ), this );
214 QPushButton* btnCancel = new QPushButton( QtxWebBrowser::tr( "&Cancel" ), this );
216 QFont f = myFileName->font(); f.setBold( true ); myFileName->setFont( f );
218 QHBoxLayout* btnLayout = new QHBoxLayout;
219 btnLayout->addWidget( btnOk );
220 btnLayout->addStretch();
221 btnLayout->addWidget( btnCancel );
223 QGridLayout* l = new QGridLayout( this );
224 l->addWidget( new QLabel( QtxWebBrowser::tr( "You are opening the file" ), this ),
226 l->addWidget( myFileName, 1, 1, 1, 3 );
227 l->addWidget( new QLabel( QtxWebBrowser::tr( "Please choose the action to be done" ), this ),
229 l->addWidget( rbOpen, 4, 1, 1, 1 );
230 l->addWidget( myBrowse, 4, 2, 1, 1 );
231 l->addWidget( rbSave, 5, 1, 1, 3 );
232 l->addWidget( myRepeat, 6, 1, 1, 3 );
233 l->addLayout( btnLayout, 7, 0, 1, 4 );
234 l->setRowMinimumHeight( 2, 10 );
236 connect( myAction, SIGNAL( buttonClicked( int ) ), this, SLOT( setAction( int ) ) );
237 connect( myBrowse, SIGNAL( clicked() ), this, SLOT( browse() ) );
238 connect( btnOk, SIGNAL( clicked() ), this, SLOT( accept() ) );
239 connect( btnCancel, SIGNAL( clicked() ), this, SLOT( reject() ) );
241 myFileName->setText( QFileInfo( fileName ).fileName() );
242 myAction->button( action )->click();
248 QtxWebBrowser::Downloader::~Downloader()
253 \brief Get action selected by the user
254 \return action being selected:
258 int QtxWebBrowser::Downloader::action() const
260 return myAction->checkedId();
264 \brief Get "repeat action for all such files" flag status
265 \return \c true if chosen action should be automatically done for all files of given type
266 or \c false otherwise
268 bool QtxWebBrowser::Downloader::isRepeatAction() const
270 return myRepeat->isChecked();
274 \brief Get program to be used to open chosen file
275 \return path to the program
277 QString QtxWebBrowser::Downloader::program() const
283 \brief Set current action
284 \param action action to be done for the file:
288 void QtxWebBrowser::Downloader::setAction( int action )
290 myBrowse->setEnabled( action == mOpen );
294 \brief Browse program to be used to open the file
296 void QtxWebBrowser::Downloader::browse()
298 QString program = QFileDialog::getOpenFileName( this, QtxWebBrowser::tr( "Choose program" ), myProgram );
299 if ( !program.isEmpty() ) myProgram = program;
306 \brief The QtxWebBrowser provides a window that can display html pages from local file system.
308 Only one instance of the QtxWebBrowser class can be created. To access the browser
309 window, use static method QtxWebBrowser::webBrowser(), which creates an
310 instance of the QtxWebBrowser widget (if it is not yet created) and returns a
313 You should not destroy this instance - it is done automatically after
314 closing of the browser window. To close window programmatically use
317 Optionally resource manager can be specified to automatically store
318 action (open/save) and program to be used to download files in the
319 application preferences.
321 The following sample demonstrates how to use web browser.
322 In this code the browser window is created, /data/index.html file is opened
323 and scrolled to the "anchor1" anchor on this page.
326 // initialize application
327 // - set resource manager
328 QtxWebBrowser::setResourceMgr(myResourceMgr);
331 QtxWebBrowser::loadUrl("file:///data/index.html", "anchor1");
335 //! The only one instance of web browser
336 QtxWebBrowser* QtxWebBrowser::myBrowser = 0;
338 //! Resources manager
339 QtxResourceMgr* QtxWebBrowser::myResourceMgr = 0;
343 Construct the web browser.
345 QtxWebBrowser::QtxWebBrowser( ) : QMainWindow( 0 )
347 Q_INIT_RESOURCE( Qtx );
349 setAttribute( Qt::WA_DeleteOnClose );
352 QWidget* frame = new QWidget( this );
354 myWebView = new WebView( frame );
356 myWebView->pageAction( WebPage::Copy )->setShortcut( QKeySequence::Copy );
357 myWebView->addAction( myWebView->pageAction( WebPage::Copy ) );
358 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
359 myWebView->pageAction( WebPage::OpenLinkInNewWindow )->setVisible( false );
361 myWebView->pageAction( WebPage::Back )->setText( tr( "Go Back" ) );
362 myWebView->pageAction( WebPage::Forward )->setText( tr( "Go Forward" ) );
363 myWebView->pageAction( WebPage::Reload )->setText( tr( "Refresh" ) );
364 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
365 myWebView->page()->setLinkDelegationPolicy( WebPage::DelegateAllLinks );
368 myFindPanel = new QtxSearchTool( frame, myWebView,
369 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
370 QtxSearchTool::Basic | QtxSearchTool::Case | QtxSearchTool::Wrap,
372 QtxSearchTool::Basic | QtxSearchTool::Case,
375 myFindPanel->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
376 myFindPanel->setActivators( QtxSearchTool::SlashKey );
377 myFindPanel->setSearcher( new Searcher( myWebView ) );
378 myFindPanel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
380 QToolBar* toolbar = addToolBar( tr( "Navigation" ) );
381 toolbar->addAction( myWebView->pageAction( WebPage::Back ) );
382 toolbar->addAction( myWebView->pageAction( WebPage::Forward ) );
383 toolbar->addAction( myWebView->pageAction( WebPage::Reload ) );
385 QMenu* fileMenu = menuBar()->addMenu( tr( "&File" ) );
386 fileMenu->addAction( QPixmap( ":/images/open.png" ), tr( "&Open..." ),
387 this, SLOT( open() ),
388 QKeySequence( QKeySequence::Open ) );
389 fileMenu->addSeparator();
390 fileMenu->addAction( myWebView->pageAction( WebPage::Back ) );
391 fileMenu->addAction( myWebView->pageAction( WebPage::Forward ) );
392 fileMenu->addAction( myWebView->pageAction( WebPage::Reload ) );
393 fileMenu->addSeparator();
394 fileMenu->addAction( tr( "&Find in text..." ),
395 myFindPanel, SLOT( find() ),
396 QKeySequence( QKeySequence::Find ) );
397 fileMenu->addAction( tr( "&Find next" ),
398 myFindPanel, SLOT( findNext() ),
399 QKeySequence( QKeySequence::FindNext ) );
400 fileMenu->addAction( tr( "&Find previous" ),
401 myFindPanel, SLOT( findPrevious() ),
402 QKeySequence( QKeySequence::FindPrevious ) );
403 fileMenu->addSeparator();
404 fileMenu->addAction( QPixmap( ":/images/close.png" ), tr( "&Close" ),
405 this, SLOT( close() ) );
407 QMenu* helpMenu = menuBar()->addMenu( tr( "&Help" ) );
408 helpMenu->addAction( tr( "&About..." ),
409 this, SLOT( about() ) );
411 QVBoxLayout* main = new QVBoxLayout( frame );
412 main->addWidget( myWebView );
413 main->addWidget( myFindPanel );
414 main->setMargin( 0 );
415 main->setSpacing( 3 );
417 connect( myWebView, SIGNAL( titleChanged( QString ) ), SLOT( adjustTitle() ) );
418 connect( myWebView, SIGNAL( loadFinished( bool ) ), SLOT( finished( bool ) ) );
420 connect( myWebView->pageAction( WebPage::DownloadLinkToDisk ), SIGNAL( triggered() ),
421 SLOT( linkAction() ) );
422 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
424 connect( myWebView, SIGNAL( linkClicked( QUrl ) ), SLOT( linkClicked( QUrl ) ) );
425 connect( myWebView->page(), SIGNAL( linkHovered( QString, QString, QString ) ),
426 SLOT( linkHovered( QString, QString, QString ) ) );
427 disconnect( myWebView->pageAction( WebPage::OpenLink ), 0, 0, 0 );
428 connect( myWebView->pageAction( WebPage::OpenLink ), SIGNAL( triggered() ),
429 SLOT( linkAction() ) );
431 //QtWebEngine (Qt-5.6.0) case:
432 connect( myWebView->page(), SIGNAL( linkHovered( QString ) ),
433 SLOT( linkHovered( QString ) ) );
434 disconnect( myWebView->pageAction( WebPage::OpenLinkInThisWindow ), 0, 0, 0 );
435 connect( myWebView->pageAction( WebPage::OpenLinkInThisWindow ), SIGNAL( triggered() ),
436 SLOT( linkAction() ) );
438 setCentralWidget( frame );
439 setFocusProxy( myWebView );
440 setWindowIcon( QPixmap( ":/images/appicon.png" ) );
447 QtxWebBrowser::~QtxWebBrowser()
453 \brief Return the only instance of the QtxWebBrowser
454 \return instance of the QtxWebBrowser
456 QtxWebBrowser* QtxWebBrowser::webBrowser()
459 myBrowser = new QtxWebBrowser();
464 \brief Load given url address and optional scroll to the specified anchor
465 \param url an url address to load
466 \param anchor an anchor to scroll page to
468 void QtxWebBrowser::loadUrl( const QString& url, const QString& anchor )
471 if( !anchor.isEmpty() ) anUrl += "#" + anchor;
473 Qtx::alignWidget( webBrowser(), (QWidget*)QApplication::desktop(), Qtx::AlignCenter );
475 QtxWebBrowser* browser = webBrowser();
477 browser->load( anUrl );
479 browser->activateWindow();
484 \brief Shutdown help browser
486 void QtxWebBrowser::shutdown()
493 \brief Set resource manager
494 \param resMgr resource manager
496 void QtxWebBrowser::setResourceMgr( QtxResourceMgr* resMgr )
498 myResourceMgr = resMgr;
502 \brief Get resource manager
503 \return resource manager
505 QtxResourceMgr* QtxWebBrowser::resourceMgr() const
507 return myResourceMgr;
511 Shows About dialog box
513 void QtxWebBrowser::about()
515 QMessageBox::about( this, tr( "About %1" ).arg( tr( "Help Browser" ) ),
516 QString( "SALOME %1" ).arg( tr( "Help Browser" ) ) );
520 \brief Called when users activated any link at the page
521 \param url URL being clicked
524 void QtxWebBrowser::linkClicked( const QUrl& url )
526 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
527 myWebView->page()->setLinkDelegationPolicy( WebPage::DontDelegateLinks );
529 myWebView->load( url );
530 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
531 myWebView->page()->setLinkDelegationPolicy( WebPage::DelegateAllLinks );
536 \brief Called when link is hovered
537 \param link link being hovered
538 \param title link title (if it is specified in the markup)
539 \param content provides text within the link element, e.g., text inside an HTML anchor tag
543 void QtxWebBrowser::linkHovered( const QString& link, const QString& /*title*/, const QString& /*context*/ )
548 void QtxWebBrowser::linkHovered( const QString& link)
551 if ( !link.isEmpty() && isLocalFile( url ) ) myLastUrl = url;
552 statusBar()->showMessage( link );
556 \brief Update title of the window
559 void QtxWebBrowser::adjustTitle()
561 QString title = tr( "Help Browser" );
562 if ( !myWebView->title().isEmpty() ) title += QString( " [%1]" ).arg( myWebView->title() );
563 setWindowTitle( title );
567 \brief Called when link is processed by browser
568 \param ok operation status: \c true is URL is correctly processed, \c false otherwise
570 void QtxWebBrowser::finished( bool ok )
572 if ( !ok && !myLastUrl.isEmpty() ) {
573 if ( isLocalFile( myLastUrl ) ) {
574 QString filename = myLastUrl.path();
575 QString extension = QFileInfo( filename ).suffix();
576 if ( extension == "html" || extension == "htm" ) return;
577 openLink( filename );
583 \brief Called when link is processed from browser via popup menu actions
585 void QtxWebBrowser::linkAction()
587 QObject* s = sender();
588 if ( s == myWebView->pageAction( WebPage::DownloadLinkToDisk ) ) {
589 saveLink( myLastUrl.path() );
591 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
592 if ( s == myWebView->pageAction( WebPage::OpenLink ) ) {
594 if ( s == myWebView->pageAction( WebPage::OpenLinkInThisWindow ) ) {
596 QString fileName = myLastUrl.path();
597 QString extension = QFileInfo( fileName ).suffix();
598 if ( extension != "html" && extension != "htm" ) {
599 openLink( fileName, true );
602 linkClicked( myLastUrl );
609 \param fileName link to the file being opened
610 Opens dialog box to allow the user to choose the program to be used to open the file.
612 void QtxWebBrowser::openLink( const QString& fileName, bool force )
614 QString extension = QFileInfo( fileName ).suffix();
615 int defAction = Downloader::mOpen;
616 bool defRepeat = false;
618 QString resSection = QString( "%1:%2" ).arg( "web_browser" ).arg( extension );
619 QString actionParam = "action";
620 QString programParam = "program";
621 QString repeatParam = "repeat";
623 if ( !extension.isEmpty() && myResourceMgr ) {
624 defAction = myResourceMgr->integerValue( resSection, actionParam, defAction );
625 defRepeat = myResourceMgr->booleanValue( resSection, repeatParam, defRepeat );
626 defProgram = myResourceMgr->stringValue( resSection, programParam, defProgram );
629 if ( force || !defRepeat || ( defAction == Downloader::mOpen && defProgram.isEmpty() ) ) {
630 Downloader downloader( fileName, defAction, defProgram, this );
631 if ( !downloader.exec() ) return;
632 defAction = downloader.action();
633 defRepeat = downloader.isRepeatAction();
634 defProgram = downloader.program();
635 if ( myResourceMgr ) {
636 myResourceMgr->setValue( resSection, actionParam, defAction );
637 myResourceMgr->setValue( resSection, repeatParam, defRepeat );
638 if ( defAction == Downloader::mOpen )
639 myResourceMgr->setValue( resSection, programParam, defProgram );
642 switch( defAction ) {
643 case Downloader::mOpen:
644 if ( !defProgram.isEmpty() ) {
645 QStringList parameters;
647 QString cmd = defProgram;
649 // If Salome Qt version is lower than the system one, on KDE an unresolved symbol is raised
650 // In this case, we can try to launch the pdf viewer after unsetting the LD_LIBRARY_PATH environnement variable
652 parameters << "LD_LIBRARY_PATH=/usr/lib:/usr/lib64";
653 parameters << defProgram;
655 parameters << QFileInfo( myLastUrl.path() ).absoluteFilePath();
656 QProcess::startDetached( cmd, parameters );
659 case Downloader::mSave:
661 saveLink( fileName );
671 \param url path to the file to be opened in the browser
673 void QtxWebBrowser::load( const QString& link )
675 QString linkPath = link;
676 linkPath.replace('\\', '/');
678 if ( !url.isEmpty() ) {
679 if ( url.scheme().isEmpty() ) url.setScheme( "file" );
680 myWebView->load( url );
686 \param fileName link to the file being saved
687 Shows "Save file" standard dialog box to allow user to choose where to save the file.
689 void QtxWebBrowser::saveLink( const QString& fileName )
691 QString newFileName = QFileDialog::getSaveFileName( this, tr( "Save file" ), fileName,
692 QString( "*.%1" ).arg( QFileInfo( fileName ).suffix() ) );
693 if ( !newFileName.isEmpty() &&
694 QFileInfo( newFileName ).canonicalFilePath() != QFileInfo( fileName ).canonicalFilePath() ) {
695 QFile toFile( newFileName );
696 QFile fromFile( fileName );
697 if ( toFile.exists() && !toFile.remove() || !fromFile.copy( newFileName ) )
698 QMessageBox::warning( this, tr( "Error"), tr( "Can't save file:\n%1" ).arg( newFileName ) );
704 Shows "Open file" standard dialog box to allow user to choose file to open.
706 void QtxWebBrowser::open()
709 if ( isLocalFile( myWebView->url() ) ) url = myWebView->url().path();
710 url = QFileDialog::getOpenFileName( this, tr( "Open file" ), url, "HTML files (*.html *.htm);; All files (*)" );
711 if ( !url.isEmpty() ) load( url );