helpdialog.cpp

来自「奇趣公司比较新的qt/emd版本」· C++ 代码 · 共 1,320 行 · 第 1/3 页

CPP
1,320
字号
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the Qt Assistant of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file.  Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "helpdialog.h"#include "helpwindow.h"#include "topicchooser.h"#include "docuparser.h"#include "mainwindow.h"#include "config.h"#include "tabbedbrowser.h"#include <QtGui>#include <QtDebug>#include <stdlib.h>#include <limits.h>enum{    LinkRole = Qt::UserRole + 1000};static bool verifyDirectory(const QString &str){    QFileInfo dirInfo(str);    if (!dirInfo.exists())        return QDir().mkdir(str);    if (!dirInfo.isDir()) {        qWarning("'%s' exists but is not a directory", str.toLatin1().constData());        return false;    }    return true;}struct IndexKeyword {    IndexKeyword(const QString &kw, const QString &l)        : keyword(kw), link(l) {}    IndexKeyword() : keyword(QString()), link(QString()) {}    bool operator<(const IndexKeyword &ik) const {        return keyword.toLower() < ik.keyword.toLower();    }    bool operator<=(const IndexKeyword &ik) const {        return keyword.toLower() <= ik.keyword.toLower();    }    bool operator>(const IndexKeyword &ik) const {        return keyword.toLower() > ik.keyword.toLower();    }    Q_DUMMY_COMPARISON_OPERATOR(IndexKeyword)    QString keyword;    QString link;};QDataStream &operator>>(QDataStream &s, IndexKeyword &ik){    s >> ik.keyword;    s >> ik.link;    return s;}QDataStream &operator<<(QDataStream &s, const IndexKeyword &ik){    s << ik.keyword;    s << ik.link;    return s;}QValidator::State SearchValidator::validate(QString &str, int &) const{    for (int i = 0; i < (int) str.length(); ++i) {        QChar c = str[i];        if (!c.isLetterOrNumber() && c != QLatin1Char('\'') && c != QLatin1Char('`')            && c != QLatin1Char('\"') && c != QLatin1Char(' ') && c != QLatin1Char('-') && c != QLatin1Char('_')            && c!= QLatin1Char('*'))            return QValidator::Invalid;    }    return QValidator::Acceptable;}class IndexListModel: public QStringListModel{public:    IndexListModel(QObject *parent = 0)        : QStringListModel(parent) {}    void clear() { contents.clear(); setStringList(QStringList()); }    QString description(int index) const { return stringList().at(index); }    QStringList links(int index) const { return contents.values(stringList().at(index)); }    void addLink(const QString &description, const QString &link) { contents.insert(description, link); }    void publish() { filter(QString(), QString()); }    QModelIndex filter(const QString &s, const QString &real);    virtual Qt::ItemFlags flags(const QModelIndex &index) const    { return QStringListModel::flags(index) & ~Qt::ItemIsEditable; }private:    QMultiMap<QString, QString> contents;};bool caseInsensitiveLessThan(const QString &as, const QString &bs){    const QChar *a = as.unicode();    const QChar *b = bs.unicode();    if (a == 0)        return true;    if (b == 0)        return false;    if (a == b)        return false;    int l=qMin(as.length(),bs.length());    while (l-- && QChar::toLower(a->unicode()) == QChar::toLower(b->unicode()))        a++,b++;    if (l==-1)        return (as.length() < bs.length());    return QChar::toLower(a->unicode()) < QChar::toLower(b->unicode());}/** * \a real is kinda a hack for the smart search, need a way to match a regexp to an item * How would you say the best match for Q.*Wiget is QWidget? */QModelIndex IndexListModel::filter(const QString &s, const QString &real){    QStringList list;    int goodMatch = -1;    int perfectMatch = -1;    if (s.isEmpty())        perfectMatch = 0;    const QRegExp regExp(s, Qt::CaseInsensitive);    QMultiMap<QString, QString>::iterator it = contents.begin();    QString lastKey;    for (; it != contents.end(); ++it) {        if (it.key() == lastKey)            continue;        lastKey = it.key();        const QString key = it.key();        if (key.contains(regExp) || key.contains(s, Qt::CaseInsensitive)) {            list.append(key);            if (perfectMatch == -1 && (key.startsWith(real, Qt::CaseInsensitive))) {                if (goodMatch == -1)                    goodMatch = list.count() - 1;                if (real.length() == key.length()){                    perfectMatch = list.count() - 1;                }            }  else if (perfectMatch > -1 && s == key) {                perfectMatch = list.count() - 1;            }        }    }    int bestMatch = perfectMatch;    if (bestMatch == -1)        bestMatch = goodMatch;    bestMatch = qMax(0, bestMatch);    // sort the new list    QString match;    if (bestMatch >= 0 && list.count() > bestMatch)        match = list[bestMatch];    qSort(list.begin(), list.end(), caseInsensitiveLessThan);    setStringList(list);    for (int i = 0; i < list.size(); ++i) {        if (list.at(i) == match){            bestMatch = i;            break;        }    }    return index(bestMatch, 0, QModelIndex());}HelpNavigationListItem::HelpNavigationListItem(QListWidget *ls, const QString &txt)    : QListWidgetItem(txt, ls){}void HelpNavigationListItem::addLink(const QString &link){    QString lnk = HelpDialog::removeAnchorFromLink(link);    if (linkList.filter(lnk, Qt::CaseInsensitive).count() > 0)        return;    linkList << link;}HelpDialog::HelpDialog(QWidget *parent, MainWindow *h)    : QWidget(parent), lwClosed(false), help(h){    ui.setupUi(this);    ui.listContents->setUniformRowHeights(true);    ui.listContents->header()->setStretchLastSection(false);    ui.listContents->header()->setResizeMode(QHeaderView::ResizeToContents);    ui.listBookmarks->setUniformRowHeights(true);    ui.listBookmarks->header()->setStretchLastSection(false);    ui.listBookmarks->header()->setResizeMode(QHeaderView::ResizeToContents);    indexModel = new IndexListModel(this);    ui.listIndex->setModel(indexModel);    ui.listIndex->setLayoutMode(QListView::Batched);    ui.listBookmarks->setItemHidden(ui.listBookmarks->headerItem(), true);    ui.listContents->setItemHidden(ui.listContents->headerItem(), true);    ui.searchButton->setShortcut(QKeySequence(Qt::ALT|Qt::SHIFT|Qt::Key_S));}void HelpDialog::initialize(){    connect(ui.tabWidget, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int)));    connect(ui.listContents, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(showTopic(QTreeWidgetItem*)));    connect(ui.listContents, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showTreeItemMenu(QPoint)));    ui.listContents->viewport()->installEventFilter(this);    connect(ui.editIndex, SIGNAL(returnPressed()), this, SLOT(showTopic()));    connect(ui.editIndex, SIGNAL(textEdited(QString)), this, SLOT(searchInIndex(QString)));    connect(ui.listIndex, SIGNAL(activated(QModelIndex)), this, SLOT(showTopic()));    connect(ui.listIndex, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showIndexItemMenu(QPoint)));    connect(ui.listBookmarks, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(showTopic(QTreeWidgetItem*)));    connect(ui.listBookmarks, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showTreeItemMenu(QPoint)));    connect(ui.termsEdit, SIGNAL(textChanged(const QString&)), this, SLOT(updateSearchButton(const QString&)));    connect(ui.resultBox, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showListItemMenu(QPoint)));    cacheFilesPath = QDir::homePath() + QLatin1String("/.assistant"); //### Find a better location for the dbs    ui.editIndex->installEventFilter(this);    ui.framePrepare->hide();    connect(qApp, SIGNAL(lastWindowClosed()), SLOT(lastWinClosed()));    ui.termsEdit->setValidator(new SearchValidator(ui.termsEdit));    actionOpenCurrentTab = new QAction(this);    actionOpenCurrentTab->setText(tr("Open Link in Current Tab"));    actionOpenLinkInNewWindow = new QAction(this);    actionOpenLinkInNewWindow->setText(tr("Open Link in New Window"));    actionOpenLinkInNewTab = new QAction(this);    actionOpenLinkInNewTab->setText(tr("Open Link in New Tab"));    itemPopup = new QMenu(this);    itemPopup->addAction(actionOpenCurrentTab);    itemPopup->addAction(actionOpenLinkInNewWindow);    itemPopup->addAction(actionOpenLinkInNewTab);    ui.tabWidget->setElideMode(Qt::ElideNone);    contentList.clear();    initDoneMsgShown = false;    fullTextIndex = 0;    indexDone = false;    titleMapDone = false;    contentsInserted = false;    bookmarksInserted = false;    setupTitleMap();}void HelpDialog::processEvents(){    qApp->processEvents(QEventLoop::ExcludeUserInputEvents);}void HelpDialog::lastWinClosed(){    lwClosed = true;}void HelpDialog::removeOldCacheFiles(bool onlyFulltextSearchIndex){    if (!verifyDirectory(cacheFilesPath)) {        qWarning("Failed to created assistant directory");        return;    }    QString pname = QLatin1String(".") + Config::configuration()->profileName();    QStringList fileList;    fileList << QLatin1String("indexdb40.dict")        << QLatin1String("indexdb40.doc");    if (!onlyFulltextSearchIndex)        fileList << QLatin1String("indexdb40") << QLatin1String("contentdb40");    QStringList::iterator it = fileList.begin();    for (; it != fileList.end(); ++it) {		if (QFile::exists(cacheFilesPath + QDir::separator() + *it + pname)) {            QFile f(cacheFilesPath + QDir::separator() + *it + pname);            f.remove();        }    }}void HelpDialog::timerEvent(QTimerEvent *e){    Q_UNUSED(e);    static int opacity = 255;    help->setWindowOpacity((opacity-=4)/255.0);    if (opacity<=0)        qApp->quit();}void HelpDialog::loadIndexFile(){    if (indexDone)        return;    setCursor(Qt::WaitCursor);    indexDone = true;    ui.labelPrepare->setText(tr("Prepare..."));    ui.framePrepare->show();    processEvents();    QProgressBar *bar = ui.progressPrepare;    bar->setMaximum(100);    bar->setValue(0);    keywordDocuments.clear();    QList<IndexKeyword> lst;    QFile indexFile(cacheFilesPath + QDir::separator() + QLatin1String("indexdb40.") +                     Config::configuration()->profileName());    if (!indexFile.open(QFile::ReadOnly)) {        buildKeywordDB();        processEvents();        if (lwClosed)            return;        if (!indexFile.open(QFile::ReadOnly)) {            QMessageBox::warning(help, tr("Qt Assistant"), tr("Failed to load keyword index file\n"                                                              "Assistant will not work!"));#if defined Q_WS_WIN || defined Q_WS_MACX            startTimer(50);#endif            return;        }    }    QDataStream ds(&indexFile);    quint32 fileAges;    ds >> fileAges;    if (fileAges != getFileAges()) {        indexFile.close();        buildKeywordDB();        if (!indexFile.open(QFile::ReadOnly)) {            QMessageBox::warning(help, tr("Qt Assistant"),                tr("Cannot open the index file %1").arg(QFileInfo(indexFile).absoluteFilePath()));            return;        }        ds.setDevice(&indexFile);        ds >> fileAges;    }    ds >> lst;    indexFile.close();    bar->setValue(bar->maximum());    processEvents();    for (int i=0; i<lst.count(); ++i) {        const IndexKeyword &idx = lst.at(i);        indexModel->addLink(idx.keyword, idx.link);        keywordDocuments << HelpDialog::removeAnchorFromLink(idx.link);    }    indexModel->publish();    ui.framePrepare->hide();    showInitDoneMessage();    setCursor(Qt::ArrowCursor);}quint32 HelpDialog::getFileAges(){    QStringList addDocuFiles = Config::configuration()->docFiles();    QStringList::const_iterator i = addDocuFiles.constBegin();    quint32 fileAges = 0;    for (; i != addDocuFiles.constEnd(); ++i) {        QFileInfo fi(*i);        if (fi.exists())            fileAges += fi.lastModified().toTime_t();    }    return fileAges;}void HelpDialog::buildKeywordDB(){    QStringList addDocuFiles = Config::configuration()->docFiles();    QStringList::iterator i = addDocuFiles.begin();    // Set up an indeterminate progress bar.    ui.labelPrepare->setText(tr("Prepare..."));    ui.progressPrepare->setMaximum(0);    ui.progressPrepare->setMinimum(0);    ui.progressPrepare->setValue(0);    processEvents();    QList<IndexKeyword> lst;    quint32 fileAges = 0;    for (i = addDocuFiles.begin(); i != addDocuFiles.end(); ++i) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?