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 + -
显示快捷键?