00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <QApplication>
00027 # include <QContextMenuEvent>
00028 # include <QDropEvent>
00029 # include <QGroupBox>
00030 # include <QHBoxLayout>
00031 # include <QHttp>
00032 # include <QLabel>
00033 # include <QMenu>
00034 # include <QMessageBox>
00035 # include <QMimeData>
00036 # include <QProcess>
00037 # include <QTimerEvent>
00038 # include <QToolButton>
00039 # include <QToolTip>
00040 # include <QWhatsThis>
00041 #endif
00042
00043 #include "HelpView.h"
00044 #include "Application.h"
00045 #include "BitmapFactory.h"
00046 #include "FileDialog.h"
00047 #include "WhatsThis.h"
00048 #include "Action.h"
00049 #include "Command.h"
00050
00051
00052 using namespace Gui;
00053 using namespace Gui::DockWnd;
00054
00055 namespace Gui {
00056 namespace DockWnd {
00057
00058 struct TextBrowserResources
00059 {
00060 QUrl url;
00061 int type;
00062 };
00063
00064 class TextBrowserPrivate
00065 {
00066 public:
00067 bool bw, fw;
00068 int toolTipId;
00069 QString toolTip;
00070 QHttp* http;
00071 QUrl source;
00072 QList<TextBrowserResources> resources;
00073
00074 TextBrowserPrivate() : bw(false), fw(false), toolTipId(0)
00075 {
00076 http = new QHttp;
00077 }
00078
00079 ~TextBrowserPrivate()
00080 {
00081 delete http;
00082 }
00083 };
00084
00085 }
00086 }
00087
00088
00089
00090 TextBrowser::TextBrowser(QWidget * parent)
00091 : QTextBrowser(parent)
00092 {
00093 d = new TextBrowserPrivate;
00094
00095 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00096 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00097
00098 setAcceptDrops( TRUE );
00099 viewport()->setAcceptDrops( TRUE );
00100
00101 connect( d->http, SIGNAL(done(bool)), this, SLOT(done(bool)));
00102 connect( d->http, SIGNAL(stateChanged(int)), this, SLOT(onStateChanged(int)));
00103 connect( d->http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), this, SLOT(onResponseHeaderReceived(const QHttpResponseHeader &)));
00104 connect( this, SIGNAL(highlighted(const QString&)), this, SLOT(onHighlighted(const QString&)));
00105 connect( this, SIGNAL(backwardAvailable(bool)), this, SLOT(setBackwardAvailable(bool)));
00106 connect( this, SIGNAL(forwardAvailable (bool)), this, SLOT(setForwardAvailable (bool)));
00107 }
00108
00109 TextBrowser::~TextBrowser()
00110 {
00111 delete d;
00112 }
00113
00114 QString TextBrowser::findUrl(const QUrl &name) const
00115 {
00116 QString fileName = name.toLocalFile();
00117 QFileInfo fi(fileName);
00118 if (fi.isAbsolute())
00119 return fileName;
00120
00121 QString slash(QLatin1String("/"));
00122 QStringList spaths = searchPaths();
00123 for (QStringList::ConstIterator it = spaths.begin(); it != spaths.end(); ++it) {
00124 QString path = *it;
00125 if (!path.endsWith(slash))
00126 path.append(slash);
00127 path.append(fileName);
00128 fi.setFile(path);
00129 if (fi.isReadable())
00130 return path;
00131 }
00132
00133 QUrl src = source();
00134 if (src.isEmpty())
00135 return fileName;
00136
00137 QFileInfo path(QFileInfo(src.toLocalFile()).absolutePath(), fileName);
00138 return path.absoluteFilePath();
00139 }
00140
00145 QVariant TextBrowser::loadResource ( int type, const QUrl& url )
00146 {
00147 QString name = url.toString();
00148 if (url.scheme() == QLatin1String("http") ||
00149 d->source.scheme() == QLatin1String("http")) {
00150 return loadHttpResource(type, url);
00151 } else {
00152 return loadFileResource(type, url);
00153 }
00154 }
00155
00160 void TextBrowser::setSource (const QUrl& url)
00161 {
00162 bool relativeUrl = url.isRelative();
00163 if (!relativeUrl)
00164 d->source = url;
00165 QString name = url.toString();
00166 if (url.scheme() == QLatin1String("http")) {
00167
00168
00169
00170 d->http->setHost(url.host());
00171 d->http->get(url.path(), 0);
00172 } else if (d->source.scheme() == QLatin1String("http")) {
00173
00174 d->source = d->source.resolved(url);
00175 d->http->get(url.path(), 0);
00176 } else {
00177 QUrl resolved = url;
00178 #if defined (Q_OS_WIN)
00179 if (url.scheme() == QLatin1String("file") && !url.isRelative()) {
00180 QString auth = url.authority();
00181 QString path = url.path();
00182
00183
00184
00185 if (!auth.isEmpty() && !path.isEmpty()) {
00186 QString fileName = auth + QLatin1Char(':') + path;
00187 resolved = QUrl::fromLocalFile(fileName);
00188 }
00189 }
00190 #endif
00191 QTextBrowser::setSource(resolved);
00192 }
00193 }
00194
00199 QVariant TextBrowser::loadFileResource(int type, const QUrl& name)
00200 {
00201 QVariant data;
00202 QUrl resolved = name;
00203 if (!QFileInfo(name.toLocalFile()).isAbsolute() && QFileInfo(d->source.toLocalFile()).isAbsolute())
00204 resolved = d->source.resolved(name);
00205 QString fileName = findUrl(resolved);
00206 QFile file(fileName);
00207 if (file.open(QFile::ReadOnly)) {
00208 data = file.readAll();
00209 file.close();
00210 } else if (type == QTextDocument::HtmlResource) {
00211 data = QString::fromAscii(
00212 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">"
00213 "<html>"
00214 "<head>"
00215 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-16\">"
00216 "<title>Error</title>"
00217 "</head>"
00218 "<body>"
00219 "<h1>%1</h1>"
00220 "<div><p><strong>%2</strong></p>"
00221 "</div></body>"
00222 "</html>").arg(tr("Could not open file.")).arg(tr("You tried to access the address %1 which is currently unavailable. "
00223 "Please make sure that the URL exists and try reloading the page.").arg(name.toString()));
00224 } else if (type == QTextDocument::ImageResource) {
00225 static const char * empty_xpm[] = {
00226 "24 24 1 1",
00227 ". c #C0C0C0",
00228 "........................",
00229 "........................",
00230 "........................",
00231 "........................",
00232 "........................",
00233 "........................",
00234 "........................",
00235 "........................",
00236 "........................",
00237 "........................",
00238 "........................",
00239 "........................",
00240 "........................",
00241 "........................",
00242 "........................",
00243 "........................",
00244 "........................",
00245 "........................",
00246 "........................",
00247 "........................",
00248 "........................",
00249 "........................",
00250 "........................",
00251 "........................"};
00252 QPixmap px(empty_xpm);
00253 data.setValue<QPixmap>(px);
00254 }
00255
00256 return data;
00257 }
00258
00264 QVariant TextBrowser::loadHttpResource(int type, const QUrl& name)
00265 {
00266 QVariant data;
00267 if (type == QTextDocument::ImageResource) {
00268 TextBrowserResources res;
00269 res.url = name;
00270 res.type = type;
00271 d->resources.push_back(res);
00272
00273 static const char * empty_xpm[] = {
00274 "24 24 1 1",
00275 ". c #C0C0C0",
00276 "........................",
00277 "........................",
00278 "........................",
00279 "........................",
00280 "........................",
00281 "........................",
00282 "........................",
00283 "........................",
00284 "........................",
00285 "........................",
00286 "........................",
00287 "........................",
00288 "........................",
00289 "........................",
00290 "........................",
00291 "........................",
00292 "........................",
00293 "........................",
00294 "........................",
00295 "........................",
00296 "........................",
00297 "........................",
00298 "........................",
00299 "........................"};
00300 QPixmap px(empty_xpm);
00301 data.setValue<QPixmap>(px);
00302 return data;
00303 }
00304
00305 if (d->http->error() == QHttp::NoError) {
00306 return d->http->readAll();
00307 } else {
00308 if (type == QTextDocument::HtmlResource) {
00309 data = QString::fromAscii(
00310 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">"
00311 "<html>"
00312 "<head>"
00313 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-16\">"
00314 "<title>Error</title>"
00315 "</head>"
00316 "<body>"
00317 "<h1>%1</h1>"
00318 "<div><p><strong>%2</strong></p>"
00319 "</div></body>"
00320 "</html>").arg(d->http->errorString()).arg(tr("You tried to access the address %1 which is currently unavailable. "
00321 "Please make sure that the URL exists and try reloading the page.").arg(name.toString()));
00322 }
00323 }
00324
00325 return data;
00326 }
00327
00331 void TextBrowser::done( bool )
00332 {
00333 if (d->resources.isEmpty()) {
00334
00335 QTextBrowser::setSource(d->source);
00336 } else {
00337
00338 TextBrowserResources res = d->resources.front();
00339
00340 QVariant data(d->http->readAll());
00341 document()->addResource(res.type, res.url, data);
00342 viewport()->repaint();
00343 d->resources.pop_front();
00344 }
00345
00346
00347 if (!d->resources.isEmpty()) {
00348 TextBrowserResources res = d->resources.front();
00349 d->http->get(res.url.toString());
00350 } else {
00351 stateChanged(d->source.toString());
00352 }
00353 }
00354
00358 void TextBrowser::onStateChanged ( int state )
00359 {
00360 switch (state) {
00361 case QHttp::Connecting:
00362 stateChanged(tr("Connecting to %1").arg(d->source.host()));
00363 break;
00364 case QHttp::Sending:
00365 stateChanged(tr("Sending to %1").arg(d->source.host()));
00366 break;
00367 case QHttp::Reading:
00368 stateChanged(tr("Reading from %1").arg(d->source.host()));
00369 break;
00370 case QHttp::Closing:
00371 case QHttp::Unconnected:
00372 if (d->http->error() == QHttp::NoError)
00373 stateChanged(d->source.toString());
00374 else
00375 stateChanged(d->http->errorString());
00376 break;
00377 default:
00378 break;
00379 }
00380 }
00381
00385 void TextBrowser::onResponseHeaderReceived(const QHttpResponseHeader &responseHeader)
00386 {
00387 if (responseHeader.statusCode() != 200) {
00388 stateChanged(tr("Download failed: %1.").arg(responseHeader.reasonPhrase()));
00389 d->http->abort();
00390 }
00391 }
00392
00393 void TextBrowser::onHighlighted(const QString& url)
00394 {
00395 if (url.isEmpty() && d->toolTipId != 0) {
00396 killTimer(d->toolTipId);
00397 d->toolTipId = 0;
00398 } else if (!url.isEmpty()) {
00399 d->toolTip = url;
00400 d->toolTipId = startTimer(1000);
00401 } else {
00402 QToolTip::showText(QCursor::pos(), url, this);
00403 }
00404 }
00405
00406 void TextBrowser::backward()
00407 {
00408 QTextBrowser::backward();
00409 reload();
00410 }
00411
00412 void TextBrowser::forward()
00413 {
00414 QTextBrowser::forward();
00415 reload();
00416 }
00417
00418 void TextBrowser::setBackwardAvailable( bool b )
00419 {
00420 d->bw = b;
00421 }
00422
00423 void TextBrowser::setForwardAvailable( bool b )
00424 {
00425 d->fw = b;
00426 }
00427
00428 void TextBrowser::timerEvent ( QTimerEvent * e )
00429 {
00430 if (d->toolTipId == e->timerId()) {
00431 QToolTip::showText(QCursor::pos(), d->toolTip, this);
00432 killTimer(d->toolTipId);
00433 d->toolTipId = 0;
00434 }
00435 }
00436
00437 void TextBrowser::contextMenuEvent ( QContextMenuEvent * e )
00438 {
00439 QMenu* menu = new QMenu(this);
00440
00441 QAction* prev = menu->addAction(Gui::BitmapFactory().pixmap("back_pixmap"), tr("Previous"), this, SLOT(backward()));
00442 prev->setEnabled(d->bw);
00443
00444 QAction* next = menu->addAction(Gui::BitmapFactory().pixmap("forward_pixmap"), tr("Forward"), this, SLOT(forward()));
00445 next->setEnabled(d->fw);
00446
00447 menu->addSeparator();
00448 menu->addAction(Gui::BitmapFactory().pixmap("home_pixmap"), tr("Home"), this, SLOT(home()));
00449 menu->addAction(tr("Refresh"), this, SLOT(reload()));
00450 menu->addSeparator();
00451 menu->addAction(tr("Copy"), this, SLOT(copy()));
00452 menu->addAction(tr("Select all"), this, SLOT(selectAll()));
00453
00454 menu->exec(e->globalPos());
00455 delete menu;
00456 }
00457
00458 void TextBrowser::dropEvent(QDropEvent * e)
00459 {
00460 const QMimeData* mimeData = e->mimeData();
00461 if ( mimeData->hasFormat(QLatin1String("text/x-action-items")) ) {
00462 QByteArray itemData = mimeData->data(QLatin1String("text/x-action-items"));
00463 QDataStream dataStream(&itemData, QIODevice::ReadOnly);
00464
00465 int ctActions; dataStream >> ctActions;
00466
00467
00468 QString action;
00469 dataStream >> action;
00470
00471 CommandManager& rclMan = Application::Instance->commandManager();
00472 Command* pCmd = rclMan.getCommandByName(action.toAscii());
00473 if ( pCmd ) {
00474 QString info = pCmd->getAction()->whatsThis();
00475 if ( !info.isEmpty() ) {
00476
00477 info = QString::fromAscii(
00478 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">"
00479 "<html>"
00480 "<body bgcolor=white text=black alink=red link=darkblue vlink=darkmagenta>"
00481 "%1"
00482 "</body>"
00483 "</html>" ).arg( info );
00484 } else {
00485 info = QString::fromAscii(
00486 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">"
00487 "<html>"
00488 "<body bgcolor=white text=black alink=red link=darkblue vlink=darkmagenta>"
00489 "<h2>"
00490 " %1 '%2'"
00491 "</h2>"
00492 "<hr>"
00493 "</body>"
00494 "</html>" ).arg(tr("No description for")).arg(action);
00495 }
00496
00497 setHtml( info );
00498 }
00499
00500 e->setDropAction(Qt::CopyAction);
00501 e->accept();
00502 } else if ( mimeData->hasUrls() ) {
00503 QList<QUrl> uri = mimeData->urls();
00504 QUrl url = uri.front();
00505 setSource(url);
00506
00507 e->setDropAction(Qt::CopyAction);
00508 e->accept();
00509 } else {
00510 e->ignore();
00511 }
00512 }
00513
00514 void TextBrowser::dragEnterEvent (QDragEnterEvent * e)
00515 {
00516 const QMimeData* mimeData = e->mimeData();
00517 if ( mimeData->hasFormat(QLatin1String("text/x-action-items")) )
00518 e->accept();
00519 else if (mimeData->hasUrls())
00520 e->accept();
00521 else
00522 e->ignore();
00523 }
00524
00525 void TextBrowser::dragMoveEvent( QDragMoveEvent *e )
00526 {
00527 const QMimeData* mimeData = e->mimeData();
00528 if ( mimeData->hasFormat(QLatin1String("text/x-action-items")) )
00529 e->accept();
00530 else if (mimeData->hasUrls())
00531 e->accept();
00532 else
00533 e->ignore();
00534 }
00535
00536
00537
00538
00539
00540
00545 HelpView::HelpView( const QString& start, QWidget* parent )
00546 : QWidget(parent)
00547 {
00548 TextBrowser* browser = new TextBrowser(this);
00549 browser->setFrameStyle( QFrame::Panel | QFrame::Sunken );
00550
00551 if (!start.isEmpty())
00552 browser->setSource(QUrl::fromLocalFile(start));
00553
00554 QHBoxLayout* layout = new QHBoxLayout();
00555 layout->setAlignment(Qt::AlignTop);
00556 layout->setSpacing(1);
00557 layout->setMargin (1);
00558
00559
00560 QGroupBox* groupBox = new QGroupBox(this);
00561
00562
00563 QToolButton* back = new QToolButton( groupBox );
00564 back->setIcon( Gui::BitmapFactory().pixmap("back_pixmap") );
00565 back->setAutoRaise(true);
00566 back->setToolTip(tr("Previous"));
00567
00568
00569 QToolButton* forward = new QToolButton( groupBox );
00570 forward->setIcon( Gui::BitmapFactory().pixmap("forward_pixmap") );
00571 forward->setAutoRaise(true);
00572 forward->setToolTip(tr("Next"));
00573
00574
00575 QToolButton* home = new QToolButton( groupBox );
00576 home->setIcon( Gui::BitmapFactory().pixmap("home_pixmap") );
00577 home->setAutoRaise(true);
00578 home->setToolTip(tr("Home"));
00579
00580
00581 QToolButton* open = new QToolButton( groupBox );
00582 open->setIcon( Gui::BitmapFactory().pixmap("helpopen") );
00583 open->setAutoRaise(true);
00584 open->setToolTip(tr("Open"));
00585
00586 QGridLayout* formLayout = new QGridLayout( this );
00587 formLayout->setSpacing( 1 );
00588 formLayout->setMargin ( 1 );
00589
00590
00591 layout->addWidget( back );
00592 layout->addWidget( forward );
00593 layout->addWidget( home );
00594 layout->addWidget( open );
00595 QSpacerItem* spacer = new QSpacerItem( 0, 20, QSizePolicy::Expanding, QSizePolicy::Minimum );
00596 layout->addItem( spacer );
00597 groupBox->setLayout(layout);
00598
00599 label = new QLabel(this);
00600 label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
00601 label->setText(start);
00602
00603
00604 formLayout->addWidget( groupBox, 0, 0 );
00605 formLayout->addWidget( browser, 1, 0 );
00606 formLayout->addWidget( label, 2, 0 );
00607
00608 connect( this, SIGNAL(setSource( const QUrl& )), browser, SLOT(setSource( const QUrl& )));
00609 connect( browser, SIGNAL(stateChanged(const QString&)), this, SLOT(onStateChanged(const QString&)));
00610 connect( browser, SIGNAL(backwardAvailable(bool)), back, SLOT(setEnabled(bool)));
00611 connect( browser, SIGNAL(forwardAvailable (bool)), forward, SLOT(setEnabled(bool)));
00612 connect( browser, SIGNAL(startExternalBrowser(const QString&)),
00613 this, SLOT (startExternalBrowser(const QString&)));
00614 connect( back, SIGNAL(clicked()), browser, SLOT(backward()));
00615 connect( browser, SIGNAL(backwardAvailable(bool) ), back, SLOT(setEnabled(bool) ) );
00616 connect( forward, SIGNAL(clicked()), browser, SLOT(forward()));
00617 connect( browser, SIGNAL(forwardAvailable(bool) ), forward, SLOT(setEnabled(bool) ) );
00618 connect( home, SIGNAL(clicked()), browser, SLOT(home()));
00619 connect( open, SIGNAL(clicked()), this, SLOT(openHelpFile()));
00620 forward->setEnabled( false );
00621 back->setEnabled( false );
00622 qApp->installEventFilter(this);
00623 }
00624
00628 HelpView::~HelpView()
00629 {
00630
00631 qApp->removeEventFilter(this);
00632 }
00633
00637 void HelpView::setFileSource( const QString& src )
00638 {
00639 setSource( src );
00640 }
00641
00645 void HelpView::openHelpFile()
00646 {
00647 QString fn = QFileDialog::getOpenFileName(this, tr("Open file"), QString(), tr("All HTML files (*.html *.htm)"));
00648 if ( !fn.isEmpty() )
00649 setSource( QUrl::fromLocalFile(fn) );
00650 }
00651
00656 void HelpView::startExternalBrowser( const QString& url )
00657 {
00658 ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
00659 ("User parameter:BaseApp/Preferences/OnlineHelp");
00660 QString browser = QString::fromUtf8(hGrp->GetASCII( "ExternalBrowser", "" ).c_str());
00661
00662 if (browser.isEmpty())
00663 {
00664 QMessageBox::critical( this, tr("External browser"), tr("No external browser found. Specify in preferences, please") );
00665 return;
00666 }
00667
00668
00669 QStringList arguments;
00670 arguments << url;
00671
00672 if (!QProcess::startDetached(browser, arguments))
00673 {
00674 QMessageBox::critical( this, tr("External browser"), tr("Starting of %1 failed").arg( browser ) );
00675 }
00676 }
00677
00678 void HelpView::onStateChanged(const QString& state)
00679 {
00680 label->setText(state);
00681 }
00682
00683 bool HelpView::eventFilter ( QObject* o, QEvent* e )
00684 {
00685
00686 if (e->type() == QEvent::WhatsThisClicked) {
00687 QString url = static_cast<QWhatsThisClickedEvent*>(e)->href();
00688 setSource(QUrl::fromLocalFile(url));
00689 QWhatsThis::hideText();
00690 return true;
00691 }
00692
00693 return QWidget::eventFilter( o, e );
00694 }
00695
00696 #include "moc_HelpView.cpp"
00697