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 );
123 myView->findText( text, fl, [&](bool found) { textFound = found; });
129 \brief Find next entry of specified text starting from the current position
130 \param text text being searched
131 \param st search tool
132 \return \c true if text has been found or \c false otherwise
135 bool QtxWebBrowser::Searcher::findNext( const QString& text, QtxSearchTool* st )
137 return find( text, st );
141 \brief Find previous entry of specified text starting from the current position
142 \param text text being searched
143 \param st search tool
144 \return \c true if text has been found or \c false otherwise
147 bool QtxWebBrowser::Searcher::findPrevious( const QString& text, QtxSearchTool* st )
149 WebPage::FindFlags fl = WebPage::FindBackward;
150 if ( st->isCaseSensitive() ) fl = fl | WebPage::FindCaseSensitively;
151 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
152 if ( st->isSearchWrapped() ) fl = fl | WebPage::FindWrapsAroundDocument;
153 return myView->findText( text, fl );
156 myView->findText( text, fl, [&](bool found) { textFound = found; });
162 \brief Find first entry of specified text; does nothing in this implementation
163 \param text text being searched
164 \param st search tool
165 \return \c true if text has been found or \c false otherwise
168 bool QtxWebBrowser::Searcher::findFirst( const QString& /*text*/, QtxSearchTool* /*st*/ )
174 \brief Find last entry of specified text; does nothing in this implementation
175 \param text text being searched
176 \param st search tool
177 \return \c true if text has been found or \c false otherwise
180 bool QtxWebBrowser::Searcher::findLast( const QString& /*text*/, QtxSearchTool* /*st*/)
187 \class QtxWebBrowser::Downloader
188 \brief A dialog box that is used to process file links
194 \param fileName name of the file being opened
195 \param action default action to be used for the file
196 \param program default program to be used to open the file
197 \param parent parent widget
200 QtxWebBrowser::Downloader::Downloader( const QString& fileName, int action, const QString& program, QWidget* parent )
201 : QDialog( parent ), myProgram( program )
204 setWindowTitle( QtxWebBrowser::tr( "Open URL" ) );
205 setSizeGripEnabled( true );
207 myFileName = new QLabel( this );
208 QRadioButton* rbOpen = new QRadioButton( QtxWebBrowser::tr( "Open in" ), this );
209 QRadioButton* rbSave = new QRadioButton( QtxWebBrowser::tr( "Save file" ), this );
210 myBrowse = new QPushButton( QtxWebBrowser::tr( "&Browse..." ), this );
211 myRepeat = new QCheckBox( QtxWebBrowser::tr( "Use this program for all files of this type" ), this );
213 myAction = new QButtonGroup( this );
214 myAction->addButton( rbOpen, mOpen );
215 myAction->addButton( rbSave, mSave );
217 QPushButton* btnOk = new QPushButton( QtxWebBrowser::tr( "&OK" ), this );
218 QPushButton* btnCancel = new QPushButton( QtxWebBrowser::tr( "&Cancel" ), this );
220 QFont f = myFileName->font(); f.setBold( true ); myFileName->setFont( f );
222 QHBoxLayout* btnLayout = new QHBoxLayout;
223 btnLayout->addWidget( btnOk );
224 btnLayout->addStretch();
225 btnLayout->addWidget( btnCancel );
227 QGridLayout* l = new QGridLayout( this );
228 l->addWidget( new QLabel( QtxWebBrowser::tr( "You are opening the file" ), this ),
230 l->addWidget( myFileName, 1, 1, 1, 3 );
231 l->addWidget( new QLabel( QtxWebBrowser::tr( "Please choose the action to be done" ), this ),
233 l->addWidget( rbOpen, 4, 1, 1, 1 );
234 l->addWidget( myBrowse, 4, 2, 1, 1 );
235 l->addWidget( rbSave, 5, 1, 1, 3 );
236 l->addWidget( myRepeat, 6, 1, 1, 3 );
237 l->addLayout( btnLayout, 7, 0, 1, 4 );
238 l->setRowMinimumHeight( 2, 10 );
240 connect( myAction, SIGNAL( buttonClicked( int ) ), this, SLOT( setAction( int ) ) );
241 connect( myBrowse, SIGNAL( clicked() ), this, SLOT( browse() ) );
242 connect( btnOk, SIGNAL( clicked() ), this, SLOT( accept() ) );
243 connect( btnCancel, SIGNAL( clicked() ), this, SLOT( reject() ) );
245 myFileName->setText( QFileInfo( fileName ).fileName() );
246 myAction->button( action )->click();
252 QtxWebBrowser::Downloader::~Downloader()
257 \brief Get action selected by the user
258 \return action being selected:
262 int QtxWebBrowser::Downloader::action() const
264 return myAction->checkedId();
268 \brief Get "repeat action for all such files" flag status
269 \return \c true if chosen action should be automatically done for all files of given type
270 or \c false otherwise
272 bool QtxWebBrowser::Downloader::isRepeatAction() const
274 return myRepeat->isChecked();
278 \brief Get program to be used to open chosen file
279 \return path to the program
281 QString QtxWebBrowser::Downloader::program() const
287 \brief Set current action
288 \param action action to be done for the file:
292 void QtxWebBrowser::Downloader::setAction( int action )
294 myBrowse->setEnabled( action == mOpen );
298 \brief Browse program to be used to open the file
300 void QtxWebBrowser::Downloader::browse()
302 QString program = QFileDialog::getOpenFileName( this, QtxWebBrowser::tr( "Choose program" ), myProgram );
303 if ( !program.isEmpty() ) myProgram = program;
310 \brief The QtxWebBrowser provides a window that can display html pages from local file system.
312 Only one instance of the QtxWebBrowser class can be created. To access the browser
313 window, use static method QtxWebBrowser::webBrowser(), which creates an
314 instance of the QtxWebBrowser widget (if it is not yet created) and returns a
317 You should not destroy this instance - it is done automatically after
318 closing of the browser window. To close window programmatically use
321 Optionally resource manager can be specified to automatically store
322 action (open/save) and program to be used to download files in the
323 application preferences.
325 The following sample demonstrates how to use web browser.
326 In this code the browser window is created, /data/index.html file is opened
327 and scrolled to the "anchor1" anchor on this page.
330 // initialize application
331 // - set resource manager
332 QtxWebBrowser::setResourceMgr(myResourceMgr);
335 QtxWebBrowser::loadUrl("file:///data/index.html", "anchor1");
339 //! The only one instance of web browser
340 QtxWebBrowser* QtxWebBrowser::myBrowser = 0;
342 //! Resources manager
343 QtxResourceMgr* QtxWebBrowser::myResourceMgr = 0;
347 Construct the web browser.
349 QtxWebBrowser::QtxWebBrowser( ) : QMainWindow( 0 )
351 Q_INIT_RESOURCE( Qtx );
353 setAttribute( Qt::WA_DeleteOnClose );
356 QWidget* frame = new QWidget( this );
358 myWebView = new WebView( frame );
360 myWebView->pageAction( WebPage::Copy )->setShortcut( QKeySequence::Copy );
361 myWebView->addAction( myWebView->pageAction( WebPage::Copy ) );
362 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
363 myWebView->pageAction( WebPage::OpenLinkInNewWindow )->setVisible( false );
365 myWebView->pageAction( WebPage::Back )->setText( tr( "Go Back" ) );
366 myWebView->pageAction( WebPage::Forward )->setText( tr( "Go Forward" ) );
367 myWebView->pageAction( WebPage::Reload )->setText( tr( "Refresh" ) );
368 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
369 myWebView->page()->setLinkDelegationPolicy( WebPage::DelegateAllLinks );
372 myFindPanel = new QtxSearchTool( frame, myWebView,
373 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
374 QtxSearchTool::Basic | QtxSearchTool::Case | QtxSearchTool::Wrap,
376 QtxSearchTool::Basic | QtxSearchTool::Case,
379 myFindPanel->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
380 myFindPanel->setActivators( QtxSearchTool::SlashKey );
381 myFindPanel->setSearcher( new Searcher( myWebView ) );
382 myFindPanel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
384 QToolBar* toolbar = addToolBar( tr( "Navigation" ) );
385 toolbar->addAction( myWebView->pageAction( WebPage::Back ) );
386 toolbar->addAction( myWebView->pageAction( WebPage::Forward ) );
387 toolbar->addAction( myWebView->pageAction( WebPage::Reload ) );
389 QMenu* fileMenu = menuBar()->addMenu( tr( "&File" ) );
390 fileMenu->addAction( QPixmap( ":/images/open.png" ), tr( "&Open..." ),
391 this, SLOT( open() ),
392 QKeySequence( QKeySequence::Open ) );
393 fileMenu->addSeparator();
394 fileMenu->addAction( myWebView->pageAction( WebPage::Back ) );
395 fileMenu->addAction( myWebView->pageAction( WebPage::Forward ) );
396 fileMenu->addAction( myWebView->pageAction( WebPage::Reload ) );
397 fileMenu->addSeparator();
398 fileMenu->addAction( tr( "&Find in text..." ),
399 myFindPanel, SLOT( find() ),
400 QKeySequence( QKeySequence::Find ) );
401 fileMenu->addAction( tr( "&Find next" ),
402 myFindPanel, SLOT( findNext() ),
403 QKeySequence( QKeySequence::FindNext ) );
404 fileMenu->addAction( tr( "&Find previous" ),
405 myFindPanel, SLOT( findPrevious() ),
406 QKeySequence( QKeySequence::FindPrevious ) );
407 fileMenu->addSeparator();
408 fileMenu->addAction( QPixmap( ":/images/close.png" ), tr( "&Close" ),
409 this, SLOT( close() ) );
411 QMenu* helpMenu = menuBar()->addMenu( tr( "&Help" ) );
412 helpMenu->addAction( tr( "&About..." ),
413 this, SLOT( about() ) );
415 QVBoxLayout* main = new QVBoxLayout( frame );
416 main->addWidget( myWebView );
417 main->addWidget( myFindPanel );
418 main->setMargin( 0 );
419 main->setSpacing( 3 );
421 connect( myWebView, SIGNAL( titleChanged( QString ) ), SLOT( adjustTitle() ) );
422 connect( myWebView, SIGNAL( loadFinished( bool ) ), SLOT( finished( bool ) ) );
424 connect( myWebView->pageAction( WebPage::DownloadLinkToDisk ), SIGNAL( triggered() ),
425 SLOT( linkAction() ) );
426 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
428 connect( myWebView, SIGNAL( linkClicked( QUrl ) ), SLOT( linkClicked( QUrl ) ) );
429 connect( myWebView->page(), SIGNAL( linkHovered( QString, QString, QString ) ),
430 SLOT( linkHovered( QString, QString, QString ) ) );
431 disconnect( myWebView->pageAction( WebPage::OpenLink ), 0, 0, 0 );
432 connect( myWebView->pageAction( WebPage::OpenLink ), SIGNAL( triggered() ),
433 SLOT( linkAction() ) );
435 //QtWebEngine (Qt-5.6.0) case:
436 connect( myWebView->page(), SIGNAL( linkHovered( QString ) ),
437 SLOT( linkHovered( QString ) ) );
438 disconnect( myWebView->pageAction( WebPage::OpenLinkInThisWindow ), 0, 0, 0 );
439 connect( myWebView->pageAction( WebPage::OpenLinkInThisWindow ), SIGNAL( triggered() ),
440 SLOT( linkAction() ) );
442 setCentralWidget( frame );
443 setFocusProxy( myWebView );
444 setWindowIcon( QPixmap( ":/images/appicon.png" ) );
451 QtxWebBrowser::~QtxWebBrowser()
457 \brief Return the only instance of the QtxWebBrowser
458 \return instance of the QtxWebBrowser
460 QtxWebBrowser* QtxWebBrowser::webBrowser()
463 myBrowser = new QtxWebBrowser();
468 \brief Load given url address and optional scroll to the specified anchor
469 \param url an url address to load
470 \param anchor an anchor to scroll page to
472 void QtxWebBrowser::loadUrl( const QString& url, const QString& anchor )
475 if( !anchor.isEmpty() ) anUrl += "#" + anchor;
477 Qtx::alignWidget( webBrowser(), (QWidget*)QApplication::desktop(), Qtx::AlignCenter );
479 QtxWebBrowser* browser = webBrowser();
481 browser->load( anUrl );
483 browser->activateWindow();
488 \brief Shutdown help browser
490 void QtxWebBrowser::shutdown()
497 \brief Set resource manager
498 \param resMgr resource manager
500 void QtxWebBrowser::setResourceMgr( QtxResourceMgr* resMgr )
502 myResourceMgr = resMgr;
506 \brief Get resource manager
507 \return resource manager
509 QtxResourceMgr* QtxWebBrowser::resourceMgr() const
511 return myResourceMgr;
515 Shows About dialog box
517 void QtxWebBrowser::about()
519 QMessageBox::about( this, tr( "About %1" ).arg( tr( "Help Browser" ) ),
520 QString( "SALOME %1" ).arg( tr( "Help Browser" ) ) );
524 \brief Called when users activated any link at the page
525 \param url URL being clicked
528 void QtxWebBrowser::linkClicked( const QUrl& url )
530 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
531 myWebView->page()->setLinkDelegationPolicy( WebPage::DontDelegateLinks );
533 myWebView->load( url );
534 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
535 myWebView->page()->setLinkDelegationPolicy( WebPage::DelegateAllLinks );
540 \brief Called when link is hovered
541 \param link link being hovered
542 \param title link title (if it is specified in the markup)
543 \param content provides text within the link element, e.g., text inside an HTML anchor tag
547 void QtxWebBrowser::linkHovered( const QString& link, const QString& /*title*/, const QString& /*context*/ )
552 void QtxWebBrowser::linkHovered( const QString& link)
555 if ( !link.isEmpty() && isLocalFile( url ) ) myLastUrl = url;
556 statusBar()->showMessage( link );
560 \brief Update title of the window
563 void QtxWebBrowser::adjustTitle()
565 QString title = tr( "Help Browser" );
566 if ( !myWebView->title().isEmpty() ) title += QString( " [%1]" ).arg( myWebView->title() );
567 setWindowTitle( title );
571 \brief Called when link is processed by browser
572 \param ok operation status: \c true is URL is correctly processed, \c false otherwise
574 void QtxWebBrowser::finished( bool ok )
576 if ( !ok && !myLastUrl.isEmpty() ) {
577 if ( isLocalFile( myLastUrl ) ) {
578 QString filename = myLastUrl.path();
579 QString extension = QFileInfo( filename ).suffix();
580 if ( extension == "html" || extension == "htm" ) return;
581 openLink( filename );
587 \brief Called when link is processed from browser via popup menu actions
589 void QtxWebBrowser::linkAction()
591 QObject* s = sender();
592 if ( s == myWebView->pageAction( WebPage::DownloadLinkToDisk ) ) {
593 saveLink( myLastUrl.path() );
595 #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
596 if ( s == myWebView->pageAction( WebPage::OpenLink ) ) {
598 if ( s == myWebView->pageAction( WebPage::OpenLinkInThisWindow ) ) {
600 QString fileName = myLastUrl.path();
601 QString extension = QFileInfo( fileName ).suffix();
602 if ( extension != "html" && extension != "htm" ) {
603 openLink( fileName, true );
606 linkClicked( myLastUrl );
613 \param fileName link to the file being opened
614 Opens dialog box to allow the user to choose the program to be used to open the file.
616 void QtxWebBrowser::openLink( const QString& fileName, bool force )
618 QString extension = QFileInfo( fileName ).suffix();
619 int defAction = Downloader::mOpen;
620 bool defRepeat = false;
622 QString resSection = QString( "%1:%2" ).arg( "web_browser" ).arg( extension );
623 QString actionParam = "action";
624 QString programParam = "program";
625 QString repeatParam = "repeat";
627 if ( !extension.isEmpty() && myResourceMgr ) {
628 defAction = myResourceMgr->integerValue( resSection, actionParam, defAction );
629 defRepeat = myResourceMgr->booleanValue( resSection, repeatParam, defRepeat );
630 defProgram = myResourceMgr->stringValue( resSection, programParam, defProgram );
633 if ( force || !defRepeat || ( defAction == Downloader::mOpen && defProgram.isEmpty() ) ) {
634 Downloader downloader( fileName, defAction, defProgram, this );
635 if ( !downloader.exec() ) return;
636 defAction = downloader.action();
637 defRepeat = downloader.isRepeatAction();
638 defProgram = downloader.program();
639 if ( myResourceMgr ) {
640 myResourceMgr->setValue( resSection, actionParam, defAction );
641 myResourceMgr->setValue( resSection, repeatParam, defRepeat );
642 if ( defAction == Downloader::mOpen )
643 myResourceMgr->setValue( resSection, programParam, defProgram );
646 switch( defAction ) {
647 case Downloader::mOpen:
648 if ( !defProgram.isEmpty() ) {
649 QStringList parameters;
651 QString cmd = defProgram;
653 // If Salome Qt version is lower than the system one, on KDE an unresolved symbol is raised
654 // In this case, we can try to launch the pdf viewer after unsetting the LD_LIBRARY_PATH environnement variable
656 parameters << "LD_LIBRARY_PATH=/usr/lib:/usr/lib64";
657 parameters << defProgram;
659 parameters << QFileInfo( myLastUrl.path() ).absoluteFilePath();
660 QProcess::startDetached( cmd, parameters );
663 case Downloader::mSave:
665 saveLink( fileName );
675 \param url path to the file to be opened in the browser
677 void QtxWebBrowser::load( const QString& link )
679 QString linkPath = link;
680 linkPath.replace('\\', '/');
682 if ( !url.isEmpty() ) {
683 if ( url.scheme().isEmpty() ) url.setScheme( "file" );
684 myWebView->load( url );
690 \param fileName link to the file being saved
691 Shows "Save file" standard dialog box to allow user to choose where to save the file.
693 void QtxWebBrowser::saveLink( const QString& fileName )
695 QString newFileName = QFileDialog::getSaveFileName( this, tr( "Save file" ), fileName,
696 QString( "*.%1" ).arg( QFileInfo( fileName ).suffix() ) );
697 if ( !newFileName.isEmpty() &&
698 QFileInfo( newFileName ).canonicalFilePath() != QFileInfo( fileName ).canonicalFilePath() ) {
699 QFile toFile( newFileName );
700 QFile fromFile( fileName );
701 if (( toFile.exists() && !toFile.remove() ) ||
702 ( !fromFile.copy( newFileName ) ))
703 QMessageBox::warning( this, tr( "Error"), tr( "Can't save file:\n%1" ).arg( newFileName ) );
709 Shows "Open file" standard dialog box to allow user to choose file to open.
711 void QtxWebBrowser::open()
714 if ( isLocalFile( myWebView->url() ) ) url = myWebView->url().path();
715 url = QFileDialog::getOpenFileName( this, tr( "Open file" ), url, "HTML files (*.html *.htm);; All files (*)" );
716 if ( !url.isEmpty() ) load( url );