Files
qt-creator/src/plugins/help/centralwidget.cpp

717 lines
20 KiB
C++
Raw Normal View History

/**************************************************************************
2008-12-02 12:01:29 +01:00
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
2008-12-02 12:01:29 +01:00
**
** Contact: Nokia Corporation (qt-info@nokia.com)
2008-12-02 12:01:29 +01:00
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
2008-12-02 12:01:29 +01:00
**
**************************************************************************/
2008-12-02 12:01:29 +01:00
#include "centralwidget.h"
#include "helpviewer.h"
#include "topicchooser.h"
#include <QtCore/QEvent>
#include <QtCore/QTimer>
#include <QtGui/QMenu>
#include <QtGui/QLabel>
#include <QtGui/QLayout>
#include <QtGui/QPrinter>
#include <QtGui/QLineEdit>
#include <QtGui/QCheckBox>
#include <QtGui/QTabBar>
#include <QtGui/QTabWidget>
#include <QtGui/QToolButton>
#include <QtGui/QMouseEvent>
#include <QtGui/QFocusEvent>
#include <QtGui/QMainWindow>
#include <QtGui/QSpacerItem>
#include <QtGui/QTextCursor>
#include <QtGui/QPrintDialog>
#include <QtGui/QApplication>
#include <QtGui/QTextDocumentFragment>
#include <QtGui/QPrintPreviewDialog>
#include <QtGui/QPageSetupDialog>
#include <QtHelp/QHelpEngine>
#include <coreplugin/coreconstants.h>
2008-12-02 12:01:29 +01:00
using namespace Help::Internal;
namespace {
2009-06-25 15:20:38 +02:00
HelpViewer* helpViewerFromTabPosition(const QTabWidget *widget,
const QPoint &point)
2008-12-02 12:01:29 +01:00
{
QTabBar *tabBar = qFindChild<QTabBar*>(widget);
for (int i = 0; i < tabBar->count(); ++i) {
if (tabBar->tabRect(i).contains(point))
return qobject_cast<HelpViewer*>(widget->widget(i));
}
return 0;
}
2009-05-07 15:34:52 +02:00
Help::Internal::CentralWidget *staticCentralWidget = 0;
2008-12-02 12:01:29 +01:00
}
CentralWidget::CentralWidget(QHelpEngine *engine, QWidget *parent)
: QWidget(parent)
, findBar(0)
, tabWidget(0)
, helpEngine(engine)
, printer(0)
{
lastTabPage = 0;
globalActionList.clear();
collectionFile = helpEngine->collectionFile();
tabWidget = new QTabWidget;
tabWidget->setDocumentMode(true);
tabWidget->setMovable(true);
connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
2009-06-25 15:20:38 +02:00
connect(tabWidget, SIGNAL(currentChanged(int)), this,
SLOT(currentPageChanged(int)));
2008-12-02 12:01:29 +01:00
QToolButton *newTabButton = new QToolButton(this);
newTabButton->setAutoRaise(true);
newTabButton->setToolTip(tr("Add new page"));
2009-06-25 15:20:38 +02:00
newTabButton->setIcon(QIcon(
#ifdef Q_OS_MAC
QLatin1String(":/trolltech/assistant/images/mac/addtab.png")));
#else
QLatin1String(":/trolltech/assistant/images/win/addtab.png")));
#endif
2008-12-02 12:01:29 +01:00
tabWidget->setCornerWidget(newTabButton, Qt::TopLeftCorner);
connect(newTabButton, SIGNAL(clicked()), this, SLOT(newTab()));
QVBoxLayout *vboxLayout = new QVBoxLayout(this);
vboxLayout->setMargin(0);
vboxLayout->addWidget(tabWidget);
QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget);
if (tabBar) {
tabBar->installEventFilter(this);
tabBar->setContextMenuPolicy(Qt::CustomContextMenu);
connect(tabBar, SIGNAL(customContextMenuRequested(QPoint)), this,
SLOT(showTabBarContextMenu(QPoint)));
2008-12-02 12:01:29 +01:00
}
staticCentralWidget = this;
}
CentralWidget::~CentralWidget()
{
2009-06-25 15:20:38 +02:00
#ifndef QT_NO_PRINTER
delete printer;
#endif
2008-12-02 12:01:29 +01:00
QHelpEngineCore engine(collectionFile, 0);
2009-06-25 15:20:38 +02:00
if (!engine.setupData())
return;
2008-12-02 12:01:29 +01:00
QString zoomCount;
2009-06-25 15:20:38 +02:00
QString currentPages;
for (int i = 0; i < tabWidget->count(); ++i) {
HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i));
if (viewer && viewer->source().isValid()) {
2009-06-25 15:20:38 +02:00
currentPages += (viewer->source().toString() + QLatin1Char('|'));
zoomCount += QString::number(viewer->zoom()) + QLatin1Char('|');
}
2008-12-02 12:01:29 +01:00
}
2009-06-25 15:20:38 +02:00
engine.setCustomValue(QLatin1String("LastTabPage"), lastTabPage);
engine.setCustomValue(QLatin1String("LastShownPages"), currentPages);
engine.setCustomValue(QLatin1String("LastShownPagesZoom"), zoomCount);
2008-12-02 12:01:29 +01:00
}
CentralWidget *CentralWidget::instance()
{
return staticCentralWidget;
}
void CentralWidget::newTab()
{
HelpViewer* viewer = currentHelpViewer();
if (viewer)
setSourceInNewTab(viewer->source());
}
void CentralWidget::zoomIn()
{
HelpViewer* viewer = currentHelpViewer();
if (viewer)
viewer->zoomIn();
}
void CentralWidget::zoomOut()
{
HelpViewer* viewer = currentHelpViewer();
if (viewer)
viewer->zoomOut();
}
void CentralWidget::nextPage()
{
2009-06-25 15:20:38 +02:00
int index = tabWidget->currentIndex() + 1;
if (index >= tabWidget->count())
index = 0;
tabWidget->setCurrentIndex(index);
2008-12-02 12:01:29 +01:00
}
void CentralWidget::resetZoom()
{
HelpViewer* viewer = currentHelpViewer();
if (viewer)
viewer->resetZoom();
}
void CentralWidget::previousPage()
{
int index = tabWidget->currentIndex() -1;
2009-06-25 15:20:38 +02:00
if (index < 0)
index = tabWidget->count() -1;
tabWidget->setCurrentIndex(index);
2008-12-02 12:01:29 +01:00
}
void CentralWidget::closeTab()
{
closeTab(tabWidget->currentIndex());
}
void CentralWidget::closeTab(int index)
{
HelpViewer* viewer = helpViewerAtIndex(index);
if (!viewer || tabWidget->count() == 1)
return;
tabWidget->removeTab(index);
QTimer::singleShot(0, viewer, SLOT(deleteLater()));
}
void CentralWidget::setSource(const QUrl &url)
{
HelpViewer* viewer = currentHelpViewer();
2009-06-25 15:20:38 +02:00
HelpViewer* lastViewer =
qobject_cast<HelpViewer*>(tabWidget->widget(lastTabPage));
2008-12-02 12:01:29 +01:00
if (!viewer && !lastViewer) {
viewer = new HelpViewer(helpEngine, this);
viewer->installEventFilter(this);
lastTabPage = tabWidget->addTab(viewer, QString());
tabWidget->setCurrentIndex(lastTabPage);
connectSignals();
qApp->processEvents();
2009-06-25 15:20:38 +02:00
} else {
2008-12-02 12:01:29 +01:00
viewer = lastViewer;
2009-06-25 15:20:38 +02:00
}
2008-12-02 12:01:29 +01:00
viewer->setSource(url);
currentPageChanged(lastTabPage);
viewer->setFocus(Qt::OtherFocusReason);
tabWidget->setCurrentIndex(lastTabPage);
tabWidget->setTabText(lastTabPage, quoteTabTitle(viewer->documentTitle()));
}
void CentralWidget::setLastShownPages()
{
2009-06-25 15:20:38 +02:00
QString value = helpEngine->customValue(QLatin1String("LastShownPages"),
QString()).toString();
const QStringList lastShownPageList = value.split(QLatin1Char('|'),
QString::SkipEmptyParts);
2008-12-02 12:01:29 +01:00
2009-06-25 15:20:38 +02:00
const int pageCount = lastShownPageList.count();
if (pageCount <= 0) {
QUrl url = helpEngine->findFile(QString::fromLatin1("qthelp://com."
"trolltech.qt.440/qdoc/index.html"));
if (!url.isValid()) {
url.setUrl(QString("qthelp://com.nokia.qtcreator.%1%2/doc/index.html").
arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR));
2009-06-25 15:20:38 +02:00
url.setUrl(QString::fromLatin1("qthelp://com.nokia.qtcreator.%1%2/"
"doc/index.html").arg(IDE_VERSION_MAJOR).arg(IDE_VERSION_MINOR));
}
setSource(url);
2009-06-25 15:20:38 +02:00
return;
2008-12-02 12:01:29 +01:00
}
2009-06-25 15:20:38 +02:00
value = helpEngine->customValue(QLatin1String("LastShownPagesZoom"),
QString()).toString();
QVector<QString> zoomVector = value.split(QLatin1Char('|'),
QString::SkipEmptyParts).toVector();
const int zoomCount = zoomVector.count();
zoomVector.insert(zoomCount, pageCount - zoomCount, QLatin1String("0"));
QVector<QString>::const_iterator zIt = zoomVector.constBegin();
2009-06-25 15:20:38 +02:00
QStringList::const_iterator it = lastShownPageList.constBegin();
for (; it != lastShownPageList.constEnd(); ++it, ++zIt)
setSourceInNewTab((*it), (*zIt).toInt());
int tab = helpEngine->customValue(QLatin1String("LastTabPage"), 0).toInt();
tabWidget->setCurrentIndex(tab);
2008-12-02 12:01:29 +01:00
}
bool CentralWidget::hasSelection() const
{
const HelpViewer* viewer = currentHelpViewer();
return viewer ? viewer->hasSelection() : false;
}
QUrl CentralWidget::currentSource() const
{
const HelpViewer* viewer = currentHelpViewer();
if (viewer)
return viewer->source();
return QUrl();
}
QString CentralWidget::currentTitle() const
{
const HelpViewer* viewer = currentHelpViewer();
if (viewer)
return viewer->documentTitle();
return QString();
}
void CentralWidget::copySelection()
{
HelpViewer* viewer = currentHelpViewer();
if (viewer)
viewer->copy();
}
void CentralWidget::initPrinter()
{
#ifndef QT_NO_PRINTER
if (!printer)
printer = new QPrinter(QPrinter::HighResolution);
#endif
}
void CentralWidget::print()
{
#ifndef QT_NO_PRINTER
HelpViewer* viewer = currentHelpViewer();
if (!viewer)
return;
initPrinter();
QPrintDialog *dlg = new QPrintDialog(printer, this);
#if defined(QT_NO_WEBKIT)
2008-12-02 12:01:29 +01:00
if (viewer->textCursor().hasSelection())
dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection);
#endif
dlg->addEnabledOption(QAbstractPrintDialog::PrintPageRange);
dlg->addEnabledOption(QAbstractPrintDialog::PrintCollateCopies);
dlg->setWindowTitle(tr("Print Document"));
if (dlg->exec() == QDialog::Accepted) {
viewer->print(printer);
}
delete dlg;
#endif
}
void CentralWidget::printPreview()
{
#ifndef QT_NO_PRINTER
initPrinter();
QPrintPreviewDialog preview(printer, this);
connect(&preview, SIGNAL(paintRequested(QPrinter*)),
SLOT(printPreview(QPrinter*)));
2008-12-02 12:01:29 +01:00
preview.exec();
#endif
}
void CentralWidget::printPreview(QPrinter *p)
{
#ifndef QT_NO_PRINTER
HelpViewer *viewer = currentHelpViewer();
if (viewer)
viewer->print(p);
2009-06-25 15:20:38 +02:00
#else
Q_UNUSED(p);
2008-12-02 12:01:29 +01:00
#endif
}
void CentralWidget::pageSetup()
{
#ifndef QT_NO_PRINTER
initPrinter();
QPageSetupDialog dlg(printer);
dlg.exec();
#endif
}
bool CentralWidget::isHomeAvailable() const
{
return currentHelpViewer() ? true : false;
}
void CentralWidget::home()
{
HelpViewer* viewer = currentHelpViewer();
if (viewer)
viewer->home();
}
bool CentralWidget::isForwardAvailable() const
{
const HelpViewer* viewer = currentHelpViewer();
if (viewer)
return viewer->isForwardAvailable();
return false;
}
void CentralWidget::forward()
{
HelpViewer* viewer = currentHelpViewer();
if (viewer)
viewer->forward();
}
bool CentralWidget::isBackwardAvailable() const
{
const HelpViewer* viewer = currentHelpViewer();
if (viewer)
return viewer->isBackwardAvailable();
return false;
}
void CentralWidget::backward()
{
HelpViewer* viewer = currentHelpViewer();
if (viewer)
viewer->backward();
}
QList<QAction*> CentralWidget::globalActions() const
{
return globalActionList;
}
void CentralWidget::setGlobalActions(const QList<QAction*> &actions)
{
globalActionList = actions;
}
void CentralWidget::setSourceInNewTab(const QUrl &url, int zoom)
2008-12-02 12:01:29 +01:00
{
HelpViewer* viewer = new HelpViewer(helpEngine, this);
viewer->installEventFilter(this);
viewer->setZoom(zoom);
2008-12-02 12:01:29 +01:00
viewer->setSource(url);
viewer->setFocus(Qt::OtherFocusReason);
#if defined(QT_NO_WEBKIT)
QFont font = viewer->font();
font.setPointSize(font.pointSize() + int(zoom));
viewer->setFont(font);
#endif
tabWidget->setCurrentIndex(tabWidget->addTab(viewer,
quoteTabTitle(viewer->documentTitle())));
2008-12-02 12:01:29 +01:00
connectSignals();
}
HelpViewer *CentralWidget::newEmptyTab()
{
HelpViewer* viewer = new HelpViewer(helpEngine, this);
viewer->installEventFilter(this);
viewer->setFocus(Qt::OtherFocusReason);
#if defined(QT_NO_WEBKIT)
2008-12-02 12:01:29 +01:00
viewer->setDocumentTitle(tr("unknown"));
#endif
tabWidget->setCurrentIndex(tabWidget->addTab(viewer, tr("unknown")));
connectSignals();
return viewer;
}
void CentralWidget::connectSignals()
{
const HelpViewer* viewer = currentHelpViewer();
if (viewer) {
connect(viewer, SIGNAL(copyAvailable(bool)), this,
SIGNAL(copyAvailable(bool)));
connect(viewer, SIGNAL(forwardAvailable(bool)), this,
SIGNAL(forwardAvailable(bool)));
connect(viewer, SIGNAL(backwardAvailable(bool)), this,
SIGNAL(backwardAvailable(bool)));
connect(viewer, SIGNAL(sourceChanged(QUrl)), this,
SIGNAL(sourceChanged(QUrl)));
connect(viewer, SIGNAL(highlighted(QString)), this,
SIGNAL(highlighted(QString)));
connect(viewer, SIGNAL(sourceChanged(QUrl)), this,
SLOT(setTabTitle(QUrl)));
2008-12-02 12:01:29 +01:00
}
}
HelpViewer *CentralWidget::helpViewerAtIndex(int index) const
{
return qobject_cast<HelpViewer*>(tabWidget->widget(index));
}
HelpViewer *CentralWidget::currentHelpViewer() const
{
return qobject_cast<HelpViewer*>(tabWidget->currentWidget());
}
void CentralWidget::activateTab(bool onlyHelpViewer)
{
if (currentHelpViewer()) {
currentHelpViewer()->setFocus();
} else {
int idx = 0;
if (onlyHelpViewer)
idx = lastTabPage;
tabWidget->setCurrentIndex(idx);
tabWidget->currentWidget()->setFocus();
}
}
void CentralWidget::setTabTitle(const QUrl& url)
{
int tab = lastTabPage;
HelpViewer* viewer = currentHelpViewer();
#if !defined(QT_NO_WEBKIT)
2008-12-02 12:01:29 +01:00
if (!viewer || viewer->source() != url) {
QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget);
for (tab = 0; tab < tabBar->count(); ++tab) {
viewer = qobject_cast<HelpViewer*>(tabWidget->widget(tab));
if (viewer && viewer->source() == url)
break;
}
}
2009-06-25 15:20:38 +02:00
#else
Q_UNUSED(url);
2008-12-02 12:01:29 +01:00
#endif
if (viewer) {
tabWidget->setTabText(tab,
quoteTabTitle(viewer->documentTitle().trimmed()));
}
}
void CentralWidget::currentPageChanged(int index)
{
2009-06-25 15:20:38 +02:00
lastTabPage = index;
2008-12-02 12:01:29 +01:00
2009-06-25 15:20:38 +02:00
tabWidget->setTabsClosable(tabWidget->count() > 1);
2008-12-02 12:01:29 +01:00
tabWidget->cornerWidget(Qt::TopLeftCorner)->setEnabled(true);
emit currentViewerChanged();
}
void CentralWidget::showTabBarContextMenu(const QPoint &point)
{
HelpViewer* viewer = helpViewerFromTabPosition(tabWidget, point);
if (!viewer)
return;
QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget);
QMenu menu(QLatin1String(""), tabBar);
2009-06-25 15:20:38 +02:00
QAction *newPage = menu.addAction(tr("Add New Page"));
2008-12-02 12:01:29 +01:00
2009-06-25 15:20:38 +02:00
bool enableAction = tabBar->count() > 1;
QAction *closePage = menu.addAction(tr("Close This Page"));
closePage->setEnabled(enableAction);
2008-12-02 12:01:29 +01:00
2009-06-25 15:20:38 +02:00
QAction *closePages = menu.addAction(tr("Close Other Pages"));
closePages->setEnabled(enableAction);
menu.addSeparator();
QAction *newBookmark = menu.addAction(tr("Add Bookmark for this Page..."));
const QString &url = viewer->source().toString();
if (url.isEmpty() || url == QLatin1String("about:blank"))
newBookmark->setEnabled(false);
2009-06-25 15:20:38 +02:00
QAction *pickedAction = menu.exec(tabBar->mapToGlobal(point));
if (pickedAction == newPage)
2008-12-02 12:01:29 +01:00
setSourceInNewTab(viewer->source());
2009-06-25 15:20:38 +02:00
if (pickedAction == closePage) {
2008-12-02 12:01:29 +01:00
tabWidget->removeTab(tabWidget->indexOf(viewer));
QTimer::singleShot(0, viewer, SLOT(deleteLater()));
}
2009-06-25 15:20:38 +02:00
if (pickedAction == closePages) {
2008-12-02 12:01:29 +01:00
int currentPage = tabWidget->indexOf(viewer);
for (int i = tabBar->count() -1; i >= 0; --i) {
viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i));
if (i != currentPage && viewer) {
tabWidget->removeTab(i);
QTimer::singleShot(0, viewer, SLOT(deleteLater()));
if (i < currentPage)
--currentPage;
}
}
}
2009-06-25 15:20:38 +02:00
if (pickedAction == newBookmark)
emit addNewBookmark(viewer->documentTitle(), url);
2008-12-02 12:01:29 +01:00
}
// If we have a current help viewer then this is the 'focus proxy', otherwise
// it's the tab widget itself. This is needed, so an embedding program can just
// set the focus to the central widget and it does TheRightThing(TM)
2008-12-02 12:01:29 +01:00
void CentralWidget::focusInEvent(QFocusEvent * /* event */)
{
QObject *receiver = tabWidget;
2008-12-02 12:01:29 +01:00
if (currentHelpViewer())
receiver = currentHelpViewer();
QTimer::singleShot(1, receiver, SLOT(setFocus()));
2008-12-02 12:01:29 +01:00
}
bool CentralWidget::eventFilter(QObject *object, QEvent *e)
{
2009-06-25 15:20:38 +02:00
if (e->type() == QEvent::KeyPress){
if ((static_cast<QKeyEvent*>(e))->key() == Qt::Key_Backspace) {
2008-12-02 12:01:29 +01:00
HelpViewer *viewer = currentHelpViewer();
2009-06-25 15:20:38 +02:00
if (viewer == object) {
if (viewer->isBackwardAvailable()) {
#if !defined(QT_NO_WEBKIT)
// this helps in case there is an html <input> field
if (!viewer->hasFocus())
#endif
viewer->backward();
}
return true;
}
2008-12-02 12:01:29 +01:00
}
}
2009-06-25 15:20:38 +02:00
if (qobject_cast<QTabBar*>(object)) {
bool dblClick = e->type() == QEvent::MouseButtonDblClick;
if((e->type() == QEvent::MouseButtonRelease) || dblClick) {
if (tabWidget->count() <= 1)
return QWidget::eventFilter(object, e);
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(e);
HelpViewer *viewer = helpViewerFromTabPosition(tabWidget,
mouseEvent->pos());
if (viewer) {
if ((mouseEvent->button() == Qt::MidButton) || dblClick) {
tabWidget->removeTab(tabWidget->indexOf(viewer));
QTimer::singleShot(0, viewer, SLOT(deleteLater()));
currentPageChanged(tabWidget->currentIndex());
return true;
}
}
2008-12-02 12:01:29 +01:00
}
}
return QWidget::eventFilter(object, e);
}
bool CentralWidget::find(const QString &txt, QTextDocument::FindFlags findFlags,
bool incremental)
2008-12-02 12:01:29 +01:00
{
HelpViewer* viewer = currentHelpViewer();
#if !defined(QT_NO_WEBKIT)
2008-12-02 12:01:29 +01:00
Q_UNUSED(incremental);
if (viewer) {
QWebPage::FindFlags options = QWebPage::FindWrapsAroundDocument;
if (findFlags & QTextDocument::FindBackward)
options |= QWebPage::FindBackward;
if (findFlags & QTextDocument::FindCaseSensitively)
options |= QWebPage::FindCaseSensitively;
return viewer->findText(txt, options);
}
return false;
#else
QTextCursor cursor;
QTextDocument *doc = 0;
QTextBrowser *browser = 0;
if (viewer) {
doc = viewer->document();
cursor = viewer->textCursor();
browser = qobject_cast<QTextBrowser*>(viewer);
}
/*
if (tabWidget->currentWidget() == m_searchWidget) {
QTextBrowser* browser = qFindChild<QTextBrowser*>(m_searchWidget);
if (browser) {
doc = browser->document();
cursor = browser->textCursor();
}
}
*/
if (!browser || !doc || cursor.isNull())
return false;
if (incremental)
cursor.setPosition(cursor.selectionStart());
QTextCursor found = doc->find(txt, cursor, findFlags);
if (found.isNull()) {
if ((findFlags&QTextDocument::FindBackward) == 0)
cursor.movePosition(QTextCursor::Start);
else
cursor.movePosition(QTextCursor::End);
found = doc->find(txt, cursor, findFlags);
if (found.isNull()) {
return false;
}
}
if (!found.isNull()) {
viewer->setTextCursor(found);
}
return true;
#endif
}
void CentralWidget::showTopicChooser(const QMap<QString, QUrl> &links,
const QString &keyword)
2008-12-02 12:01:29 +01:00
{
TopicChooser tc(this, keyword, links);
if (tc.exec() == QDialog::Accepted)
setSource(tc.link());
}
void CentralWidget::copy()
{
HelpViewer* viewer = currentHelpViewer();
if (viewer)
viewer->copy();
}
QString CentralWidget::quoteTabTitle(const QString &title) const
{
QString s = title;
return s.replace(QLatin1Char('&'), QLatin1String("&&"));
}