diff options
Diffstat (limited to 'tools')
372 files changed, 28757 insertions, 14089 deletions
diff --git a/tools/assistant/assistant.pro b/tools/assistant/assistant.pro index 08d0d4b..97196b2 100644 --- a/tools/assistant/assistant.pro +++ b/tools/assistant/assistant.pro @@ -3,6 +3,4 @@ CONFIG += ordered SUBDIRS += lib/fulltextsearch \ lib \ - tools \ - compat \ - compat/lib \
\ No newline at end of file + tools diff --git a/tools/assistant/compat/assistant.icns b/tools/assistant/compat/assistant.icns Binary files differdeleted file mode 100644 index 6291dd3..0000000 --- a/tools/assistant/compat/assistant.icns +++ /dev/null diff --git a/tools/assistant/compat/assistant.ico b/tools/assistant/compat/assistant.ico Binary files differdeleted file mode 100644 index 9e1b83f..0000000 --- a/tools/assistant/compat/assistant.ico +++ /dev/null diff --git a/tools/assistant/compat/assistant.pro b/tools/assistant/compat/assistant.pro deleted file mode 100644 index e865d6b..0000000 --- a/tools/assistant/compat/assistant.pro +++ /dev/null @@ -1,84 +0,0 @@ -include($$QT_SOURCE_TREE/tools/shared/fontpanel/fontpanel.pri) - -TEMPLATE = app -LANGUAGE = C++ -TARGET = assistant_adp - -CONFIG += qt warn_on - -unix:contains(QT_CONFIG, dbus):QT += dbus - -build_all:!build_pass { - CONFIG -= build_all - CONFIG += release -} -QT += xml network - -PROJECTNAME = Assistant -DESTDIR = ../../../bin - -FORMS += helpdialog.ui \ - mainwindow.ui \ - tabbedbrowser.ui \ - topicchooser.ui - -SOURCES += main.cpp \ - helpwindow.cpp \ - topicchooser.cpp \ - docuparser.cpp \ - index.cpp \ - profile.cpp \ - config.cpp \ - helpdialog.cpp \ - mainwindow.cpp \ - tabbedbrowser.cpp \ - fontsettingsdialog.cpp - -HEADERS += helpwindow.h \ - topicchooser.h \ - docuparser.h \ - index.h \ - profile.h \ - helpdialog.h \ - mainwindow.h \ - tabbedbrowser.h \ - config.h \ - fontsettingsdialog.h - -RESOURCES += assistant.qrc - -contains(QT_PRODUCT, OpenSource.*):DEFINES *= QT_OPENSOURCE -DEFINES += QT_KEYWORDS -#DEFINES += QT_PALMTOPCENTER_DOCS - -win32 { - !wince*:LIBS += -lshell32 - RC_FILE = assistant.rc -} - -mac { - ICON = assistant.icns - TARGET = Assistant_adp - QMAKE_INFO_PLIST = Info_mac.plist -} - -target.path=$$[QT_INSTALL_BINS] -INSTALLS += target - -TRANSLATIONS = assistant_de.ts - -unix:!contains(QT_CONFIG, zlib):LIBS += -lz - -contains(CONFIG, static): { - win32 { - exists($$[QT_INSTALL_PLUGINS]/imageformats/qjpeg.lib) { - QTPLUGIN += qjpeg - DEFINES += USE_STATIC_JPEG_PLUGIN - } - } else { - exists($$[QT_INSTALL_PLUGINS]/imageformats/qjpeg.a) { - QTPLUGIN += qjpeg - DEFINES += USE_STATIC_JPEG_PLUGIN - } - } -} diff --git a/tools/assistant/compat/assistant.qrc b/tools/assistant/compat/assistant.qrc deleted file mode 100644 index dae1f48..0000000 --- a/tools/assistant/compat/assistant.qrc +++ /dev/null @@ -1,37 +0,0 @@ -<RCC> - <qresource prefix="/trolltech/assistant" > - <file>images/assistant-128.png</file> - <file>images/assistant.png</file> - <file>images/close.png</file> - <file>images/designer.png</file> - <file>images/linguist.png</file> - <file>images/mac/addtab.png</file> - <file>images/mac/book.png</file> - <file>images/mac/closetab.png</file> - <file>images/mac/editcopy.png</file> - <file>images/mac/find.png</file> - <file>images/mac/home.png</file> - <file>images/mac/next.png</file> - <file>images/mac/prev.png</file> - <file>images/mac/print.png</file> - <file>images/mac/synctoc.png</file> - <file>images/mac/whatsthis.png</file> - <file>images/mac/zoomin.png</file> - <file>images/mac/zoomout.png</file> - <file>images/qt.png</file> - <file>images/win/addtab.png</file> - <file>images/win/book.png</file> - <file>images/win/closetab.png</file> - <file>images/win/editcopy.png</file> - <file>images/win/find.png</file> - <file>images/win/home.png</file> - <file>images/win/next.png</file> - <file>images/win/previous.png</file> - <file>images/win/print.png</file> - <file>images/win/synctoc.png</file> - <file>images/win/whatsthis.png</file> - <file>images/win/zoomin.png</file> - <file>images/win/zoomout.png</file> - <file>images/wrap.png</file> - </qresource> -</RCC> diff --git a/tools/assistant/compat/assistant.rc b/tools/assistant/compat/assistant.rc deleted file mode 100644 index b4786ce..0000000 --- a/tools/assistant/compat/assistant.rc +++ /dev/null @@ -1 +0,0 @@ -IDI_ICON1 ICON DISCARDABLE "assistant.ico" diff --git a/tools/assistant/compat/compat.pro b/tools/assistant/compat/compat.pro deleted file mode 100644 index 1086f4c..0000000 --- a/tools/assistant/compat/compat.pro +++ /dev/null @@ -1,84 +0,0 @@ -include($$QT_SOURCE_TREE/tools/shared/fontpanel/fontpanel.pri) - -TEMPLATE = app -LANGUAGE = C++ -TARGET = assistant_adp - -CONFIG += qt warn_on - -unix:contains(QT_CONFIG, dbus):QT += dbus - -build_all:!build_pass { - CONFIG -= build_all - CONFIG += release -} -QT += xml network - -PROJECTNAME = Assistant -DESTDIR = ../../../bin - -FORMS += helpdialog.ui \ - mainwindow.ui \ - tabbedbrowser.ui \ - topicchooser.ui - -SOURCES += main.cpp \ - helpwindow.cpp \ - topicchooser.cpp \ - docuparser.cpp \ - index.cpp \ - profile.cpp \ - config.cpp \ - helpdialog.cpp \ - mainwindow.cpp \ - tabbedbrowser.cpp \ - fontsettingsdialog.cpp - -HEADERS += helpwindow.h \ - topicchooser.h \ - docuparser.h \ - index.h \ - profile.h \ - helpdialog.h \ - mainwindow.h \ - tabbedbrowser.h \ - config.h \ - fontsettingsdialog.h - -RESOURCES += assistant.qrc - -contains(QT_PRODUCT, OpenSource.*):DEFINES *= QT_OPENSOURCE -DEFINES += QT_KEYWORDS -#DEFINES += QT_PALMTOPCENTER_DOCS - -win32 { - LIBS += -lshell32 - RC_FILE = assistant.rc -} - -mac { - ICON = assistant.icns - TARGET = Assistant_adp -# QMAKE_INFO_PLIST = Info_mac.plist -} - -target.path=$$[QT_INSTALL_BINS] -INSTALLS += target - -TRANSLATIONS = assistant_de.ts - -unix:!contains(QT_CONFIG, zlib):LIBS += -lz - -contains(CONFIG, static): { - win32 { - exists($$[QT_INSTALL_PLUGINS]/imageformats/qjpeg.lib) { - QTPLUGIN += qjpeg - DEFINES += USE_STATIC_JPEG_PLUGIN - } - } else { - exists($$[QT_INSTALL_PLUGINS]/imageformats/qjpeg.a) { - QTPLUGIN += qjpeg - DEFINES += USE_STATIC_JPEG_PLUGIN - } - } -} diff --git a/tools/assistant/compat/config.cpp b/tools/assistant/compat/config.cpp deleted file mode 100644 index 1faef42..0000000 --- a/tools/assistant/compat/config.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "config.h" -#include "profile.h" -#include "docuparser.h" - -#include <QApplication> -#include <QDesktopWidget> -#include <QLibraryInfo> -#include <QFont> -#include <QFontInfo> -#include <QDir> -#include <QFile> -#include <QFileInfo> -#include <QSettings> -#include <QList> - -QT_BEGIN_NAMESPACE - -static Config *static_configuration = 0; - -inline QString getVersionString() -{ - return QString::number( (QT_VERSION >> 16) & 0xff ) - + QLatin1String(".") + QString::number( (QT_VERSION >> 8) & 0xff ); -} - -Config::Config() - : profil( 0 ), hideSidebar( false ), rebuildDocs(true) -{ - if( !static_configuration ) { - static_configuration = this; - } else { - qWarning( "Multiple configurations not allowed!" ); - } -} - -Config *Config::loadConfig(const QString &profileFileName) -{ - Config *config = new Config(); - - if (profileFileName.isEmpty()) { // no profile - if (!config->defaultProfileExists()) { - config->profil = Profile::createDefaultProfile(); - config->saveProfile(config->profil); - } else { - config->profil = new Profile(); - } - config->loadDefaultProfile(); - config->load(); - return config; - } - - QFile file(profileFileName); - if (!file.exists()) { - qWarning( "File does not exist: %s", qPrintable(profileFileName) ); - return 0; - } - DocuParser *parser = DocuParser::createParser( profileFileName ); - if (!parser) { - qWarning( "Failed to create parser for file: %s", qPrintable(profileFileName) ); - return 0; - } - if (parser->parserVersion() < DocuParser::Qt320) { - qWarning( "File does not contain profile information" ); - return 0; - } - DocuParser320 *profileParser = static_cast<DocuParser320*>(parser); - parser->parse(&file); - config->profil = profileParser->profile(); - if (!config->profil) { - qWarning( "Config::loadConfig(), no profile in: %s", qPrintable(profileFileName) ); - return 0; - } - config->profil->setProfileType(Profile::UserProfile); - config->profil->setDocuParser(profileParser); - config->load(); - return config; -} - -Config *Config::configuration() -{ - Q_ASSERT( static_configuration ); - return static_configuration; -} - -void Config::load() -{ - const QString key = getVersionString() + QLatin1String("/"); - - bool isDefaultProfile = profil->props[QLatin1String("name")] == QLatin1String("default"); - const QString pKey = isDefaultProfile ? QString::fromLatin1(QT_VERSION_STR) - : getVersionString(); - - const QString profkey = pKey + QLatin1String("/Profile/") + profil->props[QLatin1String("name")] + QLatin1String("/"); - - QSettings settings; - - home = profil->props[QLatin1String("startpage")];; - if (home.isEmpty() && isDefaultProfile) - home = QLibraryInfo::location(QLibraryInfo::DocumentationPath) + QLatin1String("/html/index.html"); - src = settings.value( profkey + QLatin1String("Source") ).toStringList(); - sideBar = settings.value( key + QLatin1String("SideBarPage") ).toInt(); - if (qApp->type() != QApplication::Tty) - winGeometry = settings.value(key + QLatin1String("windowGeometry")).toByteArray(); - - mainWinState = settings.value(key + QLatin1String("MainWindowState")).toByteArray(); - pointFntSize = settings.value(key + QLatin1String("FontSize"), qApp->font().pointSizeF()).toDouble(); - rebuildDocs = settings.value( key + QLatin1String("RebuildDocDB"), true ).toBool(); - - profileNames = settings.value( key + QLatin1String("Profile") ).toStringList(); - - m_fontSettings.windowFont = qVariantValue<QFont>(settings.value(key + QLatin1String("windowfont"), qApp->font())); - m_fontSettings.browserFont = qVariantValue<QFont>(settings.value(key + QLatin1String("browserfont"), qApp->font())); - m_fontSettings.useWindowFont = settings.value(key + QLatin1String("usewindowfont"), false).toBool(); - m_fontSettings.useBrowserFont = settings.value(key + QLatin1String("usebrowserfont"), false).toBool(); - m_fontSettings.windowWritingSystem = static_cast<QFontDatabase::WritingSystem>( - settings.value(key + QLatin1String("windowwritingsystem"), QFontDatabase::Latin).toInt()); - m_fontSettings.browserWritingSystem = static_cast<QFontDatabase::WritingSystem>( - settings.value(key + QLatin1String("browserwritingsystem"), QFontDatabase::Latin).toInt()); - - m_fontSettings.browserFont.setPointSizeF(pointFntSize); -} - -void Config::save() -{ - saveSettings(); - saveProfile( profil ); -} - -void Config::saveSettings() -{ - const QString key = getVersionString() + QLatin1String("/"); - - const QString pKey = (profil->props[QLatin1String("name")] == QLatin1String("default")) - ? QString::fromLatin1(QT_VERSION_STR) - : getVersionString(); - - const QString profkey = pKey + QLatin1String("/Profile/") + profil->props[QLatin1String("name")] + QLatin1String("/"); - - QSettings settings; - - settings.setValue( profkey + QLatin1String("Source"), src ); - settings.setValue( key + QLatin1String("SideBarPage"), sideBarPage() ); - if (qApp->type() != QApplication::Tty) - settings.setValue(key + QLatin1String("windowGeometry"), winGeometry); - - settings.setValue( key + QLatin1String("MainWindowState"), mainWinState ); - settings.setValue( key + QLatin1String("FontSize"), pointFntSize); - settings.setValue( key + QLatin1String("RebuildDocDB"), rebuildDocs ); - - settings.setValue(key + QLatin1String("windowfont"), m_fontSettings.windowFont); - settings.setValue(key + QLatin1String("browserfont"), m_fontSettings.browserFont); - settings.setValue(key + QLatin1String("usewindowfont"), m_fontSettings.useWindowFont); - settings.setValue(key + QLatin1String("usebrowserfont"), m_fontSettings.useBrowserFont); - settings.setValue(key + QLatin1String("windowwritingsystem"), m_fontSettings.windowWritingSystem); - settings.setValue(key + QLatin1String("browserwritingsystem"), m_fontSettings.browserWritingSystem); -} - -#ifdef ASSISTANT_DEBUG -static void dumpmap( const QMap<QString,QString> &m, const QString &header ) -{ - qDebug( header ); - QMap<QString,QString>::ConstIterator it = m.begin(); - while (it != m.end()) { - qDebug( " " + it.key() + ":\t\t" + *it ); - ++it; - } -} -#endif - -bool Config::defaultProfileExists() -{ - QSettings settings; - const QString profKey = QLatin1String(QT_VERSION_STR) + QLatin1String("/Profile/default/"); - - if (settings.contains(profKey + QLatin1String("DocFiles")) - && settings.contains(profKey + QLatin1String("Titles")) - && settings.contains(profKey + QLatin1String("ImageDirs"))) { - QStringList dcfs = settings.value(profKey + QLatin1String("DocFiles") ).toStringList(); - foreach (QString file, dcfs) { - if (file == Profile::storableFilePath(file)) - return true; - } - } - return false; -} - -void Config::loadDefaultProfile() -{ - QSettings settings; - const QString profKey = QLatin1String(QT_VERSION_STR) + QLatin1String("/Profile/default/"); - - if (!defaultProfileExists()) - return; - - // Override the defaults with settings in registry. - profil->icons.clear(); - profil->indexPages.clear(); - profil->imageDirs.clear(); - profil->docs.clear(); - profil->dcfTitles.clear(); - - QStringList titles = settings.value( profKey + QLatin1String("Titles") ).toStringList(); - QStringList iconLst = settings.value( profKey + QLatin1String("DocIcons") ).toStringList(); - QStringList indexLst = settings.value( profKey + QLatin1String("IndexPages") ).toStringList(); - QStringList imgDirLst = settings.value( profKey + QLatin1String("ImageDirs") ).toStringList(); - QStringList dcfs = settings.value( profKey + QLatin1String("DocFiles") ).toStringList(); - profil->props[QLatin1String("name")] = QLatin1String("default"); - - QString filePath; - QStringList::ConstIterator it = titles.constBegin(); - QStringList::ConstIterator iconIt = iconLst.constBegin(); - QStringList::ConstIterator indexIt = indexLst.constBegin(); - QStringList::ConstIterator imageIt = imgDirLst.constBegin(); - QStringList::ConstIterator dcfIt = dcfs.constBegin(); - while((it != titles.constEnd()) - && (iconIt != iconLst.constEnd()) - && (indexIt != indexLst.constEnd()) - && (imageIt != imgDirLst.constEnd()) - && (dcfIt != dcfs.constEnd())) { - profil->addDCFIcon( *it, *iconIt ); - profil->addDCFIndexPage(*it, Profile::loadableFilePath(*indexIt)); - profil->addDCFImageDir( *it, *imageIt ); - profil->addDCFTitle(Profile::loadableFilePath(*dcfIt), *it); - ++it, ++iconIt, ++indexIt, ++imageIt, ++dcfIt; - } -#if ASSISTANT_DEBUG - dumpmap( profil->icons, QLatin1String("Icons") ); - dumpmap( profil->indexPages, QLatin1String("IndexPages") ); - dumpmap( profil->imageDirs, QLatin1String("ImageDirs") ); - dumpmap( profil->dcfTitles, QLatin1String("dcfTitles") ); - qDebug( "Docfiles: \n " + profil->docs.join( "\n " ) ); -#endif -} - -void Config::saveProfile( Profile *profile ) -{ - if (profil->profileType() == Profile::UserProfile) - return; - - const QString key = (profile->props[QLatin1String("name")] == QLatin1String("default")) - ? QString::fromLatin1(QT_VERSION_STR) - : getVersionString(); - - const QString profKey = key + QLatin1String("/Profile/") + profile->props[QLatin1String("name")] + QLatin1String("/"); - - QString path = QLibraryInfo::location(QLibraryInfo::DocumentationPath).replace(QLatin1String("\\"), QLatin1String("/")); - QStringList indexes, icons, imgDirs, dcfs; - QStringList titles = profile->dcfTitles.keys(); - QStringList::ConstIterator it = titles.constBegin(); - QString filePath; - for ( ; it != titles.constEnd(); ++it ) { - - indexes << Profile::storableFilePath(profile->indexPages[*it]); - icons << profile->icons[*it]; - imgDirs << profile->imageDirs[*it]; - dcfs << Profile::storableFilePath(profile->dcfTitles[*it]); - } - - QSettings settings; - settings.setValue( profKey + QLatin1String("Titles"), titles ); - settings.setValue( profKey + QLatin1String("DocFiles"), dcfs ); - settings.setValue( profKey + QLatin1String("IndexPages"), indexes ); - settings.setValue( profKey + QLatin1String("DocIcons"), icons ); - settings.setValue( profKey + QLatin1String("ImageDirs"), imgDirs ); - -#if ASSISTANT_DEBUG - qDebug() << "Titles:\n - " << ((QStringList*)&titles)->join("\n - "); - qDebug() << "Docfiles:\n - " << dcfs.join("\n - " ); - qDebug() << "IndexPages:\n - " << indexes.join("\n - "); - qDebug() << "DocIcons:\n - " << icons.join("\n - " ); - qDebug() << "ImageDirs:\n - " << imgDirs.join("\n - " ); -#endif -} - -QStringList Config::mimePaths() -{ - static QStringList lst; - - if( lst.count() > 0 ) - return lst; - - for (QMap<QString,QString>::ConstIterator it = profil->dcfTitles.constBegin(); - it != profil->dcfTitles.constEnd(); ++it ) { - - // Mime source for .dcf file path - QFileInfo info( *it ); - QString dcfPath = info.absolutePath(); - if (!lst.contains(dcfPath)) - lst << dcfPath; - - // Image dir for .dcf - QString imgDir = QDir::toNativeSeparators( dcfPath + QDir::separator() - + profil->imageDirs[it.key()] ); - if (!lst.contains(imgDir)) - lst << imgDir; - } - return lst; -} - -QStringList Config::profiles() const -{ - return profileNames; -} - -QString Config::title() const -{ - QString s = profil->props[QLatin1String("title")]; - if (s.isEmpty()) - s = QObject::tr("Qt Assistant by Nokia"); - return s; -} - -QString Config::aboutApplicationMenuText() const -{ - return profil->props[QLatin1String("aboutmenutext")]; -} - -QString Config::aboutURL() const -{ - return profil->props[QLatin1String("abouturl")]; -} - -QString Config::homePage() const -{ - return home.isEmpty() ? profil->props[QLatin1String("startpage")] : home; -} - -QStringList Config::source() const -{ - return src.size() == 0 ? QStringList(profil->props[QLatin1String("startpage")]) : src; -} - -QStringList Config::docFiles() const -{ - return profil->docs; -} - -QPixmap Config::docIcon( const QString &title ) const -{ - // ### To allow qdoc generated dcf files to reference the doc icons from qmake_image_col - QString name = profil->icons[title]; - QString resName = QLatin1String(":/trolltech/assistant/images/") + name; - - if (QFile::exists(resName)) - return QPixmap(resName); - - if (name.startsWith(QLatin1String("file:"))) - name = name.mid(5); - return QPixmap(name); -} - -QPixmap Config::applicationIcon() const -{ - QString name = profil->props[QLatin1String("applicationicon")]; - QString resName = QLatin1String(":/trolltech/assistant/images/") + name; - - if (QFile::exists(resName)) - return QPixmap(resName); - - if (name.startsWith(QLatin1String("file:"))) - name = name.mid(5); - return QPixmap(name); -} - -QStringList Config::docTitles() const -{ - return QStringList(profil->indexPages.keys()); -} - -QString Config::docImageDir( const QString &docfile ) const -{ - return profil->imageDirs[docfile]; -} - -QString Config::indexPage( const QString &title ) const -{ - return profil->indexPages[title]; -} - -void Config::hideSideBar( bool b ) -{ - hideSidebar = b; -} - -bool Config::sideBarHidden() const -{ - return hideSidebar; -} - -QString Config::assistantDocPath() const -{ - return profil->props[QLatin1String("assistantdocs")].isEmpty() - ? QLibraryInfo::location(QLibraryInfo::DocumentationPath) + QLatin1String("/html") - : profil->props[QLatin1String("assistantdocs")]; -} - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/config.h b/tools/assistant/compat/config.h deleted file mode 100644 index 498e6bb..0000000 --- a/tools/assistant/compat/config.h +++ /dev/null @@ -1,165 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef CONFIG_H -#define CONFIG_H - -#include "profile.h" - -#include <QString> -#include <QStringList> -#include <QPixmap> -#include <QMap> - -#include <QtGui/QFont> -#include <QtGui/QFontDatabase> - -QT_BEGIN_NAMESPACE - -class Profile; - -struct FontSettings -{ - FontSettings() : useWindowFont(false), useBrowserFont(false), - windowWritingSystem(QFontDatabase::Latin), browserWritingSystem(QFontDatabase::Latin) - { } - - QFont windowFont; - QFont browserFont; - - bool useWindowFont; - bool useBrowserFont; - - QFontDatabase::WritingSystem windowWritingSystem; - QFontDatabase::WritingSystem browserWritingSystem; -}; - -class Config -{ -public: - - Config(); - - void load(); - void save(); - Profile *profile() const { return profil; } - QString profileName() const { return profil->props[QLatin1String("name")]; } - bool validProfileName() const; - void hideSideBar( bool b ); - bool sideBarHidden() const; - QStringList mimePaths(); - - // From profile, read only - QStringList docFiles() const; - QStringList docTitles() const; - QString indexPage( const QString &title ) const; - QString docImageDir( const QString &title ) const; - QPixmap docIcon( const QString &title ) const; - - QStringList profiles() const; - QString title() const; - QString aboutApplicationMenuText() const; - QString aboutURL() const; - QPixmap applicationIcon() const; - - // From QSettings, read / write - QString homePage() const; - void setHomePage( const QString &hom ) { home = hom; } - - QStringList source() const; - void setSource( const QStringList &s ) { src = s; } - - int sideBarPage() const { return sideBar; } - void setSideBarPage( int sbp ) { sideBar = sbp; } - - QByteArray windowGeometry() const { return winGeometry; } - void setWindowGeometry( const QByteArray &geometry ) { winGeometry = geometry; } - - QByteArray mainWindowState() const { return mainWinState; } - void setMainWindowState( const QByteArray &state ) { mainWinState = state; } - - qreal fontPointSize() const { return pointFntSize; } - void setFontPointSize(qreal size) - { - pointFntSize = size; - m_fontSettings.useBrowserFont = true; - m_fontSettings.browserFont.setPointSizeF(size); - } - - FontSettings fontSettings() { return m_fontSettings; } - void setFontSettings(const FontSettings &settings) { m_fontSettings = settings; } - - QString assistantDocPath() const; - - bool docRebuild() const { return rebuildDocs; } - void setDocRebuild( bool rb ) { rebuildDocs = rb; } - - void saveProfile( Profile *profile ); - void loadDefaultProfile(); - bool defaultProfileExists(); - - static Config *configuration(); - static Config *loadConfig(const QString &profileFileName); - -private: - Config( const Config &c ); - Config& operator=( const Config &c ); - - void saveSettings(); - -private: - Profile *profil; - - QStringList profileNames; - QString home; - QStringList src; - QByteArray mainWinState; - QByteArray winGeometry; - qreal pointFntSize; - int sideBar; - bool hideSidebar; - bool rebuildDocs; - FontSettings m_fontSettings; -}; - -QT_END_NAMESPACE - -#endif // CONFIG_H diff --git a/tools/assistant/compat/docuparser.cpp b/tools/assistant/compat/docuparser.cpp deleted file mode 100644 index db2f824..0000000 --- a/tools/assistant/compat/docuparser.cpp +++ /dev/null @@ -1,433 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "docuparser.h" -#include "profile.h" - -#include <QDir> -#include <QFile> -#include <QFileInfo> -#include <QRegExp> -#include <QString> -#include <QDataStream> - -QT_BEGIN_NAMESPACE - -QDataStream &operator>>(QDataStream &s, ContentItem &ci) -{ - s >> ci.title; - s >> ci.reference; - s >> ci.depth; - return s; -} - -QDataStream &operator<<(QDataStream &s, const ContentItem &ci) -{ - s << ci.title; - s << ci.reference; - s << ci.depth; - return s; -} - -const QString DocuParser::DocumentKey = QLatin1String("/Qt Assistant/") + QLatin1String(QT_VERSION_STR) + QLatin1String("/"); - -DocuParser *DocuParser::createParser(const QString &fileName) -{ - QFile file(fileName); - if(!file.open(QFile::ReadOnly)) { - return 0; - } - - QString str; - int maxlen = 1024; - int majVer = 0, minVer = 0, serVer = 0; - static QRegExp re(QLatin1String("assistantconfig +version=\"(\\d)\\.(\\d)\\.(\\d)\""), Qt::CaseInsensitive); - Q_ASSERT(re.isValid()); - while(!(str = QLatin1String(file.readLine(maxlen))).isEmpty()) { - if(re.indexIn(str) >= 0) { - majVer = re.cap(1).toInt(); - minVer = re.cap(2).toInt(); - serVer = re.cap(3).toInt(); - break; - } - } - - if (majVer < 3 || (majVer == 3 && minVer < 2)) { - return new DocuParser310; - } - - return new DocuParser320; -} - - -bool DocuParser::parse(QFile *file) -{ - QXmlInputSource source(file); - QXmlSimpleReader reader; - reader.setContentHandler(this); - reader.setErrorHandler(this); - setFileName(QFileInfo(*file).absoluteFilePath()); - return reader.parse(source); -} - - -QString DocuParser::errorProtocol() const -{ - return errorProt; -} - - -QList<ContentItem> DocuParser::getContentItems() -{ - return contentList; -} - - -QList<IndexItem*> DocuParser::getIndexItems() -{ - return indexList; -} - -QString DocuParser::absolutify(const QString &name, bool makeUrl) const -{ - if (!name.isEmpty()) { - QString s = name; - s.replace(QLatin1String("\\"), QLatin1String("/")); - QFileInfo orgPath(name); - if(orgPath.isRelative()) - s = QFileInfo(fname).path() + QLatin1Char('/') + name; - if (makeUrl) - s.prepend(QLatin1String("file:")); - return s; - } - return name; -} - - -void DocuParser310::addTo(Profile *p) -{ - p->addDCFTitle(fname, docTitle); - p->addDCFIcon(docTitle, iconName); - p->addDCFIndexPage(docTitle, conURL); -} - - -bool DocuParser310::startDocument() -{ - state = StateInit; - errorProt = QLatin1String(""); - - contentRef = QLatin1String(""); - indexRef = QLatin1String(""); - depth = 0; - - contentList.clear(); - qDeleteAll(indexList); - indexList.clear(); - - return true; -} - - -bool DocuParser310::startElement(const QString &, const QString &, - const QString &qname, - const QXmlAttributes &attr) -{ - if (qname == QLatin1String("DCF") && state == StateInit) { - state = StateContent; - contentRef = absolutify(attr.value(QLatin1String("ref")), false); - conURL = contentRef; - docTitle = attr.value(QLatin1String("title")); - iconName = absolutify(attr.value(QLatin1String("icon")), false); - contentList.append(ContentItem(docTitle, absolutify(contentRef), depth)); - } else if (qname == QLatin1String("section") && (state == StateContent || state == StateSect)) { - state = StateSect; - contentRef = absolutify(attr.value(QLatin1String("ref"))); - title = attr.value(QLatin1String("title")); - depth++; - contentList.append(ContentItem(title, contentRef, depth)); - } else if (qname == QLatin1String("keyword") && state == StateSect) { - state = StateKeyword; - indexRef = absolutify(attr.value(QLatin1String("ref"))); - } else - return false; - return true; -} - -bool DocuParser310::endElement(const QString &nameSpace, const QString &localName, - const QString &qName) -{ - Q_UNUSED(nameSpace); - Q_UNUSED(localName); - Q_UNUSED(qName); - - switch(state) { - case StateInit: - break; - case StateContent: - state = StateInit; - break; - case StateSect: - state = --depth ? StateSect : StateContent; - break; - case StateKeyword: - state = StateSect; - break; - default: - break; - } - return true; -} - - -bool DocuParser310::characters(const QString& ch) -{ - QString str = ch.simplified(); - if (str.isEmpty()) - return true; - - switch (state) { - case StateInit: - case StateContent: - case StateSect: - return false; - break; - case StateKeyword: - indexList.append(new IndexItem(str, indexRef)); - break; - default: - return false; - } - return true; -} - - -bool DocuParser310::fatalError(const QXmlParseException& exception) -{ - errorProt += QString::fromLatin1("fatal parsing error: %1 in line %2, column %3\n") - .arg(exception.message()) - .arg(exception.lineNumber()) - .arg(exception.columnNumber()); - - return QXmlDefaultHandler::fatalError(exception); -} - - -DocuParser320::DocuParser320() - : prof(new Profile) -{ -} - - -void DocuParser320::addTo(Profile *p) -{ - QMap<QString,QString>::ConstIterator it; - - for (it = prof->dcfTitles.constBegin(); it != prof->dcfTitles.constEnd(); ++it) - p->dcfTitles[it.key()] = *it; - - for (it = prof->icons.constBegin(); it != prof->icons.constEnd(); ++it) - p->icons[it.key()] = *it; - - for (it = prof->indexPages.constBegin(); it != prof->indexPages.constEnd(); ++it) - p->indexPages[it.key()] = *it; -} - - -bool DocuParser320::startDocument() -{ - state = StateInit; - errorProt = QLatin1String(""); - - contentRef = QLatin1String(""); - indexRef = QLatin1String(""); - depth = 0; - contentList.clear(); - indexList.clear(); - - prof->addDCF(fname); - - return true; -} - -bool DocuParser320::startElement(const QString &, const QString &, - const QString &qname, - const QXmlAttributes &attr) -{ - QString lower = qname.toLower(); - - switch(state) { - - case StateInit: - if(lower == QLatin1String("assistantconfig")) - state = StateDocRoot; - break; - - case StateDocRoot: - if(lower == QLatin1String("dcf")) { - state = StateContent; - contentRef = absolutify(attr.value(QLatin1String("ref"))); - conURL = contentRef; - docTitle = attr.value(QLatin1String("title")); - iconName = absolutify(attr.value(QLatin1String("icon"))); - contentList.append(ContentItem(docTitle, contentRef, depth)); - } else if(lower == QLatin1String("profile")) { - state = StateProfile; - } - break; - - case StateSect: - if (lower == QLatin1String("keyword") && state == StateSect) { - state = StateKeyword; - indexRef = absolutify(attr.value(QLatin1String("ref"))); - break; - } // else if (lower == "section") - case StateContent: - if(lower == QLatin1String("section")) { - state = StateSect; - contentRef = absolutify(attr.value(QLatin1String("ref"))); - title = attr.value(QLatin1String("title")); - depth++; - contentList.append(ContentItem(title, contentRef, depth)); - } - break; - - case StateProfile: - if(lower == QLatin1String("property")) { - state = StateProperty; - propertyName = attr.value(QLatin1String("name")); - } - break; - - case StateProperty: - break; - - default: - break; - } - - return true; -} - -bool DocuParser320::endElement(const QString &nameSpace, - const QString &localName, - const QString &qName) -{ - Q_UNUSED(nameSpace); - Q_UNUSED(localName); - Q_UNUSED(qName); - - switch(state) { - case StateInit: - break; - case StateDocRoot: - state = StateInit; - break; - case StateProfile: - state = StateDocRoot; - break; - case StateProperty: - state = StateProfile; - if(propertyName.isEmpty() || propertyValue.isEmpty()) - return false; - { - static const QStringList lst = QStringList() - << QLatin1String("startpage") << QLatin1String("abouturl") - << QLatin1String("applicationicon") << QLatin1String("assistantdocs"); - - if (lst.contains(propertyName)) - propertyValue = absolutify(propertyValue); - } - prof->addProperty(propertyName, propertyValue); - break; - case StateContent: - if(!iconName.isEmpty()) - prof->addDCFIcon(docTitle, iconName); - if(contentRef.isEmpty()) - return false; - prof->addDCFIndexPage(docTitle, conURL); - prof->addDCFTitle(fname, docTitle); - state = StateDocRoot; - break; - case StateSect: - state = --depth ? StateSect : StateContent; - break; - case StateKeyword: - state = StateSect; - break; - } - return true; -} - -bool DocuParser320::characters(const QString& ch) -{ - QString str = ch.simplified(); - if (str.isEmpty()) - return true; - - switch (state) { - case StateInit: - case StateContent: - case StateSect: - return false; - break; - case StateKeyword: - indexList.append(new IndexItem(str, indexRef)); - break; - case StateProperty: - propertyValue = ch; - break; - default: - return false; - } - return true; -} - -bool DocuParser320::fatalError(const QXmlParseException& exception) -{ - errorProt += QString::fromLatin1("fatal parsing error: %1 in line %2, column %3\n") - .arg(exception.message()) - .arg(exception.lineNumber()) - .arg(exception.columnNumber()); - return QXmlDefaultHandler::fatalError(exception); -} - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/docuparser.h b/tools/assistant/compat/docuparser.h deleted file mode 100644 index 7c7692e..0000000 --- a/tools/assistant/compat/docuparser.h +++ /dev/null @@ -1,166 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef DOCUPARSER_H -#define DOCUPARSER_H - -#include <QList> -#include <QMap> -#include <QXmlDefaultHandler> -#include <QXmlAttributes> -#include <QXmlParseException> - -QT_BEGIN_NAMESPACE - -class Profile; - -struct ContentItem { - ContentItem() - : title( QString() ), reference( QString() ), depth( 0 ) {} - ContentItem( const QString &t, const QString &r, int d ) - : title( t ), reference( r ), depth( d ) {} - QString title; - QString reference; - int depth; - Q_DUMMY_COMPARISON_OPERATOR(ContentItem) -}; - -QDataStream &operator>>( QDataStream &s, ContentItem &ci ); -QDataStream &operator<<( QDataStream &s, const ContentItem &ci ); - -struct IndexItem { - IndexItem( const QString &k, const QString &r ) - : keyword( k ), reference( r ) {} - QString keyword; - QString reference; -}; - - - -class DocuParser : public QXmlDefaultHandler -{ -public: - enum ParserVersion { Qt310, Qt320 }; - // Since We don't want problems with documentation - // from version to version, this string stores the correct - // version string to save documents. - static const QString DocumentKey; - - static DocuParser *createParser( const QString &fileName ); - - virtual bool parse( QFile *file ); - - QList<ContentItem> getContentItems(); - QList<IndexItem*> getIndexItems(); - - QString errorProtocol() const; - QString contentsURL() const { return conURL; } - - virtual ParserVersion parserVersion() const = 0; - virtual void addTo( Profile *p ) = 0; - - QString fileName() const { return fname; } - void setFileName( const QString &file ) { fname = file; } - -protected: - QString absolutify( const QString &input, bool makeUrl = true ) const; - - QString contentRef, indexRef, errorProt, conURL; - QString docTitle, title, iconName; - QList<ContentItem> contentList; - QList<IndexItem*> indexList; - QString fname; -}; - - -class DocuParser310 : public DocuParser -{ -public: - enum States{ StateInit, StateContent, StateSect, StateKeyword }; - - bool startDocument(); - bool startElement( const QString&, const QString&, const QString& , - const QXmlAttributes& ); - bool endElement( const QString&, const QString&, const QString& ); - bool characters( const QString & ); - bool fatalError( const QXmlParseException& exception ); - - virtual ParserVersion parserVersion() const { return Qt310; } - virtual void addTo( Profile *p ); - -private: - States state; - int depth; -}; - - -class DocuParser320 : public DocuParser -{ -public: - enum States { StateInit, StateDocRoot, StateProfile, StateProperty, - StateContent, StateSect, StateKeyword }; - - DocuParser320(); - - bool startDocument(); - bool startElement( const QString&, const QString&, const QString& , - const QXmlAttributes& ); - bool endElement( const QString&, const QString&, const QString& ); - bool characters( const QString & ); - bool fatalError( const QXmlParseException& exception ); - - virtual ParserVersion parserVersion() const { return Qt320; } - virtual void addTo( Profile *p ); - Profile *profile() const { return prof; } - -private: - - States state; - int depth; - int docfileCounter; - QString propertyValue; - QString propertyName; - Profile *prof; -}; - -QT_END_NAMESPACE - -#endif // DOCUPARSER_H diff --git a/tools/assistant/compat/fontsettingsdialog.cpp b/tools/assistant/compat/fontsettingsdialog.cpp deleted file mode 100644 index 31a3241..0000000 --- a/tools/assistant/compat/fontsettingsdialog.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "fontsettingsdialog.h" -#include "fontpanel.h" -#include "config.h" - -#include <QtGui/QLabel> -#include <QtGui/QComboBox> -#include <QtGui/QHBoxLayout> -#include <QtGui/QVBoxLayout> -#include <QtGui/QApplication> -#include <QtGui/QStackedWidget> -#include <QtGui/QDialogButtonBox> - -QT_BEGIN_NAMESPACE - -FontSettingsDialog::FontSettingsDialog(QWidget *parent) - : QDialog(parent) - , m_windowFontPanel(new FontPanel(this)) - , m_browserFontPanel(new FontPanel(this)) - , m_dialogButtonBox(new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel)) -{ - setModal(true); - setWindowTitle(tr("Font Settings")); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - - QVBoxLayout *mainVLayout = new QVBoxLayout(this); - QHBoxLayout *hboxLayout = new QHBoxLayout; - mainVLayout->addLayout(hboxLayout); - - QLabel *label = new QLabel(tr("Font settings for:"), this); - label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); - hboxLayout->addWidget(label); - QComboBox *comboBox = new QComboBox(this); - comboBox->addItem(tr("Browser")); - comboBox->addItem(tr("Application")); - hboxLayout->addWidget(comboBox); - - m_windowFontPanel->setCheckable(true); - m_browserFontPanel->setCheckable(true); - - const QString customSettings(tr("Use custom settings")); - m_windowFontPanel->setTitle(customSettings); - m_browserFontPanel->setTitle(customSettings); - - QStackedWidget *stackWidget = new QStackedWidget(this); - stackWidget->addWidget(m_browserFontPanel); - stackWidget->addWidget(m_windowFontPanel); - - mainVLayout->addWidget(stackWidget); - mainVLayout->addWidget(m_dialogButtonBox); - - connect(m_dialogButtonBox , SIGNAL(rejected()), this, SLOT(reject())); - connect(m_dialogButtonBox , SIGNAL(accepted()), this, SLOT(accept())); - connect(comboBox, SIGNAL(activated(int)), stackWidget, SLOT(setCurrentIndex(int))); -} - -FontSettingsDialog::~FontSettingsDialog() -{ - // nothing todo -} - -bool FontSettingsDialog::showDialog(FontSettings *settings) -{ - setupFontSettingsDialog(settings); - - if (exec() != Accepted) - return false; - - updateFontSettings(settings); - return true; -} - -void FontSettingsDialog::updateFontSettings(FontSettings *settings) -{ - settings->useWindowFont = m_windowFontPanel->isChecked(); - settings->useBrowserFont = m_browserFontPanel->isChecked(); - - settings->windowFont = settings->useWindowFont ? m_windowFontPanel->selectedFont() : qApp->font(); - settings->browserFont = settings->useBrowserFont ? m_browserFontPanel->selectedFont() : qApp->font(); - - settings->windowWritingSystem = settings->useWindowFont ? m_windowFontPanel->writingSystem() : QFontDatabase::Latin; - settings->browserWritingSystem = settings->useBrowserFont ? m_browserFontPanel->writingSystem() : QFontDatabase::Latin; -} - -void FontSettingsDialog::setupFontSettingsDialog(const FontSettings *settings) -{ - m_windowFontPanel->setSelectedFont(settings->windowFont); - m_browserFontPanel->setSelectedFont(settings->browserFont); - - m_windowFontPanel->setWritingSystem(settings->windowWritingSystem); - m_browserFontPanel->setWritingSystem(settings->browserWritingSystem); - - m_windowFontPanel->setChecked(settings->useWindowFont); - m_browserFontPanel->setChecked(settings->useBrowserFont); -} - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/helpdialog.cpp b/tools/assistant/compat/helpdialog.cpp deleted file mode 100644 index 23c1bfc..0000000 --- a/tools/assistant/compat/helpdialog.cpp +++ /dev/null @@ -1,1331 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#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 <QtCore/QVarLengthArray> - -#include <stdlib.h> -#include <limits.h> - -QT_BEGIN_NAMESPACE - -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(QString)), this, SLOT(updateSearchButton(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) { - QFile file(*i); - if (!file.exists()) { - QMessageBox::warning(this, tr("Warning"), - tr("Documentation file %1 does not exist!\n" - "Skipping file.").arg(QFileInfo(file).absoluteFilePath())); - continue; - } - fileAges += QFileInfo(file).lastModified().toTime_t(); - DocuParser *handler = DocuParser::createParser(*i); - bool ok = handler->parse(&file); - file.close(); - if (!ok){ - QString msg = QString::fromLatin1("In file %1:\n%2") - .arg(QFileInfo(file).absoluteFilePath()) - .arg(handler->errorProtocol()); - QMessageBox::critical(this, tr("Parse Error"), tr(msg.toUtf8())); - delete handler; - continue; - } - - QList<IndexItem*> indLst = handler->getIndexItems(); - int counter = 0; - foreach (IndexItem *indItem, indLst) { - QFileInfo fi(indItem->reference); - lst.append(IndexKeyword(indItem->keyword, indItem->reference)); - - if (++counter%100 == 0) { - if (ui.progressPrepare) - ui.progressPrepare->setValue(counter); - processEvents(); - if (lwClosed) { - return; - } - } - } - delete handler; - } - if (!lst.isEmpty()) - qSort(lst); - - QFile indexout(cacheFilesPath + QDir::separator() + QLatin1String("indexdb40.") - + Config::configuration()->profileName()); - if (verifyDirectory(cacheFilesPath) && indexout.open(QFile::WriteOnly)) { - QDataStream s(&indexout); - s << fileAges; - s << lst; - indexout.close(); - } -} - -void HelpDialog::setupTitleMap() -{ - if (titleMapDone) - return; - - bool needRebuild = false; - if (Config::configuration()->profileName() == QLatin1String("default")) { - const QStringList docuFiles = Config::configuration()->docFiles(); - for (QStringList::ConstIterator it = docuFiles.begin(); it != docuFiles.end(); ++it) { - if (!QFile::exists(*it)) { - Config::configuration()->saveProfile(Profile::createDefaultProfile()); - Config::configuration()->loadDefaultProfile(); - needRebuild = true; - break; - } - } - } - - if (Config::configuration()->docRebuild() || needRebuild) { - removeOldCacheFiles(); - Config::configuration()->setDocRebuild(false); - Config::configuration()->saveProfile(Config::configuration()->profile()); - } - if (contentList.isEmpty()) - getAllContents(); - - titleMapDone = true; - titleMap.clear(); - for (QList<QPair<QString, ContentList> >::Iterator it = contentList.begin(); it != contentList.end(); ++it) { - ContentList lst = (*it).second; - foreach (ContentItem item, lst) { - titleMap[item.reference] = item.title.trimmed(); - } - } - processEvents(); -} - -void HelpDialog::getAllContents() -{ - QFile contentFile(cacheFilesPath + QDir::separator() + QLatin1String("contentdb40.") - + Config::configuration()->profileName()); - contentList.clear(); - if (!contentFile.open(QFile::ReadOnly)) { - buildContentDict(); - return; - } - - QDataStream ds(&contentFile); - quint32 fileAges; - ds >> fileAges; - if (fileAges != getFileAges()) { - contentFile.close(); - removeOldCacheFiles(true); - buildContentDict(); - return; - } - QString key; - QList<ContentItem> lst; - while (!ds.atEnd()) { - ds >> key; - ds >> lst; - contentList += qMakePair(key, QList<ContentItem>(lst)); - } - contentFile.close(); - processEvents(); - -} - -void HelpDialog::buildContentDict() -{ - QStringList docuFiles = Config::configuration()->docFiles(); - - quint32 fileAges = 0; - for (QStringList::iterator it = docuFiles.begin(); it != docuFiles.end(); ++it) { - QFile file(*it); - if (!file.exists()) { - QMessageBox::warning(this, tr("Warning"), - tr("Documentation file %1 does not exist!\n" - "Skipping file.").arg(QFileInfo(file).absoluteFilePath())); - continue; - } - fileAges += QFileInfo(file).lastModified().toTime_t(); - DocuParser *handler = DocuParser::createParser(*it); - if (!handler) { - QMessageBox::warning(this, tr("Warning"), - tr("Documentation file %1 is not compatible!\n" - "Skipping file.").arg(QFileInfo(file).absoluteFilePath())); - continue; - } - bool ok = handler->parse(&file); - file.close(); - if (ok) { - contentList += qMakePair(*it, QList<ContentItem>(handler->getContentItems())); - delete handler; - } else { - QString msg = QString::fromLatin1("In file %1:\n%2") - .arg(QFileInfo(file).absoluteFilePath()) - .arg(handler->errorProtocol()); - QMessageBox::critical(this, tr("Parse Error"), tr(msg.toUtf8())); - continue; - } - } - - QFile contentOut(cacheFilesPath + QDir::separator() + QLatin1String("contentdb40.") - + Config::configuration()->profileName()); - if (contentOut.open(QFile::WriteOnly)) { - QDataStream s(&contentOut); - s << fileAges; - for (QList<QPair<QString, ContentList> >::Iterator it = contentList.begin(); it != contentList.end(); ++it) { - s << *it; - } - contentOut.close(); - } -} - -void HelpDialog::currentTabChanged(int index) -{ - QString s = ui.tabWidget->widget(index)->objectName(); - if (s == QLatin1String("indexPage")) - QTimer::singleShot(0, this, SLOT(loadIndexFile())); - else if (s == QLatin1String("bookmarkPage")) - insertBookmarks(); - else if (s == QLatin1String("contentPage")) - QTimer::singleShot(0, this, SLOT(insertContents())); - else if (s == QLatin1String("searchPage")) - QTimer::singleShot(0, this, SLOT(setupFullTextIndex())); -} - -void HelpDialog::showInitDoneMessage() -{ - if (initDoneMsgShown) - return; - initDoneMsgShown = true; - help->statusBar()->showMessage(tr("Done"), 3000); -} - -void HelpDialog::showTopic(QTreeWidgetItem *item) -{ - if (item) - showTopic(); -} - -void HelpDialog::showTopic() -{ - QString tabName = ui.tabWidget->currentWidget()->objectName(); - - if (tabName == QLatin1String("indexPage")) - showIndexTopic(); - else if (tabName == QLatin1String("bookmarkPage")) - showBookmarkTopic(); - else if (tabName == QLatin1String("contentPage")) - showContentsTopic(); -} - -void HelpDialog::showIndexTopic() -{ - int row = ui.listIndex->currentIndex().row(); - if (row == -1 || row >= indexModel->rowCount()) - return; - - QString description = indexModel->description(row); - QStringList links = indexModel->links(row); - - bool blocked = ui.editIndex->blockSignals(true); - ui.editIndex->setText(description); - ui.editIndex->blockSignals(blocked); - - if (links.count() == 1) { - emit showLink(links.first()); - } else { - qSort(links); - QStringList::Iterator it = links.begin(); - QStringList linkList; - QStringList linkNames; - for (; it != links.end(); ++it) { - linkList << *it; - linkNames << titleOfLink(*it); - } - QString link = TopicChooser::getLink(this, linkNames, linkList, description); - if (!link.isEmpty()) - emit showLink(link); - } - - ui.listIndex->setCurrentIndex(indexModel->index(indexModel->stringList().indexOf(description))); - ui.listIndex->scrollTo(ui.listIndex->currentIndex(), QAbstractItemView::PositionAtTop); -} - -void HelpDialog::searchInIndex(const QString &searchString) -{ - QRegExp atoz(QLatin1String("[A-Z]")); - int matches = searchString.count(atoz); - if (matches > 0 && !searchString.contains(QLatin1String(".*"))) - { - int start = 0; - QString newSearch; - for (; matches > 0; --matches) { - int match = searchString.indexOf(atoz, start+1); - if (match <= start) - continue; - newSearch += searchString.mid(start, match-start); - newSearch += QLatin1String(".*"); - start = match; - } - newSearch += searchString.mid(start); - ui.listIndex->setCurrentIndex(indexModel->filter(newSearch, searchString)); - } - else - ui.listIndex->setCurrentIndex(indexModel->filter(searchString, searchString)); -} - -QString HelpDialog::titleOfLink(const QString &link) -{ - QString s = HelpDialog::removeAnchorFromLink(link); - s = titleMap[s]; - if (s.isEmpty()) - return link; - return s; -} - -bool HelpDialog::eventFilter(QObject * o, QEvent * e) -{ - if (o == ui.editIndex && e->type() == QEvent::KeyPress) { - switch (static_cast<QKeyEvent*>(e)->key()) { - case Qt::Key_Up: - case Qt::Key_Down: - case Qt::Key_PageDown: - case Qt::Key_PageUp: - QApplication::sendEvent(ui.listIndex, e); - break; - - default: - break; - } - } else if (o == ui.listContents->viewport()) { - if (e->type() == QEvent::MouseButtonRelease) { - QMouseEvent *me = static_cast<QMouseEvent*>(e); - if (me->button() == Qt::LeftButton) { - QTreeWidgetItem *item = ui.listContents->itemAt(me->pos()); - QRect vRect = ui.listContents->visualItemRect(item); - - // only show topic if we clicked an item - if (item && vRect.contains(me->pos())) - showTopic(item); - } - } - } - - return QWidget::eventFilter(o, e); -} - -void HelpDialog::addBookmark() -{ - if (!bookmarksInserted) - insertBookmarks(); - QString link = help->browsers()->currentBrowser()->source().toString(); - QString title = help->browsers()->currentBrowser()->documentTitle(); - if (title.isEmpty()) - title = titleOfLink(link); - - QTreeWidgetItem *i = new QTreeWidgetItem(ui.listBookmarks, 0); - i->setText(0, title); - i->setData(0, LinkRole, link); - ui.buttonRemove->setEnabled(true); - saveBookmarks(); - help->updateBookmarkMenu(); -} - -void HelpDialog::on_buttonAdd_clicked() -{ - addBookmark(); -} - -void HelpDialog::on_buttonRemove_clicked() -{ - if (!ui.listBookmarks->currentItem()) - return; - - delete ui.listBookmarks->currentItem(); - saveBookmarks(); - if (ui.listBookmarks->topLevelItemCount() != 0) { - ui.listBookmarks->setCurrentItem(ui.listBookmarks->topLevelItem(0)); - } - ui.buttonRemove->setEnabled(ui.listBookmarks->topLevelItemCount() > 0); - help->updateBookmarkMenu(); -} - -void HelpDialog::insertBookmarks() -{ - if (bookmarksInserted) - return; - bookmarksInserted = true; - ui.listBookmarks->clear(); - QFile f(cacheFilesPath + QDir::separator() + QLatin1String("bookmarks.") - + Config::configuration()->profileName()); - if (!f.open(QFile::ReadOnly)) - return; - QTextStream ts(&f); - while (!ts.atEnd()) { - QTreeWidgetItem *i = new QTreeWidgetItem(ui.listBookmarks, 0); - i->setText(0, ts.readLine()); - i->setData(0, LinkRole, ts.readLine()); - } - ui.buttonRemove->setEnabled(ui.listBookmarks->topLevelItemCount() > 0); - help->updateBookmarkMenu(); - showInitDoneMessage(); -} - -void HelpDialog::showBookmarkTopic() -{ - if (!ui.listBookmarks->currentItem()) - return; - - QTreeWidgetItem *i = (QTreeWidgetItem*)ui.listBookmarks->currentItem(); - emit showLink(i->data(0, LinkRole).toString()); -} - -static void store(QTreeWidgetItem *i, QTextStream &ts) -{ - ts << i->text(0) << endl; - ts << i->data(0, LinkRole).toString() << endl; - - for (int index = 0; index < i->childCount(); ++index) - store(i->child(index), ts); -} - -static void store(QTreeWidget *tw, QTextStream &ts) -{ - for (int index = 0; index < tw->topLevelItemCount(); ++index) - store(tw->topLevelItem(index), ts); -} - -void HelpDialog::saveBookmarks() -{ - QFile f(cacheFilesPath + QDir::separator() + QLatin1String("bookmarks.") - + Config::configuration()->profileName()); - if (!f.open(QFile::WriteOnly)) - return; - - QTextStream ts(&f); - store(ui.listBookmarks, ts); - f.close(); -} - -void HelpDialog::insertContents() -{ -#ifdef Q_WS_MAC - static const QLatin1String IconPath(":/trolltech/assistant/images/mac/book.png"); -#else - static const QLatin1String IconPath(":/trolltech/assistant/images/win/book.png"); -#endif - if (contentsInserted) - return; - - if (contentList.isEmpty()) - getAllContents(); - - contentsInserted = true; - ui.listContents->clear(); - setCursor(Qt::WaitCursor); - if (!titleMapDone) - setupTitleMap(); - -#if 0 // ### port me - ui.listContents->setSorting(-1); -#endif - - for (QList<QPair<QString, ContentList> >::Iterator it = contentList.begin(); it != contentList.end(); ++it) { - QTreeWidgetItem *newEntry = 0; - - QTreeWidgetItem *contentEntry = 0; - QStack<QTreeWidgetItem*> stack; - stack.clear(); - int depth = 0; - bool root = false; - - const int depthSize = 32; - QVarLengthArray<QTreeWidgetItem*, depthSize> lastItem(depthSize); - - ContentList lst = (*it).second; - for (ContentList::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it) { - ContentItem item = *it; - if (item.depth == 0) { - lastItem[0] = 0; - newEntry = new QTreeWidgetItem(ui.listContents, 0); - newEntry->setIcon(0, QIcon(IconPath)); - newEntry->setText(0, item.title); - newEntry->setData(0, LinkRole, item.reference); - stack.push(newEntry); - depth = 1; - root = true; - } - else{ - if ((item.depth > depth) && root) { - depth = item.depth; - stack.push(contentEntry); - } - if (item.depth == depth) { - if (lastItem.capacity() == depth) - lastItem.resize(depth + depthSize); - contentEntry = new QTreeWidgetItem(stack.top(), lastItem[ depth ]); - lastItem[ depth ] = contentEntry; - contentEntry->setText(0, item.title); - contentEntry->setData(0, LinkRole, item.reference); - } - else if (item.depth < depth) { - stack.pop(); - depth--; - item = *(--it); - } - } - } - processEvents(); - } - setCursor(Qt::ArrowCursor); - showInitDoneMessage(); -} - -void HelpDialog::showContentsTopic() -{ - QTreeWidgetItem *i = (QTreeWidgetItem*)ui.listContents->currentItem(); - if (!i) - return; - emit showLink(i->data(0, LinkRole).toString()); -} - -QTreeWidgetItem * HelpDialog::locateLink(QTreeWidgetItem *item, const QString &link) -{ - QTreeWidgetItem *child = 0; -#ifdef Q_OS_WIN - Qt::CaseSensitivity checkCase = Qt::CaseInsensitive; -#else - Qt::CaseSensitivity checkCase = Qt::CaseSensitive; -#endif - for (int i = 0, childCount = item->childCount(); i<childCount; i++) { - child = item->child(i); - ///check whether it is this item - if (link.startsWith(child->data(0, LinkRole).toString(), checkCase)) - break; - //check if the link is a child of this item - else if (child->childCount()) { - child = locateLink(child, link); - if (child) - break; - } - child = 0; - } - return child; -} - -void HelpDialog::locateContents(const QString &link) -{ - //ensure the TOC is filled - if (!contentsInserted) - insertContents(); -#ifdef Q_OS_WIN - Qt::CaseSensitivity checkCase = Qt::CaseInsensitive; -#else - Qt::CaseSensitivity checkCase = Qt::CaseSensitive; -#endif - QString findLink(link); - //Installations on a windows local drive will give the 'link' as <file:///C:/xxx> - //and the contents in the TOC will be <file:C:/xxx>. - //But on others the 'link' of format <file:///root/xxx> - //and the contents in the TOC will be <file:/root/xxx>. - if (findLink.contains(QLatin1String("file:///"))) { - if (findLink[9] == QLatin1Char(':')) //on windows drives - findLink.replace(0, 8, QLatin1String("file:")); - else - findLink.replace(0, 8, QLatin1String("file:/")); - } - - bool topLevel = false; - QTreeWidgetItem *item = 0; - int totalItems = ui.listContents->topLevelItemCount(); - - for (int i = 0; i < totalItems; i++ ) { - // first see if we are one of the top level items - item = (QTreeWidgetItem*)ui.listContents->topLevelItem(i); - if (findLink.startsWith(item->data(0, LinkRole).toString(), checkCase)) { - topLevel = true; - break; - } - } - - if (!topLevel) { - // now try to find it in the sublevel items - for (int n = 0; n < totalItems; ++n) { - item = (QTreeWidgetItem*)ui.listContents->topLevelItem(n); - item = locateLink(item, findLink); - if (item) - break; - } - } - - //remove the old selection - QList<QTreeWidgetItem *> selected = ui.listContents->selectedItems(); - foreach(QTreeWidgetItem *sel, selected) - ui.listContents->setItemSelected(sel, false); - - //set the TOC item and show - ui.listContents->setCurrentItem(item); - ui.listContents->setItemSelected(item, true); - ui.listContents->scrollToItem(item); -} - -void HelpDialog::toggleContents() -{ - if (!isVisible() || ui.tabWidget->currentIndex() != 0) { - ui.tabWidget->setCurrentIndex(0); - parentWidget()->show(); - } - else - parentWidget()->hide(); -} - -void HelpDialog::toggleIndex() -{ - if (!isVisible() || ui.tabWidget->currentIndex() != 1 || !ui.editIndex->hasFocus()) { - ui.tabWidget->setCurrentIndex(1); - parentWidget()->show(); - ui.editIndex->setFocus(); - } - else - parentWidget()->hide(); -} - -void HelpDialog::toggleBookmarks() -{ - if (!isVisible() || ui.tabWidget->currentIndex() != 2) { - ui.tabWidget->setCurrentIndex(2); - parentWidget()->show(); - } - else - parentWidget()->hide(); -} - -void HelpDialog::toggleSearch() -{ - if (!isVisible() || ui.tabWidget->currentIndex() != 3) { - ui.tabWidget->setCurrentIndex(3); - parentWidget()->show(); - } - else - parentWidget()->hide(); -} - -void HelpDialog::setupFullTextIndex() -{ - if (fullTextIndex) - return; - - QString pname = Config::configuration()->profileName(); - fullTextIndex = new Index(QStringList(), QDir::homePath()); // ### Is this correct ? - if (!verifyDirectory(cacheFilesPath)) { - QMessageBox::warning(help, tr("Qt Assistant"), - tr("Failed to save fulltext search index\n" - "Assistant will not work!")); - return; - } - fullTextIndex->setDictionaryFile(cacheFilesPath + QDir::separator() + QLatin1String("indexdb40.dict.") + pname); - fullTextIndex->setDocListFile(cacheFilesPath + QDir::separator() + QLatin1String("indexdb40.doc.") + pname); - processEvents(); - - connect(fullTextIndex, SIGNAL(indexingProgress(int)), - this, SLOT(setIndexingProgress(int))); - QFile f(cacheFilesPath + QDir::separator() + QLatin1String("indexdb40.dict.") + pname); - if (!f.exists()) { - QString doc; - QSet<QString> documentSet; - QMap<QString, QString>::ConstIterator it = titleMap.constBegin(); - for (; it != titleMap.constEnd(); ++it) { - doc = HelpDialog::removeAnchorFromLink(it.key()); - if (!doc.isEmpty()) - documentSet.insert(doc); - } - loadIndexFile(); - for ( QStringList::Iterator it = keywordDocuments.begin(); it != keywordDocuments.end(); ++it ) { - if (!(*it).isEmpty()) - documentSet.insert(*it); - } - fullTextIndex->setDocList( documentSet.toList() ); - - help->statusBar()->clearMessage(); - setCursor(Qt::WaitCursor); - ui.labelPrepare->setText(tr("Indexing files...")); - ui.progressPrepare->setMaximum(100); - ui.progressPrepare->reset(); - ui.progressPrepare->show(); - ui.framePrepare->show(); - processEvents(); - if (fullTextIndex->makeIndex() == -1) - return; - fullTextIndex->writeDict(); - ui.progressPrepare->setValue(100); - ui.framePrepare->hide(); - setCursor(Qt::ArrowCursor); - showInitDoneMessage(); - } else { - setCursor(Qt::WaitCursor); - help->statusBar()->showMessage(tr("Reading dictionary...")); - processEvents(); - fullTextIndex->readDict(); - help->statusBar()->showMessage(tr("Done"), 3000); - setCursor(Qt::ArrowCursor); - } - keywordDocuments.clear(); -} - -void HelpDialog::setIndexingProgress(int prog) -{ - ui.progressPrepare->setValue(prog); - processEvents(); -} - -void HelpDialog::startSearch() -{ - QString str = ui.termsEdit->text(); - str = str.simplified(); - str = str.replace(QLatin1String("\'"), QLatin1String("\"")); - str = str.replace(QLatin1String("`"), QLatin1String("\"")); - QString buf = str; - str = str.replace(QLatin1String("-"), QLatin1String(" ")); - str = str.replace(QRegExp(QLatin1String("\\s[\\S]?\\s")), QLatin1String(" ")); - terms = str.split(QLatin1Char(' ')); - QStringList termSeq; - QStringList seqWords; - QStringList::iterator it = terms.begin(); - for (; it != terms.end(); ++it) { - (*it) = (*it).simplified(); - (*it) = (*it).toLower(); - (*it) = (*it).replace(QLatin1String("\""), QLatin1String("")); - } - if (str.contains(QLatin1Char('\"'))) { - if ((str.count(QLatin1Char('\"')))%2 == 0) { - int beg = 0; - int end = 0; - QString s; - beg = str.indexOf(QLatin1Char('\"'), beg); - while (beg != -1) { - beg++; - end = str.indexOf(QLatin1Char('\"'), beg); - s = str.mid(beg, end - beg); - s = s.toLower(); - s = s.simplified(); - if (s.contains(QLatin1Char('*'))) { - QMessageBox::warning(this, tr("Full Text Search"), - tr("Using a wildcard within phrases is not allowed.")); - return; - } - seqWords += s.split(QLatin1Char(' ')); - termSeq << s; - beg = str.indexOf(QLatin1Char('\"'), end + 1); - } - } else { - QMessageBox::warning(this, tr("Full Text Search"), - tr("The closing quotation mark is missing.")); - return; - } - } - setCursor(Qt::WaitCursor); - foundDocs.clear(); - foundDocs = fullTextIndex->query(terms, termSeq, seqWords); - QString msg = tr("%n document(s) found.", "", foundDocs.count()); - help->statusBar()->showMessage(tr(msg.toUtf8()), 3000); - ui.resultBox->clear(); - for (it = foundDocs.begin(); it != foundDocs.end(); ++it) - ui.resultBox->addItem(fullTextIndex->getDocumentTitle(*it)); - - terms.clear(); - bool isPhrase = false; - QString s; - for (int i = 0; i < (int)buf.length(); ++i) { - if (buf[i] == QLatin1Char('\"')) { - isPhrase = !isPhrase; - s = s.simplified(); - if (!s.isEmpty()) - terms << s; - s = QLatin1String(""); - } else if (buf[i] == QLatin1Char(' ') && !isPhrase) { - s = s.simplified(); - if (!s.isEmpty()) - terms << s; - s = QLatin1String(""); - } else - s += buf[i]; - } - if (!s.isEmpty()) - terms << s; - - setCursor(Qt::ArrowCursor); -} - -void HelpDialog::on_helpButton_clicked() -{ - emit showLink(MainWindow::urlifyFileName( - Config::configuration()->assistantDocPath() + - QLatin1String("/assistant-manual.html#full-text-searching"))); -} - -void HelpDialog::on_resultBox_itemActivated(QListWidgetItem *item) -{ - showResultPage(item); -} - -void HelpDialog::showResultPage(QListWidgetItem *item) -{ - if (item) - emit showSearchLink(foundDocs[ui.resultBox->row(item)], terms); -} - -void HelpDialog::showIndexItemMenu(const QPoint &pos) -{ - QListView *listView = qobject_cast<QListView*>(sender()); - if (!listView) - return; - - QModelIndex idx = listView->indexAt(pos); - if (!idx.isValid()) - return; - - QAction *action = itemPopup->exec(listView->viewport()->mapToGlobal(pos)); - if (action == actionOpenCurrentTab) { - showTopic(); - } else if (action) { - HelpWindow *hw = help->browsers()->currentBrowser(); - QString itemName = idx.data().toString(); - ui.editIndex->setText(itemName); - QStringList links = indexModel->links(idx.row()); - if (links.count() == 1) { - if (action == actionOpenLinkInNewWindow) - hw->openLinkInNewWindow(links.first()); - else - hw->openLinkInNewPage(links.first()); - } else { - QStringList::Iterator it = links.begin(); - QStringList linkList; - QStringList linkNames; - for (; it != links.end(); ++it) { - linkList << *it; - linkNames << titleOfLink(*it); - } - QString link = TopicChooser::getLink(this, linkNames, linkList, itemName); - if (!link.isEmpty()) { - if (action == actionOpenLinkInNewWindow) - hw->openLinkInNewWindow(link); - else - hw->openLinkInNewPage(link); - } - } - } -} - -void HelpDialog::showListItemMenu(const QPoint &pos) -{ - QListWidget *listWidget = qobject_cast<QListWidget*>(sender()); - if (!listWidget) - return; - QListWidgetItem *item = listWidget->itemAt(pos); - if (!item) - return; - - QAction *action = itemPopup->exec(listWidget->viewport()->mapToGlobal(pos)); - if (action == actionOpenCurrentTab) { - showResultPage(item); - } else if (action) { - HelpWindow *hw = help->browsers()->currentBrowser(); - QString link = foundDocs[ui.resultBox->row(item)]; - if (action == actionOpenLinkInNewWindow) - hw->openLinkInNewWindow(link); - else - hw->openLinkInNewPage(link); - } -} - -void HelpDialog::showTreeItemMenu(const QPoint &pos) -{ - QTreeWidget *treeWidget = qobject_cast<QTreeWidget*>(sender()); - - if (!treeWidget) - return; - - QTreeWidgetItem *item = treeWidget->itemAt(pos); - - if (!item) - return; - - QAction *action = itemPopup->exec(treeWidget->viewport()->mapToGlobal(pos)); - if (action == actionOpenCurrentTab) { - if (ui.tabWidget->currentWidget()->objectName() == QLatin1String("contentPage")) - showContentsTopic(); - else - showBookmarkTopic(); - } else if (action) { - QTreeWidgetItem *i = (QTreeWidgetItem*)item; - if (action == actionOpenLinkInNewWindow) - help->browsers()->currentBrowser()->openLinkInNewWindow(i->data(0, LinkRole).toString()); - else - help->browsers()->currentBrowser()->openLinkInNewPage(i->data(0, LinkRole).toString()); - } -} - -void HelpDialog::on_termsEdit_returnPressed() -{ - startSearch(); -} - -void HelpDialog::updateSearchButton(const QString &txt) -{ - ui.searchButton->setDisabled(txt.isEmpty()); -} - -void HelpDialog::on_searchButton_clicked() -{ - startSearch(); -} - -QString HelpDialog::removeAnchorFromLink(const QString &link) -{ - int i = link.length(); - int j = link.lastIndexOf(QLatin1Char('/')); - int l = link.lastIndexOf(QDir::separator()); - if (l > j) - j = l; - if (j > -1) { - QString fileName = link.mid(j+1); - int k = fileName.lastIndexOf(QLatin1Char('#')); - if (k > -1) - i = j + k + 1; - } - return link.left(i); -} - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/helpdialog.h b/tools/assistant/compat/helpdialog.h deleted file mode 100644 index 4e1bac2..0000000 --- a/tools/assistant/compat/helpdialog.h +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef HELPDIALOG_H -#define HELPDIALOG_H - -#include "ui_helpdialog.h" -#include "index.h" -#include "helpwindow.h" -#include "docuparser.h" - -#include <QList> -#include <QPair> -#include <QListWidget> -#include <QTreeWidget> -#include <QMap> -#include <QStringList> -#include <QValidator> -#include <qmenu.h> -#include <QHash> - -QT_BEGIN_NAMESPACE - -class QProgressBar; -class MainWindow; -class QTextBrowser; -class IndexListModel; - -class HelpNavigationListItem : public QListWidgetItem -{ -public: - HelpNavigationListItem(QListWidget *ls, const QString &txt); - - void addLink(const QString &link); - QStringList links() const { return linkList; } -private: - QStringList linkList; - -}; - -class SearchValidator : public QValidator -{ - Q_OBJECT -public: - SearchValidator(QObject *parent) - : QValidator(parent) {} - ~SearchValidator() {} - QValidator::State validate(QString &str, int &) const; -}; - -class HelpDialog : public QWidget -{ - Q_OBJECT -public: - HelpDialog(QWidget *parent, MainWindow *h); - - inline QTabWidget *tabWidget() const - { return ui.tabWidget; } - - QString titleOfLink(const QString &link); - bool eventFilter(QObject *, QEvent *); - bool lastWindowClosed() { return lwClosed; } - - void timerEvent(QTimerEvent *e); - static QString removeAnchorFromLink(const QString &link); - -signals: - void showLink(const QString &s); - void showSearchLink(const QString &s, const QStringList &terms); - -public slots: - void initialize(); - void startSearch(); - void addBookmark(); - void currentTabChanged(int index); - void locateContents(const QString &link); - -private slots: - void on_buttonAdd_clicked(); - void on_buttonRemove_clicked(); - void on_termsEdit_returnPressed(); - void on_helpButton_clicked(); - void on_searchButton_clicked(); - void on_resultBox_itemActivated(QListWidgetItem*); - void updateSearchButton(const QString &txt); - - void showResultPage(QListWidgetItem *); - - void showTopic(QTreeWidgetItem *); - void loadIndexFile(); - void insertContents(); - void setupFullTextIndex(); - void showTopic(); - void searchInIndex(const QString &s); - void toggleContents(); - void toggleIndex(); - void toggleBookmarks(); - void toggleSearch(); - void lastWinClosed(); - void setIndexingProgress(int prog); - void showListItemMenu(const QPoint &pos); - void showIndexItemMenu(const QPoint &pos); - void showTreeItemMenu(const QPoint &pos); - void insertBookmarks(); - void processEvents(); - -private: - typedef QList<ContentItem> ContentList; - void removeOldCacheFiles(bool onlyFulltextSearchIndex = false); - void buildKeywordDB(); - quint32 getFileAges(); - void showIndexTopic(); - void showBookmarkTopic(); - void setupTitleMap(); - void saveBookmarks(); - void showContentsTopic(); - void showInitDoneMessage(); - void buildContentDict(); - QTreeWidgetItem * locateLink(QTreeWidgetItem *item, const QString &link); - -private: - Ui::HelpDialog ui; - - IndexListModel *indexModel; - QMap<QString, QString> titleMap; - bool indexDone, bookmarksInserted, titleMapDone, contentsInserted; - bool lwClosed; - MainWindow *help; - QString documentationPath; - Index *fullTextIndex; - QStringList terms, foundDocs; - bool initDoneMsgShown; - void getAllContents(); - QList<QPair<QString, ContentList> > contentList; - QMenu *itemPopup; - QString cacheFilesPath; - QStringList keywordDocuments; - - QAction *actionOpenCurrentTab; - QAction *actionOpenLinkInNewWindow; - QAction *actionOpenLinkInNewTab; -}; - -QT_END_NAMESPACE - -#endif // HELPDIALOG_H diff --git a/tools/assistant/compat/helpdialog.ui b/tools/assistant/compat/helpdialog.ui deleted file mode 100644 index 0fc8817..0000000 --- a/tools/assistant/compat/helpdialog.ui +++ /dev/null @@ -1,404 +0,0 @@ -<ui version="4.0" > - <author></author> - <comment>********************************************************************* -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -*********************************************************************</comment> - <exportmacro></exportmacro> - <class>HelpDialog</class> - <widget class="QWidget" name="HelpDialog" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>274</width> - <height>417</height> - </rect> - </property> - <property name="windowTitle" > - <string>Help</string> - </property> - <property name="whatsThis" > - <string><b>Help</b><p>Choose the topic you want help on from the contents list, or search the index for keywords.</p></string> - </property> - <layout class="QVBoxLayout" > - <property name="margin" > - <number>0</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <widget class="QTabWidget" name="tabWidget" > - <property name="whatsThis" > - <string>Displays help topics organized by category, index or bookmarks. Another tab inherits the full text search.</string> - </property> - <widget class="QWidget" name="contentPage" > - <attribute name="title" > - <string>Con&tents</string> - </attribute> - <layout class="QVBoxLayout" > - <property name="margin" > - <number>5</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <widget class="QTreeWidget" name="listContents" > - <property name="contextMenuPolicy" > - <enum>Qt::CustomContextMenu</enum> - </property> - <property name="whatsThis" > - <string><b>Help topics organized by category.</b><p>Double-click an item to see the topics in that category. To view a topic, just double-click it.</p></string> - </property> - <property name="rootIsDecorated" > - <bool>true</bool> - </property> - <property name="uniformRowHeights" > - <bool>true</bool> - </property> - <column> - <property name="text" > - <string>column 1</string> - </property> - </column> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="indexPage" > - <attribute name="title" > - <string>&Index</string> - </attribute> - <layout class="QVBoxLayout" > - <property name="margin" > - <number>5</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <widget class="QLabel" name="TextLabel1" > - <property name="text" > - <string>&Look For:</string> - </property> - <property name="buddy" > - <cstring>editIndex</cstring> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="editIndex" > - <property name="toolTip" > - <string>Enter keyword</string> - </property> - <property name="whatsThis" > - <string><b>Enter a keyword.</b><p>The list will select an item that matches the entered string best.</p></string> - </property> - </widget> - </item> - <item> - <widget class="QListView" name="listIndex" > - <property name="contextMenuPolicy" > - <enum>Qt::CustomContextMenu</enum> - </property> - <property name="whatsThis" > - <string><b>List of available help topics.</b><p>Double-click on an item to open its help page. If more than one is found, you must specify which page you want.</p></string> - </property> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="bookmarkPage" > - <attribute name="title" > - <string>&Bookmarks</string> - </attribute> - <layout class="QVBoxLayout" > - <property name="margin" > - <number>5</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <widget class="QTreeWidget" name="listBookmarks" > - <property name="contextMenuPolicy" > - <enum>Qt::CustomContextMenu</enum> - </property> - <property name="whatsThis" > - <string>Displays the list of bookmarks.</string> - </property> - <property name="uniformRowHeights" > - <bool>true</bool> - </property> - <column> - <property name="text" > - <string>column 1</string> - </property> - </column> - </widget> - </item> - <item> - <layout class="QHBoxLayout" > - <property name="margin" > - <number>0</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <spacer> - <property name="orientation" > - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType" > - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" > - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="buttonAdd" > - <property name="toolTip" > - <string>Add new bookmark</string> - </property> - <property name="whatsThis" > - <string>Add the currently displayed page as a new bookmark.</string> - </property> - <property name="text" > - <string>&New</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="buttonRemove" > - <property name="toolTip" > - <string>Delete bookmark</string> - </property> - <property name="whatsThis" > - <string>Delete the selected bookmark.</string> - </property> - <property name="text" > - <string>&Delete</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <widget class="QWidget" name="searchPage" > - <attribute name="title" > - <string>&Search</string> - </attribute> - <layout class="QGridLayout" > - <property name="margin" > - <number>5</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item row="3" column="0" > - <spacer> - <property name="orientation" > - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType" > - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" > - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="0" > - <widget class="QLabel" name="TextLabel1_2" > - <property name="text" > - <string>Searching f&or:</string> - </property> - <property name="buddy" > - <cstring>termsEdit</cstring> - </property> - </widget> - </item> - <item row="1" column="0" > - <widget class="QLineEdit" name="termsEdit" > - <property name="toolTip" > - <string>Enter searchword(s)</string> - </property> - <property name="whatsThis" > - <string><b>Enter search word(s).</b><p>Enter here the word(s) you are looking for. The words may contain wildcards (*). For a sequence of words quote them.</p></string> - </property> - </widget> - </item> - <item row="5" column="0" > - <widget class="QListWidget" name="resultBox" > - <property name="contextMenuPolicy" > - <enum>Qt::CustomContextMenu</enum> - </property> - <property name="whatsThis" > - <string><b>Found documents</b><p>This list contains all found documents from the last search. The documents are ordered, i.e. the first document has the most matches.</p></string> - </property> - </widget> - </item> - <item row="4" column="0" > - <widget class="QLabel" name="TextLabel2" > - <property name="text" > - <string>Found &Documents:</string> - </property> - <property name="buddy" > - <cstring>resultBox</cstring> - </property> - </widget> - </item> - <item row="2" column="0" > - <layout class="QHBoxLayout" > - <property name="margin" > - <number>1</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <widget class="QPushButton" name="helpButton" > - <property name="toolTip" > - <string>Display the help page</string> - </property> - <property name="whatsThis" > - <string>Display the help page for the full text search.</string> - </property> - <property name="text" > - <string>He&lp</string> - </property> - </widget> - </item> - <item> - <spacer> - <property name="orientation" > - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType" > - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" > - <size> - <width>61</width> - <height>21</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="searchButton" > - <property name="toolTip" > - <string>Start searching</string> - </property> - <property name="whatsThis" > - <string>Pressing this button starts the search.</string> - </property> - <property name="text" > - <string>&Search</string> - </property> - <property name="enabled" > - <bool>false</bool> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </widget> - </item> - <item> - <widget class="QFrame" name="framePrepare" > - <property name="frameShape" > - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow" > - <enum>QFrame::Raised</enum> - </property> - <layout class="QHBoxLayout" > - <property name="margin" > - <number>3</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <widget class="QLabel" name="labelPrepare" > - <property name="text" > - <string>Preparing...</string> - </property> - </widget> - </item> - <item> - <widget class="QProgressBar" name="progressPrepare" /> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <pixmapfunction></pixmapfunction> - <tabstops> - <tabstop>tabWidget</tabstop> - <tabstop>listContents</tabstop> - <tabstop>editIndex</tabstop> - <tabstop>listIndex</tabstop> - <tabstop>listBookmarks</tabstop> - <tabstop>buttonAdd</tabstop> - <tabstop>buttonRemove</tabstop> - <tabstop>termsEdit</tabstop> - <tabstop>searchButton</tabstop> - <tabstop>helpButton</tabstop> - <tabstop>resultBox</tabstop> - </tabstops> - <resources/> - <connections/> -</ui> diff --git a/tools/assistant/compat/helpwindow.cpp b/tools/assistant/compat/helpwindow.cpp deleted file mode 100644 index 6674342..0000000 --- a/tools/assistant/compat/helpwindow.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "helpwindow.h" -#include "mainwindow.h" -#include "tabbedbrowser.h" -#include "helpdialog.h" -#include "config.h" - -#include <QApplication> -#include <QClipboard> -#include <QUrl> -#include <QMessageBox> -#include <QDir> -#include <QFile> -#include <QProcess> -#include <QAction> -#include <QFileInfo> -#include <QFont> -#include <QtEvents> -#include <QTextStream> -#include <QTextCodec> -#include <QStatusBar> -#include <QTextCursor> -#include <QTextObject> -#include <QTextLayout> -#include <QtDebug> -#include <qdesktopservices.h> - -#include <QtGui/QClipboard> -#include <QtGui/QApplication> - -#if defined(Q_OS_WIN32) -# include <windows.h> -#endif - -QT_BEGIN_NAMESPACE - -HelpWindow::HelpWindow(MainWindow *w, QWidget *parent) - : QTextBrowser(parent) - , mw(w) - , blockScroll(false) - , shiftPressed(false) - , newWindow(false) -{ - FontSettings settings = Config::configuration()->fontSettings(); - setFont(settings.browserFont); - - connect(this, SIGNAL(copyAvailable(bool)), w, SLOT(copyAvailable(bool))); -} - -void HelpWindow::setSource(const QUrl &name) -{ - if (name.isValid()) { - if (name.scheme() == QLatin1String("http") || name.scheme() == QLatin1String("ftp") - || name.scheme() == QLatin1String("mailto") || name.path().endsWith(QLatin1String("pdf"))) { - bool launched = QDesktopServices::openUrl(name); - if (!launched) { - QMessageBox::information(mw, tr("Help"), - tr("Unable to launch web browser.\n"), - tr("OK")); - } - return; - } - - QFileInfo fi(name.toLocalFile()); - if (name.scheme() == QLatin1String("file") && fi.exists()) { - if (newWindow || (shiftPressed && hasFocus())) { - shiftPressed = false; - mw->saveSettings(); - MainWindow *nmw = new MainWindow; - nmw->move(mw->geometry().topLeft()); - nmw->show(); - - if (mw->isMaximized()) - nmw->showMaximized(); - - nmw->setup(); - nmw->showLink(name.toString()); - } else { - QTextBrowser::setSource(name); - QTextBrowser::scrollToAnchor(name.fragment()); - } - return; - } - } - - mw->statusBar()->showMessage(tr("Failed to open link: '%1'").arg(name.toString()), 5000); - setHtml(tr("<div align=\"center\"><h1>The page could not be found</h1><br>" - "<h3>'%1'</h3></div>").arg(name.toString())); - mw->browsers()->updateTitle(tr("Error...")); -} - -void HelpWindow::openLinkInNewWindow() -{ - if (lastAnchor.isEmpty()) - return; - newWindow = true; - setSource(lastAnchor); - newWindow = false; -} - -void HelpWindow::openLinkInNewWindow(const QString &link) -{ - lastAnchor = link; - openLinkInNewWindow(); -} - -void HelpWindow::openLinkInNewPage() -{ - if(lastAnchor.isEmpty()) - return; - mw->browsers()->newTab(lastAnchor); - lastAnchor.clear(); -} - -void HelpWindow::openLinkInNewPage(const QString &link) -{ - lastAnchor = link; - openLinkInNewPage(); -} - -bool HelpWindow::hasAnchorAt(const QPoint& pos) -{ - lastAnchor = anchorAt(pos); - if (lastAnchor.isEmpty()) - return false; - lastAnchor = source().resolved(lastAnchor).toString(); - if (lastAnchor.at(0) == QLatin1Char('#')) { - QString src = source().toString(); - int hsh = src.indexOf(QLatin1Char('#')); - lastAnchor = (hsh>=0 ? src.left(hsh) : src) + lastAnchor; - } - return true; -} - -void HelpWindow::contextMenuEvent(QContextMenuEvent *e) -{ - QMenu menu(QLatin1String(""), 0); - - QUrl link; - QAction *copyAnchorAction = 0; - if (hasAnchorAt(e->pos())) { - link = anchorAt(e->pos()); - if (link.isRelative()) - link = source().resolved(link); - copyAnchorAction = menu.addAction(tr("Copy &Link Location")); - copyAnchorAction->setEnabled(!link.isEmpty() && link.isValid()); - - menu.addAction(tr("Open Link in New Tab"), - this, SLOT(openLinkInNewPage())); - menu.addAction(tr("Open Link in New Window\tShift+LMB"), - this, SLOT(openLinkInNewWindow())); - } - mw->setupPopupMenu(&menu); - QAction *action = menu.exec(e->globalPos()); - if (action == copyAnchorAction) - QApplication::clipboard()->setText(link.toString()); -} - -void HelpWindow::mouseReleaseEvent(QMouseEvent *e) -{ - if (e->button() == Qt::XButton1) { - QTextBrowser::backward(); - return; - } - - if (e->button() == Qt::XButton2) { - QTextBrowser::forward(); - return; - } - - if (e->button() == Qt::MidButton && hasAnchorAt(e->pos())) { - openLinkInNewPage(); - return; - } - QTextBrowser::mouseReleaseEvent(e); -} - -void HelpWindow::blockScrolling(bool b) -{ - blockScroll = b; -} - -void HelpWindow::ensureCursorVisible() -{ - if (!blockScroll) - QTextBrowser::ensureCursorVisible(); -} - -void HelpWindow::mousePressEvent(QMouseEvent *e) -{ - shiftPressed = e->modifiers() & Qt::ShiftModifier; - if (!(shiftPressed && hasAnchorAt(e->pos()))) - QTextBrowser::mousePressEvent(e); -} - -void HelpWindow::keyPressEvent(QKeyEvent *e) -{ - shiftPressed = e->modifiers() & Qt::ShiftModifier; - QTextBrowser::keyPressEvent(e); -} - -bool HelpWindow::isKDERunning() const -{ - return !qgetenv("KDE_FULL_SESSION").isEmpty(); -} - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/images/assistant-128.png b/tools/assistant/compat/images/assistant-128.png Binary files differdeleted file mode 100644 index f05949f..0000000 --- a/tools/assistant/compat/images/assistant-128.png +++ /dev/null diff --git a/tools/assistant/compat/images/assistant.png b/tools/assistant/compat/images/assistant.png Binary files differdeleted file mode 100644 index ea4d1e7..0000000 --- a/tools/assistant/compat/images/assistant.png +++ /dev/null diff --git a/tools/assistant/compat/images/close.png b/tools/assistant/compat/images/close.png Binary files differdeleted file mode 100644 index 540694e..0000000 --- a/tools/assistant/compat/images/close.png +++ /dev/null diff --git a/tools/assistant/compat/images/designer.png b/tools/assistant/compat/images/designer.png Binary files differdeleted file mode 100644 index 72c42e7..0000000 --- a/tools/assistant/compat/images/designer.png +++ /dev/null diff --git a/tools/assistant/compat/images/linguist.png b/tools/assistant/compat/images/linguist.png Binary files differdeleted file mode 100644 index d388cbd..0000000 --- a/tools/assistant/compat/images/linguist.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/addtab.png b/tools/assistant/compat/images/mac/addtab.png Binary files differdeleted file mode 100644 index 20928fb..0000000 --- a/tools/assistant/compat/images/mac/addtab.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/book.png b/tools/assistant/compat/images/mac/book.png Binary files differdeleted file mode 100644 index 7a3204c..0000000 --- a/tools/assistant/compat/images/mac/book.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/closetab.png b/tools/assistant/compat/images/mac/closetab.png Binary files differdeleted file mode 100644 index ab9d669..0000000 --- a/tools/assistant/compat/images/mac/closetab.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/editcopy.png b/tools/assistant/compat/images/mac/editcopy.png Binary files differdeleted file mode 100644 index f551364..0000000 --- a/tools/assistant/compat/images/mac/editcopy.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/find.png b/tools/assistant/compat/images/mac/find.png Binary files differdeleted file mode 100644 index 3561745..0000000 --- a/tools/assistant/compat/images/mac/find.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/home.png b/tools/assistant/compat/images/mac/home.png Binary files differdeleted file mode 100644 index 78d94da..0000000 --- a/tools/assistant/compat/images/mac/home.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/next.png b/tools/assistant/compat/images/mac/next.png Binary files differdeleted file mode 100644 index a585cab..0000000 --- a/tools/assistant/compat/images/mac/next.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/prev.png b/tools/assistant/compat/images/mac/prev.png Binary files differdeleted file mode 100644 index 612fb34..0000000 --- a/tools/assistant/compat/images/mac/prev.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/print.png b/tools/assistant/compat/images/mac/print.png Binary files differdeleted file mode 100644 index 10ca56c..0000000 --- a/tools/assistant/compat/images/mac/print.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/synctoc.png b/tools/assistant/compat/images/mac/synctoc.png Binary files differdeleted file mode 100644 index 067fa94..0000000 --- a/tools/assistant/compat/images/mac/synctoc.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/whatsthis.png b/tools/assistant/compat/images/mac/whatsthis.png Binary files differdeleted file mode 100644 index 5b7078f..0000000 --- a/tools/assistant/compat/images/mac/whatsthis.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/zoomin.png b/tools/assistant/compat/images/mac/zoomin.png Binary files differdeleted file mode 100644 index d46f5af..0000000 --- a/tools/assistant/compat/images/mac/zoomin.png +++ /dev/null diff --git a/tools/assistant/compat/images/mac/zoomout.png b/tools/assistant/compat/images/mac/zoomout.png Binary files differdeleted file mode 100644 index 4632656..0000000 --- a/tools/assistant/compat/images/mac/zoomout.png +++ /dev/null diff --git a/tools/assistant/compat/images/qt.png b/tools/assistant/compat/images/qt.png Binary files differdeleted file mode 100644 index 2dc6716..0000000 --- a/tools/assistant/compat/images/qt.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/addtab.png b/tools/assistant/compat/images/win/addtab.png Binary files differdeleted file mode 100644 index 4bb0feb..0000000 --- a/tools/assistant/compat/images/win/addtab.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/book.png b/tools/assistant/compat/images/win/book.png Binary files differdeleted file mode 100644 index 09ec4d3..0000000 --- a/tools/assistant/compat/images/win/book.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/closetab.png b/tools/assistant/compat/images/win/closetab.png Binary files differdeleted file mode 100644 index ef9e020..0000000 --- a/tools/assistant/compat/images/win/closetab.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/editcopy.png b/tools/assistant/compat/images/win/editcopy.png Binary files differdeleted file mode 100644 index 1121b47..0000000 --- a/tools/assistant/compat/images/win/editcopy.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/find.png b/tools/assistant/compat/images/win/find.png Binary files differdeleted file mode 100644 index 6ea35e9..0000000 --- a/tools/assistant/compat/images/win/find.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/home.png b/tools/assistant/compat/images/win/home.png Binary files differdeleted file mode 100644 index b1c6ae1..0000000 --- a/tools/assistant/compat/images/win/home.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/next.png b/tools/assistant/compat/images/win/next.png Binary files differdeleted file mode 100644 index 8df4127..0000000 --- a/tools/assistant/compat/images/win/next.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/previous.png b/tools/assistant/compat/images/win/previous.png Binary files differdeleted file mode 100644 index 0780bc2..0000000 --- a/tools/assistant/compat/images/win/previous.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/print.png b/tools/assistant/compat/images/win/print.png Binary files differdeleted file mode 100644 index ba7c02d..0000000 --- a/tools/assistant/compat/images/win/print.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/synctoc.png b/tools/assistant/compat/images/win/synctoc.png Binary files differdeleted file mode 100644 index da301bc..0000000 --- a/tools/assistant/compat/images/win/synctoc.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/whatsthis.png b/tools/assistant/compat/images/win/whatsthis.png Binary files differdeleted file mode 100644 index 623cad6..0000000 --- a/tools/assistant/compat/images/win/whatsthis.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/zoomin.png b/tools/assistant/compat/images/win/zoomin.png Binary files differdeleted file mode 100644 index 2e586fc..0000000 --- a/tools/assistant/compat/images/win/zoomin.png +++ /dev/null diff --git a/tools/assistant/compat/images/win/zoomout.png b/tools/assistant/compat/images/win/zoomout.png Binary files differdeleted file mode 100644 index a736d39..0000000 --- a/tools/assistant/compat/images/win/zoomout.png +++ /dev/null diff --git a/tools/assistant/compat/images/wrap.png b/tools/assistant/compat/images/wrap.png Binary files differdeleted file mode 100644 index 90f18d9..0000000 --- a/tools/assistant/compat/images/wrap.png +++ /dev/null diff --git a/tools/assistant/compat/index.cpp b/tools/assistant/compat/index.cpp deleted file mode 100644 index ff54626..0000000 --- a/tools/assistant/compat/index.cpp +++ /dev/null @@ -1,581 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "index.h" - -#include <QFile> -#include <QDir> -#include <QStringList> -#include <QApplication> -#include <QByteArray> -#include <QTextStream> -#include <QtAlgorithms> -#include <QUrl> -#include <QTextCodec> -#include <ctype.h> -#include <QTextDocument> - -QT_BEGIN_NAMESPACE - -struct Term { - Term() : frequency(-1) {} - Term( const QString &t, int f, QVector<Document> l ) : term( t ), frequency( f ), documents( l ) {} - QString term; - int frequency; - QVector<Document>documents; - bool operator<( const Term &i2 ) const { return frequency < i2.frequency; } -}; - -QDataStream &operator>>( QDataStream &s, Document &l ) -{ - s >> l.docNumber; - s >> l.frequency; - return s; -} - -QDataStream &operator<<( QDataStream &s, const Document &l ) -{ - s << (qint16)l.docNumber; - s << (qint16)l.frequency; - return s; -} - -Index::Index( const QString &dp, const QString &hp ) - : QObject( 0 ), docPath( dp ) -{ - Q_UNUSED(hp); - - alreadyHaveDocList = false; - lastWindowClosed = false; - connect( qApp, SIGNAL(lastWindowClosed()), - this, SLOT(setLastWinClosed()) ); -} - -Index::Index( const QStringList &dl, const QString &hp ) - : QObject( 0 ) -{ - Q_UNUSED(hp); - docList = dl; - alreadyHaveDocList = true; - lastWindowClosed = false; - connect( qApp, SIGNAL(lastWindowClosed()), - this, SLOT(setLastWinClosed()) ); -} - -void Index::setLastWinClosed() -{ - lastWindowClosed = true; -} - -void Index::setDictionaryFile( const QString &f ) -{ - dictFile = f; -} - -void Index::setDocListFile( const QString &f ) -{ - docListFile = f; -} - -void Index::setDocList( const QStringList &lst ) -{ - docList = lst; -} - -int Index::makeIndex() -{ - if ( !alreadyHaveDocList ) - setupDocumentList(); - if ( docList.isEmpty() ) - return 1; - QStringList::Iterator it = docList.begin(); - int steps = docList.count() / 100; - if ( !steps ) - steps++; - int prog = 0; - for ( int i = 0; it != docList.end(); ++it, ++i ) { - if ( lastWindowClosed ) { - return -1; - } - QUrl url(*it); - parseDocument( url.toLocalFile(), i ); - if ( i%steps == 0 ) { - prog++; - emit indexingProgress( prog ); - } - } - return 0; -} - -void Index::setupDocumentList() -{ - QDir d( docPath ); - QStringList filters; - filters.append(QLatin1String("*.html")); - QStringList lst = d.entryList(filters); - QStringList::ConstIterator it = lst.constBegin(); - for ( ; it != lst.constEnd(); ++it ) - docList.append( QLatin1String("file:") + docPath + QLatin1String("/") + *it ); -} - -void Index::insertInDict( const QString &str, int docNum ) -{ - if ( str == QLatin1String("amp") || str == QLatin1String("nbsp")) - return; - Entry *e = 0; - if ( dict.count() ) - e = dict[ str ]; - - if ( e ) { - if ( e->documents.last().docNumber != docNum ) - e->documents.append( Document(docNum, 1 ) ); - else - e->documents.last().frequency++; - } else { - dict.insert( str, new Entry( docNum ) ); - } -} - -QString Index::getCharsetForDocument(QFile *file) -{ - QTextStream s(file); - QString contents = s.readAll(); - - QString encoding; - int start = contents.indexOf(QLatin1String("<meta"), 0, Qt::CaseInsensitive); - if (start > 0) { - int end = contents.indexOf(QLatin1String(">"), start); - QString meta = contents.mid(start+5, end-start); - meta = meta.toLower(); - QRegExp r(QLatin1String("charset=([^\"\\s]+)")); - if (r.indexIn(meta) != -1) { - encoding = r.cap(1); - } - } - - file->seek(0); - if (encoding.isEmpty()) - return QLatin1String("utf-8"); - return encoding; -} - -void Index::parseDocument( const QString &filename, int docNum ) -{ - QFile file( filename ); - if ( !file.open(QFile::ReadOnly) ) { - qWarning( "can not open file %s", qPrintable(filename) ); - return; - } - - QTextStream s(&file); - QString en = getCharsetForDocument(&file); - s.setCodec(QTextCodec::codecForName(en.toLatin1().constData())); - - QString text = s.readAll(); - if (text.isNull()) - return; - - bool valid = true; - const QChar *buf = text.unicode(); - QChar str[64]; - QChar c = buf[0]; - int j = 0; - int i = 0; - while ( j < text.length() ) { - if ( c == QLatin1Char('<') || c == QLatin1Char('&') ) { - valid = false; - if ( i > 1 ) - insertInDict( QString(str,i), docNum ); - i = 0; - c = buf[++j]; - continue; - } - if ( ( c == QLatin1Char('>') || c == QLatin1Char(';') ) && !valid ) { - valid = true; - c = buf[++j]; - continue; - } - if ( !valid ) { - c = buf[++j]; - continue; - } - if ( ( c.isLetterOrNumber() || c == QLatin1Char('_') ) && i < 63 ) { - str[i] = c.toLower(); - ++i; - } else { - if ( i > 1 ) - insertInDict( QString(str,i), docNum ); - i = 0; - } - c = buf[++j]; - } - if ( i > 1 ) - insertInDict( QString(str,i), docNum ); - file.close(); -} - -void Index::writeDict() -{ - QFile f( dictFile ); - if ( !f.open(QFile::WriteOnly ) ) - return; - QDataStream s( &f ); - for(QHash<QString, Entry *>::Iterator it = dict.begin(); it != dict.end(); ++it) { - s << it.key(); - s << it.value()->documents.count(); - s << it.value()->documents; - } - f.close(); - writeDocumentList(); -} - -void Index::writeDocumentList() -{ - QFile f( docListFile ); - if ( !f.open(QFile::WriteOnly ) ) - return; - QDataStream s( &f ); - s << docList; -} - -void Index::readDict() -{ - QFile f( dictFile ); - if ( !f.open(QFile::ReadOnly ) ) - return; - - dict.clear(); - QDataStream s( &f ); - QString key; - int numOfDocs; - QVector<Document> docs; - while ( !s.atEnd() ) { - s >> key; - s >> numOfDocs; - docs.resize(numOfDocs); - s >> docs; - dict.insert( key, new Entry( docs ) ); - } - f.close(); - readDocumentList(); -} - -void Index::readDocumentList() -{ - QFile f( docListFile ); - if ( !f.open(QFile::ReadOnly ) ) - return; - QDataStream s( &f ); - s >> docList; -} - -QStringList Index::query( const QStringList &terms, const QStringList &termSeq, const QStringList &seqWords ) -{ - QList<Term> termList; - for (QStringList::ConstIterator it = terms.begin(); it != terms.end(); ++it ) { - Entry *e = 0; - if ( (*it).contains(QLatin1Char('*')) ) { - QVector<Document> wcts = setupDummyTerm( getWildcardTerms( *it ) ); - termList.append( Term(QLatin1String("dummy"), wcts.count(), wcts ) ); - } else if ( dict[ *it ] ) { - e = dict[ *it ]; - termList.append( Term( *it, e->documents.count(), e->documents ) ); - } else { - return QStringList(); - } - } - if ( !termList.count() ) - return QStringList(); - qSort(termList); - - QVector<Document> minDocs = termList.takeFirst().documents; - for(QList<Term>::Iterator it = termList.begin(); it != termList.end(); ++it) { - Term *t = &(*it); - QVector<Document> docs = t->documents; - for(QVector<Document>::Iterator minDoc_it = minDocs.begin(); minDoc_it != minDocs.end(); ) { - bool found = false; - for (QVector<Document>::ConstIterator doc_it = docs.constBegin(); doc_it != docs.constEnd(); ++doc_it ) { - if ( (*minDoc_it).docNumber == (*doc_it).docNumber ) { - (*minDoc_it).frequency += (*doc_it).frequency; - found = true; - break; - } - } - if ( !found ) - minDoc_it = minDocs.erase( minDoc_it ); - else - ++minDoc_it; - } - } - - QStringList results; - qSort( minDocs ); - if ( termSeq.isEmpty() ) { - for(QVector<Document>::Iterator it = minDocs.begin(); it != minDocs.end(); ++it) - results << docList.at((int)(*it).docNumber); - return results; - } - - QString fileName; - for(QVector<Document>::Iterator it = minDocs.begin(); it != minDocs.end(); ++it) { - fileName = docList[ (int)(*it).docNumber ]; - if ( searchForPattern( termSeq, seqWords, fileName ) ) - results << fileName; - } - return results; -} - -QString Index::getDocumentTitle( const QString &fullFileName ) -{ - QUrl url(fullFileName); - QString fileName = url.toLocalFile(); - - if (documentTitleCache.contains(fileName)) - return documentTitleCache.value(fileName); - - QFile file( fileName ); - if ( !file.open( QFile::ReadOnly ) ) { - qWarning( "cannot open file %s", qPrintable(fileName) ); - return fileName; - } - QTextStream s( &file ); - QString text = s.readAll(); - - int start = text.indexOf(QLatin1String("<title>"), 0, Qt::CaseInsensitive) + 7; - int end = text.indexOf(QLatin1String("</title>"), 0, Qt::CaseInsensitive); - - QString title = tr("Untitled"); - if (end - start > 0) { - title = text.mid(start, end - start); - if (Qt::mightBeRichText(title)) { - QTextDocument doc; - doc.setHtml(title); - title = doc.toPlainText(); - } - } - documentTitleCache.insert(fileName, title); - return title; -} - -QStringList Index::getWildcardTerms( const QString &term ) -{ - QStringList lst; - QStringList terms = split( term ); - QStringList::Iterator iter; - - for(QHash<QString, Entry*>::Iterator it = dict.begin(); it != dict.end(); ++it) { - int index = 0; - bool found = false; - QString text( it.key() ); - for ( iter = terms.begin(); iter != terms.end(); ++iter ) { - if ( *iter == QLatin1String("*") ) { - found = true; - continue; - } - if ( iter == terms.begin() && (*iter)[0] != text[0] ) { - found = false; - break; - } - index = text.indexOf( *iter, index ); - if ( *iter == terms.last() && index != (int)text.length()-1 ) { - index = text.lastIndexOf( *iter ); - if ( index != (int)text.length() - (int)(*iter).length() ) { - found = false; - break; - } - } - if ( index != -1 ) { - found = true; - index += (*iter).length(); - continue; - } else { - found = false; - break; - } - } - if ( found ) - lst << text; - } - - return lst; -} - -QStringList Index::split( const QString &str ) -{ - QStringList lst; - int j = 0; - int i = str.indexOf(QLatin1Char('*'), j ); - - if (str.startsWith(QLatin1String("*"))) - lst << QLatin1String("*"); - - while ( i != -1 ) { - if ( i > j && i <= (int)str.length() ) { - lst << str.mid( j, i - j ); - lst << QLatin1String("*"); - } - j = i + 1; - i = str.indexOf(QLatin1Char('*'), j ); - } - - int l = str.length() - 1; - if ( str.mid( j, l - j + 1 ).length() > 0 ) - lst << str.mid( j, l - j + 1 ); - - return lst; -} - -QVector<Document> Index::setupDummyTerm( const QStringList &terms ) -{ - QList<Term> termList; - for (QStringList::ConstIterator it = terms.begin(); it != terms.end(); ++it) { - Entry *e = 0; - if ( dict[ *it ] ) { - e = dict[ *it ]; - termList.append( Term( *it, e->documents.count(), e->documents ) ); - } - } - QVector<Document> maxList(0); - if ( !termList.count() ) - return maxList; - qSort(termList); - - maxList = termList.takeLast().documents; - for(QList<Term>::Iterator it = termList.begin(); it != termList.end(); ++it) { - Term *t = &(*it); - QVector<Document> docs = t->documents; - for (QVector<Document>::iterator docIt = docs.begin(); docIt != docs.end(); ++docIt ) { - if ( maxList.indexOf( *docIt ) == -1 ) - maxList.append( *docIt ); - } - } - return maxList; -} - -void Index::buildMiniDict( const QString &str ) -{ - if ( miniDict[ str ] ) - miniDict[ str ]->positions.append( wordNum ); - ++wordNum; -} - -bool Index::searchForPattern( const QStringList &patterns, const QStringList &words, const QString &fileName ) -{ - QUrl url(fileName); - QString fName = url.toLocalFile(); - QFile file( fName ); - if ( !file.open( QFile::ReadOnly ) ) { - qWarning( "cannot open file %s", qPrintable(fName) ); - return false; - } - - wordNum = 3; - miniDict.clear(); - QStringList::ConstIterator cIt = words.begin(); - for ( ; cIt != words.end(); ++cIt ) - miniDict.insert( *cIt, new PosEntry( 0 ) ); - - QTextStream s( &file ); - QString text = s.readAll(); - bool valid = true; - const QChar *buf = text.unicode(); - QChar str[64]; - QChar c = buf[0]; - int j = 0; - int i = 0; - while ( j < text.length() ) { - if ( c == QLatin1Char('<') || c == QLatin1Char('&') ) { - valid = false; - if ( i > 1 ) - buildMiniDict( QString(str,i) ); - i = 0; - c = buf[++j]; - continue; - } - if ( ( c == QLatin1Char('>') || c == QLatin1Char(';') ) && !valid ) { - valid = true; - c = buf[++j]; - continue; - } - if ( !valid ) { - c = buf[++j]; - continue; - } - if ( ( c.isLetterOrNumber() || c == QLatin1Char('_') ) && i < 63 ) { - str[i] = c.toLower(); - ++i; - } else { - if ( i > 1 ) - buildMiniDict( QString(str,i) ); - i = 0; - } - c = buf[++j]; - } - if ( i > 1 ) - buildMiniDict( QString(str,i) ); - file.close(); - - QStringList::ConstIterator patIt = patterns.begin(); - QStringList wordLst; - QList<uint> a, b; - QList<uint>::iterator aIt; - for ( ; patIt != patterns.end(); ++patIt ) { - wordLst = (*patIt).split(QLatin1Char(' ')); - a = miniDict[ wordLst[0] ]->positions; - for ( int j = 1; j < (int)wordLst.count(); ++j ) { - b = miniDict[ wordLst[j] ]->positions; - aIt = a.begin(); - while ( aIt != a.end() ) { - if ( b.contains( *aIt + 1 )) { - (*aIt)++; - ++aIt; - } else { - aIt = a.erase( aIt ); - } - } - } - } - if ( a.count() ) - return true; - return false; -} - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/index.h b/tools/assistant/compat/index.h deleted file mode 100644 index 9dd6d54..0000000 --- a/tools/assistant/compat/index.h +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef INDEX_H -#define INDEX_H - -#include <QStringList> -#include <QHash> -#include <QDataStream> -#include <QObject> -#include <QList> -#include <QFile> -#include <QVector> - -QT_BEGIN_NAMESPACE - -struct Document { - Document( int d, int f ) : docNumber( d ), frequency( f ) {} - Document() : docNumber( -1 ), frequency( 0 ) {} - bool operator==( const Document &doc ) const { - return docNumber == doc.docNumber; - } - bool operator<( const Document &doc ) const { - return frequency > doc.frequency; - } - bool operator<=( const Document &doc ) const { - return frequency >= doc.frequency; - } - bool operator>( const Document &doc ) const { - return frequency < doc.frequency; - } - qint16 docNumber; - qint16 frequency; -}; - -QDataStream &operator>>( QDataStream &s, Document &l ); -QDataStream &operator<<( QDataStream &s, const Document &l ); - -class Index : public QObject -{ - Q_OBJECT -public: - struct Entry { - Entry( int d ) { documents.append( Document( d, 1 ) ); } - Entry( QVector<Document> l ) : documents( l ) {} - QVector<Document> documents; - }; - struct PosEntry { - PosEntry( int p ) { positions.append( p ); } - QList<uint> positions; - }; - - Index( const QString &dp, const QString &hp ); - Index( const QStringList &dl, const QString &hp ); - void writeDict(); - void readDict(); - int makeIndex(); - QStringList query( const QStringList&, const QStringList&, const QStringList& ); - QString getDocumentTitle( const QString& ); - void setDictionaryFile( const QString& ); - void setDocListFile( const QString& ); - void setDocList( const QStringList & ); - -signals: - void indexingProgress( int ); - -private slots: - void setLastWinClosed(); - -private: - void setupDocumentList(); - void parseDocument( const QString&, int ); - void insertInDict( const QString&, int ); - void writeDocumentList(); - void readDocumentList(); - QStringList getWildcardTerms( const QString& ); - QStringList split( const QString& ); - QVector<Document> setupDummyTerm( const QStringList& ); - bool searchForPattern( const QStringList&, const QStringList&, const QString& ); - void buildMiniDict( const QString& ); - QString getCharsetForDocument(QFile *); - QStringList docList; - QHash<QString, Entry*> dict; - QHash<QString, PosEntry*> miniDict; - uint wordNum; - QString docPath; - QString dictFile, docListFile; - bool alreadyHaveDocList; - bool lastWindowClosed; - QHash<QString, QString> documentTitleCache; -}; - -#endif - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/lib/lib.pro b/tools/assistant/compat/lib/lib.pro deleted file mode 100644 index e50d470..0000000 --- a/tools/assistant/compat/lib/lib.pro +++ /dev/null @@ -1,78 +0,0 @@ -TEMPLATE = lib -QT += network -TARGET = QtAssistantClient -isEmpty(QT_MAJOR_VERSION) { - VERSION=4.3.0 -} else { - VERSION=$${QT_MAJOR_VERSION}.$${QT_MINOR_VERSION}.$${QT_PATCH_VERSION} -} - -CONFIG += qt warn_on -mac|win32:CONFIG += debug_and_release -mac:unix:CONFIG += explicitlib -CONFIG -= dll - -HEADERS = qassistantclient.h \ - qassistantclient_global.h -SOURCES = qassistantclient.cpp - -DESTDIR = ../../../../lib -DLLDESTDIR = ../../../../bin - -unix { - QMAKE_CFLAGS += $$QMAKE_CFLAGS_SHLIB - QMAKE_CXXFLAGS += $$QMAKE_CXXFLAGS_SHLIB -} - -DEFINES += QT_ASSISTANT_CLIENT_LIBRARY -contains(CONFIG, static) { - DEFINES += QT_ASSISTANT_CLIENT_STATIC -} - -#load up the headers info -CONFIG += qt_install_headers -HEADERS_PRI = $$QT_BUILD_TREE/include/QtAssistant/headers.pri -include($$HEADERS_PRI, "", true)|clear(HEADERS_PRI) - -#mac frameworks -mac:!static:contains(QT_CONFIG, qt_framework) { - TARGET = QtAssistant # Change the name to match the headers - QMAKE_FRAMEWORK_BUNDLE_NAME = $$TARGET - CONFIG += lib_bundle qt_no_framework_direct_includes qt_framework - CONFIG(debug, debug|release) { - !build_pass:CONFIG += build_all - } else { #release - !debug_and_release|build_pass { - CONFIG -= qt_install_headers #no need to install these as well - FRAMEWORK_HEADERS.version = Versions - FRAMEWORK_HEADERS.files = $$SYNCQT.HEADER_FILES $$SYNCQT.HEADER_CLASSES - FRAMEWORK_HEADERS.path = Headers - } - QMAKE_BUNDLE_DATA += FRAMEWORK_HEADERS - } -} - -TARGET = $$qtLibraryTarget($$TARGET$$QT_LIBINFIX) #done towards the end - -target.path=$$[QT_INSTALL_LIBS] -INSTALLS += target -win32 { - dlltarget.path=$$[QT_INSTALL_BINS] - INSTALLS += dlltarget -} - -qt_install_headers { - assistant_headers.files = $$SYNCQT.HEADER_FILES $$SYNCQT.HEADER_CLASSES - assistant_headers.path = $$[QT_INSTALL_HEADERS]/QtAssistant - INSTALLS += assistant_headers -} - -unix { - CONFIG += create_pc - QMAKE_PKGCONFIG_LIBDIR = $$[QT_INSTALL_LIBS] - QMAKE_PKGCONFIG_INCDIR = $$[QT_INSTALL_HEADERS]/QtAssistant - QMAKE_PKGCONFIG_CFLAGS = -I$$[QT_INSTALL_HEADERS] - QMAKE_PKGCONFIG_DESTDIR = pkgconfig - QMAKE_PKGCONFIG_REQUIRES += QtNetwork -} - diff --git a/tools/assistant/compat/lib/qassistantclient.cpp b/tools/assistant/compat/lib/qassistantclient.cpp deleted file mode 100644 index 72d0a92..0000000 --- a/tools/assistant/compat/lib/qassistantclient.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qassistantclient.h" - -#include <qtcpsocket.h> -#include <qtextstream.h> -#include <qtimer.h> -#include <qfileinfo.h> -#include <qmap.h> - -QT_BEGIN_NAMESPACE - -class QAssistantClientPrivate -{ - friend class QAssistantClient; - QStringList arguments; -}; - -static QMap<const QAssistantClient*,QAssistantClientPrivate*> *dpointers = 0; - -static QAssistantClientPrivate *data( const QAssistantClient *client, bool create=false ) -{ - if( !dpointers ) - dpointers = new QMap<const QAssistantClient*,QAssistantClientPrivate*>; - QAssistantClientPrivate *d = (*dpointers)[client]; - if( !d && create ) { - d = new QAssistantClientPrivate; - dpointers->insert( client, d ); - } - return d; -} - -/*! - \class QAssistantClient - \obsolete - \brief The QAssistantClient class provides a means of using Qt - Assistant as an application's help tool. - - \ingroup helpsystem - - \bold{Note:} \e{This class is obsolete and only required when using - the old Qt Assistant, now called assistant_adp. If you want to use - the new Qt Assistant as a remote help viewer, simple create a - QProcess instance and specify \tt{assistant} as its executable. - The following code shows how to start Qt Assistant and request a - certain page to be shown:} - - \snippet doc/src/snippets/code/tools_assistant_compat_lib_qassistantclient.cpp 0 - - \e{For a complete example using the Qt Assistant remotely, see the \l - {help/remotecontrol}{Remote Control} example.} - - In order to make Qt Assistant act as a customized help tool for - your application, you must provide your application with a - QAssistantClient object in addition to a \l - {assistant-manual.html} {Qt Assistant Document Profile} (\c .adp - file) and the associated documentation. - - Note that the QAssistantClient class is not included in the Qt - library. To use it you must add the following line to your pro - file: - - \snippet doc/src/snippets/code/tools_assistant_compat_lib_qassistantclient.cpp 1 - - A QAssistantClient instance can open or close Qt Assistant - whenever it is required. - - Once you have created a QAssistantClient instance, specifying the - path to the Qt Assistant executable, using Qt Assistant is - simple: You can either call the openAssistant() slot to show the - defined start page of the documentation, or you can call the - showPage() slot to show a particular help page. When you call - openAssistant() and showPage(), Qt Assistant will be launched if - it isn't already running. When Qt Assistant is running, the - isOpen() function returns true. - - When calling showPage() the Qt Assistant instance will also be - brought to the foreground if its hidden. The showPage() slot can - be called multiple times, while calling openAssistant() several - times without closing the application in between, will have no - effect. - - You can close Qt Assistant at any time using the closeAssistant() - slot. When you call openAssistant(), or you call showPage() - without a previous call to openAssistant(), the assistantOpened() - signal is emitted. Similarly when closeAssistant() is called, - assistantClosed() is emitted. In either case, if an error occurs, - error() is emitted. - - One QAssistantClient instance interacts with one Qt Assistant - instance, so every time you call openAssistant(), showPage() or - closeAssistant() they are applied to the particular Qt Assistant - instance associated with the QAssistantClient. - - Qt Assistant's documentation set can be altered using the command - line arguments that are passed to the application when it is - launched. When started without any options, Qt Assistant displays - a default set of documentation. When Qt is installed, the default - documentation set in Qt Assistant contains the Qt reference - documentation as well as the tools that come with Qt, such as \QD - and \c qmake. - - Use the setArguments() function to specify the command line - arguments. You can add or remove documentation from Qt Assistant - by adding and removing the relevant content files: The command - line arguments are \c {-addContentFile file.dcf} and \c - {-removeContentFile file.dcf} respectively. You can make Qt - Assistant run customized documentation sets that are separate from - the Qt documentation, by specifying a profile: \c {-profile - myapplication.adp}. The profile format can also be used to alter - several of Qt Assistant's properties such as its title and - startpage. - - The Documentation Content File (\c .dcf) and Qt Assistant - Documentation Profile (\c .adp) formats are documented in the \l - {assistant-manual.html}{Qt Assistant Manual}. - - For a complete example using the QAssistantClient class, see the - \e{Simple Text Viewer} example. The example shows how you can make - Qt Assistant act as a customized help tool for your application - using the QAssistantClient class combined with a Qt Assistant - Document Profile. - - \sa {Qt Assistant Manual}, {Simple Text Viewer Example} -*/ - -/*! - \fn void QAssistantClient::assistantOpened() - - This signal is emitted when Qt Assistant is opened and the - client-server communication is set up. - - \sa openAssistant(), showPage() -*/ - -/*! - \fn void QAssistantClient::assistantClosed() - - This signal is emitted when the connection to Qt Assistant is - closed. This happens when the user exits Qt Assistant, if an - error in the server or client occurs, or if closeAssistant() is - called. - - \sa closeAssistant() -*/ - -/*! - \fn void QAssistantClient::error( const QString &message ) - - This signal is emitted if Qt Assistant cannot be started, or if an - error occurs during the initialization of the connection between - Qt Assistant and the calling application. The \a message provides an - explanation of the error. -*/ - -/*! - Constructs an assistant client with the specified \a parent. For - systems other than Mac OS, \a path specifies the path to the Qt - Assistant executable. For Mac OS, \a path specifies a directory - containing a valid assistant.app bundle. If \a path is the empty - string, the system path (\c{%PATH%} or \c $PATH) is used. -*/ -QAssistantClient::QAssistantClient( const QString &path, QObject *parent ) - : QObject( parent ), host ( QLatin1String("localhost") ) -{ -#if defined(Q_OS_MAC) - const QString assistant = QLatin1String("Assistant_adp"); -#else - const QString assistant = QLatin1String("assistant_adp"); -#endif - - if ( path.isEmpty() ) - assistantCommand = assistant; - else { - QFileInfo fi( path ); - if ( fi.isDir() ) - assistantCommand = path + QLatin1String("/") + assistant; - else - assistantCommand = path; - } - -#if defined(Q_OS_MAC) - assistantCommand += QLatin1String(".app/Contents/MacOS/Assistant_adp"); -#endif - - socket = new QTcpSocket( this ); - connect( socket, SIGNAL(connected()), - SLOT(socketConnected()) ); - connect( socket, SIGNAL(disconnected()), - SLOT(socketConnectionClosed()) ); - connect( socket, SIGNAL(error(QAbstractSocket::SocketError)), - SLOT(socketError()) ); - opened = false; - proc = new QProcess( this ); - port = 0; - pageBuffer = QLatin1String(""); - connect( proc, SIGNAL(readyReadStandardError()), - this, SLOT(readStdError()) ); - connect( proc, SIGNAL(error(QProcess::ProcessError)), - this, SLOT(procError(QProcess::ProcessError)) ); -} - -/*! - Destroys the assistant client object. -*/ -QAssistantClient::~QAssistantClient() -{ - if ( proc->state() == QProcess::Running ) - proc->terminate(); - - if( dpointers ) { - QAssistantClientPrivate *d = (*dpointers)[ this ]; - if ( d ) { - dpointers->remove(this); - delete d; - if( dpointers->isEmpty() ) { - delete dpointers; - dpointers = 0; - } - } - } -} - -/*! - Opens Qt Assistant, i.e. sets up the client-server communication - between the application and Qt Assistant, and shows the start page - specified by the current \l {assistant-manual.html} - {Qt Assistant Document Profile}. If there is no specfied profile, - and Qt is installed, the default start page is the Qt Reference - Documentation's index page. - - If the connection is already established, this function does - nothing. Use the showPage() function to show another page. If an - error occurs, the error() signal is emitted. - - \sa showPage(), assistantOpened() -*/ -void QAssistantClient::openAssistant() -{ - if ( proc->state() == QProcess::Running ) - return; - - QStringList args; - args.append(QLatin1String("-server")); - if( !pageBuffer.isEmpty() ) { - args.append( QLatin1String("-file") ); - args.append( pageBuffer ); - } - - QAssistantClientPrivate *d = data( this ); - if( d ) { - QStringList::ConstIterator it = d->arguments.constBegin(); - while( it!=d->arguments.constEnd() ) { - args.append( *it ); - ++it; - } - } - - connect( proc, SIGNAL(readyReadStandardOutput()), - this, SLOT(readPort()) ); - - proc->start(assistantCommand, args); -} - -void QAssistantClient::procError(QProcess::ProcessError err) -{ - switch (err) - { - case QProcess::FailedToStart: - emit error( tr( "Failed to start Qt Assistant." ) ); - break; - case QProcess::Crashed: - emit error( tr( "Qt Assistant crashed." ) ); - break; - default: - emit error( tr( "Error while running Qt Assistant." ) ); - } -} - -void QAssistantClient::readPort() -{ - QString p(QString::fromLatin1(proc->readAllStandardOutput())); - quint16 port = p.toUShort(); - if ( port == 0 ) { - emit error( tr( "Cannot connect to Qt Assistant." ) ); - return; - } - socket->connectToHost( host, port ); - disconnect( proc, SIGNAL(readyReadStandardOutput()), - this, SLOT(readPort()) ); -} - -/*! - Closes the Qt Assistant instance. - - \sa openAssistant(), assistantClosed() -*/ -void QAssistantClient::closeAssistant() -{ - if ( !opened ) - return; - - bool blocked = proc->blockSignals(true); - proc->terminate(); - if (!proc->waitForFinished(2000)) { - // If the process hasn't died after 2 seconds, - // we kill it, causing it to exit immediately. - proc->kill(); - } - proc->blockSignals(blocked); -} - -/*! - Brings Qt Assistant to the foreground showing the given \a page. - The \a page parameter is a path to an HTML file - (e.g., QLatin1String("/home/pasquale/superproduct/docs/html/intro.html")). - - If Qt Assistant hasn't been opened yet, this function will call - the openAssistant() slot with the specified page as the start - page. - - \note The first time Qt Assistant is started, its window will open - in front of the application's windows. Subsequent calls to this function - will only load the specified pages in Qt Assistant and will not display - its window in front of the application's windows. - - \sa openAssistant() -*/ -void QAssistantClient::showPage( const QString &page ) -{ - if (opened) { - QTextStream os( socket ); - os << page << QLatin1String("\n"); - } else { - pageBuffer = page; - - if (proc->state() == QProcess::NotRunning) { - openAssistant(); - pageBuffer.clear(); - return; - } - } -} - -/*! - \property QAssistantClient::open - \brief whether Qt Assistant is open - -*/ -bool QAssistantClient::isOpen() const -{ - return opened; -} - -void QAssistantClient::socketConnected() -{ - opened = true; - if ( !pageBuffer.isEmpty() ) - showPage( pageBuffer ); - emit assistantOpened(); -} - -void QAssistantClient::socketConnectionClosed() -{ - opened = false; - emit assistantClosed(); -} - -void QAssistantClient::socketError() -{ - QAbstractSocket::SocketError err = socket->error(); - if (err == QTcpSocket::ConnectionRefusedError) - emit error( tr( "Could not connect to Assistant: Connection refused" ) ); - else if (err == QTcpSocket::HostNotFoundError) - emit error( tr( "Could not connect to Assistant: Host not found" ) ); - else if (err != QTcpSocket::RemoteHostClosedError) - emit error( tr( "Communication error" ) ); -} - -void QAssistantClient::readStdError() -{ - QString errmsg = QString::fromLatin1(proc->readAllStandardError()); - - if (!errmsg.isEmpty()) - emit error( errmsg.simplified() ); -} - -/*! - \fn void QAssistantClient::setArguments(const QStringList &arguments) - - Sets the command line \a arguments that are passed to Qt Assistant - when it is launched. - - The command line arguments can be used to alter Qt Assistant's - documentation set. When started without any options, Qt Assistant - displays a default set of documentation. When Qt is installed, the - default documentation set in Qt Assistant contains the Qt - reference documentation as well as the tools that come with Qt, - such as Qt Designer and qmake. -*/ -void QAssistantClient::setArguments( const QStringList &args ) -{ - QAssistantClientPrivate *d = data( this, true ); - d->arguments = args; -} - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/main.cpp b/tools/assistant/compat/main.cpp deleted file mode 100644 index c16c52e..0000000 --- a/tools/assistant/compat/main.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "mainwindow.h" -#include "helpdialog.h" -#include "config.h" - -#include <QTcpServer> -#include <QTcpSocket> -#include <QApplication> -#include <QPixmap> -#include <QStringList> -#include <QDir> -#include <QMessageBox> -#include <QPointer> -#include <QTranslator> -#include <QLibraryInfo> -#include <QLocale> -#include <stdlib.h> -#include <stdio.h> - -#if defined(USE_STATIC_JPEG_PLUGIN) - #include <QtPlugin> - Q_IMPORT_PLUGIN(qjpeg) -#endif - -#define INDEX_CHECK( text ) if( i+1 >= argc ) { fprintf(stderr, "%s\n", text); return 1; } - -QT_BEGIN_NAMESPACE - -#if !defined(QT_NO_DBUS) && defined(Q_OS_UNIX) -QT_BEGIN_INCLUDE_NAMESPACE -#include <QtDBus/QDBusConnection> -#include <QtDBus/QDBusAbstractAdaptor> -#include <QtDBus/QDBusObjectPath> -#include "tabbedbrowser.h" -QT_END_INCLUDE_NAMESPACE - -class HelpWindowAdaptor : public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "com.trolltech.Assistant.HelpWindow") - - Q_PROPERTY(QString source READ source WRITE setSource) - -public: - HelpWindowAdaptor(HelpWindow *w) : QDBusAbstractAdaptor(w), helpWindow(w) - { - setAutoRelaySignals(true); - } - -public Q_SLOTS: - inline QString source() const { return helpWindow->source().toString(); } - inline void setSource(const QString &src) { helpWindow->setSource(src); } - - inline void clearHistory() { helpWindow->clearHistory(); } - inline void backward() { helpWindow->backward(); } - inline void forward() { helpWindow->forward(); } - inline void reload() { helpWindow->reload(); } - inline void home() { helpWindow->home(); } - -private: - HelpWindow *helpWindow; -}; - -class AssistantAdaptor : public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "com.trolltech.Assistant.HelpViewer") - -public: - AssistantAdaptor(MainWindow *mw) : QDBusAbstractAdaptor(mw), mw(mw) - { - QDBusConnection connection = QDBusConnection::sessionBus(); - connection.registerService(QLatin1String("com.trolltech.Assistant")); - connection.registerObject(QLatin1String("/Assistant"), mw); - } - -public slots: - void showLink(const QString &link) { mw->showLink(link); } - QDBusObjectPath createNewTab(); - QDBusObjectPath currentTab(); - -private: - QDBusObjectPath pathForBrowser(HelpWindow *window); - MainWindow *mw; -}; - -QDBusObjectPath AssistantAdaptor::createNewTab() -{ - HelpWindow *window = mw->browsers()->newBackgroundTab(); - return pathForBrowser(window); -} - -QDBusObjectPath AssistantAdaptor::currentTab() -{ - HelpWindow *window = mw->browsers()->currentBrowser(); - return pathForBrowser(window); -} - -QDBusObjectPath AssistantAdaptor::pathForBrowser(HelpWindow *window) -{ - int index = mw->browsers()->browsers().indexOf(window); - if (index == -1) - return QDBusObjectPath(); - - QString name(QLatin1String("/Assistant/Tabs/")); - name += QString::number(index); - QDBusObjectPath path(name); - - if (!window->findChild<HelpWindowAdaptor *>()) { - (void)new HelpWindowAdaptor(window); - QDBusConnection::sessionBus().registerObject(name, window); - } - - return path; -} - -#endif // QT_NO_DBUS - -class AssistantSocket : public QTcpSocket -{ - Q_OBJECT -public: - AssistantSocket( int sock, QObject *parent = 0 ); - ~AssistantSocket() {} - -signals: - void showLinkRequest( const QString& ); - -private slots: - void readClient(); - void connectionClosed(); -}; - - -class AssistantServer : public QTcpServer -{ - Q_OBJECT -public: - AssistantServer( QObject* parent = 0 ); - quint16 getPort() const; - -signals: - void showLinkRequest( const QString& ); - void newConnect(); - -public slots: - virtual void incomingConnection( int socket ); - -private: - quint16 p; -}; - -AssistantSocket::AssistantSocket( int sock, QObject *parent ) - : QTcpSocket( parent ) -{ - connect( this, SIGNAL(readyRead()), SLOT(readClient()) ); - connect( this, SIGNAL(disconnected()), SLOT(connectionClosed()) ); - setSocketDescriptor( sock ); -} - -void AssistantSocket::readClient() -{ - QString link = QString(); - while ( canReadLine() ) - link = QLatin1String(readLine()); - if ( !link.isNull() ) { - link = link.replace(QLatin1String("\n"), QLatin1String("")); - link = link.replace(QLatin1String("\r"), QLatin1String("")); - QFileInfo fi(link); - link = fi.absoluteFilePath(); - emit showLinkRequest( link ); - } -} - -void AssistantSocket::connectionClosed() -{ - deleteLater(); -} - -AssistantServer::AssistantServer( QObject *parent ) - : QTcpServer( parent ) -{ - listen(QHostAddress::LocalHost, 0); - if ( !isListening() ) { - QMessageBox::critical( 0, tr( "Qt Assistant" ), - tr( "Failed to bind to port %1" ).arg( serverPort() ) ); - exit( 1 ); - } - p = serverPort(); -} - -quint16 AssistantServer::getPort() const -{ - return p; -} - -void AssistantServer::incomingConnection( int socket ) -{ - AssistantSocket *as = new AssistantSocket( socket, this ); - connect( as, SIGNAL(showLinkRequest(QString)), - this, SIGNAL(showLinkRequest(QString)) ); - emit newConnect(); -} - -int runAssistant( int argc, char ** argv ) -{ - bool withGUI = true; -#ifndef Q_WS_WIN - if ( argc > 1 ) { - QString arg = QString::fromLocal8Bit(argv[1]); - arg = arg.toLower(); - if ( arg == QLatin1String("-addcontentfile") - || arg == QLatin1String("-removecontentfile") - || arg == QLatin1String("-help") - || arg == QLatin1String("/?") - ) - withGUI = false; - } -#endif - QApplication a(argc, argv, withGUI); - a.setOrganizationName(QLatin1String("Trolltech")); - a.setApplicationName(QLatin1String("Assistant")); - - QString resourceDir; - AssistantServer *as = 0; - QStringList catlist; - QString file, profileName, aDocPath; - bool server = false; - bool hideSidebar = false; - bool configLoaded = false; - if ( argc == 2 ) { - file = QString::fromLocal8Bit(argv[1]); - if (file.startsWith(QLatin1String("-")) || file == QLatin1String("/?")) { - file.clear(); - } else { - QFileInfo fi(file); - file = fi.absoluteFilePath(); - file = MainWindow::urlifyFileName(file); - } - } - if ( file.isEmpty() ) { - for ( int i = 1; i < argc; i++ ) { - QString opt = QString::fromLocal8Bit(argv[i]).toLower(); - if ( opt == QLatin1String("-file") ) { - INDEX_CHECK( "Missing file argument!" ); - i++; - file = QFile::decodeName(argv[i]); - } else if ( opt == QLatin1String("-server") ) { - server = true; - } else if ( opt == QLatin1String("-profile") ) { - INDEX_CHECK( "Missing profile argument!" ); - profileName = QFile::decodeName(argv[++i]); - } else if ( opt == QLatin1String("-addcontentfile") ) { - INDEX_CHECK( "Missing content file!" ); - Config *c = Config::loadConfig(QString()); - QFileInfo file( QFile::decodeName(argv[i+1]) ); - if( !file.exists() ) { - fprintf(stderr, "Could not locate content file: %s\n", qPrintable(file.absoluteFilePath())); - return 1; - } - DocuParser *parser = DocuParser::createParser( file.absoluteFilePath() ); - if( parser ) { - QFile f( QFile::decodeName(argv[i+1]) ); - if( !parser->parse( &f ) ) { - fprintf(stderr, "Failed to parse file: %s\n", qPrintable(file.absoluteFilePath())); - return 1; - } - parser->addTo( c->profile() ); - c->setDocRebuild( true ); - c->save(); - } - return 0; - } else if ( opt == QLatin1String("-removecontentfile") ) { - INDEX_CHECK("Missing content file!"); - Config *c = Config::loadConfig(QString()); - Profile *profile = c->profile(); - QString contentFile = QString::fromLocal8Bit(argv[i+i]); - QStringList entries; -#ifdef Q_WS_WIN - contentFile.replace(QLatin1Char('\\'), QLatin1Char('/')); - entries = profile->docs.filter(contentFile, Qt::CaseInsensitive); -#else - entries = profile->docs.filter(contentFile); -#endif - if (entries.count() == 0) { - fprintf(stderr, "Could not locate content file: %s\n", qPrintable(contentFile)); - return 1; - } else if (entries.count() > 1) { - fprintf(stderr, "More than one entry matching file name found, " - "please specify full path to file"); - return 1; - } else { - QFileInfo file(entries[0]); - if( !file.exists() ) { - fprintf(stderr, "Could not locate content file: %s\n", qPrintable(file.absoluteFilePath())); - return 1; - } - profile->removeDocFileEntry( file.absoluteFilePath() ); - c->setDocRebuild( true ); - c->save(); - } - return 0; - } else if ( QString( QLatin1String(argv[i]) ).toLower() == QLatin1String("-docpath") ) { - INDEX_CHECK( "Missing path!" ); - QDir dir(QString::fromLocal8Bit(argv[i+1])); - if ( dir.exists() ) { - Config *c = Config::loadConfig(QString()); - c->saveProfile(Profile::createDefaultProfile(dir.absolutePath())); - c->loadDefaultProfile(); - c->setDocRebuild(true); - c->save(); - configLoaded = true; - ++i; - } else { - fprintf(stderr, "The specified path does not exist!\n"); - return 1; - } - } else if ( opt == QLatin1String("-hidesidebar") ) { - hideSidebar = true; - } else if ( opt == QLatin1String("-help") || opt == QLatin1String("/?") ) { - QString helpText = QLatin1String( "Usage: assistant [option]\n" - "Options:\n" - " -file Filename assistant opens the specified file\n" - " -server reads commands from a socket after\n" - " assistant has started\n" - " -profile fileName starts assistant and displays the\n" - " profile specified in the file fileName.\n" - " -addContentFile file adds the content file 'file' to the set of\n" - " documentation available by default\n" - " -removeContentFile file removes the content file 'file' from the\n" - " documentation available by default\n" - " -docPath path sets the Qt documentation root path to\n" - " 'path' and starts assistant\n" - " -hideSidebar assistant will hide the sidebar.\n" - " -resourceDir assistant will load translations from\n" - " this directory.\n" - " -help shows this help."); -#ifdef Q_WS_WIN - QMessageBox::information( 0, QLatin1String("Qt Assistant"), - QLatin1String("<pre>") + helpText + QLatin1String("</pre>") ); -#else - fprintf(stdout, "%s\n", qPrintable(helpText)); -#endif - exit( 0 ); - } else if ( opt == QLatin1String("-resourcedir") ) { - INDEX_CHECK( "Missing resource directory argument!" ); - resourceDir = QFile::decodeName( argv[++i] ); - } else { - fprintf(stderr, "Unrecognized option %s. Try -help to get help.\n", qPrintable(opt)); - return 1; - } - } - } - - if( resourceDir.isNull() ) - resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); - - QTranslator translator( 0 ); - translator.load( QLatin1String("assistant_adp_") + QLocale::system().name(), resourceDir ); - a.installTranslator( &translator ); - - QTranslator qtTranslator( 0 ); - qtTranslator.load( QLatin1String("qt_") + QLocale::system().name(), resourceDir ); - a.installTranslator( &qtTranslator ); - - Config *conf = 0; - if (configLoaded) - conf = Config::configuration(); - else - conf = Config::loadConfig( profileName ); - if (!conf) { - fprintf( stderr, "Profile '%s' does not exist!\n", profileName.toLatin1().constData() ); - fflush( stderr ); - return -1; - } - - QStringList links = conf->source(); - conf->hideSideBar( hideSidebar ); - - QPointer<MainWindow> mw = new MainWindow(); - mw->setObjectName(QLatin1String("Assistant")); - - if ( server ) { - as = new AssistantServer(); - printf("%d\n", as->serverPort() ); - fflush( stdout ); - as->connect( as, SIGNAL(showLinkRequest(QString)), - mw, SLOT(showLinkFromClient(QString)) ); - } - -#if !defined(QT_NO_DBUS) && defined(Q_OS_UNIX) - new AssistantAdaptor(mw); -#endif // QT_NO_DBUS - - FontSettings settings = conf->fontSettings(); - if (mw->font() != settings.windowFont) - a.setFont(settings.windowFont, "QWidget"); - -#ifdef Q_WS_MAC - // Make sure AssitantClient shows the window in front. - mw->raise(); -#endif - mw->show(); - - if (!file.isEmpty()) - mw->showLink( MainWindow::urlifyFileName(file) ); - else if (file.isEmpty()) - mw->showLinks( links ); - - a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) ); - - int appExec = a.exec(); - delete (MainWindow*)mw; - return appExec; -} - -QT_END_NAMESPACE - -int main( int argc, char ** argv ) -{ - Q_INIT_RESOURCE(assistant); - return QT_PREPEND_NAMESPACE(runAssistant)(argc, argv); -} - -#include "main.moc" diff --git a/tools/assistant/compat/mainwindow.cpp b/tools/assistant/compat/mainwindow.cpp deleted file mode 100644 index 76143a5..0000000 --- a/tools/assistant/compat/mainwindow.cpp +++ /dev/null @@ -1,885 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "mainwindow.h" -#include "tabbedbrowser.h" -#include "helpdialog.h" -#include "config.h" -#include "fontsettingsdialog.h" - -#include <QDockWidget> -#include <QDir> -#include <QTimer> -#include <QStatusBar> -#include <QShortcut> -#include <QMessageBox> -#include <QPainter> -#include <QEventLoop> -#include <QtEvents> -#include <QFontDatabase> -#include <QWhatsThis> -#include <QTextDocumentFragment> -#include <QLibraryInfo> -#include <QPrinter> -#include <QPrintDialog> -#include <QAbstractTextDocumentLayout> -#include <QTextDocument> -#include <QTextObject> -#include <QFileDialog> -#include <QThread> - -QT_BEGIN_NAMESPACE - -QList<MainWindow*> MainWindow::windows; - -#if defined(Q_WS_WIN) -extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; -#endif - -MainWindow::MainWindow() -{ - setUnifiedTitleAndToolBarOnMac(true); - ui.setupUi(this); - -#if defined(Q_WS_WIN) - // Workaround for QMimeSourceFactory failing in QFileInfo::isReadable() for - // certain user configs. See task: 34372 - qt_ntfs_permission_lookup = 0; -#endif - setupCompleted = false; - - goActions = QList<QAction*>(); - goActionDocFiles = new QMap<QAction*,QString>; - - windows.append(this); - tabs = new TabbedBrowser(this); - connect(tabs, SIGNAL(tabCountChanged(int)), this, SLOT(updateTabActions(int))); - setCentralWidget(tabs); - - Config *config = Config::configuration(); - - updateProfileSettings(); - - dw = new QDockWidget(this); - dw->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - dw->setWindowTitle(tr("Sidebar")); - dw->setObjectName(QLatin1String("sidebar")); - helpDock = new HelpDialog(dw, this); - dw->setWidget(helpDock); - - addDockWidget(Qt::LeftDockWidgetArea, dw); - - // read geometry configuration - setupGoActions(); - - restoreGeometry(config->windowGeometry()); - restoreState(config->mainWindowState()); - if (config->sideBarHidden()) - dw->hide(); - - tabs->setup(); - QTimer::singleShot(0, this, SLOT(setup())); -#if defined(Q_WS_MAC) - QMenu *windowMenu = new QMenu(tr("&Window"), this); - menuBar()->insertMenu(ui.helpMenu->menuAction(), windowMenu); - windowMenu->addAction(tr("Minimize"), this, - SLOT(showMinimized()), QKeySequence(tr("Ctrl+M"))); - // Use the same forward and backward browser shortcuts as Safari and Internet Explorer do - // on the Mac. This means that if you have access to one of those cool Intellimice, the thing - // works just fine, since that's how Microsoft hacked it. - ui.actionGoPrevious->setShortcut(QKeySequence(Qt::CTRL|Qt::Key_Left)); - ui.actionGoNext->setShortcut(QKeySequence(Qt::CTRL|Qt::Key_Right)); - - static const QLatin1String MacIconPath(":/trolltech/assistant/images/mac"); - ui.actionGoNext->setIcon(QIcon(MacIconPath + QLatin1String("/next.png"))); - ui.actionGoPrevious->setIcon(QIcon(MacIconPath + QLatin1String("/prev.png"))); - ui.actionGoHome->setIcon(QIcon(MacIconPath + QLatin1String("/home.png"))); - ui.actionEditCopy->setIcon(QIcon(MacIconPath + QLatin1String("/editcopy.png"))); - ui.actionEditCopy->setIcon(QIcon(MacIconPath + QLatin1String("/editcopy.png"))); - ui.actionEditFind->setIcon(QIcon(MacIconPath + QLatin1String("/find.png"))); - ui.actionFilePrint->setIcon(QIcon(MacIconPath + QLatin1String("/print.png"))); - ui.actionZoomOut->setIcon(QIcon(MacIconPath + QLatin1String("/zoomout.png"))); - ui.actionZoomIn->setIcon(QIcon(MacIconPath + QLatin1String("/zoomin.png"))); - ui.actionSyncToc->setIcon(QIcon(MacIconPath + QLatin1String("/synctoc.png"))); - ui.actionHelpWhatsThis->setIcon(QIcon(MacIconPath + QLatin1String("/whatsthis.png"))); -#elif defined(Q_WS_X11) - ui.actionGoNext->setIcon(QIcon::fromTheme("go-next" , ui.actionGoNext->icon())); - ui.actionGoPrevious->setIcon(QIcon::fromTheme("go-previous" , ui.actionGoPrevious->icon())); - ui.actionGoHome->setIcon(QIcon::fromTheme("user-home" , ui.actionGoHome->icon())); - ui.actionEditCopy->setIcon(QIcon::fromTheme("edit-copy" , ui.actionEditCopy->icon())); - ui.actionEditFind->setIcon(QIcon::fromTheme("edit-find" , ui.actionEditFind->icon())); - ui.actionFilePrint->setIcon(QIcon::fromTheme("document-print" , ui.actionFilePrint->icon())); - ui.actionZoomOut->setIcon(QIcon::fromTheme("zoom-out" , ui.actionZoomOut->icon())); - ui.actionZoomIn->setIcon(QIcon::fromTheme("zoom-in" , ui.actionZoomIn->icon())); - ui.actionSyncToc->setIcon(QIcon::fromTheme("view-refresh" , ui.actionSyncToc->icon())); -#endif -} - -MainWindow::~MainWindow() -{ - windows.removeAll(this); - delete goActionDocFiles; -} - -void MainWindow::setup() -{ - if(setupCompleted) - return; - - qApp->setOverrideCursor(QCursor(Qt::WaitCursor)); - statusBar()->showMessage(tr("Initializing Qt Assistant...")); - setupCompleted = true; - helpDock->initialize(); - connect(ui.actionGoPrevious, SIGNAL(triggered()), tabs, SLOT(backward())); - connect(ui.actionGoNext, SIGNAL(triggered()), tabs, SLOT(forward())); - connect(ui.actionEditCopy, SIGNAL(triggered()), tabs, SLOT(copy())); - connect(ui.actionFileExit, SIGNAL(triggered()), qApp, SLOT(closeAllWindows())); - connect(ui.actionAddBookmark, SIGNAL(triggered()), - helpDock, SLOT(addBookmark())); - connect(helpDock, SIGNAL(showLink(QString)), - this, SLOT(showLink(QString))); - connect(helpDock, SIGNAL(showSearchLink(QString,QStringList)), - this, SLOT(showSearchLink(QString,QStringList))); - - connect(ui.bookmarkMenu, SIGNAL(triggered(QAction*)), - this, SLOT(showBookmark(QAction*))); - connect(ui.actionZoomIn, SIGNAL(triggered()), tabs, SLOT(zoomIn())); - connect(ui.actionZoomOut, SIGNAL(triggered()), tabs, SLOT(zoomOut())); - - connect(ui.actionOpenPage, SIGNAL(triggered()), tabs, SLOT(newTab())); - connect(ui.actionClosePage, SIGNAL(triggered()), tabs, SLOT(closeTab())); - connect(ui.actionNextPage, SIGNAL(triggered()), tabs, SLOT(nextTab())); - connect(ui.actionPrevPage, SIGNAL(triggered()), tabs, SLOT(previousTab())); - - -#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) - QShortcut *acc = new QShortcut(tr("SHIFT+CTRL+="), this); - connect(acc, SIGNAL(activated()), ui.actionZoomIn, SIGNAL(triggered())); -#endif - - connect(new QShortcut(tr("Ctrl+T"), this), SIGNAL(activated()), helpDock, SLOT(toggleContents())); - connect(new QShortcut(tr("Ctrl+I"), this), SIGNAL(activated()), helpDock, SLOT(toggleIndex())); - connect(new QShortcut(tr("Ctrl+B"), this), SIGNAL(activated()), helpDock, SLOT(toggleBookmarks())); - connect(new QShortcut(tr("Ctrl+S"), this), SIGNAL(activated()), helpDock, SLOT(toggleSearch())); - connect(new QShortcut(tr("Ctrl+]"), this), SIGNAL(activated()), tabs, SLOT(nextTab())); - connect(new QShortcut(tr("Ctrl+["), this), SIGNAL(activated()), tabs, SLOT(previousTab())); - - Config *config = Config::configuration(); - - setupBookmarkMenu(); - - QAction *viewsAction = createPopupMenu()->menuAction(); - viewsAction->setText(tr("Views")); - ui.viewMenu->addAction(viewsAction); - - const int tabIndex = config->sideBarPage(); - helpDock->tabWidget()->setCurrentIndex(tabIndex); - // The tab index is 0 by default, so we need to force an upate - // to poulate the contents in this case. - if (tabIndex == 0) - helpDock->currentTabChanged(tabIndex); - - ui.actionEditFind->setShortcut(QKeySequence::Find); - ui.actionEditFindNext->setShortcut(QKeySequence::FindNext); - ui.actionEditFindPrev->setShortcut(QKeySequence::FindPrevious); - - QObject::connect(ui.actionEditFind, SIGNAL(triggered()), tabs, SLOT(find())); - QObject::connect(ui.actionEditFindNext, SIGNAL(triggered()), tabs, SLOT(findNext())); - QObject::connect(ui.actionEditFindPrev, SIGNAL(triggered()), tabs, SLOT(findPrevious())); - connect(ui.actionEditFont_Settings, SIGNAL(triggered()), this, SLOT(showFontSettingsDialog())); - - qApp->restoreOverrideCursor(); - ui.actionGoPrevious->setEnabled(false); - ui.actionGoNext->setEnabled(false); - ui.actionEditCopy->setEnabled(false); - - // set the current selected item in the treeview - helpDialog()->locateContents(tabs->currentBrowser()->source().toString()); - connect(tabs, SIGNAL(browserUrlChanged(QString)), helpDock, SLOT(locateContents(QString))); -} - -void MainWindow::browserTabChanged() -{ - HelpWindow *win = tabs->currentBrowser(); - if (win) { - QTextCursor cursor(win->textCursor()); - ui.actionEditCopy->setEnabled(cursor.hasSelection()); - ui.actionGoPrevious->setEnabled(win->isBackwardAvailable()); - ui.actionGoNext->setEnabled(win->isForwardAvailable()); - } -} - -void MainWindow::copyAvailable(bool yes) -{ - ui.actionEditCopy->setEnabled(yes); -} - -void MainWindow::updateTabActions(int index) -{ - bool enabled = (index > 1) ? true : false; - ui.actionPrevPage->setEnabled(enabled); - ui.actionNextPage->setEnabled(enabled); - ui.actionClosePage->setEnabled(enabled); -} - -void MainWindow::setupGoActions() -{ - Config *config = Config::configuration(); - QStringList titles = config->docTitles(); - QAction *action = 0; - - static bool separatorInserted = false; - - foreach (QAction *a, goActions) { - ui.goMenu->removeAction(a); - ui.goActionToolbar->removeAction(a); - } - qDeleteAll(goActions); - goActions.clear(); - goActionDocFiles->clear(); - - int addCount = 0; - - foreach (QString title, titles) { - QPixmap pix = config->docIcon(title); - if(!pix.isNull()) { - if(!separatorInserted) { - ui.goMenu->addSeparator(); - separatorInserted = true; - } - action = new QAction(this); - action->setText(title); - action->setWhatsThis(tr("Displays the main page of a specific documentation set.")); - action->setIcon(QIcon(pix)); - ui.goMenu->addAction(action); - ui.goActionToolbar->addAction(action); - goActions.append(action); - goActionDocFiles->insert(action, config->indexPage(title)); - connect(action, SIGNAL(triggered()), - this, SLOT(showGoActionLink())); - ++addCount; - } - } - if(!addCount) - ui.goActionToolbar->hide(); - else - ui.goActionToolbar->show(); - -} - -bool MainWindow::insertActionSeparator() -{ - ui.goMenu->addSeparator(); - ui.Toolbar->addSeparator(); - return true; -} - -void MainWindow::closeEvent(QCloseEvent *e) -{ - saveSettings(); - e->accept(); -} - -void MainWindow::about() -{ - QMessageBox box(this); - - box.setText(QString::fromLatin1("<center><img src=\":/trolltech/assistant/images/assistant-128.png\">" - "<h3>%1</h3>" - "<p>Version %2</p></center>" - "<p>Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).</p>") - .arg(tr("Qt Assistant")).arg(QLatin1String(QT_VERSION_STR))); - box.setWindowTitle(tr("Qt Assistant")); - box.setIcon(QMessageBox::NoIcon); - box.exec(); -} - -void MainWindow::on_actionAboutApplication_triggered() -{ - QString url = Config::configuration()->aboutURL(); - if (url == QLatin1String("about_qt")) { - QMessageBox::aboutQt(this, QLatin1String("Qt Assistant")); - return; - } - QString text; - if (url.startsWith(QLatin1String("file:"))) - url = url.mid(5); - QFile file(url); - if(file.exists() && file.open(QFile::ReadOnly)) - text = QString::fromUtf8(file.readAll()); - if(text.isNull()) - text = tr("Failed to open about application contents in file: '%1'").arg(url); - - QFileInfo fi(file); - QString path = QDir::cleanPath(fi.absolutePath()); - if (!QDir::searchPaths(QLatin1String("aboutImages")).contains(path)) - QDir::addSearchPath(QLatin1String("aboutImages"), path); - - QMessageBox box(this); - box.setText(text); - box.setWindowTitle(Config::configuration()->aboutApplicationMenuText()); - box.setIcon(QMessageBox::NoIcon); - box.exec(); -} - -void MainWindow::on_actionAboutAssistant_triggered() -{ - about(); -} - -void MainWindow::on_actionGoHome_triggered() -{ - QString home = MainWindow::urlifyFileName(Config::configuration()->homePage()); - showLink(home); -} - -QString MainWindow::urlifyFileName(const QString &fileName) -{ - QString name = fileName; - QUrl url(name); - -#if defined(Q_OS_WIN32) - if (!url.isValid() || url.scheme().isEmpty() || url.scheme().toLower() != QLatin1String("file:")) { - int i = name.indexOf(QLatin1Char('#')); - QString anchor = name.mid(i); - name = name.toLower(); - if (i > -1) - name.replace(i, anchor.length(), anchor); - name.replace(QLatin1Char('\\'), QLatin1Char('/')); - foreach (QFileInfo drive, QDir::drives()) { - if (name.startsWith(drive.absolutePath().toLower())) { - name = QLatin1String("file:") + name; - break; - } - } - } -#else - if (!url.isValid() || url.scheme().isEmpty()) - name.prepend(QLatin1String("file:")); -#endif - return name; -} - -#ifndef QT_NO_PRINTER -class PrintThread : public QThread -{ - QPrinter _printer; - QTextDocument *_document; - -public: - PrintThread(QObject *parent) - : QThread(parent), _printer(QPrinter::HighResolution), _document(0) - { - } - ~PrintThread() - { - wait(); - } - - QPrinter *printer() - { - return &_printer; - } - - void start(QTextDocument *document) - { - _document = document->clone(); - _document->moveToThread(this); - QThread::start(); - } - -protected: - void run() - { - _document->print(printer()); - delete _document; - _document = 0; - } -}; -#endif //QT_NO_PRINTER - -void MainWindow::on_actionFilePrint_triggered() -{ -#ifndef QT_NO_PRINTER - if (!QFontDatabase::supportsThreadedFontRendering()) { - QPrinter printer(QPrinter::HighResolution); - - QPrintDialog dlg(&printer, this); - if (dlg.exec() == QDialog::Accepted) { - qApp->setOverrideCursor(Qt::WaitCursor); - tabs->currentBrowser()->document()->print(&printer); - qApp->restoreOverrideCursor(); - } - return; - } - - PrintThread *thread = new PrintThread(this); - - QPrintDialog dlg(thread->printer(), this); - if (dlg.exec() == QDialog::Accepted) { - connect(thread, SIGNAL(finished()), SLOT(printingFinished())); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - - qApp->setOverrideCursor(Qt::BusyCursor); - thread->start(tabs->currentBrowser()->document()); - } else { - delete thread; - } -#else - Q_ASSERT("No printing support"); -#endif -} - -void MainWindow::printingFinished() -{ - qApp->restoreOverrideCursor(); -} - -void MainWindow::updateBookmarkMenu() -{ - for(QList<MainWindow*>::Iterator it = windows.begin(); it != windows.end(); ++it) - (*it)->setupBookmarkMenu(); -} - -void MainWindow::setupBookmarkMenu() -{ - ui.bookmarkMenu->clear(); - bookmarks.clear(); - ui.bookmarkMenu->addAction(ui.actionAddBookmark); - - QFile f(QDir::homePath() + QLatin1String("/.assistant/bookmarks.") + - Config::configuration()->profileName()); - if (!f.open(QFile::ReadOnly)) - return; - QTextStream ts(&f); - ui.bookmarkMenu->addSeparator(); - while (!ts.atEnd()) { - QString title = ts.readLine(); - QString link = ts.readLine(); - bookmarks.insert(ui.bookmarkMenu->addAction(title), link); - } -} - -void MainWindow::showBookmark(QAction *action) -{ - if (bookmarks.contains(action)) - showLink(bookmarks.value(action)); -} - -void MainWindow::showLinkFromClient(const QString &link) -{ - setWindowState(windowState() & ~Qt::WindowMinimized); - raise(); - activateWindow(); - QString l = MainWindow::urlifyFileName(link); - showLink(l); - if (isMinimized()) - showNormal(); -} - -void MainWindow::showLink(const QString &link) -{ - if(link.isEmpty()) - qWarning("The link is empty!"); - - // don't fill the history with the same url more then once - if (link == tabs->currentBrowser()->source().toString()) - return; - - QUrl url(link); - QFileInfo fi(url.toLocalFile()); - tabs->setSource(url.toString()); - tabs->currentBrowser()->setFocus(); -} - -void MainWindow::showLinks(const QStringList &links) -{ - if (links.size() == 0) { - qWarning("MainWindow::showLinks() - Empty link"); - return; - } - - if (links.size() == 1) { - showLink(MainWindow::urlifyFileName(links.first())); - return; - } - - QStringList::ConstIterator it = links.begin(); - // Initial showing, The tab is empty so update that without creating it first - if (!tabs->currentBrowser()->source().isValid()) { - QPair<HelpWindow*, QString> browser; - browser.first = tabs->currentBrowser(); - browser.second = links.first(); - pendingBrowsers.append(browser); - tabs->setTitle(tabs->currentBrowser(), tr("...")); - } - ++it; - - while(it != links.end()) { - QPair<HelpWindow*, QString> browser; - browser.first = tabs->newBackgroundTab(); - browser.second = *it; - pendingBrowsers.append(browser); - ++it; - } - - startTimer(50); - return; -} - -void MainWindow::removePendingBrowser(HelpWindow *win) -{ - if (!pendingBrowsers.count()) - return; - - QMutableListIterator<QPair<HelpWindow*, QString> > it(pendingBrowsers); - while (it.hasNext()) { - QPair<HelpWindow*, QString> browser = it.next(); - if (browser.first == win) { - it.remove(); - break; - } - } -} - -void MainWindow::timerEvent(QTimerEvent *e) -{ - QPair<HelpWindow*, QString> browser = pendingBrowsers.first(); - pendingBrowsers.pop_front(); - - if (pendingBrowsers.size() == 0) - killTimer(e->timerId()); - - browser.first->setSource(MainWindow::urlifyFileName(browser.second)); -} - -void MainWindow::showQtHelp() -{ - showLink(QLibraryInfo::location(QLibraryInfo::DocumentationPath) + - QLatin1String("/html/index.html")); -} - -MainWindow* MainWindow::newWindow() -{ - saveSettings(); - MainWindow *mw = new MainWindow; - mw->move(geometry().topLeft()); - if (isMaximized()) - mw->showMaximized(); - else - mw->show(); - mw->on_actionGoHome_triggered(); - return mw; -} - -void MainWindow::saveSettings() -{ - Config *config = Config::configuration(); - - config->setSideBarPage(helpDock->tabWidget()->currentIndex()); - config->setWindowGeometry(saveGeometry()); - config->setMainWindowState(saveState()); - - // Create list of the tab urls - QStringList lst; - QList<HelpWindow*> browsers = tabs->browsers(); - foreach (HelpWindow *browser, browsers) - lst << browser->source().toString(); - config->setSource(lst); - config->save(); -} - -TabbedBrowser* MainWindow::browsers() const -{ - return tabs; -} - -void MainWindow::showSearchLink(const QString &link, const QStringList &terms) -{ - HelpWindow * hw = tabs->currentBrowser(); - hw->blockScrolling(true); - hw->setCursor(Qt::WaitCursor); - if (hw->source() == link) - hw->reload(); - else - showLink(link); - hw->setCursor(Qt::ArrowCursor); - - hw->viewport()->setUpdatesEnabled(false); - - QTextCharFormat marker; - marker.setForeground(Qt::red); - - QTextCursor firstHit; - - QTextCursor c = hw->textCursor(); - c.beginEditBlock(); - foreach (QString term, terms) { - c.movePosition(QTextCursor::Start); - hw->setTextCursor(c); - - bool found = hw->find(term, QTextDocument::FindWholeWords); - while (found) { - QTextCursor hit = hw->textCursor(); - if (firstHit.isNull() || hit.position() < firstHit.position()) - firstHit = hit; - - hit.mergeCharFormat(marker); - found = hw->find(term, QTextDocument::FindWholeWords); - } - } - - if (firstHit.isNull()) { - firstHit = hw->textCursor(); - firstHit.movePosition(QTextCursor::Start); - } - firstHit.clearSelection(); - c.endEditBlock(); - hw->setTextCursor(firstHit); - - hw->blockScrolling(false); - hw->viewport()->setUpdatesEnabled(true); -} - - -void MainWindow::showGoActionLink() -{ - const QObject *origin = sender(); - if(!origin || - QString::fromLatin1(origin->metaObject()->className()) != QString::fromLatin1("QAction")) - return; - - QAction *action = (QAction*) origin; - QString docfile = *(goActionDocFiles->find(action)); - showLink(MainWindow::urlifyFileName(docfile)); -} - -void MainWindow::on_actionHelpAssistant_triggered() -{ - showLink(Config::configuration()->assistantDocPath() + QLatin1String("/assistant-manual.html")); -} - -HelpDialog* MainWindow::helpDialog() const -{ - return helpDock; -} - -void MainWindow::backwardAvailable(bool enable) -{ - ui.actionGoPrevious->setEnabled(enable); -} - -void MainWindow::forwardAvailable(bool enable) -{ - ui.actionGoNext->setEnabled(enable); -} - -void MainWindow::updateProfileSettings() -{ - Config *config = Config::configuration(); -#ifndef Q_WS_MAC - setWindowIcon(config->applicationIcon()); -#endif - ui.helpMenu->clear(); - //ui.helpMenu->addAction(ui.actionHelpAssistant); - //ui.helpMenu->addSeparator(); - ui.helpMenu->addAction(ui.actionAboutAssistant); - if (!config->aboutApplicationMenuText().isEmpty()) - ui.helpMenu->addAction(ui.actionAboutApplication); - ui.helpMenu->addSeparator(); - ui.helpMenu->addAction(ui.actionHelpWhatsThis); - - ui.actionAboutApplication->setText(config->aboutApplicationMenuText()); - - if(!config->title().isNull()) - setWindowTitle(config->title()); -} - -void MainWindow::setupPopupMenu(QMenu *m) -{ - m->addAction(ui.actionNewWindow); - m->addAction(ui.actionOpenPage); - m->addAction(ui.actionClosePage); - m->addSeparator(); - m->addAction(ui.actionSaveAs); - m->addSeparator(); - m->addAction(ui.actionGoPrevious); - m->addAction(ui.actionGoNext); - m->addAction(ui.actionGoHome); - m->addSeparator(); - m->addAction(ui.actionZoomIn); - m->addAction(ui.actionZoomOut); - m->addSeparator(); - m->addAction(ui.actionEditCopy); - m->addAction(ui.actionEditFind); -} - -void MainWindow::on_actionSyncToc_triggered() -{ - HelpWindow *w = tabs->currentBrowser(); - if(w) { - qApp->setOverrideCursor(QCursor(Qt::WaitCursor)); - QString link = w->source().toString(); - helpDock->locateContents(link); - helpDock->tabWidget()->setCurrentIndex(0); - qApp->restoreOverrideCursor(); - } -} - -void MainWindow::on_actionNewWindow_triggered() -{ - newWindow()->show(); -} - -void MainWindow::on_actionClose_triggered() -{ - close(); -} - -void MainWindow::on_actionHelpWhatsThis_triggered() -{ - QWhatsThis::enterWhatsThisMode(); -} - -void MainWindow::on_actionSaveAs_triggered() -{ - QString fileName; - QUrl url = tabs->currentBrowser()->source(); - if (url.isValid()) { - QFileInfo fi(url.toLocalFile()); - fileName = fi.fileName(); - } - fileName = QFileDialog::getSaveFileName(this, tr("Save Page"), fileName); - if (fileName.isEmpty()) - return; - - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly)) { - QMessageBox::critical(this, tr("Save Page"), tr("Cannot open file for writing!")); - return; - } - - QFileInfo fi(fileName); - QString fn = fi.fileName(); - int i = fn.lastIndexOf(QLatin1Char('.')); - if (i > -1) - fn = fn.left(i); - QString relativeDestPath = fn + QLatin1String("_images"); - QDir destDir(fi.absolutePath() + QDir::separator() + relativeDestPath); - bool imgDirAvailable = destDir.exists(); - if (!imgDirAvailable) - imgDirAvailable = destDir.mkdir(destDir.absolutePath()); - - // save images - QTextDocument *doc = tabs->currentBrowser()->document()->clone(); - if (url.isValid() && imgDirAvailable) { - QTextBlock::iterator it; - for (QTextBlock block = doc->begin(); block != doc->end(); block = block.next()) { - for (it = block.begin(); !(it.atEnd()); ++it) { - QTextFragment fragment = it.fragment(); - if (fragment.isValid()) { - QTextImageFormat fm = fragment.charFormat().toImageFormat(); - if (fm.isValid() && !fm.name().isEmpty()) { - QUrl imagePath = tabs->currentBrowser()->source().resolved(fm.name()); - if (!imagePath.isValid()) - continue; - QString from = imagePath.toLocalFile(); - QString destName = fm.name(); - int j = destName.lastIndexOf(QLatin1Char('/')); - if (j > -1) - destName = destName.mid(j+1); - QFileInfo info(from); - if (info.exists()) { - if (!QFile::copy(from, destDir.absolutePath() - + QDir::separator() + destName)) - continue; - fm.setName(QLatin1String("./") + relativeDestPath + QLatin1String("/") + destName); - QTextCursor cursor(doc); - cursor.setPosition(fragment.position()); - cursor.setPosition(fragment.position() + fragment.length(), - QTextCursor::KeepAnchor); - cursor.setCharFormat(fm); - } - } - } - } - } - } - QString src = doc->toHtml(QByteArray("utf-8")); - QTextStream s(&file); - s.setCodec("utf-8"); - s << src; - s.flush(); - file.close(); -} - -void MainWindow::showFontSettingsDialog() -{ - Config *config = Config::configuration(); - FontSettings settings = config->fontSettings(); - - { // It is important that the dialog be deleted before UI mode changes. - FontSettingsDialog dialog; - if (!dialog.showDialog(&settings)) - return; - } - - config->setFontPointSize(settings.browserFont.pointSizeF()); - config->setFontSettings(settings); - - updateApplicationFontSettings(settings); -} - -void MainWindow::updateApplicationFontSettings(FontSettings &settings) -{ - QFont font = settings.windowFont; - if (this->font() != font) - qApp->setFont(font, "QWidget"); - - font = settings.browserFont; - QList<HelpWindow*> browsers = tabs->browsers(); - foreach (HelpWindow *browser, browsers) { - if (browser->font() != font) - browser->setFont(font); - } -} - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/mainwindow.h b/tools/assistant/compat/mainwindow.h deleted file mode 100644 index a08064d..0000000 --- a/tools/assistant/compat/mainwindow.h +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include "ui_mainwindow.h" -#include "config.h" - -#include <QPointer> -#include <QMap> - -QT_BEGIN_NAMESPACE - -class TabbedBrowser; -class HelpDialog; -class HelpWindow; -class QMenu; -class QDockWidget; - -class MainWindow : public QMainWindow -{ - Q_OBJECT -public: - MainWindow(); - virtual ~MainWindow(); - - TabbedBrowser *browsers() const; - HelpDialog *helpDialog() const; - - void setupPopupMenu(QMenu *menu); - static QString urlifyFileName(const QString &fileName); - - void removePendingBrowser(HelpWindow *win); - -public slots: - MainWindow *newWindow(); - - void setup(); - void showLink(const QString &link); - void showLinks(const QStringList &links); - void saveSettings(); - void updateBookmarkMenu(); - void printingFinished(); - -private slots: - void on_actionNewWindow_triggered(); - void on_actionGoHome_triggered(); - void on_actionFilePrint_triggered(); - void on_actionClose_triggered(); - void on_actionHelpWhatsThis_triggered(); - void on_actionHelpAssistant_triggered(); - void on_actionAboutApplication_triggered(); - void on_actionAboutAssistant_triggered(); - void on_actionSaveAs_triggered(); - void on_actionSyncToc_triggered(); - - void about(); - void setupBookmarkMenu(); - void showBookmark(QAction *action); - void showLinkFromClient(const QString &link); - void showQtHelp(); - void showSearchLink(const QString &link, const QStringList &terms); - void showGoActionLink(); - void updateProfileSettings(); - void backwardAvailable(bool); - void forwardAvailable(bool); - - void browserTabChanged(); - void copyAvailable(bool yes); - void updateTabActions(int index); - void showFontSettingsDialog(); - -protected: - void closeEvent(QCloseEvent *); - void timerEvent(QTimerEvent *); - -private: - void setupGoActions(); - bool insertActionSeparator(); - void updateApplicationFontSettings(FontSettings &settings); - -private: - Ui::MainWindow ui; - - QList<QAction*> goActions; - uint setupCompleted:1; - TabbedBrowser *tabs; - QMap<QAction*, QString> bookmarks; - HelpDialog *helpDock; - QDockWidget *dw; - static QList<MainWindow*> windows; - QMap<QAction*,QString> *goActionDocFiles; - QList<QPair<HelpWindow*,QString> > pendingBrowsers; -}; - -#endif // MAINWINDOW_H - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/mainwindow.ui b/tools/assistant/compat/mainwindow.ui deleted file mode 100644 index 535e27e..0000000 --- a/tools/assistant/compat/mainwindow.ui +++ /dev/null @@ -1,457 +0,0 @@ -<ui version="4.0" > - <comment>********************************************************************* -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -*********************************************************************</comment> - <class>MainWindow</class> - <widget class="QMainWindow" name="MainWindow" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>949</width> - <height>670</height> - </rect> - </property> - <property name="windowTitle" > - <string>Qt Assistant by Nokia</string> - </property> - <widget class="QWidget" name="__qt_central_widget" /> - <widget class="QToolBar" name="Toolbar" > - <property name="windowTitle" > - <string>Toolbar</string> - </property> - <property name="orientation" > - <enum>Qt::Horizontal</enum> - </property> - <attribute name="toolBarArea" > - <enum>TopToolBarArea</enum> - </attribute> - <attribute name="toolBarBreak" > - <bool>false</bool> - </attribute> - <addaction name="actionGoPrevious" /> - <addaction name="actionGoNext" /> - <addaction name="actionGoHome" /> - <addaction name="actionSyncToc" /> - <addaction name="separator" /> - <addaction name="actionEditCopy" /> - <addaction name="actionEditFind" /> - <addaction name="actionFilePrint" /> - <addaction name="separator" /> - <addaction name="actionZoomIn" /> - <addaction name="actionZoomOut" /> - <addaction name="separator" /> - <addaction name="actionHelpWhatsThis" /> - </widget> - <widget class="QToolBar" name="goActionToolbar" > - <property name="windowTitle" > - <string>Go</string> - </property> - <property name="orientation" > - <enum>Qt::Horizontal</enum> - </property> - <attribute name="toolBarArea" > - <enum>TopToolBarArea</enum> - </attribute> - <attribute name="toolBarBreak" > - <bool>false</bool> - </attribute> - </widget> - <widget class="QMenuBar" name="menubar" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>949</width> - <height>29</height> - </rect> - </property> - <widget class="QMenu" name="helpMenu" > - <property name="title" > - <string>&Help</string> - </property> - <addaction name="actionHelpAssistant" /> - <addaction name="separator" /> - <addaction name="actionAboutAssistant" /> - <addaction name="actionAboutApplication" /> - <addaction name="separator" /> - <addaction name="actionHelpWhatsThis" /> - </widget> - <widget class="QMenu" name="fileMenu" > - <property name="title" > - <string>&File</string> - </property> - <addaction name="actionNewWindow" /> - <addaction name="actionOpenPage" /> - <addaction name="actionClosePage" /> - <addaction name="separator" /> - <addaction name="actionSaveAs" /> - <addaction name="separator" /> - <addaction name="actionFilePrint" /> - <addaction name="separator" /> - <addaction name="actionClose" /> - <addaction name="actionFileExit" /> - </widget> - <widget class="QMenu" name="bookmarkMenu" > - <property name="title" > - <string>Boo&kmarks</string> - </property> - </widget> - <widget class="QMenu" name="goMenu" > - <property name="title" > - <string>&Go</string> - </property> - <addaction name="actionGoPrevious" /> - <addaction name="actionGoNext" /> - <addaction name="actionGoHome" /> - <addaction name="actionSyncToc" /> - <addaction name="separator" /> - <addaction name="actionNextPage" /> - <addaction name="actionPrevPage" /> - </widget> - <widget class="QMenu" name="viewMenu" > - <property name="title" > - <string>&View</string> - </property> - <addaction name="actionZoomIn" /> - <addaction name="actionZoomOut" /> - </widget> - <widget class="QMenu" name="editMenu" > - <property name="title" > - <string>&Edit</string> - </property> - <addaction name="actionEditCopy" /> - <addaction name="actionEditFind" /> - <addaction name="actionEditFindNext" /> - <addaction name="actionEditFindPrev" /> - <addaction name="separator" /> - <addaction name="actionEditFont_Settings" /> - </widget> - <addaction name="fileMenu" /> - <addaction name="editMenu" /> - <addaction name="viewMenu" /> - <addaction name="goMenu" /> - <addaction name="bookmarkMenu" /> - <addaction name="helpMenu" /> - </widget> - <action name="actionFilePrint" > - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/win/print.png</iconset> - </property> - <property name="text" > - <string>&Print...</string> - </property> - <property name="whatsThis" > - <string>Print the currently displayed page.</string> - </property> - <property name="shortcut" > - <string>Ctrl+P</string> - </property> - </action> - <action name="actionFileExit" > - <property name="text" > - <string>E&xit</string> - </property> - <property name="whatsThis" > - <string>Quit Qt Assistant.</string> - </property> - <property name="shortcut" > - <string>Ctrl+Q</string> - </property> - <property name="menuRole" > - <enum>QAction::QuitRole</enum> - </property> - </action> - <action name="actionEditCopy" > - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/win/editcopy.png</iconset> - </property> - <property name="text" > - <string>&Copy</string> - </property> - <property name="whatsThis" > - <string>Copy the selected text to the clipboard.</string> - </property> - <property name="shortcut" > - <string>Ctrl+C</string> - </property> - </action> - <action name="actionEditFind" > - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/win/find.png</iconset> - </property> - <property name="text" > - <string>&Find in Text...</string> - </property> - <property name="whatsThis" > - <string>Open the Find dialog. Qt Assistant will search the currently displayed page for the text you enter.</string> - </property> - <property name="shortcut" > - <string>Ctrl+F</string> - </property> - </action> - <action name="actionEditFindNext" > - <property name="text" > - <string>Find &Next</string> - </property> - <property name="shortcut" > - <string>F3</string> - </property> - </action> - <action name="actionEditFindPrev" > - <property name="text" > - <string>Find &Previous</string> - </property> - <property name="shortcut" > - <string>Shift+F3</string> - </property> - </action> - <action name="actionGoHome" > - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/win/home.png</iconset> - </property> - <property name="text" > - <string>&Home</string> - </property> - <property name="whatsThis" > - <string>Go to the home page. Qt Assistant's home page is the Qt Reference Documentation.</string> - </property> - <property name="shortcut" > - <string>Ctrl+Home</string> - </property> - </action> - <action name="actionGoPrevious" > - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/win/previous.png</iconset> - </property> - <property name="text" > - <string>&Previous</string> - </property> - <property name="whatsThis" > - <string>Go to the previous page.</string> - </property> - <property name="shortcut" > - <string>Alt+Left</string> - </property> - </action> - <action name="actionGoNext" > - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/win/next.png</iconset> - </property> - <property name="text" > - <string>&Next</string> - </property> - <property name="whatsThis" > - <string>Go to the next page.</string> - </property> - <property name="shortcut" > - <string>Alt+Right</string> - </property> - </action> - <action name="actionAboutAssistant" > - <property name="text" > - <string>About Qt Assistant</string> - </property> - <property name="whatsThis" > - <string>Display further information about Qt Assistant.</string> - </property> - <property name="menuRole" > - <enum>QAction::AboutRole</enum> - </property> - </action> - <action name="actionAboutApplication" > - <property name="text" > - <string>About Qt</string> - </property> - <property name="menuRole" > - <enum>QAction::AboutQtRole</enum> - </property> - </action> - <action name="actionZoomIn" > - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/win/zoomin.png</iconset> - </property> - <property name="text" > - <string>Zoom &in</string> - </property> - <property name="whatsThis" > - <string>Zoom in on the document, i.e. increase the font size.</string> - </property> - <property name="shortcut" > - <string>Ctrl++</string> - </property> - </action> - <action name="actionZoomOut" > - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/win/zoomout.png</iconset> - </property> - <property name="text" > - <string>Zoom &out</string> - </property> - <property name="whatsThis" > - <string>Zoom out on the document, i.e. decrease the font size.</string> - </property> - <property name="shortcut" > - <string>Ctrl+-</string> - </property> - </action> - <action name="actionNewWindow" > - <property name="text" > - <string>New Window</string> - </property> - <property name="whatsThis" > - <string>Open a new window.</string> - </property> - <property name="shortcut" > - <string>Ctrl+N</string> - </property> - </action> - <action name="actionClose" > - <property name="text" > - <string>&Close</string> - </property> - <property name="whatsThis" > - <string>Close the current window.</string> - </property> - <property name="shortcut" > - <string>Ctrl+W</string> - </property> - </action> - <action name="actionAddBookmark" > - <property name="text" > - <string>&Add Bookmark</string> - </property> - <property name="whatsThis" > - <string>Add the currently displayed page as a new bookmark.</string> - </property> - </action> - <action name="actionHelpWhatsThis" > - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/win/whatsthis.png</iconset> - </property> - <property name="text" > - <string>What's This?</string> - </property> - <property name="statusTip" > - <string>"What's This?" context sensitive help.</string> - </property> - <property name="whatsThis" > - <string>"What's This?" context sensitive help.</string> - </property> - <property name="shortcut" > - <string>Shift+F1</string> - </property> - </action> - <action name="actionOpenPage" > - <property name="text" > - <string>Add Tab</string> - </property> - <property name="shortcut" > - <string>Ctrl+Alt+N</string> - </property> - </action> - <action name="actionNextPage" > - <property name="text" > - <string>Next Tab</string> - </property> - <property name="shortcut" > - <string>Ctrl+Alt+Right</string> - </property> - </action> - <action name="actionPrevPage" > - <property name="text" > - <string>Previous Tab</string> - </property> - <property name="shortcut" > - <string>Ctrl+Alt+Left</string> - </property> - </action> - <action name="actionClosePage" > - <property name="text" > - <string>Close Tab</string> - </property> - <property name="shortcut" > - <string>Ctrl+Alt+Q</string> - </property> - </action> - <action name="actionHelpAssistant" > - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/assistant.png</iconset> - </property> - <property name="text" > - <string>Qt Assistant Manual</string> - </property> - <property name="shortcut" > - <string>F1</string> - </property> - </action> - <action name="actionSaveAs" > - <property name="text" > - <string>Save Page As...</string> - </property> - <property name="shortcut" > - <string>Ctrl+Alt+S</string> - </property> - </action> - <action name="actionSyncToc" > - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/win/synctoc.png</iconset> - </property> - <property name="text" > - <string>Sync with Table of Contents</string> - </property> - <property name="whatsThis" > - <string>Select the page in contents tab.</string> - </property> - </action> - <action name="actionEditFont_Settings" > - <property name="text" > - <string>Font Settings...</string> - </property> - <property name="menuRole" > - <enum>QAction::PreferencesRole</enum> - </property> - </action> - </widget> - <resources> - <include location="assistant.qrc" /> - </resources> - <connections/> -</ui> diff --git a/tools/assistant/compat/profile.cpp b/tools/assistant/compat/profile.cpp deleted file mode 100644 index 2878a20..0000000 --- a/tools/assistant/compat/profile.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "profile.h" -#include <QTextCodec> -#include <QFileInfo> -#include <QRegExp> -#include <QDir> -#include <QList> -#include <QLibraryInfo> - -QT_BEGIN_NAMESPACE - -#define QT_TITLE QLatin1String("Qt Reference Documentation") -#define DESIGNER_TITLE QLatin1String("Qt Designer Manual") -#define ASSISTANT_TITLE QLatin1String("Qt Assistant Manual") -#define LINGUIST_TITLE QLatin1String("Qt Linguist Manual") -#define QMAKE_TITLE QLatin1String("qmake Manual") - -Profile *Profile::createDefaultProfile(const QString &docPath) -{ - QString path = QLibraryInfo::location(QLibraryInfo::DocumentationPath); - if (!docPath.isEmpty()) - path = docPath; - path = QDir::cleanPath(path) + QLatin1String("/html/"); - - Profile *profile = new Profile; - profile->valid = true; - profile->type = DefaultProfile; - profile->props[QLatin1String("name")] = QLatin1String("default"); - profile->props[QLatin1String("applicationicon")] = QLatin1String("assistant.png"); - profile->props[QLatin1String("aboutmenutext")] = QLatin1String("About Qt"); - profile->props[QLatin1String("abouturl")] = QLatin1String("about_qt"); - profile->props[QLatin1String("basepath")] = path; - profile->props[QLatin1String("startpage")] = path + QLatin1String("index.html"); - - profile->addDCFTitle( path + QLatin1String("qt.dcf"), QT_TITLE ); - profile->addDCFTitle( path + QLatin1String("designer.dcf"), DESIGNER_TITLE ); - profile->addDCFTitle( path + QLatin1String("assistant.dcf"), ASSISTANT_TITLE ); - profile->addDCFTitle( path + QLatin1String("linguist.dcf"), LINGUIST_TITLE ); - profile->addDCFTitle( path + QLatin1String("qmake.dcf"), QMAKE_TITLE ); - - profile->addDCFIcon( QT_TITLE, QLatin1String("qt.png") ); - profile->addDCFIcon( DESIGNER_TITLE, QLatin1String("designer.png") ); - profile->addDCFIcon( ASSISTANT_TITLE, QLatin1String("assistant.png") ); - profile->addDCFIcon( LINGUIST_TITLE, QLatin1String("linguist.png") ); - - profile->addDCFIndexPage( QT_TITLE, path + QLatin1String("index.html") ); - profile->addDCFIndexPage( DESIGNER_TITLE, path + QLatin1String("designer-manual.html") ); - profile->addDCFIndexPage( ASSISTANT_TITLE, path + QLatin1String("assistant-manual.html") ); - profile->addDCFIndexPage( LINGUIST_TITLE, path + QLatin1String("linguist-manual.html") ); - profile->addDCFIndexPage( QMAKE_TITLE, path + QLatin1String("qmake-manual.html") ); - - profile->addDCFImageDir( QT_TITLE, QLatin1String("../../gif/") ); - profile->addDCFImageDir( DESIGNER_TITLE, QLatin1String("../../gif/") ); - profile->addDCFImageDir( ASSISTANT_TITLE, QLatin1String("../../gif/") ); - profile->addDCFImageDir( LINGUIST_TITLE, QLatin1String("../../gif/") ); - profile->addDCFImageDir( QMAKE_TITLE, QLatin1String("../../gif/") ); - - return profile; -} - -Profile::Profile() - : valid( true ), dparser( 0 ) -{ - type = DefaultProfile; -} - -bool Profile::isValid() const -{ - return valid; -} - -void Profile::addDCFTitle(const QString &dcf, const QString &title) -{ - QString absdcf = QFileInfo(dcf).absoluteFilePath(); - dcfTitles[title] = absdcf; - if (!docs.contains(absdcf)) - docs << absdcf; -} - -void Profile::addDCF(const QString &docfile) -{ - if( !docs.contains( docfile ) == 0 ) - docs << docfile; -} - -void Profile::addDCFIcon(const QString docfile, const QString &icon) -{ - icons[docfile] = icon; -} - -void Profile::addDCFIndexPage(const QString title, const QString &indexPage) -{ - indexPages[title] = indexPage; -} - -void Profile::addDCFImageDir(const QString docfile, const QString &imgDir) -{ - imageDirs[docfile] = imgDir; -} - -void Profile::addProperty(const QString &name, const QString &value) -{ - props[name] = value; -} - -bool Profile::hasDocFile(const QString &name) -{ - return docs.contains( name ); -} - -void Profile::removeDocFileEntry(const QString &docfile) -{ - docs.removeAll(docfile); - QStringList titles; - - for( QMap<QString,QString>::Iterator it = dcfTitles.begin(); - it != dcfTitles.end(); ++it ) { - if( (*it) == docfile ) { - indexPages.remove( *it ); - icons.remove( *it ); - imageDirs.remove( *it ); - titles << it.key(); - } - } - - for( QStringList::ConstIterator title = titles.constBegin(); - title != titles.constEnd(); ++title ) - dcfTitles.remove( *title ); - -#ifdef ASSISTANT_DEBUG - qDebug() << "docs:\n - " << docs.join("\n - "); - qDebug() << "titles:\n - " << titles.join("\n - "); - qDebug() << "keys:\n - " << ((QStringList*)&(dcfTitles.keys()))->join("\n - "); - qDebug() << "values:\n - " << ((QStringList*)&(dcfTitles.values()))->join("\n - "); -#endif -} - -QString Profile::storableFilePath(const QString &fileName) -{ - QString path = QLibraryInfo::location(QLibraryInfo::DocumentationPath).replace(QLatin1String("\\"), QLatin1String("/")); - QString fName = fileName; - if (fName.startsWith(path)) - fName.replace(0, path.length(), QLatin1String("$DOCPATH$")); - return fName; -} - -QString Profile::loadableFilePath(const QString &fileName) -{ - QString path = QLibraryInfo::location(QLibraryInfo::DocumentationPath).replace(QLatin1String("\\"), QLatin1String("/")); - QString fName = fileName; - if (fName.startsWith(QLatin1String("$DOCPATH$"))) - fName.replace(0, 9, path); - return fName; -} - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/profile.h b/tools/assistant/compat/profile.h deleted file mode 100644 index 1aa9719..0000000 --- a/tools/assistant/compat/profile.h +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef PROFILE_H -#define PROFILE_H - -#include <QFileInfo> -#include <QString> -#include <QStringList> -#include <QMap> - -QT_BEGIN_NAMESPACE - -class DocuParser; - -class Profile -{ -public: - enum ProfileType { DefaultProfile, UserProfile }; - Profile(); - - bool isValid() const; - - void addDCF( const QString &docfile ); - void addDCFIcon( const QString title, const QString &icon ); - void addDCFIndexPage( const QString title, const QString &indexPage ); - void addDCFImageDir( const QString title, const QString &imgDir ); - void addDCFTitle( const QString &dcf, const QString &title ); - void addProperty( const QString &name, const QString &value ); - bool hasDocFile( const QString &docFile ); - void removeDocFileEntry( const QString &title ); - - ProfileType profileType() const { return type; } - void setProfileType( ProfileType t ) { type = t; } - - DocuParser *docuParser() const { return dparser; } - void setDocuParser( DocuParser *dp ) { dparser = dp; } - - static Profile* createDefaultProfile(const QString &docPath = QString()); - static QString makeRelativePath(const QString &base, const QString &path); - static QString storableFilePath(const QString &fileName); - static QString loadableFilePath(const QString &fileName); - - uint valid:1; - ProfileType type; - DocuParser *dparser; - QMap<QString,QString> props; - QMap<QString,QString> icons; - QMap<QString,QString> indexPages; - QMap<QString,QString> imageDirs; - QMap<QString,QString> dcfTitles; - QStringList docs; -}; - -QT_END_NAMESPACE - -#endif // PROFILE_H diff --git a/tools/assistant/compat/tabbedbrowser.cpp b/tools/assistant/compat/tabbedbrowser.cpp deleted file mode 100644 index c3c1572..0000000 --- a/tools/assistant/compat/tabbedbrowser.cpp +++ /dev/null @@ -1,530 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "tabbedbrowser.h" -#include "mainwindow.h" -#include "helpwindow.h" -#include "config.h" - -#include <QStyleOptionTab> -#include <QToolTip> -#include <QFileInfo> -#include <QToolButton> -#include <QPixmap> -#include <QIcon> -#include <QStyle> -#include <QTimer> -#include <QStackedWidget> -#include <QTimer> -#include <QTextBlock> -#include <QKeyEvent> - -QT_BEGIN_NAMESPACE - -#ifdef Q_WS_MAC -const QLatin1String ImageLocation(":trolltech/assistant/images/mac/"); -#else -const QLatin1String ImageLocation(":trolltech/assistant/images/win/"); -#endif - -TabbedBrowser::TabbedBrowser(MainWindow *parent) - : QWidget(parent) -{ - ui.setupUi(this); - init(); - - QStackedWidget *stack = qFindChild<QStackedWidget*>(ui.tab); - Q_ASSERT(stack); - stack->setContentsMargins(0, 0, 0, 0); - connect(stack, SIGNAL(currentChanged(int)), parent, SLOT(browserTabChanged())); - - QPalette p = palette(); - p.setColor(QPalette::Inactive, QPalette::Highlight, - p.color(QPalette::Active, QPalette::Highlight)); - p.setColor(QPalette::Inactive, QPalette::HighlightedText, - p.color(QPalette::Active, QPalette::HighlightedText)); - setPalette(p); -} - -TabbedBrowser::~TabbedBrowser() -{ -} - -MainWindow *TabbedBrowser::mainWindow() const -{ - return static_cast<MainWindow*>(parentWidget()); -} - -void TabbedBrowser::forward() -{ - currentBrowser()->forward(); - emit browserUrlChanged(currentBrowser()->source().toString()); -} - -void TabbedBrowser::backward() -{ - currentBrowser()->backward(); - emit browserUrlChanged(currentBrowser()->source().toString()); -} - -void TabbedBrowser::setSource( const QString &ref ) -{ - HelpWindow * win = currentBrowser(); - win->setSource(ref); -} - -void TabbedBrowser::reload() -{ - currentBrowser()->reload(); -} - -void TabbedBrowser::home() -{ - currentBrowser()->home(); -} - -HelpWindow *TabbedBrowser::currentBrowser() const -{ - return static_cast<HelpWindow*>(ui.tab->currentWidget()); -} - -void TabbedBrowser::nextTab() -{ - if(ui.tab->currentIndex()<=ui.tab->count()-1) - ui.tab->setCurrentIndex(ui.tab->currentIndex()+1); -} - -void TabbedBrowser::previousTab() -{ - int idx = ui.tab->currentIndex()-1; - if(idx>=0) - ui.tab->setCurrentIndex(idx); -} - -HelpWindow *TabbedBrowser::createHelpWindow() -{ - MainWindow *mainWin = mainWindow(); - HelpWindow *win = new HelpWindow(mainWin, 0); - win->setFrameStyle(QFrame::NoFrame); - win->setPalette(palette()); - win->setSearchPaths(Config::configuration()->mimePaths()); - ui.tab->addTab(win, tr("...")); - connect(win, SIGNAL(highlighted(QString)), - (const QObject*) (mainWin->statusBar()), SLOT(showMessage(QString))); - connect(win, SIGNAL(backwardAvailable(bool)), - mainWin, SLOT(backwardAvailable(bool))); - connect(win, SIGNAL(forwardAvailable(bool)), - mainWin, SLOT(forwardAvailable(bool))); - connect(win, SIGNAL(sourceChanged(QUrl)), this, SLOT(sourceChanged())); - - ui.tab->cornerWidget(Qt::TopRightCorner)->setEnabled(ui.tab->count() > 1); - win->installEventFilter(this); - win->viewport()->installEventFilter(this); - ui.editFind->installEventFilter(this); - return win; -} - -HelpWindow *TabbedBrowser::newBackgroundTab() -{ - HelpWindow *win = createHelpWindow(); - emit tabCountChanged(ui.tab->count()); - return win; -} - -void TabbedBrowser::newTab(const QString &lnk) -{ - QString link(lnk); - if(link.isNull()) { - HelpWindow *w = currentBrowser(); - if(w) - link = w->source().toString(); - } - HelpWindow *win = createHelpWindow(); - ui.tab->setCurrentIndex(ui.tab->indexOf(win)); - if(!link.isNull()) { - win->setSource(link); - } - - emit tabCountChanged(ui.tab->count()); -} - -void TabbedBrowser::zoomIn() -{ - currentBrowser()->zoomIn(); - Config::configuration()->setFontPointSize(currentBrowser()->font().pointSizeF()); -} - -void TabbedBrowser::zoomOut() -{ - currentBrowser()->zoomOut(); - Config::configuration()->setFontPointSize(currentBrowser()->font().pointSizeF()); -} - -void TabbedBrowser::init() -{ - - lastCurrentTab = 0; - while(ui.tab->count()) { - QWidget *page = ui.tab->widget(0); - ui.tab->removeTab(0); - delete page; - } - - connect(ui.tab, SIGNAL(currentChanged(int)), - this, SLOT(transferFocus())); - - QTabBar *tabBar = qFindChild<QTabBar*>(ui.tab); - QStyleOptionTab opt; - if (tabBar) { - opt.init(tabBar); - opt.shape = tabBar->shape(); - tabBar->setContextMenuPolicy(Qt::CustomContextMenu); - connect(tabBar, SIGNAL(customContextMenuRequested(QPoint)), SLOT(openTabMenu(QPoint))); - } - - // workaround for sgi style - QPalette pal = palette(); - pal.setColor(QPalette::Active, QPalette::Button, pal.color(QPalette::Active, QPalette::Window)); - pal.setColor(QPalette::Disabled, QPalette::Button, pal.color(QPalette::Disabled, QPalette::Window)); - pal.setColor(QPalette::Inactive, QPalette::Button, pal.color(QPalette::Inactive, QPalette::Window)); - - QToolButton *newTabButton = new QToolButton(this); - ui.tab->setCornerWidget(newTabButton, Qt::TopLeftCorner); - newTabButton->setCursor(Qt::ArrowCursor); - newTabButton->setAutoRaise(true); - newTabButton->setIcon(QIcon(ImageLocation + QLatin1String("addtab.png"))); - QObject::connect(newTabButton, SIGNAL(clicked()), this, SLOT(newTab())); - newTabButton->setToolTip(tr("Add page")); - - QToolButton *closeTabButton = new QToolButton(this); - closeTabButton->setPalette(pal); - ui.tab->setCornerWidget(closeTabButton, Qt::TopRightCorner); - closeTabButton->setCursor(Qt::ArrowCursor); - closeTabButton->setAutoRaise(true); - closeTabButton->setIcon(QIcon(ImageLocation + QLatin1String("closetab.png"))); - QObject::connect(closeTabButton, SIGNAL(clicked()), this, SLOT(closeTab())); - closeTabButton->setToolTip(tr("Close page")); - closeTabButton->setEnabled(false); - - QObject::connect(ui.toolClose, SIGNAL(clicked()), ui.frameFind, SLOT(hide())); - QObject::connect(ui.toolPrevious, SIGNAL(clicked()), this, SLOT(findPrevious())); - QObject::connect(ui.toolNext, SIGNAL(clicked()), this, SLOT(findNext())); - QObject::connect(ui.editFind, SIGNAL(returnPressed()), this, SLOT(findNext())); - QObject::connect(ui.editFind, SIGNAL(textEdited(QString)), - this, SLOT(find(QString))); - ui.frameFind->setVisible(false); - ui.labelWrapped->setVisible(false); - autoHideTimer = new QTimer(this); - autoHideTimer->setInterval(5000); - autoHideTimer->setSingleShot(true); - QObject::connect(autoHideTimer, SIGNAL(timeout()), ui.frameFind, SLOT(hide())); -} - -void TabbedBrowser::updateTitle(const QString &title) -{ - ui.tab->setTabText(ui.tab->indexOf(currentBrowser()), title.trimmed()); -} - -void TabbedBrowser::newTab() -{ - newTab(QString()); -} - -void TabbedBrowser::transferFocus() -{ - if(currentBrowser()) { - currentBrowser()->setFocus(); - } - mainWindow()->setWindowTitle(Config::configuration()->title() - + QLatin1String(" - ") - + currentBrowser()->documentTitle()); -} - -void TabbedBrowser::initHelpWindow(HelpWindow * /*win*/) -{ -} - -void TabbedBrowser::setup() -{ - newTab(QString()); -} - -void TabbedBrowser::copy() -{ - currentBrowser()->copy(); -} - -void TabbedBrowser::closeTab() -{ - if(ui.tab->count()==1) - return; - HelpWindow *win = currentBrowser(); - mainWindow()->removePendingBrowser(win); - ui.tab->removeTab(ui.tab->indexOf(win)); - QTimer::singleShot(0, win, SLOT(deleteLater())); - ui.tab->cornerWidget(Qt::TopRightCorner)->setEnabled(ui.tab->count() > 1); - emit tabCountChanged(ui.tab->count()); -} - -QStringList TabbedBrowser::sources() const -{ - QStringList lst; - int cnt = ui.tab->count(); - for(int i=0; i<cnt; i++) { - lst.append(((QTextBrowser*) ui.tab->widget(i))->source().toString()); - } - return lst; -} - -QList<HelpWindow*> TabbedBrowser::browsers() const -{ - QList<HelpWindow*> list; - for (int i=0; i<ui.tab->count(); ++i) { - Q_ASSERT(qobject_cast<HelpWindow*>(ui.tab->widget(i))); - list.append(static_cast<HelpWindow*>(ui.tab->widget(i))); - } - return list; -} - -void TabbedBrowser::sourceChanged() -{ - HelpWindow *win = qobject_cast<HelpWindow *>(QObject::sender()); - Q_ASSERT(win); - QString docTitle(win->documentTitle()); - if (docTitle.isEmpty()) - docTitle = QLatin1String("..."); - // Make the classname in the title a bit more visible (otherwise - // we just see the "Qt 4.0 : Q..." which isn't really helpful ;-) - QString qtTitle = QLatin1String("Qt ") + QString::number( (QT_VERSION >> 16) & 0xff ) - + QLatin1String(".") + QString::number( (QT_VERSION >> 8) & 0xff ) - + QLatin1String(": "); - if (docTitle.startsWith(qtTitle)) - docTitle = docTitle.mid(qtTitle.length()); - setTitle(win, docTitle); - ui.frameFind->hide(); - ui.labelWrapped->hide(); - win->setTextCursor(win->cursorForPosition(QPoint(0, 0))); -} - -void TabbedBrowser::setTitle(HelpWindow *win, const QString &title) -{ - const QString tt = title.trimmed(); - ui.tab->setTabText(ui.tab->indexOf(win), tt); - if (win == currentBrowser()) - mainWindow()->setWindowTitle(Config::configuration()->title() + QLatin1String(" - ") + tt); -} - -void TabbedBrowser::keyPressEvent(QKeyEvent *e) -{ - int key = e->key(); - QString ttf = ui.editFind->text(); - QString text = e->text(); - - if (ui.frameFind->isVisible()) { - switch (key) { - case Qt::Key_Escape: - ui.frameFind->hide(); - ui.labelWrapped->hide(); - return; - case Qt::Key_Backspace: - ttf.chop(1); - break; - case Qt::Key_Return: - case Qt::Key_Enter: - // Return/Enter key events are not accepted by QLineEdit - return; - default: - if (text.isEmpty()) { - QWidget::keyPressEvent(e); - return; - } - ttf += text; - } - } else { - if (text.isEmpty() || text[0].isSpace() || !text[0].isPrint()) { - QWidget::keyPressEvent(e); - return; - } - if (text.startsWith(QLatin1Char('/'))) { - ui.editFind->clear(); - find(); - return; - } - ttf = text; - ui.frameFind->show(); - } - - ui.editFind->setText(ttf); - find(ttf, false, false); -} - -void TabbedBrowser::findNext() -{ - find(ui.editFind->text(), true, false); -} - -void TabbedBrowser::findPrevious() -{ - find(ui.editFind->text(), false, true); -} - -void TabbedBrowser::find() -{ - ui.frameFind->show(); - ui.editFind->setFocus(Qt::ShortcutFocusReason); - ui.editFind->selectAll(); - autoHideTimer->stop(); -} - -void TabbedBrowser::find(QString ttf, bool forward, bool backward) -{ - HelpWindow *browser = currentBrowser(); - QTextDocument *doc = browser->document(); - QString oldText = ui.editFind->text(); - QTextCursor c = browser->textCursor(); - QTextDocument::FindFlags options; - QPalette p = ui.editFind->palette(); - p.setColor(QPalette::Active, QPalette::Base, Qt::white); - - if (c.hasSelection()) - c.setPosition(forward ? c.position() : c.anchor(), QTextCursor::MoveAnchor); - - QTextCursor newCursor = c; - - if (!ttf.isEmpty()) { - if (backward) - options |= QTextDocument::FindBackward; - - if (ui.checkCase->isChecked()) - options |= QTextDocument::FindCaseSensitively; - - if (ui.checkWholeWords->isChecked()) - options |= QTextDocument::FindWholeWords; - - newCursor = doc->find(ttf, c, options); - ui.labelWrapped->hide(); - - if (newCursor.isNull()) { - QTextCursor ac(doc); - ac.movePosition(options & QTextDocument::FindBackward - ? QTextCursor::End : QTextCursor::Start); - newCursor = doc->find(ttf, ac, options); - if (newCursor.isNull()) { - p.setColor(QPalette::Active, QPalette::Base, QColor(255, 102, 102)); - newCursor = c; - } else - ui.labelWrapped->show(); - } - } - - if (!ui.frameFind->isVisible()) - ui.frameFind->show(); - browser->setTextCursor(newCursor); - ui.editFind->setPalette(p); - if (!ui.editFind->hasFocus()) - autoHideTimer->start(); -} - -bool TabbedBrowser::eventFilter(QObject *o, QEvent *e) -{ - if (o == ui.editFind) { - if (e->type() == QEvent::FocusIn && autoHideTimer->isActive()) - autoHideTimer->stop(); - } else if (e->type() == QEvent::KeyPress && ui.frameFind->isVisible()) { // assume textbrowser - QKeyEvent *ke = static_cast<QKeyEvent *>(e); - if (ke->key() == Qt::Key_Space) { - keyPressEvent(ke); - return true; - } - } - - return QWidget::eventFilter(o, e); -} - -void TabbedBrowser::openTabMenu(const QPoint& pos) -{ - QTabBar *tabBar = qFindChild<QTabBar*>(ui.tab); - - QMenu m(QLatin1String(""), tabBar); - QAction *new_action = m.addAction(tr("New Tab")); - QAction *close_action = m.addAction(tr("Close Tab")); - QAction *close_others_action = m.addAction(tr("Close Other Tabs")); - - if (tabBar->count() == 1) { - close_action->setEnabled(false); - close_others_action->setEnabled(false); - } - - QAction *action_picked = m.exec(tabBar->mapToGlobal(pos)); - if (!action_picked) - return; - - if (action_picked == new_action) { - newTab(); - return; - } - - QList<HelpWindow*> windowList = browsers(); - for (int i = 0; i < tabBar->count(); ++i) { - if (tabBar->tabRect(i).contains(pos)) { - HelpWindow *win = static_cast<HelpWindow*>(ui.tab->widget(i)); - if (action_picked == close_action) { - mainWindow()->removePendingBrowser(win); - QTimer::singleShot(0, win, SLOT(deleteLater())); - } - windowList.removeOne(win); - break; - } - } - - if (action_picked == close_others_action) { - foreach (HelpWindow* win, windowList) { - mainWindow()->removePendingBrowser(win); - QTimer::singleShot(0, win, SLOT(deleteLater())); - windowList.removeOne(win); - } - } - - ui.tab->cornerWidget(Qt::TopRightCorner)->setEnabled(windowList.count() > 1); - emit tabCountChanged(windowList.count()); -} - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/tabbedbrowser.h b/tools/assistant/compat/tabbedbrowser.h deleted file mode 100644 index 0e32505..0000000 --- a/tools/assistant/compat/tabbedbrowser.h +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef TABBEDBROWSER_H -#define TABBEDBROWSER_H - -#include "ui_tabbedbrowser.h" - -QT_BEGIN_NAMESPACE - -class MainWindow; -class HelpWindow; -class QStyleSheet; -class QMimeSourceFactory; -class QTimer; - -class TabbedBrowser : public QWidget -{ - Q_OBJECT -public: - TabbedBrowser(MainWindow *parent); - virtual ~TabbedBrowser(); - - MainWindow *mainWindow() const; - HelpWindow *currentBrowser() const; - QStringList sources() const; - QList<HelpWindow*> browsers() const; - - HelpWindow* newBackgroundTab(); - HelpWindow* createHelpWindow(); - - void setTitle(HelpWindow*, const QString &); - -signals: - void tabCountChanged(int count); - void browserUrlChanged(const QString &link); - -protected: - void keyPressEvent(QKeyEvent *); - bool eventFilter(QObject *o, QEvent *e); - -public slots: - void init(); - void forward(); - void backward(); - void setSource(const QString &ref); - void reload(); - void home(); - void nextTab(); - void previousTab(); - void newTab(const QString &lnk); - void zoomIn(); - void zoomOut(); - void updateTitle(const QString &title); - void newTab(); - void transferFocus(); - void initHelpWindow(HelpWindow *win); - void setup(); - void copy(); - void closeTab(); - void sourceChanged(); - - void find(); - void findNext(); - void findPrevious(); - -private slots: - void find(QString, bool forward = false, bool backward = false); - void openTabMenu(const QPoint& pos); - -private: - Ui::TabbedBrowser ui; - QWidget *lastCurrentTab; - QFont tabFont; - - QString fixedFontFam; - QColor lnkColor; - bool underlineLnk; - QTimer *autoHideTimer; -}; - -QT_END_NAMESPACE - -#endif // TABBEDBROWSER_H diff --git a/tools/assistant/compat/tabbedbrowser.ui b/tools/assistant/compat/tabbedbrowser.ui deleted file mode 100644 index 411f145..0000000 --- a/tools/assistant/compat/tabbedbrowser.ui +++ /dev/null @@ -1,233 +0,0 @@ -<ui version="4.0" > - <author></author> - <comment>********************************************************************* -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -*********************************************************************</comment> - <exportmacro></exportmacro> - <class>TabbedBrowser</class> - <widget class="QWidget" name="TabbedBrowser" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>710</width> - <height>664</height> - </rect> - </property> - <property name="windowTitle" > - <string>TabbedBrowser</string> - </property> - <layout class="QVBoxLayout" > - <property name="margin" > - <number>0</number> - </property> - <property name="spacing" > - <number>0</number> - </property> - <item> - <widget class="QTabWidget" name="tab" > - <widget class="QWidget" name="frontpage" > - <attribute name="title" > - <string>Untitled</string> - </attribute> - <layout class="QGridLayout" > - <property name="margin" > - <number>8</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - </layout> - </widget> - </widget> - </item> - <item> - <widget class="QFrame" name="frameFind" > - <property name="frameShape" > - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow" > - <enum>QFrame::Raised</enum> - </property> - <layout class="QHBoxLayout" > - <property name="margin" > - <number>0</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <widget class="QToolButton" name="toolClose" > - <property name="text" > - <string/> - </property> - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/close.png</iconset> - </property> - <property name="autoRaise" > - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="editFind" > - <property name="sizePolicy" > - <sizepolicy> - <hsizetype>0</hsizetype> - <vsizetype>0</vsizetype> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize" > - <size> - <width>150</width> - <height>0</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="toolPrevious" > - <property name="text" > - <string>Previous</string> - </property> - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/win/previous.png</iconset> - </property> - <property name="toolButtonStyle" > - <enum>Qt::ToolButtonTextBesideIcon</enum> - </property> - <property name="autoRaise" > - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="toolNext" > - <property name="minimumSize" > - <size> - <width>0</width> - <height>0</height> - </size> - </property> - <property name="text" > - <string>Next</string> - </property> - <property name="icon" > - <iconset resource="assistant.qrc" >:/trolltech/assistant/images/win/next.png</iconset> - </property> - <property name="toolButtonStyle" > - <enum>Qt::ToolButtonTextBesideIcon</enum> - </property> - <property name="autoRaise" > - <bool>true</bool> - </property> - <property name="arrowType" > - <enum>Qt::NoArrow</enum> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="checkCase" > - <property name="text" > - <string>Case Sensitive</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="checkWholeWords" > - <property name="text" > - <string>Whole words</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="labelWrapped" > - <property name="minimumSize" > - <size> - <width>0</width> - <height>20</height> - </size> - </property> - <property name="maximumSize" > - <size> - <width>105</width> - <height>20</height> - </size> - </property> - <property name="text" > - <string><img src=":/trolltech/assistant/images/wrap.png">&nbsp;Search wrapped</string> - </property> - <property name="textFormat" > - <enum>Qt::RichText</enum> - </property> - <property name="scaledContents" > - <bool>true</bool> - </property> - <property name="alignment" > - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item> - <spacer> - <property name="orientation" > - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" > - <size> - <width>81</width> - <height>21</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <pixmapfunction></pixmapfunction> - <resources> - <include location="assistant.qrc" /> - </resources> - <connections/> -</ui> diff --git a/tools/assistant/compat/topicchooser.cpp b/tools/assistant/compat/topicchooser.cpp deleted file mode 100644 index b2e7e98..0000000 --- a/tools/assistant/compat/topicchooser.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "topicchooser.h" - -#include <QLabel> -#include <QListWidget> -#include <QPushButton> - -QT_BEGIN_NAMESPACE - -TopicChooser::TopicChooser(QWidget *parent, const QStringList &lnkNames, - const QStringList &lnks, const QString &title) - : QDialog(parent), links(lnks), linkNames(lnkNames) -{ - ui.setupUi(this); - - ui.label->setText(tr("Choose a topic for <b>%1</b>").arg(title)); - ui.listbox->addItems(linkNames); - if (ui.listbox->count() != 0) - ui.listbox->setCurrentRow(0); - ui.listbox->setFocus(); -} - -QString TopicChooser::link() const -{ - if (ui.listbox->currentRow() == -1) - return QString(); - QString s = ui.listbox->item(ui.listbox->currentRow())->text(); - if (s.isEmpty()) - return s; - int i = linkNames.indexOf(s); - return links[i]; -} - -QString TopicChooser::getLink(QWidget *parent, const QStringList &lnkNames, - const QStringList &lnks, const QString &title) -{ - TopicChooser *dlg = new TopicChooser(parent, lnkNames, lnks, title); - QString lnk; - if (dlg->exec() == QDialog::Accepted) - lnk = dlg->link(); - delete dlg; - return lnk; -} - -void TopicChooser::on_buttonDisplay_clicked() -{ - accept(); -} - -void TopicChooser::on_buttonCancel_clicked() -{ - reject(); -} - -void TopicChooser::on_listbox_itemActivated(QListWidgetItem *item) -{ - Q_UNUSED(item); - accept(); -} - -QT_END_NAMESPACE diff --git a/tools/assistant/compat/topicchooser.ui b/tools/assistant/compat/topicchooser.ui deleted file mode 100644 index 18ff61b..0000000 --- a/tools/assistant/compat/topicchooser.ui +++ /dev/null @@ -1,162 +0,0 @@ -<ui version="4.0" > - <comment>********************************************************************* -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -*********************************************************************</comment> - <class>TopicChooser</class> - <widget class="QDialog" name="TopicChooser" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>391</width> - <height>223</height> - </rect> - </property> - <property name="windowTitle" > - <string>Choose Topic</string> - </property> - <property name="whatsThis" > - <string>Select a topic from the list and click the <b>Display</b>-button to open the online help.</string> - </property> - <property name="sizeGripEnabled" > - <bool>true</bool> - </property> - <layout class="QVBoxLayout" > - <property name="spacing" > - <number>6</number> - </property> - <property name="leftMargin" > - <number>11</number> - </property> - <property name="topMargin" > - <number>11</number> - </property> - <property name="rightMargin" > - <number>11</number> - </property> - <property name="bottomMargin" > - <number>11</number> - </property> - <item> - <widget class="QLabel" name="label" > - <property name="text" > - <string>&Topics</string> - </property> - <property name="buddy" > - <cstring>listbox</cstring> - </property> - </widget> - </item> - <item> - <widget class="QListWidget" name="listbox" > - <property name="whatsThis" > - <string>Displays a list of available help topics for the keyword.</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" > - <property name="spacing" > - <number>6</number> - </property> - <property name="leftMargin" > - <number>0</number> - </property> - <property name="topMargin" > - <number>0</number> - </property> - <property name="rightMargin" > - <number>0</number> - </property> - <property name="bottomMargin" > - <number>0</number> - </property> - <item> - <spacer> - <property name="orientation" > - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType" > - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" > - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="buttonDisplay" > - <property name="whatsThis" > - <string>Open the topic selected in the list.</string> - </property> - <property name="text" > - <string>&Display</string> - </property> - <property name="autoDefault" > - <bool>true</bool> - </property> - <property name="default" > - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="buttonCancel" > - <property name="whatsThis" > - <string>Close the Dialog.</string> - </property> - <property name="text" > - <string>&Close</string> - </property> - <property name="autoDefault" > - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/tools/assistant/lib/fulltextsearch/qclucene-config_p.h b/tools/assistant/lib/fulltextsearch/qclucene-config_p.h index 0c70718..387d64d 100644 --- a/tools/assistant/lib/fulltextsearch/qclucene-config_p.h +++ b/tools/assistant/lib/fulltextsearch/qclucene-config_p.h @@ -314,14 +314,12 @@ configure. #define _CL_HAVE_SYS_TYPES_H 1 #endif -// Do not use the tchar.h that ships with mingw, this causes the qt build to -// fail (211547, 211401, etc...), reuse the replacement as with any other compiler -// #if defined(__MINGW32__) -// /* Define to 1 if you have the <tchar.h> header file. */ -// # ifndef _CL_HAVE_TCHAR_H -// # define _CL_HAVE_TCHAR_H 1 -// # endif -// #endif +#if defined(__MINGW32__) + /* Define to 1 if you have the <tchar.h> header file. */ + # ifndef _CL_HAVE_TCHAR_H + # define _CL_HAVE_TCHAR_H 1 + # endif +#endif #if defined(__MINGW32__) || defined(__SUNPRO_CC) || defined(__SUNPRO_C) /* Define to 1 if you have the `tell' function. */ diff --git a/tools/assistant/lib/fulltextsearch/qclucene_global_p.h b/tools/assistant/lib/fulltextsearch/qclucene_global_p.h index f4b744d..206725b 100644 --- a/tools/assistant/lib/fulltextsearch/qclucene_global_p.h +++ b/tools/assistant/lib/fulltextsearch/qclucene_global_p.h @@ -36,7 +36,7 @@ #include <QtCore/QChar> #include <QtCore/QString> -#if !defined(_MSC_VER) && defined(_CL_HAVE_WCHAR_H) && defined(_CL_HAVE_WCHAR_T) +#if !defined(_MSC_VER) && !defined(__MINGW32__) && defined(_CL_HAVE_WCHAR_H) && defined(_CL_HAVE_WCHAR_T) # if !defined(TCHAR) # define TCHAR wchar_t # endif diff --git a/tools/assistant/lib/lib.pro b/tools/assistant/lib/lib.pro index 51933de..26d3456 100644 --- a/tools/assistant/lib/lib.pro +++ b/tools/assistant/lib/lib.pro @@ -23,7 +23,6 @@ unix:QMAKE_PKGCONFIG_REQUIRES += QtNetwork \ QtSql \ QtXml LIBS_PRIVATE += -l$$qclucene - RESOURCES += helpsystem.qrc SOURCES += qhelpenginecore.cpp \ qhelpengine.cpp \ @@ -41,6 +40,7 @@ SOURCES += qhelpenginecore.cpp \ qhelpsearchindexwriter_default.cpp \ qhelpsearchindexreader_default.cpp \ qhelpsearchindexreader.cpp \ + qclucenefieldnames.cpp \ qhelp_global.cpp # access to clucene @@ -63,7 +63,8 @@ HEADERS += qhelpenginecore.h \ qhelpsearchindex_default_p.h \ qhelpsearchindexwriter_default_p.h \ qhelpsearchindexreader_default_p.h \ - qhelpsearchindexreader_p.h + qhelpsearchindexreader_p.h \ + qclucenefieldnames_p.h # access to clucene HEADERS += qhelpsearchindexwriter_clucene_p.h \ diff --git a/tools/assistant/compat/topicchooser.h b/tools/assistant/lib/qclucenefieldnames.cpp index fef57df..5c3a474 100644 --- a/tools/assistant/compat/topicchooser.h +++ b/tools/assistant/lib/qclucenefieldnames.cpp @@ -39,39 +39,19 @@ ** ****************************************************************************/ -#ifndef TOPICCHOOSER_H -#define TOPICCHOOSER_H - -#include "ui_topicchooser.h" - -#include <QDialog> -#include <QStringList> +#include "qclucenefieldnames_p.h" QT_BEGIN_NAMESPACE -class TopicChooser : public QDialog -{ - Q_OBJECT -public: - TopicChooser(QWidget *parent, const QStringList &lnkNames, - const QStringList &lnks, const QString &title); - - QString link() const; - - static QString getLink(QWidget *parent, const QStringList &lnkNames, - const QStringList &lnks, const QString &title); - -private slots: - void on_buttonDisplay_clicked(); - void on_buttonCancel_clicked(); - void on_listbox_itemActivated(QListWidgetItem *item); - -private: - Ui::TopicChooser ui; - QString theLink; - QStringList links, linkNames; -}; - -#endif // TOPICCHOOSER_H +namespace fulltextsearch { +namespace clucene { +const QString AttributeField(QLatin1String("attribute")); +const QString ContentField(QLatin1String("content")); +const QString NamespaceField(QLatin1String("namespace")); +const QString PathField(QLatin1String("path")); +const QString TitleField(QLatin1String("title")); +const QString TitleTokenizedField(QLatin1String("titleTokenized")); +} // namespace clucene +} // namespace fulltextsearch QT_END_NAMESPACE diff --git a/tools/assistant/compat/fontsettingsdialog.h b/tools/assistant/lib/qclucenefieldnames_p.h index 6599d2a..a611382 100644 --- a/tools/assistant/compat/fontsettingsdialog.h +++ b/tools/assistant/lib/qclucenefieldnames_p.h @@ -39,39 +39,25 @@ ** ****************************************************************************/ -#ifndef _FONT_SETTINGS_DIALOG_H_ -#define _FONT_SETTINGS_DIALOG_H_ +#ifndef QCLUCENEFIELDNAMES_P_H +#define QCLUCENEFIELDNAMES_P_H -#include <QtCore/QObject> -#include <QtGui/QDialog> +#include <QtCore/QtGlobal> +#include <QtCore/QString> QT_BEGIN_NAMESPACE -class FontPanel; -struct FontSettings; -class QDialogButtonBox; - -class FontSettingsDialog : public QDialog -{ - Q_OBJECT - -public: - FontSettingsDialog(QWidget *parent = 0); - ~FontSettingsDialog(); - - bool showDialog(FontSettings *settings); - -private: - void updateFontSettings(FontSettings *settings); - void setupFontSettingsDialog(const FontSettings *settings); - -private: - FontPanel *m_windowFontPanel; - FontPanel *m_browserFontPanel; - QDialogButtonBox *m_dialogButtonBox; -}; - -#endif // _FONT_SETTINGS_DIALOG_H_ - +namespace fulltextsearch { +namespace clucene { + extern const QString AttributeField; + extern const QString ContentField; + extern const QString NamespaceField; + extern const QString PathField; + extern const QString TitleField; + extern const QString TitleTokenizedField; +} // namespace clucene +} // namespace fulltextsearch QT_END_NAMESPACE + +#endif // QCLUCENEFIELDNAMES_P_H diff --git a/tools/assistant/lib/qhelp_global.cpp b/tools/assistant/lib/qhelp_global.cpp index 539b504..c2c916b 100644 --- a/tools/assistant/lib/qhelp_global.cpp +++ b/tools/assistant/lib/qhelp_global.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#include <QtCore/QCoreApplication> #include <QtCore/QRegExp> #include <QtCore/QMutexLocker> #include <QtGui/QTextDocument> @@ -55,12 +56,12 @@ QString QHelpGlobal::uniquifyConnectionName(const QString &name, void *pointer) counter = 0; return QString::fromLatin1("%1-%2-%3"). - arg(name).arg(long(pointer)).arg(counter); + arg(name).arg(quintptr(pointer)).arg(counter); } QString QHelpGlobal::documentTitle(const QString &content) { - QString title = QObject::tr("Untitled"); + QString title = QCoreApplication::translate("QHelp", "Untitled"); if (!content.isEmpty()) { int start = content.indexOf(QLatin1String("<title>"), 0, Qt::CaseInsensitive) + 7; int end = content.indexOf(QLatin1String("</title>"), 0, Qt::CaseInsensitive); @@ -86,17 +87,18 @@ QString QHelpGlobal::codecFromData(const QByteArray &data) QString QHelpGlobal::codecFromHtmlData(const QByteArray &data) { - QString content = QString::fromUtf8(data.constData(), data.size()); - int start = content.indexOf(QLatin1String("<meta"), 0, Qt::CaseInsensitive); + QString head = QString::fromUtf8(data.constData(), qMin(1000, data.size())); + int start = head.indexOf(QLatin1String("<meta"), 0, Qt::CaseInsensitive); if (start > 0) { - int end; QRegExp r(QLatin1String("charset=([^\"\\s]+)")); while (start != -1) { - end = content.indexOf(QLatin1Char('>'), start) + 1; - const QString &meta = content.mid(start, end - start).toLower(); + const int end = head.indexOf(QLatin1Char('>'), start) + 1; + if (end <= start) + break; + const QString &meta = head.mid(start, end - start).toLower(); if (r.indexIn(meta) != -1) return r.cap(1); - start = content.indexOf(QLatin1String("<meta"), end, + start = head.indexOf(QLatin1String("<meta"), end, Qt::CaseInsensitive); } } @@ -105,8 +107,8 @@ QString QHelpGlobal::codecFromHtmlData(const QByteArray &data) QString QHelpGlobal::codecFromXmlData(const QByteArray &data) { - QString content = QString::fromUtf8(data.constData(), data.size()); + QString head = QString::fromUtf8(data.constData(), qMin(1000, data.size())); const QRegExp encodingExp(QLatin1String("^\\s*<\\?xml version=" "\"\\d\\.\\d\" encoding=\"([^\"]+)\"\\?>.*")); - return encodingExp.exactMatch(content) ? encodingExp.cap(1) : QString(); + return encodingExp.exactMatch(head) ? encodingExp.cap(1) : QString(); } diff --git a/tools/assistant/lib/qhelpcollectionhandler.cpp b/tools/assistant/lib/qhelpcollectionhandler.cpp index cb7e457..bd8dc20 100644 --- a/tools/assistant/lib/qhelpcollectionhandler.cpp +++ b/tools/assistant/lib/qhelpcollectionhandler.cpp @@ -114,6 +114,9 @@ bool QHelpCollectionHandler::openCollectionFile() return false; } + m_query.exec(QLatin1String("PRAGMA synchronous=OFF")); + m_query.exec(QLatin1String("PRAGMA cache_size=3000")); + m_query.exec(QLatin1String("SELECT COUNT(*) FROM sqlite_master WHERE TYPE=\'table\'" "AND Name=\'NamespaceTable\'")); m_query.next(); @@ -163,6 +166,9 @@ bool QHelpCollectionHandler::copyCollectionFile(const QString &fileName) return false; } + copyQuery->exec(QLatin1String("PRAGMA synchronous=OFF")); + copyQuery->exec(QLatin1String("PRAGMA cache_size=3000")); + if (!createTables(copyQuery)) { emit error(tr("Cannot copy collection file: %1").arg(colFile)); return false; @@ -308,10 +314,8 @@ bool QHelpCollectionHandler::addCustomFilter(const QString &filterName, m_query.prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?")); m_query.bindValue(0, filterName); m_query.exec(); - while (m_query.next()) { + if (m_query.next()) nameId = m_query.value(0).toInt(); - break; - } m_query.exec(QLatin1String("SELECT Id, Name FROM FilterAttributeTable")); QStringList idsToInsert = attributes; @@ -584,6 +588,8 @@ void QHelpCollectionHandler::optimizeDatabase(const QString &fileName) } QSqlQuery query(db); + db.exec(QLatin1String("PRAGMA synchronous=OFF")); + db.exec(QLatin1String("PRAGMA cache_size=3000")); db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS NameIndex ON IndexTable(Name)")); db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS FileNameIndex ON FileNameTable(Name)")); db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS FileIdIndex ON FileNameTable(FileId)")); diff --git a/tools/assistant/lib/qhelpcontentwidget.cpp b/tools/assistant/lib/qhelpcontentwidget.cpp index a80dc39..6f3f942 100644 --- a/tools/assistant/lib/qhelpcontentwidget.cpp +++ b/tools/assistant/lib/qhelpcontentwidget.cpp @@ -370,7 +370,8 @@ void QHelpContentModel::invalidateContents(bool onShutDown) delete d->rootItem; d->rootItem = 0; } - reset(); + if (!onShutDown) + reset(); } /*! diff --git a/tools/assistant/lib/qhelpdbreader.cpp b/tools/assistant/lib/qhelpdbreader.cpp index 6dd949a..5c0f595 100644 --- a/tools/assistant/lib/qhelpdbreader.cpp +++ b/tools/assistant/lib/qhelpdbreader.cpp @@ -205,7 +205,7 @@ QByteArray QHelpDBReader::fileData(const QString &virtualFolder, "NamespaceTable d WHERE a.Id=b.FileId AND (b.Name=? OR b.Name=?) AND b.FolderId=c.Id " "AND c.Name=? AND c.NamespaceId=d.Id AND d.Name=?")); m_query->bindValue(0, filePath); - m_query->bindValue(1, QLatin1String("./") + filePath); + m_query->bindValue(1, QString(QLatin1String("./") + filePath)); m_query->bindValue(2, virtualFolder); m_query->bindValue(3, m_namespace); m_query->exec(); diff --git a/tools/assistant/lib/qhelpengine.cpp b/tools/assistant/lib/qhelpengine.cpp index 96cf0fd..e8ae31b 100644 --- a/tools/assistant/lib/qhelpengine.cpp +++ b/tools/assistant/lib/qhelpengine.cpp @@ -75,14 +75,15 @@ void QHelpEnginePrivate::init(const QString &collectionFile, { QHelpEngineCorePrivate::init(collectionFile, helpEngineCore); - contentModel = new QHelpContentModel(this); - indexModel = new QHelpIndexModel(this); - - connect(helpEngineCore, SIGNAL(setupFinished()), - this, SLOT(applyCurrentFilter())); - connect(helpEngineCore, SIGNAL(currentFilterChanged(QString)), - this, SLOT(applyCurrentFilter())); - + if (!contentModel) + contentModel = new QHelpContentModel(this); + if (!indexModel) + indexModel = new QHelpIndexModel(this); + + connect(helpEngineCore, SIGNAL(setupFinished()), this, + SLOT(applyCurrentFilter())); + connect(helpEngineCore, SIGNAL(currentFilterChanged(QString)), this, + SLOT(applyCurrentFilter())); } void QHelpEnginePrivate::applyCurrentFilter() diff --git a/tools/assistant/lib/qhelpenginecore.cpp b/tools/assistant/lib/qhelpenginecore.cpp index 066e4d5..71306af 100644 --- a/tools/assistant/lib/qhelpenginecore.cpp +++ b/tools/assistant/lib/qhelpenginecore.cpp @@ -119,7 +119,7 @@ bool QHelpEngineCorePrivate::setup() QHelpDBReader *reader = new QHelpDBReader(absFileName, QHelpGlobal::uniquifyConnectionName(info.fileName, this), this); if (!reader->init()) { - emit q->warning(tr("Cannot open documentation file %1: %2!") + emit q->warning(QHelpEngineCore::tr("Cannot open documentation file %1: %2!") .arg(absFileName, reader->errorMessage())); continue; } @@ -406,8 +406,9 @@ QStringList QHelpEngineCore::customFilters() const /*! Adds the new custom filter \a filterName. The filter attributes - are specified by \a attributes. The function returns false if - the filter can not be added, e.g. when the filter already exists. + are specified by \a attributes. If the filter already exists, + its attribute set is replaced. The function returns true if + the operation succeeded, otherwise it returns false. \sa customFilters(), removeCustomFilter() */ diff --git a/tools/assistant/lib/qhelpgenerator.cpp b/tools/assistant/lib/qhelpgenerator.cpp index 4b94ebf..85bdd75 100644 --- a/tools/assistant/lib/qhelpgenerator.cpp +++ b/tools/assistant/lib/qhelpgenerator.cpp @@ -47,6 +47,7 @@ #include <QtCore/QFileInfo> #include <QtCore/QDir> #include <QtCore/QDebug> +#include <QtCore/QSet> #include <QtCore/QVariant> #include <QtCore/QDateTime> #include <QtCore/QTextCodec> @@ -190,6 +191,9 @@ bool QHelpGenerator::generate(QHelpDataInterface *helpData, return false; } + d->query->exec(QLatin1String("PRAGMA synchronous=OFF")); + d->query->exec(QLatin1String("PRAGMA cache_size=3000")); + addProgress(1.0); createTables(); insertFileNotFoundFile(); @@ -537,7 +541,8 @@ bool QHelpGenerator::insertFiles(const QStringList &files, const QString &rootPa } int fileId = -1; - if (!d->fileMap.contains(fileName)) { + QMap<QString, int>::Iterator fileMapIt = d->fileMap.find(fileName); + if (fileMapIt == d->fileMap.end()) { fileDataList.append(qCompress(data)); fileNameData.name = fileName; @@ -551,18 +556,20 @@ bool QHelpGenerator::insertFiles(const QStringList &files, const QString &rootPa ++tableFileId; } else { - fileId = d->fileMap.value(fileName); + fileId = fileMapIt.value(); + QSet<int> &fileFilterSet = d->fileFilterMap[fileId]; + QSet<int> &tmpFileFilterSet = tmpFileFilterMap[fileId]; foreach (const int &filter, filterAtts) { - if (!d->fileFilterMap.value(fileId).contains(filter) - && !tmpFileFilterMap.value(fileId).contains(filter)) { - d->fileFilterMap[fileId].insert(filter); - tmpFileFilterMap[fileId].insert(filter); + if (!fileFilterSet.contains(filter) + && !tmpFileFilterSet.contains(filter)) { + fileFilterSet.insert(filter); + tmpFileFilterSet.insert(filter); } } } } - if (tmpFileFilterMap.count()) { + if (!tmpFileFilterMap.isEmpty()) { d->query->exec(QLatin1String("BEGIN")); QMap<int, QSet<int> >::const_iterator it = tmpFileFilterMap.constBegin(); while (it != tmpFileFilterMap.constEnd()) { @@ -625,8 +632,7 @@ bool QHelpGenerator::registerCustomFilter(const QString &filterName, while (d->query->next()) { attributeMap.insert(d->query->value(1).toString(), d->query->value(0).toInt()); - if (idsToInsert.contains(d->query->value(1).toString())) - idsToInsert.removeAll(d->query->value(1).toString()); + idsToInsert.removeAll(d->query->value(1).toString()); } foreach (const QString &id, idsToInsert) { @@ -674,7 +680,7 @@ bool QHelpGenerator::registerCustomFilter(const QString &filterName, return true; } -bool QHelpGenerator::insertKeywords(const QList<QHelpDataIndexItem> keywords, +bool QHelpGenerator::insertKeywords(const QList<QHelpDataIndexItem> &keywords, const QStringList &filterAttributes) { if (!d->query) @@ -704,7 +710,17 @@ bool QHelpGenerator::insertKeywords(const QList<QHelpDataIndexItem> keywords, int i = 0; d->query->exec(QLatin1String("BEGIN")); + QSet<QString> indices; foreach (const QHelpDataIndexItem &itm, keywords) { + + /* + * Identical ids make no sense and just confuse the Assistant user, + * so we ignore all repetitions. + */ + if (indices.contains(itm.identifier)) + continue; + indices.insert(itm.identifier); + pos = itm.reference.indexOf(QLatin1Char('#')); fileName = itm.reference.left(pos); if (pos > -1) @@ -716,8 +732,9 @@ bool QHelpGenerator::insertKeywords(const QList<QHelpDataIndexItem> keywords, if (fName.startsWith(QLatin1String("./"))) fName = fName.mid(2); - if (d->fileMap.contains(fName)) - fileId = d->fileMap.value(fName); + QMap<QString, int>::ConstIterator it = d->fileMap.find(fName); + if (it != d->fileMap.end()) + fileId = it.value(); else fileId = 1; @@ -749,7 +766,7 @@ bool QHelpGenerator::insertKeywords(const QList<QHelpDataIndexItem> keywords, d->query->exec(QLatin1String("COMMIT")); d->query->exec(QLatin1String("SELECT COUNT(Id) FROM IndexTable")); - if (d->query->next() && d->query->value(0).toInt() >= keywords.count()) + if (d->query->next() && d->query->value(0).toInt() >= indices.count()) return true; return false; } @@ -824,4 +841,68 @@ bool QHelpGenerator::insertMetaData(const QMap<QString, QVariant> &metaData) return true; } +bool QHelpGenerator::checkLinks(const QHelpDataInterface &helpData) +{ + /* + * Step 1: Gather the canoncal file paths of all files in the project. + * We use a set, because there will be a lot of look-ups. + */ + QSet<QString> files; + foreach (const QHelpDataFilterSection &filterSection, helpData.filterSections()) { + foreach (const QString &file, filterSection.files()) { + QFileInfo fileInfo(helpData.rootPath() + QDir::separator() + file); + const QString &canonicalFileName = fileInfo.canonicalFilePath(); + if (!fileInfo.exists()) + emit warning(tr("File '%1' does not exist.").arg(file)); + else + files.insert(canonicalFileName); + } + } + + /* + * Step 2: Check the hypertext and image references of all HTML files. + * Note that we don't parse the files, but simply grep for the + * respective HTML elements. Therefore. contents that are e.g. + * commented out can cause false warning. + */ + bool allLinksOk = true; + foreach (const QString &fileName, files) { + if (!fileName.endsWith(QLatin1String("html")) + && !fileName.endsWith(QLatin1String("htm"))) + continue; + QFile htmlFile(fileName); + if (!htmlFile.open(QIODevice::ReadOnly)) { + emit warning(tr("File '%1' cannot be opened.").arg(fileName)); + continue; + } + const QRegExp linkPattern(QLatin1String("<(?:a href|img src)=\"?([^#\">]+)[#\">]")); + QTextStream stream(&htmlFile); + const QString codec = QHelpGlobal::codecFromData(htmlFile.read(1000)); + stream.setCodec(QTextCodec::codecForName(codec.toLatin1().constData())); + const QString &content = stream.readAll(); + QStringList invalidLinks; + for (int pos = linkPattern.indexIn(content); pos != -1; + pos = linkPattern.indexIn(content, pos + 1)) { + const QString& linkedFileName = linkPattern.cap(1); + if (linkedFileName.contains(QLatin1String("://"))) + continue; + const QString curDir = QFileInfo(fileName).dir().path(); + const QString &canonicalLinkedFileName = + QFileInfo(curDir + QDir::separator() + linkedFileName).canonicalFilePath(); + if (!files.contains(canonicalLinkedFileName) + && !invalidLinks.contains(canonicalLinkedFileName)) { + emit warning(tr("File '%1' contains an invalid link to file '%2'"). + arg(fileName).arg(linkedFileName)); + allLinksOk = false; + invalidLinks.append(canonicalLinkedFileName); + } + } + } + + if (!allLinksOk) + d->error = tr("Invalid links in HTML files."); + return allLinksOk; +} + QT_END_NAMESPACE + diff --git a/tools/assistant/lib/qhelpgenerator_p.h b/tools/assistant/lib/qhelpgenerator_p.h index c589e25..823a07a 100644 --- a/tools/assistant/lib/qhelpgenerator_p.h +++ b/tools/assistant/lib/qhelpgenerator_p.h @@ -74,6 +74,7 @@ public: bool generate(QHelpDataInterface *helpData, const QString &outputFileName); + bool checkLinks(const QHelpDataInterface &helpData); QString error() const; Q_SIGNALS: @@ -96,7 +97,7 @@ private: const QStringList &filterAttribs, bool forceUpdate = false); bool registerVirtualFolder(const QString &folderName, const QString &ns); bool insertFilterAttributes(const QStringList &attributes); - bool insertKeywords(const QList<QHelpDataIndexItem> keywords, + bool insertKeywords(const QList<QHelpDataIndexItem> &keywords, const QStringList &filterAttributes); bool insertFiles(const QStringList &files, const QString &rootPath, const QStringList &filterAttributes); diff --git a/tools/assistant/lib/qhelpindexwidget.cpp b/tools/assistant/lib/qhelpindexwidget.cpp index 270bcdd..11b9966 100644 --- a/tools/assistant/lib/qhelpindexwidget.cpp +++ b/tools/assistant/lib/qhelpindexwidget.cpp @@ -244,7 +244,8 @@ void QHelpIndexModel::invalidateIndex(bool onShutDown) disconnect(this, SLOT(insertIndices())); d->indexProvider->stopCollecting(); d->indices.clear(); - filter(QString()); + if (!onShutDown) + filter(QString()); } /*! diff --git a/tools/assistant/lib/qhelpprojectdata.cpp b/tools/assistant/lib/qhelpprojectdata.cpp index 869a446..b0faf0c 100644 --- a/tools/assistant/lib/qhelpprojectdata.cpp +++ b/tools/assistant/lib/qhelpprojectdata.cpp @@ -41,11 +41,13 @@ #include "qhelpprojectdata_p.h" +#include <QtCore/QCoreApplication> #include <QtCore/QDir> #include <QtCore/QFileInfo> #include <QtCore/QStack> #include <QtCore/QMap> #include <QtCore/QRegExp> +#include <QtCore/QUrl> #include <QtCore/QVariant> #include <QtXml/QXmlStreamReader> @@ -76,13 +78,14 @@ private: void readFiles(); void raiseUnknownTokenError(); void addMatchingFiles(const QString &pattern); + bool hasValidSyntax(const QString &nameSpace, const QString &vFolder) const; QMap<QString, QStringList> dirEntriesCache; }; void QHelpProjectDataPrivate::raiseUnknownTokenError() { - raiseError(QObject::tr("Unknown token.")); + raiseError(QCoreApplication::translate("QHelpProject", "Unknown token.")); } void QHelpProjectDataPrivate::readData(const QByteArray &contents) @@ -95,12 +98,14 @@ void QHelpProjectDataPrivate::readData(const QByteArray &contents) && attributes().value(QLatin1String("version")) == QLatin1String("1.0")) readProject(); else - raiseError(QObject::tr("Unknown token. Expected \"QtHelpProject\"!")); + raiseError(QCoreApplication::translate("QHelpProject", + "Unknown token. Expected \"QtHelpProject\"!")); } } if (hasError()) { - raiseError(QObject::tr("Error in line %1: %2").arg(lineNumber()) + raiseError(QCoreApplication::translate("QHelpProject", + "Error in line %1: %2").arg(lineNumber()) .arg(errorString())); } } @@ -112,12 +117,14 @@ void QHelpProjectDataPrivate::readProject() if (isStartElement()) { if (name() == QLatin1String("virtualFolder")) { virtualFolder = readElementText(); - if (virtualFolder.contains(QLatin1String("/"))) - raiseError(QObject::tr("A virtual folder must not contain a \'/\' character!")); + if (!hasValidSyntax(QLatin1String("test"), virtualFolder)) + raiseError(QCoreApplication::translate("QHelpProject", + "Virtual folder has invalid syntax.")); } else if (name() == QLatin1String("namespace")) { namespaceName = readElementText(); - if (namespaceName.contains(QLatin1String("/"))) - raiseError(QObject::tr("A namespace must not contain a \'/\' character!")); + if (!hasValidSyntax(namespaceName, QLatin1String("test"))) + raiseError(QCoreApplication::translate("QHelpProject", + "Namespace has invalid syntax.")); } else if (name() == QLatin1String("customFilter")) { readCustomFilter(); } else if (name() == QLatin1String("filterSection")) { @@ -125,17 +132,21 @@ void QHelpProjectDataPrivate::readProject() } else if (name() == QLatin1String("metaData")) { QString n = attributes().value(QLatin1String("name")).toString(); if (!metaData.contains(n)) - metaData[n] = attributes().value(QLatin1String("value")).toString(); + metaData[n] + = attributes().value(QLatin1String("value")).toString(); else - metaData.insert(n, attributes().value(QLatin1String("value")).toString()); + metaData.insert(n, attributes(). + value(QLatin1String("value")).toString()); } else { raiseUnknownTokenError(); } } else if (isEndElement() && name() == QLatin1String("QtHelpProject")) { if (namespaceName.isEmpty()) - raiseError(QObject::tr("Missing namespace in QtHelpProject.")); + raiseError(QCoreApplication::translate("QHelpProject", + "Missing namespace in QtHelpProject.")); else if (virtualFolder.isEmpty()) - raiseError(QObject::tr("Missing virtual folder in QtHelpProject")); + raiseError(QCoreApplication::translate("QHelpProject", + "Missing virtual folder in QtHelpProject")); break; } } @@ -223,12 +234,14 @@ void QHelpProjectDataPrivate::readKeywords() if (attributes().value(QLatin1String("ref")).toString().isEmpty() || (attributes().value(QLatin1String("name")).toString().isEmpty() && attributes().value(QLatin1String("id")).toString().isEmpty())) - raiseError(QObject::tr("Missing attribute in keyword at line %1.") - .arg(lineNumber())); - filterSectionList.last().addIndex( - QHelpDataIndexItem(attributes().value(QLatin1String("name")).toString(), - attributes().value(QLatin1String("id")).toString(), - attributes().value(QLatin1String("ref")).toString())); + raiseError(QCoreApplication::translate("QHelpProject", + "Missing attribute in keyword at line %1.") + .arg(lineNumber())); + filterSectionList.last() + .addIndex(QHelpDataIndexItem(attributes(). + value(QLatin1String("name")).toString(), + attributes().value(QLatin1String("id")).toString(), + attributes().value(QLatin1String("ref")).toString())); } else { raiseUnknownTokenError(); } @@ -305,6 +318,22 @@ void QHelpProjectDataPrivate::addMatchingFiles(const QString &pattern) filterSectionList.last().addFile(pattern); } +bool QHelpProjectDataPrivate::hasValidSyntax(const QString &nameSpace, + const QString &vFolder) const +{ + const QLatin1Char slash('/'); + if (nameSpace.contains(slash) || vFolder.contains(slash)) + return false; + QUrl url; + const QLatin1String scheme("qthelp"); + url.setScheme(scheme); + url.setHost(nameSpace); + url.setPath(vFolder); + + const QString expectedUrl(scheme + QLatin1String("://") + nameSpace + slash + vFolder); + return url.isValid() && url.toString() == expectedUrl; +} + /*! \internal \class QHelpProjectData @@ -346,8 +375,8 @@ bool QHelpProjectData::readData(const QString &fileName) d->rootPath = QFileInfo(fileName).absolutePath(); QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { - d->errorMsg = QObject::tr("The input file %1 could not be opened!") - .arg(fileName); + d->errorMsg = QCoreApplication::translate("QHelpProject", + "The input file %1 could not be opened!").arg(fileName); return false; } diff --git a/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp b/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp index b050361..c2274c4 100644 --- a/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp +++ b/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp @@ -39,16 +39,19 @@ ** ****************************************************************************/ -#include "qhelpenginecore.h" -#include "fulltextsearch/qsearchable_p.h" -#include "fulltextsearch/qqueryparser_p.h" #include "fulltextsearch/qindexreader_p.h" +#include "fulltextsearch/qqueryparser_p.h" +#include "fulltextsearch/qsearchable_p.h" +#include "qclucenefieldnames_p.h" +#include "qhelpenginecore.h" + #include "qhelpsearchindexreader_clucene_p.h" #include <QtCore/QDir> #include <QtCore/QSet> #include <QtCore/QString> #include <QtCore/QFileInfo> +#include <QtCore/QSharedPointer> #include <QtCore/QStringList> #include <QtCore/QTextStream> #include <QtCore/QMutexLocker> @@ -107,64 +110,88 @@ void QHelpSearchIndexReaderClucene::run() #if !defined(QT_NO_EXCEPTIONS) try { #endif - QCLuceneBooleanQuery booleanQuery; + QCLuceneBooleanQuery booleanQueryTitle; + QCLuceneBooleanQuery booleanQueryContent; QCLuceneStandardAnalyzer analyzer; - if (!buildQuery(booleanQuery, queryList, analyzer)) { + const QStringList& attribList = + engine.filterAttributes(engine.currentFilter()); + bool titleQueryIsValid = buildQuery(queryList, TitleTokenizedField, + attribList, booleanQueryTitle, analyzer); + bool contentQueryIsValid = buildQuery(queryList, ContentField, + attribList, booleanQueryContent, analyzer); + if (!titleQueryIsValid && !contentQueryIsValid) { emit searchingFinished(0); return; } - const QStringList attribList = engine.filterAttributes(engine.currentFilter()); - if (!attribList.isEmpty()) { - QCLuceneQuery* query = QCLuceneQueryParser::parse(QLatin1String("+") - + attribList.join(QLatin1String(" +")), QLatin1String("attribute"), analyzer); + QCLuceneIndexSearcher indexSearcher(indexPath); - if (!query) { + // QCLuceneHits object must be allocated on the heap, because + // there is no default constructor. + QSharedPointer<QCLuceneHits> titleHits; + QSharedPointer<QCLuceneHits> contentHits; + if (titleQueryIsValid) { + titleHits = QSharedPointer<QCLuceneHits>(new QCLuceneHits( + indexSearcher.search(booleanQueryTitle))); + } + if (contentQueryIsValid) { + contentHits = QSharedPointer<QCLuceneHits>(new QCLuceneHits( + indexSearcher.search(booleanQueryContent))); + } + bool boost = true; + if ((titleHits.isNull() || titleHits->length() == 0) + && (contentHits.isNull() || contentHits->length() == 0)) { + booleanQueryTitle = QCLuceneBooleanQuery(); + booleanQueryContent = QCLuceneBooleanQuery(); + titleQueryIsValid = + buildTryHarderQuery(queryList, TitleTokenizedField, + attribList, booleanQueryTitle, analyzer); + contentQueryIsValid = + buildTryHarderQuery(queryList, ContentField, attribList, + booleanQueryContent, analyzer); + if (!titleQueryIsValid && !contentQueryIsValid) { emit searchingFinished(0); return; } - booleanQuery.add(query, true, true, false); - } - - QCLuceneIndexSearcher indexSearcher(indexPath); - QCLuceneHits hits = indexSearcher.search(booleanQuery); - - bool boost = true; - QCLuceneBooleanQuery tryHarderQuery; - if (hits.length() == 0) { - if (buildTryHarderQuery(tryHarderQuery, queryList, analyzer)) { - if (!attribList.isEmpty()) { - QCLuceneQuery* query = QCLuceneQueryParser::parse(QLatin1String("+") - + attribList.join(QLatin1String(" +")), QLatin1String("attribute"), - analyzer); - tryHarderQuery.add(query, true, true, false); - } - hits = indexSearcher.search(tryHarderQuery); - boost = (hits.length() == 0); + if (titleQueryIsValid) { + titleHits = QSharedPointer<QCLuceneHits>(new QCLuceneHits( + indexSearcher.search(booleanQueryTitle))); + } + if (contentQueryIsValid) { + contentHits = QSharedPointer<QCLuceneHits>(new QCLuceneHits( + indexSearcher.search(booleanQueryContent))); } + boost = false; } + QList<QSharedPointer<QCLuceneHits> > cluceneHitsList; + if (!titleHits.isNull()) + cluceneHitsList.append(titleHits); + if (!contentHits.isNull()) + cluceneHitsList.append(contentHits); QSet<QString> pathSet; QCLuceneDocument document; const QStringList namespaceList = engine.registeredDocumentations(); - for (qint32 i = 0; i < hits.length(); i++) { - document = hits.document(i); - const QString path = document.get(QLatin1String("path")); - if (!pathSet.contains(path) && namespaceList.contains( - document.get(QLatin1String("namespace")), Qt::CaseInsensitive)) { - pathSet.insert(path); - hitList.append(qMakePair(path, document.get(QLatin1String("title")))); - } - document.clear(); + foreach (QSharedPointer<QCLuceneHits> hits, cluceneHitsList) { + for (qint32 i = 0; i < hits->length(); i++) { + document = hits->document(i); + const QString path = document.get(PathField); + if (!pathSet.contains(path) && namespaceList.contains( + document.get(NamespaceField), Qt::CaseInsensitive)) { + pathSet.insert(path); + hitList.append(qMakePair(path, document.get(TitleField))); + } + document.clear(); - mutex.lock(); - if (m_cancel) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + emit searchingFinished(0); + return; + } mutex.unlock(); - emit searchingFinished(0); - return; } - mutex.unlock(); } indexSearcher.close(); @@ -184,144 +211,205 @@ void QHelpSearchIndexReaderClucene::run() } } -bool QHelpSearchIndexReaderClucene::defaultQuery(const QString &term, QCLuceneBooleanQuery &booleanQuery, - QCLuceneStandardAnalyzer &analyzer) +bool QHelpSearchIndexReaderClucene::buildQuery( + const QList<QHelpSearchQuery> &queries, const QString &fieldName, + const QStringList &filterAttributes, QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer) { - const QLatin1String c("content"); - const QLatin1String t("titleTokenized"); - - QCLuceneQuery *query = QCLuceneQueryParser::parse(term, c, analyzer); - QCLuceneQuery *query2 = QCLuceneQueryParser::parse(term, t, analyzer); - if (query && query2) { - booleanQuery.add(query, true, false, false); - booleanQuery.add(query2, true, false, false); - return true; + bool queryIsValid = false; + foreach (const QHelpSearchQuery &query, queries) { + if (fieldName != ContentField && isNegativeQuery(query)) { + queryIsValid = false; + break; + } + switch (query.fieldName) { + case QHelpSearchQuery::FUZZY: + if (addFuzzyQuery(query, fieldName, booleanQuery, analyzer)) + queryIsValid = true; + break; + case QHelpSearchQuery::WITHOUT: + if (fieldName != ContentField) + return false; + if (addWithoutQuery(query, fieldName, booleanQuery)) + queryIsValid = true; + break; + case QHelpSearchQuery::PHRASE: + if (addPhraseQuery(query, fieldName, booleanQuery)) + queryIsValid = true; + break; + case QHelpSearchQuery::ALL: + if (addAllQuery(query, fieldName, booleanQuery)) + queryIsValid = true; + break; + case QHelpSearchQuery::DEFAULT: + if (addDefaultQuery(query, fieldName, true, booleanQuery, analyzer)) + queryIsValid = true; + break; + case QHelpSearchQuery::ATLEAST: + if (addAtLeastQuery(query, fieldName, booleanQuery, analyzer)) + queryIsValid = true; + break; + default: + Q_ASSERT(!"Invalid field name"); + } } - return false; + if (queryIsValid && !filterAttributes.isEmpty()) { + queryIsValid = + addAttributesQuery(filterAttributes, booleanQuery, analyzer); + } + + return queryIsValid; } -bool QHelpSearchIndexReaderClucene::buildQuery(QCLuceneBooleanQuery &booleanQuery, - const QList<QHelpSearchQuery> &queryList, QCLuceneStandardAnalyzer &analyzer) +bool QHelpSearchIndexReaderClucene::buildTryHarderQuery( + const QList<QHelpSearchQuery> &queries, const QString &fieldName, + const QStringList &filterAttributes, QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer) { - foreach (const QHelpSearchQuery query, queryList) { - switch (query.fieldName) { - case QHelpSearchQuery::FUZZY: { - const QLatin1String fuzzy("~"); - foreach (const QString &term, query.wordList) { - if (term.isEmpty() - || !defaultQuery(term.toLower() + fuzzy, booleanQuery, analyzer)) { - return false; - } - } - } break; - - case QHelpSearchQuery::WITHOUT: { - QStringList stopWords = QCLuceneStopAnalyzer().englishStopWords(); - foreach (const QString &term, query.wordList) { - if (stopWords.contains(term, Qt::CaseInsensitive)) - continue; - - QCLuceneQuery *query = new QCLuceneTermQuery(QCLuceneTerm( - QLatin1String("content"), term.toLower())); - QCLuceneQuery *query2 = new QCLuceneTermQuery(QCLuceneTerm( - QLatin1String("titleTokenized"), term.toLower())); - - if (query && query2) { - booleanQuery.add(query, true, false, true); - booleanQuery.add(query2, true, false, true); - } else { - return false; - } - } - } break; - - case QHelpSearchQuery::PHRASE: { - const QString &term = query.wordList.at(0).toLower(); - if (term.contains(QLatin1Char(' '))) { - QStringList termList = term.split(QLatin1String(" ")); - QCLucenePhraseQuery *q = new QCLucenePhraseQuery(); - QStringList stopWords = QCLuceneStopAnalyzer().englishStopWords(); - foreach (const QString &term, termList) { - if (!stopWords.contains(term, Qt::CaseInsensitive)) - q->addTerm(QCLuceneTerm(QLatin1String("content"), term.toLower())); - } - booleanQuery.add(q, true, true, false); - } else { - QCLuceneQuery *query = new QCLuceneTermQuery(QCLuceneTerm( - QLatin1String("content"), term.toLower())); - QCLuceneQuery *query2 = new QCLuceneTermQuery(QCLuceneTerm( - QLatin1String("titleTokenized"), term.toLower())); - - if (query && query2) { - booleanQuery.add(query, true, true, false); - booleanQuery.add(query2, true, false, false); - } else { - return false; - } - } - } break; + if (queries.isEmpty()) + return false; + const QHelpSearchQuery &query = queries.front(); + if (query.fieldName != QHelpSearchQuery::DEFAULT) + return false; + if (isNegativeQuery(query)) + return false; + if (!addDefaultQuery(query, fieldName, false, booleanQuery, analyzer)) + return false; + if (filterAttributes.isEmpty()) + return true; + return addAttributesQuery(filterAttributes, booleanQuery, analyzer); +} - case QHelpSearchQuery::ALL: { - QStringList stopWords = QCLuceneStopAnalyzer().englishStopWords(); - foreach (const QString &term, query.wordList) { - if (stopWords.contains(term, Qt::CaseInsensitive)) - continue; +bool QHelpSearchIndexReaderClucene::isNegativeQuery(const QHelpSearchQuery &query) const +{ + const QString &search = query.wordList.join(" "); + return search.contains('!') || search.contains('-') + || search.contains(QLatin1String(" NOT ")); +} - QCLuceneQuery *query = new QCLuceneTermQuery(QCLuceneTerm( - QLatin1String("content"), term.toLower())); +bool QHelpSearchIndexReaderClucene::addFuzzyQuery(const QHelpSearchQuery &query, + const QString &fieldName, QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer) +{ + bool queryIsValid = false; + const QLatin1String fuzzy("~"); + foreach (const QString &term, query.wordList) { + if (!term.isEmpty()) { + QCLuceneQuery *lQuery = + QCLuceneQueryParser::parse(term + fuzzy, fieldName, analyzer); + if (lQuery != 0) { + booleanQuery.add(lQuery, true, false, false); + queryIsValid = true; + } + } + } + return queryIsValid; +} - if (query) { - booleanQuery.add(query, true, true, false); - } else { - return false; - } - } - } break; +bool QHelpSearchIndexReaderClucene::addWithoutQuery(const QHelpSearchQuery &query, + const QString &fieldName, QCLuceneBooleanQuery &booleanQuery) +{ + bool queryIsValid = false; + const QStringList &stopWords = QCLuceneStopAnalyzer().englishStopWords(); + foreach (const QString &term, query.wordList) { + if (stopWords.contains(term, Qt::CaseInsensitive)) + continue; + QCLuceneQuery *lQuery = new QCLuceneTermQuery(QCLuceneTerm( + fieldName, term.toLower())); + booleanQuery.add(lQuery, true, false, true); + queryIsValid = true; + } + return queryIsValid; +} - case QHelpSearchQuery::DEFAULT: { - foreach (const QString &term, query.wordList) { - QCLuceneQuery *query = QCLuceneQueryParser::parse(term.toLower(), - QLatin1String("content"), analyzer); +bool QHelpSearchIndexReaderClucene::addPhraseQuery(const QHelpSearchQuery &query, + const QString &fieldName, QCLuceneBooleanQuery &booleanQuery) +{ + bool queryIsValid = false; + const QString &term = query.wordList.at(0).toLower(); + if (term.contains(QLatin1Char(' '))) { + const QStringList termList = term.split(QLatin1String(" ")); + QCLucenePhraseQuery *q = new QCLucenePhraseQuery(); + const QStringList stopWords = QCLuceneStopAnalyzer().englishStopWords(); + foreach (const QString &term, termList) { + if (!stopWords.contains(term, Qt::CaseInsensitive)) + q->addTerm(QCLuceneTerm(fieldName, term.toLower())); + } + if (!q->getTerms().isEmpty()) { + booleanQuery.add(q, true, true, false); + queryIsValid = true; + } + } else { + QCLuceneQuery *lQuery = new QCLuceneTermQuery(QCLuceneTerm( + fieldName, term.toLower())); + booleanQuery.add(lQuery, true, true, false); + queryIsValid = true; + } + return queryIsValid; +} - if (query) - booleanQuery.add(query, true, true, false); - } - } break; +bool QHelpSearchIndexReaderClucene::addAllQuery(const QHelpSearchQuery &query, + const QString &fieldName, QCLuceneBooleanQuery &booleanQuery) +{ + bool queryIsValid = false; + const QStringList &stopWords = QCLuceneStopAnalyzer().englishStopWords(); + foreach (const QString &term, query.wordList) { + if (stopWords.contains(term, Qt::CaseInsensitive)) + continue; + QCLuceneQuery *lQuery = new QCLuceneTermQuery(QCLuceneTerm( + fieldName, term.toLower())); + booleanQuery.add(lQuery, true, true, false); + queryIsValid = true; + } + return queryIsValid; +} - case QHelpSearchQuery::ATLEAST: { - foreach (const QString &term, query.wordList) { - if (term.isEmpty() || !defaultQuery(term.toLower(), booleanQuery, analyzer)) - return false; - } - } +bool QHelpSearchIndexReaderClucene::addDefaultQuery(const QHelpSearchQuery &query, + const QString &fieldName, bool allTermsRequired, + QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer) +{ + bool queryIsValid = false; + foreach (const QString &term, query.wordList) { + QCLuceneQuery *lQuery = + QCLuceneQueryParser::parse(term.toLower(), fieldName, analyzer); + if (lQuery) { + booleanQuery.add(lQuery, true, allTermsRequired, false); + queryIsValid = true; } } - - return true; + return queryIsValid; } -bool QHelpSearchIndexReaderClucene::buildTryHarderQuery(QCLuceneBooleanQuery &booleanQuery, - const QList<QHelpSearchQuery> &queryList, QCLuceneStandardAnalyzer &analyzer) +bool QHelpSearchIndexReaderClucene::addAtLeastQuery( + const QHelpSearchQuery &query, const QString &fieldName, + QCLuceneBooleanQuery &booleanQuery, QCLuceneAnalyzer &analyzer) { - bool retVal = false; - foreach (const QHelpSearchQuery query, queryList) { - switch (query.fieldName) { - default: break; - case QHelpSearchQuery::DEFAULT: { - foreach (const QString &term, query.wordList) { - QCLuceneQuery *query = QCLuceneQueryParser::parse(term.toLower(), - QLatin1String("content"), analyzer); - - if (query) { - retVal = true; - booleanQuery.add(query, true, false, false); - } - } - } break; + bool queryIsValid = false; + foreach (const QString &term, query.wordList) { + if (!term.isEmpty()) { + QCLuceneQuery *lQuery = + QCLuceneQueryParser::parse(term, fieldName, analyzer); + if (lQuery) { + booleanQuery.add(lQuery, true, false, false); + queryIsValid = true; + } } } - return retVal; + return queryIsValid; +} + +bool QHelpSearchIndexReaderClucene::addAttributesQuery( + const QStringList &filterAttributes, QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer) +{ + QCLuceneQuery* lQuery = QCLuceneQueryParser::parse(QLatin1String("+") + + filterAttributes.join(QLatin1String(" +")), AttributeField, analyzer); + if (!lQuery) + return false; + booleanQuery.add(lQuery, true, true, false); + return true; } void QHelpSearchIndexReaderClucene::boostSearchHits(const QHelpEngineCore &engine, @@ -335,21 +423,22 @@ void QHelpSearchIndexReaderClucene::boostSearchHits(const QHelpEngineCore &engin QCLuceneStandardAnalyzer analyzer; QCLuceneQuery *parsedQuery = QCLuceneQueryParser::parse( - joinedQuery, QLatin1String("content"), analyzer); + joinedQuery, ContentField, analyzer); if (parsedQuery) { joinedQuery = parsedQuery->toString(); delete parsedQuery; } - int length = QString(QLatin1String("content:")).length(); - int index = joinedQuery.indexOf(QLatin1String("content:")); + const QString contentString(ContentField + QLatin1String(":")); + int length = contentString.length(); + int index = joinedQuery.indexOf(contentString); QString term; int nextIndex = 0; QStringList searchTerms; while (index != -1) { - nextIndex = joinedQuery.indexOf(QLatin1String("content:"), index + 1); + nextIndex = joinedQuery.indexOf(contentString, index + 1); term = joinedQuery.mid(index + length, nextIndex - (length + index)).simplified(); if (term.startsWith(QLatin1String("\"")) && term.endsWith(QLatin1String("\""))) { diff --git a/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h b/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h index 8f51cb1..7f53733 100644 --- a/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h +++ b/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h @@ -53,10 +53,13 @@ // We mean it. // -#include "qhelpsearchindexreader_p.h" +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QStringList> #include "fulltextsearch/qanalyzer_p.h" #include "fulltextsearch/qquery_p.h" +#include "qhelpsearchindexreader_p.h" QT_BEGIN_NAMESPACE @@ -73,14 +76,34 @@ public: private: void run(); - bool defaultQuery(const QString &term, QCLuceneBooleanQuery &booleanQuery, - QCLuceneStandardAnalyzer &analyzer); - bool buildQuery(QCLuceneBooleanQuery &booleanQuery, const QList<QHelpSearchQuery> &queryList, - QCLuceneStandardAnalyzer &analyzer); - bool buildTryHarderQuery(QCLuceneBooleanQuery &booleanQuery, - const QList<QHelpSearchQuery> &queryList, QCLuceneStandardAnalyzer &analyzer); void boostSearchHits(const QHelpEngineCore &engine, QList<QHelpSearchEngine::SearchHit> &hitList, const QList<QHelpSearchQuery> &queryList); + bool buildQuery(const QList<QHelpSearchQuery> &queries, + const QString &fieldName, + const QStringList &filterAttributes, + QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer); + bool buildTryHarderQuery(const QList<QHelpSearchQuery> &queries, + const QString &fieldName, + const QStringList &filterAttributes, + QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer); + bool addFuzzyQuery(const QHelpSearchQuery &query, const QString &fieldName, + QCLuceneBooleanQuery &booleanQuery, QCLuceneAnalyzer &analyzer); + bool addWithoutQuery(const QHelpSearchQuery &query, const QString &fieldName, + QCLuceneBooleanQuery &booleanQuery); + bool addPhraseQuery(const QHelpSearchQuery &query, const QString &fieldName, + QCLuceneBooleanQuery &booleanQuery); + bool addAllQuery(const QHelpSearchQuery &query, const QString &fieldName, + QCLuceneBooleanQuery &booleanQuery); + bool addDefaultQuery(const QHelpSearchQuery &query, const QString &fieldName, + bool allTermsRequired, QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer); + bool addAtLeastQuery(const QHelpSearchQuery &query, const QString &fieldName, + QCLuceneBooleanQuery &booleanQuery, QCLuceneAnalyzer &analyzer); + bool addAttributesQuery(const QStringList &filterAttributes, + QCLuceneBooleanQuery &booleanQuery, QCLuceneAnalyzer &analyzer); + bool isNegativeQuery(const QHelpSearchQuery &query) const; }; } // namespace clucene diff --git a/tools/assistant/lib/qhelpsearchindexwriter_clucene.cpp b/tools/assistant/lib/qhelpsearchindexwriter_clucene.cpp index 4f9fa3f..4baa376 100644 --- a/tools/assistant/lib/qhelpsearchindexwriter_clucene.cpp +++ b/tools/assistant/lib/qhelpsearchindexwriter_clucene.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#include "qclucenefieldnames_p.h" #include "qhelpenginecore.h" #include "qhelp_global.h" #include "fulltextsearch/qhits_p.h" @@ -406,17 +407,17 @@ public: QString parsedTitle = QHelpGlobal::documentTitle(data); if(!parsedData.isEmpty()) { - document->add(new QCLuceneField(QLatin1String("content"), + document->add(new QCLuceneField(ContentField, parsedData,QCLuceneField::INDEX_TOKENIZED)); - document->add(new QCLuceneField(QLatin1String("path"), fileName, + document->add(new QCLuceneField(PathField, fileName, QCLuceneField::STORE_YES | QCLuceneField::INDEX_UNTOKENIZED)); - document->add(new QCLuceneField(QLatin1String("title"), parsedTitle, + document->add(new QCLuceneField(TitleField, parsedTitle, QCLuceneField::STORE_YES | QCLuceneField::INDEX_UNTOKENIZED)); - document->add(new QCLuceneField(QLatin1String("titleTokenized"), parsedTitle, + document->add(new QCLuceneField(TitleTokenizedField, parsedTitle, QCLuceneField::STORE_YES | QCLuceneField::INDEX_TOKENIZED)); - document->add(new QCLuceneField(QLatin1String("namespace"), namespaceName, + document->add(new QCLuceneField(NamespaceField, namespaceName, QCLuceneField::STORE_YES | QCLuceneField::INDEX_UNTOKENIZED)); - document->add(new QCLuceneField(QLatin1String("attribute"), attributes, + document->add(new QCLuceneField(AttributeField, attributes, QCLuceneField::STORE_YES | QCLuceneField::INDEX_TOKENIZED)); return true; } @@ -715,9 +716,7 @@ void QHelpSearchIndexWriter::run() if (indexMap.contains(namespaceName)) { // make sure we really have content indexed for namespace - // NOTE: Extra variable just for GCC 3.3.5 - QLatin1String key("namespace"); - QCLuceneTermQuery query(QCLuceneTerm(key, namespaceName)); + QCLuceneTermQuery query(QCLuceneTerm(NamespaceField, namespaceName)); QCLuceneIndexSearcher indexSearcher(indexPath); QCLuceneHits hits = indexSearcher.search(query); if (hits.length() <= 0) @@ -851,8 +850,7 @@ void QHelpSearchIndexWriter::removeDocuments(const QString &indexPath, return; QCLuceneIndexReader reader = QCLuceneIndexReader::open(indexPath); - reader.deleteDocuments(QCLuceneTerm(QLatin1String("namespace"), - namespaceName)); + reader.deleteDocuments(QCLuceneTerm(NamespaceField, namespaceName)); reader.close(); } diff --git a/tools/assistant/lib/qhelpsearchquerywidget.cpp b/tools/assistant/lib/qhelpsearchquerywidget.cpp index 3c3919e..1634a0d 100644 --- a/tools/assistant/lib/qhelpsearchquerywidget.cpp +++ b/tools/assistant/lib/qhelpsearchquerywidget.cpp @@ -41,8 +41,6 @@ #include "qhelpsearchquerywidget.h" -#include <QtCore/QDebug> - #include <QtCore/QAbstractListModel> #include <QtCore/QObject> #include <QtCore/QStringList> @@ -101,8 +99,9 @@ private: }; QHelpSearchQueryWidgetPrivate() - : QObject(), simpleSearch(true), - searchCompleter(new CompleterModel(this), this) + : QObject() + , simpleSearch(true) + , searchCompleter(new CompleterModel(this), this) { searchButton = 0; advancedSearchWidget = 0; @@ -136,33 +135,6 @@ private: #endif } - QString escapeString(const QString &text) - { - QString retValue = text; - const QString escape(QLatin1String("\\")); - QStringList escapableCharsList; - escapableCharsList << QLatin1String("\\") << QLatin1String("+") - << QLatin1String("-") << QLatin1String("!") << QLatin1String("(") - << QLatin1String(")") << QLatin1String(":") << QLatin1String("^") - << QLatin1String("[") << QLatin1String("]") << QLatin1String("{") - << QLatin1String("}") << QLatin1String("~"); - - // make sure we won't end up with an empty string - foreach (const QString &escapeChar, escapableCharsList) { - if (retValue.contains(escapeChar)) - retValue.replace(escapeChar, QLatin1String("")); - } - if (retValue.trimmed().isEmpty()) - return retValue; - - retValue = text; // now really escape the string... - foreach (const QString &escapeChar, escapableCharsList) { - if (retValue.contains(escapeChar)) - retValue.replace(escapeChar, escape + escapeChar); - } - return retValue; - } - QStringList buildTermList(const QString query) { bool s = false; @@ -222,8 +194,8 @@ private: } } - void nextOrPrevQuery(int maxOrMinIndex, int addend, - QToolButton *thisButton, QToolButton *otherButton) + void nextOrPrevQuery(int maxOrMinIndex, int addend, QToolButton *thisButton, + QToolButton *otherButton) { QueryHistory *queryHist; QList<QLineEdit *> lineEdits; @@ -233,7 +205,7 @@ private: } else { queryHist = &complexQueries; lineEdits << allQuery << atLeastQuery << similarQuery - << withoutQuery << exactQuery; + << withoutQuery << exactQuery; } foreach (QLineEdit *lineEdit, lineEdits) lineEdit->clear(); @@ -278,11 +250,11 @@ private: void enableOrDisableToolButtons() { - const QueryHistory &queryHist = - simpleSearch ? simpleQueries : complexQueries; + const QueryHistory &queryHist = simpleSearch ? simpleQueries + : complexQueries; prevQueryButton->setEnabled(queryHist.curQuery > 0); - nextQueryButton->setEnabled(queryHist.curQuery < - queryHist.queries.size() - 1); + nextQueryButton->setEnabled(queryHist.curQuery + < queryHist.queries.size() - 1); } private slots: @@ -306,41 +278,45 @@ private slots: QList<QHelpSearchQuery> queryList; #if !defined(QT_CLUCENE_SUPPORT) queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT, - QStringList(defaultQuery->text()))); + QStringList(defaultQuery->text()))); #else if (defaultQuery->isEnabled()) { queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT, - buildTermList(escapeString(defaultQuery->text())))); + buildTermList(defaultQuery->text()))); } else { const QRegExp exp(QLatin1String("\\s+")); - QStringList lst = similarQuery->text().split(exp, QString::SkipEmptyParts); + QStringList lst = similarQuery->text().split(exp, + QString::SkipEmptyParts); if (!lst.isEmpty()) { QStringList fuzzy; foreach (const QString &term, lst) - fuzzy += buildTermList(escapeString(term)); - queryList.append(QHelpSearchQuery(QHelpSearchQuery::FUZZY, fuzzy)); + fuzzy += buildTermList(term); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::FUZZY, + fuzzy)); } lst = withoutQuery->text().split(exp, QString::SkipEmptyParts); if (!lst.isEmpty()) { QStringList without; foreach (const QString &term, lst) - without.append(escapeString(term)); - queryList.append(QHelpSearchQuery(QHelpSearchQuery::WITHOUT, without)); + without.append(term); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::WITHOUT, + without)); } if (!exactQuery->text().isEmpty()) { QString phrase = exactQuery->text().remove(QLatin1Char('\"')); - phrase = escapeString(phrase.simplified()); - queryList.append(QHelpSearchQuery(QHelpSearchQuery::PHRASE, QStringList(phrase))); + phrase = phrase.simplified(); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::PHRASE, + QStringList(phrase))); } lst = allQuery->text().split(exp, QString::SkipEmptyParts); if (!lst.isEmpty()) { QStringList all; foreach (const QString &term, lst) - all.append(escapeString(term)); + all.append(term); queryList.append(QHelpSearchQuery(QHelpSearchQuery::ALL, all)); } @@ -348,8 +324,9 @@ private slots: if (!lst.isEmpty()) { QStringList atLeast; foreach (const QString &term, lst) - atLeast += buildTermList(escapeString(term)); - queryList.append(QHelpSearchQuery(QHelpSearchQuery::ATLEAST, atLeast)); + atLeast += buildTermList(term); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::ATLEAST, + atLeast)); } } #endif @@ -363,8 +340,9 @@ private slots: void nextQuery() { - nextOrPrevQuery((simpleSearch ? simpleQueries : complexQueries).queries.size() - 1, - 1, nextQueryButton, prevQueryButton); + nextOrPrevQuery((simpleSearch ? simpleQueries + : complexQueries).queries.size() - 1, 1, nextQueryButton, + prevQueryButton); } void prevQuery() @@ -415,8 +393,9 @@ private: \fn void QHelpSearchQueryWidget::search() This signal is emitted when a the user has the search button invoked. - After reciving the signal you can ask the QHelpSearchQueryWidget for the build list - of QHelpSearchQuery's that you may pass to the QHelpSearchEngine's search() function. + After reciving the signal you can ask the QHelpSearchQueryWidget for the + build list of QHelpSearchQuery's that you may pass to the QHelpSearchEngine's + search() function. */ /*! @@ -544,7 +523,8 @@ QList<QHelpSearchQuery> QHelpSearchQueryWidget::query() const QList<QHelpSearchQuery>() : queryHist.queries.last(); } -/*! \reimp +/*! + \reimp */ void QHelpSearchQueryWidget::focusInEvent(QFocusEvent *focusEvent) { diff --git a/tools/assistant/lib/qhelpsearchresultwidget.cpp b/tools/assistant/lib/qhelpsearchresultwidget.cpp index ad540c6..2f5489b 100644 --- a/tools/assistant/lib/qhelpsearchresultwidget.cpp +++ b/tools/assistant/lib/qhelpsearchresultwidget.cpp @@ -304,7 +304,7 @@ private: last = resultLastToShow > count ? count : resultLastToShow; } } - hitsLabel->setText(tr("%1 - %2 of %3 Hits").arg(first).arg(last).arg(count)); + hitsLabel->setText(QHelpSearchResultWidget::tr("%1 - %2 of %n Hits", 0, count).arg(first).arg(last)); } private: diff --git a/tools/assistant/tools/assistant/aboutdialog.cpp b/tools/assistant/tools/assistant/aboutdialog.cpp index 0ab8659..a9bc352 100644 --- a/tools/assistant/tools/assistant/aboutdialog.cpp +++ b/tools/assistant/tools/assistant/aboutdialog.cpp @@ -38,6 +38,8 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "helpviewer.h" +#include "tracer.h" #include <QtCore/QBuffer> @@ -56,6 +58,7 @@ QT_BEGIN_NAMESPACE AboutLabel::AboutLabel(QWidget *parent) : QTextBrowser(parent) { + TRACE_OBJ setFrameStyle(QFrame::NoFrame); QPalette p; p.setColor(QPalette::Base, p.color(QPalette::Background)); @@ -64,14 +67,16 @@ AboutLabel::AboutLabel(QWidget *parent) void AboutLabel::setText(const QString &text, const QByteArray &resources) { + TRACE_OBJ QDataStream in(resources); in >> m_resourceMap; - + QTextBrowser::setText(text); } QSize AboutLabel::minimumSizeHint() const { + TRACE_OBJ QTextDocument *doc = document(); doc->adjustSize(); return QSize(int(doc->size().width()), int(doc->size().height())); @@ -79,6 +84,7 @@ QSize AboutLabel::minimumSizeHint() const QVariant AboutLabel::loadResource(int type, const QUrl &name) { + TRACE_OBJ if (type == 2 || type == 3) { if (m_resourceMap.contains(name.toString())) { return m_resourceMap.value(name.toString()); @@ -89,44 +95,47 @@ QVariant AboutLabel::loadResource(int type, const QUrl &name) void AboutLabel::setSource(const QUrl &url) { - if (url.isValid() - && (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("ftp") - || url.scheme() == QLatin1String("mailto") || url.path().endsWith(QLatin1String("pdf")))) { + TRACE_OBJ + if (url.isValid() && (!AbstractHelpViewer::isLocalUrl(url) + || !AbstractHelpViewer::canOpenPage(url.path()))) { if (!QDesktopServices::openUrl(url)) { QMessageBox::warning(this, tr("Warning"), - tr("Unable to launch external application.\n"), - tr("OK")); + tr("Unable to launch external application.\n"), tr("OK")); } } } AboutDialog::AboutDialog(QWidget *parent) - : QDialog(parent, Qt::MSWindowsFixedSizeDialogHint|Qt::WindowTitleHint|Qt::WindowSystemMenuHint) + : QDialog(parent, Qt::MSWindowsFixedSizeDialogHint | + Qt::WindowTitleHint|Qt::WindowSystemMenuHint) { + TRACE_OBJ m_pixmapLabel = 0; m_aboutLabel = new AboutLabel(); - + m_closeButton = new QPushButton(); m_closeButton->setText(tr("&Close")); - connect(m_closeButton, SIGNAL(clicked()), - this, SLOT(close())); + connect(m_closeButton, SIGNAL(clicked()), this, SLOT(close())); m_layout = new QGridLayout(this); m_layout->addWidget(m_aboutLabel, 1, 0, 1, -1); - m_layout->addItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), 2, 1, 1, 1); + m_layout->addItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, + QSizePolicy::Fixed), 2, 1, 1, 1); m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding), 3, 0, 1, 1); m_layout->addWidget(m_closeButton, 3, 1, 1, 1); - m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding), 3, 2, 1, 1); + m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding), 3, 2, 1, 1); } void AboutDialog::setText(const QString &text, const QByteArray &resources) { + TRACE_OBJ m_aboutLabel->setText(text, resources); updateSize(); } void AboutDialog::setPixmap(const QPixmap &pixmap) { + TRACE_OBJ if (!m_pixmapLabel) { m_pixmapLabel = new QLabel(); m_layout->addWidget(m_pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter); @@ -137,12 +146,15 @@ void AboutDialog::setPixmap(const QPixmap &pixmap) QString AboutDialog::documentTitle() const { + TRACE_OBJ return m_aboutLabel->documentTitle(); } void AboutDialog::updateSize() { - QSize screenSize = QApplication::desktop()->availableGeometry(QCursor::pos()).size(); + TRACE_OBJ + QSize screenSize = QApplication::desktop()->availableGeometry(QCursor::pos()) + .size(); int limit = qMin(screenSize.width()/2, 500); #ifdef Q_WS_MAC @@ -154,7 +166,7 @@ void AboutDialog::updateSize() if (width > limit) width = limit; - + QFontMetrics fm(qApp->font("QWorkspaceTitleBar")); int windowTitleWidth = qMin(fm.width(windowTitle()) + 50, limit); if (windowTitleWidth > width) @@ -162,8 +174,8 @@ void AboutDialog::updateSize() layout()->activate(); int height = (layout()->hasHeightForWidth()) - ? layout()->totalHeightForWidth(width) - : layout()->totalMinimumSize().height(); + ? layout()->totalHeightForWidth(width) + : layout()->totalMinimumSize().height(); setFixedSize(width, height); QCoreApplication::removePostedEvents(this, QEvent::LayoutRequest); } diff --git a/tools/assistant/tools/assistant/assistant.pro b/tools/assistant/tools/assistant/assistant.pro index 1a7e874..eb8cc51 100644 --- a/tools/assistant/tools/assistant/assistant.pro +++ b/tools/assistant/tools/assistant/assistant.pro @@ -1,71 +1,94 @@ include($$QT_SOURCE_TREE/tools/shared/fontpanel/fontpanel.pri) - TEMPLATE = app LANGUAGE = C++ TARGET = assistant - -contains(QT_CONFIG, webkit) { - QT += webkit -} - -CONFIG += qt warn_on help - +contains(QT_CONFIG, webkit):QT += webkit +CONFIG += qt \ + warn_on \ + help QT += network - PROJECTNAME = Assistant DESTDIR = ../../../../bin - -target.path=$$[QT_INSTALL_BINS] +target.path = $$[QT_INSTALL_BINS] INSTALLS += target +DEPENDPATH += ../shared -### Work around a qmake issue when statically linking to -### not-yet-installed plugins -LIBS += -L$$QT_BUILD_TREE/plugins/sqldrivers - -HEADERS += helpviewer.h \ - mainwindow.h \ - indexwindow.h \ - topicchooser.h \ - contentwindow.h \ - searchwidget.h \ - preferencesdialog.h \ - filternamedialog.h \ - centralwidget.h \ - installdialog.h \ - bookmarkmanager.h \ - remotecontrol.h \ - cmdlineparser.h \ - aboutdialog.h \ - qtdocinstaller.h +# ## Work around a qmake issue when statically linking to +# ## not-yet-installed plugins +QMAKE_LIBDIR += $$QT_BUILD_TREE/plugins/sqldrivers +HEADERS += aboutdialog.h \ + bookmarkdialog.h \ + bookmarkfiltermodel.h \ + bookmarkitem.h \ + bookmarkmanager.h \ + bookmarkmanagerwidget.h \ + bookmarkmodel.h \ + centralwidget.h \ + cmdlineparser.h \ + contentwindow.h \ + findwidget.h \ + filternamedialog.h \ + helpenginewrapper.h \ + helpviewer.h \ + indexwindow.h \ + installdialog.h \ + mainwindow.h \ + preferencesdialog.h \ + qtdocinstaller.h \ + remotecontrol.h \ + searchwidget.h \ + topicchooser.h \ + tracer.h \ + xbelsupport.h \ + ../shared/collectionconfiguration.h +contains(QT_CONFIG, webkit) { + HEADERS += helpviewer_qwv.h +} else { + HEADERS += helpviewer_qtb.h + } +win32:HEADERS += remotecontrol_win.h -win32 { - HEADERS += remotecontrol_win.h +SOURCES += aboutdialog.cpp \ + bookmarkdialog.cpp \ + bookmarkfiltermodel.cpp \ + bookmarkitem.cpp \ + bookmarkmanager.cpp \ + bookmarkmanagerwidget.cpp \ + bookmarkmodel.cpp \ + centralwidget.cpp \ + cmdlineparser.cpp \ + contentwindow.cpp \ + findwidget.cpp \ + filternamedialog.cpp \ + helpenginewrapper.cpp \ + helpviewer.cpp \ + indexwindow.cpp \ + installdialog.cpp \ + main.cpp \ + mainwindow.cpp \ + preferencesdialog.cpp \ + qtdocinstaller.cpp \ + remotecontrol.cpp \ + searchwidget.cpp \ + topicchooser.cpp \ + xbelsupport.cpp \ + ../shared/collectionconfiguration.cpp + contains(QT_CONFIG, webkit) { + SOURCES += helpviewer_qwv.cpp +} else { + SOURCES += helpviewer_qtb.cpp } -SOURCES += helpviewer.cpp \ - main.cpp \ - mainwindow.cpp \ - indexwindow.cpp \ - topicchooser.cpp \ - contentwindow.cpp \ - searchwidget.cpp \ - preferencesdialog.cpp \ - filternamedialog.cpp \ - centralwidget.cpp \ - installdialog.cpp \ - bookmarkmanager.cpp \ - remotecontrol.cpp \ - cmdlineparser.cpp \ - aboutdialog.cpp \ - qtdocinstaller.cpp - -FORMS += topicchooser.ui \ - preferencesdialog.ui \ - filternamedialog.ui \ - installdialog.ui \ - bookmarkdialog.ui +FORMS += bookmarkdialog.ui \ + bookmarkmanagerwidget.ui \ + bookmarkwidget.ui \ + filternamedialog.ui \ + installdialog.ui \ + preferencesdialog.ui \ + topicchooser.ui -RESOURCES += assistant.qrc assistant_images.qrc +RESOURCES += assistant.qrc \ + assistant_images.qrc win32 { !wince*:LIBS += -lshell32 diff --git a/tools/assistant/tools/assistant/assistant.qch b/tools/assistant/tools/assistant/assistant.qch Binary files differindex 78fe9f3..e6d5299 100644 --- a/tools/assistant/tools/assistant/assistant.qch +++ b/tools/assistant/tools/assistant/assistant.qch diff --git a/tools/assistant/tools/assistant/assistant_images.qrc b/tools/assistant/tools/assistant/assistant_images.qrc index 58e03b5..34918c0 100644 --- a/tools/assistant/tools/assistant/assistant_images.qrc +++ b/tools/assistant/tools/assistant/assistant_images.qrc @@ -4,6 +4,7 @@ <file>images/assistant-128.png</file> <file>images/assistant.png</file> <file>images/wrap.png</file> + <file>images/bookmark.png</file> #mac <file>images/mac/addtab.png</file> <file>images/mac/book.png</file> diff --git a/tools/assistant/tools/assistant/bookmarkdialog.cpp b/tools/assistant/tools/assistant/bookmarkdialog.cpp new file mode 100644 index 0000000..8b195c1 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkdialog.cpp @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "bookmarkdialog.h" +#include "bookmarkfiltermodel.h" +#include "bookmarkitem.h" +#include "bookmarkmodel.h" +#include "helpenginewrapper.h" +#include "tracer.h" + +#include <QtGui/QKeyEvent> +#include <QtGui/QMenu> + +QT_BEGIN_NAMESPACE + +BookmarkDialog::BookmarkDialog(BookmarkModel *sourceModel, const QString &title, + const QString &url, QWidget *parent) + : QDialog(parent) + , m_url(url) + , m_title(title) + , bookmarkModel(sourceModel) +{ + TRACE_OBJ + ui.setupUi(this); + + ui.bookmarkEdit->setText(m_title); + ui.newFolderButton->setVisible(false); + ui.buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); + + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(accepted())); + connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(rejected())); + connect(ui.newFolderButton, SIGNAL(clicked()), this, SLOT(addFolder())); + connect(ui.toolButton, SIGNAL(clicked()), this, SLOT(toolButtonClicked())); + connect(ui.bookmarkEdit, SIGNAL(textChanged(QString)), this, + SLOT(textChanged(QString))); + + bookmarkProxyModel = new BookmarkFilterModel(this); + bookmarkProxyModel->setSourceModel(bookmarkModel); + ui.bookmarkFolders->setModel(bookmarkProxyModel); + connect(ui.bookmarkFolders, SIGNAL(currentIndexChanged(int)), this, + SLOT(currentIndexChanged(int))); + + bookmarkTreeModel = new BookmarkTreeModel(this); + bookmarkTreeModel->setSourceModel(bookmarkModel); + ui.treeView->setModel(bookmarkTreeModel); + + ui.treeView->expandAll(); + ui.treeView->setVisible(false); + ui.treeView->installEventFilter(this); + ui.treeView->viewport()->installEventFilter(this); + ui.treeView->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(ui.treeView, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(customContextMenuRequested(QPoint))); + connect(ui.treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, + QModelIndex)), this, SLOT(currentIndexChanged(QModelIndex))); + + ui.bookmarkFolders->setCurrentIndex(0); + ui.treeView->setCurrentIndex(ui.treeView->indexAt(QPoint(2, 2))); + + const HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + if (helpEngine.usesAppFont()) + setFont(helpEngine.appFont()); +} + +BookmarkDialog::~BookmarkDialog() +{ + TRACE_OBJ +} + +bool BookmarkDialog::isRootItem(const QModelIndex &index) const +{ + return !bookmarkTreeModel->parent(index).isValid(); +} + +bool BookmarkDialog::eventFilter(QObject *object, QEvent *event) +{ + TRACE_OBJ + if (object != ui.treeView && object != ui.treeView->viewport()) + return QWidget::eventFilter(object, event); + + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(event); + switch (ke->key()) { + case Qt::Key_F2: { + const QModelIndex &index = ui.treeView->currentIndex(); + if (!isRootItem(index)) { + bookmarkModel->setItemsEditable(true); + ui.treeView->edit(index); + bookmarkModel->setItemsEditable(false); + } + } break; + default: break; + } + } + + return QObject::eventFilter(object, event); +} + +void BookmarkDialog::currentIndexChanged(int row) +{ + TRACE_OBJ + QModelIndex next = bookmarkProxyModel->index(row, 0, QModelIndex()); + if (next.isValid()) { + next = bookmarkProxyModel->mapToSource(next); + ui.treeView->setCurrentIndex(bookmarkTreeModel->mapFromSource(next)); + } +} + +void BookmarkDialog::currentIndexChanged(const QModelIndex &index) +{ + TRACE_OBJ + const QModelIndex current = bookmarkTreeModel->mapToSource(index); + if (current.isValid()) { + const int row = bookmarkProxyModel->mapFromSource(current).row(); + ui.bookmarkFolders->setCurrentIndex(row); + } +} + +void BookmarkDialog::accepted() +{ + TRACE_OBJ + QModelIndex index = ui.treeView->currentIndex(); + if (index.isValid()) { + index = bookmarkModel->addItem(bookmarkTreeModel->mapToSource(index)); + if (BookmarkItem *item = bookmarkModel->itemFromIndex(index)) + item->setData(DataVector() << m_title << m_url << false); + } else + rejected(); + + accept(); +} + +void BookmarkDialog::rejected() +{ + TRACE_OBJ + foreach (const QPersistentModelIndex &index, cache) + bookmarkModel->removeItem(index); + reject(); +} + +void BookmarkDialog::addFolder() +{ + TRACE_OBJ + QModelIndex index = ui.treeView->currentIndex(); + if (index.isValid()) { + index = bookmarkModel->addItem(bookmarkTreeModel->mapToSource(index), + true); + cache.append(index); + + index = bookmarkTreeModel->mapFromSource(index); + if (index.isValid()) { + bookmarkModel->setItemsEditable(true); + ui.treeView->edit(index); + ui.treeView->expand(index); + ui.treeView->setCurrentIndex(index); + bookmarkModel->setItemsEditable(false); + } + } +} + +void BookmarkDialog::toolButtonClicked() +{ + TRACE_OBJ + const bool visible = !ui.treeView->isVisible(); + ui.treeView->setVisible(visible); + ui.newFolderButton->setVisible(visible); + + if (visible) { + resize(QSize(width(), 400)); + ui.toolButton->setText(QLatin1String("-")); + } else { + resize(width(), minimumHeight()); + ui.toolButton->setText(QLatin1String("+")); + } +} + +void BookmarkDialog::textChanged(const QString& text) +{ + m_title = text; +} + +void BookmarkDialog::customContextMenuRequested(const QPoint &point) +{ + TRACE_OBJ + const QModelIndex &index = ui.treeView->currentIndex(); + if (isRootItem(index)) + return; // check if we go to rename the "Bookmarks Menu", bail + + QMenu menu(QLatin1String(""), this); + QAction *renameItem = menu.addAction(tr("Rename Folder")); + + QAction *picked = menu.exec(ui.treeView->mapToGlobal(point)); + if (picked == renameItem) { + bookmarkModel->setItemsEditable(true); + ui.treeView->edit(index); + bookmarkModel->setItemsEditable(false); + } +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/bookmarkdialog.h b/tools/assistant/tools/assistant/bookmarkdialog.h new file mode 100644 index 0000000..e177af6 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkdialog.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef BOOKMARKDIALOG_H +#define BOOKMARKDIALOG_H + +#include "ui_bookmarkdialog.h" + +QT_BEGIN_NAMESPACE + +class BookmarkModel; +class BookmarkFilterModel; +class BookmarkTreeModel; + +class BookmarkDialog : public QDialog +{ + Q_OBJECT +public: + BookmarkDialog(BookmarkModel *bookmarkModel, const QString &title, + const QString &url, QWidget *parent = 0); + ~BookmarkDialog(); + +private: + bool isRootItem(const QModelIndex &index) const; + bool eventFilter(QObject *object, QEvent *event); + +private slots: + void currentIndexChanged(int index); + void currentIndexChanged(const QModelIndex &index); + + void accepted(); + void rejected(); + + void addFolder(); + void toolButtonClicked(); + void textChanged(const QString& text); + void customContextMenuRequested(const QPoint &point); + +private: + QString m_url; + QString m_title; + Ui::BookmarkDialog ui; + QList<QPersistentModelIndex> cache; + + BookmarkModel *bookmarkModel; + BookmarkTreeModel *bookmarkTreeModel; + BookmarkFilterModel *bookmarkProxyModel; +}; + +QT_END_NAMESPACE + +#endif // BOOKMARKDIALOG_H diff --git a/tools/assistant/tools/assistant/bookmarkdialog.ui b/tools/assistant/tools/assistant/bookmarkdialog.ui index 7a878f9..5131531 100644 --- a/tools/assistant/tools/assistant/bookmarkdialog.ui +++ b/tools/assistant/tools/assistant/bookmarkdialog.ui @@ -1,38 +1,39 @@ -<ui version="4.0" > +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> <class>BookmarkDialog</class> - <widget class="QDialog" name="BookmarkDialog" > - <property name="geometry" > + <widget class="QDialog" name="BookmarkDialog"> + <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>450</width> - <height>135</height> + <height>133</height> </rect> </property> - <property name="sizePolicy" > - <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="windowTitle" > + <property name="windowTitle"> <string>Add Bookmark</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_3" > + <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <layout class="QHBoxLayout" name="horizontalLayout" > + <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <layout class="QVBoxLayout" name="verticalLayout_2" > + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QLabel" name="label" > - <property name="text" > + <widget class="QLabel" name="label"> + <property name="text"> <string>Bookmark:</string> </property> </widget> </item> <item> - <widget class="QLabel" name="label_2" > - <property name="text" > + <widget class="QLabel" name="label_2"> + <property name="text"> <string>Add in Folder:</string> </property> </widget> @@ -40,35 +41,35 @@ </layout> </item> <item> - <layout class="QVBoxLayout" name="verticalLayout" > + <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QLineEdit" name="bookmarkEdit" /> + <widget class="QLineEdit" name="bookmarkEdit"/> </item> <item> - <widget class="QComboBox" name="bookmarkFolders" /> + <widget class="QComboBox" name="bookmarkFolders"/> </item> </layout> </item> </layout> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_3" > + <layout class="QHBoxLayout" name="horizontalLayout_3"> <item> - <widget class="QToolButton" name="toolButton" > - <property name="minimumSize" > + <widget class="QToolButton" name="toolButton"> + <property name="minimumSize"> <size> <width>25</width> <height>20</height> </size> </property> - <property name="text" > + <property name="text"> <string>+</string> </property> </widget> </item> <item> - <widget class="Line" name="line" > - <property name="orientation" > + <widget class="Line" name="line"> + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> @@ -76,30 +77,39 @@ </layout> </item> <item> - <widget class="QTreeView" name="treeView" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Ignored" hsizetype="Expanding" > + <widget class="QTreeView" name="treeView"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Ignored"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> + <property name="uniformRowHeights"> + <bool>true</bool> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="headerHidden"> + <bool>true</bool> + </property> </widget> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_4" > + <layout class="QHBoxLayout" name="horizontalLayout_4"> <item> - <widget class="QPushButton" name="newFolderButton" > - <property name="text" > + <widget class="QPushButton" name="newFolderButton"> + <property name="text"> <string>New Folder</string> </property> </widget> </item> <item> - <widget class="QDialogButtonBox" name="buttonBox" > - <property name="orientation" > + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <property name="standardButtons" > + <property name="standardButtons"> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> </widget> @@ -116,11 +126,11 @@ <receiver>BookmarkDialog</receiver> <slot>accept()</slot> <hints> - <hint type="sourcelabel" > + <hint type="sourcelabel"> <x>248</x> <y>254</y> </hint> - <hint type="destinationlabel" > + <hint type="destinationlabel"> <x>157</x> <y>274</y> </hint> @@ -132,11 +142,11 @@ <receiver>BookmarkDialog</receiver> <slot>reject()</slot> <hints> - <hint type="sourcelabel" > + <hint type="sourcelabel"> <x>316</x> <y>260</y> </hint> - <hint type="destinationlabel" > + <hint type="destinationlabel"> <x>286</x> <y>274</y> </hint> diff --git a/tools/assistant/tools/assistant/bookmarkfiltermodel.cpp b/tools/assistant/tools/assistant/bookmarkfiltermodel.cpp new file mode 100644 index 0000000..5874493 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkfiltermodel.cpp @@ -0,0 +1,322 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "bookmarkfiltermodel.h" + +#include "bookmarkitem.h" +#include "bookmarkmodel.h" + +BookmarkFilterModel::BookmarkFilterModel(QObject *parent) + : QAbstractProxyModel(parent) + , hideBookmarks(true) + , sourceModel(0) +{ +} + +void +BookmarkFilterModel::setSourceModel(QAbstractItemModel *_sourceModel) +{ + beginResetModel(); + + QAbstractProxyModel::setSourceModel(sourceModel); + sourceModel = qobject_cast<BookmarkModel*> (_sourceModel); + + connect(sourceModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, + SLOT(changed(QModelIndex, QModelIndex))); + + connect(sourceModel, SIGNAL(rowsInserted(QModelIndex, int, int)), + this, SLOT(rowsInserted(QModelIndex, int, int))); + + connect(sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), + this, SLOT(rowsAboutToBeRemoved(QModelIndex, int, int))); + connect(sourceModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, + SLOT(rowsRemoved(QModelIndex, int, int))); + + connect(sourceModel, SIGNAL(layoutAboutToBeChanged()), this, + SLOT(layoutAboutToBeChanged())); + connect(sourceModel, SIGNAL(layoutChanged()), this, + SLOT(layoutChanged())); + + connect(sourceModel, SIGNAL(modelAboutToBeReset()), this, + SLOT(modelAboutToBeReset())); + connect(sourceModel, SIGNAL(modelReset()), this, SLOT(modelReset())); + + if (sourceModel) + setupCache(sourceModel->index(0, 0, QModelIndex())); + + endResetModel(); +} + +int +BookmarkFilterModel::rowCount(const QModelIndex &index) const +{ + Q_UNUSED(index) + return cache.count(); +} + +int +BookmarkFilterModel::columnCount(const QModelIndex &index) const +{ + Q_UNUSED(index) + if (sourceModel) + return sourceModel->columnCount(); + return 0; +} + +QModelIndex +BookmarkFilterModel::mapToSource(const QModelIndex &proxyIndex) const +{ + const int row = proxyIndex.row(); + if (proxyIndex.isValid() && row >= 0 && row < cache.count()) + return cache[row]; + return QModelIndex(); +} + +QModelIndex +BookmarkFilterModel::mapFromSource(const QModelIndex &sourceIndex) const +{ + return index(cache.indexOf(sourceIndex), 0, QModelIndex()); +} + +QModelIndex +BookmarkFilterModel::parent(const QModelIndex &child) const +{ + Q_UNUSED(child) + return QModelIndex(); +} + +QModelIndex +BookmarkFilterModel::index(int row, int column, const QModelIndex &index) const +{ + Q_UNUSED(index) + if (row < 0 || column < 0 || cache.count() <= row + || !sourceModel || sourceModel->columnCount() <= column) { + return QModelIndex(); + } + return createIndex(row, 0); +} + +Qt::DropActions +BookmarkFilterModel::supportedDropActions () const +{ + if (sourceModel) + return sourceModel->supportedDropActions(); + return Qt::IgnoreAction; +} + +Qt::ItemFlags +BookmarkFilterModel::flags(const QModelIndex &index) const +{ + if (sourceModel) + return sourceModel->flags(index); + return Qt::NoItemFlags; +} + +QVariant +BookmarkFilterModel::data(const QModelIndex &index, int role) const +{ + if (sourceModel) + return sourceModel->data(mapToSource(index), role); + return QVariant(); +} + +bool +BookmarkFilterModel::setData(const QModelIndex &index, const QVariant &value, + int role) +{ + if (sourceModel) + return sourceModel->setData(mapToSource(index), value, role); + return false; +} + +void +BookmarkFilterModel::filterBookmarks() +{ + if (sourceModel) { + beginResetModel(); + hideBookmarks = true; + setupCache(sourceModel->index(0, 0, QModelIndex())); + endResetModel(); + } +} + +void +BookmarkFilterModel::filterBookmarkFolders() +{ + if (sourceModel) { + beginResetModel(); + hideBookmarks = false; + setupCache(sourceModel->index(0, 0, QModelIndex())); + endResetModel(); + } +} + +void +BookmarkFilterModel::changed(const QModelIndex &topLeft, + const QModelIndex &bottomRight) +{ + emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight)); +} + +void +BookmarkFilterModel::rowsInserted(const QModelIndex &parent, int start, int end) +{ + if (!sourceModel) + return; + + QModelIndex cachePrevious = parent; + if (BookmarkItem *parentItem = sourceModel->itemFromIndex(parent)) { + BookmarkItem *newItem = parentItem->child(start); + + // iterate over tree hirarchie to find the previous folder + for (int i = 0; i < parentItem->childCount(); ++i) { + if (BookmarkItem *child = parentItem->child(i)) { + const QModelIndex &tmp = sourceModel->indexFromItem(child); + if (tmp.data(UserRoleFolder).toBool() && child != newItem) + cachePrevious = tmp; + } + } + + const QModelIndex &newIndex = sourceModel->indexFromItem(newItem); + const bool isFolder = newIndex.data(UserRoleFolder).toBool(); + if ((isFolder && hideBookmarks) || (!isFolder && !hideBookmarks)) { + beginInsertRows(mapFromSource(parent), start, end); + cache.insert(cache.indexOf(cachePrevious) + 1, newIndex); + endInsertRows(); + } + } +} + +void +BookmarkFilterModel::rowsAboutToBeRemoved(const QModelIndex &parent, int start, + int end) +{ + if (!sourceModel) + return; + + if (BookmarkItem *parentItem = sourceModel->itemFromIndex(parent)) { + if (BookmarkItem *child = parentItem->child(start)) { + indexToRemove = sourceModel->indexFromItem(child); + if (cache.contains(indexToRemove)) + beginRemoveRows(mapFromSource(parent), start, end); + } + } +} + +void +BookmarkFilterModel::rowsRemoved(const QModelIndex &/*parent*/, int, int) +{ + if (cache.contains(indexToRemove)) { + cache.removeAll(indexToRemove); + endRemoveRows(); + } +} + +void +BookmarkFilterModel::layoutAboutToBeChanged() +{ + // TODO: ??? +} + +void +BookmarkFilterModel::layoutChanged() +{ + // TODO: ??? +} + +void +BookmarkFilterModel::modelAboutToBeReset() +{ + beginResetModel(); +} + +void +BookmarkFilterModel::modelReset() +{ + if (sourceModel) + setupCache(sourceModel->index(0, 0, QModelIndex())); + endResetModel(); +} + +void +BookmarkFilterModel::setupCache(const QModelIndex &parent) +{ + cache.clear(); + collectItems(parent); +} + +void +BookmarkFilterModel::collectItems(const QModelIndex &parent) +{ + if (parent.isValid()) { + bool isFolder = sourceModel->data(parent, UserRoleFolder).toBool(); + if ((isFolder && hideBookmarks) || (!isFolder && !hideBookmarks)) + cache.append(parent); + + if (sourceModel->hasChildren(parent)) { + for (int i = 0; i < sourceModel->rowCount(parent); ++i) + collectItems(sourceModel->index(i, 0, parent)); + } + } +} + +// -- BookmarkTreeModel + +BookmarkTreeModel::BookmarkTreeModel(QObject *parent) + : QSortFilterProxyModel(parent) +{ +} + +int +BookmarkTreeModel::columnCount(const QModelIndex &parent) const +{ + return qMin(1, QSortFilterProxyModel::columnCount(parent)); +} + +bool +BookmarkTreeModel::filterAcceptsRow(int row, const QModelIndex &parent) const +{ + Q_UNUSED(row) + BookmarkModel *model = qobject_cast<BookmarkModel*> (sourceModel()); + if (model->rowCount(parent) > 0 + && model->data(model->index(row, 0, parent), UserRoleFolder).toBool()) + return true; + return false; +}
\ No newline at end of file diff --git a/tools/assistant/tools/assistant/bookmarkfiltermodel.h b/tools/assistant/tools/assistant/bookmarkfiltermodel.h new file mode 100644 index 0000000..4ea7ab9 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkfiltermodel.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef BOOKMARKFILTERMODEL_H +#define BOOKMARKFILTERMODEL_H + +#include <QtCore/QPersistentModelIndex> + +#include <QtGui/QAbstractProxyModel> +#include <QtGui/QSortFilterProxyModel> + +QT_BEGIN_NAMESPACE + +class BookmarkItem; +class BookmarkModel; + +typedef QList<QPersistentModelIndex> PersistentModelIndexCache; + +class BookmarkFilterModel : public QAbstractProxyModel +{ + Q_OBJECT +public: + explicit BookmarkFilterModel(QObject *parent = 0); + + void setSourceModel(QAbstractItemModel *sourceModel); + + int rowCount(const QModelIndex &index) const; + int columnCount(const QModelIndex &index) const; + + QModelIndex mapToSource(const QModelIndex &proxyIndex) const; + QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; + + QModelIndex parent(const QModelIndex &child) const; + QModelIndex index(int row, int column, const QModelIndex &parent) const; + + Qt::DropActions supportedDropActions () const; + Qt::ItemFlags flags(const QModelIndex &index) const; + + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + + void filterBookmarks(); + void filterBookmarkFolders(); + +private slots: + void changed(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void rowsInserted(const QModelIndex &parent, int start, int end); + void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + void rowsRemoved(const QModelIndex &parent, int start, int end); + void layoutAboutToBeChanged(); + void layoutChanged(); + void modelAboutToBeReset(); + void modelReset(); + +private: + void setupCache(const QModelIndex &parent); + void collectItems(const QModelIndex &parent); + +private: + bool hideBookmarks; + BookmarkModel *sourceModel; + PersistentModelIndexCache cache; + QPersistentModelIndex indexToRemove; +}; + +// -- BookmarkTreeModel + +class BookmarkTreeModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + BookmarkTreeModel(QObject *parent = 0); + int columnCount(const QModelIndex &parent = QModelIndex()) const; + +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; +}; + +QT_END_NAMESPACE + +#endif // BOOKMARKFILTERMODEL_H diff --git a/tools/assistant/tools/assistant/bookmarkitem.cpp b/tools/assistant/tools/assistant/bookmarkitem.cpp new file mode 100644 index 0000000..2e81e38 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkitem.cpp @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "bookmarkitem.h" + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +BookmarkItem::BookmarkItem(const DataVector &data, BookmarkItem *parent) + : m_data(data) + , m_parent(parent) +{ +} + +BookmarkItem::~BookmarkItem() +{ + qDeleteAll(m_children); +} + +BookmarkItem* +BookmarkItem::parent() const +{ + return m_parent; +} + +void +BookmarkItem::setParent(BookmarkItem *parent) +{ + m_parent = parent; +} + +void +BookmarkItem::addChild(BookmarkItem *child) +{ + child->setParent(this); + m_children.append(child); +} + +BookmarkItem* +BookmarkItem::child(int number) const +{ + if (number >= 0 && number < m_children.count()) + return m_children[number]; + return 0; +} + +int BookmarkItem::childCount() const +{ + return m_children.count(); +} + +int BookmarkItem::childNumber() const +{ + if (m_parent) + return m_parent->m_children.indexOf(const_cast<BookmarkItem*>(this)); + return 0; +} + +QVariant +BookmarkItem::data(int column) const +{ + if (column == 0) + return m_data[0]; + + if (column == 1 || column == UserRoleUrl) + return m_data[1]; + + if (column == UserRoleFolder) + return m_data[1].toString() == QLatin1String("Folder"); + + if (column == UserRoleExpanded) + return m_data[2]; + + return QVariant(); +} + +void +BookmarkItem::setData(const DataVector &data) +{ + m_data = data; +} + +bool +BookmarkItem::setData(int column, const QVariant &newValue) +{ + int index = -1; + if (column == 0 || column == 1) + index = column; + + if (column == UserRoleUrl || column == UserRoleFolder) + index = 1; + + if (column == UserRoleExpanded) + index = 2; + + if (index < 0) + return false; + + m_data[index] = newValue; + return true; +} + +bool +BookmarkItem::insertChildren(bool isFolder, int position, int count) +{ + if (position < 0 || position > m_children.size()) + return false; + + for (int row = 0; row < count; ++row) { + m_children.insert(position, new BookmarkItem(DataVector() + << QObject::tr(isFolder ? "New Folder" : "Untitled") + << (isFolder ? "Folder" : "about:blank") << false, this)); + } + + return true; +} + +bool +BookmarkItem::removeChildren(int position, int count) +{ + if (position < 0 || position > m_children.size()) + return false; + + for (int row = 0; row < count; ++row) + delete m_children.takeAt(position); + + return true; +} + +void +BookmarkItem::dumpTree(int indent) const +{ + const QString tree(indent, ' '); + qDebug() << tree + (data(UserRoleFolder).toBool() ? "Folder" : "Bookmark") + << "Label:" << data(0).toString() << "parent:" << m_parent << "this:" + << this; + + foreach (BookmarkItem *item, m_children) + item->dumpTree(indent + 4); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/bookmarkitem.h b/tools/assistant/tools/assistant/bookmarkitem.h new file mode 100644 index 0000000..924a762 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkitem.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BOOKMARKITEM_H +#define BOOKMARKITEM_H + +#include <QtCore/QVariant> +#include <QtCore/QVector> + +QT_BEGIN_NAMESPACE + +enum { + UserRoleUrl = Qt::UserRole + 50, + UserRoleFolder = Qt::UserRole + 100, + UserRoleExpanded = Qt::UserRole + 150 +}; + +typedef QVector<QVariant> DataVector; + +class BookmarkItem +{ +public: + BookmarkItem(const DataVector &data, BookmarkItem *parent = 0); + ~BookmarkItem(); + + BookmarkItem *parent() const; + void setParent(BookmarkItem *parent); + + void addChild(BookmarkItem *child); + BookmarkItem *child(int number) const; + + int childCount() const; + int childNumber() const; + + QVariant data(int column) const; + void setData(const DataVector &data); + bool setData(int column, const QVariant &value); + + bool insertChildren(bool isFolder, int position, int count); + bool removeChildren(int position, int count); + + void dumpTree(int indent) const; + +private: + DataVector m_data; + + BookmarkItem *m_parent; + QList<BookmarkItem*> m_children; +}; + +QT_END_NAMESPACE + +#endif // BOOKMARKITEM_H diff --git a/tools/assistant/tools/assistant/bookmarkmanager.cpp b/tools/assistant/tools/assistant/bookmarkmanager.cpp index 0ce1b9d..4bc7027 100644 --- a/tools/assistant/tools/assistant/bookmarkmanager.cpp +++ b/tools/assistant/tools/assistant/bookmarkmanager.cpp @@ -38,549 +38,214 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "tracer.h" #include "bookmarkmanager.h" +#include "bookmarkmanagerwidget.h" +#include "bookmarkdialog.h" +#include "bookmarkfiltermodel.h" +#include "bookmarkitem.h" +#include "bookmarkmodel.h" #include "centralwidget.h" +#include "helpenginewrapper.h" #include <QtGui/QMenu> -#include <QtGui/QIcon> -#include <QtGui/QStyle> -#include <QtGui/QLabel> -#include <QtGui/QLayout> -#include <QtCore/QEvent> -#include <QtGui/QComboBox> #include <QtGui/QKeyEvent> -#include <QtGui/QLineEdit> #include <QtGui/QMessageBox> -#include <QtGui/QHeaderView> -#include <QtGui/QToolButton> -#include <QtGui/QPushButton> -#include <QtGui/QApplication> -#include <QtHelp/QHelpEngineCore> -#include <QtGui/QDialogButtonBox> #include <QtGui/QSortFilterProxyModel> QT_BEGIN_NAMESPACE -BookmarkDialog::BookmarkDialog(BookmarkManager *manager, const QString &title, - const QString &url, QWidget *parent) - : QDialog(parent) - , m_url(url) - , m_title(title) - , bookmarkManager(manager) -{ - ui.setupUi(this); - - installEventFilter(this); - ui.treeView->installEventFilter(this); - ui.treeView->viewport()->installEventFilter(this); - - ui.bookmarkEdit->setText(title); - ui.newFolderButton->setVisible(false); - ui.buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); - ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders()); - - proxyModel = new QSortFilterProxyModel(this); - proxyModel->setFilterKeyColumn(0); - proxyModel->setDynamicSortFilter(true); - proxyModel->setFilterRole(Qt::UserRole + 10); - proxyModel->setSourceModel(bookmarkManager->treeBookmarkModel()); - proxyModel->setFilterRegExp(QRegExp(QLatin1String("Folder"), - Qt::CaseSensitive, QRegExp::FixedString)); - ui.treeView->setModel(proxyModel); - - ui.treeView->expandAll(); - ui.treeView->setVisible(false); - ui.treeView->header()->setVisible(false); - ui.treeView->setContextMenuPolicy(Qt::CustomContextMenu); - - connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(addAccepted())); - connect(ui.newFolderButton, SIGNAL(clicked()), this, SLOT(addNewFolder())); - connect(ui.toolButton, SIGNAL(clicked()), this, SLOT(toolButtonClicked())); - connect(ui.bookmarkEdit, SIGNAL(textChanged(QString)), this, - SLOT(textChanged(QString))); - - connect(bookmarkManager->treeBookmarkModel(), - SIGNAL(itemChanged(QStandardItem*)), - this, SLOT(itemChanged(QStandardItem*))); - - connect(ui.bookmarkFolders, SIGNAL(currentIndexChanged(QString)), this, - SLOT(selectBookmarkFolder(QString))); - - connect(ui.treeView, SIGNAL(customContextMenuRequested(QPoint)), this, - SLOT(customContextMenuRequested(QPoint))); - - connect(ui.treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, - QModelIndex)), this, SLOT(currentChanged(QModelIndex))); -} - -BookmarkDialog::~BookmarkDialog() -{ -} +// -- BookmarkManager::BookmarkWidget -void BookmarkDialog::addAccepted() +void BookmarkManager::BookmarkWidget::focusInEvent(QFocusEvent *event) { - QItemSelectionModel *model = ui.treeView->selectionModel(); - const QModelIndexList &list = model->selection().indexes(); + TRACE_OBJ + if (event->reason() != Qt::MouseFocusReason) { + ui.lineEdit->selectAll(); + ui.lineEdit->setFocus(); - QModelIndex index; - if (!list.isEmpty()) - index = proxyModel->mapToSource(list.at(0)); - - bookmarkManager->addNewBookmark(index, ui.bookmarkEdit->text(), m_url); - accept(); -} - -void BookmarkDialog::addNewFolder() -{ - QItemSelectionModel *model = ui.treeView->selectionModel(); - const QModelIndexList &list = model->selection().indexes(); - - QModelIndex index; - if (!list.isEmpty()) - index = list.at(0); - - QModelIndex newFolder = - bookmarkManager->addNewFolder(proxyModel->mapToSource(index)); - if (newFolder.isValid()) { - ui.treeView->expand(index); - const QModelIndex &index = proxyModel->mapFromSource(newFolder); - model->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); - - ui.bookmarkFolders->clear(); - ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders()); - - const QString &name = index.data().toString(); - ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(name)); + // force the focus in event on bookmark manager + emit focusInEvent(); } - ui.treeView->setFocus(); } -void BookmarkDialog::toolButtonClicked() -{ - bool visible = !ui.treeView->isVisible(); - ui.treeView->setVisible(visible); - ui.newFolderButton->setVisible(visible); +// -- BookmarkManager::BookmarkTreeView - if (visible) { - resize(QSize(width(), 400)); - ui.toolButton->setText(QLatin1String("-")); - } else { - resize(width(), minimumHeight()); - ui.toolButton->setText(QLatin1String("+")); - } -} - -void BookmarkDialog::itemChanged(QStandardItem *item) +BookmarkManager::BookmarkTreeView::BookmarkTreeView(QWidget *parent) + : QTreeView(parent) { - if (renameItem != item) { - renameItem = item; - oldText = item->text(); - return; - } + TRACE_OBJ + setAcceptDrops(true); + setDragEnabled(true); + setAutoExpandDelay(1000); + setUniformRowHeights(true); + setDropIndicatorShown(true); + setExpandsOnDoubleClick(true); - if (item->text() != oldText) { - ui.bookmarkFolders->clear(); - ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders()); + connect(this, SIGNAL(expanded(QModelIndex)), this, + SLOT(setExpandedData(QModelIndex))); + connect(this, SIGNAL(collapsed(QModelIndex)), this, + SLOT(setExpandedData(QModelIndex))); - QString name = tr("Bookmarks"); - const QModelIndex &index = ui.treeView->currentIndex(); - if (index.isValid()) - name = index.data().toString(); - ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(name)); - } } -void BookmarkDialog::textChanged(const QString &string) +void BookmarkManager::BookmarkTreeView::subclassKeyPressEvent(QKeyEvent *event) { - ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!string.isEmpty()); + TRACE_OBJ + QTreeView::keyPressEvent(event); } -void BookmarkDialog::selectBookmarkFolder(const QString &folderName) +void BookmarkManager::BookmarkTreeView::setExpandedData(const QModelIndex &index) { - if (folderName.isEmpty()) - return; - - if (folderName == tr("Bookmarks")) { - ui.treeView->clearSelection(); - return; - } - - QStandardItemModel *model = bookmarkManager->treeBookmarkModel(); - QList<QStandardItem*> list = model->findItems(folderName, - Qt::MatchCaseSensitive | Qt::MatchRecursive, 0); - if (!list.isEmpty()) { - const QModelIndex &index = model->indexFromItem(list.at(0)); - QItemSelectionModel *model = ui.treeView->selectionModel(); - if (model) { - model->setCurrentIndex(proxyModel->mapFromSource(index), - QItemSelectionModel::ClearAndSelect); - } - } + TRACE_OBJ + if (BookmarkModel *treeModel = qobject_cast<BookmarkModel*> (model())) + treeModel->setData(index, isExpanded(index), UserRoleExpanded); } -void BookmarkDialog::customContextMenuRequested(const QPoint &point) -{ - QModelIndex index = ui.treeView->indexAt(point); - if (!index.isValid()) - return; - - QMenu menu(QLatin1String(""), this); +// -- BookmarkManager - QAction *removeItem = menu.addAction(tr("Delete Folder")); - QAction *renameItem = menu.addAction(tr("Rename Folder")); - - QAction *picked = menu.exec(ui.treeView->mapToGlobal(point)); - if (!picked) - return; - - const QModelIndex &proxyIndex = proxyModel->mapToSource(index); - if (picked == removeItem) { - bookmarkManager->removeBookmarkItem(ui.treeView, proxyIndex); - ui.bookmarkFolders->clear(); - ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders()); - - QString name = tr("Bookmarks"); - index = ui.treeView->currentIndex(); - if (index.isValid()) - name = index.data().toString(); - ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(name)); - } - else if (picked == renameItem) { - BookmarkModel *model = bookmarkManager->treeBookmarkModel(); - if (QStandardItem *item = model->itemFromIndex(proxyIndex)) { - item->setEditable(true); - ui.treeView->edit(index); - item->setEditable(false); - } - } -} +QMutex BookmarkManager::mutex; +BookmarkManager* BookmarkManager::bookmarkManager = 0; -void BookmarkDialog::currentChanged(const QModelIndex ¤t) -{ - QString text = tr("Bookmarks"); - if (current.isValid()) - text = current.data().toString(); - ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(text)); -} +// -- public -bool BookmarkDialog::eventFilter(QObject *object, QEvent *e) +BookmarkManager* BookmarkManager::instance() { - if (object != ui.treeView && object != ui.treeView->viewport()) - return QWidget::eventFilter(object, e); - - if (e->type() == QEvent::KeyPress) { - QKeyEvent *ke = static_cast<QKeyEvent*>(e); - switch (ke->key()) { - case Qt::Key_F2: { - const QModelIndex &index = ui.treeView->currentIndex(); - const QModelIndex &source = proxyModel->mapToSource(index); - QStandardItem *item = - bookmarkManager->treeBookmarkModel()->itemFromIndex(source); - if (item) { - item->setEditable(true); - ui.treeView->edit(index); - item->setEditable(false); - } - } break; - - case Qt::Key_Delete: { - const QModelIndex &index = ui.treeView->currentIndex(); - bookmarkManager->removeBookmarkItem(ui.treeView, - proxyModel->mapToSource(index)); - ui.bookmarkFolders->clear(); - ui.bookmarkFolders->addItems(bookmarkManager->bookmarkFolders()); - - QString name = tr("Bookmarks"); - if (index.isValid()) - name = index.data().toString(); - ui.bookmarkFolders->setCurrentIndex(ui.bookmarkFolders->findText(name)); - } break; - - default: - break; - } + TRACE_OBJ + if (!bookmarkManager) { + QMutexLocker _(&mutex); + if (!bookmarkManager) + bookmarkManager = new BookmarkManager(); } - - return QObject::eventFilter(object, e); + return bookmarkManager; } - -// #pragma mark -- BookmarkWidget - - -BookmarkWidget::BookmarkWidget(BookmarkManager *manager, QWidget *parent, - bool showButtons) - : QWidget(parent) - , addButton(0) - , removeButton(0) - , bookmarkManager(manager) +void BookmarkManager::destroy() { - setup(showButtons); - - installEventFilter(this); - treeView->installEventFilter(this); - treeView->viewport()->installEventFilter(this); + TRACE_OBJ + delete bookmarkManager; + bookmarkManager = 0; } -BookmarkWidget::~BookmarkWidget() +QWidget* BookmarkManager::bookmarkDockWidget() const { + TRACE_OBJ + if (bookmarkWidget) + return bookmarkWidget; + return 0; } -void BookmarkWidget::removeClicked() +void BookmarkManager::takeBookmarksMenu(QMenu* menu) { - const QModelIndex &index = treeView->currentIndex(); - if (searchField->text().isEmpty()) { - bookmarkManager->removeBookmarkItem(treeView, - filterBookmarkModel->mapToSource(index)); - } + TRACE_OBJ + bookmarkMenu = menu; + refeshBookmarkMenu(); } -void BookmarkWidget::filterChanged() -{ - bool searchBookmarks = searchField->text().isEmpty(); - if (!searchBookmarks) { - regExp.setPattern(searchField->text()); - filterBookmarkModel->setSourceModel(bookmarkManager->listBookmarkModel()); - } else { - regExp.setPattern(QLatin1String("")); - filterBookmarkModel->setSourceModel(bookmarkManager->treeBookmarkModel()); - } +// -- public slots - if (addButton) - addButton->setEnabled(searchBookmarks); - - if (removeButton) - removeButton->setEnabled(searchBookmarks); - - filterBookmarkModel->setFilterRegExp(regExp); - - const QModelIndex &index = treeView->indexAt(QPoint(1, 1)); - if (index.isValid()) - treeView->setCurrentIndex(index); - - if (searchBookmarks) - expandItems(); -} - -void BookmarkWidget::expand(const QModelIndex &index) +void BookmarkManager::addBookmark(const QString &title, const QString &url) { - const QModelIndex &source = filterBookmarkModel->mapToSource(index); - QStandardItem *item = - bookmarkManager->treeBookmarkModel()->itemFromIndex(source); - if (item) - item->setData(treeView->isExpanded(index), Qt::UserRole + 11); + TRACE_OBJ + showBookmarkDialog(title.isEmpty() ? tr("Untitled") : title, + url.isEmpty() ? QLatin1String("about:blank") : url); } -void BookmarkWidget::activated(const QModelIndex &index) -{ - if (!index.isValid()) - return; +// -- private - QString data = index.data(Qt::UserRole + 10).toString(); - if (data != QLatin1String("Folder")) - emit requestShowLink(data); -} - -void BookmarkWidget::customContextMenuRequested(const QPoint &point) +BookmarkManager::BookmarkManager() + : typeAndSearch(false) + , bookmarkMenu(0) + , bookmarkModel(new BookmarkModel) + , bookmarkWidget(new BookmarkWidget) + , bookmarkTreeView(new BookmarkTreeView) + , bookmarkManagerWidget(0) { - QModelIndex index = treeView->indexAt(point); - if (!index.isValid()) - return; + TRACE_OBJ + bookmarkWidget->installEventFilter(this); + connect(bookmarkWidget->ui.add, SIGNAL(clicked()), this, + SLOT(addBookmark())); + connect(bookmarkWidget->ui.remove, SIGNAL(clicked()), this, + SLOT(removeBookmark())); + connect(bookmarkWidget->ui.lineEdit, SIGNAL(textChanged(QString)), this, + SLOT(textChanged(QString))); + connect(bookmarkWidget, SIGNAL(focusInEvent()), this, SLOT(focusInEvent())); - QAction *showItem = 0; - QAction *removeItem = 0; - QAction *renameItem = 0; - QAction *showItemNewTab = 0; - - QMenu menu(QLatin1String(""), this); - QString data = index.data(Qt::UserRole + 10).toString(); - if (data == QLatin1String("Folder")) { - removeItem = menu.addAction(tr("Delete Folder")); - renameItem = menu.addAction(tr("Rename Folder")); - } else { - showItem = menu.addAction(tr("Show Bookmark")); - showItemNewTab = menu.addAction(tr("Show Bookmark in New Tab")); - if (searchField->text().isEmpty()) { - menu.addSeparator(); - removeItem = menu.addAction(tr("Delete Bookmark")); - renameItem = menu.addAction(tr("Rename Bookmark")); - } - } + bookmarkTreeView->setModel(bookmarkModel); + bookmarkTreeView->installEventFilter(this); + bookmarkTreeView->viewport()->installEventFilter(this); + bookmarkTreeView->setContextMenuPolicy(Qt::CustomContextMenu); + bookmarkWidget->ui.stackedWidget->addWidget(bookmarkTreeView); - QAction *pickedAction = menu.exec(treeView->mapToGlobal(point)); - if (!pickedAction) - return; + connect(bookmarkTreeView, SIGNAL(activated(QModelIndex)), this, + SLOT(setSourceFromIndex(QModelIndex))); + connect(bookmarkTreeView, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(customContextMenuRequested(QPoint))); - if (pickedAction == showItem) { - emit requestShowLink(data); - } - else if (pickedAction == showItemNewTab) { - CentralWidget::instance()->setSourceInNewTab(data); - } - else if (pickedAction == removeItem) { - bookmarkManager->removeBookmarkItem(treeView, - filterBookmarkModel->mapToSource(index)); - } - else if (pickedAction == renameItem) { - const QModelIndex &source = filterBookmarkModel->mapToSource(index); - QStandardItem *item = - bookmarkManager->treeBookmarkModel()->itemFromIndex(source); - if (item) { - item->setEditable(true); - treeView->edit(index); - item->setEditable(false); - } - } + connect(&HelpEngineWrapper::instance(), SIGNAL(setupFinished()), this, + SLOT(setupFinished())); + connect(bookmarkModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, + SLOT(refeshBookmarkMenu())); + connect(bookmarkModel, SIGNAL(rowsInserted(QModelIndex, int, int)), this, + SLOT(refeshBookmarkMenu())); + connect(bookmarkModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, + SLOT(refeshBookmarkMenu())); } -void BookmarkWidget::setup(bool showButtons) +BookmarkManager::~BookmarkManager() { - regExp.setPatternSyntax(QRegExp::FixedString); - regExp.setCaseSensitivity(Qt::CaseInsensitive); - - QLayout *vlayout = new QVBoxLayout(this); - vlayout->setMargin(4); - - QLabel *label = new QLabel(tr("Filter:"), this); - vlayout->addWidget(label); - - searchField = new QLineEdit(this); - vlayout->addWidget(searchField); - connect(searchField, SIGNAL(textChanged(QString)), this, - SLOT(filterChanged())); - - treeView = new TreeView(this); - vlayout->addWidget(treeView); - -#ifdef Q_OS_MAC -# define SYSTEM "mac" -#else -# define SYSTEM "win" -#endif - - if (showButtons) { - QLayout *hlayout = new QHBoxLayout(); - vlayout->addItem(hlayout); - - hlayout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding)); - - addButton = new QToolButton(this); - addButton->setText(tr("Add")); - addButton->setIcon(QIcon(QLatin1String(":/trolltech/assistant/images/" - SYSTEM "/addtab.png"))); - addButton->setAutoRaise(true); - addButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - hlayout->addWidget(addButton); - connect(addButton, SIGNAL(clicked()), this, SIGNAL(addBookmark())); - - removeButton = new QToolButton(this); - removeButton->setText(tr("Remove")); - removeButton->setIcon(QIcon(QLatin1String(":/trolltech/assistant/images/" - SYSTEM "/closetab.png"))); - removeButton->setAutoRaise(true); - removeButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - hlayout->addWidget(removeButton); - connect(removeButton, SIGNAL(clicked()), this, SLOT(removeClicked())); - } - - filterBookmarkModel = new QSortFilterProxyModel(this); - treeView->setModel(filterBookmarkModel); - - treeView->setDragEnabled(true); - treeView->setAcceptDrops(true); - treeView->setAutoExpandDelay(1000); - treeView->setDropIndicatorShown(true); - treeView->header()->setVisible(false); - treeView->setContextMenuPolicy(Qt::CustomContextMenu); - - connect(treeView, SIGNAL(expanded(QModelIndex)), this, - SLOT(expand(QModelIndex))); - connect(treeView, SIGNAL(collapsed(QModelIndex)), this, - SLOT(expand(QModelIndex))); - connect(treeView, SIGNAL(activated(QModelIndex)), this, - SLOT(activated(QModelIndex))); - connect(treeView, SIGNAL(customContextMenuRequested(QPoint)), - this, SLOT(customContextMenuRequested(QPoint))); - - filterBookmarkModel->setFilterKeyColumn(0); - filterBookmarkModel->setDynamicSortFilter(true); - filterBookmarkModel->setSourceModel(bookmarkManager->treeBookmarkModel()); - - expandItems(); + TRACE_OBJ + delete bookmarkManagerWidget; + HelpEngineWrapper::instance().setBookmarks(bookmarkModel->bookmarks()); + delete bookmarkModel; } -void BookmarkWidget::expandItems() +void BookmarkManager::removeItem(const QModelIndex &index) { - QStandardItemModel *model = bookmarkManager->treeBookmarkModel(); - QList<QStandardItem*>list = model->findItems(QLatin1String("*"), - Qt::MatchWildcard | Qt::MatchRecursive, 0); - foreach (const QStandardItem *item, list) { - const QModelIndex &index = model->indexFromItem(item); - treeView->setExpanded(filterBookmarkModel->mapFromSource(index), - item->data(Qt::UserRole + 11).toBool()); + TRACE_OBJ + QModelIndex current = index; + if (typeAndSearch) { // need to map because of proxy + current = typeAndSearchModel->mapToSource(current); + current = bookmarkFilterModel->mapToSource(current); + } else if (!bookmarkModel->parent(index).isValid()) { + return; // check if we should delete the "Bookmarks Menu", bail } -} - -void BookmarkWidget::focusInEvent(QFocusEvent *e) -{ - if (e->reason() != Qt::MouseFocusReason) { - searchField->selectAll(); - searchField->setFocus(); - - QModelIndex index = treeView->indexAt(QPoint(1, 1)); - if (index.isValid()) - treeView->setCurrentIndex(index); + if (bookmarkModel->hasChildren(current)) { + int value = QMessageBox::question(bookmarkTreeView, tr("Remove"), + tr("You are going to delete a Folder, this will also<br>" + "remove it's content. Are you sure to continue?"), + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); + if (value == QMessageBox::Cancel) + return; } + bookmarkModel->removeItem(current); } -bool BookmarkWidget::eventFilter(QObject *object, QEvent *e) +bool BookmarkManager::eventFilter(QObject *object, QEvent *event) { - if (object != this && object != treeView - && object != treeView->viewport()) { - return QWidget::eventFilter(object, e); - } + if (object != bookmarkTreeView && object != bookmarkTreeView->viewport() + && object != bookmarkWidget) + return QObject::eventFilter(object, event); - if (e->type() == QEvent::KeyPress) { - QKeyEvent *ke = static_cast<QKeyEvent*>(e); - const bool tree = object == treeView || object == treeView->viewport(); + TRACE_OBJ + const bool isWidget = object == bookmarkWidget; + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(event); switch (ke->key()) { case Qt::Key_F2: { - const QModelIndex &index = treeView->currentIndex(); - const QModelIndex &src = filterBookmarkModel->mapToSource(index); - if (tree && searchField->text().isEmpty()) { - if (QStandardItem *item = bookmarkManager->treeBookmarkModel() - ->itemFromIndex(src)) { - item->setEditable(true); - treeView->edit(index); - item->setEditable(false); - } - } - } break; - - case Qt::Key_Enter: { - case Qt::Key_Return: - if (tree) { - const QString &data = treeView->selectionModel()->currentIndex() - .data(Qt::UserRole + 10).toString(); - if (!data.isEmpty() && data != QLatin1String("Folder")) - emit requestShowLink(data); - } + renameBookmark(bookmarkTreeView->currentIndex()); } break; case Qt::Key_Delete: { - const QModelIndex &index = treeView->currentIndex(); - const QModelIndex &src = filterBookmarkModel->mapToSource(index); - if (tree && searchField->text().isEmpty()) - bookmarkManager->removeBookmarkItem(treeView, src); + removeItem(bookmarkTreeView->currentIndex()); } break; - case Qt::Key_Up: { + case Qt::Key_Up: { // needs event filter on widget case Qt::Key_Down: - if (!tree) - treeView->subclassKeyPressEvent(ke); + if (isWidget) + bookmarkTreeView->subclassKeyPressEvent(ke); } break; case Qt::Key_Escape: { @@ -591,324 +256,233 @@ bool BookmarkWidget::eventFilter(QObject *object, QEvent *e) } } - if (e->type() == QEvent::MouseButtonRelease) { - QMouseEvent *me = static_cast<QMouseEvent*>(e); - bool controlPressed = me->modifiers() & Qt::ControlModifier; - if(((me->button() == Qt::LeftButton) && controlPressed) - || (me->button() == Qt::MidButton)) { - const QModelIndex &index = treeView->currentIndex(); - const QString &data = index.data(Qt::UserRole + 10).toString(); - if (!data.isEmpty() && data != QLatin1String("Folder")) - CentralWidget::instance()->setSourceInNewTab(data); + if (event->type() == QEvent::MouseButtonRelease && !isWidget) { + QMouseEvent *me = static_cast<QMouseEvent*>(event); + switch (me->button()) { + case Qt::LeftButton: { + if (me->modifiers() & Qt::ControlModifier) + setSourceFromIndex(bookmarkTreeView->currentIndex(), true); + } break; + + case Qt::MidButton: { + setSourceFromIndex(bookmarkTreeView->currentIndex(), true); + } break; + + default: break; } } - return QWidget::eventFilter(object, e); + return QObject::eventFilter(object, event); } - -// #pragma mark -- BookmarkModel - - -BookmarkModel::BookmarkModel(int rows, int columns, QObject *parent) - : QStandardItemModel(rows, columns, parent) +void BookmarkManager::buildBookmarksMenu(const QModelIndex &index, QMenu* menu) { -} + TRACE_OBJ + if (!index.isValid()) + return; -BookmarkModel::~BookmarkModel() -{ + const QString &text = index.data().toString(); + const QIcon &icon = qVariantValue<QIcon>(index.data(Qt::DecorationRole)); + if (index.data(UserRoleFolder).toBool()) { + if (QMenu* subMenu = menu->addMenu(icon, text)) { + for (int i = 0; i < bookmarkModel->rowCount(index); ++i) + buildBookmarksMenu(bookmarkModel->index(i, 0, index), subMenu); + } + } else { + QAction *action = menu->addAction(icon, text); + action->setData(index.data(UserRoleUrl).toString()); + } } -Qt::DropActions BookmarkModel::supportedDropActions() const +void BookmarkManager::showBookmarkDialog(const QString &name, const QString &url) { - return Qt::MoveAction; + TRACE_OBJ + BookmarkDialog dialog(bookmarkModel, name, url, bookmarkTreeView); + dialog.exec(); } -Qt::ItemFlags BookmarkModel::flags(const QModelIndex &index) const -{ - Qt::ItemFlags defaultFlags = QStandardItemModel::flags(index); - if ((!index.isValid()) // can only happen for the invisible root item - || index.data(Qt::UserRole + 10).toString() == QLatin1String("Folder")) - return (Qt::ItemIsDropEnabled | defaultFlags) &~ Qt::ItemIsDragEnabled; +// -- private slots - return (Qt::ItemIsDragEnabled | defaultFlags) &~ Qt::ItemIsDropEnabled; -} +void BookmarkManager::setupFinished() +{ + TRACE_OBJ + bookmarkModel->setBookmarks(HelpEngineWrapper::instance().bookmarks()); + bookmarkModel->expandFoldersIfNeeeded(bookmarkTreeView); + refeshBookmarkMenu(); -// #pragma mark -- BookmarkManager + bookmarkTreeView->hideColumn(1); + bookmarkTreeView->header()->setVisible(false); + bookmarkTreeView->header()->setStretchLastSection(true); + bookmarkFilterModel = new BookmarkFilterModel(this); + bookmarkFilterModel->setSourceModel(bookmarkModel); + bookmarkFilterModel->filterBookmarkFolders(); -BookmarkManager::BookmarkManager(QHelpEngineCore *_helpEngine) - : treeModel(new BookmarkModel(0, 1, this)) - , listModel(new BookmarkModel(0, 1, this)) - , renameItem(0) - , helpEngine(_helpEngine) -{ - folderIcon = QApplication::style()->standardIcon(QStyle::SP_DirClosedIcon); - - connect(treeModel, SIGNAL(itemChanged(QStandardItem*)), this, - SLOT(itemChanged(QStandardItem*))); - connect(treeModel, SIGNAL(itemChanged(QStandardItem*)), this, - SIGNAL(bookmarksChanged())); - connect(treeModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SIGNAL(bookmarksChanged())); + typeAndSearchModel = new QSortFilterProxyModel(this); + typeAndSearchModel->setDynamicSortFilter(true); + typeAndSearchModel->setSourceModel(bookmarkFilterModel); } -BookmarkManager::~BookmarkManager() +void BookmarkManager::addBookmark() { - treeModel->clear(); - listModel->clear(); + TRACE_OBJ + if (CentralWidget *widget = CentralWidget::instance()) + addBookmark(widget->currentTitle(), widget->currentSource().toString()); } -BookmarkModel* BookmarkManager::treeBookmarkModel() +void BookmarkManager::removeBookmark() { - return treeModel; + TRACE_OBJ + removeItem(bookmarkTreeView->currentIndex()); } -BookmarkModel* BookmarkManager::listBookmarkModel() +void BookmarkManager::manageBookmarks() { - return listModel; + TRACE_OBJ + if (bookmarkManagerWidget == 0) { + bookmarkManagerWidget = new BookmarkManagerWidget(bookmarkModel); + connect(bookmarkManagerWidget, SIGNAL(setSource(QUrl)), this, + SIGNAL(setSource(QUrl))); + connect(bookmarkManagerWidget, SIGNAL(setSourceInNewTab(QUrl)) + , this, SIGNAL(setSourceInNewTab(QUrl))); + connect(bookmarkManagerWidget, SIGNAL(managerWidgetAboutToClose()) + , this, SLOT(managerWidgetAboutToClose())); + } + bookmarkManagerWidget->show(); + bookmarkManagerWidget->raise(); } -void BookmarkManager::saveBookmarks() +void BookmarkManager::refeshBookmarkMenu() { - QByteArray bookmarks; - QDataStream stream(&bookmarks, QIODevice::WriteOnly); + TRACE_OBJ + if (!bookmarkMenu) + return; - readBookmarksRecursive(treeModel->invisibleRootItem(), stream, 0); - helpEngine->setCustomValue(QLatin1String("Bookmarks"), bookmarks); -} + bookmarkMenu->clear(); -QStringList BookmarkManager::bookmarkFolders() const -{ - QStringList folders(tr("Bookmarks")); + bookmarkMenu->addAction(tr("Manage Bookmarks..."), this, + SLOT(manageBookmarks())); + bookmarkMenu->addAction(QIcon::fromTheme("bookmark-new"), + tr("Add Bookmark..."), this, SLOT(addBookmark()), + QKeySequence(tr("Ctrl+D"))); + bookmarkMenu->addSeparator(); - QList<QStandardItem*>list = treeModel->findItems(QLatin1String("*"), - Qt::MatchWildcard | Qt::MatchRecursive, 0); - - QString data; - foreach (const QStandardItem *item, list) { - data = item->data(Qt::UserRole + 10).toString(); - if (data == QLatin1String("Folder")) - folders << item->data(Qt::DisplayRole).toString(); - } - return folders; -} + const QModelIndex &root = bookmarkModel->index(0, 0, QModelIndex()); + for (int i = 0; i < bookmarkModel->rowCount(root); ++i) + buildBookmarksMenu(bookmarkModel->index(i, 0, root), bookmarkMenu); -QModelIndex BookmarkManager::addNewFolder(const QModelIndex &index) -{ - QStandardItem *item = new QStandardItem(uniqueFolderName()); - item->setEditable(false); - item->setData(false, Qt::UserRole + 11); - item->setData(QLatin1String("Folder"), Qt::UserRole + 10); - item->setIcon(QApplication::style()->standardIcon(QStyle::SP_DirClosedIcon)); - - if (index.isValid()) { - treeModel->itemFromIndex(index)->appendRow(item); - } else { - treeModel->appendRow(item); - } - return treeModel->indexFromItem(item); + connect(bookmarkMenu, SIGNAL(triggered(QAction*)), this, + SLOT(setSourceFromAction(QAction*))); } -void BookmarkManager::removeBookmarkItem(QTreeView *treeView, - const QModelIndex &index) +void BookmarkManager::renameBookmark(const QModelIndex &index) { - QStandardItem *item = treeModel->itemFromIndex(index); - if (item) { - QString data = index.data(Qt::UserRole + 10).toString(); - if (data == QLatin1String("Folder") && item->rowCount() > 0) { - int value = QMessageBox::question(treeView, tr("Remove"), - tr("You are going to delete a Folder, this will also<br>" - "remove it's content. Are you sure to continue?"), - QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); - - if (value == QMessageBox::Cancel) - return; - } - - if (data != QLatin1String("Folder")) { - QList<QStandardItem*>itemList = listModel->findItems(item->text()); - foreach (const QStandardItem *i, itemList) { - if (i->data(Qt::UserRole + 10) == data) { - listModel->removeRow(i->row()); - break; - } - } - } else { - removeBookmarkFolderItems(item); - } - treeModel->removeRow(item->row(), index.parent()); - } -} + // check if we should rename the "Bookmarks Menu", bail + if (!typeAndSearch && !bookmarkModel->parent(index).isValid()) + return; -void BookmarkManager::showBookmarkDialog(QWidget *parent, const QString &name, - const QString &url) -{ - BookmarkDialog dialog(this, name, url, parent); - dialog.exec(); + bookmarkModel->setItemsEditable(true); + bookmarkTreeView->edit(index); + bookmarkModel->setItemsEditable(false); } -void BookmarkManager::addNewBookmark(const QModelIndex &index, - const QString &name, const QString &url) +void BookmarkManager::setSourceFromAction(QAction *action) { - QStandardItem *item = new QStandardItem(name); - item->setEditable(false); - item->setData(false, Qt::UserRole + 11); - item->setData(url, Qt::UserRole + 10); + TRACE_OBJ + const QVariant &data = action->data(); - if (index.isValid()) - treeModel->itemFromIndex(index)->appendRow(item); - else - treeModel->appendRow(item); - listModel->appendRow(item->clone()); - emit bookmarksChanged(); + if (data.canConvert<QUrl>()) + emit setSource(data.toUrl()); } -void BookmarkManager::fillBookmarkMenu(QMenu *menu) +void BookmarkManager::setSourceFromIndex(const QModelIndex &index, bool newTab) { - if (!menu || !treeModel) - return; + TRACE_OBJ + QAbstractItemModel *base = bookmarkModel; + if (typeAndSearch) + base = typeAndSearchModel; - map.clear(); - fillBookmarkMenu(menu, treeModel->invisibleRootItem()); -} - -void BookmarkManager::fillBookmarkMenu(QMenu *menu, QStandardItem *root) -{ - for (int i = 0; i < root->rowCount(); ++i) { - QStandardItem *item = root->child(i); - if (item && item->data(Qt::UserRole + 10) - .toString() == QLatin1String("Folder")) { - QMenu* newMenu = menu->addMenu(folderIcon, item->text()); - if (item->rowCount() > 0) - fillBookmarkMenu(newMenu, item); - } else { - map.insert(menu->addAction(item->text()), item->index()); - } - } -} + if (base->data(index, UserRoleFolder).toBool()) + return; -QUrl BookmarkManager::urlForAction(QAction* action) const -{ - if (map.contains(action)) { - const QModelIndex &index = map.value(action); - if (QStandardItem* item = treeModel->itemFromIndex(index)) - return QUrl(item->data(Qt::UserRole + 10).toString()); + const QVariant &data = base->data(index, UserRoleUrl); + if (data.canConvert<QUrl>()) { + if (newTab) + emit setSourceInNewTab(data.toUrl()); + else + emit setSource(data.toUrl()); } - return QUrl(); } -void BookmarkManager::itemChanged(QStandardItem *item) +void BookmarkManager::customContextMenuRequested(const QPoint &point) { - if (renameItem != item) { - renameItem = item; - oldText = item->text(); + TRACE_OBJ + QModelIndex index = bookmarkTreeView->indexAt(point); + if (!index.isValid()) return; - } - if (item->text() != oldText) { - if (item->data(Qt::UserRole + 10).toString() != QLatin1String("Folder")) { - QList<QStandardItem*>itemList = listModel->findItems(oldText); - if (itemList.count() > 0) - itemList.at(0)->setText(item->text()); - } - } -} + // check if we should open the menu on "Bookmarks Menu", bail + if (!typeAndSearch && !bookmarkModel->parent(index).isValid()) + return; -void BookmarkManager::setupBookmarkModels() -{ - treeModel->clear(); - listModel->clear(); - - qint32 depth; - bool expanded; - QString name, type; - QList<int> lastDepths; - QList<QStandardItem*> parents; - - QByteArray ba = - helpEngine->customValue(QLatin1String("Bookmarks")).toByteArray(); - QDataStream stream(ba); - while (!stream.atEnd()) { - stream >> depth >> name >> type >> expanded; - - QStandardItem *item = new QStandardItem(name); - item->setEditable(false); - item->setData(type, Qt::UserRole + 10); - item->setData(expanded, Qt::UserRole + 11); - if (depth == 0) { - parents.clear(); lastDepths.clear(); - treeModel->appendRow(item); - parents << item; lastDepths << depth; - } else { - if (depth <= lastDepths.last()) { - while (depth <= lastDepths.last() && parents.count() > 0) { - parents.pop_back(); lastDepths.pop_back(); - } - } - parents.last()->appendRow(item); - if (type == QLatin1String("Folder")) { - parents << item; lastDepths << depth; - } - } + QAction *remove = 0; + QAction *rename = 0; + QAction *showItem = 0; + QAction *showItemInNewTab = 0; - if (type == QLatin1String("Folder")) - item->setIcon(folderIcon); - else - listModel->appendRow(item->clone()); + QMenu menu(QLatin1String("")); + if (!typeAndSearch && bookmarkModel->data(index, UserRoleFolder).toBool()) { + remove = menu.addAction(tr("Delete Folder")); + rename = menu.addAction(tr("Rename Folder")); + } else { + showItem = menu.addAction(tr("Show Bookmark")); + showItemInNewTab = menu.addAction(tr("Show Bookmark in New Tab")); + menu.addSeparator(); + remove = menu.addAction(tr("Delete Bookmark")); + rename = menu.addAction(tr("Rename Bookmark")); } + + QAction *pickedAction = menu.exec(bookmarkTreeView->mapToGlobal(point)); + if (pickedAction == rename) + renameBookmark(index); + else if (pickedAction == remove) + removeItem(index); + else if (pickedAction == showItem || pickedAction == showItemInNewTab) + setSourceFromIndex(index, pickedAction == showItemInNewTab); } -QString BookmarkManager::uniqueFolderName() const +void BookmarkManager::focusInEvent() { - QString folderName = tr("New Folder"); - QList<QStandardItem*> list = treeModel->findItems(folderName, - Qt::MatchContains | Qt::MatchRecursive, 0); - if (!list.isEmpty()) { - QStringList names; - foreach (const QStandardItem *item, list) - names << item->text(); - - for (int i = 1; i <= names.count(); ++i) { - folderName = (tr("New Folder") + QLatin1String(" %1")).arg(i); - if (!names.contains(folderName)) - break; - } - } - return folderName; + TRACE_OBJ + const QModelIndex &index = bookmarkTreeView->indexAt(QPoint(2, 2)); + if (index.isValid()) + bookmarkTreeView->setCurrentIndex(index); } -void BookmarkManager::removeBookmarkFolderItems(QStandardItem *item) +void BookmarkManager::managerWidgetAboutToClose() { - for (int j = 0; j < item->rowCount(); ++j) { - QStandardItem *child = item->child(j); - if (child->rowCount() > 0) - removeBookmarkFolderItems(child); - - QString data = child->data(Qt::UserRole + 10).toString(); - QList<QStandardItem*>itemList = listModel->findItems(child->text()); - foreach (const QStandardItem *i, itemList) { - if (i->data(Qt::UserRole + 10) == data) { - listModel->removeRow(i->row()); - break; - } - } - } + delete bookmarkManagerWidget; + bookmarkManagerWidget = 0; } -void BookmarkManager::readBookmarksRecursive(const QStandardItem *item, - QDataStream &stream, const qint32 depth) const +void BookmarkManager::textChanged(const QString &text) { - for (int j = 0; j < item->rowCount(); ++j) { - const QStandardItem *child = item->child(j); - stream << depth; - stream << child->data(Qt::DisplayRole).toString(); - stream << child->data(Qt::UserRole + 10).toString(); - stream << child->data(Qt::UserRole + 11).toBool(); - - if (child->rowCount() > 0) - readBookmarksRecursive(child, stream, (depth +1)); + TRACE_OBJ + if (!bookmarkWidget->ui.lineEdit->text().isEmpty()) { + if (!typeAndSearch) { + typeAndSearch = true; + bookmarkTreeView->setItemsExpandable(false); + bookmarkTreeView->setRootIsDecorated(false); + bookmarkTreeView->setModel(typeAndSearchModel); + } + typeAndSearchModel->setFilterRegExp(QRegExp(text)); + } else { + typeAndSearch = false; + bookmarkTreeView->setModel(bookmarkModel); + bookmarkTreeView->setItemsExpandable(true); + bookmarkTreeView->setRootIsDecorated(true); + bookmarkModel->expandFoldersIfNeeeded(bookmarkTreeView); } } diff --git a/tools/assistant/tools/assistant/bookmarkmanager.h b/tools/assistant/tools/assistant/bookmarkmanager.h index da36833..c26dad8 100644 --- a/tools/assistant/tools/assistant/bookmarkmanager.h +++ b/tools/assistant/tools/assistant/bookmarkmanager.h @@ -38,178 +38,118 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - #ifndef BOOKMARKMANAGER_H #define BOOKMARKMANAGER_H -#include "ui_bookmarkdialog.h" - -#include <QtCore/QUrl> -#include <QtCore/QObject> -#include <QtCore/QString> -#include <QtCore/QByteArray> -#include <QtCore/QDataStream> - -#include <QtGui/QIcon> -#include <QtGui/QDialog> -#include <QtGui/QWidget> +#include <QtCore/QMutex> #include <QtGui/QTreeView> -#include <QtGui/QStandardItemModel> + +#include "ui_bookmarkwidget.h" QT_BEGIN_NAMESPACE -class QEvent; -class QLineEdit; -class QTreeView; -class QToolButton; -class QStandardItem; -class QHelpEngineCore; -class QAbstractItemModel; +class BookmarkManagerWidget; +class BookmarkModel; +class BookmarkFilterModel; +class QKeyEvent; class QSortFilterProxyModel; -class BookmarkManager; - -class BookmarkDialog : public QDialog +class BookmarkManager : public QObject { Q_OBJECT + class BookmarkWidget; + class BookmarkTreeView; + class BookmarkListView; + Q_DISABLE_COPY(BookmarkManager); public: - BookmarkDialog(BookmarkManager *manager, const QString &title, - const QString &url, QWidget *parent = 0); - ~BookmarkDialog(); + static BookmarkManager* instance(); + static void destroy(); -private slots: - void addAccepted(); - void addNewFolder(); - void toolButtonClicked(); - void itemChanged(QStandardItem *item); - void textChanged(const QString& string); - void selectBookmarkFolder(const QString &folderName); - void customContextMenuRequested(const QPoint &point); - void currentChanged(const QModelIndex& current); - -private: - bool eventFilter(QObject *object, QEvent *e); + QWidget* bookmarkDockWidget() const; + void takeBookmarksMenu(QMenu* menu); -private: - QString m_url; - QString m_title; - - QString oldText; - QStandardItem *renameItem; +public slots: + void addBookmark(const QString &title, const QString &url); - Ui::BookmarkDialog ui; - BookmarkManager *bookmarkManager; - QSortFilterProxyModel *proxyModel; -}; +signals: + void escapePressed(); + void setSource(const QUrl &url); + void setSourceInNewTab(const QUrl &url); -class TreeView : public QTreeView { - Q_OBJECT -public: - TreeView(QWidget* parent = 0) : QTreeView(parent) {} - void subclassKeyPressEvent(QKeyEvent* event) - { - QTreeView::keyPressEvent(event); - } -}; +private: + BookmarkManager(); + ~BookmarkManager(); -class BookmarkWidget : public QWidget -{ - Q_OBJECT + void removeItem(const QModelIndex &index); + bool eventFilter(QObject *object, QEvent *event); + void buildBookmarksMenu(const QModelIndex &index, QMenu *menu); + void showBookmarkDialog(const QString &name, const QString &url); -public: - BookmarkWidget(BookmarkManager *manager, QWidget *parent = 0, - bool showButtons = true); - ~BookmarkWidget(); +private slots: + void setupFinished(); -signals: void addBookmark(); - void requestShowLink(const QUrl &url); - void escapePressed(); + void removeBookmark(); + void manageBookmarks(); + void refeshBookmarkMenu(); + void renameBookmark(const QModelIndex &index); -private slots: - void removeClicked(); - void filterChanged(); - void expand(const QModelIndex& index); - void activated(const QModelIndex &index); + void setSourceFromAction(QAction *action); + void setSourceFromIndex(const QModelIndex &index, bool newTab = false); + + void focusInEvent(); + void managerWidgetAboutToClose(); + void textChanged(const QString &text); void customContextMenuRequested(const QPoint &point); private: - void setup(bool showButtons); - void expandItems(); - void focusInEvent(QFocusEvent *e); - bool eventFilter(QObject *object, QEvent *event); + bool typeAndSearch; -private: - QRegExp regExp; - TreeView *treeView; - QLineEdit *searchField; - QToolButton *addButton; - QToolButton *removeButton; - BookmarkManager *bookmarkManager; - QSortFilterProxyModel* filterBookmarkModel; -}; + static QMutex mutex; + static BookmarkManager *bookmarkManager; -class BookmarkModel : public QStandardItemModel -{ - Q_OBJECT + QMenu *bookmarkMenu; -public: - BookmarkModel(int rows, int columns, QObject *parent = 0); - ~BookmarkModel(); + BookmarkModel *bookmarkModel; + BookmarkFilterModel *bookmarkFilterModel; + QSortFilterProxyModel *typeAndSearchModel; - Qt::DropActions supportedDropActions() const; - Qt::ItemFlags flags(const QModelIndex &index) const; + BookmarkWidget *bookmarkWidget; + BookmarkTreeView *bookmarkTreeView; + BookmarkManagerWidget *bookmarkManagerWidget; }; -class BookmarkManager : public QObject +class BookmarkManager::BookmarkWidget : public QWidget { Q_OBJECT - public: - BookmarkManager(QHelpEngineCore* helpEngine); - ~BookmarkManager(); + BookmarkWidget(QWidget *parent = 0) + : QWidget(parent) { ui.setupUi(this); } + virtual ~BookmarkWidget() {} - BookmarkModel* treeBookmarkModel(); - BookmarkModel* listBookmarkModel(); - - void saveBookmarks(); - QStringList bookmarkFolders() const; - QModelIndex addNewFolder(const QModelIndex& index); - void removeBookmarkItem(QTreeView *treeView, const QModelIndex& index); - void showBookmarkDialog(QWidget* parent, const QString &name, - const QString &url); - void addNewBookmark(const QModelIndex& index, const QString &name, - const QString &url); - void setupBookmarkModels(); - - void fillBookmarkMenu(QMenu *menu); - QUrl urlForAction(QAction* action) const; + Ui::BookmarkWidget ui; signals: - void bookmarksChanged(); - -private slots: - void itemChanged(QStandardItem *item); + void focusInEvent(); private: - QString uniqueFolderName() const; - void removeBookmarkFolderItems(QStandardItem *item); - void readBookmarksRecursive(const QStandardItem *item, QDataStream &stream, - const qint32 depth) const; - void fillBookmarkMenu(QMenu *menu, QStandardItem *root); + void focusInEvent(QFocusEvent *event); +}; -private: - QString oldText; - QIcon folderIcon; - - BookmarkModel *treeModel; - BookmarkModel *listModel; - QStandardItem *renameItem; - QHelpEngineCore *helpEngine; - QMap<QAction*, QModelIndex> map; +class BookmarkManager::BookmarkTreeView : public QTreeView +{ + Q_OBJECT +public: + BookmarkTreeView(QWidget *parent = 0); + ~BookmarkTreeView() {} + + void subclassKeyPressEvent(QKeyEvent *event); + +private slots: + void setExpandedData(const QModelIndex &index); }; QT_END_NAMESPACE -#endif +#endif // BOOKMARKMANAGER_H diff --git a/tools/assistant/tools/assistant/bookmarkmanagerwidget.cpp b/tools/assistant/tools/assistant/bookmarkmanagerwidget.cpp new file mode 100644 index 0000000..65df6be --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkmanagerwidget.cpp @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "bookmarkmanagerwidget.h" +#include "bookmarkitem.h" +#include "bookmarkmodel.h" +#include "tracer.h" +#include "xbelsupport.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QFile> +#include <QtCore/QUrl> + +#include <QtGui/QCloseEvent> +#include <QtGui/QFileDialog> +#include <QtGui/QKeySequence> +#include <QtGui/QMessageBox> +#include <QtGui/QShortcut> + +QT_BEGIN_NAMESPACE + +namespace { + #define TR(x) QCoreApplication::translate("BookmarkManager", x) +} + +BookmarkManagerWidget::BookmarkManagerWidget(BookmarkModel *sourceModel, + QWidget *parent) + : QWidget(parent) + , bookmarkModel(sourceModel) +{ + TRACE_OBJ + ui.setupUi(this); + + ui.treeView->setModel(bookmarkModel); + + ui.treeView->expandAll(); + ui.treeView->installEventFilter(this); + ui.treeView->viewport()->installEventFilter(this); + ui.treeView->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(ui.treeView, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(customContextMenuRequested(QPoint))); + + connect(ui.remove, SIGNAL(clicked()), this, SLOT(removeItem())); + connect(ui.lineEdit, SIGNAL(textChanged(QString)), this, + SLOT(textChanged(QString))); + new QShortcut(QKeySequence::Find, ui.lineEdit, SLOT(setFocus())); + + importExportMenu.addAction(tr("Import..."), this, SLOT(importBookmarks())); + importExportMenu.addAction(tr("Export..."), this, SLOT(exportBookmarks())); + ui.importExport->setMenu(&importExportMenu); + + new QShortcut(QKeySequence::FindNext, this, SLOT(findNext())); + new QShortcut(QKeySequence::FindPrevious, this, SLOT(findPrevious())); + + connect(bookmarkModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, + SLOT(refeshBookmarkCache())); + connect(bookmarkModel, SIGNAL(rowsInserted(QModelIndex, int, int)), this, + SLOT(refeshBookmarkCache())); + connect(bookmarkModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, + SLOT(refeshBookmarkCache())); + + ui.treeView->setCurrentIndex(ui.treeView->indexAt(QPoint(2, 2))); +} + +BookmarkManagerWidget::~BookmarkManagerWidget() +{ + TRACE_OBJ +} + +void BookmarkManagerWidget::closeEvent(QCloseEvent *event) +{ + TRACE_OBJ + event->accept(); + emit managerWidgetAboutToClose(); +} + +void BookmarkManagerWidget::renameItem(const QModelIndex &index) +{ + TRACE_OBJ + // check if we should rename the "Bookmarks Menu", bail + if (!bookmarkModel->parent(index).isValid()) + return; + + bookmarkModel->setItemsEditable(true); + ui.treeView->edit(index); + bookmarkModel->setItemsEditable(false); +} + +static int nextIndex(int current, int count, bool forward) +{ + TRACE_OBJ + if (current >= 0) + return (forward ? (current + 1) : ((current - 1) + count)) % count; + return 0; +} + +void BookmarkManagerWidget::selectNextIndex(bool direction) const +{ + QModelIndex current = ui.treeView->currentIndex(); + if (current.isValid() && !cache.isEmpty()) { + current = cache.at(nextIndex(cache.indexOf(current), cache.count(), + direction)); + } + ui.treeView->setCurrentIndex(current); +} + +bool BookmarkManagerWidget::eventFilter(QObject *object, QEvent *event) +{ + TRACE_OBJ + if (object != ui.treeView && object != ui.treeView->viewport()) + return QWidget::eventFilter(object, event); + + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(event); + switch (ke->key()) { + case Qt::Key_F2: { + renameItem(ui.treeView->currentIndex()); + } break; + + case Qt::Key_Delete: { + removeItem(ui.treeView->currentIndex()); + } break; + + default: break; + } + } + + if (event->type() == QEvent::MouseButtonRelease) { + QMouseEvent *me = static_cast<QMouseEvent*>(event); + switch (me->button()) { + case Qt::LeftButton: { + if (me->modifiers() & Qt::ControlModifier) + setSourceFromIndex(ui.treeView->currentIndex(), true); + } break; + + case Qt::MidButton: { + setSourceFromIndex(ui.treeView->currentIndex(), true); + } break; + + default: break; + } + } + return QObject::eventFilter(object, event); +} + +void BookmarkManagerWidget::findNext() +{ + TRACE_OBJ + selectNextIndex(true); +} + +void BookmarkManagerWidget::findPrevious() +{ + TRACE_OBJ + selectNextIndex(false); +} + +void BookmarkManagerWidget::importBookmarks() +{ + TRACE_OBJ + const QString &fileName = QFileDialog::getOpenFileName(0, TR("Open File"), + QDir::currentPath(), TR("Files (*.xbel)")); + + if (fileName.isEmpty()) + return; + + QFile file(fileName); + if (file.open(QIODevice::ReadOnly)) { + XbelReader reader(bookmarkModel); + reader.readFromFile(&file); + } +} + +void BookmarkManagerWidget::exportBookmarks() +{ + TRACE_OBJ + QString fileName = QFileDialog::getSaveFileName(0, TR("Save File"), + QLatin1String("untitled.xbel"), TR("Files (*.xbel)")); + + const QLatin1String suffix(".xbel"); + if (!fileName.endsWith(suffix)) + fileName.append(suffix); + + QFile file(fileName); + if (file.open(QIODevice::WriteOnly)) { + XbelWriter writer(bookmarkModel); + writer.writeToFile(&file); + } else { + QMessageBox::information(this, TR("Qt Assistant"), + TR("Unable to save bookmarks."), TR("OK")); + } +} + +void BookmarkManagerWidget::refeshBookmarkCache() +{ + TRACE_OBJ + cache.clear(); + + const QString &text = ui.lineEdit->text(); + if (!text.isEmpty()) + cache = bookmarkModel->indexListFor(text); +} + +void BookmarkManagerWidget::textChanged(const QString &/*text*/) +{ + TRACE_OBJ + refeshBookmarkCache(); + if (!cache.isEmpty()) + ui.treeView->setCurrentIndex(cache.at(0)); +} + +void BookmarkManagerWidget::removeItem(const QModelIndex &index) +{ + TRACE_OBJ + QModelIndex current = index.isValid() ? index : ui.treeView->currentIndex(); + if (!bookmarkModel->parent(current).isValid()) + return; // check if we should delete the "Bookmarks Menu", bail + + if (bookmarkModel->hasChildren(current)) { + int value = QMessageBox::question(this, TR("Remove"), TR("You are going" + "to delete a Folder, this will also<br> remove it's content. Are " + "you sure to continue?"), + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); + if (value == QMessageBox::Cancel) + return; + } + bookmarkModel->removeItem(current); +} + +void BookmarkManagerWidget::customContextMenuRequested(const QPoint &point) +{ + TRACE_OBJ + const QModelIndex &index = ui.treeView->indexAt(point); + if (!index.isValid()) + return; + + // check if we should open the menu on "Bookmarks Menu", bail + if (!bookmarkModel->parent(index).isValid()) + return; + + QAction *remove = 0; + QAction *rename = 0; + QAction *showItem = 0; + QAction *showItemInNewTab = 0; + + QMenu menu(QLatin1String("")); + if (bookmarkModel->data(index, UserRoleFolder).toBool()) { + remove = menu.addAction(TR("Delete Folder")); + rename = menu.addAction(TR("Rename Folder")); + } else { + showItem = menu.addAction(TR("Show Bookmark")); + showItemInNewTab = menu.addAction(TR("Show Bookmark in New Tab")); + menu.addSeparator(); + remove = menu.addAction(TR("Delete Bookmark")); + rename = menu.addAction(TR("Rename Bookmark")); + } + + QAction *pickedAction = menu.exec(ui.treeView->mapToGlobal(point)); + if (pickedAction == rename) + renameItem(index); + else if (pickedAction == remove) + removeItem(index); + else if (pickedAction == showItem || pickedAction == showItemInNewTab) + setSourceFromIndex(index, pickedAction == showItemInNewTab); +} + +void +BookmarkManagerWidget::setSourceFromIndex(const QModelIndex &index, bool newTab) +{ + TRACE_OBJ + if (bookmarkModel->data(index, UserRoleFolder).toBool()) + return; + + const QVariant &data = bookmarkModel->data(index, UserRoleUrl); + if (data.canConvert<QUrl>()) { + if (newTab) + emit setSourceInNewTab(data.toUrl()); + else + emit setSource(data.toUrl()); + } +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/bookmarkmanagerwidget.h b/tools/assistant/tools/assistant/bookmarkmanagerwidget.h new file mode 100644 index 0000000..94384a6 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkmanagerwidget.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef BOOKMARKMANAGERWIDGET_H +#define BOOKMARKMANAGERWIDGET_H + +#include "ui_bookmarkmanagerwidget.h" + +#include <QtCore/QPersistentModelIndex> + +#include <QtGui/QMenu> + +QT_BEGIN_NAMESPACE + +class BookmarkModel; +class QCloseEvent; +class QString; + +class BookmarkManagerWidget : public QWidget +{ + Q_OBJECT +public: + BookmarkManagerWidget(BookmarkModel *bookmarkModel, QWidget *parent = 0); + ~BookmarkManagerWidget(); + +protected: + void closeEvent(QCloseEvent *event); + +signals: + void setSource(const QUrl &url); + void setSourceInNewTab(const QUrl &url); + + void managerWidgetAboutToClose(); + +private: + void renameItem(const QModelIndex &index); + void selectNextIndex(bool direction) const; + bool eventFilter(QObject *object, QEvent *event); + +private slots: + void findNext(); + void findPrevious(); + + void importBookmarks(); + void exportBookmarks(); + + void refeshBookmarkCache(); + void textChanged(const QString &text); + + void removeItem(const QModelIndex &index = QModelIndex()); + + void customContextMenuRequested(const QPoint &point); + void setSourceFromIndex(const QModelIndex &index, bool newTab = false); + +private: + QMenu importExportMenu; + Ui::BookmarkManagerWidget ui; + QList<QPersistentModelIndex> cache; + + BookmarkModel *bookmarkModel; +}; + +QT_END_NAMESPACE + +#endif // BOOKMARKMANAGERWIDGET_H
\ No newline at end of file diff --git a/tools/assistant/tools/assistant/bookmarkmanagerwidget.ui b/tools/assistant/tools/assistant/bookmarkmanagerwidget.ui new file mode 100644 index 0000000..dc965d9 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkmanagerwidget.ui @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>BookmarkManagerWidget</class> + <widget class="QWidget" name="BookmarkManagerWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>517</width> + <height>348</height> + </rect> + </property> + <property name="windowTitle"> + <string>Manage Bookmarks</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Search:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit"/> + </item> + </layout> + </item> + <item> + <widget class="QTreeView" name="treeView"> + <property name="acceptDrops"> + <bool>true</bool> + </property> + <property name="showDropIndicator" stdset="0"> + <bool>true</bool> + </property> + <property name="dragEnabled"> + <bool>true</bool> + </property> + <property name="autoExpandDelay"> + <number>1000</number> + </property> + <property name="uniformRowHeights"> + <bool>true</bool> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <attribute name="headerDefaultSectionSize"> + <number>225</number> + </attribute> + <attribute name="headerMinimumSectionSize"> + <number>50</number> + </attribute> + <attribute name="headerDefaultSectionSize"> + <number>225</number> + </attribute> + <attribute name="headerMinimumSectionSize"> + <number>50</number> + </attribute> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="remove"> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="importExport"> + <property name="text"> + <string>Import and Backup</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="pushButton_5"> + <property name="text"> + <string>OK</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>pushButton_5</sender> + <signal>clicked()</signal> + <receiver>BookmarkManagerWidget</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>445</x> + <y>328</y> + </hint> + <hint type="destinationlabel"> + <x>340</x> + <y>313</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/assistant/tools/assistant/bookmarkmodel.cpp b/tools/assistant/tools/assistant/bookmarkmodel.cpp new file mode 100644 index 0000000..e446ff0 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkmodel.cpp @@ -0,0 +1,444 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "bookmarkmodel.h" +#include "bookmarkitem.h" + +#include <QtCore/QMimeData> +#include <QtCore/QStack> + +#include <QtGui/QApplication> +#include <QtGui/QStyle> +#include <QtGui/QTreeView> + +const QLatin1String MIMETYPE("application/bookmarks.assistant"); + +BookmarkModel::BookmarkModel() + : QAbstractItemModel() + , m_folder(false) + , m_editable(false) + , rootItem(0) +{ +} + +BookmarkModel::~BookmarkModel() +{ + delete rootItem; +} + +QByteArray +BookmarkModel::bookmarks() const +{ + QByteArray ba; + QDataStream stream(&ba, QIODevice::WriteOnly); + + const QModelIndex &root = index(0,0, QModelIndex()); + for (int i = 0; i < rowCount(root); ++i) + collectItems(index(i, 0, root), 0, &stream); + + return ba; +} + +void +BookmarkModel::setBookmarks(const QByteArray &bookmarks) +{ + beginResetModel(); + + delete rootItem; + folderIcon = QApplication::style()->standardIcon(QStyle::SP_DirClosedIcon); + bookmarkIcon = QIcon(QLatin1String(":/trolltech/assistant/images/bookmark.png")); + + rootItem = new BookmarkItem(DataVector() << tr("Name") << tr("Address") + << true); + BookmarkItem* item = new BookmarkItem(DataVector() << tr("Bookmarks Menu") + << QLatin1String("Folder") << true); + rootItem->addChild(item); + + QStack<BookmarkItem*> parents; + parents.push(item); + + qint32 depth; + bool expanded; + QString name, url; + QDataStream stream(bookmarks); + while (!stream.atEnd()) { + stream >> depth >> name >> url >> expanded; + + while ((parents.count() - 1) != depth) + parents.pop(); + + item = new BookmarkItem(DataVector() << name << url << expanded); + if (url == QLatin1String("Folder")) { + parents.top()->addChild(item); + parents.push(item); + } else { + parents.top()->addChild(item); + } + } + + cache.clear(); + const QModelIndex &root = index(0,0, QModelIndex()); + + setupCache(root); + cache.insert(static_cast<BookmarkItem*> (root.internalPointer()), root); + + endResetModel(); +} + +void +BookmarkModel::setItemsEditable(bool editable) +{ + m_editable = editable; +} + +void +BookmarkModel::expandFoldersIfNeeeded(QTreeView *treeView) +{ + foreach (const QModelIndex &index, cache) + treeView->setExpanded(index, index.data(UserRoleExpanded).toBool()); +} + +QModelIndex +BookmarkModel::addItem(const QModelIndex &parent, bool isFolder) +{ + m_folder = isFolder; + QModelIndex next; + if (insertRow(rowCount(parent), parent)) + next = index(rowCount(parent) - 1, 0, parent); + m_folder = false; + + return next; +} + +bool +BookmarkModel::removeItem(const QModelIndex &index) +{ + if (!index.isValid()) + return false; + + QModelIndexList indexes; + if (rowCount(index) > 0) + indexes = collectItems(index); + indexes.append(index); + + foreach (const QModelIndex &itemToRemove, indexes) { + if (!removeRow(itemToRemove.row(), itemToRemove.parent())) + return false; + cache.remove(itemFromIndex(itemToRemove)); + } + return true; +} + +int +BookmarkModel::rowCount(const QModelIndex &index) const +{ + if (BookmarkItem *item = itemFromIndex(index)) + return item->childCount(); + return 0; +} + +int +BookmarkModel::columnCount(const QModelIndex &/*index*/) const +{ + return 2; +} + +QModelIndex +BookmarkModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + if (BookmarkItem *childItem = itemFromIndex(index)) { + if (BookmarkItem *parent = childItem->parent()) { + if (parent != rootItem) + return createIndex(parent->childNumber(), 0, parent); + } + } + return QModelIndex(); +} + +QModelIndex +BookmarkModel::index(int row, int column, const QModelIndex &index) const +{ + if (index.isValid() && (index.column() != 0 && index.column() != 1)) + return QModelIndex(); + + if (BookmarkItem *parent = itemFromIndex(index)) { + if (BookmarkItem *childItem = parent->child(row)) + return createIndex(row, column, childItem); + } + return QModelIndex(); +} + +Qt::DropActions +BookmarkModel::supportedDropActions () const +{ + return /* Qt::CopyAction | */Qt::MoveAction; +} + +Qt::ItemFlags +BookmarkModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::NoItemFlags; + + Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + + if (m_editable) + defaultFlags |= Qt::ItemIsEditable; + + if (itemFromIndex(index) && index.data(UserRoleFolder).toBool()) { + if (index.column() > 0) + return defaultFlags &~ Qt::ItemIsEditable; + return defaultFlags | Qt::ItemIsDropEnabled; + } + + return defaultFlags | Qt::ItemIsDragEnabled; +} + +QVariant +BookmarkModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid()) { + if (BookmarkItem *item = itemFromIndex(index)) { + switch (role) { + case Qt::EditRole: { + case Qt::DisplayRole: + if (index.data(UserRoleFolder).toBool() && index.column() == 1) + return QLatin1String(""); + return item->data(index.column()); + } break; + + case Qt::DecorationRole: { + if (index.column() == 0) + return index.data(UserRoleFolder).toBool() + ? folderIcon : bookmarkIcon; + } break; + + default:; + return item->data(role); + } + } + } + return QVariant(); +} + +bool +BookmarkModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + bool result = false; + if (role != Qt::EditRole && role != UserRoleExpanded) + return result; + + if (BookmarkItem *item = itemFromIndex(index)) { + if (role == Qt::EditRole) { + const bool isFolder = index.data(UserRoleFolder).toBool(); + if (!isFolder || (isFolder && index.column() == 0)) + result = item->setData(index.column(), value); + } else if (role == UserRoleExpanded) { + result = item->setData(UserRoleExpanded, value); + } + } + + if (result) + emit dataChanged(index, index); + return result; +} + +QVariant +BookmarkModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (rootItem && orientation == Qt::Horizontal && role == Qt::DisplayRole) + return rootItem->data(section); + return QVariant(); +} + +QModelIndex +BookmarkModel::indexFromItem(BookmarkItem *item) const +{ + return cache.value(item, QModelIndex()); +} + +BookmarkItem* +BookmarkModel::itemFromIndex(const QModelIndex &index) const +{ + if (index.isValid()) + return static_cast<BookmarkItem*>(index.internalPointer()); + return rootItem; +} + +QList<QPersistentModelIndex> +BookmarkModel::indexListFor(const QString &label) const +{ + QList<QPersistentModelIndex> hits; + const QModelIndexList &list = collectItems(QModelIndex()); + foreach(const QModelIndex &index, list) { + if (index.data().toString().contains(label, Qt::CaseInsensitive)) + hits.prepend(index); // list is reverse sorted + } + return hits; +} + +bool +BookmarkModel::insertRows(int position, int rows, const QModelIndex &parent) +{ + if (!parent.data(UserRoleFolder).toBool()) + return false; + + bool success = false; + if (BookmarkItem *parentItem = itemFromIndex(parent)) { + beginInsertRows(parent, position, position + rows - 1); + success = parentItem->insertChildren(m_folder, position, rows); + if (success) { + const QModelIndex ¤t = index(position, 0, parent); + cache.insert(itemFromIndex(current), current); + } + endInsertRows(); + } + return success; +} + +bool +BookmarkModel::removeRows(int position, int rows, const QModelIndex &index) +{ + bool success = false; + if (BookmarkItem *parent = itemFromIndex(index)) { + beginRemoveRows(index, position, position + rows - 1); + success = parent->removeChildren(position, rows); + endRemoveRows(); + } + return success; +} + +QStringList +BookmarkModel::mimeTypes() const +{ + return QStringList() << MIMETYPE; +} + +QMimeData* +BookmarkModel::mimeData(const QModelIndexList &indexes) const +{ + if (indexes.isEmpty()) + return 0; + + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + + foreach (const QModelIndex &index, indexes) { + if (index.column() == 0) + collectItems(index, 0, &stream); + } + + QMimeData *mimeData = new QMimeData(); + mimeData->setData(MIMETYPE, data); + return mimeData; +} + +bool +BookmarkModel::dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) +{ + if (action == Qt::IgnoreAction) + return true; + + if (!data->hasFormat(MIMETYPE) || column > 0) + return false; + + QByteArray ba = data->data(MIMETYPE); + QDataStream stream(&ba, QIODevice::ReadOnly); + while (stream.atEnd()) + return false; + + qint32 depth; + bool expanded; + QString name, url; + while (!stream.atEnd()) { + stream >> depth >> name >> url >> expanded; + if (insertRow(qMax(0, row), parent)) { + const QModelIndex ¤t = index(qMax(0, row), 0, parent); + if (current.isValid()) { + BookmarkItem* item = itemFromIndex(current); + item->setData(DataVector() << name << url << expanded); + } + } + } + return true; +} + +void +BookmarkModel::setupCache(const QModelIndex &parent) +{ + const QModelIndexList &list = collectItems(parent); + foreach (const QModelIndex &index, list) + cache.insert(itemFromIndex(index), index); +} + +QModelIndexList +BookmarkModel::collectItems(const QModelIndex &parent) const +{ + QModelIndexList list; + for (int i = rowCount(parent) - 1; i >= 0 ; --i) { + const QModelIndex &next = index(i, 0, parent); + if (data(next, UserRoleFolder).toBool()) + list += collectItems(next); + list.append(next); + } + return list; +} + +void +BookmarkModel::collectItems(const QModelIndex &parent, qint32 depth, + QDataStream *stream) const +{ + if (parent.isValid()) { + *stream << depth; + *stream << parent.data().toString(); + *stream << parent.data(UserRoleUrl).toString(); + *stream << parent.data(UserRoleExpanded).toBool(); + + for (int i = 0; i < rowCount(parent); ++i) { + if (parent.data(UserRoleFolder).toBool()) + collectItems(index(i, 0 , parent), depth + 1, stream); + } + } +} diff --git a/tools/assistant/tools/assistant/bookmarkmodel.h b/tools/assistant/tools/assistant/bookmarkmodel.h new file mode 100644 index 0000000..6469258 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkmodel.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef BOOKMARKMODEL_H +#define BOOKMARKMODEL_H + +#include <QtCore/QAbstractItemModel> + +#include <QtGui/QIcon> + +QT_BEGIN_NAMESPACE + +class BookmarkItem; +class QMimeData; +class QTreeView; + +typedef QMap<BookmarkItem*, QPersistentModelIndex> ItemModelIndexCache; + +class BookmarkModel : public QAbstractItemModel +{ + Q_OBJECT +public: + BookmarkModel(); + ~BookmarkModel(); + + QByteArray bookmarks() const; + void setBookmarks(const QByteArray &bookmarks); + + void setItemsEditable(bool editable); + void expandFoldersIfNeeeded(QTreeView *treeView); + + QModelIndex addItem(const QModelIndex &parent, bool isFolder = false); + bool removeItem(const QModelIndex &index); + + int rowCount(const QModelIndex &index = QModelIndex()) const; + int columnCount(const QModelIndex &index = QModelIndex()) const; + + QModelIndex parent(const QModelIndex &index) const; + QModelIndex index(int row, int column, const QModelIndex &index) const; + + Qt::DropActions supportedDropActions () const; + Qt::ItemFlags flags(const QModelIndex &index) const; + + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + + QModelIndex indexFromItem(BookmarkItem *item) const; + BookmarkItem *itemFromIndex(const QModelIndex &index) const; + QList<QPersistentModelIndex> indexListFor(const QString &label) const; + + bool insertRows(int position, int rows, const QModelIndex &parent); + bool removeRows(int position, int rows, const QModelIndex &parent); + + QStringList mimeTypes() const; + QMimeData* mimeData(const QModelIndexList &indexes) const; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, + int column, const QModelIndex &parent); + +private: + void setupCache(const QModelIndex &parent); + QModelIndexList collectItems(const QModelIndex &parent) const; + void collectItems(const QModelIndex &parent, qint32 depth, + QDataStream *stream) const; + +private: + int columns; + bool m_folder; + bool m_editable; + QIcon folderIcon; + QIcon bookmarkIcon; + QTreeView *treeView; + BookmarkItem *rootItem; + ItemModelIndexCache cache; +}; + +QT_END_NAMESPACE + +#endif // BOOKMARKMODEL_H diff --git a/tools/assistant/tools/assistant/bookmarkwidget.ui b/tools/assistant/tools/assistant/bookmarkwidget.ui new file mode 100644 index 0000000..a31a277 --- /dev/null +++ b/tools/assistant/tools/assistant/bookmarkwidget.ui @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>BookmarkWidget</class> + <widget class="QWidget" name="BookmarkWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>235</width> + <height>606</height> + </rect> + </property> + <property name="windowTitle"> + <string>Bookmarks</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="margin"> + <number>4</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Filter:</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QLineEdit" name="lineEdit"/> + </item> + <item> + <widget class="QStackedWidget" name="stackedWidget"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="add"> + <property name="text"> + <string>Add</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="remove"> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tools/assistant/tools/assistant/centralwidget.cpp b/tools/assistant/tools/assistant/centralwidget.cpp index 0e4096b..131fb85 100644 --- a/tools/assistant/tools/assistant/centralwidget.cpp +++ b/tools/assistant/tools/assistant/centralwidget.cpp @@ -38,36 +38,36 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "tracer.h" #include "centralwidget.h" -#include "helpviewer.h" +#include "findwidget.h" +#include "helpenginewrapper.h" #include "searchwidget.h" #include "mainwindow.h" -#include "preferencesdialog.h" +#include "../shared/collectionconfiguration.h" + +#if defined(QT_NO_WEBKIT) +#include "helpviewer_qtb.h" +#else +#include "helpviewer_qwv.h" +#endif // QT_NO_WEBKIT -#include <QtCore/QDir> -#include <QtCore/QEvent> #include <QtCore/QTimer> -#include <QtGui/QMenu> -#include <QtGui/QLabel> +#include <QtGui/QApplication> +#include <QtGui/QKeyEvent> #include <QtGui/QLayout> +#include <QtGui/QMenu> #include <QtGui/QPrinter> -#include <QtGui/QLineEdit> -#include <QtGui/QCheckBox> #include <QtGui/QTabBar> #include <QtGui/QTabWidget> +#include <QtGui/QTextBrowser> #include <QtGui/QToolButton> -#include <QtGui/QMouseEvent> -#include <QtGui/QSpacerItem> -#include <QtGui/QTextCursor> +#include <QtGui/QPageSetupDialog> #include <QtGui/QPrintDialog> -#include <QtGui/QApplication> -#include <QtGui/QTextDocumentFragment> #include <QtGui/QPrintPreviewDialog> -#include <QtGui/QPageSetupDialog> -#include <QtHelp/QHelpEngine> #include <QtHelp/QHelpSearchEngine> QT_BEGIN_NAMESPACE @@ -76,6 +76,7 @@ namespace { HelpViewer* helpViewerFromTabPosition(const QTabWidget *widget, const QPoint &point) { + TRACE_OBJ QTabBar *tabBar = qFindChild<QTabBar*>(widget); for (int i = 0; i < tabBar->count(); ++i) { if (tabBar->tabRect(i).contains(point)) @@ -86,137 +87,18 @@ namespace { CentralWidget *staticCentralWidget = 0; } -FindWidget::FindWidget(QWidget *parent) - : QWidget(parent) - , appPalette(qApp->palette()) -{ - QHBoxLayout *hboxLayout = new QHBoxLayout(this); - QString resourcePath = QLatin1String(":/trolltech/assistant/images/"); - -#ifndef Q_OS_MAC - hboxLayout->setMargin(0); - hboxLayout->setSpacing(6); - resourcePath.append(QLatin1String("win")); -#else - resourcePath.append(QLatin1String("mac")); -#endif - - toolClose = setupToolButton(QLatin1String(""), - resourcePath + QLatin1String("/closetab.png")); - hboxLayout->addWidget(toolClose); - - editFind = new QLineEdit(this); - hboxLayout->addWidget(editFind); - editFind->setMinimumSize(QSize(150, 0)); - connect(editFind, SIGNAL(textChanged(QString)), this, SLOT(updateButtons())); - - toolPrevious = setupToolButton(tr("Previous"), - resourcePath + QLatin1String("/previous.png")); - hboxLayout->addWidget(toolPrevious); - - toolNext = setupToolButton(tr("Next"), - resourcePath + QLatin1String("/next.png")); - hboxLayout->addWidget(toolNext); - - checkCase = new QCheckBox(tr("Case Sensitive"), this); - hboxLayout->addWidget(checkCase); - - checkWholeWords = new QCheckBox(tr("Whole words"), this); - hboxLayout->addWidget(checkWholeWords); -#if !defined(QT_NO_WEBKIT) - checkWholeWords->hide(); -#endif - - labelWrapped = new QLabel(this); - labelWrapped->setScaledContents(true); - labelWrapped->setTextFormat(Qt::RichText); - labelWrapped->setMinimumSize(QSize(0, 20)); - labelWrapped->setMaximumSize(QSize(105, 20)); - labelWrapped->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); - labelWrapped->setText(tr("<img src=\":/trolltech/assistant/images/wrap.png\"" - "> Search wrapped")); - hboxLayout->addWidget(labelWrapped); - - QSpacerItem *spacerItem = new QSpacerItem(20, 20, QSizePolicy::Expanding, - QSizePolicy::Minimum); - hboxLayout->addItem(spacerItem); - setMinimumWidth(minimumSizeHint().width()); - labelWrapped->hide(); - - updateButtons(); -} - -FindWidget::~FindWidget() -{ -} +// -- CentralWidget -void FindWidget::hideEvent(QHideEvent* event) -{ -#if !defined(QT_NO_WEBKIT) - // TODO: remove this once webkit supports setting the palette - if (!event->spontaneous()) - qApp->setPalette(appPalette); -#else - Q_UNUSED(event); -#endif -} - -void FindWidget::showEvent(QShowEvent* event) -{ -#if !defined(QT_NO_WEBKIT) - // TODO: remove this once webkit supports setting the palette - if (!event->spontaneous()) { - QPalette p = appPalette; - p.setColor(QPalette::Inactive, QPalette::Highlight, - p.color(QPalette::Active, QPalette::Highlight)); - p.setColor(QPalette::Inactive, QPalette::HighlightedText, - p.color(QPalette::Active, QPalette::HighlightedText)); - qApp->setPalette(p); - } -#else - Q_UNUSED(event); -#endif -} - -void FindWidget::updateButtons() -{ - if (editFind->text().isEmpty()) { - toolPrevious->setEnabled(false); - toolNext->setEnabled(false); - } else { - toolPrevious->setEnabled(true); - toolNext->setEnabled(true); - } -} - -QToolButton* FindWidget::setupToolButton(const QString &text, const QString &icon) -{ - QToolButton *toolButton = new QToolButton(this); - - toolButton->setText(text); - toolButton->setAutoRaise(true); - toolButton->setIcon(QIcon(icon)); - toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - - return toolButton; -} - - -// -- - - -CentralWidget::CentralWidget(QHelpEngine *engine, MainWindow *parent) +CentralWidget::CentralWidget(MainWindow *parent) : QWidget(parent) , lastTabPage(0) - , collectionFile(engine->collectionFile()) - , findBar(0) , tabWidget(0) , findWidget(0) - , helpEngine(engine) , printer(0) , usesDefaultCollection(parent->usesDefaultCollection()) , m_searchWidget(0) { + TRACE_OBJ globalActionList.clear(); staticCentralWidget = this; QVBoxLayout *vboxLayout = new QVBoxLayout(this); @@ -253,20 +135,15 @@ CentralWidget::CentralWidget(QHelpEngine *engine, MainWindow *parent) vboxLayout->addWidget(tabWidget); - findBar = new QWidget(this); - findWidget = new FindWidget(findBar); - findBar->setMinimumHeight(findWidget->minimumSizeHint().height()); - findWidget->move(0, 0); - vboxLayout->addWidget(findBar); - findBar->hide(); - findWidget->editFind->installEventFilter(this); - - connect(findWidget->toolClose, SIGNAL(clicked()), findBar, SLOT(hide())); - connect(findWidget->toolNext, SIGNAL(clicked()), this, SLOT(findNext())); - connect(findWidget->editFind, SIGNAL(returnPressed()), this, SLOT(findNext())); - connect(findWidget->editFind, SIGNAL(textChanged(QString)), this, - SLOT(findCurrentText(QString))); - connect(findWidget->toolPrevious, SIGNAL(clicked()), this, SLOT(findPrevious())); + findWidget = new FindWidget(this); + vboxLayout->addWidget(findWidget); + findWidget->hide(); + + connect(findWidget, SIGNAL(findNext()), this, SLOT(findNext())); + connect(findWidget, SIGNAL(findPrevious()), this, SLOT(findPrevious())); + connect(findWidget, SIGNAL(find(QString, bool)), this, + SLOT(find(QString, bool))); + connect(findWidget, SIGNAL(escapePressed()), this, SLOT(activateTab())); QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget); if (tabBar) { @@ -288,45 +165,40 @@ CentralWidget::CentralWidget(QHelpEngine *engine, MainWindow *parent) CentralWidget::~CentralWidget() { + TRACE_OBJ #ifndef QT_NO_PRINTER delete printer; #endif - QHelpEngineCore engine(collectionFile, 0); - if (!engine.setupData()) - return; - - QString zoomCount; - QString currentPages; - QLatin1Char separator('|'); + QStringList zoomFactors; + QStringList currentPages; bool searchAttached = m_searchWidget->isAttached(); int i = searchAttached ? 1 : 0; for (; i < tabWidget->count(); ++i) { HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i)); if (viewer && viewer->source().isValid()) { - currentPages += viewer->source().toString() + separator; - zoomCount += QString::number(viewer->zoom()) + separator; + currentPages << viewer->source().toString(); + zoomFactors << QString::number(viewer->scale()); } } - engine.setCustomValue(QLatin1String("LastTabPage"), lastTabPage); - engine.setCustomValue(QLatin1String("LastShownPages"), currentPages); - engine.setCustomValue(QLatin1String("SearchWasAttached"), searchAttached); -#if !defined(QT_NO_WEBKIT) - engine.setCustomValue(QLatin1String("LastPagesZoomWebView"), zoomCount); -#else - engine.setCustomValue(QLatin1String("LastPagesZoomTextBrowser"), zoomCount); -#endif + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + helpEngine.setLastTabPage(tabWidget->currentIndex()); + helpEngine.setLastShownPages(currentPages); + helpEngine.setSearchWasAttached(searchAttached); + helpEngine.setLastZoomFactors(zoomFactors); } CentralWidget *CentralWidget::instance() { + TRACE_OBJ return staticCentralWidget; } void CentralWidget::newTab() { + TRACE_OBJ HelpViewer *viewer = currentHelpViewer(); #if !defined(QT_NO_WEBKIT) if (viewer && viewer->hasLoadFinished()) @@ -338,9 +210,10 @@ void CentralWidget::newTab() void CentralWidget::zoomIn() { + TRACE_OBJ HelpViewer *viewer = currentHelpViewer(); if (viewer) - viewer->zoomIn(); + viewer->scaleUp(); if (tabWidget->currentWidget() == m_searchWidget) m_searchWidget->zoomIn(); @@ -348,21 +221,18 @@ void CentralWidget::zoomIn() void CentralWidget::zoomOut() { + TRACE_OBJ HelpViewer *viewer = currentHelpViewer(); if (viewer) - viewer->zoomOut(); + viewer->scaleDown(); if (tabWidget->currentWidget() == m_searchWidget) m_searchWidget->zoomOut(); } -void CentralWidget::findNext() -{ - find(findWidget->editFind->text(), true); -} - void CentralWidget::nextPage() { + TRACE_OBJ int index = tabWidget->currentIndex() + 1; if (index >= tabWidget->count()) index = 0; @@ -371,9 +241,9 @@ void CentralWidget::nextPage() void CentralWidget::resetZoom() { - HelpViewer *viewer = currentHelpViewer(); - if (viewer) - viewer->resetZoom(); + TRACE_OBJ + if (HelpViewer *viewer = currentHelpViewer()) + viewer->resetScale(); if (tabWidget->currentWidget() == m_searchWidget) m_searchWidget->resetZoom(); @@ -381,19 +251,16 @@ void CentralWidget::resetZoom() void CentralWidget::previousPage() { + TRACE_OBJ int index = tabWidget->currentIndex() -1; if (index < 0) index = tabWidget->count() -1; tabWidget->setCurrentIndex(index); } -void CentralWidget::findPrevious() -{ - find(findWidget->editFind->text(), false); -} - void CentralWidget::closeTab() { + TRACE_OBJ HelpViewer *viewer = currentHelpViewer(); if (!viewer|| tabWidget->count() == 1) return; @@ -404,12 +271,13 @@ void CentralWidget::closeTab() void CentralWidget::setSource(const QUrl &url) { + TRACE_OBJ HelpViewer *viewer = currentHelpViewer(); HelpViewer *lastViewer = qobject_cast<HelpViewer*>(tabWidget->widget(lastTabPage)); if (!viewer && !lastViewer) { - viewer = new HelpViewer(helpEngine, this); + viewer = new HelpViewer(this); viewer->installEventFilter(this); lastTabPage = tabWidget->addTab(viewer, QString()); tabWidget->setCurrentIndex(lastTabPage); @@ -427,18 +295,14 @@ void CentralWidget::setSource(const QUrl &url) void CentralWidget::setupWidget() { - int option = helpEngine->customValue(QLatin1String("StartOption"), - ShowLastPages).toInt(); - + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + int option = helpEngine.startOption(); if (option != ShowLastPages) { QString homePage; - if (option == ShowHomePage) { - homePage = helpEngine->customValue(QLatin1String("defaultHomepage"), - QLatin1String("help")).toString(); - homePage = helpEngine->customValue(QLatin1String("homepage"), - homePage).toString(); - } - if (option == ShowBlankPage) + if (option == ShowHomePage) + homePage = helpEngine.homePage(); + else if (option == ShowBlankPage) homePage = QLatin1String("about:blank"); setSource(homePage); } else { @@ -448,11 +312,9 @@ void CentralWidget::setupWidget() void CentralWidget::setLastShownPages() { - const QLatin1String key("LastShownPages"); - QString value = helpEngine->customValue(key, QString()).toString(); - const QStringList lastShownPageList = value.split(QLatin1Char('|'), - QString::SkipEmptyParts); - + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + const QStringList &lastShownPageList = helpEngine.lastShownPages(); const int pageCount = lastShownPageList.count(); if (pageCount == 0) { if (usesDefaultCollection) @@ -461,48 +323,40 @@ void CentralWidget::setLastShownPages() setSource(QUrl(QLatin1String("about:blank"))); return; } + QStringList zoomFactors = helpEngine.lastZoomFactors(); + while (zoomFactors.count() < pageCount) + zoomFactors.append(CollectionConfiguration::DefaultZoomFactor); -#if !defined(QT_NO_WEBKIT) - const QLatin1String zoom("LastPagesZoomWebView"); -#else - const QLatin1String zoom("LastPagesZoomTextBrowser"); -#endif - - value = helpEngine->customValue(zoom, QString()).toString(); - QVector<QString> zoomVector = value.split(QLatin1Char('|'), - QString::SkipEmptyParts).toVector(); - - const int zoomCount = zoomVector.count(); - zoomVector.insert(zoomCount, pageCount - zoomCount, QLatin1String("0.0")); - - QVector<QString>::const_iterator zIt = zoomVector.constBegin(); - QStringList::const_iterator it = lastShownPageList.constBegin(); - for (; it != lastShownPageList.constEnd(); ++it, ++zIt) - setSourceInNewTab((*it), (*zIt).toFloat()); - - const QLatin1String lastTab("LastTabPage"); - int tab = helpEngine->customValue(lastTab, 1).toInt(); - - const QLatin1String searchKey("SearchWasAttached"); const bool searchIsAttached = m_searchWidget->isAttached(); - const bool searchWasAttached = helpEngine->customValue(searchKey).toBool(); - - if (searchWasAttached && !searchIsAttached) - tabWidget->setCurrentIndex(--tab); + const bool searchWasAttached = helpEngine.searchWasAttached(); + int tabToShow = helpEngine.lastTabPage(); + if (searchWasAttached && !searchIsAttached && tabToShow != 0) + --tabToShow; else if (!searchWasAttached && searchIsAttached) - tabWidget->setCurrentIndex(++tab); - else - tabWidget->setCurrentIndex(tab); + ++tabToShow; + + for (int curTab = 0; curTab < pageCount; ++curTab) { + const QString &curFile = lastShownPageList.at(curTab); + if (helpEngine.findFile(curFile).isValid() + || curFile == QLatin1String("about:blank")) { + setSourceInNewTab(curFile, zoomFactors.at(curTab).toFloat()); + } else if (curTab + searchIsAttached <= tabToShow) + --tabToShow; + } + + tabWidget->setCurrentIndex(tabToShow); } bool CentralWidget::hasSelection() const { + TRACE_OBJ const HelpViewer *viewer = currentHelpViewer(); return viewer ? viewer->hasSelection() : false; } QUrl CentralWidget::currentSource() const { + TRACE_OBJ const HelpViewer *viewer = currentHelpViewer(); if (viewer) return viewer->source(); @@ -512,6 +366,7 @@ QUrl CentralWidget::currentSource() const QString CentralWidget::currentTitle() const { + TRACE_OBJ const HelpViewer *viewer = currentHelpViewer(); if (viewer) return viewer->documentTitle(); @@ -521,6 +376,7 @@ QString CentralWidget::currentTitle() const void CentralWidget::copySelection() { + TRACE_OBJ HelpViewer *viewer = currentHelpViewer(); if (viewer) viewer->copy(); @@ -528,13 +384,13 @@ void CentralWidget::copySelection() void CentralWidget::showTextSearch() { - findBar->show(); - findWidget->editFind->selectAll(); - findWidget->editFind->setFocus(Qt::ShortcutFocusReason); + TRACE_OBJ + findWidget->show(); } void CentralWidget::initPrinter() { + TRACE_OBJ #ifndef QT_NO_PRINTER if (!printer) printer = new QPrinter(QPrinter::HighResolution); @@ -543,6 +399,7 @@ void CentralWidget::initPrinter() void CentralWidget::print() { + TRACE_OBJ #ifndef QT_NO_PRINTER HelpViewer *viewer = currentHelpViewer(); if (!viewer) @@ -550,23 +407,23 @@ void CentralWidget::print() initPrinter(); - QPrintDialog *dlg = new QPrintDialog(printer, this); + QPrintDialog dlg(printer, this); #if defined(QT_NO_WEBKIT) if (viewer->textCursor().hasSelection()) - dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection); + dlg.addEnabledOption(QAbstractPrintDialog::PrintSelection); #endif - dlg->addEnabledOption(QAbstractPrintDialog::PrintPageRange); - dlg->addEnabledOption(QAbstractPrintDialog::PrintCollateCopies); - dlg->setWindowTitle(tr("Print Document")); - if (dlg->exec() == QDialog::Accepted) { + 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() { + TRACE_OBJ #ifndef QT_NO_PRINTER initPrinter(); QPrintPreviewDialog preview(printer, this); @@ -578,6 +435,7 @@ void CentralWidget::printPreview() void CentralWidget::printPreview(QPrinter *p) { + TRACE_OBJ #ifndef QT_NO_PRINTER HelpViewer *viewer = currentHelpViewer(); if (viewer) @@ -587,6 +445,7 @@ void CentralWidget::printPreview(QPrinter *p) void CentralWidget::pageSetup() { + TRACE_OBJ #ifndef QT_NO_PRINTER initPrinter(); QPageSetupDialog dlg(printer); @@ -596,11 +455,13 @@ void CentralWidget::pageSetup() bool CentralWidget::isHomeAvailable() const { + TRACE_OBJ return currentHelpViewer() ? true : false; } void CentralWidget::home() { + TRACE_OBJ HelpViewer *viewer = currentHelpViewer(); if (viewer) viewer->home(); @@ -608,6 +469,7 @@ void CentralWidget::home() bool CentralWidget::isForwardAvailable() const { + TRACE_OBJ const HelpViewer *viewer = currentHelpViewer(); if (viewer) return viewer->isForwardAvailable(); @@ -617,6 +479,7 @@ bool CentralWidget::isForwardAvailable() const void CentralWidget::forward() { + TRACE_OBJ HelpViewer *viewer = currentHelpViewer(); if (viewer) viewer->forward(); @@ -624,6 +487,7 @@ void CentralWidget::forward() bool CentralWidget::isBackwardAvailable() const { + TRACE_OBJ const HelpViewer *viewer = currentHelpViewer(); if (viewer) return viewer->isBackwardAvailable(); @@ -633,6 +497,7 @@ bool CentralWidget::isBackwardAvailable() const void CentralWidget::backward() { + TRACE_OBJ HelpViewer *viewer = currentHelpViewer(); if (viewer) viewer->backward(); @@ -641,49 +506,37 @@ void CentralWidget::backward() QList<QAction*> CentralWidget::globalActions() const { + TRACE_OBJ return globalActionList; } void CentralWidget::setGlobalActions(const QList<QAction*> &actions) { + TRACE_OBJ globalActionList = actions; } void CentralWidget::setSourceInNewTab(const QUrl &url, qreal zoom) { - HelpViewer *viewer; - -#if defined(QT_NO_WEBKIT) - viewer = currentHelpViewer(); - if (viewer && viewer->launchedWithExternalApp(url)) - return; -#endif + TRACE_OBJ + if (HelpViewer *viewer = currentHelpViewer()) { + if (viewer->launchWithExternalApp(url)) + return; + } - viewer = new HelpViewer(helpEngine, this); + HelpViewer *viewer = new HelpViewer(this, zoom); viewer->installEventFilter(this); viewer->setSource(url); viewer->setFocus(Qt::OtherFocusReason); tabWidget->setCurrentIndex(tabWidget->addTab(viewer, quoteTabTitle(viewer->documentTitle()))); - - QFont font; - getBrowserFontFor(viewer, &font); - -#if defined(QT_NO_WEBKIT) - font.setPointSize((int)(font.pointSize() + zoom)); - setBrowserFontFor(viewer, font); - viewer->setZoom((int)zoom); -#else - setBrowserFontFor(viewer, font); - viewer->setTextSizeMultiplier(zoom == 0.0 ? 1.0 : zoom); -#endif - connectSignals(); } HelpViewer *CentralWidget::newEmptyTab() { - HelpViewer *viewer = new HelpViewer(helpEngine, this); + TRACE_OBJ + HelpViewer *viewer = new HelpViewer(this); viewer->installEventFilter(this); viewer->setFocus(Qt::OtherFocusReason); #if defined(QT_NO_WEBKIT) @@ -695,13 +548,9 @@ HelpViewer *CentralWidget::newEmptyTab() return viewer; } -void CentralWidget::findCurrentText(const QString &text) -{ - find(text, true); -} - void CentralWidget::connectSignals() { + TRACE_OBJ const HelpViewer *viewer = currentHelpViewer(); if (viewer) { connect(viewer, SIGNAL(copyAvailable(bool)), this, @@ -716,16 +565,25 @@ void CentralWidget::connectSignals() SIGNAL(highlighted(QString))); connect(viewer, SIGNAL(sourceChanged(QUrl)), this, SLOT(setTabTitle(QUrl))); + connect(viewer, SIGNAL(printRequested()), this, SLOT(print())); } } -HelpViewer *CentralWidget::currentHelpViewer() const +HelpViewer* CentralWidget::viewerAt(int index) const +{ + TRACE_OBJ + return qobject_cast<HelpViewer*>(tabWidget->widget(index)); +} + +HelpViewer* CentralWidget::currentHelpViewer() const { + TRACE_OBJ return qobject_cast<HelpViewer*>(tabWidget->currentWidget()); } void CentralWidget::activateTab(bool onlyHelpViewer) { + TRACE_OBJ if (currentHelpViewer()) { currentHelpViewer()->setFocus(); } else { @@ -739,6 +597,7 @@ void CentralWidget::activateTab(bool onlyHelpViewer) void CentralWidget::setTabTitle(const QUrl &url) { + TRACE_OBJ Q_UNUSED(url) #if !defined(QT_NO_WEBKIT) QTabBar *tabBar = qFindChild<QTabBar*>(tabWidget); @@ -760,6 +619,7 @@ void CentralWidget::setTabTitle(const QUrl &url) void CentralWidget::currentPageChanged(int index) { + TRACE_OBJ const HelpViewer *viewer = currentHelpViewer(); if (viewer) lastTabPage = index; @@ -775,6 +635,7 @@ void CentralWidget::currentPageChanged(int index) void CentralWidget::showTabBarContextMenu(const QPoint &point) { + TRACE_OBJ HelpViewer *viewer = helpViewerFromTabPosition(tabWidget, point); if (!viewer) return; @@ -822,11 +683,12 @@ void CentralWidget::showTabBarContextMenu(const QPoint &point) } if (pickedAction == newBookmark) - emit addNewBookmark(viewer->documentTitle(), viewer->source().toString()); + emit addBookmark(viewer->documentTitle(), viewer->source().toString()); } bool CentralWidget::eventFilter(QObject *object, QEvent *e) { + TRACE_OBJ if (e->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast<QKeyEvent*>(e); switch (ke->key()) { @@ -834,14 +696,6 @@ bool CentralWidget::eventFilter(QObject *object, QEvent *e) return QWidget::eventFilter(object, e); } break; - case Qt::Key_Escape: { - if (findWidget->editFind == object) { - findBar->hide(); - if (HelpViewer *viewer = currentHelpViewer()) - viewer->setFocus(); - } - } break; - case Qt::Key_Backspace: { HelpViewer *viewer = currentHelpViewer(); if (viewer == object) { @@ -882,43 +736,52 @@ bool CentralWidget::eventFilter(QObject *object, QEvent *e) void CentralWidget::keyPressEvent(QKeyEvent *e) { + TRACE_OBJ const QString &text = e->text(); if (text.startsWith(QLatin1Char('/'))) { - if (!findBar->isVisible()) { - findBar->show(); - findWidget->editFind->clear(); + if (!findWidget->isVisible()) { + findWidget->showAndClear(); } else { - findWidget->editFind->selectAll(); + findWidget->show(); } - findWidget->editFind->setFocus(); - return; + } else { + QWidget::keyPressEvent(e); } - QWidget::keyPressEvent(e); } -void CentralWidget::find(const QString &ttf, bool forward) +void CentralWidget::findNext() { - QPalette p = findWidget->editFind->palette(); - p.setColor(QPalette::Active, QPalette::Base, Qt::white); + TRACE_OBJ + find(findWidget->text(), true); +} - bool found = false; +void CentralWidget::findPrevious() +{ + TRACE_OBJ + find(findWidget->text(), false); +} +void CentralWidget::find(const QString &ttf, bool forward) +{ + TRACE_OBJ + bool found = false; #if defined(QT_NO_WEBKIT) found = findInTextBrowser(ttf, forward); #else found = findInWebPage(ttf, forward); #endif - if (!found && !ttf.isEmpty()) - p.setColor(QPalette::Active, QPalette::Base, QColor(255, 102, 102)); + if (!found && ttf.isEmpty()) + found = true; // the line edit is empty, no need to mark it red... if (!findWidget->isVisible()) findWidget->show(); - findWidget->editFind->setPalette(p); + findWidget->setPalette(found); } bool CentralWidget::findInWebPage(const QString &ttf, bool forward) { + TRACE_OBJ #if !defined(QT_NO_WEBKIT) if (HelpViewer *viewer = currentHelpViewer()) { bool found = false; @@ -927,21 +790,23 @@ bool CentralWidget::findInWebPage(const QString &ttf, bool forward) if (!forward) options |= QWebPage::FindBackward; - if (findWidget->checkCase->isChecked()) + if (findWidget->caseSensitive()) options |= QWebPage::FindCaseSensitively; found = viewer->findText(ttf, options); - findWidget->labelWrapped->hide(); + findWidget->setTextWrappedVisible(false); if (!found) { options |= QWebPage::FindWrapsAroundDocument; found = viewer->findText(ttf, options); if (found) - findWidget->labelWrapped->show(); + findWidget->setTextWrappedVisible(true); } } // force highlighting of all other matches, also when empty (clear) options = QWebPage::HighlightAllOccurrences; + if (findWidget->caseSensitive()) + options |= QWebPage::FindCaseSensitively; viewer->findText(QLatin1String(""), options); viewer->findText(ttf, options); return found; @@ -949,12 +814,16 @@ bool CentralWidget::findInWebPage(const QString &ttf, bool forward) // this needs to stay, case for active search results page return findInTextBrowser(ttf, forward); +#else + Q_UNUSED(ttf); + Q_UNUSED(forward); #endif return false; } bool CentralWidget::findInTextBrowser(const QString &ttf, bool forward) { + TRACE_OBJ QTextBrowser *browser = qobject_cast<QTextBrowser*>(currentHelpViewer()); if (tabWidget->currentWidget() == m_searchWidget) browser = qFindChild<QTextBrowser*>(m_searchWidget); @@ -978,13 +847,10 @@ bool CentralWidget::findInTextBrowser(const QString &ttf, bool forward) if (!forward) options |= QTextDocument::FindBackward; - if (findWidget->checkCase->isChecked()) + if (findWidget->caseSensitive()) options |= QTextDocument::FindCaseSensitively; - if (findWidget->checkWholeWords->isChecked()) - options |= QTextDocument::FindWholeWords; - - findWidget->labelWrapped->hide(); + findWidget->setTextWrappedVisible(false); bool found = true; QTextCursor newCursor = doc->find(ttf, cursor, options); @@ -997,7 +863,7 @@ bool CentralWidget::findInTextBrowser(const QString &ttf, bool forward) found = false; newCursor = cursor; } else { - findWidget->labelWrapped->show(); + findWidget->setTextWrappedVisible(true); } } browser->setTextCursor(newCursor); @@ -1006,21 +872,31 @@ bool CentralWidget::findInTextBrowser(const QString &ttf, bool forward) void CentralWidget::updateBrowserFont() { - QFont font; - bool searchAttached = searchWidgetAttached(); + TRACE_OBJ + const bool searchAttached = searchWidgetAttached(); if (searchAttached) { - getBrowserFontFor(m_searchWidget, &font); - setBrowserFontFor(m_searchWidget, font); + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + m_searchWidget->setFont(helpEngine.usesBrowserFont() + ? helpEngine.browserFont() : qApp->font()); } - int i = searchAttached ? 1 : 0; - getBrowserFontFor(tabWidget->widget(i), &font); - for ( ; i < tabWidget->count(); ++i) - setBrowserFontFor(tabWidget->widget(i), font); + const int count = tabWidget->count(); + if (HelpViewer* viewer = viewerAt(count - 1)) { + const QFont &font = viewer->viewerFont(); + for (int i = searchAttached ? 1 : 0; i < count; ++i) + viewerAt(i)->setViewerFont(font); + } +} + +bool CentralWidget::searchWidgetAttached() const +{ + TRACE_OBJ + return m_searchWidget && m_searchWidget->isAttached(); } void CentralWidget::createSearchWidget(QHelpSearchEngine *searchEngine) { + TRACE_OBJ if (m_searchWidget) return; @@ -1030,15 +906,16 @@ void CentralWidget::createSearchWidget(QHelpSearchEngine *searchEngine) connect(m_searchWidget, SIGNAL(requestShowLinkInNewTab(QUrl)), this, SLOT(setSourceFromSearchInNewTab(QUrl))); - QFont font; - getBrowserFontFor(m_searchWidget, &font); - setBrowserFontFor(m_searchWidget, font); + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + m_searchWidget->setFont(!helpEngine.usesBrowserFont() ? qApp->font() + : helpEngine.browserFont()); } void CentralWidget::activateSearchWidget(bool updateLastTabPage) { + TRACE_OBJ if (!m_searchWidget) - createSearchWidget(helpEngine->searchEngine()); + createSearchWidget(HelpEngineWrapper::instance().searchEngine()); if (!m_searchWidget->isAttached()) { tabWidget->insertTab(0, m_searchWidget, tr("Search")); @@ -1054,6 +931,7 @@ void CentralWidget::activateSearchWidget(bool updateLastTabPage) void CentralWidget::removeSearchWidget() { + TRACE_OBJ if (searchWidgetAttached()) { tabWidget->removeTab(0); m_searchWidget->setAttached(false); @@ -1062,6 +940,7 @@ void CentralWidget::removeSearchWidget() int CentralWidget::availableHelpViewer() const { + TRACE_OBJ int count = tabWidget->count(); if (searchWidgetAttached()) count--; @@ -1070,6 +949,7 @@ int CentralWidget::availableHelpViewer() const bool CentralWidget::enableTabCloseAction() const { + TRACE_OBJ int minTabCount = 1; if (searchWidgetAttached()) minTabCount = 2; @@ -1079,6 +959,7 @@ bool CentralWidget::enableTabCloseAction() const QString CentralWidget::quoteTabTitle(const QString &title) const { + TRACE_OBJ QString s = title; return s.replace(QLatin1Char('&'), QLatin1String("&&")); } @@ -1086,6 +967,7 @@ QString CentralWidget::quoteTabTitle(const QString &title) const void CentralWidget::setSourceFromSearch(const QUrl &url) { + TRACE_OBJ setSource(url); #if defined(QT_NO_WEBKIT) highlightSearchTerms(); @@ -1098,6 +980,7 @@ CentralWidget::setSourceFromSearch(const QUrl &url) void CentralWidget::setSourceFromSearchInNewTab(const QUrl &url) { + TRACE_OBJ setSourceInNewTab(url); #if defined(QT_NO_WEBKIT) highlightSearchTerms(); @@ -1110,11 +993,13 @@ CentralWidget::setSourceFromSearchInNewTab(const QUrl &url) void CentralWidget::highlightSearchTerms() { + TRACE_OBJ HelpViewer *viewer = currentHelpViewer(); if (!viewer) return; - QHelpSearchEngine *searchEngine = helpEngine->searchEngine(); + QHelpSearchEngine *searchEngine = + HelpEngineWrapper::instance().searchEngine(); QList<QHelpSearchQuery> queryList = searchEngine->query(); QStringList terms; @@ -1174,8 +1059,33 @@ CentralWidget::highlightSearchTerms() #endif } + +void CentralWidget::closeOrReloadTabs(const QList<int> &indices, bool tryReload) +{ + TRACE_OBJ + QList<int> sortedIndices = indices; + qSort(sortedIndices); + for (int i = sortedIndices.count(); --i >= 0;) { + const int tab = sortedIndices.at(i); + bool close = true; + if (tryReload) { + HelpViewer *viewer = + qobject_cast<HelpViewer*>(tabWidget->widget(tab)); + if (HelpEngineWrapper::instance().findFile(viewer->source()).isValid()) { + viewer->reload(); + close = false; + } + } + if (close) + closeTabAt(tab); + } + if (availableHelpViewer() == 0) + setSource(QUrl(QLatin1String("about:blank"))); +} + void CentralWidget::closeTabAt(int index) { + TRACE_OBJ HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(index)); tabWidget->removeTab(index); QTimer::singleShot(0, viewer, SLOT(deleteLater())); @@ -1183,8 +1093,9 @@ void CentralWidget::closeTabAt(int index) QMap<int, QString> CentralWidget::currentSourceFileList() const { + TRACE_OBJ QMap<int, QString> sourceList; - for (int i = 1; i < tabWidget->count(); ++i) { + for (int i = 0; i < tabWidget->count(); ++i) { HelpViewer *viewer = qobject_cast<HelpViewer*>(tabWidget->widget(i)); if (viewer && viewer->source().isValid()) sourceList.insert(i, viewer->source().host()); @@ -1192,40 +1103,4 @@ QMap<int, QString> CentralWidget::currentSourceFileList() const return sourceList; } -void CentralWidget::getBrowserFontFor(QWidget *viewer, QFont *font) -{ - const QLatin1String key("useBrowserFont"); - if (!helpEngine->customValue(key, false).toBool()) { - *font = qApp->font(); // case for QTextBrowser and SearchWidget -#if !defined(QT_NO_WEBKIT) - QWebView *view = qobject_cast<QWebView*> (viewer); - if (view) { - QWebSettings *settings = QWebSettings::globalSettings(); - *font = QFont(settings->fontFamily(QWebSettings::StandardFont), - settings->fontSize(QWebSettings::DefaultFontSize)); - } -#endif - } else { - *font = qVariantValue<QFont>(helpEngine->customValue( - QLatin1String("browserFont"))); - } -} - -void CentralWidget::setBrowserFontFor(QWidget *widget, const QFont &font) -{ -#if !defined(QT_NO_WEBKIT) - QWebView *view = qobject_cast<QWebView*> (widget); - if (view) { - QWebSettings *settings = view->settings(); - settings->setFontFamily(QWebSettings::StandardFont, font.family()); - settings->setFontSize(QWebSettings::DefaultFontSize, font.pointSize()); - } else if (widget && widget->font() != font) { - widget->setFont(font); - } -#else - if (widget && widget->font() != font) - widget->setFont(font); -#endif -} - QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/centralwidget.h b/tools/assistant/tools/assistant/centralwidget.h index 9e32985..f286ff7 100644 --- a/tools/assistant/tools/assistant/centralwidget.h +++ b/tools/assistant/tools/assistant/centralwidget.h @@ -38,78 +38,27 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - #ifndef CENTRALWIDGET_H #define CENTRALWIDGET_H #include <QtCore/QUrl> -#include <QtCore/QPoint> -#include <QtCore/QObject> - #include <QtGui/QWidget> -#include "searchwidget.h" - QT_BEGIN_NAMESPACE -class QEvent; -class QLabel; -class QAction; -class QCheckBox; -class QLineEdit; -class QTextBrowser; -class QToolButton; - +class FindWidget; class HelpViewer; -class QTabWidget; -class QHelpEngine; -class CentralWidget; -class PrintHelper; class MainWindow; - class QHelpSearchEngine; - -class FindWidget : public QWidget -{ - Q_OBJECT - -public: - FindWidget(QWidget *parent = 0); - ~FindWidget(); - -signals: - void findNext(); - void findPrevious(); - -protected: - void hideEvent(QHideEvent* event); - void showEvent(QShowEvent * event); - -private slots: - void updateButtons(); - -private: - QToolButton* setupToolButton(const QString &text, const QString &icon); - -private: - QLineEdit *editFind; - QCheckBox *checkCase; - QLabel *labelWrapped; - QToolButton *toolNext; - QToolButton *toolClose; - QToolButton *toolPrevious; - QCheckBox *checkWholeWords; - - QPalette appPalette; - friend class CentralWidget; -}; +class QTabWidget; +class SearchWidget; class CentralWidget : public QWidget { Q_OBJECT public: - CentralWidget(QHelpEngine *engine, MainWindow *parent); + CentralWidget(MainWindow *parent); ~CentralWidget(); void setupWidget(); @@ -121,12 +70,11 @@ public: bool isBackwardAvailable() const; QList<QAction*> globalActions() const; void setGlobalActions(const QList<QAction*> &actions); + + HelpViewer *viewerAt(int index) const; HelpViewer *currentHelpViewer() const; - void activateTab(bool onlyHelpViewer = false); - bool searchWidgetAttached() const { - return m_searchWidget && m_searchWidget->isAttached(); - } + bool searchWidgetAttached() const; void createSearchWidget(QHelpSearchEngine *searchEngine); void activateSearchWidget(bool updateLastTabPage = false); void removeSearchWidget(); @@ -134,6 +82,7 @@ public: int availableHelpViewer() const; bool enableTabCloseAction() const; + void closeOrReloadTabs(const QList<int> &indices, bool tryReload); void closeTabAt(int index); QMap<int, QString> currentSourceFileList() const; @@ -142,11 +91,9 @@ public: public slots: void zoomIn(); void zoomOut(); - void findNext(); void nextPage(); void resetZoom(); void previousPage(); - void findPrevious(); void copySelection(); void showTextSearch(); void print(); @@ -155,12 +102,17 @@ public slots: void updateBrowserFont(); void setSource(const QUrl &url); void setSourceInNewTab(const QUrl &url, qreal zoom = 0.0); - void findCurrentText(const QString &text); HelpViewer *newEmptyTab(); void home(); void forward(); void backward(); + void activateTab(bool onlyHelpViewer = false); + + void findNext(); + void findPrevious(); + void find(const QString &text, bool forward); + signals: void currentViewerChanged(); void copyAvailable(bool yes); @@ -168,7 +120,7 @@ signals: void highlighted(const QString &link); void forwardAvailable(bool available); void backwardAvailable(bool available); - void addNewBookmark(const QString &title, const QString &url); + void addBookmark(const QString &title, const QString &url); protected: void keyPressEvent(QKeyEvent *); @@ -187,25 +139,18 @@ private slots: private: void connectSignals(); bool eventFilter(QObject *object, QEvent *e); - void find(const QString &ttf, bool forward); bool findInWebPage(const QString &ttf, bool forward); bool findInTextBrowser(const QString &ttf, bool forward); void initPrinter(); QString quoteTabTitle(const QString &title) const; void setLastShownPages(); - void getBrowserFontFor(QWidget* viewer, QFont *font); - void setBrowserFontFor(QWidget *widget, const QFont &font); - private: int lastTabPage; - QString collectionFile; QList<QAction*> globalActionList; - QWidget *findBar; QTabWidget *tabWidget; FindWidget *findWidget; - QHelpEngine *helpEngine; QPrinter *printer; bool usesDefaultCollection; diff --git a/tools/assistant/tools/assistant/cmdlineparser.cpp b/tools/assistant/tools/assistant/cmdlineparser.cpp index 38814a5..b6c0beb 100644 --- a/tools/assistant/tools/assistant/cmdlineparser.cpp +++ b/tools/assistant/tools/assistant/cmdlineparser.cpp @@ -38,29 +38,17 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "tracer.h" #include <QtCore/QFileInfo> +#include <QtCore/QStringBuilder> #include <QtGui/QMessageBox> #include "cmdlineparser.h" QT_BEGIN_NAMESPACE -#define CHECK_NEXT_ARG \ - ++i < arguments.count() && !arguments.at(i).startsWith(QLatin1String("-")) - -CmdLineParser::CmdLineParser() - : m_enableRemoteControl(false), - m_contents(Untouched), - m_index(Untouched), - m_bookmarks(Untouched), - m_search(Untouched), - m_register(None), - m_removeSearchIndex(false), - m_copy(false), - m_quiet(false) -{ - m_helpMessage = QLatin1String( +const QString CmdLineParser::m_helpMessage = QLatin1String( "Usage: assistant [Options]\n\n" "-collectionFile file Uses the specified collection\n" " file instead of the default one\n" @@ -85,156 +73,72 @@ CmdLineParser::CmdLineParser() " file.\n" "-setCurrentFilter filter Set the filter as the active filter.\n" "-remove-search-index Removes the full text search index.\n" + "-rebuild-search-index Re-builds the full text search index (potentially slow).\n" "-quiet Does not display any error or\n" " status message.\n" "-help Displays this help.\n" ); -} -CmdLineParser::Result CmdLineParser::parse(const QStringList &arguments) -{ - QString error; - bool showHelp = false; - for (int j=1; j<arguments.count(); ++j) { - if (arguments.at(j).toLower() == QLatin1String("-quiet")) { +CmdLineParser::CmdLineParser(const QStringList &arguments) + : m_pos(0), + m_enableRemoteControl(false), + m_contents(Untouched), + m_index(Untouched), + m_bookmarks(Untouched), + m_search(Untouched), + m_register(None), + m_removeSearchIndex(false), + m_rebuildSearchIndex(false), + m_quiet(false) +{ + TRACE_OBJ + for (int i = 1; i < arguments.count(); ++i) { + const QString &arg = arguments.at(i); + if (arg.toLower() == "-quiet") m_quiet = true; - break; - } + else + m_arguments.append(arg); } +} - for (int i=1; i<arguments.count(); ++i) { - QString arg = arguments.at(i).toLower(); - if (arg == QLatin1String("-collectionfile")) { - if (CHECK_NEXT_ARG) { - m_collectionFile = getFileName(arguments.at(i)); - if (m_collectionFile.isEmpty()) { - error = QObject::tr("The specified collection file does not exist!"); - break; - } - } else { - error = QObject::tr("Missing collection file!"); - break; - } - } else if (arg == QLatin1String("-showurl")) { - if (CHECK_NEXT_ARG) { - QUrl url(arguments.at(i)); - if (url.isValid()) { - m_url = url; - } else { - error = QObject::tr("Invalid URL!"); - break; - } - } else { - error = QObject::tr("Missing URL!"); - break; - } - } else if (arg == QLatin1String("-enableremotecontrol")) { +CmdLineParser::Result CmdLineParser::parse() +{ + TRACE_OBJ + bool showHelp = false; + + while (m_error.isEmpty() && hasMoreArgs()) { + const QString &arg = nextArg().toLower(); + if (arg == QLatin1String("-collectionfile")) + handleCollectionFileOption(); + else if (arg == QLatin1String("-showurl")) + handleShowUrlOption(); + else if (arg == QLatin1String("-enableremotecontrol")) m_enableRemoteControl = true; - } else if (arg == QLatin1String("-show")) { - if (CHECK_NEXT_ARG) { - arg = arguments.at(i).toLower(); - if (arg == QLatin1String("contents")) { - m_contents = Show; - } else if (arg == QLatin1String("index")) { - m_index = Show; - } else if (arg == QLatin1String("bookmarks")) { - m_bookmarks = Show; - } else if (arg == QLatin1String("search")) { - m_search = Show; - } else { - error = QObject::tr("Unknown widget: %1").arg(arg); - break; - } - } else { - error = QObject::tr("Missing widget!"); - break; - } - } else if (arg == QLatin1String("-hide")) { - if (CHECK_NEXT_ARG) { - arg = arguments.at(i).toLower(); - if (arg == QLatin1String("contents")) { - m_contents = Hide; - } else if (arg == QLatin1String("index")) { - m_index = Hide; - } else if (arg == QLatin1String("bookmarks")) { - m_bookmarks = Hide; - } else if (arg == QLatin1String("search")) { - m_search = Hide; - } else { - error = QObject::tr("Unknown widget: %1").arg(arg); - break; - } - } else { - error = QObject::tr("Missing widget!"); - break; - } - } else if (arg == QLatin1String("-activate")) { - if (CHECK_NEXT_ARG) { - arg = arguments.at(i).toLower(); - if (arg == QLatin1String("contents")) { - m_contents = Activate; - } else if (arg == QLatin1String("index")) { - m_index = Activate; - } else if (arg == QLatin1String("bookmarks")) { - m_bookmarks = Activate; - } else if (arg == QLatin1String("search")) { - m_search = Activate; - } else { - error = QObject::tr("Unknown widget: %1").arg(arg); - break; - } - } else { - error = QObject::tr("Missing widget!"); - break; - } - } else if (arg == QLatin1String("-register")) { - if (CHECK_NEXT_ARG) { - m_helpFile = getFileName(arguments.at(i)); - if (m_helpFile.isEmpty()) { - error = QObject::tr("The specified Qt help file does not exist!"); - break; - } - m_register = Register; - } else { - error = QObject::tr("Missing help file!"); - break; - } - } else if (arg == QLatin1String("-unregister")) { - if (CHECK_NEXT_ARG) { - m_helpFile = getFileName(arguments.at(i)); - if (m_helpFile.isEmpty()) { - error = QObject::tr("The specified Qt help file does not exist!"); - break; - } - m_register = Unregister; - } else { - error = QObject::tr("Missing help file!"); - break; - } - } else if (arg == QLatin1String("-setcurrentfilter")) { - if (CHECK_NEXT_ARG) { - m_currentFilter = arguments.at(i); - } else { - error = QObject::tr("Missing filter argument!"); - break; - } - } else if (arg == QLatin1String("-remove-search-index")) { + else if (arg == QLatin1String("-show")) + handleShowOption(); + else if (arg == QLatin1String("-hide")) + handleHideOption(); + else if (arg == QLatin1String("-activate")) + handleActivateOption(); + else if (arg == QLatin1String("-register")) + handleRegisterOption(); + else if (arg == QLatin1String("-unregister")) + handleUnregisterOption(); + else if (arg == QLatin1String("-setcurrentfilter")) + handleSetCurrentFilterOption(); + else if (arg == QLatin1String("-remove-search-index")) m_removeSearchIndex = true; - } else if (arg == QLatin1String("-quiet")) { - continue; - } else if (arg == QLatin1String("-help")) { + else if (arg == QLatin1String("-rebuild-search-index")) + m_rebuildSearchIndex = true; + else if (arg == QLatin1String("-help")) showHelp = true; - } else if (arg == QLatin1String("-copy")) { - m_copy = true; - } else { - error = QObject::tr("Unknown option: %1").arg(arg); - break; - } + else + m_error = tr("Unknown option: %1").arg(arg); } - if (!error.isEmpty()) { - showMessage(error + QLatin1String("\n\n\n") + m_helpMessage, true); + if (!m_error.isEmpty()) { + showMessage(m_error + QLatin1String("\n\n\n") + m_helpMessage, true); return Error; } else if (showHelp) { showMessage(m_helpMessage, false); @@ -243,8 +147,125 @@ CmdLineParser::Result CmdLineParser::parse(const QStringList &arguments) return Ok; } +bool CmdLineParser::hasMoreArgs() const +{ + TRACE_OBJ + return m_pos < m_arguments.count(); +} + +const QString &CmdLineParser::nextArg() +{ + TRACE_OBJ + Q_ASSERT(hasMoreArgs()); + return m_arguments.at(m_pos++); +} + +void CmdLineParser::handleCollectionFileOption() +{ + TRACE_OBJ + if (hasMoreArgs()) { + const QString &fileName = nextArg(); + m_collectionFile = getFileName(fileName); + if (m_collectionFile.isEmpty()) + m_error = tr("The collection file '%1' does not exist."). + arg(fileName); + } else { + m_error = tr("Missing collection file."); + } +} + +void CmdLineParser::handleShowUrlOption() +{ + TRACE_OBJ + if (hasMoreArgs()) { + const QString &urlString = nextArg(); + QUrl url(urlString); + if (url.isValid()) { + m_url = url; + } else + m_error = tr("Invalid URL '%1'.").arg(urlString); + } else { + m_error = tr("Missing URL."); + } +} + +void CmdLineParser::handleShowOption() +{ + TRACE_OBJ + handleShowOrHideOrActivateOption(Show); +} + +void CmdLineParser::handleHideOption() +{ + TRACE_OBJ + handleShowOrHideOrActivateOption(Hide); +} + +void CmdLineParser::handleActivateOption() +{ + TRACE_OBJ + handleShowOrHideOrActivateOption(Activate); +} + +void CmdLineParser::handleShowOrHideOrActivateOption(ShowState state) +{ + TRACE_OBJ + if (hasMoreArgs()) { + const QString &widget = nextArg().toLower(); + if (widget == QLatin1String("contents")) + m_contents = state; + else if (widget == QLatin1String("index")) + m_index = state; + else if (widget == QLatin1String("bookmarks")) + m_bookmarks = state; + else if (widget == QLatin1String("search")) + m_search = state; + else + m_error = tr("Unknown widget: %1").arg(widget); + } else { + m_error = tr("Missing widget."); + } +} + +void CmdLineParser::handleRegisterOption() +{ + TRACE_OBJ + handleRegisterOrUnregisterOption(Register); +} + +void CmdLineParser::handleUnregisterOption() +{ + TRACE_OBJ + handleRegisterOrUnregisterOption(Unregister); +} + +void CmdLineParser::handleRegisterOrUnregisterOption(RegisterState state) +{ + TRACE_OBJ + if (hasMoreArgs()) { + const QString &fileName = nextArg(); + m_helpFile = getFileName(fileName); + if (m_helpFile.isEmpty()) + m_error = tr("The Qt help file '%1' does not exist.").arg(fileName); + else + m_register = state; + } else { + m_error = tr("Missing help file."); + } +} + +void CmdLineParser::handleSetCurrentFilterOption() +{ + TRACE_OBJ + if (hasMoreArgs()) + m_currentFilter = nextArg(); + else + m_error = tr("Missing filter argument."); +} + QString CmdLineParser::getFileName(const QString &fileName) { + TRACE_OBJ QFileInfo fi(fileName); if (!fi.exists()) return QString(); @@ -253,14 +274,15 @@ QString CmdLineParser::getFileName(const QString &fileName) void CmdLineParser::showMessage(const QString &msg, bool error) { + TRACE_OBJ if (m_quiet) return; #ifdef Q_OS_WIN - QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>"); + QString message = QLatin1String("<pre>") % msg % QLatin1String("</pre>"); if (error) - QMessageBox::critical(0, QObject::tr("Qt Assistant"), s); + QMessageBox::critical(0, tr("Error"), message); else - QMessageBox::information(0, QObject::tr("Qt Assistant"), s); + QMessageBox::information(0, tr("Notice"), message); #else fprintf(error ? stderr : stdout, "%s\n", qPrintable(msg)); #endif @@ -268,61 +290,79 @@ void CmdLineParser::showMessage(const QString &msg, bool error) void CmdLineParser::setCollectionFile(const QString &file) { + TRACE_OBJ m_collectionFile = file; } QString CmdLineParser::collectionFile() const { + TRACE_OBJ return m_collectionFile; } QUrl CmdLineParser::url() const { + TRACE_OBJ return m_url; } bool CmdLineParser::enableRemoteControl() const { + TRACE_OBJ return m_enableRemoteControl; } CmdLineParser::ShowState CmdLineParser::contents() const { + TRACE_OBJ return m_contents; } CmdLineParser::ShowState CmdLineParser::index() const { + TRACE_OBJ return m_index; } CmdLineParser::ShowState CmdLineParser::bookmarks() const { + TRACE_OBJ return m_bookmarks; } CmdLineParser::ShowState CmdLineParser::search() const { + TRACE_OBJ return m_search; } QString CmdLineParser::currentFilter() const { + TRACE_OBJ return m_currentFilter; } bool CmdLineParser::removeSearchIndex() const { + TRACE_OBJ return m_removeSearchIndex; } +bool CmdLineParser::rebuildSearchIndex() const +{ + TRACE_OBJ + return m_rebuildSearchIndex; +} + CmdLineParser::RegisterState CmdLineParser::registerRequest() const { + TRACE_OBJ return m_register; } QString CmdLineParser::helpFile() const { + TRACE_OBJ return m_helpFile; } diff --git a/tools/assistant/tools/assistant/cmdlineparser.h b/tools/assistant/tools/assistant/cmdlineparser.h index 17707cb..5573081 100644 --- a/tools/assistant/tools/assistant/cmdlineparser.h +++ b/tools/assistant/tools/assistant/cmdlineparser.h @@ -42,6 +42,7 @@ #ifndef CMDLINEPARSER_H #define CMDLINEPARSER_H +#include <QtCore/QCoreApplication> #include <QtCore/QStringList> #include <QtCore/QUrl> @@ -49,13 +50,14 @@ QT_BEGIN_NAMESPACE class CmdLineParser { + Q_DECLARE_TR_FUNCTIONS(CmdLineParser) public: enum Result {Ok, Help, Error}; enum ShowState {Untouched, Show, Hide, Activate}; enum RegisterState {None, Register, Unregister}; - CmdLineParser(); - Result parse(const QStringList &arguments); + CmdLineParser(const QStringList &arguments); + Result parse(); void setCollectionFile(const QString &file); QString collectionFile() const; @@ -68,17 +70,30 @@ public: ShowState search() const; QString currentFilter() const; bool removeSearchIndex() const; + bool rebuildSearchIndex() const; RegisterState registerRequest() const; QString helpFile() const; - bool copy() const { return m_copy; } - void showMessage(const QString &msg, bool error); private: QString getFileName(const QString &fileName); + bool hasMoreArgs() const; + const QString &nextArg(); + void handleCollectionFileOption(); + void handleShowUrlOption(); + void handleShowOption(); + void handleHideOption(); + void handleActivateOption(); + void handleShowOrHideOrActivateOption(ShowState state); + void handleRegisterOption(); + void handleUnregisterOption(); + void handleRegisterOrUnregisterOption(RegisterState state); + void handleSetCurrentFilterOption(); - QString m_helpMessage; + QStringList m_arguments; + int m_pos; + static const QString m_helpMessage; QString m_collectionFile; QString m_cloneFile; QString m_helpFile; @@ -92,8 +107,9 @@ private: RegisterState m_register; QString m_currentFilter; bool m_removeSearchIndex; - bool m_copy; + bool m_rebuildSearchIndex; bool m_quiet; + QString m_error; }; QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/contentwindow.cpp b/tools/assistant/tools/assistant/contentwindow.cpp index 4640673..8afa1df 100644 --- a/tools/assistant/tools/assistant/contentwindow.cpp +++ b/tools/assistant/tools/assistant/contentwindow.cpp @@ -38,25 +38,26 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "tracer.h" #include "contentwindow.h" #include "centralwidget.h" +#include "helpenginewrapper.h" +#include "helpviewer.h" #include <QtGui/QLayout> #include <QtGui/QFocusEvent> #include <QtGui/QMenu> -#include <QtHelp/QHelpEngine> #include <QtHelp/QHelpContentWidget> QT_BEGIN_NAMESPACE -ContentWindow::ContentWindow(QHelpEngine *helpEngine) - : m_helpEngine(helpEngine) - , m_contentWidget(0) +ContentWindow::ContentWindow() + : m_contentWidget(HelpEngineWrapper::instance().contentWidget()) , m_expandDepth(-2) { - m_contentWidget = m_helpEngine->contentWidget(); + TRACE_OBJ m_contentWidget->viewport()->installEventFilter(this); m_contentWidget->setContextMenuPolicy(Qt::CustomContextMenu); @@ -76,10 +77,12 @@ ContentWindow::ContentWindow(QHelpEngine *helpEngine) ContentWindow::~ContentWindow() { + TRACE_OBJ } bool ContentWindow::syncToContent(const QUrl& url) { + TRACE_OBJ QModelIndex idx = m_contentWidget->indexOf(url); if (!idx.isValid()) return false; @@ -89,6 +92,8 @@ bool ContentWindow::syncToContent(const QUrl& url) void ContentWindow::expandTOC() { + TRACE_OBJ + Q_ASSERT(m_expandDepth >= -2); if (m_expandDepth > -2) { expandToDepth(m_expandDepth); m_expandDepth = -2; @@ -97,42 +102,51 @@ void ContentWindow::expandTOC() void ContentWindow::expandToDepth(int depth) { + TRACE_OBJ + Q_ASSERT(depth >= -2); m_expandDepth = depth; if (depth == -1) m_contentWidget->expandAll(); + else if (depth == 0) + m_contentWidget->collapseAll(); else - m_contentWidget->expandToDepth(depth); + m_contentWidget->expandToDepth(depth - 1); } void ContentWindow::focusInEvent(QFocusEvent *e) { + TRACE_OBJ if (e->reason() != Qt::MouseFocusReason) m_contentWidget->setFocus(); } void ContentWindow::keyPressEvent(QKeyEvent *e) { + TRACE_OBJ if (e->key() == Qt::Key_Escape) emit escapePressed(); } bool ContentWindow::eventFilter(QObject *o, QEvent *e) { + TRACE_OBJ if (m_contentWidget && o == m_contentWidget->viewport() && e->type() == QEvent::MouseButtonRelease) { QMouseEvent *me = static_cast<QMouseEvent*>(e); - QModelIndex index = m_contentWidget->indexAt(me->pos()); - QItemSelectionModel *sm = m_contentWidget->selectionModel(); + const QModelIndex &index = m_contentWidget->indexAt(me->pos()); + if (!index.isValid()) + return QWidget::eventFilter(o, e); - Qt::MouseButtons button = me->button(); - if (index.isValid() && (sm && sm->isSelected(index))) { + const Qt::MouseButtons button = me->button(); + QItemSelectionModel *sm = m_contentWidget->selectionModel(); + if (sm->isSelected(index)) { if ((button == Qt::LeftButton && (me->modifiers() & Qt::ControlModifier)) || (button == Qt::MidButton)) { QHelpContentModel *contentModel = qobject_cast<QHelpContentModel*>(m_contentWidget->model()); if (contentModel) { QHelpContentItem *itm = contentModel->contentItemAt(index); - if (itm && !isPdfFile(itm)) + if (itm && AbstractHelpViewer::canOpenPage(itm->url().path())) CentralWidget::instance()->setSourceInNewTab(itm->url()); } } else if (button == Qt::LeftButton) { @@ -146,6 +160,7 @@ bool ContentWindow::eventFilter(QObject *o, QEvent *e) void ContentWindow::showContextMenu(const QPoint &pos) { + TRACE_OBJ if (!m_contentWidget->indexAt(pos).isValid()) return; @@ -157,7 +172,7 @@ void ContentWindow::showContextMenu(const QPoint &pos) QMenu menu; QAction *curTab = menu.addAction(tr("Open Link")); QAction *newTab = menu.addAction(tr("Open Link in New Tab")); - if (isPdfFile(itm)) + if (!AbstractHelpViewer::canOpenPage(itm->url().path())) newTab->setEnabled(false); menu.move(m_contentWidget->mapToGlobal(pos)); @@ -171,20 +186,17 @@ void ContentWindow::showContextMenu(const QPoint &pos) void ContentWindow::itemClicked(const QModelIndex &index) { + TRACE_OBJ QHelpContentModel *contentModel = qobject_cast<QHelpContentModel*>(m_contentWidget->model()); if (contentModel) { - QHelpContentItem *itm = contentModel->contentItemAt(index); - if (itm) - emit linkActivated(itm->url()); + if (QHelpContentItem *itm = contentModel->contentItemAt(index)) { + const QUrl &url = itm->url(); + if (url != CentralWidget::instance()->currentSource()) + emit linkActivated(url); + } } } -bool ContentWindow::isPdfFile(QHelpContentItem *item) const -{ - const QString &path = item->url().path(); - return path.endsWith(QLatin1String(".pdf"), Qt::CaseInsensitive); -} - QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/contentwindow.h b/tools/assistant/tools/assistant/contentwindow.h index f3bf060..62855dd 100644 --- a/tools/assistant/tools/assistant/contentwindow.h +++ b/tools/assistant/tools/assistant/contentwindow.h @@ -57,7 +57,7 @@ class ContentWindow : public QWidget Q_OBJECT public: - ContentWindow(QHelpEngine *helpEngine); + ContentWindow(); ~ContentWindow(); bool syncToContent(const QUrl &url); @@ -78,8 +78,7 @@ private: bool eventFilter(QObject *o, QEvent *e); bool isPdfFile(QHelpContentItem *item) const; - QHelpEngine *m_helpEngine; - QHelpContentWidget *m_contentWidget; + QHelpContentWidget * const m_contentWidget; int m_expandDepth; }; diff --git a/tools/assistant/tools/assistant/doc/assistant.qdocconf b/tools/assistant/tools/assistant/doc/assistant.qdocconf index 365613b..3b4b5f8 100644 --- a/tools/assistant/tools/assistant/doc/assistant.qdocconf +++ b/tools/assistant/tools/assistant/doc/assistant.qdocconf @@ -12,5 +12,5 @@ HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \ "<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \ "<td width=\"30%\" align=\"left\">Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)</td>\n" \ "<td width=\"40%\" align=\"center\">Trademarks</td>\n" \ - "<td width=\"30%\" align=\"right\"><div align=\"right\">Qt 4.6.3</div></td>\n" \ + "<td width=\"30%\" align=\"right\"><div align=\"right\">Qt 4.7.0</div></td>\n" \ "</tr></table></div></address>" diff --git a/tools/assistant/tools/assistant/filternamedialog.cpp b/tools/assistant/tools/assistant/filternamedialog.cpp index 1560e04..f75f999 100644 --- a/tools/assistant/tools/assistant/filternamedialog.cpp +++ b/tools/assistant/tools/assistant/filternamedialog.cpp @@ -38,6 +38,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "tracer.h" #include <QtGui/QPushButton> @@ -48,6 +49,7 @@ QT_BEGIN_NAMESPACE FilterNameDialog::FilterNameDialog(QWidget *parent) : QDialog(parent) { + TRACE_OBJ m_ui.setupUi(this); connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept())); @@ -61,11 +63,13 @@ FilterNameDialog::FilterNameDialog(QWidget *parent) QString FilterNameDialog::filterName() const { + TRACE_OBJ return m_ui.lineEdit->text(); } void FilterNameDialog::updateOkButton() { + TRACE_OBJ m_ui.buttonBox->button(QDialogButtonBox::Ok) ->setDisabled(m_ui.lineEdit->text().isEmpty()); } diff --git a/tools/assistant/tools/assistant/findwidget.cpp b/tools/assistant/tools/assistant/findwidget.cpp new file mode 100644 index 0000000..60318d4 --- /dev/null +++ b/tools/assistant/tools/assistant/findwidget.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" +#include "findwidget.h" + +#include <QtGui/QApplication> +#include <QtGui/QCheckBox> +#include <QtGui/QHideEvent> +#include <QtGui/QKeyEvent> +#include <QtGui/QLabel> +#include <QtGui/QLayout> +#include <QtGui/QLineEdit> +#include <QtGui/QToolButton> + +QT_BEGIN_NAMESPACE + +FindWidget::FindWidget(QWidget *parent) + : QWidget(parent) + , appPalette(qApp->palette()) +{ + TRACE_OBJ + installEventFilter(this); + QHBoxLayout *hboxLayout = new QHBoxLayout(this); + QString resourcePath = QLatin1String(":/trolltech/assistant/images/"); + +#ifndef Q_OS_MAC + hboxLayout->setMargin(0); + hboxLayout->setSpacing(6); + resourcePath.append(QLatin1String("win")); +#else + resourcePath.append(QLatin1String("mac")); +#endif + + toolClose = setupToolButton(QLatin1String(""), + resourcePath + QLatin1String("/closetab.png")); + hboxLayout->addWidget(toolClose); + connect(toolClose, SIGNAL(clicked()), SLOT(hide())); + + editFind = new QLineEdit(this); + hboxLayout->addWidget(editFind); + editFind->setMinimumSize(QSize(150, 0)); + connect(editFind, SIGNAL(textChanged(QString)), this, + SLOT(textChanged(QString))); + connect(editFind, SIGNAL(returnPressed()), this, SIGNAL(findNext())); + connect(editFind, SIGNAL(textChanged(QString)), this, SLOT(updateButtons())); + + toolPrevious = setupToolButton(tr("Previous"), + resourcePath + QLatin1String("/previous.png")); + connect(toolPrevious, SIGNAL(clicked()), this, SIGNAL(findPrevious())); + + hboxLayout->addWidget(toolPrevious); + + toolNext = setupToolButton(tr("Next"), + resourcePath + QLatin1String("/next.png")); + hboxLayout->addWidget(toolNext); + connect(toolNext, SIGNAL(clicked()), this, SIGNAL(findNext())); + + checkCase = new QCheckBox(tr("Case Sensitive"), this); + hboxLayout->addWidget(checkCase); + + labelWrapped = new QLabel(this); + labelWrapped->setScaledContents(true); + labelWrapped->setTextFormat(Qt::RichText); + labelWrapped->setMinimumSize(QSize(0, 20)); + labelWrapped->setMaximumSize(QSize(105, 20)); + labelWrapped->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); + labelWrapped->setText(tr("<img src=\":/trolltech/assistant/images/wrap.png\"" + "> Search wrapped")); + hboxLayout->addWidget(labelWrapped); + + QSpacerItem *spacerItem = new QSpacerItem(20, 20, QSizePolicy::Expanding, + QSizePolicy::Minimum); + hboxLayout->addItem(spacerItem); + setMinimumWidth(minimumSizeHint().width()); + labelWrapped->hide(); + + updateButtons(); +} + +FindWidget::~FindWidget() +{ + TRACE_OBJ +} + +void FindWidget::show() +{ + TRACE_OBJ + QWidget::show(); + editFind->selectAll(); + editFind->setFocus(Qt::ShortcutFocusReason); +} + +void FindWidget::showAndClear() +{ + TRACE_OBJ + show(); + editFind->clear(); +} + +QString FindWidget::text() const +{ + TRACE_OBJ + return editFind->text(); +} + +bool FindWidget::caseSensitive() const +{ + TRACE_OBJ + return checkCase->isChecked(); +} + +void FindWidget::setPalette(bool found) +{ + TRACE_OBJ + QPalette palette = editFind->palette(); + palette.setColor(QPalette::Active, QPalette::Base, found ? Qt::white + : QColor(255, 102, 102)); + editFind->setPalette(palette); +} + +void FindWidget::setTextWrappedVisible(bool visible) +{ + TRACE_OBJ + labelWrapped->setVisible(visible); +} + +void FindWidget::hideEvent(QHideEvent* event) +{ + TRACE_OBJ +#if !defined(QT_NO_WEBKIT) + // TODO: remove this once webkit supports setting the palette + if (!event->spontaneous()) + qApp->setPalette(appPalette); +#else + Q_UNUSED(event); +#endif +} + +void FindWidget::showEvent(QShowEvent* event) +{ + TRACE_OBJ +#if !defined(QT_NO_WEBKIT) + // TODO: remove this once webkit supports setting the palette + if (!event->spontaneous()) { + QPalette p = appPalette; + p.setColor(QPalette::Inactive, QPalette::Highlight, + p.color(QPalette::Active, QPalette::Highlight)); + p.setColor(QPalette::Inactive, QPalette::HighlightedText, + p.color(QPalette::Active, QPalette::HighlightedText)); + qApp->setPalette(p); + } +#else + Q_UNUSED(event); +#endif +} + +void FindWidget::updateButtons() +{ + TRACE_OBJ + const bool enable = !editFind->text().isEmpty(); + toolNext->setEnabled(enable); + toolPrevious->setEnabled(enable); +} + +void FindWidget::textChanged(const QString &text) +{ + TRACE_OBJ + emit find(text, true); +} + +bool FindWidget::eventFilter(QObject *object, QEvent *e) +{ + TRACE_OBJ + if (e->type() == QEvent::KeyPress) { + if ((static_cast<QKeyEvent*>(e))->key() == Qt::Key_Escape) { + hide(); + emit escapePressed(); + } + } + return QWidget::eventFilter(object, e); +} + +QToolButton* FindWidget::setupToolButton(const QString &text, const QString &icon) +{ + TRACE_OBJ + QToolButton *toolButton = new QToolButton(this); + + toolButton->setText(text); + toolButton->setAutoRaise(true); + toolButton->setIcon(QIcon(icon)); + toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + + return toolButton; +} + +QT_END_NAMESPACE diff --git a/tools/assistant/compat/helpwindow.h b/tools/assistant/tools/assistant/findwidget.h index c20a21f..cf78003 100644 --- a/tools/assistant/compat/helpwindow.h +++ b/tools/assistant/tools/assistant/findwidget.h @@ -38,63 +38,64 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#ifndef FINDWIDGET_H +#define FINDWIDGET_H -#ifndef HELPWINDOW_H -#define HELPWINDOW_H - -#include <QTextBrowser> +#include <QtGui/QWidget> QT_BEGIN_NAMESPACE -class MainWindow; -class QKeyEvent; -class QMime; -class QMouseEvent; -class QMenu; +class QCheckBox; +class QLabel; +class QLineEdit; +class QToolButton; -class HelpWindow : public QTextBrowser +class FindWidget : public QWidget { Q_OBJECT public: - HelpWindow( MainWindow *m, QWidget *parent = 0); - void setSource( const QUrl &name ); - void blockScrolling( bool b ); - void openLinkInNewWindow( const QString &link ); - void openLinkInNewPage( const QString &link ); - void addMimePath( const QString &path ); + FindWidget(QWidget *parent = 0); + ~FindWidget(); + + void show(); + void showAndClear(); - void mousePressEvent(QMouseEvent *e); - void keyPressEvent(QKeyEvent *); + QString text() const; + bool caseSensitive() const; + + void setPalette(bool found); + void setTextWrappedVisible(bool visible); signals: - void chooseWebBrowser(); - void choosePDFReader(); + void escapePressed(); -protected: - virtual void contextMenuEvent(QContextMenuEvent *e); - virtual void mouseReleaseEvent(QMouseEvent *e); + void findNext(); + void findPrevious(); + void find(const QString &text, bool forward); -protected slots: - void ensureCursorVisible(); +protected: + void hideEvent(QHideEvent* event); + void showEvent(QShowEvent * event); private slots: - void openLinkInNewWindow(); - void openLinkInNewPage(); + void updateButtons(); + void textChanged(const QString &text); - bool isKDERunning() const; +private: + bool eventFilter(QObject *object, QEvent *e); + QToolButton* setupToolButton(const QString &text, const QString &icon); private: - bool hasAnchorAt(const QPoint& pos); - - MainWindow *mw; - QString lastAnchor; - bool blockScroll; - bool shiftPressed; - bool newWindow; - bool fwdAvail; - bool backAvail; + QPalette appPalette; + + QLineEdit *editFind; + QCheckBox *checkCase; + QLabel *labelWrapped; + QToolButton *toolNext; + QToolButton *toolClose; + QToolButton *toolPrevious; }; QT_END_NAMESPACE -#endif // HELPWINDOW_H +#endif // FINDWIDGET_H diff --git a/tools/assistant/tools/assistant/helpenginewrapper.cpp b/tools/assistant/tools/assistant/helpenginewrapper.cpp new file mode 100644 index 0000000..9748702 --- /dev/null +++ b/tools/assistant/tools/assistant/helpenginewrapper.cpp @@ -0,0 +1,835 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" + +#include "helpenginewrapper.h" +#include "../shared/collectionconfiguration.h" + +#include <QtCore/QDateTime> +#include <QtCore/QFileInfo> +#include <QtCore/QFileSystemWatcher> +#include <QtCore/QPair> +#include <QtCore/QSharedPointer> +#include <QtCore/QTimer> +#include <QtHelp/QHelpContentModel> +#include <QtHelp/QHelpEngine> +#include <QtHelp/QHelpIndexModel> +#include <QtHelp/QHelpSearchEngine> + +QT_BEGIN_NAMESPACE + +namespace { + const QString Unfiltered; + const QString AppFontKey(QLatin1String("appFont")); + const QString AppWritingSystemKey(QLatin1String("appWritingSystem")); + const QString BookmarksKey(QLatin1String("Bookmarks")); + const QString BrowserFontKey(QLatin1String("browserFont")); + const QString BrowserWritingSystemKey(QLatin1String("browserWritingSystem")); + const QString HomePageKey(QLatin1String("homepage")); + const QString MainWindowKey(QLatin1String("MainWindow")); + const QString MainWindowGeometryKey(QLatin1String("MainWindowGeometry")); + const QString SearchWasAttachedKey(QLatin1String("SearchWasAttached")); + const QString StartOptionKey(QLatin1String("StartOption")); + const QString UseAppFontKey(QLatin1String("useAppFont")); + const QString UseBrowserFontKey(QLatin1String("useBrowserFont")); + const QString VersionKey(QString(QLatin1String("qtVersion%1$$$%2")). + arg(QLatin1String(QT_VERSION_STR))); +} // anonymous namespace + +class TimeoutForwarder : public QObject +{ + Q_OBJECT +public: + TimeoutForwarder(const QString &fileName); +private slots: + void forward(); +private: + friend class HelpEngineWrapperPrivate; + + const QString m_fileName; +}; + +class HelpEngineWrapperPrivate : public QObject +{ + Q_OBJECT + friend class HelpEngineWrapper; + friend class TimeoutForwarder; +private slots: + void qchFileChanged(const QString &fileName); + +signals: + void documentationRemoved(const QString &namespaceName); + void documentationUpdated(const QString &namespaceName); + +private: + HelpEngineWrapperPrivate(const QString &collectionFile); + + void initFileSystemWatchers(); + void checkDocFilesWatched(); + void qchFileChanged(const QString &fileName, bool fromTimeout); + + static const int UpdateGracePeriod = 2000; + + QHelpEngine * const m_helpEngine; + QFileSystemWatcher * const m_qchWatcher; + typedef QPair<QDateTime, QSharedPointer<TimeoutForwarder> > RecentSignal; + QMap<QString, RecentSignal> m_recentQchUpdates; +}; + +const QString HelpEngineWrapper::TrUnfiltered = tr("Unfiltered"); + +HelpEngineWrapper *HelpEngineWrapper::helpEngineWrapper = 0; + +HelpEngineWrapper &HelpEngineWrapper::instance(const QString &collectionFile) +{ + TRACE_OBJ + /* + * Note that this Singleton cannot be static, because it has to be + * deleted before the QApplication. + */ + if (helpEngineWrapper == 0) + helpEngineWrapper = new HelpEngineWrapper(collectionFile); + return *helpEngineWrapper; +} + +void HelpEngineWrapper::removeInstance() +{ + TRACE_OBJ + delete helpEngineWrapper; + helpEngineWrapper = 0; +} + +HelpEngineWrapper::HelpEngineWrapper(const QString &collectionFile) + : d(new HelpEngineWrapperPrivate(collectionFile)) +{ + TRACE_OBJ + + /* + * Otherwise we will waste time if several new docs are found, + * because we will start to index them, only to be interupted + * by the next request. Also, there is a nasty SQLITE bug that will + * cause the application to hang for minutes in that case. + * This call is reverted by initalDocSetupDone(), which must be + * called after the new docs have been installed. + */ + disconnect(d->m_helpEngine, SIGNAL(setupFinished()), + searchEngine(), SLOT(indexDocumentation())); + + connect(d, SIGNAL(documentationRemoved(QString)), + this, SIGNAL(documentationRemoved(QString))); + connect(d, SIGNAL(documentationUpdated(QString)), + this, SIGNAL(documentationUpdated(QString))); + connect(d->m_helpEngine, SIGNAL(currentFilterChanged(QString)), + this, SLOT(handleCurrentFilterChanged(QString))); + connect(d->m_helpEngine, SIGNAL(setupFinished()), + this, SIGNAL(setupFinished())); +} + +HelpEngineWrapper::~HelpEngineWrapper() +{ + TRACE_OBJ + const QStringList &namespaces = d->m_helpEngine->registeredDocumentations(); + foreach (const QString &nameSpace, namespaces) { + const QString &docFile + = d->m_helpEngine->documentationFileName(nameSpace); + d->m_qchWatcher->removePath(docFile); + } + + delete d; +} + +void HelpEngineWrapper::initialDocSetupDone() +{ + TRACE_OBJ + connect(d->m_helpEngine, SIGNAL(setupFinished()), + searchEngine(), SLOT(indexDocumentation())); + setupData(); +} + +QHelpSearchEngine *HelpEngineWrapper::searchEngine() const +{ + TRACE_OBJ + return d->m_helpEngine->searchEngine(); +} + +QHelpContentModel *HelpEngineWrapper::contentModel() const +{ + TRACE_OBJ + return d->m_helpEngine->contentModel(); +} + +QHelpIndexModel *HelpEngineWrapper::indexModel() const +{ + TRACE_OBJ + return d->m_helpEngine->indexModel(); +} + +QHelpContentWidget *HelpEngineWrapper::contentWidget() +{ + TRACE_OBJ + return d->m_helpEngine->contentWidget(); +} + +QHelpIndexWidget *HelpEngineWrapper::indexWidget() +{ + TRACE_OBJ + return d->m_helpEngine->indexWidget(); +} + +const QStringList HelpEngineWrapper::registeredDocumentations() const +{ + TRACE_OBJ + return d->m_helpEngine->registeredDocumentations(); +} + +const QString HelpEngineWrapper::collectionFile() const +{ + TRACE_OBJ + return d->m_helpEngine->collectionFile(); +} + +bool HelpEngineWrapper::registerDocumentation(const QString &docFile) +{ + TRACE_OBJ + d->checkDocFilesWatched(); + if (!d->m_helpEngine->registerDocumentation(docFile)) + return false; + d->m_qchWatcher->addPath(docFile); + d->checkDocFilesWatched(); + return true; +} + +bool HelpEngineWrapper::unregisterDocumentation(const QString &namespaceName) +{ + TRACE_OBJ + d->checkDocFilesWatched(); + const QString &file = d->m_helpEngine->documentationFileName(namespaceName); + if (!d->m_helpEngine->unregisterDocumentation(namespaceName)) + return false; + d->m_qchWatcher->removePath(file); + d->checkDocFilesWatched(); + return true; +} + +bool HelpEngineWrapper::setupData() +{ + TRACE_OBJ + return d->m_helpEngine->setupData(); +} + +bool HelpEngineWrapper::addCustomFilter(const QString &filterName, + const QStringList &attributes) +{ + TRACE_OBJ + return d->m_helpEngine->addCustomFilter(filterName, attributes); +} + +bool HelpEngineWrapper::removeCustomFilter(const QString &filterName) +{ + TRACE_OBJ + return d->m_helpEngine->removeCustomFilter(filterName); +} + +void HelpEngineWrapper::setCurrentFilter(const QString ¤tFilter) +{ + TRACE_OBJ + const QString &filter + = currentFilter == TrUnfiltered ? Unfiltered : currentFilter; + d->m_helpEngine->setCurrentFilter(filter); +} + +const QString HelpEngineWrapper::currentFilter() const +{ + TRACE_OBJ + const QString &filter = d->m_helpEngine->currentFilter(); + return filter == Unfiltered ? TrUnfiltered : filter; +} + +const QStringList HelpEngineWrapper::customFilters() const +{ + TRACE_OBJ + QStringList filters = d->m_helpEngine->customFilters(); + filters.removeOne(Unfiltered); + filters.prepend(TrUnfiltered); + return filters; +} + +QUrl HelpEngineWrapper::findFile(const QUrl &url) const +{ + TRACE_OBJ + return d->m_helpEngine->findFile(url); +} + +QByteArray HelpEngineWrapper::fileData(const QUrl &url) const +{ + TRACE_OBJ + return d->m_helpEngine->fileData(url); +} + +QMap<QString, QUrl> HelpEngineWrapper::linksForIdentifier(const QString &id) const +{ + TRACE_OBJ + return d->m_helpEngine->linksForIdentifier(id); +} + +const QStringList HelpEngineWrapper::filterAttributes() const +{ + TRACE_OBJ + return d->m_helpEngine->filterAttributes(); +} + +const QStringList HelpEngineWrapper::filterAttributes(const QString &filterName) const +{ + TRACE_OBJ + return d->m_helpEngine->filterAttributes(filterName); +} + +QString HelpEngineWrapper::error() const +{ + TRACE_OBJ + return d->m_helpEngine->error(); +} + +const QStringList HelpEngineWrapper::qtDocInfo(const QString &component) const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(VersionKey.arg(component)).toString(). + split(CollectionConfiguration::ListSeparator); +} + +void HelpEngineWrapper::setQtDocInfo(const QString &component, + const QStringList &doc) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(VersionKey.arg(component), + doc.join(CollectionConfiguration::ListSeparator)); +} + +const QStringList HelpEngineWrapper::lastShownPages() const +{ + TRACE_OBJ + return CollectionConfiguration::lastShownPages(*d->m_helpEngine); +} + +void HelpEngineWrapper::setLastShownPages(const QStringList &lastShownPages) +{ + TRACE_OBJ + CollectionConfiguration::setLastShownPages(*d->m_helpEngine, lastShownPages); +} + +const QStringList HelpEngineWrapper::lastZoomFactors() const +{ + TRACE_OBJ + return CollectionConfiguration::lastZoomFactors(*d->m_helpEngine); +} + +void HelpEngineWrapper::setLastZoomFactors(const QStringList &lastZoomFactors) +{ + TRACE_OBJ + CollectionConfiguration::setLastZoomFactors(*d->m_helpEngine, lastZoomFactors); +} + +const QString HelpEngineWrapper::cacheDir() const +{ + TRACE_OBJ + return CollectionConfiguration::cacheDir(*d->m_helpEngine); +} + +bool HelpEngineWrapper::cacheDirIsRelativeToCollection() const +{ + TRACE_OBJ + return CollectionConfiguration::cacheDirIsRelativeToCollection(*d->m_helpEngine); +} + +void HelpEngineWrapper::setCacheDir(const QString &cacheDir, + bool relativeToCollection) +{ + TRACE_OBJ + CollectionConfiguration::setCacheDir(*d->m_helpEngine, cacheDir, + relativeToCollection); +} + +bool HelpEngineWrapper::filterFunctionalityEnabled() const +{ + TRACE_OBJ + return CollectionConfiguration::filterFunctionalityEnabled(*d->m_helpEngine); +} + +void HelpEngineWrapper::setFilterFunctionalityEnabled(bool enabled) +{ + TRACE_OBJ + CollectionConfiguration::setFilterFunctionalityEnabled(*d->m_helpEngine, + enabled); +} + +bool HelpEngineWrapper::filterToolbarVisible() const +{ + TRACE_OBJ + return CollectionConfiguration::filterToolbarVisible(*d->m_helpEngine); +} + +void HelpEngineWrapper::setFilterToolbarVisible(bool visible) +{ + TRACE_OBJ + CollectionConfiguration::setFilterToolbarVisible(*d->m_helpEngine, visible); +} + +bool HelpEngineWrapper::addressBarEnabled() const +{ + TRACE_OBJ + return CollectionConfiguration::addressBarEnabled(*d->m_helpEngine); +} + +void HelpEngineWrapper::setAddressBarEnabled(bool enabled) +{ + TRACE_OBJ + CollectionConfiguration::setAddressBarEnabled(*d->m_helpEngine, enabled); +} + +bool HelpEngineWrapper::addressBarVisible() const +{ + TRACE_OBJ + return CollectionConfiguration::addressBarVisible(*d->m_helpEngine); +} + +void HelpEngineWrapper::setAddressBarVisible(bool visible) +{ + TRACE_OBJ + CollectionConfiguration::setAddressBarVisible(*d->m_helpEngine, visible); +} + +bool HelpEngineWrapper::documentationManagerEnabled() const +{ + TRACE_OBJ + return CollectionConfiguration::documentationManagerEnabled(*d->m_helpEngine); +} + +void HelpEngineWrapper::setDocumentationManagerEnabled(bool enabled) +{ + TRACE_OBJ + CollectionConfiguration::setDocumentationManagerEnabled(*d->m_helpEngine, + enabled); +} + +const QByteArray HelpEngineWrapper::aboutMenuTexts() const +{ + TRACE_OBJ + return CollectionConfiguration::aboutMenuTexts(*d->m_helpEngine); +} + +void HelpEngineWrapper::setAboutMenuTexts(const QByteArray &texts) +{ + TRACE_OBJ + CollectionConfiguration::setAboutMenuTexts(*d->m_helpEngine, texts); +} + +const QByteArray HelpEngineWrapper::aboutIcon() const +{ + TRACE_OBJ + return CollectionConfiguration::aboutIcon(*d->m_helpEngine); +} + +void HelpEngineWrapper::setAboutIcon(const QByteArray &icon) +{ + TRACE_OBJ + CollectionConfiguration::setAboutIcon(*d->m_helpEngine, icon); +} + +const QByteArray HelpEngineWrapper::aboutImages() const +{ + TRACE_OBJ + return CollectionConfiguration::aboutImages(*d->m_helpEngine); +} + +void HelpEngineWrapper::setAboutImages(const QByteArray &images) +{ + TRACE_OBJ + CollectionConfiguration::setAboutImages(*d->m_helpEngine, images); +} + +const QByteArray HelpEngineWrapper::aboutTexts() const +{ + TRACE_OBJ + return CollectionConfiguration::aboutTexts(*d->m_helpEngine); +} + +void HelpEngineWrapper::setAboutTexts(const QByteArray &texts) +{ + TRACE_OBJ + CollectionConfiguration::setAboutTexts(*d->m_helpEngine, texts); +} + +const QString HelpEngineWrapper::windowTitle() const +{ + TRACE_OBJ + return CollectionConfiguration::windowTitle(*d->m_helpEngine); +} + +void HelpEngineWrapper::setWindowTitle(const QString &windowTitle) +{ + TRACE_OBJ + CollectionConfiguration::setWindowTitle(*d->m_helpEngine, windowTitle); +} + +const QByteArray HelpEngineWrapper::applicationIcon() const +{ + TRACE_OBJ + return CollectionConfiguration::applicationIcon(*d->m_helpEngine); +} + +void HelpEngineWrapper::setApplicationIcon(const QByteArray &icon) +{ + TRACE_OBJ + CollectionConfiguration::setApplicationIcon(*d->m_helpEngine, icon); +} + +const QByteArray HelpEngineWrapper::mainWindow() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(MainWindowKey).toByteArray(); +} + +void HelpEngineWrapper::setMainWindow(const QByteArray &mainWindow) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(MainWindowKey, mainWindow); +} + +const QByteArray HelpEngineWrapper::mainWindowGeometry() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(MainWindowGeometryKey).toByteArray(); +} + +void HelpEngineWrapper::setMainWindowGeometry(const QByteArray &geometry) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(MainWindowGeometryKey, geometry); +} + +const QByteArray HelpEngineWrapper::bookmarks() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(BookmarksKey).toByteArray(); +} + +void HelpEngineWrapper::setBookmarks(const QByteArray &bookmarks) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(BookmarksKey, bookmarks); +} + +int HelpEngineWrapper::lastTabPage() const +{ + TRACE_OBJ + return CollectionConfiguration::lastTabPage(*d->m_helpEngine); +} + +void HelpEngineWrapper::setLastTabPage(int lastPage) +{ + TRACE_OBJ + CollectionConfiguration::setLastTabPage(*d->m_helpEngine, lastPage); +} + +bool HelpEngineWrapper::searchWasAttached() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(SearchWasAttachedKey).toBool(); +} + +void HelpEngineWrapper::setSearchWasAttached(bool attached) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(SearchWasAttachedKey, attached); +} + +int HelpEngineWrapper::startOption() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(StartOptionKey, ShowLastPages).toInt(); +} + +void HelpEngineWrapper::setStartOption(int option) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(StartOptionKey, option); +} + +const QString HelpEngineWrapper::homePage() const +{ + TRACE_OBJ + const QString &homePage + = d->m_helpEngine->customValue(HomePageKey).toString(); + if (!homePage.isEmpty()) + return homePage; + return defaultHomePage(); +} + +void HelpEngineWrapper::setHomePage(const QString &page) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(HomePageKey, page); + +} + +const QString HelpEngineWrapper::defaultHomePage() const +{ + TRACE_OBJ + return CollectionConfiguration::defaultHomePage(*d->m_helpEngine); +} + +void HelpEngineWrapper::setDefaultHomePage(const QString &page) +{ + TRACE_OBJ + CollectionConfiguration::setDefaultHomePage(*d->m_helpEngine, page); +} + +bool HelpEngineWrapper::hasFontSettings() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(UseAppFontKey).isValid(); +} + +bool HelpEngineWrapper::usesAppFont() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(UseAppFontKey).toBool(); +} + +void HelpEngineWrapper::setUseAppFont(bool useAppFont) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(UseAppFontKey, useAppFont); +} + +bool HelpEngineWrapper::usesBrowserFont() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(UseBrowserFontKey, false).toBool(); +} + +void HelpEngineWrapper::setUseBrowserFont(bool useBrowserFont) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(UseBrowserFontKey, useBrowserFont); +} + +const QFont HelpEngineWrapper::appFont() const +{ + TRACE_OBJ + return qVariantValue<QFont>(d->m_helpEngine->customValue(AppFontKey)); +} + +void HelpEngineWrapper::setAppFont(const QFont &font) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(AppFontKey, font); +} + +QFontDatabase::WritingSystem HelpEngineWrapper::appWritingSystem() const +{ + TRACE_OBJ + return static_cast<QFontDatabase::WritingSystem>( + d->m_helpEngine->customValue(AppWritingSystemKey).toInt()); +} + +void HelpEngineWrapper::setAppWritingSystem(QFontDatabase::WritingSystem system) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(AppWritingSystemKey, system); +} + +const QFont HelpEngineWrapper::browserFont() const +{ + TRACE_OBJ + return qVariantValue<QFont>(d->m_helpEngine->customValue(BrowserFontKey)); +} + +void HelpEngineWrapper::setBrowserFont(const QFont &font) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(BrowserFontKey, font); +} + +QFontDatabase::WritingSystem HelpEngineWrapper::browserWritingSystem() const +{ + TRACE_OBJ + return static_cast<QFontDatabase::WritingSystem>( + d->m_helpEngine->customValue(BrowserWritingSystemKey).toInt()); +} + +void HelpEngineWrapper::setBrowserWritingSystem(QFontDatabase::WritingSystem system) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(BrowserWritingSystemKey, system); +} + +void HelpEngineWrapper::handleCurrentFilterChanged(const QString &filter) +{ + const QString &filterToReport + = filter == Unfiltered ? TrUnfiltered : filter; + emit currentFilterChanged(filterToReport); +} + + +TimeoutForwarder::TimeoutForwarder(const QString &fileName) + : m_fileName(fileName) +{ + TRACE_OBJ +} + +void TimeoutForwarder::forward() +{ + TRACE_OBJ + HelpEngineWrapper::instance().d->qchFileChanged(m_fileName, true); +} + + +HelpEngineWrapperPrivate::HelpEngineWrapperPrivate(const QString &collectionFile) + : m_helpEngine(new QHelpEngine(collectionFile, this)), + m_qchWatcher(new QFileSystemWatcher(this)) +{ + TRACE_OBJ + if (!m_helpEngine->customFilters().contains(Unfiltered)) + m_helpEngine->addCustomFilter(Unfiltered, QStringList()); + initFileSystemWatchers(); +} + +void HelpEngineWrapperPrivate::initFileSystemWatchers() +{ + TRACE_OBJ + foreach(const QString &ns, m_helpEngine->registeredDocumentations()) { + const QString &docFile = m_helpEngine->documentationFileName(ns); + m_qchWatcher->addPath(docFile); + connect(m_qchWatcher, SIGNAL(fileChanged(QString)), + this, SLOT(qchFileChanged(QString))); + } + checkDocFilesWatched(); +} + +void HelpEngineWrapperPrivate::qchFileChanged(const QString &fileName) +{ + TRACE_OBJ + qchFileChanged(fileName, false); +} + +void HelpEngineWrapperPrivate::checkDocFilesWatched() +{ + TRACE_OBJ + const int watchedFilesCount = m_qchWatcher->files().count(); + const int docFilesCount = m_helpEngine->registeredDocumentations().count(); + if (watchedFilesCount != docFilesCount) { + qWarning("Strange: Have %d docs, but %d are being watched", + watchedFilesCount, docFilesCount); + } +} + +void HelpEngineWrapperPrivate::qchFileChanged(const QString &fileName, + bool fromTimeout) +{ + TRACE_OBJ + + /* + * We don't use QHelpEngineCore::namespaceName(fileName), because the file + * may not exist anymore or contain a different namespace. + */ + QString ns; + foreach (const QString &curNs, m_helpEngine->registeredDocumentations()) { + if (m_helpEngine->documentationFileName(curNs) == fileName) { + ns = curNs; + break; + } + } + + /* + * We can't do an assertion here, because QFileSystemWatcher may send the + * signal more than once. + */ + if (ns.isEmpty()) { + m_recentQchUpdates.remove(fileName); + return; + } + + /* + * Since the QFileSystemWatcher typically sends the signal more than once, + * we repeatedly delay our reaction a bit until we think the last signal + * was sent. + */ + + QMap<QString, RecentSignal>::Iterator it = m_recentQchUpdates.find(fileName); + const QDateTime &now = QDateTime::currentDateTime(); + + // Case 1: This is the first recent signal for the file. + if (it == m_recentQchUpdates.end()) { + QSharedPointer<TimeoutForwarder> forwarder(new TimeoutForwarder(fileName)); + m_recentQchUpdates.insert(fileName, RecentSignal(now, forwarder)); + QTimer::singleShot(UpdateGracePeriod, forwarder.data(), SLOT(forward())); + return; + } + + // Case 2: The last signal for this file has not expired yet. + if (it.value().first > now.addMSecs(-UpdateGracePeriod)) { + if (!fromTimeout) + it.value().first = now; + else + QTimer::singleShot(UpdateGracePeriod, it.value().second.data(), + SLOT(forward())); + return; + } + + // Case 3: The last signal for this file has expired. + if (m_helpEngine->unregisterDocumentation(ns)) { + if (!QFileInfo(fileName).exists() + || !m_helpEngine->registerDocumentation(fileName)) { + m_qchWatcher->removePath(fileName); + emit documentationRemoved(ns); + } else { + emit documentationUpdated(ns); + } + m_helpEngine->setupData(); + } + m_recentQchUpdates.erase(it); +} + + +QT_END_NAMESPACE + +#include "helpenginewrapper.moc" diff --git a/tools/assistant/tools/assistant/helpenginewrapper.h b/tools/assistant/tools/assistant/helpenginewrapper.h new file mode 100644 index 0000000..c1041b6 --- /dev/null +++ b/tools/assistant/tools/assistant/helpenginewrapper.h @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HELPENGINEWRAPPER_H +#define HELPENGINEWRAPPER_H + +#include <QtCore/QMap> +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QUrl> +#include <QtGui/QFont> +#include <QtGui/QFontDatabase> + +QT_BEGIN_NAMESPACE + +class QFileSystemWatcher; +class QHelpContentModel; +class QHelpContentWidget; +class QHelpIndexModel; +class QHelpIndexWidget; +class QHelpSearchEngine; + +enum { + ShowHomePage = 0, + ShowBlankPage = 1, + ShowLastPages = 2 +}; + +class HelpEngineWrapperPrivate; +class TimeoutForwarder; + +class HelpEngineWrapper : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(HelpEngineWrapper) + friend class TimeoutForwarder; +public: + static HelpEngineWrapper &instance(const QString &collectionFile = QString()); + static void removeInstance(); + + // Forwarded help engine member functions, possibly enriched. + QHelpSearchEngine *searchEngine() const; + QHelpContentModel *contentModel() const; + QHelpIndexModel *indexModel() const; + QHelpContentWidget *contentWidget(); + QHelpIndexWidget *indexWidget(); + bool setupData(); + const QStringList registeredDocumentations() const; + const QString collectionFile() const; + bool registerDocumentation(const QString &docFile); + bool unregisterDocumentation(const QString &namespaceName); + bool addCustomFilter(const QString &filterName, + const QStringList &attributes); + bool removeCustomFilter(const QString &filterName); + void setCurrentFilter(const QString &filterName); + const QString currentFilter() const; + const QStringList customFilters() const; + QUrl findFile(const QUrl &url) const; + QByteArray fileData(const QUrl &url) const; + QMap<QString, QUrl> linksForIdentifier(const QString &id) const; + const QStringList filterAttributes() const; + const QStringList filterAttributes(const QString &filterName) const; + QString error() const; + + /* + * To be called after assistant has finished looking for new documentation. + * This will mainly cause the search index to be updated, if necessary. + */ + void initialDocSetupDone(); + + const QStringList qtDocInfo(const QString &component) const; + void setQtDocInfo(const QString &component, const QStringList &doc); + + const QString homePage() const; + void setHomePage(const QString &page); + const QString defaultHomePage() const; + void setDefaultHomePage(const QString &page); + + int lastTabPage() const; + void setLastTabPage(int lastPage); + + // TODO: Don't allow last pages and zoom factors to be set in isolation + // Perhaps also fill up missing elements automatically or assert. + const QStringList lastShownPages() const; + void setLastShownPages(const QStringList &lastShownPages); + const QStringList lastZoomFactors() const; + void setLastZoomFactors(const QStringList &lastZoomFactors); + + const QString cacheDir() const; + bool cacheDirIsRelativeToCollection() const; + void setCacheDir(const QString &cacheDir, bool relativeToCollection); + + bool filterFunctionalityEnabled() const; + void setFilterFunctionalityEnabled(bool enabled); + + bool filterToolbarVisible() const; + void setFilterToolbarVisible(bool visible); + + bool addressBarEnabled() const; + void setAddressBarEnabled(bool enabled); + + bool addressBarVisible() const; + void setAddressBarVisible(bool visible); + + bool documentationManagerEnabled() const; + void setDocumentationManagerEnabled(bool enabled); + + const QByteArray aboutMenuTexts() const; + void setAboutMenuTexts(const QByteArray &texts); + const QByteArray aboutTexts() const; + void setAboutTexts(const QByteArray &texts); + const QByteArray aboutIcon() const; + void setAboutIcon(const QByteArray &icon); + const QByteArray aboutImages() const; + void setAboutImages(const QByteArray &images); + + const QString windowTitle() const; + void setWindowTitle(const QString &windowTitle); + + const QByteArray applicationIcon() const; + void setApplicationIcon(const QByteArray &icon); + + const QByteArray mainWindow() const; + void setMainWindow(const QByteArray &mainWindow); + const QByteArray mainWindowGeometry() const; + void setMainWindowGeometry(const QByteArray &geometry); + + const QByteArray bookmarks() const; + void setBookmarks(const QByteArray &bookmarks); + + int startOption() const; + void setStartOption(int option); + + bool searchWasAttached() const; + void setSearchWasAttached(bool attached); + + bool hasFontSettings() const; + bool usesAppFont() const; + void setUseAppFont(bool useAppFont); + bool usesBrowserFont() const; + void setUseBrowserFont(bool useBrowserFont); + const QFont appFont() const; + void setAppFont(const QFont &font); + QFontDatabase::WritingSystem appWritingSystem() const; + void setAppWritingSystem(QFontDatabase::WritingSystem system); + const QFont browserFont() const; + void setBrowserFont(const QFont &font); + QFontDatabase::WritingSystem browserWritingSystem() const; + void setBrowserWritingSystem(QFontDatabase::WritingSystem system); + + static const QString TrUnfiltered; + +signals: + + // For asynchronous doc updates triggered by external actions. + void documentationRemoved(const QString &namespaceName); + void documentationUpdated(const QString &namespaceName); + + // Forwarded from QHelpEngineCore. + void currentFilterChanged(const QString ¤tFilter); + void setupFinished(); + +private slots: + void handleCurrentFilterChanged(const QString &filter); + +private: + HelpEngineWrapper(const QString &collectionFile); + ~HelpEngineWrapper(); + + static HelpEngineWrapper *helpEngineWrapper; + + HelpEngineWrapperPrivate *d; +}; + +QT_END_NAMESPACE + +#endif // HELPENGINEWRAPPER_H diff --git a/tools/assistant/tools/assistant/helpviewer.cpp b/tools/assistant/tools/assistant/helpviewer.cpp index f22ab8a..6499139 100644 --- a/tools/assistant/tools/assistant/helpviewer.cpp +++ b/tools/assistant/tools/assistant/helpviewer.cpp @@ -38,590 +38,143 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - #include "helpviewer.h" -#include "centralwidget.h" +#include "helpenginewrapper.h" +#include "tracer.h" -#include <QtCore/QDir> -#include <QtCore/QEvent> -#include <QtCore/QVariant> -#include <QtCore/QByteArray> -#include <QtCore/QTimer> +#include <QtCore/QCoreApplication> +#include <QtCore/QFileInfo> +#include <QtCore/QStringBuilder> +#include <QtCore/QTemporaryFile> +#include <QtCore/QUrl> -#include <QtGui/QMenu> -#include <QtGui/QKeyEvent> -#include <QtGui/QClipboard> -#include <QtGui/QApplication> -#include <QtGui/QMessageBox> #include <QtGui/QDesktopServices> -#include <QtHelp/QHelpEngine> - -#include <QNetworkAccessManager> -#include <QNetworkReply> -#include <QNetworkRequest> - QT_BEGIN_NAMESPACE -#if !defined(QT_NO_WEBKIT) - -class HelpNetworkReply : public QNetworkReply -{ -public: - HelpNetworkReply(const QNetworkRequest &request, const QByteArray &fileData, - const QString &mimeType); - - virtual void abort(); - - virtual qint64 bytesAvailable() const - { return data.length() + QNetworkReply::bytesAvailable(); } - -protected: - virtual qint64 readData(char *data, qint64 maxlen); - -private: - QByteArray data; - qint64 origLen; -}; - -HelpNetworkReply::HelpNetworkReply(const QNetworkRequest &request, - const QByteArray &fileData, const QString& mimeType) - : data(fileData), origLen(fileData.length()) -{ - setRequest(request); - setOpenMode(QIODevice::ReadOnly); - - setHeader(QNetworkRequest::ContentTypeHeader, mimeType); - setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(origLen)); - QTimer::singleShot(0, this, SIGNAL(metaDataChanged())); - QTimer::singleShot(0, this, SIGNAL(readyRead())); -} - -void HelpNetworkReply::abort() -{ - // nothing to do -} - -qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen) -{ - qint64 len = qMin(qint64(data.length()), maxlen); - if (len) { - qMemCopy(buffer, data.constData(), len); - data.remove(0, len); - } - if (!data.length()) - QTimer::singleShot(0, this, SIGNAL(finished())); - return len; -} - -class HelpNetworkAccessManager : public QNetworkAccessManager -{ -public: - HelpNetworkAccessManager(QHelpEngine *engine, QObject *parent); - -protected: - virtual QNetworkReply *createRequest(Operation op, - const QNetworkRequest &request, QIODevice *outgoingData = 0); - -private: - QHelpEngine *helpEngine; +const QLatin1String AbstractHelpViewer::DocPath("qthelp://com.trolltech."); + +const QString AbstractHelpViewer::AboutBlank = + QCoreApplication::translate("HelpViewer", "<title>about:blank</title>"); + +const QString AbstractHelpViewer::LocalHelpFile = QLatin1String("qthelp://" + "com.trolltech.com.assistantinternal-1.0.0/assistant/assistant.html"); + +const QString AbstractHelpViewer::PageNotFoundMessage = + QCoreApplication::translate("HelpViewer", "<title>Error 404...</title><div " + "align=\"center\"><br><br><h1>The page could not be found</h1><br><h3>'%1'" + "</h3></div>"); + +struct ExtensionMap { + const char *extension; + const char *mimeType; +} extensionMap[] = { + { ".bmp", "image/bmp" }, + { ".css", "text/css" }, + { ".gif", "image/gif" }, + { ".html", "text/html" }, + { ".htm", "text/html" }, + { ".ico", "image/x-icon" }, + { ".jpeg", "image/jpeg" }, + { ".jpg", "image/jpeg" }, + { ".js", "application/x-javascript" }, + { ".mng", "video/x-mng" }, + { ".pbm", "image/x-portable-bitmap" }, + { ".pgm", "image/x-portable-graymap" }, + { ".pdf", "application/pdf" }, + { ".png", "image/png" }, + { ".ppm", "image/x-portable-pixmap" }, + { ".rss", "application/rss+xml" }, + { ".svg", "image/svg+xml" }, + { ".svgz", "image/svg+xml" }, + { ".text", "text/plain" }, + { ".tif", "image/tiff" }, + { ".tiff", "image/tiff" }, + { ".txt", "text/plain" }, + { ".xbm", "image/x-xbitmap" }, + { ".xml", "text/xml" }, + { ".xpm", "image/x-xpm" }, + { ".xsl", "text/xsl" }, + { ".xhtml", "application/xhtml+xml" }, + { ".wml", "text/vnd.wap.wml" }, + { ".wmlc", "application/vnd.wap.wmlc" }, + { "about:blank", 0 }, + { 0, 0 } }; -HelpNetworkAccessManager::HelpNetworkAccessManager(QHelpEngine *engine, - QObject *parent) - : QNetworkAccessManager(parent), helpEngine(engine) -{ -} - -QNetworkReply *HelpNetworkAccessManager::createRequest(Operation /*op*/, - const QNetworkRequest &request, QIODevice* /*outgoingData*/) -{ - const QUrl& url = request.url(); - QString mimeType = url.toString(); - if (mimeType.endsWith(QLatin1String(".svg")) - || mimeType.endsWith(QLatin1String(".svgz"))) { - mimeType = QLatin1String("image/svg+xml"); - } else if (mimeType.endsWith(QLatin1String(".css"))) { - mimeType = QLatin1String("text/css"); - } else if (mimeType.endsWith(QLatin1String(".js"))) { - mimeType = QLatin1String("text/javascript"); - } else if (mimeType.endsWith(QLatin1String(".txt"))) { - mimeType = QLatin1String("text/plain"); - } else { - mimeType = QLatin1String("text/html"); - } - - const QByteArray &data = helpEngine->findFile(url).isValid() - ? helpEngine->fileData(url) : QByteArray("File not found!"); - return new HelpNetworkReply(request, data, mimeType); -} - -class HelpPage : public QWebPage -{ -public: - HelpPage(CentralWidget *central, QHelpEngine *engine, QObject *parent); - -protected: - virtual QWebPage *createWindow(QWebPage::WebWindowType); - virtual void triggerAction(WebAction action, bool checked = false); - - virtual bool acceptNavigationRequest(QWebFrame *frame, - const QNetworkRequest &request, NavigationType type); - -private: - CentralWidget *centralWidget; - QHelpEngine *helpEngine; - bool closeNewTabIfNeeded; - - friend class HelpViewer; - Qt::MouseButtons m_pressedButtons; - Qt::KeyboardModifiers m_keyboardModifiers; -}; +// -- AbstractHelpViewer -HelpPage::HelpPage(CentralWidget *central, QHelpEngine *engine, QObject *parent) - : QWebPage(parent) - , centralWidget(central) - , helpEngine(engine) - , closeNewTabIfNeeded(false) - , m_pressedButtons(Qt::NoButton) - , m_keyboardModifiers(Qt::NoModifier) +AbstractHelpViewer::AbstractHelpViewer() { } -QWebPage *HelpPage::createWindow(QWebPage::WebWindowType) +AbstractHelpViewer::~AbstractHelpViewer() { - HelpPage* newPage = static_cast<HelpPage*>(centralWidget->newEmptyTab()->page()); - if (newPage) - newPage->closeNewTabIfNeeded = closeNewTabIfNeeded; - closeNewTabIfNeeded = false; - return newPage; } -static bool isLocalUrl(const QUrl &url) +bool AbstractHelpViewer::isLocalUrl(const QUrl &url) { - const QString scheme = url.scheme(); - if (scheme.isEmpty() + TRACE_OBJ + const QString &scheme = url.scheme(); + return scheme.isEmpty() || scheme == QLatin1String("file") || scheme == QLatin1String("qrc") || scheme == QLatin1String("data") || scheme == QLatin1String("qthelp") - || scheme == QLatin1String("about")) - return true; - return false; -} - -void HelpPage::triggerAction(WebAction action, bool checked) -{ - switch (action) { - case OpenLinkInNewWindow: - closeNewTabIfNeeded = true; - default: // fall through - QWebPage::triggerAction(action, checked); - break; - } + || scheme == QLatin1String("about"); } -bool HelpPage::acceptNavigationRequest(QWebFrame *, - const QNetworkRequest &request, QWebPage::NavigationType type) +bool AbstractHelpViewer::canOpenPage(const QString &url) { - const QUrl &url = request.url(); - const bool closeNewTab = closeNewTabIfNeeded; - closeNewTabIfNeeded = false; - - if (isLocalUrl(url)) { - const QString& path = url.path(); - if (path.endsWith(QLatin1String(".pdf"))) { - const int lastDash = path.lastIndexOf(QChar('/')); - QString fileName = QDir::tempPath() + QDir::separator(); - if (lastDash < 0) - fileName += path; - else - fileName += path.mid(lastDash + 1, path.length()); - - QFile tmpFile(QDir::cleanPath(fileName)); - if (tmpFile.open(QIODevice::ReadWrite)) { - tmpFile.write(helpEngine->fileData(url)); - tmpFile.close(); - } - QDesktopServices::openUrl(QUrl(tmpFile.fileName())); - - if (closeNewTab) - QMetaObject::invokeMethod(CentralWidget::instance(), "closeTab"); - return false; - } - - if (type == QWebPage::NavigationTypeLinkClicked - && (m_keyboardModifiers & Qt::ControlModifier - || m_pressedButtons == Qt::MidButton)) { - HelpViewer* viewer = centralWidget->newEmptyTab(); - if (viewer) - CentralWidget::instance()->setSource(url); - m_pressedButtons = Qt::NoButton; - m_keyboardModifiers = Qt::NoModifier; - return false; - } - return true; - } - - QDesktopServices::openUrl(url); - return false; -} - -HelpViewer::HelpViewer(QHelpEngine *engine, CentralWidget *parent) - : QWebView(parent) - , helpEngine(engine) - , parentWidget(parent) - , loadFinished(false) -{ - setAcceptDrops(false); - - setPage(new HelpPage(parent, helpEngine, this)); - - page()->setNetworkAccessManager(new HelpNetworkAccessManager(engine, this)); - - QAction* action = pageAction(QWebPage::OpenLinkInNewWindow); - action->setText(tr("Open Link in New Tab")); - if (!parent) - action->setVisible(false); - - pageAction(QWebPage::DownloadLinkToDisk)->setVisible(false); - pageAction(QWebPage::DownloadImageToDisk)->setVisible(false); - pageAction(QWebPage::OpenImageInNewWindow)->setVisible(false); - - connect(pageAction(QWebPage::Copy), SIGNAL(changed()), this, - SLOT(actionChanged())); - connect(pageAction(QWebPage::Back), SIGNAL(changed()), this, - SLOT(actionChanged())); - connect(pageAction(QWebPage::Forward), SIGNAL(changed()), this, - SLOT(actionChanged())); - connect(page(), SIGNAL(linkHovered(QString,QString,QString)), this, - SIGNAL(highlighted(QString))); - connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl))); - connect(this, SIGNAL(loadFinished(bool)), this, SLOT(setLoadFinished(bool))); -} - -void HelpViewer::setSource(const QUrl &url) -{ - loadFinished = false; - if (url.toString() == QLatin1String("help")) { - load(QUrl(QLatin1String("qthelp://com.trolltech.com." - "assistantinternal-1.0.0/assistant/assistant.html"))); - } else { - load(url); - } -} - -void HelpViewer::resetZoom() -{ - setTextSizeMultiplier(1.0); -} - -void HelpViewer::zoomIn(qreal range) -{ - setTextSizeMultiplier(textSizeMultiplier() + range / 10.0); -} - -void HelpViewer::zoomOut(qreal range) -{ - setTextSizeMultiplier(qMax(0.0, textSizeMultiplier() - range / 10.0)); + TRACE_OBJ + return !mimeFromUrl(url).isEmpty(); } -void HelpViewer::home() +QString AbstractHelpViewer::mimeFromUrl(const QUrl &url) { - QString homepage = helpEngine->customValue(QLatin1String("homepage"), - QLatin1String("")).toString(); + TRACE_OBJ + const QString &path = url.path(); + const int index = path.lastIndexOf(QLatin1Char('.')); + const QByteArray &ext = path.mid(index).toUtf8().toLower(); - if (homepage.isEmpty()) { - homepage = helpEngine->customValue(QLatin1String("defaultHomepage"), - QLatin1String("help")).toString(); + const ExtensionMap *e = extensionMap; + while (e->extension) { + if (ext == e->extension) + return QLatin1String(e->mimeType); + ++e; } - - setSource(homepage); -} - -void HelpViewer::wheelEvent(QWheelEvent *e) -{ - if (e->modifiers() & Qt::ControlModifier) { - const int delta = e->delta(); - if (delta > 0) - zoomIn(delta / 120); - else if (delta < 0) - zoomOut(-delta / 120); - e->accept(); - return; - } - QWebView::wheelEvent(e); + return QLatin1String(""); } -void HelpViewer::mouseReleaseEvent(QMouseEvent *e) +bool AbstractHelpViewer::launchWithExternalApp(const QUrl &url) { - if (e->button() == Qt::XButton1) { - triggerPageAction(QWebPage::Back); - return; - } - - if (e->button() == Qt::XButton2) { - triggerPageAction(QWebPage::Forward); - return; - } - - QWebView::mouseReleaseEvent(e); -} - -void HelpViewer::actionChanged() -{ - QAction *a = qobject_cast<QAction *>(sender()); - if (a == pageAction(QWebPage::Copy)) - emit copyAvailable(a->isEnabled()); - else if (a == pageAction(QWebPage::Back)) - emit backwardAvailable(a->isEnabled()); - else if (a == pageAction(QWebPage::Forward)) - emit forwardAvailable(a->isEnabled()); -} - -void HelpViewer::mousePressEvent(QMouseEvent *event) -{ - HelpPage *currentPage = static_cast<HelpPage*>(page()); - if (currentPage) { - currentPage->m_pressedButtons = event->buttons(); - currentPage->m_keyboardModifiers = event->modifiers(); - } - QWebView::mousePressEvent(event); -} - -void HelpViewer::setLoadFinished(bool ok) -{ - loadFinished = ok; - emit sourceChanged(url()); -} - -#else // !defined(QT_NO_WEBKIT) - -HelpViewer::HelpViewer(QHelpEngine *engine, CentralWidget *parent) - : QTextBrowser(parent) - , zoomCount(0) - , controlPressed(false) - , lastAnchor(QString()) - , helpEngine(engine) - , parentWidget(parent) -{ - document()->setDocumentMargin(8); -} - -void HelpViewer::setSource(const QUrl &url) -{ - bool help = url.toString() == QLatin1String("help"); - if (url.isValid() && !help) { - if (launchedWithExternalApp(url)) - return; - - QUrl u = helpEngine->findFile(url); - if (u.isValid()) { - QTextBrowser::setSource(u); - return; - } - } - - if (help) { - QTextBrowser::setSource(QUrl(QLatin1String("qthelp://com.trolltech.com." - "assistantinternal-1.0.0/assistant/assistant.html"))); - } else { - QTextBrowser::setSource(url); - setHtml(tr("<title>Error 404...</title><div align=\"center\"><br><br>" - "<h1>The page could not be found</h1><br><h3>'%1'</h3></div>") - .arg(url.toString())); - emit sourceChanged(url); - } -} - -void HelpViewer::resetZoom() -{ - if (zoomCount == 0) - return; - - QTextBrowser::zoomOut(zoomCount); - zoomCount = 0; -} - -void HelpViewer::zoomIn(int range) -{ - if (zoomCount == 10) - return; - - QTextBrowser::zoomIn(range); - zoomCount++; -} - -void HelpViewer::zoomOut(int range) -{ - if (zoomCount == -5) - return; - - QTextBrowser::zoomOut(range); - zoomCount--; -} + TRACE_OBJ + if (isLocalUrl(url)) { + const HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + const QUrl &resolvedUrl = helpEngine.findFile(url); + if (!resolvedUrl.isValid()) + return false; -bool HelpViewer::launchedWithExternalApp(const QUrl &url) -{ - bool isPdf = url.path().endsWith(QLatin1String(".pdf")); - if (url.scheme() == QLatin1String("http") - || url.scheme() == QLatin1String("ftp") - || url.scheme() == QLatin1String("mailto") || isPdf) { - bool launched = false; - if (isPdf && url.scheme() == QLatin1String("qthelp")) { - const QString& path = url.path(); - const int lastDash = path.lastIndexOf(QChar('/')); - QString fileName = QDir::tempPath() + QDir::separator(); - if (lastDash < 0) - fileName += path; - else - fileName += path.mid(lastDash + 1, path.length()); + const QString& path = resolvedUrl.path(); + if (!canOpenPage(path)) { + QTemporaryFile tmpTmpFile; + if (!tmpTmpFile.open()) + return false; - QFile tmpFile(QDir::cleanPath(fileName)); - if (tmpFile.open(QIODevice::ReadWrite)) { - tmpFile.write(helpEngine->fileData(url)); - tmpFile.close(); - } - launched = QDesktopServices::openUrl(QUrl(tmpFile.fileName())); - } else { - launched = QDesktopServices::openUrl(url); - } + const QString &extension = QFileInfo(path).completeSuffix(); + QFile actualTmpFile(tmpTmpFile.fileName() % QLatin1String(".") + % extension); + if (!actualTmpFile.open(QIODevice::ReadWrite | QIODevice::Truncate)) + return false; - if (!launched) { - QMessageBox::information(this, tr("Help"), - tr("Unable to launch external application.\n"), tr("OK")); + actualTmpFile.write(helpEngine.fileData(resolvedUrl)); + actualTmpFile.close(); + return QDesktopServices::openUrl(QUrl(actualTmpFile.fileName())); } - return true; + } else if (url.scheme() == QLatin1String("http")) { + return QDesktopServices::openUrl(url); } return false; } -QVariant HelpViewer::loadResource(int type, const QUrl &name) -{ - QByteArray ba; - if (type < 4) { - ba = helpEngine->fileData(name); - if (name.toString().endsWith(QLatin1String(".svg"), Qt::CaseInsensitive)) { - QImage image; - image.loadFromData(ba, "svg"); - if (!image.isNull()) - return image; - } - } - return ba; -} - -void HelpViewer::openLinkInNewTab() -{ - if(lastAnchor.isEmpty()) - return; - - parentWidget->setSourceInNewTab(QUrl(lastAnchor)); - lastAnchor.clear(); -} - -void HelpViewer::openLinkInNewTab(const QString &link) -{ - lastAnchor = link; - openLinkInNewTab(); -} - -bool HelpViewer::hasAnchorAt(const QPoint& pos) -{ - lastAnchor = anchorAt(pos); - if (lastAnchor.isEmpty()) - return false; - - lastAnchor = source().resolved(lastAnchor).toString(); - if (lastAnchor.at(0) == QLatin1Char('#')) { - QString src = source().toString(); - int hsh = src.indexOf(QLatin1Char('#')); - lastAnchor = (hsh>=0 ? src.left(hsh) : src) + lastAnchor; - } - - return true; -} - -void HelpViewer::contextMenuEvent(QContextMenuEvent *e) -{ - QMenu menu(QLatin1String(""), 0); - - QUrl link; - QAction *copyAnchorAction = 0; - if (hasAnchorAt(e->pos())) { - link = anchorAt(e->pos()); - if (link.isRelative()) - link = source().resolved(link); - copyAnchorAction = menu.addAction(tr("Copy &Link Location")); - copyAnchorAction->setEnabled(!link.isEmpty() && link.isValid()); - - menu.addAction(tr("Open Link in New Tab\tCtrl+LMB"), this, - SLOT(openLinkInNewTab())); - menu.addSeparator(); - } - menu.addActions(parentWidget->globalActions()); - QAction *action = menu.exec(e->globalPos()); - if (action == copyAnchorAction) - QApplication::clipboard()->setText(link.toString()); -} - -void HelpViewer::mouseReleaseEvent(QMouseEvent *e) -{ - if (e->button() == Qt::XButton1) { - QTextBrowser::backward(); - return; - } - - if (e->button() == Qt::XButton2) { - QTextBrowser::forward(); - return; - } - - controlPressed = e->modifiers() & Qt::ControlModifier; - if ((controlPressed && hasAnchorAt(e->pos())) || - (e->button() == Qt::MidButton && hasAnchorAt(e->pos()))) { - openLinkInNewTab(); - return; - } - - QTextBrowser::mouseReleaseEvent(e); -} - -void HelpViewer::keyPressEvent(QKeyEvent *e) -{ - if ((e->key() == Qt::Key_Home && e->modifiers() != Qt::NoModifier) - || (e->key() == Qt::Key_End && e->modifiers() != Qt::NoModifier)) { - QKeyEvent* event = new QKeyEvent(e->type(), e->key(), Qt::NoModifier, - e->text(), e->isAutoRepeat(), e->count()); - e = event; - } - QTextBrowser::keyPressEvent(e); -} - -void HelpViewer::home() -{ - QString homepage = helpEngine->customValue(QLatin1String("homepage"), - QLatin1String("")).toString(); - - if (homepage.isEmpty()) { - homepage = helpEngine->customValue(QLatin1String("defaultHomepage"), - QLatin1String("help")).toString(); - } - - setSource(homepage); -} - -void HelpViewer::wheelEvent(QWheelEvent *e) -{ - if (e->modifiers() == Qt::CTRL) { - e->accept(); - (e->delta() > 0) ? zoomIn() : zoomOut(); - } else { - e->ignore(); - QTextBrowser::wheelEvent(e); - } -} - -#endif // !defined(QT_NO_WEBKIT) - QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/helpviewer.h b/tools/assistant/tools/assistant/helpviewer.h index 3618a73..def9418 100644 --- a/tools/assistant/tools/assistant/helpviewer.h +++ b/tools/assistant/tools/assistant/helpviewer.h @@ -38,139 +38,46 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - #ifndef HELPVIEWER_H #define HELPVIEWER_H -#include <QtCore/QUrl> -#include <QtCore/QVariant> -#include <QtGui/QTextBrowser> -#include <QtGui/QAction> +#include <QtCore/QString> -#if !defined(QT_NO_WEBKIT) -#include <QWebView> -#endif +#include <QtGui/QFont> QT_BEGIN_NAMESPACE -class QHelpEngine; -class CentralWidget; - -class QPoint; -class QString; -class QKeyEvent; class QMouseEvent; -class QContextMenuEvent; +class QUrl; -#if !defined(QT_NO_WEBKIT) - -class HelpViewer : public QWebView +class AbstractHelpViewer { - Q_OBJECT - public: - HelpViewer(QHelpEngine *helpEngine, CentralWidget *parent); - void setSource(const QUrl &url); - - inline QUrl source() const - { return url(); } - - inline QString documentTitle() const - { return title(); } - - inline bool hasSelection() const - { return !selectedText().isEmpty(); } // ### this is suboptimal + AbstractHelpViewer(); + virtual ~AbstractHelpViewer(); - void resetZoom(); - void zoomIn(qreal range = 1); - void zoomOut(qreal range = 1); + virtual QFont viewerFont() const = 0; + virtual void setViewerFont(const QFont &font) = 0; - inline void copy() - { return triggerPageAction(QWebPage::Copy); } + virtual void scaleUp() = 0; + virtual void scaleDown() = 0; + + virtual void resetScale() = 0; + virtual qreal scale() const = 0; - inline bool isForwardAvailable() const - { return pageAction(QWebPage::Forward)->isEnabled(); } - inline bool isBackwardAvailable() const - { return pageAction(QWebPage::Back)->isEnabled(); } - inline bool hasLoadFinished() const - { return loadFinished; } - inline qreal zoom() const - { return textSizeMultiplier(); } + virtual bool handleForwardBackwardMouseButtons(QMouseEvent *e) = 0; -public Q_SLOTS: - void home(); - void backward() { back(); } + static const QLatin1String DocPath; + static const QString AboutBlank; + static const QString LocalHelpFile; + static const QString PageNotFoundMessage; -Q_SIGNALS: - void copyAvailable(bool enabled); - void forwardAvailable(bool enabled); - void backwardAvailable(bool enabled); - void highlighted(const QString &); - void sourceChanged(const QUrl &); - -protected: - virtual void wheelEvent(QWheelEvent *); - void mouseReleaseEvent(QMouseEvent *e); - void mousePressEvent(QMouseEvent *event); - -private Q_SLOTS: - void actionChanged(); - void setLoadFinished(bool ok); - -private: - QHelpEngine *helpEngine; - CentralWidget* parentWidget; - bool loadFinished; + static bool isLocalUrl(const QUrl &url); + static bool canOpenPage(const QString &url); + static QString mimeFromUrl(const QUrl &url); + static bool launchWithExternalApp(const QUrl &url); }; -#else - -class HelpViewer : public QTextBrowser -{ - Q_OBJECT - -public: - HelpViewer(QHelpEngine *helpEngine, CentralWidget *parent); - void setSource(const QUrl &url); - - void resetZoom(); - void zoomIn(int range = 1); - void zoomOut(int range = 1); - int zoom() const { return zoomCount; } - void setZoom(int zoom) { zoomCount = zoom; } - - inline bool hasSelection() const - { return textCursor().hasSelection(); } - - bool launchedWithExternalApp(const QUrl &url); - -public Q_SLOTS: - void home(); - -protected: - void wheelEvent(QWheelEvent *e); - -private: - QVariant loadResource(int type, const QUrl &name); - void openLinkInNewTab(const QString &link); - bool hasAnchorAt(const QPoint& pos); - void contextMenuEvent(QContextMenuEvent *e); - void mouseReleaseEvent(QMouseEvent *e); - void keyPressEvent(QKeyEvent *e); - -private slots: - void openLinkInNewTab(); - -private: - int zoomCount; - bool controlPressed; - QString lastAnchor; - QHelpEngine *helpEngine; - CentralWidget* parentWidget; -}; - -#endif - QT_END_NAMESPACE -#endif +#endif // HELPVIEWER_H diff --git a/tools/assistant/tools/assistant/helpviewer_qtb.cpp b/tools/assistant/tools/assistant/helpviewer_qtb.cpp new file mode 100644 index 0000000..7f82b56 --- /dev/null +++ b/tools/assistant/tools/assistant/helpviewer_qtb.cpp @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "helpviewer_qtb.h" + +#include "centralwidget.h" +#include "helpenginewrapper.h" +#include "tracer.h" + +#include <QtCore/QStringBuilder> + +#include <QtGui/QContextMenuEvent> +#include <QtGui/QMenu> +#include <QtGui/QClipboard> +#include <QtGui/QApplication> + +QT_BEGIN_NAMESPACE + +HelpViewer::HelpViewer(CentralWidget *parent, qreal zoom) + : QTextBrowser(parent) + , zoomCount(zoom) + , controlPressed(false) + , lastAnchor(QString()) + , parentWidget(parent) + , helpEngine(HelpEngineWrapper::instance()) + , forceFont(false) +{ + TRACE_OBJ + installEventFilter(this); + document()->setDocumentMargin(8); + + QFont font = viewerFont(); + font.setPointSize(int(font.pointSize() + zoom)); + setViewerFont(font); +} + +HelpViewer::~HelpViewer() +{ + TRACE_OBJ +} + +QFont HelpViewer::viewerFont() const +{ + TRACE_OBJ + if (HelpEngineWrapper::instance().usesBrowserFont()) + return helpEngine.browserFont(); + return qApp->font(); +} + +void HelpViewer::setViewerFont(const QFont &newFont) +{ + TRACE_OBJ + if (font() != newFont) { + forceFont = true; + setFont(newFont); + forceFont = false; + } +} + +void HelpViewer::scaleUp() +{ + TRACE_OBJ + if (zoomCount < 10) { + ++zoomCount; + forceFont = true; + zoomIn(); + forceFont = false; + } +} + +void HelpViewer::scaleDown() +{ + TRACE_OBJ + if (zoomCount > -5) { + --zoomCount; + forceFont = true; + zoomOut(); + forceFont = false; + } +} + +void HelpViewer::resetScale() +{ + TRACE_OBJ + if (zoomCount != 0) { + forceFont = true; + zoomOut(zoomCount); + forceFont = false; + } + zoomCount = 0; +} + +bool HelpViewer::handleForwardBackwardMouseButtons(QMouseEvent *e) +{ + if (e->button() == Qt::XButton1) { + QTextBrowser::backward(); + return true; + } + + if (e->button() == Qt::XButton2) { + QTextBrowser::forward(); + return true; + } + return false; +} + +void HelpViewer::setSource(const QUrl &url) +{ + TRACE_OBJ + const QString &string = url.toString(); + if (url.isValid() && string != QLatin1String("help")) { + if (launchWithExternalApp(url)) + return; + + const QUrl &resolvedUrl = helpEngine.findFile(url); + if (resolvedUrl.isValid()) { + QTextBrowser::setSource(resolvedUrl); + return; + } + } + + if (string != QLatin1String("help")) { + QTextBrowser::setSource(url); + setHtml(string == QLatin1String("about:blank") ? AboutBlank + : PageNotFoundMessage.arg(url.toString())); + emit sourceChanged(url); + } else { + QTextBrowser::setSource(LocalHelpFile); + } +} + +QVariant HelpViewer::loadResource(int type, const QUrl &name) +{ + TRACE_OBJ + QByteArray ba; + if (type < 4) { + ba = helpEngine.fileData(name); + if (name.toString().endsWith(QLatin1String(".svg"), Qt::CaseInsensitive)) { + QImage image; + image.loadFromData(ba, "svg"); + if (!image.isNull()) + return image; + } + } + return ba; +} + +void HelpViewer::openLinkInNewTab() +{ + TRACE_OBJ + if(lastAnchor.isEmpty()) + return; + + parentWidget->setSourceInNewTab(QUrl(lastAnchor)); + lastAnchor.clear(); +} + +void HelpViewer::openLinkInNewTab(const QString &link) +{ + TRACE_OBJ + lastAnchor = link; + openLinkInNewTab(); +} + +bool HelpViewer::hasAnchorAt(const QPoint& pos) +{ + TRACE_OBJ + lastAnchor = anchorAt(pos); + if (lastAnchor.isEmpty()) + return false; + + lastAnchor = source().resolved(lastAnchor).toString(); + if (lastAnchor.at(0) == QLatin1Char('#')) { + QString src = source().toString(); + int hsh = src.indexOf(QLatin1Char('#')); + lastAnchor = (hsh>=0 ? src.left(hsh) : src) + lastAnchor; + } + + return true; +} + +void HelpViewer::contextMenuEvent(QContextMenuEvent *e) +{ + TRACE_OBJ + QMenu menu(QLatin1String(""), 0); + + QUrl link; + QAction *copyAnchorAction = 0; + if (hasAnchorAt(e->pos())) { + link = anchorAt(e->pos()); + if (link.isRelative()) + link = source().resolved(link); + copyAnchorAction = menu.addAction(tr("Copy &Link Location")); + copyAnchorAction->setEnabled(!link.isEmpty() && link.isValid()); + + menu.addAction(tr("Open Link in New Tab\tCtrl+LMB"), this, + SLOT(openLinkInNewTab())); + menu.addSeparator(); + } + menu.addActions(parentWidget->globalActions()); + QAction *action = menu.exec(e->globalPos()); + if (action == copyAnchorAction) + QApplication::clipboard()->setText(link.toString()); +} + +void HelpViewer::mouseReleaseEvent(QMouseEvent *e) +{ + TRACE_OBJ +#ifndef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(e)) + return; +#endif + + controlPressed = e->modifiers() & Qt::ControlModifier; + if ((controlPressed && hasAnchorAt(e->pos())) || + (e->button() == Qt::MidButton && hasAnchorAt(e->pos()))) { + openLinkInNewTab(); + return; + } + + QTextBrowser::mouseReleaseEvent(e); +} + +void HelpViewer::mousePressEvent(QMouseEvent *e) +{ +#ifdef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(e)) + return; +#endif + QTextBrowser::mousePressEvent(e); +} + +void HelpViewer::keyPressEvent(QKeyEvent *e) +{ + TRACE_OBJ + if ((e->key() == Qt::Key_Home && e->modifiers() != Qt::NoModifier) + || (e->key() == Qt::Key_End && e->modifiers() != Qt::NoModifier)) { + QKeyEvent* event = new QKeyEvent(e->type(), e->key(), Qt::NoModifier, + e->text(), e->isAutoRepeat(), e->count()); + e = event; + } + QTextBrowser::keyPressEvent(e); +} + +void HelpViewer::home() +{ + TRACE_OBJ + setSource(helpEngine.homePage()); +} + +void HelpViewer::wheelEvent(QWheelEvent *e) +{ + TRACE_OBJ + if (e->modifiers() == Qt::ControlModifier) { + e->accept(); + e->delta() > 0 ? scaleUp() : scaleDown(); + } else { + QTextBrowser::wheelEvent(e); + } +} + +bool HelpViewer::eventFilter(QObject *obj, QEvent *event) +{ + TRACE_OBJ + if (event->type() == QEvent::FontChange && !forceFont) + return true; + return QTextBrowser::eventFilter(obj, event); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/helpviewer_qtb.h b/tools/assistant/tools/assistant/helpviewer_qtb.h new file mode 100644 index 0000000..acb734b --- /dev/null +++ b/tools/assistant/tools/assistant/helpviewer_qtb.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef HELPVIEWERQTB_H +#define HELPVIEWERQTB_H + +#include "helpviewer.h" + +#include <QtCore/QUrl> +#include <QtCore/QVariant> + +#include <QtGui/QTextBrowser> + +QT_BEGIN_NAMESPACE + +class CentralWidget; +class HelpEngineWrapper; +class QContextMenuEvent; +class QKeyEvent; +class QMouseEvent; + +class HelpViewer : public QTextBrowser, public AbstractHelpViewer +{ + Q_OBJECT + +public: + HelpViewer(CentralWidget *parent, qreal zoom = 0.0); + ~HelpViewer(); + + QFont viewerFont() const; + void setViewerFont(const QFont &font); + + void scaleUp(); + void scaleDown(); + void resetScale(); + qreal scale() const { return zoomCount; } + + bool handleForwardBackwardMouseButtons(QMouseEvent *e); + + void setSource(const QUrl &url); + + inline bool hasSelection() const + { return textCursor().hasSelection(); } + +public Q_SLOTS: + void home(); + +protected: + void wheelEvent(QWheelEvent *e); + bool eventFilter(QObject *obj, QEvent *event); + +private: + QVariant loadResource(int type, const QUrl &name); + void openLinkInNewTab(const QString &link); + bool hasAnchorAt(const QPoint& pos); + void contextMenuEvent(QContextMenuEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void keyPressEvent(QKeyEvent *e); + void mousePressEvent(QMouseEvent *e); + +private slots: + void openLinkInNewTab(); + +private: + int zoomCount; + bool controlPressed; + QString lastAnchor; + CentralWidget* parentWidget; + HelpEngineWrapper &helpEngine; + + bool forceFont; +}; + +QT_END_NAMESPACE + +#endif // HELPVIEWERQTB_H diff --git a/tools/assistant/tools/assistant/helpviewer_qwv.cpp b/tools/assistant/tools/assistant/helpviewer_qwv.cpp new file mode 100644 index 0000000..244d091 --- /dev/null +++ b/tools/assistant/tools/assistant/helpviewer_qwv.cpp @@ -0,0 +1,406 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "helpviewer_qwv.h" + +#include "centralwidget.h" +#include "helpenginewrapper.h" +#include "tracer.h" + +#include <QtCore/QFileInfo> +#include <QtCore/QString> +#include <QtCore/QStringBuilder> +#include <QtCore/QTimer> + +#include <QtGui/QWheelEvent> + +#include <QtNetwork/QNetworkAccessManager> +#include <QtNetwork/QNetworkReply> +#include <QtNetwork/QNetworkRequest> + +QT_BEGIN_NAMESPACE + +class HelpNetworkReply : public QNetworkReply +{ +public: + HelpNetworkReply(const QNetworkRequest &request, const QByteArray &fileData, + const QString &mimeType); + + virtual void abort(); + + virtual qint64 bytesAvailable() const + { return data.length() + QNetworkReply::bytesAvailable(); } + +protected: + virtual qint64 readData(char *data, qint64 maxlen); + +private: + QByteArray data; + qint64 origLen; +}; + +HelpNetworkReply::HelpNetworkReply(const QNetworkRequest &request, + const QByteArray &fileData, const QString& mimeType) + : data(fileData), origLen(fileData.length()) +{ + TRACE_OBJ + setRequest(request); + setOpenMode(QIODevice::ReadOnly); + + setHeader(QNetworkRequest::ContentTypeHeader, mimeType); + setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(origLen)); + QTimer::singleShot(0, this, SIGNAL(metaDataChanged())); + QTimer::singleShot(0, this, SIGNAL(readyRead())); +} + +void HelpNetworkReply::abort() +{ + TRACE_OBJ +} + +qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen) +{ + TRACE_OBJ + qint64 len = qMin(qint64(data.length()), maxlen); + if (len) { + qMemCopy(buffer, data.constData(), len); + data.remove(0, len); + } + if (!data.length()) + QTimer::singleShot(0, this, SIGNAL(finished())); + return len; +} + +class HelpNetworkAccessManager : public QNetworkAccessManager +{ +public: + HelpNetworkAccessManager(QObject *parent); + +protected: + virtual QNetworkReply *createRequest(Operation op, + const QNetworkRequest &request, QIODevice *outgoingData = 0); +}; + +HelpNetworkAccessManager::HelpNetworkAccessManager(QObject *parent) + : QNetworkAccessManager(parent) +{ + TRACE_OBJ +} + +QNetworkReply *HelpNetworkAccessManager::createRequest(Operation /*op*/, + const QNetworkRequest &request, QIODevice* /*outgoingData*/) +{ + TRACE_OBJ + QString url = request.url().toString(); + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + + // TODO: For some reason the url to load is already wrong (passed from webkit) + // though the css file and the references inside should work that way. One + // possible problem might be that the css is loaded at the same level as the + // html, thus a path inside the css like (../images/foo.png) might cd out of + // the virtual folder + if (!helpEngine.findFile(url).isValid()) { + if (url.startsWith(AbstractHelpViewer::DocPath)) { + QUrl newUrl = request.url(); + if (!newUrl.path().startsWith(QLatin1String("/qdoc/"))) { + newUrl.setPath(QLatin1String("qdoc") + newUrl.path()); + url = newUrl.toString(); + } + } + } + + const QString &mimeType = AbstractHelpViewer::mimeFromUrl(url); + const QByteArray &data = helpEngine.findFile(url).isValid() + ? helpEngine.fileData(url) + : AbstractHelpViewer::PageNotFoundMessage.arg(url).toUtf8(); + return new HelpNetworkReply(request, data, mimeType.isEmpty() + ? QLatin1String("application/octet-stream") : mimeType); +} + +class HelpPage : public QWebPage +{ +public: + HelpPage(CentralWidget *central, QObject *parent); + +protected: + virtual QWebPage *createWindow(QWebPage::WebWindowType); + virtual void triggerAction(WebAction action, bool checked = false); + + virtual bool acceptNavigationRequest(QWebFrame *frame, + const QNetworkRequest &request, NavigationType type); + +private: + CentralWidget *centralWidget; + bool closeNewTabIfNeeded; + + friend class HelpViewer; + Qt::MouseButtons m_pressedButtons; + Qt::KeyboardModifiers m_keyboardModifiers; +}; + +HelpPage::HelpPage(CentralWidget *central, QObject *parent) + : QWebPage(parent) + , centralWidget(central) + , closeNewTabIfNeeded(false) + , m_pressedButtons(Qt::NoButton) + , m_keyboardModifiers(Qt::NoModifier) +{ + TRACE_OBJ +} + +QWebPage *HelpPage::createWindow(QWebPage::WebWindowType) +{ + TRACE_OBJ + HelpPage* newPage = static_cast<HelpPage*>(centralWidget->newEmptyTab()->page()); + if (newPage) + newPage->closeNewTabIfNeeded = closeNewTabIfNeeded; + closeNewTabIfNeeded = false; + return newPage; +} + +void HelpPage::triggerAction(WebAction action, bool checked) +{ + TRACE_OBJ + switch (action) { + case OpenLinkInNewWindow: + closeNewTabIfNeeded = true; + default: // fall through + QWebPage::triggerAction(action, checked); + break; + } +} + +bool HelpPage::acceptNavigationRequest(QWebFrame *, + const QNetworkRequest &request, QWebPage::NavigationType type) +{ + TRACE_OBJ + const bool closeNewTab = closeNewTabIfNeeded; + closeNewTabIfNeeded = false; + + const QUrl &url = request.url(); + if (AbstractHelpViewer::launchWithExternalApp(url)) { + if (closeNewTab) + QMetaObject::invokeMethod(centralWidget, "closeTab"); + return false; + } + + if (type == QWebPage::NavigationTypeLinkClicked + && (m_keyboardModifiers & Qt::ControlModifier + || m_pressedButtons == Qt::MidButton)) { + if (centralWidget->newEmptyTab()) + centralWidget->setSource(url); + m_pressedButtons = Qt::NoButton; + m_keyboardModifiers = Qt::NoModifier; + return false; + } + + return true; +} + +// -- HelpViewer + +HelpViewer::HelpViewer(CentralWidget *parent, qreal zoom) + : QWebView(parent) + , parentWidget(parent) + , loadFinished(false) + , helpEngine(HelpEngineWrapper::instance()) +{ + TRACE_OBJ + setAcceptDrops(false); + + setPage(new HelpPage(parent, this)); + + page()->setNetworkAccessManager(new HelpNetworkAccessManager(this)); + + QAction* action = pageAction(QWebPage::OpenLinkInNewWindow); + action->setText(tr("Open Link in New Tab")); + if (!parent) + action->setVisible(false); + + pageAction(QWebPage::DownloadLinkToDisk)->setVisible(false); + pageAction(QWebPage::DownloadImageToDisk)->setVisible(false); + pageAction(QWebPage::OpenImageInNewWindow)->setVisible(false); + + connect(pageAction(QWebPage::Copy), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(pageAction(QWebPage::Back), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(pageAction(QWebPage::Forward), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(page(), SIGNAL(linkHovered(QString,QString,QString)), this, + SIGNAL(highlighted(QString))); + connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl))); + connect(this, SIGNAL(loadFinished(bool)), this, SLOT(setLoadFinished(bool))); + connect(page(), SIGNAL(printRequested(QWebFrame*)), this, SIGNAL(printRequested())); + + setFont(viewerFont()); + setTextSizeMultiplier(zoom == 0.0 ? 1.0 : zoom); +} + +HelpViewer::~HelpViewer() +{ + TRACE_OBJ +} + +QFont HelpViewer::viewerFont() const +{ + TRACE_OBJ + if (helpEngine.usesBrowserFont()) + return helpEngine.browserFont(); + + QWebSettings *webSettings = QWebSettings::globalSettings(); + return QFont(webSettings->fontFamily(QWebSettings::StandardFont), + webSettings->fontSize(QWebSettings::DefaultFontSize)); +} + +void HelpViewer::setViewerFont(const QFont &font) +{ + TRACE_OBJ + QWebSettings *webSettings = settings(); + webSettings->setFontFamily(QWebSettings::StandardFont, font.family()); + webSettings->setFontSize(QWebSettings::DefaultFontSize, font.pointSize()); +} + +void HelpViewer::scaleUp() +{ + TRACE_OBJ + setTextSizeMultiplier(textSizeMultiplier() + 0.1); +} + +void HelpViewer::scaleDown() +{ + TRACE_OBJ + setTextSizeMultiplier(qMax(0.0, textSizeMultiplier() - 0.1)); +} + +void HelpViewer::resetScale() +{ + TRACE_OBJ + setTextSizeMultiplier(1.0); +} + +bool HelpViewer::handleForwardBackwardMouseButtons(QMouseEvent *e) +{ + TRACE_OBJ + if (e->button() == Qt::XButton1) { + triggerPageAction(QWebPage::Back); + return true; + } + + if (e->button() == Qt::XButton2) { + triggerPageAction(QWebPage::Forward); + return true; + } + + return false; +} + +void HelpViewer::setSource(const QUrl &url) +{ + TRACE_OBJ + loadFinished = false; + load(url.toString() == QLatin1String("help") ? LocalHelpFile : url); +} + +void HelpViewer::home() +{ + TRACE_OBJ + setSource(helpEngine.homePage()); +} + +void HelpViewer::wheelEvent(QWheelEvent *e) +{ + TRACE_OBJ + if (e->modifiers()& Qt::ControlModifier) { + e->accept(); + e->delta() > 0 ? scaleUp() : scaleDown(); + } else { + QWebView::wheelEvent(e); + } +} + +void HelpViewer::mouseReleaseEvent(QMouseEvent *e) +{ + TRACE_OBJ +#ifndef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(e)) + return; +#endif + + QWebView::mouseReleaseEvent(e); +} + +void HelpViewer::actionChanged() +{ + TRACE_OBJ + QAction *a = qobject_cast<QAction *>(sender()); + if (a == pageAction(QWebPage::Copy)) + emit copyAvailable(a->isEnabled()); + else if (a == pageAction(QWebPage::Back)) + emit backwardAvailable(a->isEnabled()); + else if (a == pageAction(QWebPage::Forward)) + emit forwardAvailable(a->isEnabled()); +} + +void HelpViewer::mousePressEvent(QMouseEvent *event) +{ + TRACE_OBJ +#ifdef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(event)) + return; +#endif + + HelpPage *currentPage = static_cast<HelpPage*>(page()); + if (currentPage) { + currentPage->m_pressedButtons = event->buttons(); + currentPage->m_keyboardModifiers = event->modifiers(); + } + QWebView::mousePressEvent(event); +} + +void HelpViewer::setLoadFinished(bool ok) +{ + TRACE_OBJ + loadFinished = ok; + emit sourceChanged(url()); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/helpviewer_qwv.h b/tools/assistant/tools/assistant/helpviewer_qwv.h new file mode 100644 index 0000000..2577828 --- /dev/null +++ b/tools/assistant/tools/assistant/helpviewer_qwv.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HELPVIEWERQWV_H +#define HELPVIEWERQWV_H + +#include "helpviewer.h" + +#include <QtGui/QAction> +#include <QtWebKit/QWebView> + +QT_BEGIN_NAMESPACE + +class CentralWidget; +class HelpEngineWrapper; +class QMouseEvent; + +class HelpViewer : public QWebView, public AbstractHelpViewer +{ + Q_OBJECT + +public: + HelpViewer(CentralWidget *parent, qreal zoom = 0.0); + ~HelpViewer(); + + QFont viewerFont() const; + void setViewerFont(const QFont &font); + + void scaleUp(); + void scaleDown(); + void resetScale(); + qreal scale() const { return textSizeMultiplier(); } + + bool handleForwardBackwardMouseButtons(QMouseEvent *e); + + void setSource(const QUrl &url); + inline QUrl source() const { return url(); } + + inline QString documentTitle() const + { return title(); } + + inline bool hasSelection() const + { return !selectedText().isEmpty(); } // ### this is suboptimal + + inline void copy() + { return triggerPageAction(QWebPage::Copy); } + + inline bool isForwardAvailable() const + { return pageAction(QWebPage::Forward)->isEnabled(); } + inline bool isBackwardAvailable() const + { return pageAction(QWebPage::Back)->isEnabled(); } + inline bool hasLoadFinished() const + { return loadFinished; } + +public Q_SLOTS: + void home(); + void backward() { back(); } + +Q_SIGNALS: + void copyAvailable(bool enabled); + void forwardAvailable(bool enabled); + void backwardAvailable(bool enabled); + void highlighted(const QString &); + void sourceChanged(const QUrl &); + void printRequested(); + +protected: + virtual void wheelEvent(QWheelEvent *); + void mouseReleaseEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *event); + +private Q_SLOTS: + void actionChanged(); + void setLoadFinished(bool ok); + +private: + CentralWidget* parentWidget; + bool loadFinished; + HelpEngineWrapper &helpEngine; +}; + +QT_END_NAMESPACE + +#endif // HELPVIEWERQWV_H diff --git a/tools/assistant/tools/assistant/images/bookmark.png b/tools/assistant/tools/assistant/images/bookmark.png Binary files differnew file mode 100644 index 0000000..57e57e3 --- /dev/null +++ b/tools/assistant/tools/assistant/images/bookmark.png diff --git a/tools/assistant/tools/assistant/indexwindow.cpp b/tools/assistant/tools/assistant/indexwindow.cpp index 24a212e..63ddbe4 100644 --- a/tools/assistant/tools/assistant/indexwindow.cpp +++ b/tools/assistant/tools/assistant/indexwindow.cpp @@ -38,9 +38,12 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "tracer.h" #include "indexwindow.h" #include "centralwidget.h" +#include "helpenginewrapper.h" +#include "helpviewer.h" #include "topicchooser.h" #include <QtGui/QLayout> @@ -51,22 +54,20 @@ #include <QtGui/QContextMenuEvent> #include <QtGui/QListWidgetItem> -#include <QtHelp/QHelpEngine> #include <QtHelp/QHelpIndexWidget> QT_BEGIN_NAMESPACE -IndexWindow::IndexWindow(QHelpEngine *helpEngine, QWidget *parent) +IndexWindow::IndexWindow(QWidget *parent) : QWidget(parent) - , m_searchLineEdit(0) - , m_indexWidget(0) - , m_helpEngine(helpEngine) + , m_searchLineEdit(new QLineEdit) + , m_indexWidget(HelpEngineWrapper::instance().indexWidget()) { + TRACE_OBJ QVBoxLayout *layout = new QVBoxLayout(this); QLabel *l = new QLabel(tr("&Look for:")); layout->addWidget(l); - m_searchLineEdit = new QLineEdit(); l->setBuddy(m_searchLineEdit); connect(m_searchLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterIndices(QString))); @@ -74,11 +75,11 @@ IndexWindow::IndexWindow(QHelpEngine *helpEngine, QWidget *parent) layout->setMargin(4); layout->addWidget(m_searchLineEdit); - m_indexWidget = m_helpEngine->indexWidget(); + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); m_indexWidget->installEventFilter(this); - connect(m_helpEngine->indexModel(), SIGNAL(indexCreationStarted()), this, + connect(helpEngine.indexModel(), SIGNAL(indexCreationStarted()), this, SLOT(disableSearchLineEdit())); - connect(m_helpEngine->indexModel(), SIGNAL(indexCreated()), this, + connect(helpEngine.indexModel(), SIGNAL(indexCreated()), this, SLOT(enableSearchLineEdit())); connect(m_indexWidget, SIGNAL(linkActivated(QUrl,QString)), this, SIGNAL(linkActivated(QUrl))); @@ -93,10 +94,12 @@ IndexWindow::IndexWindow(QHelpEngine *helpEngine, QWidget *parent) IndexWindow::~IndexWindow() { + TRACE_OBJ } void IndexWindow::filterIndices(const QString &filter) { + TRACE_OBJ if (filter.contains(QLatin1Char('*'))) m_indexWidget->filterIndices(filter, filter); else @@ -105,6 +108,7 @@ void IndexWindow::filterIndices(const QString &filter) bool IndexWindow::eventFilter(QObject *obj, QEvent *e) { + TRACE_OBJ if (obj == m_searchLineEdit && e->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast<QKeyEvent*>(e); QModelIndex idx = m_indexWidget->currentIndex(); @@ -170,22 +174,26 @@ bool IndexWindow::eventFilter(QObject *obj, QEvent *e) void IndexWindow::enableSearchLineEdit() { + TRACE_OBJ m_searchLineEdit->setDisabled(false); filterIndices(m_searchLineEdit->text()); } void IndexWindow::disableSearchLineEdit() { + TRACE_OBJ m_searchLineEdit->setDisabled(true); } void IndexWindow::setSearchLineEditText(const QString &text) { + TRACE_OBJ m_searchLineEdit->setText(text); } void IndexWindow::focusInEvent(QFocusEvent *e) { + TRACE_OBJ if (e->reason() != Qt::MouseFocusReason) { m_searchLineEdit->selectAll(); m_searchLineEdit->setFocus(); @@ -194,6 +202,7 @@ void IndexWindow::focusInEvent(QFocusEvent *e) void IndexWindow::open(QHelpIndexWidget* indexWidget, const QModelIndex &index) { + TRACE_OBJ QHelpIndexModel *model = qobject_cast<QHelpIndexModel*>(indexWidget->model()); if (model) { QString keyword = model->data(index, Qt::DisplayRole).toString(); @@ -210,7 +219,7 @@ void IndexWindow::open(QHelpIndexWidget* indexWidget, const QModelIndex &index) return; } - if (url.path().endsWith(QLatin1String(".pdf"), Qt::CaseInsensitive)) + if (!AbstractHelpViewer::canOpenPage(url.path())) CentralWidget::instance()->setSource(url); else CentralWidget::instance()->setSourceInNewTab(url); diff --git a/tools/assistant/tools/assistant/indexwindow.h b/tools/assistant/tools/assistant/indexwindow.h index 4343d0e..eb587b1 100644 --- a/tools/assistant/tools/assistant/indexwindow.h +++ b/tools/assistant/tools/assistant/indexwindow.h @@ -49,7 +49,6 @@ QT_BEGIN_NAMESPACE class QHelpIndexWidget; -class QHelpEngine; class QModelIndex; class IndexWindow : public QWidget @@ -57,7 +56,7 @@ class IndexWindow : public QWidget Q_OBJECT public: - IndexWindow(QHelpEngine *helpEngine, QWidget *parent = 0); + IndexWindow(QWidget *parent = 0); ~IndexWindow(); void setSearchLineEditText(const QString &text); @@ -84,7 +83,6 @@ private: QLineEdit *m_searchLineEdit; QHelpIndexWidget *m_indexWidget; - QHelpEngine *m_helpEngine; }; QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/installdialog.cpp b/tools/assistant/tools/assistant/installdialog.cpp index 95a1226..f3bf6f6 100644 --- a/tools/assistant/tools/assistant/installdialog.cpp +++ b/tools/assistant/tools/assistant/installdialog.cpp @@ -38,6 +38,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "tracer.h" #include "installdialog.h" @@ -66,6 +67,7 @@ InstallDialog::InstallDialog(QHelpEngineCore *helpEngine, QWidget *parent, const QString &host, int port) : QDialog(parent), m_helpEngine(helpEngine), m_host(host), m_port(port) { + TRACE_OBJ m_ui.setupUi(this); m_ui.installButton->setEnabled(false); @@ -94,15 +96,18 @@ InstallDialog::InstallDialog(QHelpEngineCore *helpEngine, QWidget *parent, InstallDialog::~InstallDialog() { + TRACE_OBJ } QStringList InstallDialog::installedDocumentations() const { + TRACE_OBJ return m_installedDocumentations; } void InstallDialog::init() { + TRACE_OBJ m_ui.statusLabel->setText(tr("Downloading documentation info...")); m_ui.progressBar->show(); @@ -122,6 +127,7 @@ void InstallDialog::init() void InstallDialog::updateInstallButton() { + TRACE_OBJ QListWidgetItem *item = 0; for (int i=0; i<m_ui.listWidget->count(); ++i) { item = m_ui.listWidget->item(i); @@ -136,6 +142,7 @@ void InstallDialog::updateInstallButton() void InstallDialog::updateDocItemList() { + TRACE_OBJ QStringList registeredDocs = m_helpEngine->registeredDocumentations(); QListWidgetItem *item = 0; for (int i=0; i<m_ui.listWidget->count(); ++i) { @@ -151,6 +158,7 @@ void InstallDialog::updateDocItemList() void InstallDialog::cancelDownload() { + TRACE_OBJ m_ui.statusLabel->setText(tr("Download canceled.")); m_httpAborted = true; m_itemsToInstall.clear(); @@ -162,6 +170,7 @@ void InstallDialog::cancelDownload() void InstallDialog::install() { + TRACE_OBJ QListWidgetItem *item = 0; for (int i=0; i<m_ui.listWidget->count(); ++i) { item = m_ui.listWidget->item(i); @@ -174,6 +183,7 @@ void InstallDialog::install() void InstallDialog::downloadNextFile() { + TRACE_OBJ if (!m_itemsToInstall.count()) { m_ui.cancelButton->setEnabled(false); m_ui.closeButton->setEnabled(true); @@ -226,6 +236,7 @@ void InstallDialog::downloadNextFile() void InstallDialog::httpRequestFinished(int requestId, bool error) { + TRACE_OBJ if (requestId == m_docInfoId && m_buffer) { m_ui.progressBar->hide(); if (error) { @@ -296,6 +307,7 @@ void InstallDialog::httpRequestFinished(int requestId, bool error) void InstallDialog::installFile(const QString &fileName) { + TRACE_OBJ if (m_helpEngine->registerDocumentation(fileName)) { m_installedDocumentations .append(QHelpEngineCore::namespaceName(fileName)); @@ -308,6 +320,7 @@ void InstallDialog::installFile(const QString &fileName) void InstallDialog::readResponseHeader(const QHttpResponseHeader &responseHeader) { + TRACE_OBJ if (responseHeader.statusCode() != 200) { QMessageBox::information(this, m_windowTitle, tr("Download failed: %1.") @@ -321,6 +334,7 @@ void InstallDialog::readResponseHeader(const QHttpResponseHeader &responseHeader void InstallDialog::updateDataReadProgress(int bytesRead, int totalBytes) { + TRACE_OBJ if (m_httpAborted) return; @@ -330,6 +344,7 @@ void InstallDialog::updateDataReadProgress(int bytesRead, int totalBytes) void InstallDialog::browseDirectories() { + TRACE_OBJ QString dir = QFileDialog::getExistingDirectory(this, m_windowTitle, m_ui.pathLineEdit->text()); if (!dir.isEmpty()) diff --git a/tools/assistant/tools/assistant/main.cpp b/tools/assistant/tools/assistant/main.cpp index 7a957e2..51ea9f9 100644 --- a/tools/assistant/tools/assistant/main.cpp +++ b/tools/assistant/tools/assistant/main.cpp @@ -38,27 +38,34 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "tracer.h" #include <QtCore/QDir> #include <QtCore/QFileInfo> +#include <QtCore/QLibraryInfo> #include <QtCore/QLocale> +#include <QtCore/QScopedPointer> +#include <QtCore/QStringList> #include <QtCore/QTranslator> -#include <QtCore/QLibraryInfo> #include <QtCore/QUrl> -#include <QtCore/QStringList> #include <QtGui/QApplication> #include <QtGui/QDesktopServices> -#include <QtHelp/QHelpEngineCore> +#include <QtHelp/QHelpEngine> +#include <QtHelp/QHelpSearchEngine> #include <QtNetwork/QLocalSocket> #include <QtSql/QSqlDatabase> +#include "../shared/collectionconfiguration.h" +#include "helpenginewrapper.h" #include "mainwindow.h" #include "cmdlineparser.h" +// #define TRACING_REQUESTED + QT_USE_NAMESPACE #if defined(USE_STATIC_SQLITE_PLUGIN) @@ -66,118 +73,57 @@ QT_USE_NAMESPACE Q_IMPORT_PLUGIN(qsqlite) #endif +namespace { + void updateLastPagesOnUnregister(QHelpEngineCore& helpEngine, const QString& nsName) { - int lastPage = helpEngine.customValue(QLatin1String("LastTabPage")).toInt(); - - QLatin1String sep("|"); - QLatin1String pages("LastShownPages"); -#if !defined(QT_NO_WEBKIT) - QLatin1String zoom("LastPagesZoomWebView"); -#else - QLatin1String zoom("LastPagesZoomTextBrowser"); -#endif - - QStringList currentPages = - helpEngine.customValue(pages).toString(). - split(QLatin1Char('|'), QString::SkipEmptyParts); - + TRACE_OBJ + int lastPage = CollectionConfiguration::lastTabPage(helpEngine); + QStringList currentPages = CollectionConfiguration::lastShownPages(helpEngine); if (!currentPages.isEmpty()) { - QVector<QString>zoomList = helpEngine.customValue(zoom).toString(). - split(sep, QString::SkipEmptyParts).toVector(); - if (zoomList.isEmpty()) - zoomList.fill(QLatin1String("0.0"), currentPages.size()); - else if(zoomList.count() < currentPages.count()) { - zoomList.insert(zoomList.count(), - currentPages.count() - zoomList.count(), QLatin1String("0.0")); - } + QStringList zoomList = CollectionConfiguration::lastZoomFactors(helpEngine); + while (zoomList.count() < currentPages.count()) + zoomList.append(CollectionConfiguration::DefaultZoomFactor); for (int i = currentPages.count(); --i >= 0;) { if (QUrl(currentPages.at(i)).host() == nsName) { - zoomList.remove(i); + zoomList.removeAt(i); currentPages.removeAt(i); lastPage = (lastPage == (i + 1)) ? 1 : lastPage; } } - helpEngine.setCustomValue(pages, currentPages.join(sep)); - helpEngine.setCustomValue(QLatin1String("LastTabPage"), lastPage); - helpEngine.setCustomValue(zoom, QStringList(zoomList.toList()).join(sep)); + CollectionConfiguration::setLastShownPages(helpEngine, currentPages); + CollectionConfiguration::setLastTabPage(helpEngine, lastPage); + CollectionConfiguration::setLastZoomFactors(helpEngine, zoomList); } } bool updateUserCollection(QHelpEngineCore& user, const QHelpEngineCore& caller) { - const uint callerCollectionCreationTime = caller. - customValue(QLatin1String("CreationTime"), 0).toUInt(); - const uint userCollectionCreationTime = user. - customValue(QLatin1String("CreationTime"), 1).toUInt(); - - if (callerCollectionCreationTime <= userCollectionCreationTime) + TRACE_OBJ + if (!CollectionConfiguration::isNewer(caller, user)) return false; - - user.setCustomValue(QLatin1String("CreationTime"), - callerCollectionCreationTime); - user.setCustomValue(QLatin1String("WindowTitle"), - caller.customValue(QLatin1String("WindowTitle"))); - user.setCustomValue(QLatin1String("LastShownPages"), - caller.customValue(QLatin1String("LastShownPages"))); -#if !defined(QT_NO_WEBKIT) - const QLatin1String zoomKey("LastPagesZoomWebView"); -#else - const QLatin1String zoomKey("LastPagesZoomTextBrowser"); -#endif - user.setCustomValue(zoomKey, caller.customValue(zoomKey)); - user.setCustomValue(QLatin1String("CurrentFilter"), - caller.customValue(QLatin1String("CurrentFilter"))); - user.setCustomValue(QLatin1String("CacheDirectory"), - caller.customValue(QLatin1String("CacheDirectory"))); - user.setCustomValue(QLatin1String("EnableFilterFunctionality"), - caller.customValue(QLatin1String("EnableFilterFunctionality"))); - user.setCustomValue(QLatin1String("HideFilterFunctionality"), - caller.customValue(QLatin1String("HideFilterFunctionality"))); - user.setCustomValue(QLatin1String("EnableDocumentationManager"), - caller.customValue(QLatin1String("EnableDocumentationManager"))); - user.setCustomValue(QLatin1String("EnableAddressBar"), - caller.customValue(QLatin1String("EnableAddressBar"))); - user.setCustomValue(QLatin1String("HideAddressBar"), - caller.customValue(QLatin1String("HideAddressBar"))); - user.setCustomValue(QLatin1String("ApplicationIcon"), - caller.customValue(QLatin1String("ApplicationIcon"))); - user.setCustomValue(QLatin1String("AboutMenuTexts"), - caller.customValue(QLatin1String("AboutMenuTexts"))); - user.setCustomValue(QLatin1String("AboutIcon"), - caller.customValue(QLatin1String("AboutIcon"))); - user.setCustomValue(QLatin1String("AboutTexts"), - caller.customValue(QLatin1String("AboutTexts"))); - user.setCustomValue(QLatin1String("AboutImages"), - caller.customValue(QLatin1String("AboutImages"))); - user.setCustomValue(QLatin1String("defaultHomepage"), - caller.customValue(QLatin1String("defaultHomepage"))); - + CollectionConfiguration::copyConfiguration(caller, user); return true; } -bool -referencedHelpFilesExistAll(QHelpEngineCore& user, QStringList& nameSpaces) +void stripNonexistingDocs(QHelpEngineCore& collection) { - QFileInfo fi; - int counter = nameSpaces.count(); - for (int i = counter; --i >= 0;) { - const QString& nameSpace = nameSpaces.at(i); - fi.setFile(user.documentationFileName(nameSpace)); - if (!fi.exists() || !fi.isFile()) { - user.unregisterDocumentation(nameSpace); - nameSpaces.removeAll(nameSpace); - } + TRACE_OBJ + const QStringList &namespaces = collection.registeredDocumentations(); + foreach (const QString &ns, namespaces) { + QFileInfo fi(collection.documentationFileName(ns)); + if (!fi.exists() || !fi.isFile()) + collection.unregisterDocumentation(ns); } - return (counter != nameSpaces.count()) ? false : true; } QString indexFilesFolder(const QString &collectionFile) { + TRACE_OBJ QString indexFilesFolder = QLatin1String(".fulltextsearch"); if (!collectionFile.isEmpty()) { QFileInfo fi(collectionFile); @@ -187,192 +133,306 @@ QString indexFilesFolder(const QString &collectionFile) return indexFilesFolder; } -int main(int argc, char *argv[]) +/* + * Returns the expected absolute file path of the cached collection file + * correspondinging to the given collection's file. + * It may or may not exist yet. + */ +QString constructCachedCollectionFilePath(const QHelpEngineCore &collection) +{ + TRACE_OBJ + const QString &filePath = collection.collectionFile(); + const QString &fileName = QFileInfo(filePath).fileName(); + const QString &cacheDir = CollectionConfiguration::cacheDir(collection); + const QString &dir = !cacheDir.isEmpty() + && CollectionConfiguration::cacheDirIsRelativeToCollection(collection) + ? QFileInfo(filePath).dir().absolutePath() + + QDir::separator() + cacheDir + : MainWindow::collectionFileDirectory(false, cacheDir); + return dir + QDir::separator() + fileName; +} + +bool synchronizeDocs(QHelpEngineCore &collection, + QHelpEngineCore &cachedCollection, + CmdLineParser &cmd) { -#ifndef Q_OS_WIN - // First do a quick search for arguments that imply command-line mode. + TRACE_OBJ + const QDateTime &lastCollectionRegisterTime = + CollectionConfiguration::lastRegisterTime(collection); + if (!lastCollectionRegisterTime.isValid() || lastCollectionRegisterTime + < CollectionConfiguration::lastRegisterTime(cachedCollection)) + return true; + + const QStringList &docs = collection.registeredDocumentations(); + const QStringList &cachedDocs = cachedCollection.registeredDocumentations(); + + /* + * Ensure that the cached collection contains all docs that + * the collection contains. + */ + foreach (const QString &doc, docs) { + if (!cachedDocs.contains(doc)) { + const QString &docFile = collection.documentationFileName(doc); + if (!cachedCollection.registerDocumentation(docFile)) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Error registering documentation file '%1': %2"). + arg(docFile).arg(cachedCollection.error()), true); + return false; + } + } + } + + CollectionConfiguration::updateLastRegisterTime(cachedCollection); + + return true; +} + +bool removeSearchIndex(const QString &collectionFile) +{ + TRACE_OBJ + QString path = QFileInfo(collectionFile).path(); + path += QLatin1Char('/') + indexFilesFolder(collectionFile); + + QLocalSocket localSocket; + localSocket.connectToServer(QString(QLatin1String("QtAssistant%1")) + .arg(QLatin1String(QT_VERSION_STR))); + + QDir dir(path); // check if there is no other instance ruinning + if (!dir.exists() || localSocket.waitForConnected()) + return false; + + QStringList lst = dir.entryList(QDir::Files | QDir::Hidden); + foreach (const QString &item, lst) + dir.remove(item); + return true; +} + +bool rebuildSearchIndex(QCoreApplication &app, const QString &collectionFile, + CmdLineParser &cmd) +{ + TRACE_OBJ + QHelpEngine engine(collectionFile); + if (!engine.setupData()) { + cmd.showMessage(QCoreApplication::translate("Assistant", "Error: %1") + .arg(engine.error()), true); + return false; + } + + QHelpSearchEngine * const searchEngine = engine.searchEngine(); + QObject::connect(searchEngine, SIGNAL(indexingFinished()), &app, + SLOT(quit())); + searchEngine->reindexDocumentation(); + return app.exec() == 0; +} + +bool useGui(int argc, char *argv[]) +{ + TRACE_OBJ + bool gui = true; +#ifndef Q_OS_WIN + // Look for arguments that imply command-line mode. const char * cmdModeArgs[] = { - "-help", "-register", "-unregister", "-remove-search-index" + "-help", "-register", "-unregister", "-remove-search-index", + "-rebuild-search-index" }; - bool useGui = true; for (int i = 1; i < argc; ++i) { for (size_t j = 0; j < sizeof cmdModeArgs/sizeof *cmdModeArgs; ++j) { if(strcmp(argv[i], cmdModeArgs[j]) == 0) { - useGui = false; + gui = false; break; } } } - QApplication a(argc, argv, useGui); #else - QApplication a(argc, argv); + Q_UNUSED(argc) + Q_UNUSED(argv) #endif + return gui; +} + +bool registerDocumentation(QHelpEngineCore &collection, CmdLineParser &cmd, + bool printSuccess) +{ + TRACE_OBJ + if (!collection.registerDocumentation(cmd.helpFile())) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Could not register documentation file\n%1\n\nReason:\n%2") + .arg(cmd.helpFile()).arg(collection.error()), true); + return false; + } + if (printSuccess) + cmd.showMessage(QCoreApplication::translate("Assistant", + "Documentation successfully registered."), + false); + CollectionConfiguration::updateLastRegisterTime(collection); + return true; +} + +bool unregisterDocumentation(QHelpEngineCore &collection, + const QString &namespaceName, CmdLineParser &cmd, bool printSuccess) +{ + TRACE_OBJ + if (!collection.unregisterDocumentation(namespaceName)) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Could not unregister documentation" + " file\n%1\n\nReason:\n%2"). + arg(cmd.helpFile()).arg(collection.error()), true); + return false; + } + updateLastPagesOnUnregister(collection, namespaceName); + if (printSuccess) + cmd.showMessage(QCoreApplication::translate("Assistant", + "Documentation successfully unregistered."), + false); + return true; +} + +void setupTranslation(const QString &fileName, const QString &dir) +{ + QTranslator *translator = new QTranslator(QCoreApplication::instance()); + if (translator->load(fileName, dir)) { + QCoreApplication::installTranslator(translator); + } else if (!fileName.endsWith(QLatin1String("en_US"))) { + qWarning("Could not load translation file %s in directory %s.", + qPrintable(fileName), qPrintable(dir)); + } +} + +void setupTranslations() +{ + TRACE_OBJ + const QString& locale = QLocale::system().name(); + const QString &resourceDir + = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + setupTranslation(QLatin1String("assistant_") + locale, resourceDir); + setupTranslation(QLatin1String("qt_") + locale, resourceDir); + setupTranslation(QLatin1String("qt_help_") + locale, resourceDir); +} + +} // Anonymous namespace. + +int main(int argc, char *argv[]) +{ + TRACE_OBJ + QApplication a(argc, argv, useGui(argc, argv)); a.addLibraryPath(a.applicationDirPath() + QLatin1String("/plugins")); - CmdLineParser cmd; - CmdLineParser::Result res = cmd.parse(a.arguments()); + // Parse arguments. + CmdLineParser cmd(a.arguments()); + CmdLineParser::Result res = cmd.parse(); if (res == CmdLineParser::Help) return 0; else if (res == CmdLineParser::Error) return -1; - QString cmdCollectionFile = cmd.collectionFile(); - if (cmd.registerRequest() != CmdLineParser::None) { - if (cmdCollectionFile.isEmpty()) - cmdCollectionFile = MainWindow::defaultHelpCollectionFileName(); - QHelpEngineCore help(cmdCollectionFile); - help.setupData(); - if (cmd.registerRequest() == CmdLineParser::Register) { - if (!help.registerDocumentation(cmd.helpFile())) { - cmd.showMessage( - QObject::tr("Could not register documentation file\n%1\n\nReason:\n%2") - .arg(cmd.helpFile()).arg(help.error()), true); - return -1; - } else { - cmd.showMessage(QObject::tr("Documentation successfully registered."), - false); - } - } else { - QString nsName = QHelpEngineCore::namespaceName(cmd.helpFile()); - if (help.unregisterDocumentation(nsName)) { - updateLastPagesOnUnregister(help, nsName); - cmd.showMessage( - QObject::tr("Documentation successfully unregistered."), - false); - } else { - cmd.showMessage(QObject::tr("Could not unregister documentation" - " file\n%1\n\nReason:\n%2").arg(cmd.helpFile()). - arg(help.error()), true); - return -1; - } + /* + * Create the collection objects that we need. We always have the + * cached collection file. Depending on whether the user specified + * one, we also may have an input collection file. + */ + const QString collectionFile = cmd.collectionFile(); + const bool collectionFileGiven = !collectionFile.isEmpty(); + QScopedPointer<QHelpEngineCore> collection; + if (collectionFileGiven) { + collection.reset(new QHelpEngineCore(collectionFile)); + if (!collection->setupData()) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Error reading collection file '%1': %2."). + arg(collectionFile).arg(collection->error()), true); + return EXIT_FAILURE; } - help.setCustomValue(QLatin1String("DocUpdate"), true); - return 0; } - - if (cmd.removeSearchIndex()) { - QString file = cmdCollectionFile; - if (file.isEmpty()) - file = MainWindow::defaultHelpCollectionFileName(); - QString path = QFileInfo(file).path(); - path += QLatin1Char('/') + indexFilesFolder(file); - - QLocalSocket localSocket; - localSocket.connectToServer(QString(QLatin1String("QtAssistant%1")) - .arg(QLatin1String(QT_VERSION_STR))); - - QDir dir(path); // check if there is no other instance ruinning - if (!localSocket.waitForConnected() && dir.exists()) { - QStringList lst = dir.entryList(QDir::Files | QDir::Hidden); - foreach (const QString &item, lst) - dir.remove(item); - return 0; - } else { - return -1; - } + const QString &cachedCollectionFile = collectionFileGiven + ? constructCachedCollectionFilePath(*collection) + : MainWindow::defaultHelpCollectionFileName(); + if (collectionFileGiven && !QFileInfo(cachedCollectionFile).exists() + && !collection->copyCollectionFile(cachedCollectionFile)) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Error creating collection file '%1': %2."). + arg(cachedCollectionFile).arg(collection->error()), true); + return EXIT_FAILURE; } - - { - QSqlDatabase db; - QStringList sqlDrivers(db.drivers()); - if (sqlDrivers.isEmpty() - || !sqlDrivers.contains(QLatin1String("QSQLITE"))) { - cmd.showMessage(QObject::tr("Cannot load sqlite database driver!"), - true); - return -1; - } + QHelpEngineCore cachedCollection(cachedCollectionFile); + if (!cachedCollection.setupData()) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Error reading collection file '%1': %2"). + arg(cachedCollectionFile). + arg(cachedCollection.error()), true); + return EXIT_FAILURE; } - if (!cmdCollectionFile.isEmpty()) { - QHelpEngineCore caller(cmdCollectionFile); - if (!caller.setupData()) { - cmd.showMessage(QObject::tr("The specified collection file could " - "not be read!"), true); - return -1; - } + stripNonexistingDocs(cachedCollection); + if (collectionFileGiven) { + if (CollectionConfiguration::isNewer(*collection, cachedCollection)) + CollectionConfiguration::copyConfiguration(*collection, + cachedCollection); + if (!synchronizeDocs(*collection, cachedCollection, cmd)) + return EXIT_FAILURE; + } - QString fileName = QFileInfo(cmdCollectionFile).fileName(); - QString dir = MainWindow::collectionFileDirectory(false, - caller.customValue(QLatin1String("CacheDirectory"), - QString()).toString()); - - bool collectionFileExists = true; - QFileInfo fi(dir + QDir::separator() + fileName); - if (!fi.exists()) { - collectionFileExists = false; - if (!caller.copyCollectionFile(fi.absoluteFilePath())) { - cmd.showMessage(caller.error(), true); - return -1; - } + if (cmd.registerRequest() != CmdLineParser::None) { + const QStringList &cachedDocs = + cachedCollection.registeredDocumentations(); + const QString &namespaceName = + QHelpEngineCore::namespaceName(cmd.helpFile()); + if (cmd.registerRequest() == CmdLineParser::Register) { + if (collectionFileGiven + && !registerDocumentation(*collection, cmd, true)) + return EXIT_FAILURE; + if (!cachedDocs.contains(namespaceName) + && !registerDocumentation(cachedCollection, cmd, !collectionFileGiven)) + return EXIT_FAILURE; + return EXIT_SUCCESS; } - - if (collectionFileExists) { - QHelpEngineCore user(fi.absoluteFilePath()); - if (user.setupData()) { - // some docs might have been un/registered - bool docUpdate = caller. - customValue(QLatin1String("DocUpdate"), false).toBool(); - - // update in case the passed collection file changed - if (updateUserCollection(user, caller)) - docUpdate = true; - - QStringList userDocs = user.registeredDocumentations(); - // update user collection file, docs might have been (re)moved - if (!referencedHelpFilesExistAll(user, userDocs)) - docUpdate = true; - - if (docUpdate) { - QStringList callerDocs = caller.registeredDocumentations(); - foreach (const QString &doc, callerDocs) { - if (!userDocs.contains(doc)) { - user.registerDocumentation( - caller.documentationFileName(doc)); - } - } - - QLatin1String intern("com.trolltech.com.assistantinternal-"); - foreach (const QString &doc, userDocs) { - if (!callerDocs.contains(doc) && !doc.startsWith(intern)) - user.unregisterDocumentation(doc); - } - - caller.setCustomValue(QLatin1String("DocUpdate"), false); - } - } + if (cmd.registerRequest() == CmdLineParser::Unregister) { + if (collectionFileGiven + && !unregisterDocumentation(*collection, namespaceName, cmd, true)) + return EXIT_FAILURE; + if (cachedDocs.contains(namespaceName) + && !unregisterDocumentation(cachedCollection, namespaceName, + cmd, !collectionFileGiven)) + return EXIT_FAILURE; + return EXIT_SUCCESS; } - cmd.setCollectionFile(fi.absoluteFilePath()); } - if (!cmd.currentFilter().isEmpty()) { - QString collectionFile; - if (cmdCollectionFile.isEmpty()) { - MainWindow::collectionFileDirectory(true); - cmdCollectionFile = MainWindow::defaultHelpCollectionFileName(); - } - - QHelpEngineCore user(cmdCollectionFile); - if (user.setupData()) - user.setCurrentFilter(cmd.currentFilter()); + if (cmd.removeSearchIndex()) { + return removeSearchIndex(cachedCollectionFile) + ? EXIT_SUCCESS : EXIT_FAILURE; } - const QString& locale = QLocale::system().name(); - QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); - - QTranslator translator(0); - translator.load(QLatin1String("assistant_") + locale, resourceDir); - a.installTranslator(&translator); + if (cmd.rebuildSearchIndex()) { + return rebuildSearchIndex(a, cachedCollectionFile, cmd) + ? EXIT_SUCCESS : EXIT_FAILURE; + } - QTranslator qtTranslator(0); - qtTranslator.load(QLatin1String("qt_") + locale, resourceDir); - a.installTranslator(&qtTranslator); + if (!QSqlDatabase::isDriverAvailable(QLatin1String("QSQLITE"))) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Cannot load sqlite database driver!"), + true); + return EXIT_FAILURE; + } - QTranslator qtHelpTranslator(0); - qtHelpTranslator.load(QLatin1String("qt_help_") + locale, resourceDir); - a.installTranslator(&qtHelpTranslator); + if (!cmd.currentFilter().isEmpty()) { + if (collectionFileGiven) + collection->setCurrentFilter(cmd.currentFilter()); + cachedCollection.setCurrentFilter(cmd.currentFilter()); + } - MainWindow w(&cmd); - w.show(); + setupTranslations(); + + /* + * We need to be careful here: The main window has to be deleted before + * the help engine wrapper, which has to be deleted before the + * QApplication. + */ + if (collectionFileGiven) + cmd.setCollectionFile(cachedCollectionFile); + MainWindow *w = new MainWindow(&cmd); + w->show(); a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); - return a.exec(); + const int retval = a.exec(); + delete w; + HelpEngineWrapper::removeInstance(); + return retval; } diff --git a/tools/assistant/tools/assistant/mainwindow.cpp b/tools/assistant/tools/assistant/mainwindow.cpp index 0dbf813..913e342 100644 --- a/tools/assistant/tools/assistant/mainwindow.cpp +++ b/tools/assistant/tools/assistant/mainwindow.cpp @@ -38,24 +38,31 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "tracer.h" #include "mainwindow.h" + +#include "bookmarkmanager.h" #include "centralwidget.h" -#include "helpviewer.h" #include "indexwindow.h" #include "topicchooser.h" #include "contentwindow.h" #include "preferencesdialog.h" -#include "bookmarkmanager.h" +#include "helpenginewrapper.h" #include "remotecontrol.h" #include "cmdlineparser.h" #include "aboutdialog.h" #include "searchwidget.h" #include "qtdocinstaller.h" +// #define TRACING_REQUESTED + #include <QtCore/QDir> #include <QtCore/QTimer> +#include <QtCore/QDateTime> #include <QtCore/QDebug> +#include <QtCore/QFileSystemWatcher> +#include <QtCore/QPair> #include <QtCore/QResource> #include <QtCore/QByteArray> #include <QtCore/QTextStream> @@ -76,8 +83,9 @@ #include <QtGui/QProgressBar> #include <QtGui/QDesktopServices> #include <QtGui/QToolButton> +#include <QtGui/QFileDialog> -#include <QtHelp/QHelpEngine> +#include <QtHelp/QHelpEngineCore> #include <QtHelp/QHelpSearchEngine> #include <QtHelp/QHelpContentModel> #include <QtHelp/QHelpIndexModel> @@ -86,6 +94,7 @@ QT_BEGIN_NAMESPACE MainWindow::MainWindow(CmdLineParser *cmdLine, QWidget *parent) : QMainWindow(parent) + , m_bookmarkWidget(0) , m_filterCombo(0) , m_toolBarMenu(0) , m_cmdLine(cmdLine) @@ -93,37 +102,53 @@ MainWindow::MainWindow(CmdLineParser *cmdLine, QWidget *parent) , m_qtDocInstaller(0) , m_connectedInitSignals(false) { + TRACE_OBJ + setToolButtonStyle(Qt::ToolButtonFollowStyle); + QString collectionFile; if (usesDefaultCollection()) { MainWindow::collectionFileDirectory(true); - m_helpEngine = new QHelpEngine(MainWindow::defaultHelpCollectionFileName(), - this); + collectionFile = MainWindow::defaultHelpCollectionFileName(); } else { - m_helpEngine = new QHelpEngine(cmdLine->collectionFile(), this); + collectionFile = cmdLine->collectionFile(); } + HelpEngineWrapper &helpEngineWrapper = + HelpEngineWrapper::instance(collectionFile); - m_centralWidget = new CentralWidget(m_helpEngine, this); + m_centralWidget = new CentralWidget(this); setCentralWidget(m_centralWidget); - m_indexWindow = new IndexWindow(m_helpEngine); + m_indexWindow = new IndexWindow(this); QDockWidget *indexDock = new QDockWidget(tr("Index"), this); indexDock->setObjectName(QLatin1String("IndexWindow")); indexDock->setWidget(m_indexWindow); addDockWidget(Qt::LeftDockWidgetArea, indexDock); - m_contentWindow = new ContentWindow(m_helpEngine); + m_contentWindow = new ContentWindow; QDockWidget *contentDock = new QDockWidget(tr("Contents"), this); contentDock->setObjectName(QLatin1String("ContentWindow")); contentDock->setWidget(m_contentWindow); addDockWidget(Qt::LeftDockWidgetArea, contentDock); - QDockWidget *bookmarkDock = new QDockWidget(tr("Bookmarks"), this); - bookmarkDock->setObjectName(QLatin1String("BookmarkWindow")); - bookmarkDock->setWidget(setupBookmarkWidget()); - addDockWidget(Qt::LeftDockWidgetArea, bookmarkDock); + QDockWidget *bookmarkDock = 0; + if (BookmarkManager *manager = BookmarkManager::instance()) { + bookmarkDock = new QDockWidget(tr("Bookmarks"), this); + bookmarkDock->setObjectName(QLatin1String("BookmarkWindow")); + bookmarkDock->setWidget(m_bookmarkWidget = manager->bookmarkDockWidget()); + addDockWidget(Qt::LeftDockWidgetArea, bookmarkDock); + + connect(manager, SIGNAL(escapePressed()), this, + SLOT(activateCurrentCentralWidgetTab())); + connect(manager, SIGNAL(setSource(QUrl)), m_centralWidget, + SLOT(setSource(QUrl))); + connect(manager, SIGNAL(setSourceInNewTab(QUrl)), m_centralWidget, + SLOT(setSourceInNewTab(QUrl))); + connect(m_centralWidget, SIGNAL(addBookmark(QString, QString)), manager, + SLOT(addBookmark(QString, QString))); + } - QHelpSearchEngine *searchEngine = m_helpEngine->searchEngine(); + QHelpSearchEngine *searchEngine = helpEngineWrapper.searchEngine(); connect(searchEngine, SIGNAL(indexingStarted()), this, SLOT(indexingStarted())); connect(searchEngine, SIGNAL(indexingFinished()), this, SLOT(indexingFinished())); @@ -140,18 +165,9 @@ MainWindow::MainWindow(CmdLineParser *cmdLine, QWidget *parent) setupFilterToolbar(); setupAddressToolbar(); - m_bookmarkManager->setupBookmarkModels(); - m_bookmarkMenu->addSeparator(); - m_bookmarkManager->fillBookmarkMenu(m_bookmarkMenu); - connect(m_bookmarkMenu, SIGNAL(triggered(QAction*)), this, - SLOT(showBookmark(QAction*))); - connect(m_bookmarkManager, SIGNAL(bookmarksChanged()), this, - SLOT(updateBookmarkMenu())); - - setWindowTitle(m_helpEngine->customValue(QLatin1String("WindowTitle"), - defWindowTitle).toString()); - QByteArray iconArray = m_helpEngine->customValue(QLatin1String("ApplicationIcon"), - QByteArray()).toByteArray(); + const QString windowTitle = helpEngineWrapper.windowTitle(); + setWindowTitle(windowTitle.isEmpty() ? defWindowTitle : windowTitle); + QByteArray iconArray = helpEngineWrapper.applicationIcon(); if (iconArray.size() > 0) { QPixmap pix; pix.loadFromData(iconArray); @@ -165,29 +181,28 @@ MainWindow::MainWindow(CmdLineParser *cmdLine, QWidget *parent) // Show the widget here, otherwise the restore geometry and state won't work // on x11. show(); - QByteArray ba(m_helpEngine->customValue(QLatin1String("MainWindow")).toByteArray()); + QByteArray ba(helpEngineWrapper.mainWindow()); if (!ba.isEmpty()) restoreState(ba); - ba = m_helpEngine->customValue(QLatin1String("MainWindowGeometry")).toByteArray(); + ba = helpEngineWrapper.mainWindowGeometry(); if (!ba.isEmpty()) { restoreGeometry(ba); } else { tabifyDockWidget(contentDock, indexDock); - tabifyDockWidget(indexDock, bookmarkDock); + if (bookmarkDock) + tabifyDockWidget(indexDock, bookmarkDock); contentDock->raise(); resize(QSize(800, 600)); } - if (!m_helpEngine->customValue(QLatin1String("useAppFont")).isValid()) { - m_helpEngine->setCustomValue(QLatin1String("useAppFont"), false); - m_helpEngine->setCustomValue(QLatin1String("useBrowserFont"), false); - m_helpEngine->setCustomValue(QLatin1String("appFont"), qApp->font()); - m_helpEngine->setCustomValue(QLatin1String("appWritingSystem"), - QFontDatabase::Latin); - m_helpEngine->setCustomValue(QLatin1String("browserFont"), qApp->font()); - m_helpEngine->setCustomValue(QLatin1String("browserWritingSystem"), - QFontDatabase::Latin); + if (!helpEngineWrapper.hasFontSettings()) { + helpEngineWrapper.setUseAppFont(false); + helpEngineWrapper.setUseBrowserFont(false); + helpEngineWrapper.setAppFont(qApp->font()); + helpEngineWrapper.setAppWritingSystem(QFontDatabase::Latin); + helpEngineWrapper.setBrowserFont(qApp->font()); + helpEngineWrapper.setBrowserWritingSystem(QFontDatabase::Latin); } else { updateApplicationFont(); } @@ -196,7 +211,7 @@ MainWindow::MainWindow(CmdLineParser *cmdLine, QWidget *parent) QTimer::singleShot(0, this, SLOT(insertLastPages())); if (m_cmdLine->enableRemoteControl()) - (void)new RemoteControl(this, m_helpEngine); + (void)new RemoteControl(this); if (m_cmdLine->contents() == CmdLineParser::Show) showContents(); @@ -209,9 +224,9 @@ MainWindow::MainWindow(CmdLineParser *cmdLine, QWidget *parent) hideIndex(); if (m_cmdLine->bookmarks() == CmdLineParser::Show) - showBookmarks(); + showBookmarksDockWidget(); else if (m_cmdLine->bookmarks() == CmdLineParser::Hide) - hideBookmarks(); + hideBookmarksDockWidget(); if (m_cmdLine->search() == CmdLineParser::Show) showSearch(); @@ -223,51 +238,59 @@ MainWindow::MainWindow(CmdLineParser *cmdLine, QWidget *parent) else if (m_cmdLine->index() == CmdLineParser::Activate) showIndex(); else if (m_cmdLine->bookmarks() == CmdLineParser::Activate) - showBookmarks(); + showBookmarksDockWidget(); if (!m_cmdLine->currentFilter().isEmpty()) { const QString &curFilter = m_cmdLine->currentFilter(); - if (m_helpEngine->customFilters().contains(curFilter)) - m_helpEngine->setCurrentFilter(curFilter); + if (helpEngineWrapper.customFilters().contains(curFilter)) + helpEngineWrapper.setCurrentFilter(curFilter); } if (usesDefaultCollection()) QTimer::singleShot(0, this, SLOT(lookForNewQtDocumentation())); else checkInitState(); + + connect(&helpEngineWrapper, SIGNAL(documentationRemoved(QString)), + this, SLOT(documentationRemoved(QString))); + connect(&helpEngineWrapper, SIGNAL(documentationUpdated(QString)), + this, SLOT(documentationUpdated(QString))); } setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); } MainWindow::~MainWindow() { + TRACE_OBJ if (m_qtDocInstaller) delete m_qtDocInstaller; } bool MainWindow::usesDefaultCollection() const { + TRACE_OBJ return m_cmdLine->collectionFile().isEmpty(); } void MainWindow::closeEvent(QCloseEvent *e) { - m_bookmarkManager->saveBookmarks(); - m_helpEngine->setCustomValue(QLatin1String("MainWindow"), saveState()); - m_helpEngine->setCustomValue(QLatin1String("MainWindowGeometry"), - saveGeometry()); - + TRACE_OBJ + BookmarkManager::destroy(); + HelpEngineWrapper::instance().setMainWindow(saveState()); + HelpEngineWrapper::instance().setMainWindowGeometry(saveGeometry()); QMainWindow::closeEvent(e); } bool MainWindow::initHelpDB() { - if (!m_helpEngine->setupData()) + TRACE_OBJ + HelpEngineWrapper &helpEngineWrapper = HelpEngineWrapper::instance(); + if (!helpEngineWrapper.setupData()) return false; bool assistantInternalDocRegistered = false; QString intern(QLatin1String("com.trolltech.com.assistantinternal-")); - foreach (const QString &ns, m_helpEngine->registeredDocumentations()) { + foreach (const QString &ns, helpEngineWrapper.registeredDocumentations()) { if (ns.startsWith(intern)) { intern = ns; assistantInternalDocRegistered = true; @@ -275,8 +298,7 @@ bool MainWindow::initHelpDB() } } - const QString &collectionFile = m_helpEngine->collectionFile(); - + const QString &collectionFile = helpEngineWrapper.collectionFile(); QFileInfo fi(collectionFile); QString helpFile; QTextStream(&helpFile) << fi.absolutePath() << QDir::separator() @@ -293,109 +315,78 @@ bool MainWindow::initHelpDB() file.close(); } - QHelpEngineCore hc(fi.absoluteFilePath()); - hc.setupData(); - hc.unregisterDocumentation(intern); - hc.registerDocumentation(helpFile); - needsSetup = true; - } - - const QLatin1String unfiltered("UnfilteredFilterInserted"); - if (1 != m_helpEngine->customValue(unfiltered).toInt()) { - { - QHelpEngineCore hc(collectionFile); - hc.setupData(); - hc.addCustomFilter(tr("Unfiltered"), QStringList()); - hc.setCustomValue(unfiltered, 1); - } - - m_helpEngine->blockSignals(true); - m_helpEngine->setCurrentFilter(tr("Unfiltered")); - m_helpEngine->blockSignals(false); + helpEngineWrapper.unregisterDocumentation(intern); + helpEngineWrapper.registerDocumentation(helpFile); needsSetup = true; } if (needsSetup) - m_helpEngine->setupData(); + helpEngineWrapper.setupData(); return true; } void MainWindow::lookForNewQtDocumentation() { - m_qtDocInstaller = new QtDocInstaller(m_helpEngine->collectionFile()); - connect(m_qtDocInstaller, SIGNAL(errorMessage(QString)), this, - SLOT(displayInstallationError(QString))); + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + QStringList docs; + docs << QLatin1String("assistant") + << QLatin1String("designer") + << QLatin1String("linguist") + << QLatin1String("qmake") + << QLatin1String("qt"); + QList<QtDocInstaller::DocInfo> qtDocInfos; + foreach (const QString &doc, docs) + qtDocInfos.append(QtDocInstaller::DocInfo(doc, helpEngine.qtDocInfo(doc))); + + m_qtDocInstaller = new QtDocInstaller(qtDocInfos); connect(m_qtDocInstaller, SIGNAL(docsInstalled(bool)), this, - SLOT(qtDocumentationInstalled(bool))); - - QString versionKey = QString(QLatin1String("qtVersion%1$$$qt")). - arg(QLatin1String(QT_VERSION_STR)); - if (m_helpEngine->customValue(versionKey, 0).toInt() != 1) + SLOT(qtDocumentationInstalled())); + connect(m_qtDocInstaller, SIGNAL(qchFileNotFound(QString)), this, + SLOT(resetQtDocInfo(QString))); + connect(m_qtDocInstaller, SIGNAL(registerDocumentation(QString, QString)), + this, SLOT(registerDocumentation(QString, QString))); + if (helpEngine.qtDocInfo(QLatin1String("qt")).count() != 2) statusBar()->showMessage(tr("Looking for Qt Documentation...")); m_qtDocInstaller->installDocs(); } -void MainWindow::displayInstallationError(const QString &errorMessage) +void MainWindow::qtDocumentationInstalled() { - QMessageBox::warning(this, tr("Qt Assistant"), errorMessage); -} - -void MainWindow::qtDocumentationInstalled(bool newDocsInstalled) -{ - if (newDocsInstalled) - m_helpEngine->setupData(); + TRACE_OBJ statusBar()->clearMessage(); checkInitState(); } void MainWindow::checkInitState() { + TRACE_OBJ + HelpEngineWrapper::instance().initialDocSetupDone(); if (!m_cmdLine->enableRemoteControl()) return; - if (m_helpEngine->contentModel()->isCreatingContents() - || m_helpEngine->indexModel()->isCreatingIndex()) { + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + if (helpEngine.contentModel()->isCreatingContents() + || helpEngine.indexModel()->isCreatingIndex()) { if (!m_connectedInitSignals) { - connect(m_helpEngine->contentModel(), SIGNAL(contentsCreated()), + connect(helpEngine.contentModel(), SIGNAL(contentsCreated()), this, SLOT(checkInitState())); - connect(m_helpEngine->indexModel(), SIGNAL(indexCreated()), this, + connect(helpEngine.indexModel(), SIGNAL(indexCreated()), this, SLOT(checkInitState())); m_connectedInitSignals = true; } } else { if (m_connectedInitSignals) { - disconnect(m_helpEngine->contentModel(), 0, this, 0); - disconnect(m_helpEngine->indexModel(), 0, this, 0); + disconnect(helpEngine.contentModel(), 0, this, 0); + disconnect(helpEngine.indexModel(), 0, this, 0); } emit initDone(); } } -void MainWindow::updateBookmarkMenu() -{ - if (m_bookmarkManager) { - m_bookmarkMenu->removeAction(m_bookmarkMenuAction); - - m_bookmarkMenu->clear(); - - m_bookmarkMenu->addAction(m_bookmarkMenuAction); - m_bookmarkMenu->addSeparator(); - - m_bookmarkManager->fillBookmarkMenu(m_bookmarkMenu); - } -} - -void MainWindow::showBookmark(QAction *action) -{ - if (m_bookmarkManager) { - const QUrl &url = m_bookmarkManager->urlForAction(action); - if (url.isValid()) - m_centralWidget->setSource(url); - } -} - void MainWindow::insertLastPages() { + TRACE_OBJ if (m_cmdLine->url().isValid()) m_centralWidget->setSource(m_cmdLine->url()); else @@ -407,6 +398,7 @@ void MainWindow::insertLastPages() void MainWindow::setupActions() { + TRACE_OBJ QString resourcePath = QLatin1String(":/trolltech/assistant/images/"); #ifdef Q_OS_MAC setUnifiedTitleAndToolBarOnMac(true); @@ -417,6 +409,11 @@ void MainWindow::setupActions() QMenu *menu = menuBar()->addMenu(tr("&File")); + m_newTabAction = menu->addAction(tr("New &Tab"), m_centralWidget, SLOT(newTab())); + m_newTabAction->setShortcut(QKeySequence::AddTab); + + menu->addSeparator(); + m_pageSetupAction = menu->addAction(tr("Page Set&up..."), m_centralWidget, SLOT(pageSetup())); m_printPreviewAction = menu->addAction(tr("Print Preview..."), m_centralWidget, @@ -429,16 +426,18 @@ void MainWindow::setupActions() menu->addSeparator(); - m_newTabAction = menu->addAction(tr("New &Tab"), m_centralWidget, SLOT(newTab())); - m_newTabAction->setShortcut(QKeySequence::AddTab); - m_closeTabAction = menu->addAction(tr("&Close Tab"), m_centralWidget, SLOT(closeTab())); m_closeTabAction->setShortcuts(QKeySequence::Close); - QAction *tmp = menu->addAction(tr("&Quit"), this, SLOT(close())); - tmp->setShortcut(QKeySequence::Quit); + QAction *tmp = menu->addAction(QIcon::fromTheme("application-exit"), + tr("&Quit"), this, SLOT(close())); tmp->setMenuRole(QAction::QuitRole); +#ifdef Q_OS_WIN + tmp->setShortcut(QKeySequence(tr("CTRL+Q"))); +#else + tmp->setShortcut(QKeySequence::Quit); +#endif menu = menuBar()->addMenu(tr("&Edit")); m_copyAction = menu->addAction(tr("&Copy selected Text"), m_centralWidget, @@ -492,7 +491,7 @@ void MainWindow::setupActions() QKeySequence(tr("ALT+C"))); m_viewMenu->addAction(tr("Index"), this, SLOT(showIndex()), QKeySequence(tr("ALT+I"))); - m_viewMenu->addAction(tr("Bookmarks"), this, SLOT(showBookmarks()), + m_viewMenu->addAction(tr("Bookmarks"), this, SLOT(showBookmarksDockWidget()), QKeySequence(tr("ALT+O"))); m_viewMenu->addAction(tr("Search"), this, SLOT(showSearchWidget()), QKeySequence(tr("ALT+S"))); @@ -528,16 +527,16 @@ void MainWindow::setupActions() tmp->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Alt+Left")) << QKeySequence(Qt::CTRL + Qt::Key_PageUp)); - m_bookmarkMenu = menuBar()->addMenu(tr("&Bookmarks")); - m_bookmarkMenuAction = m_bookmarkMenu->addAction(tr("Add Bookmark..."), - this, SLOT(addBookmark())); - m_bookmarkMenuAction->setShortcut(tr("CTRL+D")); + if (BookmarkManager *manager = BookmarkManager::instance()) + manager->takeBookmarksMenu(menuBar()->addMenu(tr("&Bookmarks"))); menu = menuBar()->addMenu(tr("&Help")); m_aboutAction = menu->addAction(tr("About..."), this, SLOT(showAboutDialog())); m_aboutAction->setMenuRole(QAction::AboutRole); #ifdef Q_WS_X11 + m_newTabAction->setIcon(QIcon::fromTheme("tab-new", m_newTabAction->icon())); + m_closeTabAction->setIcon(QIcon::fromTheme("window-close", m_closeTabAction->icon())); m_backAction->setIcon(QIcon::fromTheme("go-previous" , m_backAction->icon())); m_nextAction->setIcon(QIcon::fromTheme("go-next" , m_nextAction->icon())); m_zoomInAction->setIcon(QIcon::fromTheme("zoom-in" , m_zoomInAction->icon())); @@ -547,7 +546,10 @@ void MainWindow::setupActions() m_copyAction->setIcon(QIcon::fromTheme("edit-copy" , m_copyAction->icon())); m_findAction->setIcon(QIcon::fromTheme("edit-find" , m_findAction->icon())); m_homeAction->setIcon(QIcon::fromTheme("go-home" , m_homeAction->icon())); + m_pageSetupAction->setIcon(QIcon::fromTheme("document-page-setup", m_pageSetupAction->icon())); + m_printPreviewAction->setIcon(QIcon::fromTheme("document-print-preview", m_printPreviewAction->icon())); m_printAction->setIcon(QIcon::fromTheme("document-print" , m_printAction->icon())); + m_aboutAction->setIcon(QIcon::fromTheme("help-about", m_aboutAction->icon())); #endif QToolBar *navigationBar = addToolBar(tr("Navigation Toolbar")); @@ -592,14 +594,6 @@ void MainWindow::setupActions() SLOT(updateNavigationItems())); connect(m_centralWidget, SIGNAL(highlighted(QString)), statusBar(), SLOT(showMessage(QString))); - connect(m_centralWidget, SIGNAL(addNewBookmark(QString,QString)), this, - SLOT(addNewBookmark(QString,QString))); - - // bookmarks - connect(m_bookmarkWidget, SIGNAL(requestShowLink(QUrl)), m_centralWidget, - SLOT(setSource(QUrl))); - connect(m_bookmarkWidget, SIGNAL(escapePressed()), this, - SLOT(activateCurrentCentralWidgetTab())); // index window connect(m_indexWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget, @@ -624,6 +618,7 @@ void MainWindow::setupActions() QMenu *MainWindow::toolBarMenu() { + TRACE_OBJ if (!m_toolBarMenu) { m_viewMenu->addSeparator(); m_toolBarMenu = m_viewMenu->addMenu(tr("Toolbars")); @@ -633,8 +628,9 @@ QMenu *MainWindow::toolBarMenu() void MainWindow::setupFilterToolbar() { - if (!m_helpEngine-> - customValue(QLatin1String("EnableFilterFunctionality"), true).toBool()) + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + if (!helpEngine.filterFunctionalityEnabled()) return; m_filterCombo = new QComboBox(this); @@ -647,16 +643,15 @@ void MainWindow::setupFilterToolbar() this)); filterToolBar->addWidget(m_filterCombo); - const QLatin1String hideFilter("HideFilterFunctionality"); - if (m_helpEngine->customValue(hideFilter, true).toBool()) + if (!helpEngine.filterToolbarVisible()) filterToolBar->hide(); toolBarMenu()->addAction(filterToolBar->toggleViewAction()); - connect(m_helpEngine, SIGNAL(setupFinished()), this, - SLOT(setupFilterCombo())); + connect(&helpEngine, SIGNAL(setupFinished()), this, + SLOT(setupFilterCombo()), Qt::QueuedConnection); connect(m_filterCombo, SIGNAL(activated(QString)), this, SLOT(filterDocumentation(QString))); - connect(m_helpEngine, SIGNAL(currentFilterChanged(QString)), this, + connect(&helpEngine, SIGNAL(currentFilterChanged(QString)), this, SLOT(currentFilterChanged(QString))); setupFilterCombo(); @@ -664,7 +659,9 @@ void MainWindow::setupFilterToolbar() void MainWindow::setupAddressToolbar() { - if (!m_helpEngine->customValue(QLatin1String("EnableAddressBar"), true).toBool()) + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + if (!helpEngine.addressBarEnabled()) return; m_addressLineEdit = new QLineEdit(this); @@ -676,7 +673,7 @@ void MainWindow::setupAddressToolbar() this)); addressToolBar->addWidget(m_addressLineEdit); - if (m_helpEngine->customValue(QLatin1String("HideAddressBar"), true).toBool()) + if (!helpEngine.addressBarVisible()) addressToolBar->hide(); toolBarMenu()->addAction(addressToolBar->toggleViewAction()); @@ -691,57 +688,53 @@ void MainWindow::setupAddressToolbar() void MainWindow::updateAboutMenuText() { - if (m_helpEngine) { - QByteArray ba = m_helpEngine->customValue(QLatin1String("AboutMenuTexts"), - QByteArray()).toByteArray(); - if (ba.size() > 0) { - QString lang; - QString str; - QString trStr; - QString currentLang = QLocale::system().name(); - int i = currentLang.indexOf(QLatin1Char('_')); - if (i > -1) - currentLang = currentLang.left(i); - QDataStream s(&ba, QIODevice::ReadOnly); - while (!s.atEnd()) { - s >> lang; - s >> str; - if (lang == QLatin1String("default") && trStr.isEmpty()) { - trStr = str; - } else if (lang == currentLang) { - trStr = str; - break; - } + TRACE_OBJ + QByteArray ba = HelpEngineWrapper::instance().aboutMenuTexts(); + if (ba.size() > 0) { + QString lang; + QString str; + QString trStr; + QString currentLang = QLocale::system().name(); + int i = currentLang.indexOf(QLatin1Char('_')); + if (i > -1) + currentLang = currentLang.left(i); + QDataStream s(&ba, QIODevice::ReadOnly); + while (!s.atEnd()) { + s >> lang; + s >> str; + if (lang == QLatin1String("default") && trStr.isEmpty()) { + trStr = str; + } else if (lang == currentLang) { + trStr = str; + break; } - if (!trStr.isEmpty()) - m_aboutAction->setText(trStr); } + if (!trStr.isEmpty()) + m_aboutAction->setText(trStr); } } void MainWindow::showNewAddress() { + TRACE_OBJ showNewAddress(m_centralWidget->currentSource()); } void MainWindow::showNewAddress(const QUrl &url) { + TRACE_OBJ m_addressLineEdit->setText(url.toString()); } -void MainWindow::addBookmark() -{ - addNewBookmark(m_centralWidget->currentTitle(), - m_centralWidget->currentSource().toString()); -} - void MainWindow::gotoAddress() { + TRACE_OBJ m_centralWidget->setSource(m_addressLineEdit->text()); } void MainWindow::updateNavigationItems() { + TRACE_OBJ bool hasCurrentViewer = m_centralWidget->isHomeAvailable(); m_copyAction->setEnabled(m_centralWidget->hasSelection()); m_homeAction->setEnabled(hasCurrentViewer); @@ -755,12 +748,14 @@ void MainWindow::updateNavigationItems() void MainWindow::updateTabCloseAction() { + TRACE_OBJ m_closeTabAction->setEnabled(m_centralWidget->enableTabCloseAction()); } void MainWindow::showTopicChooser(const QMap<QString, QUrl> &links, const QString &keyword) { + TRACE_OBJ TopicChooser tc(this, keyword, links); if (tc.exec() == QDialog::Accepted) { m_centralWidget->setSource(tc.link()); @@ -769,18 +764,18 @@ void MainWindow::showTopicChooser(const QMap<QString, QUrl> &links, void MainWindow::showPreferences() { - PreferencesDialog dia(m_helpEngine, this); - + TRACE_OBJ + PreferencesDialog dia(this); connect(&dia, SIGNAL(updateApplicationFont()), this, SLOT(updateApplicationFont())); connect(&dia, SIGNAL(updateBrowserFont()), m_centralWidget, SLOT(updateBrowserFont())); - dia.showDialog(); } void MainWindow::syncContents() { + TRACE_OBJ qApp->setOverrideCursor(QCursor(Qt::WaitCursor)); const QUrl url = m_centralWidget->currentSource(); showContents(); @@ -792,40 +787,32 @@ void MainWindow::syncContents() void MainWindow::copyAvailable(bool yes) { + TRACE_OBJ m_copyAction->setEnabled(yes); } -void MainWindow::addNewBookmark(const QString &title, const QString &url) -{ - if (url.isEmpty() || url == QLatin1String("about:blank")) - return; - - m_bookmarkManager->showBookmarkDialog(this, title, url); -} - void MainWindow::showAboutDialog() { + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); QByteArray contents; - if (m_helpEngine) { - QByteArray ba = m_helpEngine->customValue(QLatin1String("AboutTexts"), - QByteArray()).toByteArray(); - if (!ba.isEmpty()) { - QString lang; - QByteArray cba; - QString currentLang = QLocale::system().name(); - int i = currentLang.indexOf(QLatin1Char('_')); - if (i > -1) - currentLang = currentLang.left(i); - QDataStream s(&ba, QIODevice::ReadOnly); - while (!s.atEnd()) { - s >> lang; - s >> cba; - if (lang == QLatin1String("default") && contents.isEmpty()) { - contents = cba; - } else if (lang == currentLang) { - contents = cba; - break; - } + QByteArray ba = helpEngine.aboutTexts(); + if (!ba.isEmpty()) { + QString lang; + QByteArray cba; + QString currentLang = QLocale::system().name(); + int i = currentLang.indexOf(QLatin1Char('_')); + if (i > -1) + currentLang = currentLang.left(i); + QDataStream s(&ba, QIODevice::ReadOnly); + while (!s.atEnd()) { + s >> lang; + s >> cba; + if (lang == QLatin1String("default") && contents.isEmpty()) { + contents = cba; + } else if (lang == currentLang) { + contents = cba; + break; } } } @@ -834,11 +821,8 @@ void MainWindow::showAboutDialog() QByteArray iconArray; if (!contents.isEmpty()) { - iconArray = m_helpEngine->customValue(QLatin1String("AboutIcon"), - QByteArray()).toByteArray(); - QByteArray resources = - m_helpEngine->customValue(QLatin1String("AboutImages"), - QByteArray()).toByteArray(); + iconArray = helpEngine.aboutIcon(); + QByteArray resources = helpEngine.aboutImages(); QPixmap pix; pix.loadFromData(iconArray); aboutDia.setText(QString::fromUtf8(contents), resources); @@ -861,50 +845,109 @@ void MainWindow::showAboutDialog() aboutDia.exec(); } +void MainWindow::setContentsVisible(bool visible) +{ + TRACE_OBJ + if (visible) + showContents(); + else + hideContents(); +} + void MainWindow::showContents() { + TRACE_OBJ activateDockWidget(m_contentWindow); } +void MainWindow::hideContents() +{ + TRACE_OBJ + m_contentWindow->parentWidget()->hide(); +} + +void MainWindow::setIndexVisible(bool visible) +{ + TRACE_OBJ + if (visible) + showIndex(); + else + hideIndex(); +} + void MainWindow::showIndex() { + TRACE_OBJ activateDockWidget(m_indexWindow); } -void MainWindow::showBookmarks() +void MainWindow::hideIndex() { - activateDockWidget(m_bookmarkWidget); + TRACE_OBJ + m_indexWindow->parentWidget()->hide(); } -void MainWindow::activateDockWidget(QWidget *w) +void MainWindow::setBookmarksVisible(bool visible) { - w->parentWidget()->show(); - w->parentWidget()->raise(); - w->setFocus(); + TRACE_OBJ + if (visible) + showBookmarksDockWidget(); + else + hideBookmarksDockWidget(); } -void MainWindow::hideContents() +void MainWindow::showBookmarksDockWidget() { - m_contentWindow->parentWidget()->hide(); + TRACE_OBJ + if (m_bookmarkWidget) + activateDockWidget(m_bookmarkWidget); } -void MainWindow::hideIndex() +void MainWindow::hideBookmarksDockWidget() { - m_indexWindow->parentWidget()->hide(); + TRACE_OBJ + if (m_bookmarkWidget) + m_bookmarkWidget->parentWidget()->hide(); } -void MainWindow::hideBookmarks() +void MainWindow::setSearchVisible(bool visible) { - m_bookmarkWidget->parentWidget()->hide(); + TRACE_OBJ + if (visible) + showSearch(); + else + hideSearch(); +} + +void MainWindow::showSearch() +{ + TRACE_OBJ + m_centralWidget->activateSearchWidget(); +} + +void MainWindow::hideSearch() +{ + TRACE_OBJ + m_centralWidget->removeSearchWidget(); +} + +void MainWindow::activateDockWidget(QWidget *w) +{ + TRACE_OBJ + w->parentWidget()->show(); + w->parentWidget()->raise(); + w->setFocus(); } void MainWindow::setIndexString(const QString &str) { + TRACE_OBJ m_indexWindow->setSearchLineEditText(str); } void MainWindow::activateCurrentBrowser() { + TRACE_OBJ CentralWidget *cw = CentralWidget::instance(); if (cw) { cw->activateTab(true); @@ -913,40 +956,38 @@ void MainWindow::activateCurrentBrowser() void MainWindow::activateCurrentCentralWidgetTab() { + TRACE_OBJ m_centralWidget->activateTab(); } -void MainWindow::showSearch() -{ - m_centralWidget->activateSearchWidget(); -} - void MainWindow::showSearchWidget() { + TRACE_OBJ m_centralWidget->activateSearchWidget(true); } -void MainWindow::hideSearch() -{ - m_centralWidget->removeSearchWidget(); -} - void MainWindow::updateApplicationFont() { + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); QFont font = qApp->font(); - if (m_helpEngine->customValue(QLatin1String("useAppFont")).toBool()) - font = qVariantValue<QFont>(m_helpEngine->customValue(QLatin1String("appFont"))); + if (helpEngine.usesAppFont()) + font = helpEngine.appFont(); - qApp->setFont(font, "QWidget"); + const QWidgetList &widgets = qApp->allWidgets(); + foreach (QWidget* widget, widgets) + widget->setFont(font); } void MainWindow::setupFilterCombo() { + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); QString curFilter = m_filterCombo->currentText(); if (curFilter.isEmpty()) - curFilter = m_helpEngine->currentFilter(); + curFilter = helpEngine.currentFilter(); m_filterCombo->clear(); - m_filterCombo->addItems(m_helpEngine->customFilters()); + m_filterCombo->addItems(helpEngine.customFilters()); int idx = m_filterCombo->findText(curFilter); if (idx < 0) idx = 0; @@ -955,16 +996,20 @@ void MainWindow::setupFilterCombo() void MainWindow::filterDocumentation(const QString &customFilter) { - m_helpEngine->setCurrentFilter(customFilter); + TRACE_OBJ + HelpEngineWrapper::instance().setCurrentFilter(customFilter); } void MainWindow::expandTOC(int depth) { + TRACE_OBJ + Q_ASSERT(depth >= -1); m_contentWindow->expandToDepth(depth); } void MainWindow::indexingStarted() { + TRACE_OBJ if (!m_progressWidget) { m_progressWidget = new QWidget(); QLayout* hlayout = new QHBoxLayout(m_progressWidget); @@ -990,21 +1035,15 @@ void MainWindow::indexingStarted() void MainWindow::indexingFinished() { + TRACE_OBJ statusBar()->removeWidget(m_progressWidget); delete m_progressWidget; m_progressWidget = 0; } -QWidget* MainWindow::setupBookmarkWidget() -{ - m_bookmarkManager = new BookmarkManager(m_helpEngine); - m_bookmarkWidget = new BookmarkWidget(m_bookmarkManager, this); - connect(m_bookmarkWidget, SIGNAL(addBookmark()), this, SLOT(addBookmark())); - return m_bookmarkWidget; -} - QString MainWindow::collectionFileDirectory(bool createDir, const QString &cacheDir) { + TRACE_OBJ QString collectionPath = QDesktopServices::storageLocation(QDesktopServices::DataLocation); if (collectionPath.isEmpty()) { @@ -1030,16 +1069,65 @@ QString MainWindow::collectionFileDirectory(bool createDir, const QString &cache QString MainWindow::defaultHelpCollectionFileName() { - return collectionFileDirectory() + QDir::separator() + + TRACE_OBJ + // forces creation of the default collection file path + return collectionFileDirectory(true) + QDir::separator() + QString(QLatin1String("qthelpcollection_%1.qhc")). arg(QLatin1String(QT_VERSION_STR)); } void MainWindow::currentFilterChanged(const QString &filter) { + TRACE_OBJ const int index = m_filterCombo->findText(filter); Q_ASSERT(index != -1); m_filterCombo->setCurrentIndex(index); } +void MainWindow::documentationRemoved(const QString &namespaceName) +{ + TRACE_OBJ + CentralWidget* widget = CentralWidget::instance(); + widget->closeOrReloadTabs(widget->currentSourceFileList(). + keys(namespaceName), false); +} + +void MainWindow::documentationUpdated(const QString &namespaceName) +{ + TRACE_OBJ + CentralWidget* widget = CentralWidget::instance(); + widget->closeOrReloadTabs(widget->currentSourceFileList(). + keys(namespaceName), true); +} + +void MainWindow::resetQtDocInfo(const QString &component) +{ + TRACE_OBJ + HelpEngineWrapper::instance().setQtDocInfo(component, + QStringList(QDateTime().toString(Qt::ISODate))); +} + +void MainWindow::registerDocumentation(const QString &component, + const QString &absFileName) +{ + TRACE_OBJ + QString ns = QHelpEngineCore::namespaceName(absFileName); + if (ns.isEmpty()) + return; + + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + if (helpEngine.registeredDocumentations().contains(ns)) + helpEngine.unregisterDocumentation(ns); + if (!helpEngine.registerDocumentation(absFileName)) { + QMessageBox::warning(this, tr("Qt Assistant"), + tr("Could not register file '%1': %2"). + arg(absFileName).arg(helpEngine.error())); + } else { + QStringList docInfo; + docInfo << QFileInfo(absFileName).lastModified().toString(Qt::ISODate) + << absFileName; + helpEngine.setQtDocInfo(component, docInfo); + } +} + QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/mainwindow.h b/tools/assistant/tools/assistant/mainwindow.h index 8a9b572..8e4276d 100644 --- a/tools/assistant/tools/assistant/mainwindow.h +++ b/tools/assistant/tools/assistant/mainwindow.h @@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE class QAction; +class QFileSystemWatcher; class QLineEdit; class QComboBox; class QMenu; @@ -57,8 +58,6 @@ class QHelpEngineCore; class QHelpEngine; class CentralWidget; class ContentWindow; -class BookmarkManager; -class BookmarkWidget; class CmdLineParser; class QtDocInstaller; @@ -76,10 +75,6 @@ public: static QString defaultHelpCollectionFileName(); public: - void hideContents(); - void hideIndex(); - void hideBookmarks(); - void hideSearch(); void setIndexString(const QString &str); void expandTOC(int depth); bool usesDefaultCollection() const; @@ -88,18 +83,20 @@ signals: void initDone(); public slots: - void showContents(); - void showIndex(); - void showBookmarks(); - void showSearch(); + void setContentsVisible(bool visible); + void setIndexVisible(bool visible); + void setBookmarksVisible(bool visible); + void setSearchVisible(bool visible); void showSearchWidget(); void syncContents(); void activateCurrentCentralWidgetTab(); void currentFilterChanged(const QString &filter); private slots: + void showContents(); + void showIndex(); + void showSearch(); void insertLastPages(); - void addBookmark(); void gotoAddress(); void showPreferences(); void showNewAddress(); @@ -108,7 +105,6 @@ private slots: void updateNavigationItems(); void updateTabCloseAction(); void showNewAddress(const QUrl &url); - void addNewBookmark(const QString &title, const QString &url); void showTopicChooser(const QMap<QString, QUrl> &links, const QString &keyword); void updateApplicationFont(); void filterDocumentation(const QString &customFilter); @@ -116,12 +112,13 @@ private slots: void lookForNewQtDocumentation(); void indexingStarted(); void indexingFinished(); - void displayInstallationError(const QString &errorMessage); - void qtDocumentationInstalled(bool newDocsInstalled); + void qtDocumentationInstalled(); + void registerDocumentation(const QString &component, + const QString &absFileName); + void resetQtDocInfo(const QString &component); void checkInitState(); - - void updateBookmarkMenu(); - void showBookmark(QAction *action); + void documentationRemoved(const QString &namespaceName); + void documentationUpdated(const QString &namespaceName); private: bool initHelpDB(); @@ -132,14 +129,21 @@ private: void setupFilterToolbar(); void setupAddressToolbar(); QMenu *toolBarMenu(); - QWidget *setupBookmarkWidget(); + void hideContents(); + void hideIndex(); + void hideSearch(); - QHelpEngine *m_helpEngine; +private slots: + void showBookmarksDockWidget(); + void hideBookmarksDockWidget(); + +private: + QWidget *m_bookmarkWidget; + +private: CentralWidget *m_centralWidget; IndexWindow *m_indexWindow; ContentWindow *m_contentWindow; - BookmarkWidget *m_bookmarkWidget; - BookmarkManager *m_bookmarkManager; QLineEdit *m_addressLineEdit; QComboBox *m_filterCombo; @@ -161,8 +165,6 @@ private: QMenu *m_viewMenu; QMenu *m_toolBarMenu; - QMenu *m_bookmarkMenu; - QAction *m_bookmarkMenuAction; CmdLineParser *m_cmdLine; diff --git a/tools/assistant/tools/assistant/preferencesdialog.cpp b/tools/assistant/tools/assistant/preferencesdialog.cpp index ca12d8f..0e1d719 100644 --- a/tools/assistant/tools/assistant/preferencesdialog.cpp +++ b/tools/assistant/tools/assistant/preferencesdialog.cpp @@ -38,34 +38,36 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - #include "preferencesdialog.h" + +#include "centralwidget.h" #include "filternamedialog.h" -#include "installdialog.h" #include "fontpanel.h" -#include "centralwidget.h" -#include "aboutdialog.h" +#include "helpenginewrapper.h" +#include "installdialog.h" +#include "tracer.h" -#include <QtAlgorithms> +#include <QtCore/QtAlgorithms> +#include <QtCore/QFileSystemWatcher> -#include <QtGui/QHeaderView> +#include <QtGui/QDesktopWidget> #include <QtGui/QFileDialog> -#include <QtGui/QMessageBox> -#include <QtGui/QMenu> #include <QtGui/QFontDatabase> -#include <QtGui/QApplication> -#include <QtGui/QDesktopWidget> +#include <QtGui/QHeaderView> +#include <QtGui/QMenu> +#include <QtGui/QMessageBox> #include <QtHelp/QHelpEngineCore> QT_BEGIN_NAMESPACE -PreferencesDialog::PreferencesDialog(QHelpEngineCore *helpEngine, QWidget *parent) +PreferencesDialog::PreferencesDialog(QWidget *parent) : QDialog(parent) - , m_helpEngine(helpEngine) , m_appFontChanged(false) , m_browserFontChanged(false) + , helpEngine(HelpEngineWrapper::instance()) { + TRACE_OBJ m_ui.setupUi(this); connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), @@ -73,11 +75,8 @@ PreferencesDialog::PreferencesDialog(QHelpEngineCore *helpEngine, QWidget *paren connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject())); - QLatin1String key("EnableFilterFunctionality"); - m_hideFiltersTab = !m_helpEngine->customValue(key, true).toBool(); - - key = QLatin1String("EnableDocumentationManager"); - m_hideDocsTab = !m_helpEngine->customValue(key, true).toBool(); + m_hideFiltersTab = !helpEngine.filterFunctionalityEnabled(); + m_hideDocsTab = !helpEngine.documentationManagerEnabled(); if (!m_hideFiltersTab) { m_ui.attributeWidget->header()->hide(); @@ -106,7 +105,7 @@ PreferencesDialog::PreferencesDialog(QHelpEngineCore *helpEngine, QWidget *paren connect(m_ui.docRemoveButton, SIGNAL(clicked()), this, SLOT(removeDocumentation())); - m_docsBackup = m_helpEngine->registeredDocumentations(); + m_docsBackup = helpEngine.registeredDocumentations(); m_ui.registeredDocsListWidget->addItems(m_docsBackup); } else { m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.docsTab)); @@ -114,67 +113,56 @@ PreferencesDialog::PreferencesDialog(QHelpEngineCore *helpEngine, QWidget *paren updateFontSettingsPage(); updateOptionsPage(); + + if (helpEngine.usesAppFont()) + setFont(helpEngine.appFont()); } PreferencesDialog::~PreferencesDialog() { - QLatin1String key(""); + TRACE_OBJ if (m_appFontChanged) { - key = QLatin1String("appFont"); - m_helpEngine->setCustomValue(key, m_appFontPanel->selectedFont()); - - key = QLatin1String("useAppFont"); - m_helpEngine->setCustomValue(key, m_appFontPanel->isChecked()); - - key = QLatin1String("appWritingSystem"); - m_helpEngine->setCustomValue(key, m_appFontPanel->writingSystem()); + helpEngine.setAppFont(m_appFontPanel->selectedFont()); + helpEngine.setUseAppFont(m_appFontPanel->isChecked()); + helpEngine.setAppWritingSystem(m_appFontPanel->writingSystem()); + emit updateApplicationFont(); } if (m_browserFontChanged) { - key = QLatin1String("browserFont"); - m_helpEngine->setCustomValue(key, m_browserFontPanel->selectedFont()); - - key = QLatin1String("useBrowserFont"); - m_helpEngine->setCustomValue(key, m_browserFontPanel->isChecked()); - - key = QLatin1String("browserWritingSystem"); - m_helpEngine->setCustomValue(key, m_browserFontPanel->writingSystem()); - } - - if (m_appFontChanged || m_browserFontChanged) { - emit updateApplicationFont(); + helpEngine.setBrowserFont(m_browserFontPanel->selectedFont()); + helpEngine.setUseBrowserFont(m_browserFontPanel->isChecked()); + helpEngine.setBrowserWritingSystem(m_browserFontPanel->writingSystem()); emit updateBrowserFont(); } QString homePage = m_ui.homePageLineEdit->text(); if (homePage.isEmpty()) homePage = QLatin1String("help"); - m_helpEngine->setCustomValue(QLatin1String("homepage"), homePage); + helpEngine.setHomePage(homePage); int option = m_ui.helpStartComboBox->currentIndex(); - m_helpEngine->setCustomValue(QLatin1String("StartOption"), option); + helpEngine.setStartOption(option); } void PreferencesDialog::showDialog() { + TRACE_OBJ if (exec() != Accepted) m_appFontChanged = m_browserFontChanged = false; } void PreferencesDialog::updateFilterPage() { - if (!m_helpEngine) - return; - + TRACE_OBJ m_ui.filterWidget->clear(); m_ui.attributeWidget->clear(); - QHelpEngineCore help(m_helpEngine->collectionFile(), 0); - help.setupData(); m_filterMapBackup.clear(); - const QStringList filters = help.customFilters(); + const QStringList &filters = helpEngine.customFilters(); foreach (const QString &filter, filters) { - QStringList atts = help.filterAttributes(filter); + if (filter == HelpEngineWrapper::TrUnfiltered) + continue; + QStringList atts = helpEngine.filterAttributes(filter); m_filterMapBackup.insert(filter, atts); if (!m_filterMap.contains(filter)) m_filterMap.insert(filter, atts); @@ -182,15 +170,16 @@ void PreferencesDialog::updateFilterPage() m_ui.filterWidget->addItems(m_filterMap.keys()); - foreach (const QString &a, help.filterAttributes()) + foreach (const QString &a, helpEngine.filterAttributes()) new QTreeWidgetItem(m_ui.attributeWidget, QStringList() << a); - if (m_filterMap.keys().count()) + if (!m_filterMap.keys().isEmpty()) m_ui.filterWidget->setCurrentRow(0); } void PreferencesDialog::updateAttributes(QListWidgetItem *item) { + TRACE_OBJ QStringList checkedList; if (item) checkedList = m_filterMap.value(item->text()); @@ -206,6 +195,7 @@ void PreferencesDialog::updateAttributes(QListWidgetItem *item) void PreferencesDialog::updateFilterMap() { + TRACE_OBJ if (!m_ui.filterWidget->currentItem()) return; QString filter = m_ui.filterWidget->currentItem()->text(); @@ -224,6 +214,7 @@ void PreferencesDialog::updateFilterMap() void PreferencesDialog::addFilter() { + TRACE_OBJ FilterNameDialog dia(this); if (dia.exec() == QDialog::Rejected) return; @@ -241,6 +232,7 @@ void PreferencesDialog::addFilter() void PreferencesDialog::removeFilter() { + TRACE_OBJ QListWidgetItem *item = m_ui.filterWidget ->takeItem(m_ui.filterWidget->currentRow()); if (!item) @@ -255,6 +247,7 @@ void PreferencesDialog::removeFilter() void PreferencesDialog::addDocumentationLocal() { + TRACE_OBJ const QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Add Documentation"), QString(), tr("Qt Compressed Help Files (*.qch)")); if (fileNames.isEmpty()) @@ -275,10 +268,11 @@ void PreferencesDialog::addDocumentationLocal() continue; } - m_helpEngine->registerDocumentation(fileName); - m_ui.registeredDocsListWidget->addItem(nameSpace); - m_regDocs.append(nameSpace); - m_unregDocs.removeAll(nameSpace); + if (helpEngine.registerDocumentation(fileName)) { + m_ui.registeredDocsListWidget->addItem(nameSpace); + m_regDocs.append(nameSpace); + m_unregDocs.removeAll(nameSpace); + } } if (!invalidFiles.isEmpty() || !alreadyRegistered.isEmpty()) { @@ -307,6 +301,7 @@ void PreferencesDialog::addDocumentationLocal() void PreferencesDialog::removeDocumentation() { + TRACE_OBJ bool foundBefore = false; CentralWidget* widget = CentralWidget::instance(); QMap<int, QString> openedDocList = widget->currentSourceFileList(); @@ -338,6 +333,7 @@ void PreferencesDialog::removeDocumentation() void PreferencesDialog::applyChanges() { + TRACE_OBJ bool filtersWereChanged = false; if (!m_hideFiltersTab) { if (m_filterMap.count() != m_filterMapBackup.count()) { @@ -370,34 +366,28 @@ void PreferencesDialog::applyChanges() if (filtersWereChanged) { foreach (const QString &filter, m_removedFilters) - m_helpEngine->removeCustomFilter(filter); + helpEngine.removeCustomFilter(filter); QMapIterator<QString, QStringList> it(m_filterMap); while (it.hasNext()) { it.next(); - m_helpEngine->addCustomFilter(it.key(), it.value()); + helpEngine.addCustomFilter(it.key(), it.value()); } } - qSort(m_TabsToClose); - CentralWidget* widget = CentralWidget::instance(); - for (int i = m_TabsToClose.count(); --i >= 0;) - widget->closeTabAt(m_TabsToClose.at(i)); - if (widget->availableHelpViewer()== 0) - widget->setSource(QUrl(QLatin1String("about:blank"))); - - if (m_unregDocs.count()) { - foreach (const QString &doc, m_unregDocs) - m_helpEngine->unregisterDocumentation(doc); - } + CentralWidget::instance()->closeOrReloadTabs(m_TabsToClose, false); + + foreach (const QString &doc, m_unregDocs) + helpEngine.unregisterDocumentation(doc); - if (filtersWereChanged || m_regDocs.count() || m_unregDocs.count()) - m_helpEngine->setupData(); + if (filtersWereChanged || !m_regDocs.isEmpty() || !m_unregDocs.isEmpty()) + helpEngine.setupData(); accept(); } void PreferencesDialog::updateFontSettingsPage() { + TRACE_OBJ m_browserFontPanel = new FontPanel(this); m_browserFontPanel->setCheckable(true); m_ui.stackedWidget_2->insertWidget(0, m_browserFontPanel); @@ -411,31 +401,23 @@ void PreferencesDialog::updateFontSettingsPage() const QString customSettings(tr("Use custom settings")); m_appFontPanel->setTitle(customSettings); - QLatin1String key = QLatin1String("appFont"); - QFont font = qVariantValue<QFont>(m_helpEngine->customValue(key)); + QFont font = helpEngine.appFont(); m_appFontPanel->setSelectedFont(font); - key = QLatin1String("appWritingSystem"); - QFontDatabase::WritingSystem system = static_cast<QFontDatabase::WritingSystem> - (m_helpEngine->customValue(key).toInt()); + QFontDatabase::WritingSystem system = helpEngine.appWritingSystem(); m_appFontPanel->setWritingSystem(system); - key = QLatin1String("useAppFont"); - m_appFontPanel->setChecked(m_helpEngine->customValue(key).toBool()); + m_appFontPanel->setChecked(helpEngine.usesAppFont()); m_browserFontPanel->setTitle(customSettings); - key = QLatin1String("browserFont"); - font = qVariantValue<QFont>(m_helpEngine->customValue(key)); + font = helpEngine.browserFont(); m_browserFontPanel->setSelectedFont(font); - key = QLatin1String("browserWritingSystem"); - system = static_cast<QFontDatabase::WritingSystem> - (m_helpEngine->customValue(key).toInt()); + system = helpEngine.browserWritingSystem(); m_browserFontPanel->setWritingSystem(system); - key = QLatin1String("useBrowserFont"); - m_browserFontPanel->setChecked(m_helpEngine->customValue(key).toBool()); + m_browserFontPanel->setChecked(helpEngine.usesBrowserFont()); connect(m_appFontPanel, SIGNAL(toggled(bool)), this, SLOT(appFontSettingToggled(bool))); @@ -457,41 +439,38 @@ void PreferencesDialog::updateFontSettingsPage() void PreferencesDialog::appFontSettingToggled(bool on) { + TRACE_OBJ Q_UNUSED(on) m_appFontChanged = true; } void PreferencesDialog::appFontSettingChanged(int index) { + TRACE_OBJ Q_UNUSED(index) m_appFontChanged = true; } void PreferencesDialog::browserFontSettingToggled(bool on) { + TRACE_OBJ Q_UNUSED(on) m_browserFontChanged = true; } void PreferencesDialog::browserFontSettingChanged(int index) { + TRACE_OBJ Q_UNUSED(index) m_browserFontChanged = true; } void PreferencesDialog::updateOptionsPage() { - QString homepage = m_helpEngine->customValue(QLatin1String("homepage"), - QLatin1String("")).toString(); + TRACE_OBJ + m_ui.homePageLineEdit->setText(helpEngine.homePage()); - if (homepage.isEmpty()) { - homepage = m_helpEngine->customValue(QLatin1String("defaultHomepage"), - QLatin1String("help")).toString(); - } - m_ui.homePageLineEdit->setText(homepage); - - int option = m_helpEngine->customValue(QLatin1String("StartOption"), - ShowLastPages).toInt(); + int option = helpEngine.startOption(); m_ui.helpStartComboBox->setCurrentIndex(option); connect(m_ui.blankPageButton, SIGNAL(clicked()), this, SLOT(setBlankPage())); @@ -501,11 +480,13 @@ void PreferencesDialog::updateOptionsPage() void PreferencesDialog::setBlankPage() { + TRACE_OBJ m_ui.homePageLineEdit->setText(QLatin1String("about:blank")); } void PreferencesDialog::setCurrentPage() { + TRACE_OBJ QString homepage = CentralWidget::instance()->currentSource().toString(); if (homepage.isEmpty()) homepage = QLatin1String("help"); @@ -515,9 +496,8 @@ void PreferencesDialog::setCurrentPage() void PreferencesDialog::setDefaultPage() { - QString homepage = m_helpEngine->customValue(QLatin1String("defaultHomepage"), - QLatin1String("help")).toString(); - m_ui.homePageLineEdit->setText(homepage); + TRACE_OBJ + m_ui.homePageLineEdit->setText(helpEngine.defaultHomePage()); } QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/preferencesdialog.h b/tools/assistant/tools/assistant/preferencesdialog.h index 9ad6b6a..2894494 100644 --- a/tools/assistant/tools/assistant/preferencesdialog.h +++ b/tools/assistant/tools/assistant/preferencesdialog.h @@ -48,20 +48,15 @@ QT_BEGIN_NAMESPACE class FontPanel; -class QHelpEngineCore; - -enum { - ShowHomePage = 0, - ShowBlankPage = 1, - ShowLastPages = 2 -}; +class HelpEngineWrapper; +class QFileSystemWatcher; class PreferencesDialog : public QDialog { Q_OBJECT public: - PreferencesDialog(QHelpEngineCore *helpEngine, QWidget *parent = 0); + PreferencesDialog(QWidget *parent = 0); ~PreferencesDialog(); void showDialog(); @@ -93,7 +88,6 @@ private: void updateOptionsPage(); Ui::PreferencesDialogClass m_ui; - QHelpEngineCore *m_helpEngine; bool m_hideFiltersTab; bool m_hideDocsTab; QMap<QString, QStringList> m_filterMapBackup; @@ -107,6 +101,7 @@ private: FontPanel *m_browserFontPanel; bool m_appFontChanged; bool m_browserFontChanged; + HelpEngineWrapper &helpEngine; }; QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/qtdocinstaller.cpp b/tools/assistant/tools/assistant/qtdocinstaller.cpp index 652f630..5a501bf 100644 --- a/tools/assistant/tools/assistant/qtdocinstaller.cpp +++ b/tools/assistant/tools/assistant/qtdocinstaller.cpp @@ -38,23 +38,27 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "tracer.h" #include <QtCore/QDir> #include <QtCore/QLibraryInfo> #include <QtCore/QDateTime> +#include <QtCore/QFileSystemWatcher> #include <QtHelp/QHelpEngineCore> +#include "helpenginewrapper.h" #include "qtdocinstaller.h" QT_BEGIN_NAMESPACE -QtDocInstaller::QtDocInstaller(const QString &collectionFile) +QtDocInstaller::QtDocInstaller(const QList<DocInfo> &docInfos) + : m_abort(false), m_docInfos(docInfos) { - m_abort = false; - m_collectionFile = collectionFile; + TRACE_OBJ } QtDocInstaller::~QtDocInstaller() { + TRACE_OBJ if (!isRunning()) return; m_mutex.lock(); @@ -65,86 +69,59 @@ QtDocInstaller::~QtDocInstaller() void QtDocInstaller::installDocs() { + TRACE_OBJ start(LowPriority); } void QtDocInstaller::run() { - QHelpEngineCore *helpEngine = new QHelpEngineCore(m_collectionFile); - helpEngine->setupData(); - bool changes = false; - - QStringList docs; - docs << QLatin1String("assistant") - << QLatin1String("designer") - << QLatin1String("linguist") - << QLatin1String("qmake") - << QLatin1String("qt"); + TRACE_OBJ + m_qchDir = QLibraryInfo::location(QLibraryInfo::DocumentationPath) + + QDir::separator() + QLatin1String("qch"); + m_qchFiles = m_qchDir.entryList(QStringList() << QLatin1String("*.qch")); - foreach (const QString &doc, docs) { - changes |= installDoc(doc, helpEngine); + bool changes = false; + foreach (const DocInfo &docInfo, m_docInfos) { + changes |= installDoc(docInfo); m_mutex.lock(); if (m_abort) { - delete helpEngine; m_mutex.unlock(); return; } m_mutex.unlock(); } - delete helpEngine; emit docsInstalled(changes); } -bool QtDocInstaller::installDoc(const QString &name, QHelpEngineCore *helpEngine) +bool QtDocInstaller::installDoc(const DocInfo &docInfo) { - QString versionKey = QString(QLatin1String("qtVersion%1$$$%2")). - arg(QLatin1String(QT_VERSION_STR)).arg(name); - - QString info = helpEngine->customValue(versionKey, QString()).toString(); - QStringList lst = info.split(QLatin1String("|")); - + TRACE_OBJ + const QString &component = docInfo.first; + const QStringList &info = docInfo.second; QDateTime dt; - if (lst.count() && !lst.first().isEmpty()) - dt = QDateTime::fromString(lst.first(), Qt::ISODate); + if (!info.isEmpty() && !info.first().isEmpty()) + dt = QDateTime::fromString(info.first(), Qt::ISODate); QString qchFile; - if (lst.count() == 2) - qchFile = lst.last(); - - QDir dir(QLibraryInfo::location(QLibraryInfo::DocumentationPath) - + QDir::separator() + QLatin1String("qch")); + if (info.count() == 2) + qchFile = info.last(); - const QStringList files = dir.entryList(QStringList() << QLatin1String("*.qch")); - if (files.isEmpty()) { - helpEngine->setCustomValue(versionKey, QDateTime().toString(Qt::ISODate) - + QLatin1String("|")); + if (m_qchFiles.isEmpty()) { + emit qchFileNotFound(component); return false; } - foreach (const QString &f, files) { - if (f.startsWith(name)) { - QFileInfo fi(dir.absolutePath() + QDir::separator() + f); - if (dt.isValid() && fi.lastModified().toString(Qt::ISODate) == dt.toString(Qt::ISODate) + foreach (const QString &f, m_qchFiles) { + if (f.startsWith(component)) { + QFileInfo fi(m_qchDir.absolutePath() + QDir::separator() + f); + if (dt.isValid() && fi.lastModified().toTime_t() == dt.toTime_t() && qchFile == fi.absoluteFilePath()) return false; - - QString namespaceName = QHelpEngineCore::namespaceName(fi.absoluteFilePath()); - if (namespaceName.isEmpty()) - continue; - - if (helpEngine->registeredDocumentations().contains(namespaceName)) - helpEngine->unregisterDocumentation(namespaceName); - - if (!helpEngine->registerDocumentation(fi.absoluteFilePath())) { - emit errorMessage( - tr("The file %1 could not be registered successfully!\n\nReason: %2") - .arg(fi.absoluteFilePath()).arg(helpEngine->error())); - } - - helpEngine->setCustomValue(versionKey, fi.lastModified().toString(Qt::ISODate) - + QLatin1String("|") + fi.absoluteFilePath()); + emit registerDocumentation(component, fi.absoluteFilePath()); return true; } } + + emit qchFileNotFound(component); return false; } diff --git a/tools/assistant/tools/assistant/qtdocinstaller.h b/tools/assistant/tools/assistant/qtdocinstaller.h index 05606f9..92a707b 100644 --- a/tools/assistant/tools/assistant/qtdocinstaller.h +++ b/tools/assistant/tools/assistant/qtdocinstaller.h @@ -42,34 +42,41 @@ #ifndef QTDOCINSTALLER #define QTDOCINSTALLER -#include <QtCore/QThread> +#include <QtCore/QDir> #include <QtCore/QMutex> +#include <QtCore/QPair> +#include <QtCore/QStringList> +#include <QtCore/QThread> QT_BEGIN_NAMESPACE -class QHelpEngineCore; +class HelpEngineWrapper; class QtDocInstaller : public QThread { Q_OBJECT public: - QtDocInstaller(const QString &collectionFile); + typedef QPair<QString, QStringList> DocInfo; + QtDocInstaller(const QList<DocInfo> &docInfos); ~QtDocInstaller(); void installDocs(); signals: - void errorMessage(const QString &msg); + void qchFileNotFound(const QString &component); + void registerDocumentation(const QString &component, + const QString &absFileName); void docsInstalled(bool newDocsInstalled); private: void run(); - bool installDoc(const QString &name, - QHelpEngineCore *helpEngine); + bool installDoc(const DocInfo &docInfo); bool m_abort; - QString m_collectionFile; QMutex m_mutex; + QStringList m_qchFiles; + QDir m_qchDir; + QList<DocInfo> m_docInfos; }; QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/remotecontrol.cpp b/tools/assistant/tools/assistant/remotecontrol.cpp index 5fa7432..5ecdd69 100644 --- a/tools/assistant/tools/assistant/remotecontrol.cpp +++ b/tools/assistant/tools/assistant/remotecontrol.cpp @@ -38,12 +38,16 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "tracer.h" #include "remotecontrol.h" #include "mainwindow.h" #include "centralwidget.h" +#include "helpenginewrapper.h" #include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QFileSystemWatcher> #include <QtCore/QThread> #include <QtCore/QTextStream> #include <QtCore/QSocketNotifier> @@ -65,16 +69,19 @@ QT_BEGIN_NAMESPACE StdInListenerWin::StdInListenerWin(QObject *parent) : QThread(parent) { + TRACE_OBJ } StdInListenerWin::~StdInListenerWin() { + TRACE_OBJ terminate(); wait(); } void StdInListenerWin::run() { + TRACE_OBJ bool ok = true; char chBuf[4096]; DWORD dwRead; @@ -97,23 +104,24 @@ void StdInListenerWin::run() #endif while (ok) { - ok = ReadFile(hStdinDup, chBuf, 4096, &dwRead, NULL); + ok = ReadFile(hStdinDup, chBuf, sizeof(chBuf), &dwRead, NULL); if (ok && dwRead != 0) - emit receivedCommand(QString::fromLocal8Bit(chBuf)); + emit receivedCommand(QString::fromLocal8Bit(chBuf, dwRead)); } } #endif -RemoteControl::RemoteControl(MainWindow *mainWindow, QHelpEngine *helpEngine) +RemoteControl::RemoteControl(MainWindow *mainWindow) : QObject(mainWindow) , m_mainWindow(mainWindow) - , m_helpEngine(helpEngine) , m_debug(false) , m_caching(true) , m_syncContents(false) - , m_expandTOC(-3) + , m_expandTOC(-2) + , helpEngine(HelpEngineWrapper::instance()) { + TRACE_OBJ connect(m_mainWindow, SIGNAL(initDone()), this, SLOT(applyCache())); #ifdef Q_OS_WIN StdInListenerWin *l = new StdInListenerWin(this); @@ -130,6 +138,7 @@ RemoteControl::RemoteControl(MainWindow *mainWindow, QHelpEngine *helpEngine) void RemoteControl::receivedData() { + TRACE_OBJ QByteArray ba; while (true) { char c = getc(stdin); @@ -145,135 +154,204 @@ void RemoteControl::receivedData() void RemoteControl::handleCommandString(const QString &cmdString) { + TRACE_OBJ QStringList cmds = cmdString.split(QLatin1Char(';')); QStringList::const_iterator it = cmds.constBegin(); - QString cmdLine, cmd, arg; while (it != cmds.constEnd()) { - cmdLine = (*it).trimmed(); - cmd = cmdLine; - arg.clear(); - int i = cmdLine.indexOf(QLatin1Char(' ')); - if (i > 0) { - cmd = cmdLine.left(i); - arg = cmdLine.mid(i+1); - } - cmd = cmd.toLower(); + QString cmd, arg; + splitInputString(*it, cmd, arg); if (m_debug) QMessageBox::information(0, tr("Debugging Remote Control"), tr("Received Command: %1 %2").arg(cmd).arg(arg)); - if (cmd == QLatin1String("debug")) { - if (arg == QLatin1String("on")) - m_debug = true; - else - m_debug = false; - } else if (cmd == QLatin1String("show")) { - if (arg.toLower() == QLatin1String("contents")) { - m_mainWindow->showContents(); - } else if (arg.toLower() == QLatin1String("index")) { - m_mainWindow->showIndex(); - } else if (arg.toLower() == QLatin1String("bookmarks")) { - m_mainWindow->showBookmarks(); - } else if (arg.toLower() == QLatin1String("search")) { - m_mainWindow->showSearch(); - } - } else if (cmd == QLatin1String("hide")) { - if (arg.toLower() == QLatin1String("contents")) { - m_mainWindow->hideContents(); - } else if (arg.toLower() == QLatin1String("index")) { - m_mainWindow->hideIndex(); - } else if (arg.toLower() == QLatin1String("bookmarks")) { - m_mainWindow->hideBookmarks(); - } else if (arg.toLower() == QLatin1String("search")) { - m_mainWindow->hideSearch(); - } - } else if (cmd == QLatin1String("setsource")) { - QUrl url(arg); - if (url.isValid()) { - if (url.isRelative()) - url = CentralWidget::instance()->currentSource().resolved(url); - if (m_caching) { - clearCache(); - m_setSource = url; - } else { - CentralWidget::instance()->setSource(url); - } - } - } else if (cmd == QLatin1String("synccontents")) { - if (m_caching) - m_syncContents = true; - else - m_mainWindow->syncContents(); - } else if (cmd == QLatin1String("activatekeyword")) { - if (m_caching) { - clearCache(); - m_activateKeyword = arg; - } else { - m_mainWindow->setIndexString(arg); - if (!arg.isEmpty()) - m_helpEngine->indexWidget()->activateCurrentItem(); - } - } else if (cmd == QLatin1String("activateidentifier")) { - if (m_caching) { - clearCache(); - m_activateIdentifier = arg; - } else { - QMap<QString, QUrl> links = - m_helpEngine->linksForIdentifier(arg); - if (links.count()) - CentralWidget::instance()->setSource(links.constBegin().value()); - } - } else if (cmd == QLatin1String("expandtoc")) { - bool ok = false; - int depth = -1; - if (!arg.isEmpty()) - depth = arg.toInt(&ok); - if (!ok) - depth = -1; - - if (m_caching) - m_expandTOC = depth; - else - m_mainWindow->expandTOC(depth); - } else if (cmd == QLatin1String("setcurrentfilter")) { - if (!m_helpEngine->customFilters().contains(arg)) - return; - if (m_caching) { - clearCache(); - m_currentFilter = arg; - } else { - m_helpEngine->setCurrentFilter(arg); - } - } else { + if (cmd == QLatin1String("debug")) + handleDebugCommand(arg); + else if (cmd == QLatin1String("show")) + handleShowOrHideCommand(arg, true); + else if (cmd == QLatin1String("hide")) + handleShowOrHideCommand(arg, false); + else if (cmd == QLatin1String("setsource")) + handleSetSourceCommand(arg); + else if (cmd == QLatin1String("synccontents")) + handleSyncContentsCommand(); + else if (cmd == QLatin1String("activatekeyword")) + handleActivateKeywordCommand(arg); + else if (cmd == QLatin1String("activateidentifier")) + handleActivateIdentifierCommand(arg); + else if (cmd == QLatin1String("expandtoc")) + handleExpandTocCommand(arg); + else if (cmd == QLatin1String("setcurrentfilter")) + handleSetCurrentFilterCommand(arg); + else if (cmd == QLatin1String("register")) + handleRegisterCommand(arg); + else if (cmd == QLatin1String("unregister")) + handleUnregisterCommand(arg); + else return; - } + ++it; } m_mainWindow->raise(); m_mainWindow->activateWindow(); } +void RemoteControl::splitInputString(const QString &input, QString &cmd, + QString &arg) +{ + TRACE_OBJ + QString cmdLine = input.trimmed(); + int i = cmdLine.indexOf(QLatin1Char(' ')); + cmd = cmdLine.left(i); + arg = cmdLine.mid(i+1); + cmd = cmd.toLower(); +} + +void RemoteControl::handleDebugCommand(const QString &arg) +{ + TRACE_OBJ + m_debug = arg == QLatin1String("on"); +} + +void RemoteControl::handleShowOrHideCommand(const QString &arg, bool show) +{ + TRACE_OBJ + if (arg.toLower() == QLatin1String("contents")) + m_mainWindow->setContentsVisible(show); + else if (arg.toLower() == QLatin1String("index")) + m_mainWindow->setIndexVisible(show); + else if (arg.toLower() == QLatin1String("bookmarks")) + m_mainWindow->setBookmarksVisible(show); + else if (arg.toLower() == QLatin1String("search")) + m_mainWindow->setSearchVisible(show); +} + +void RemoteControl::handleSetSourceCommand(const QString &arg) +{ + TRACE_OBJ + QUrl url(arg); + if (url.isValid()) { + if (url.isRelative()) + url = CentralWidget::instance()->currentSource().resolved(url); + if (m_caching) { + clearCache(); + m_setSource = url; + } else { + CentralWidget::instance()->setSource(url); + } + } +} + +void RemoteControl::handleSyncContentsCommand() +{ + TRACE_OBJ + if (m_caching) + m_syncContents = true; + else + m_mainWindow->syncContents(); +} + +void RemoteControl::handleActivateKeywordCommand(const QString &arg) +{ + TRACE_OBJ + if (m_caching) { + clearCache(); + m_activateKeyword = arg; + } else { + m_mainWindow->setIndexString(arg); + if (!arg.isEmpty()) + helpEngine.indexWidget()->activateCurrentItem(); + } +} + +void RemoteControl::handleActivateIdentifierCommand(const QString &arg) +{ + TRACE_OBJ + if (m_caching) { + clearCache(); + m_activateIdentifier = arg; + } else { + const QMap<QString, QUrl> &links = helpEngine.linksForIdentifier(arg); + if (!links.isEmpty()) + CentralWidget::instance()->setSource(links.constBegin().value()); + } +} + +void RemoteControl::handleExpandTocCommand(const QString &arg) +{ + TRACE_OBJ + bool ok = false; + int depth = -2; + if (!arg.isEmpty()) + depth = arg.toInt(&ok); + if (!ok || depth < -2) + depth = -2; + + if (m_caching) + m_expandTOC = depth; + else if (depth != -2) + m_mainWindow->expandTOC(depth); +} + +void RemoteControl::handleSetCurrentFilterCommand(const QString &arg) +{ + TRACE_OBJ + if (helpEngine.customFilters().contains(arg)) { + if (m_caching) { + clearCache(); + m_currentFilter = arg; + } else { + helpEngine.setCurrentFilter(arg); + } + } +} + +void RemoteControl::handleRegisterCommand(const QString &arg) +{ + TRACE_OBJ + const QString &absFileName = QFileInfo(arg).absoluteFilePath(); + if (helpEngine.registeredDocumentations(). + contains(QHelpEngineCore::namespaceName(absFileName))) + return; + if (helpEngine.registerDocumentation(absFileName)) + helpEngine.setupData(); +} + +void RemoteControl::handleUnregisterCommand(const QString &arg) +{ + TRACE_OBJ + const QString &absFileName = QFileInfo(arg).absoluteFilePath(); + const QString &ns = QHelpEngineCore::namespaceName(absFileName); + if (helpEngine.registeredDocumentations().contains(ns)) { + CentralWidget* widget = CentralWidget::instance(); + widget->closeOrReloadTabs(widget->currentSourceFileList().keys(ns), false); + if (helpEngine.unregisterDocumentation(ns)) + helpEngine.setupData(); + } +} + void RemoteControl::applyCache() { + TRACE_OBJ if (m_setSource.isValid()) { CentralWidget::instance()->setSource(m_setSource); } else if (!m_activateKeyword.isEmpty()) { m_mainWindow->setIndexString(m_activateKeyword); - m_helpEngine->indexWidget()->activateCurrentItem(); + helpEngine.indexWidget()->activateCurrentItem(); } else if (!m_activateIdentifier.isEmpty()) { QMap<QString, QUrl> links = - m_helpEngine->linksForIdentifier(m_activateIdentifier); - if (links.count()) + helpEngine.linksForIdentifier(m_activateIdentifier); + if (!links.isEmpty()) CentralWidget::instance()->setSource(links.constBegin().value()); } else if (!m_currentFilter.isEmpty()) { - m_helpEngine->setCurrentFilter(m_currentFilter); + helpEngine.setCurrentFilter(m_currentFilter); } if (m_syncContents) m_mainWindow->syncContents(); - if (m_expandTOC != -3) + Q_ASSERT(m_expandTOC >= -2); + if (m_expandTOC != -2) m_mainWindow->expandTOC(m_expandTOC); m_caching = false; @@ -281,6 +359,7 @@ void RemoteControl::applyCache() void RemoteControl::clearCache() { + TRACE_OBJ m_currentFilter.clear(); m_setSource.clear(); m_syncContents = false; diff --git a/tools/assistant/tools/assistant/remotecontrol.h b/tools/assistant/tools/assistant/remotecontrol.h index b888b40..0777878 100644 --- a/tools/assistant/tools/assistant/remotecontrol.h +++ b/tools/assistant/tools/assistant/remotecontrol.h @@ -43,19 +43,20 @@ #define REMOTECONTROL_H #include <QtCore/QObject> +#include <QtCore/QString> #include <QtCore/QUrl> QT_BEGIN_NAMESPACE +class HelpEngineWrapper; class MainWindow; -class QHelpEngine; class RemoteControl : public QObject { Q_OBJECT public: - RemoteControl(MainWindow *mainWindow, QHelpEngine *helpEngine); + RemoteControl(MainWindow *mainWindow); private slots: void receivedData(); @@ -64,10 +65,20 @@ private slots: private: void clearCache(); + void splitInputString(const QString &input, QString &cmd, QString &arg); + void handleDebugCommand(const QString &arg); + void handleShowOrHideCommand(const QString &arg, bool show); + void handleSetSourceCommand(const QString &arg); + void handleSyncContentsCommand(); + void handleActivateKeywordCommand(const QString &arg); + void handleActivateIdentifierCommand(const QString &arg); + void handleExpandTocCommand(const QString &arg); + void handleSetCurrentFilterCommand(const QString &arg); + void handleRegisterCommand(const QString &arg); + void handleUnregisterCommand(const QString &arg); private: MainWindow *m_mainWindow; - QHelpEngine *m_helpEngine; bool m_debug; bool m_caching; @@ -77,6 +88,7 @@ private: QString m_activateIdentifier; int m_expandTOC; QString m_currentFilter; + HelpEngineWrapper &helpEngine; }; QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/searchwidget.cpp b/tools/assistant/tools/assistant/searchwidget.cpp index ad24231..d83790d 100644 --- a/tools/assistant/tools/assistant/searchwidget.cpp +++ b/tools/assistant/tools/assistant/searchwidget.cpp @@ -38,6 +38,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "tracer.h" #include "mainwindow.h" #include "searchwidget.h" @@ -65,6 +66,7 @@ SearchWidget::SearchWidget(QHelpSearchEngine *engine, QWidget *parent) , attached(false) , searchEngine(engine) { + TRACE_OBJ QVBoxLayout *vLayout = new QVBoxLayout(this); resultWidget = searchEngine->resultWidget(); @@ -91,11 +93,13 @@ SearchWidget::SearchWidget(QHelpSearchEngine *engine, QWidget *parent) SearchWidget::~SearchWidget() { + TRACE_OBJ // nothing todo } void SearchWidget::zoomIn() { + TRACE_OBJ QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget); if (browser && zoomCount != 10) { zoomCount++; @@ -105,6 +109,7 @@ void SearchWidget::zoomIn() void SearchWidget::zoomOut() { + TRACE_OBJ QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget); if (browser && zoomCount != -5) { zoomCount--; @@ -114,6 +119,7 @@ void SearchWidget::zoomOut() void SearchWidget::resetZoom() { + TRACE_OBJ if (zoomCount == 0) return; @@ -126,33 +132,39 @@ void SearchWidget::resetZoom() bool SearchWidget::isAttached() const { + TRACE_OBJ return attached; } void SearchWidget::setAttached(bool state) { + TRACE_OBJ attached = state; } void SearchWidget::search() const { + TRACE_OBJ QList<QHelpSearchQuery> query = searchEngine->queryWidget()->query(); searchEngine->search(query); } void SearchWidget::searchingStarted() { + TRACE_OBJ qApp->setOverrideCursor(QCursor(Qt::WaitCursor)); } void SearchWidget::searchingFinished(int hits) { + TRACE_OBJ Q_UNUSED(hits) qApp->restoreOverrideCursor(); } bool SearchWidget::eventFilter(QObject* o, QEvent *e) { + TRACE_OBJ QTextBrowser* browser = qFindChild<QTextBrowser*>(resultWidget); if (browser && o == browser->viewport() && e->type() == QEvent::MouseButtonRelease){ @@ -171,6 +183,7 @@ bool SearchWidget::eventFilter(QObject* o, QEvent *e) void SearchWidget::keyPressEvent(QKeyEvent *keyEvent) { + TRACE_OBJ if (keyEvent->key() == Qt::Key_Escape) MainWindow::activateCurrentBrowser(); else @@ -179,6 +192,7 @@ void SearchWidget::keyPressEvent(QKeyEvent *keyEvent) void SearchWidget::contextMenuEvent(QContextMenuEvent *contextMenuEvent) { + TRACE_OBJ QMenu menu; QPoint point = contextMenuEvent->globalPos(); diff --git a/tools/assistant/tools/assistant/topicchooser.cpp b/tools/assistant/tools/assistant/topicchooser.cpp index 5c04244..262fea8 100644 --- a/tools/assistant/tools/assistant/topicchooser.cpp +++ b/tools/assistant/tools/assistant/topicchooser.cpp @@ -38,9 +38,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ - -#include <QtCore/QMap> -#include <QtCore/QUrl> +#include "tracer.h" #include "topicchooser.h" @@ -50,37 +48,40 @@ TopicChooser::TopicChooser(QWidget *parent, const QString &keyword, const QMap<QString, QUrl> &links) : QDialog(parent) { + TRACE_OBJ ui.setupUi(this); ui.label->setText(tr("Choose a topic for <b>%1</b>:").arg(keyword)); - m_links = links; - QMap<QString, QUrl>::const_iterator it = m_links.constBegin(); - for (; it != m_links.constEnd(); ++it) + QMap<QString, QUrl>::const_iterator it = links.constBegin(); + for (; it != links.constEnd(); ++it) { ui.listWidget->addItem(it.key()); + m_links.append(it.value()); + } if (ui.listWidget->count() != 0) ui.listWidget->setCurrentRow(0); ui.listWidget->setFocus(); - connect(ui.buttonDisplay, SIGNAL(clicked()), - this, SLOT(accept())); - connect(ui.buttonCancel, SIGNAL(clicked()), - this, SLOT(reject())); - connect(ui.listWidget, SIGNAL(itemActivated(QListWidgetItem*)), - this, SLOT(accept())); + connect(ui.buttonDisplay, SIGNAL(clicked()), this, SLOT(accept())); + connect(ui.buttonCancel, SIGNAL(clicked()), this, SLOT(reject())); + connect(ui.listWidget, SIGNAL(itemActivated(QListWidgetItem*)), this, + SLOT(accept())); } QUrl TopicChooser::link() const { + TRACE_OBJ QListWidgetItem *item = ui.listWidget->currentItem(); if (!item) return QUrl(); QString title = item->text(); - if (title.isEmpty() || !m_links.contains(title)) + if (title.isEmpty()) return QUrl(); - return m_links.value(title); + const int row = ui.listWidget->row(item); + Q_ASSERT(row < m_links.count()); + return m_links.at(row); } QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/topicchooser.h b/tools/assistant/tools/assistant/topicchooser.h index 4dba726..4113cee 100644 --- a/tools/assistant/tools/assistant/topicchooser.h +++ b/tools/assistant/tools/assistant/topicchooser.h @@ -44,9 +44,10 @@ #include "ui_topicchooser.h" -#include <QUrl> -#include <QMap> -#include <QString> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QUrl> #include <QtGui/QDialog> @@ -64,7 +65,7 @@ public: private: Ui::TopicChooser ui; - QMap<QString, QUrl> m_links; + QList<QUrl> m_links; }; QT_END_NAMESPACE diff --git a/tools/assistant/compat/lib/qassistantclient_global.h b/tools/assistant/tools/assistant/tracer.h index 6b58736..66d450a 100644 --- a/tools/assistant/compat/lib/qassistantclient_global.h +++ b/tools/assistant/tools/assistant/tracer.h @@ -39,25 +39,37 @@ ** ****************************************************************************/ -#ifndef QASSISTANTCLIENT_GLOBAL_H -#define QASSISTANTCLIENT_GLOBAL_H +#ifndef TRACER_H +#define TRACER_H -#include <QtCore/qglobal.h> - -QT_BEGIN_HEADER +#include <QtCore/QtGlobal> QT_BEGIN_NAMESPACE -#if defined(QT_ASSISTANT_CLIENT_STATIC) || (!defined(QT_SHARED) && !defined(QT_DLL)) -# define QT_ASSISTANT_CLIENT_EXPORT -#elif defined(QT_ASSISTANT_CLIENT_LIBRARY) -# define QT_ASSISTANT_CLIENT_EXPORT Q_DECL_EXPORT -#else -# define QT_ASSISTANT_CLIENT_EXPORT Q_DECL_IMPORT -#endif +class Tracer +{ +public: + Tracer(const char *func) : m_func(func) + { + qDebug("Entering function %s.", m_func); + } -QT_END_NAMESPACE + ~Tracer() + { + qDebug("Leaving function %s.", m_func); + } -QT_END_HEADER +private: + const char * const m_func; +}; +QT_END_NAMESPACE + +// #define TRACING_REQUESTED +#ifdef TRACING_REQUESTED +#define TRACE_OBJ Tracer traceObj__(Q_FUNC_INFO); +#else +#define TRACE_OBJ #endif + +#endif // TRACER_H diff --git a/tools/assistant/tools/assistant/xbelsupport.cpp b/tools/assistant/tools/assistant/xbelsupport.cpp new file mode 100644 index 0000000..ce49230 --- /dev/null +++ b/tools/assistant/tools/assistant/xbelsupport.cpp @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" + +#include "xbelsupport.h" + +#include "bookmarkitem.h" +#include "bookmarkmodel.h" + +#include <QtCore/QDate> +#include <QtCore/QModelIndex> + +QT_BEGIN_NAMESPACE + +struct Bookmark { + QString title; + QString url; + bool folded; +}; + +XbelWriter::XbelWriter(BookmarkModel *model) + : QXmlStreamWriter() + , bookmarkModel(model) +{ + TRACE_OBJ + setAutoFormatting(true); +} + +void XbelWriter::writeToFile(QIODevice *device) +{ + TRACE_OBJ + setDevice(device); + + writeStartDocument(); + writeDTD(QLatin1String("<!DOCTYPE xbel>")); + writeStartElement(QLatin1String("xbel")); + writeAttribute(QLatin1String("version"), QLatin1String("1.0")); + + const QModelIndex &root = bookmarkModel->index(0,0, QModelIndex()); + for (int i = 0; i < bookmarkModel->rowCount(root); ++i) + writeData(bookmarkModel->index(i, 0, root)); + writeEndDocument(); +} + +void XbelWriter::writeData(const QModelIndex &index) +{ + TRACE_OBJ + if (index.isValid()) { + Bookmark entry; + entry.title = index.data().toString(); + entry.url = index.data(UserRoleUrl).toString(); + + if (index.data(UserRoleFolder).toBool()) { + writeStartElement(QLatin1String("folder")); + entry.folded = !index.data(UserRoleExpanded).toBool(); + writeAttribute(QLatin1String("folded"), entry.folded + ? QLatin1String("yes") : QLatin1String("no")); + writeTextElement(QLatin1String("title"), entry.title); + + for (int i = 0; i < bookmarkModel->rowCount(index); ++i) + writeData(bookmarkModel->index(i, 0 , index)); + writeEndElement(); + } else { + writeStartElement(QLatin1String("bookmark")); + writeAttribute(QLatin1String("href"), entry.url); + writeTextElement(QLatin1String("title"), entry.title); + writeEndElement(); + } + } +} + +// -- XbelReader + +XbelReader::XbelReader(BookmarkModel *model) + : QXmlStreamReader() + , bookmarkModel(model) +{ + TRACE_OBJ +} + +bool XbelReader::readFromFile(QIODevice *device) +{ + TRACE_OBJ + setDevice(device); + + while (!atEnd()) { + readNext(); + + if (isStartElement()) { + if (name() == QLatin1String("xbel") + && attributes().value(QLatin1String("version")) + == QLatin1String("1.0")) { + const QModelIndex &root = bookmarkModel->index(0,0, QModelIndex()); + parents.append(bookmarkModel->addItem(root, true)); + readXBEL(); + bookmarkModel->setData(parents.first(), + QDate::currentDate().toString(Qt::ISODate), Qt::EditRole); + } else { + raiseError(QLatin1String("The file is not an XBEL version 1.0 file.")); + } + } + } + + return !error(); +} + +void XbelReader::readXBEL() +{ + TRACE_OBJ + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + if (name() == QLatin1String("folder")) + readFolder(); + else if (name() == QLatin1String("bookmark")) + readBookmark(); + else + readUnknownElement(); + } + } +} + +void XbelReader::readFolder() +{ + TRACE_OBJ + parents.append(bookmarkModel->addItem(parents.last(), true)); + bookmarkModel->setData(parents.last(), + attributes().value(QLatin1String("folded")) == QLatin1String("no"), + UserRoleExpanded); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + if (name() == QLatin1String("title")) { + bookmarkModel->setData(parents.last(), readElementText(), + Qt::EditRole); + } else if (name() == QLatin1String("folder")) + readFolder(); + else if (name() == QLatin1String("bookmark")) + readBookmark(); + else + readUnknownElement(); + } + } + + parents.removeLast(); +} + +void XbelReader::readBookmark() +{ + TRACE_OBJ + const QModelIndex &index = bookmarkModel->addItem(parents.last(), false); + if (BookmarkItem* item = bookmarkModel->itemFromIndex(index)) { + item->setData(UserRoleUrl, attributes().value(QLatin1String("href")) + .toString()); + } + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + if (name() == QLatin1String("title")) + bookmarkModel->setData(index, readElementText(), Qt::EditRole); + else + readUnknownElement(); + } + } +} + +void XbelReader::readUnknownElement() +{ + TRACE_OBJ + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) + readUnknownElement(); + } +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/xbelsupport.h b/tools/assistant/tools/assistant/xbelsupport.h new file mode 100644 index 0000000..037415f --- /dev/null +++ b/tools/assistant/tools/assistant/xbelsupport.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef XBELSUPPORT_H +#define XBELSUPPORT_H + +#include <QtXml/QXmlStreamReader> +#include <QtCore/QPersistentModelIndex> + +QT_FORWARD_DECLARE_CLASS(QIODevice) +QT_FORWARD_DECLARE_CLASS(QModelIndex) + +QT_BEGIN_NAMESPACE + +class BookmarkModel; + +class XbelWriter : public QXmlStreamWriter +{ +public: + XbelWriter(BookmarkModel *model); + void writeToFile(QIODevice *device); + +private: + void writeData(const QModelIndex &index); + +private: + BookmarkModel *bookmarkModel; +}; + +class XbelReader : public QXmlStreamReader +{ +public: + XbelReader(BookmarkModel *model); + bool readFromFile(QIODevice *device); + +private: + void readXBEL(); + void readFolder(); + void readBookmark(); + void readUnknownElement(); + +private: + BookmarkModel *bookmarkModel; + QList<QPersistentModelIndex> parents; +}; + +QT_END_NAMESPACE + +#endif // XBELSUPPORT_H diff --git a/tools/assistant/tools/qcollectiongenerator/main.cpp b/tools/assistant/tools/qcollectiongenerator/main.cpp index 2339c50..7fcb4e1 100644 --- a/tools/assistant/tools/qcollectiongenerator/main.cpp +++ b/tools/assistant/tools/qcollectiongenerator/main.cpp @@ -39,21 +39,23 @@ ** ****************************************************************************/ +#include "../shared/collectionconfiguration.h" #include "../shared/helpgenerator.h" +#include <private/qhelpgenerator_p.h> +#include <private/qhelpprojectdata_p.h> + +#include <QtCore/QCoreApplication> #include <QtCore/QDir> #include <QtCore/QMap> #include <QtCore/QFileInfo> #include <QtCore/QCoreApplication> #include <QtCore/QDateTime> #include <QtCore/QBuffer> - -#include <private/qhelpgenerator_p.h> -#include <private/qhelpprojectdata_p.h> #include <QtHelp/QHelpEngineCore> - #include <QtXml/QXmlStreamReader> + QT_USE_NAMESPACE class CollectionConfigReader : public QXmlStreamReader @@ -87,6 +89,7 @@ public: QStringList filesToRegister() const { return m_filesToRegister; } QString cacheDirectory() const { return m_cacheDirectory; } + bool cacheDirRelativeToCollection() const { return m_cacheDirRelativeToCollection; } private: void raiseErrorWithLine(); @@ -115,11 +118,13 @@ private: QMap<QString, QString> m_filesToGenerate; QStringList m_filesToRegister; QString m_cacheDirectory; + bool m_cacheDirRelativeToCollection; }; void CollectionConfigReader::raiseErrorWithLine() { - raiseError(QObject::tr("Unknown token at line %1.") + raiseError(QCoreApplication::translate("QCollectionGenerator", + "Unknown token at line %1.") .arg(lineNumber())); } @@ -139,8 +144,10 @@ void CollectionConfigReader::readData(const QByteArray &contents) && attributes().value(QLatin1String("version")) == QLatin1String("1.0")) readConfig(); else - raiseError(QObject::tr("Unknown token at line %1. Expected \"QtHelpCollectionProject\"!") - .arg(lineNumber())); + raiseError(QCoreApplication::translate("QCollectionGenerator", + "Unknown token at line %1. " + "Expected \"QtHelpCollectionProject\"!") + .arg(lineNumber())); } } } @@ -198,6 +205,9 @@ void CollectionConfigReader::readAssistantSettings() } else if (name() == QLatin1String("aboutDialog")) { readAboutDialog(); } else if (name() == "cacheDirectory") { + m_cacheDirRelativeToCollection = + attributes().value(QLatin1String("base")) + == QLatin1String("collection"); m_cacheDirectory = readElementText(); } else { raiseErrorWithLine(); @@ -322,6 +332,14 @@ void CollectionConfigReader::readRegister() } } +namespace { + QString absoluteFileName(const QString &basePath, const QString &fileName) + { + return QFileInfo(fileName).isAbsolute() ? + fileName : basePath + QDir::separator() + fileName; + } +} + int main(int argc, char *argv[]) { QString error; @@ -339,7 +357,8 @@ int main(int argc, char *argv[]) QFileInfo fi(QString::fromLocal8Bit(argv[i])); collectionFile = fi.absoluteFilePath(); } else { - error = QObject::tr("Missing output file name!"); + error = QCoreApplication::translate("QCollectionGenerator", + "Missing output file name!"); } } else if (arg == QLatin1String("-h")) { showHelp = true; @@ -353,14 +372,16 @@ int main(int argc, char *argv[]) } if (showVersion) { - fprintf(stdout, "Qt Collection Generator version 1.0 (Qt %s)\n", QT_VERSION_STR); + fprintf(stdout, "Qt Collection Generator version 1.0 (Qt %s)\n", + QT_VERSION_STR); return 0; } if (configFile.isEmpty() && !showHelp) - error = QObject::tr("Missing collection config file!"); + error = QCoreApplication::translate("QCollectionGenerator", + "Missing collection config file!"); - QString help = QObject::tr("\nUsage:\n\n" + QString help = QCoreApplication::translate("QCollectionGenerator", "\nUsage:\n\n" "qcollectiongenerator <collection-config-file> [options]\n\n" " -o <collection-file> Generates a collection file\n" " called <collection-file>. If\n" @@ -403,13 +424,13 @@ int main(int argc, char *argv[]) while (it != config.filesToGenerate().constEnd()) { fprintf(stdout, "Generating help for %s...\n", qPrintable(it.key())); QHelpProjectData helpData; - if (!helpData.readData(basePath + QDir::separator() + it.key())) { + if (!helpData.readData(absoluteFileName(basePath, it.key()))) { fprintf(stderr, "%s\n", qPrintable(helpData.errorMessage())); return -1; } HelpGenerator helpGenerator; - if (!helpGenerator.generate(&helpData, basePath + QDir::separator() + it.value())) { + if (!helpGenerator.generate(&helpData, absoluteFileName(basePath, it.value()))) { fprintf(stderr, "%s\n", qPrintable(helpGenerator.error())); return -1; } @@ -433,49 +454,54 @@ int main(int argc, char *argv[]) } foreach (const QString &file, config.filesToRegister()) { - if (!helpEngine.registerDocumentation(basePath + QDir::separator() + file)) { + if (!helpEngine.registerDocumentation(absoluteFileName(basePath, file))) { fprintf(stderr, "%s\n", qPrintable(helpEngine.error())); return -1; } } if (!config.title().isEmpty()) - helpEngine.setCustomValue(QLatin1String("WindowTitle"), config.title()); + CollectionConfiguration::setWindowTitle(helpEngine, config.title()); if (!config.homePage().isEmpty()) { - helpEngine.setCustomValue(QLatin1String("defaultHomepage"), - config.homePage()); + CollectionConfiguration::setDefaultHomePage(helpEngine, + config.homePage()); } - if (!config.startPage().isEmpty()) - helpEngine.setCustomValue(QLatin1String("LastShownPages"), config.startPage()); + if (!config.startPage().isEmpty()) { + CollectionConfiguration::setLastShownPages(helpEngine, + QStringList(config.startPage())); + } - if (!config.currentFilter().isEmpty()) - helpEngine.setCustomValue(QLatin1String("CurrentFilter"), config.currentFilter()); + if (!config.currentFilter().isEmpty()) { + helpEngine.setCurrentFilter(config.currentFilter()); + } - if (!config.cacheDirectory().isEmpty()) - helpEngine.setCustomValue(QLatin1String("CacheDirectory"), config.cacheDirectory()); + if (!config.cacheDirectory().isEmpty()) { + CollectionConfiguration::setCacheDir(helpEngine, config.cacheDirectory(), + config.cacheDirRelativeToCollection()); + } - helpEngine.setCustomValue(QLatin1String("EnableFilterFunctionality"), + CollectionConfiguration::setFilterFunctionalityEnabled(helpEngine, config.enableFilterFunctionality()); - helpEngine.setCustomValue(QLatin1String("HideFilterFunctionality"), - config.hideFilterFunctionality()); - helpEngine.setCustomValue(QLatin1String("EnableDocumentationManager"), + CollectionConfiguration::setFilterToolbarVisible(helpEngine, + !config.hideFilterFunctionality()); + CollectionConfiguration::setDocumentationManagerEnabled(helpEngine, config.enableDocumentationManager()); - helpEngine.setCustomValue(QLatin1String("EnableAddressBar"), + CollectionConfiguration::setAddressBarEnabled(helpEngine, config.enableAddressBar()); - helpEngine.setCustomValue(QLatin1String("HideAddressBar"), - config.hideAddressBar()); - helpEngine.setCustomValue(QLatin1String("CreationTime"), + CollectionConfiguration::setAddressBarVisible(helpEngine, + !config.hideAddressBar()); + CollectionConfiguration::setCreationTime(helpEngine, QDateTime::currentDateTime().toTime_t()); if (!config.applicationIcon().isEmpty()) { - QFile icon(basePath + QDir::separator() + config.applicationIcon()); + QFile icon(absoluteFileName(basePath, config.applicationIcon())); if (!icon.open(QIODevice::ReadOnly)) { fprintf(stderr, "Cannot open %s!\n", qPrintable(icon.fileName())); return -1; } - helpEngine.setCustomValue(QLatin1String("ApplicationIcon"), icon.readAll()); + CollectionConfiguration::setApplicationIcon(helpEngine, icon.readAll()); } if (config.aboutMenuTexts().count()) { @@ -487,16 +513,16 @@ int main(int argc, char *argv[]) s << it.value(); ++it; } - helpEngine.setCustomValue(QLatin1String("AboutMenuTexts"), ba); + CollectionConfiguration::setAboutMenuTexts(helpEngine, ba); } if (!config.aboutIcon().isEmpty()) { - QFile icon(basePath + QDir::separator() + config.aboutIcon()); + QFile icon(absoluteFileName(basePath, config.aboutIcon())); if (!icon.open(QIODevice::ReadOnly)) { fprintf(stderr, "Cannot open %s!\n", qPrintable(icon.fileName())); return -1; } - helpEngine.setCustomValue(QLatin1String("AboutIcon"), icon.readAll()); + CollectionConfiguration::setAboutIcon(helpEngine, icon.readAll()); } if (config.aboutTextFiles().count()) { @@ -512,7 +538,7 @@ int main(int argc, char *argv[]) while (it != config.aboutTextFiles().constEnd()) { s << it.key(); - QFileInfo fi(basePath + QDir::separator() + it.value()); + QFileInfo fi(absoluteFileName(basePath, it.value())); QFile f(fi.absoluteFilePath()); if (!f.open(QIODevice::ReadOnly)) { fprintf(stderr, "Cannot open %s!\n", qPrintable(f.fileName())); @@ -544,14 +570,14 @@ int main(int argc, char *argv[]) } ++it; } - helpEngine.setCustomValue(QLatin1String("AboutTexts"), ba); + CollectionConfiguration::setAboutTexts(helpEngine, ba); if (imgData.count()) { QByteArray imageData; QBuffer buffer(&imageData); buffer.open(QIODevice::WriteOnly); QDataStream out(&buffer); out << imgData; - helpEngine.setCustomValue(QLatin1String("AboutImages"), imageData); + CollectionConfiguration::setAboutImages(helpEngine, imageData); } } diff --git a/tools/assistant/tools/qcollectiongenerator/qcollectiongenerator.pro b/tools/assistant/tools/qcollectiongenerator/qcollectiongenerator.pro index cf70e48..98e6a31 100644 --- a/tools/assistant/tools/qcollectiongenerator/qcollectiongenerator.pro +++ b/tools/assistant/tools/qcollectiongenerator/qcollectiongenerator.pro @@ -1,14 +1,17 @@ -QT += xml network +QT += xml \ + network TEMPLATE = app DESTDIR = ../../../../bin TARGET = qcollectiongenerator -CONFIG += qt warn_on help console +CONFIG += qt \ + warn_on \ + help \ + console CONFIG -= app_bundle - -target.path=$$[QT_INSTALL_BINS] +target.path = $$[QT_INSTALL_BINS] INSTALLS += target - SOURCES += ../shared/helpgenerator.cpp \ - main.cpp - -HEADERS += ../shared/helpgenerator.h + main.cpp \ + ../shared/collectionconfiguration.cpp +HEADERS += ../shared/helpgenerator.h \ + ../shared/collectionconfiguration.h diff --git a/tools/assistant/tools/qhelpgenerator/main.cpp b/tools/assistant/tools/qhelpgenerator/main.cpp index 6245e33..a309f42 100644 --- a/tools/assistant/tools/qhelpgenerator/main.cpp +++ b/tools/assistant/tools/qhelpgenerator/main.cpp @@ -58,6 +58,7 @@ int main(int argc, char *argv[]) QString basePath; bool showHelp = false; bool showVersion = false; + bool checkLinks = false; for (int i = 1; i < argc; ++i) { arg = QString::fromLocal8Bit(argv[i]); @@ -66,12 +67,15 @@ int main(int argc, char *argv[]) QFileInfo fi(QString::fromLocal8Bit(argv[i])); compressedFile = fi.absoluteFilePath(); } else { - error = QObject::tr("Missing output file name!"); + error = QCoreApplication::translate("QHelpGenerator", + "Missing output file name!"); } } else if (arg == QLatin1String("-v")) { showVersion = true; } else if (arg == QLatin1String("-h")) { showHelp = true; + } else if (arg == QLatin1String("-c")) { + checkLinks = true; } else { QFileInfo fi(arg); projectFile = fi.absoluteFilePath(); @@ -80,19 +84,23 @@ int main(int argc, char *argv[]) } if (showVersion) { - fprintf(stdout, "Qt Help Generator version 1.0 (Qt %s)\n", QT_VERSION_STR); + fprintf(stdout, "Qt Help Generator version 1.0 (Qt %s)\n", + QT_VERSION_STR); return 0; } if (projectFile.isEmpty() && !showHelp) - error = QObject::tr("Missing Qt help project file!"); + error = QCoreApplication::translate("QHelpGenerator", + "Missing Qt help project file!"); - QString help = QObject::tr("\nUsage:\n\n" + QString help = QCoreApplication::translate("QHelpGenerator", "\nUsage:\n\n" "qhelpgenerator <help-project-file> [options]\n\n" " -o <compressed-file> Generates a Qt compressed help\n" " file called <compressed-file>.\n" " If this option is not specified\n" " a default name will be used.\n" + " -c Checks whether all links in HTML files\n" + " point to files in this help project.\n" " -v Displays the version of \n" " qhelpgenerator.\n\n"); @@ -111,9 +119,11 @@ int main(int argc, char *argv[]) } if (compressedFile.isEmpty()) { - QFileInfo fi(projectFile); - compressedFile = basePath + QDir::separator() - + fi.baseName() + QLatin1String(".qch"); + if (!checkLinks) { + QFileInfo fi(projectFile); + compressedFile = basePath + QDir::separator() + + fi.baseName() + QLatin1String(".qch"); + } } else { // check if the output dir exists -- create if it doesn't QFileInfo fi(compressedFile); @@ -134,7 +144,11 @@ int main(int argc, char *argv[]) QCoreApplication app(argc, argv); HelpGenerator generator; - bool success = generator.generate(helpData, compressedFile); + bool success = true; + if (checkLinks) + success = generator.checkLinks(*helpData); + if (success && !compressedFile.isEmpty()) + success = generator.generate(helpData, compressedFile); delete helpData; if (!success) { fprintf(stderr, "%s\n", qPrintable(generator.error())); diff --git a/tools/assistant/tools/shared/collectionconfiguration.cpp b/tools/assistant/tools/shared/collectionconfiguration.cpp new file mode 100644 index 0000000..e3944b6 --- /dev/null +++ b/tools/assistant/tools/shared/collectionconfiguration.cpp @@ -0,0 +1,313 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "collectionconfiguration.h" + +#include <QtHelp/QHelpEngineCore> + +QT_BEGIN_NAMESPACE + +namespace { + const QString AboutIconKey(QLatin1String("AboutIcon")); + const QString AboutImagesKey(QLatin1String("AboutImages")); + const QString AboutMenuTextsKey(QLatin1String("AboutMenuTexts")); + const QString AboutTextsKey(QLatin1String("AboutTexts")); + const QString ApplicationIconKey(QLatin1String("ApplicationIcon")); + const QString CacheDirKey(QLatin1String("CacheDirectory")); + const QString CacheDirRelativeToCollectionKey(QLatin1String("CacheDirRelativeToCollection")); + const QString CreationTimeKey(QLatin1String("CreationTime")); + const QString DefaultHomePageKey(QLatin1String("defaultHomepage")); + const QString EnableAddressBarKey(QLatin1String("EnableAddressBar")); + const QString EnableDocManagerKey(QLatin1String("EnableDocumentationManager")); + const QString EnableFilterKey(QLatin1String("EnableFilterFunctionality")); + const QString HideAddressBarKey(QLatin1String("HideAddressBar")); + const QString FilterToolbarHiddenKey(QLatin1String("HideFilterFunctionality")); + const QString LastPageKey(QLatin1String("LastTabPage")); + const QString LastRegisterTime(QLatin1String("LastRegisterTime")); + const QString LastShownPagesKey(QLatin1String("LastShownPages")); + const QString LastZoomFactorsKey(QLatin1String( +#if !defined(QT_NO_WEBKIT) + "LastPagesZoomWebView" +#else + "LastPagesZoomTextBrowser" +#endif + )); + const QString WindowTitleKey(QLatin1String("WindowTitle")); +} // anonymous namespace + +const QString CollectionConfiguration::DefaultZoomFactor(QLatin1String("0.0")); +const QString CollectionConfiguration::ListSeparator(QLatin1String("|")); + +uint CollectionConfiguration::creationTime(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(CreationTimeKey, 0).toUInt(); +} + +void CollectionConfiguration::setCreationTime(QHelpEngineCore &helpEngine, uint time) +{ + helpEngine.setCustomValue(CreationTimeKey, time); +} + +const QString CollectionConfiguration::windowTitle(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(WindowTitleKey).toString(); +} + +void CollectionConfiguration::setWindowTitle(QHelpEngineCore &helpEngine, + const QString &windowTitle) +{ + helpEngine.setCustomValue(WindowTitleKey, windowTitle); +} + +bool CollectionConfiguration::filterFunctionalityEnabled(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(EnableFilterKey, true).toBool(); +} + +void CollectionConfiguration::setFilterFunctionalityEnabled(QHelpEngineCore &helpEngine, + bool enabled) +{ + helpEngine.setCustomValue(EnableFilterKey, enabled); +} + +bool CollectionConfiguration::filterToolbarVisible(const QHelpEngineCore &helpEngine) +{ + return !helpEngine.customValue(FilterToolbarHiddenKey, true).toBool(); +} + +void CollectionConfiguration::setFilterToolbarVisible(QHelpEngineCore &helpEngine, + bool visible) +{ + helpEngine.setCustomValue(FilterToolbarHiddenKey, !visible); +} + +bool CollectionConfiguration::addressBarEnabled(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(EnableAddressBarKey, true).toBool(); +} + +void CollectionConfiguration::setAddressBarEnabled(QHelpEngineCore &helpEngine, + bool enabled) +{ + helpEngine.setCustomValue(EnableAddressBarKey, enabled); +} + +bool CollectionConfiguration::addressBarVisible(const QHelpEngineCore &helpEngine) +{ + return !helpEngine.customValue(HideAddressBarKey, true).toBool(); +} + +void CollectionConfiguration::setAddressBarVisible(QHelpEngineCore &helpEngine, + bool visible) +{ + helpEngine.setCustomValue(HideAddressBarKey, !visible); +} + +const QString CollectionConfiguration::cacheDir(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(CacheDirKey).toString(); +} + +bool CollectionConfiguration::cacheDirIsRelativeToCollection(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(CacheDirRelativeToCollectionKey).toBool(); +} + +void CollectionConfiguration::setCacheDir(QHelpEngineCore &helpEngine, + const QString &cacheDir, bool relativeToCollection) +{ + helpEngine.setCustomValue(CacheDirKey, cacheDir); + helpEngine.setCustomValue(CacheDirRelativeToCollectionKey, + relativeToCollection); +} + +bool CollectionConfiguration::documentationManagerEnabled(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(EnableDocManagerKey, true).toBool(); +} + +void CollectionConfiguration::setDocumentationManagerEnabled(QHelpEngineCore &helpEngine, + bool enabled) +{ + helpEngine.setCustomValue(EnableDocManagerKey, enabled); +} + +const QByteArray CollectionConfiguration::applicationIcon(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(ApplicationIconKey).toByteArray(); +} + +void CollectionConfiguration::setApplicationIcon(QHelpEngineCore &helpEngine, + const QByteArray &icon) +{ + helpEngine.setCustomValue(ApplicationIconKey, icon); +} + +const QByteArray CollectionConfiguration::aboutMenuTexts(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(AboutMenuTextsKey).toByteArray(); +} + +void CollectionConfiguration::setAboutMenuTexts(QHelpEngineCore &helpEngine, + const QByteArray &texts) +{ + helpEngine.setCustomValue(AboutMenuTextsKey, texts); +} + +const QByteArray CollectionConfiguration::aboutIcon(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(AboutIconKey).toByteArray(); +} + +void CollectionConfiguration::setAboutIcon(QHelpEngineCore &helpEngine, + const QByteArray &icon) +{ + helpEngine.setCustomValue(AboutIconKey, icon); +} + +const QByteArray CollectionConfiguration::aboutTexts(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(AboutTextsKey).toByteArray(); +} + +void CollectionConfiguration::setAboutTexts(QHelpEngineCore &helpEngine, + const QByteArray &texts) +{ + helpEngine.setCustomValue(AboutTextsKey, texts); +} + +const QByteArray CollectionConfiguration::aboutImages(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(AboutImagesKey).toByteArray(); +} + +void CollectionConfiguration::setAboutImages(QHelpEngineCore &helpEngine, + const QByteArray &images) +{ + helpEngine.setCustomValue(AboutImagesKey, images); +} + +const QString CollectionConfiguration::defaultHomePage(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(DefaultHomePageKey, QLatin1String("help")). + toString(); +} + +void CollectionConfiguration::setDefaultHomePage(QHelpEngineCore &helpEngine, + const QString &page) +{ + helpEngine.setCustomValue(DefaultHomePageKey, page); +} + +const QStringList CollectionConfiguration::lastShownPages(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(LastShownPagesKey).toString(). + split(ListSeparator, QString::SkipEmptyParts); +} + +void CollectionConfiguration::setLastShownPages(QHelpEngineCore &helpEngine, + const QStringList &lastShownPages) +{ + helpEngine.setCustomValue(LastShownPagesKey, + lastShownPages.join(ListSeparator)); +} + +const QStringList CollectionConfiguration::lastZoomFactors(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(LastZoomFactorsKey).toString(). + split(ListSeparator, QString::SkipEmptyParts); +} + +void CollectionConfiguration::setLastZoomFactors(QHelpEngineCore &helpEngine, + const QStringList &lastZoomFactors) +{ + helpEngine.setCustomValue(LastZoomFactorsKey, + lastZoomFactors.join(ListSeparator)); +} + +int CollectionConfiguration::lastTabPage(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(LastPageKey, 1).toInt(); +} + +void CollectionConfiguration::setLastTabPage(QHelpEngineCore &helpEngine, + int lastPage) +{ + helpEngine.setCustomValue(LastPageKey, lastPage); +} + +const QDateTime CollectionConfiguration::lastRegisterTime(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(LastRegisterTime, QDateTime()).toDateTime(); +} + +void CollectionConfiguration::updateLastRegisterTime(QHelpEngineCore &helpEngine) +{ + helpEngine.setCustomValue(LastRegisterTime, QDateTime::currentDateTime()); +} + +bool CollectionConfiguration::isNewer(const QHelpEngineCore &newer, + const QHelpEngineCore &older) +{ + return creationTime(newer) > creationTime(older); +} + +void CollectionConfiguration::copyConfiguration(const QHelpEngineCore &source, + QHelpEngineCore &target) +{ + setCreationTime(target, creationTime(source)); + setWindowTitle(target, windowTitle(source)); + target.setCurrentFilter(source.currentFilter()); + setCacheDir(target, cacheDir(source), cacheDirIsRelativeToCollection(source)); + setFilterFunctionalityEnabled(target, filterFunctionalityEnabled(source)); + setFilterToolbarVisible(target, filterToolbarVisible(source)); + setAddressBarEnabled(target, addressBarEnabled(source)); + setAddressBarVisible(target, addressBarVisible(source)); + setDocumentationManagerEnabled(target, documentationManagerEnabled(source)); + setApplicationIcon(target, applicationIcon(source)); + setAboutMenuTexts(target, aboutMenuTexts(source)); + setAboutIcon(target, aboutIcon(source)); + setAboutTexts(target, aboutTexts(source)); + setAboutImages(target, aboutImages(source)); + setDefaultHomePage(target, defaultHomePage(source)); +} + +QT_END_NAMESPACE diff --git a/tools/assistant/tools/shared/collectionconfiguration.h b/tools/assistant/tools/shared/collectionconfiguration.h new file mode 100644 index 0000000..b7bf247 --- /dev/null +++ b/tools/assistant/tools/shared/collectionconfiguration.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COLLECTIONCONFIGURATION_H +#define COLLECTIONCONFIGURATION_H + +#include <QtCore/QByteArray> +#include <QtCore/QCoreApplication> +#include <QtCore/QDateTime> +#include <QtCore/QString> +#include <QtCore/QStringList> + +QT_BEGIN_NAMESPACE + +class QHelpEngineCore; + +class CollectionConfiguration +{ +public: + static const QString windowTitle(const QHelpEngineCore &helpEngine); + static void setWindowTitle(QHelpEngineCore &helpEngine, + const QString &windowTitle); + + static const QString cacheDir(const QHelpEngineCore &helpEngine); + static bool cacheDirIsRelativeToCollection(const QHelpEngineCore &helpEngine); + static void setCacheDir(QHelpEngineCore &helpEngine, + const QString &cacheDir, bool relativeToCollection); + + static uint creationTime(const QHelpEngineCore &helpEngine); + static void setCreationTime(QHelpEngineCore &helpEngine, uint time); + + static bool filterFunctionalityEnabled(const QHelpEngineCore &helpEngine); + static void setFilterFunctionalityEnabled(QHelpEngineCore &helpEngine, + bool enabled); + + static bool filterToolbarVisible(const QHelpEngineCore &helpEngine); + static void setFilterToolbarVisible(QHelpEngineCore &helpEngine, + bool visible); + + static bool addressBarEnabled(const QHelpEngineCore &helpEngine); + static void setAddressBarEnabled(QHelpEngineCore &helpEngine, bool enabled); + + static bool addressBarVisible(const QHelpEngineCore &helpEngine); + static void setAddressBarVisible(QHelpEngineCore &helpEngine, bool visible); + + + static bool documentationManagerEnabled(const QHelpEngineCore &helpEngine); + static void setDocumentationManagerEnabled(QHelpEngineCore &helpEngine, + bool enabled); + + static const QByteArray applicationIcon(const QHelpEngineCore &helpEngine); + static void setApplicationIcon(QHelpEngineCore &helpEngine, + const QByteArray &icon); + + // TODO: Encapsulate encoding from/to QByteArray here + static const QByteArray aboutMenuTexts(const QHelpEngineCore &helpEngine); + static void setAboutMenuTexts(QHelpEngineCore &helpEngine, + const QByteArray &texts); + + static const QByteArray aboutIcon(const QHelpEngineCore &helpEngine); + static void setAboutIcon(QHelpEngineCore &helpEngine, + const QByteArray &icon); + + // TODO: Encapsulate encoding from/to QByteArray here + static const QByteArray aboutTexts(const QHelpEngineCore &helpEngine); + static void setAboutTexts(QHelpEngineCore &helpEngine, + const QByteArray &texts); + + static const QByteArray aboutImages(const QHelpEngineCore &helpEngine); + static void setAboutImages(QHelpEngineCore &helpEngine, + const QByteArray &images); + + static const QString defaultHomePage(const QHelpEngineCore &helpEngine); + static void setDefaultHomePage(QHelpEngineCore &helpEngine, + const QString &page); + + // TODO: Don't allow last pages and zoom factors to be set in isolation + // Perhaps also fill up missing elements automatically or assert. + static const QStringList lastShownPages(const QHelpEngineCore &helpEngine); + static void setLastShownPages(QHelpEngineCore &helpEngine, + const QStringList &lastShownPages); + static const QStringList lastZoomFactors(const QHelpEngineCore &helpEngine); + static void setLastZoomFactors(QHelpEngineCore &helPEngine, + const QStringList &lastZoomFactors); + + static int lastTabPage(const QHelpEngineCore &helpEngine); + static void setLastTabPage(QHelpEngineCore &helpEngine, int lastPage); + + static bool isNewer(const QHelpEngineCore &newer, + const QHelpEngineCore &older); + static void copyConfiguration(const QHelpEngineCore &source, + QHelpEngineCore &target); + + /* + * Note that this only reflects register actions caused by the + * "-register" command line switch, not GUI or remote control actions. + */ + static const QDateTime lastRegisterTime(const QHelpEngineCore &helpEngine); + static void updateLastRegisterTime(QHelpEngineCore &helpEngine); + + static const QString DefaultZoomFactor; + static const QString ListSeparator; +}; + +QT_END_NAMESPACE + +#endif // COLLECTIONCONFIGURATION_H diff --git a/tools/assistant/tools/shared/helpgenerator.cpp b/tools/assistant/tools/shared/helpgenerator.cpp index fa183cd..12008e6 100644 --- a/tools/assistant/tools/shared/helpgenerator.cpp +++ b/tools/assistant/tools/shared/helpgenerator.cpp @@ -61,6 +61,11 @@ bool HelpGenerator::generate(QHelpDataInterface *helpData, return generator->generate(helpData, outputFileName); } +bool HelpGenerator::checkLinks(const QHelpDataInterface &helpData) +{ + return generator->checkLinks(helpData); +} + QString HelpGenerator::error() const { return generator->error(); diff --git a/tools/assistant/tools/shared/helpgenerator.h b/tools/assistant/tools/shared/helpgenerator.h index 903d588..6da1c2b 100644 --- a/tools/assistant/tools/shared/helpgenerator.h +++ b/tools/assistant/tools/shared/helpgenerator.h @@ -57,6 +57,7 @@ public: HelpGenerator(); bool generate(QHelpDataInterface *helpData, const QString &outputFileName); + bool checkLinks(const QHelpDataInterface &helpData); QString error() const; private slots: diff --git a/tools/assistant/translations/qt_help.pro b/tools/assistant/translations/qt_help.pro index 1012f3f..6f66876 100644 --- a/tools/assistant/translations/qt_help.pro +++ b/tools/assistant/translations/qt_help.pro @@ -44,6 +44,7 @@ TRANSLATIONS = \ $$TR_DIR/qt_help_cs.ts \ $$TR_DIR/qt_help_da.ts \ $$TR_DIR/qt_help_de.ts \ + $$TR_DIR/qt_help_hu.ts \ $$TR_DIR/qt_help_ja.ts \ $$TR_DIR/qt_help_pl.ts \ $$TR_DIR/qt_help_ru.ts \ diff --git a/tools/assistant/translations/translations.pro b/tools/assistant/translations/translations.pro index d29ffc3..c692262 100644 --- a/tools/assistant/translations/translations.pro +++ b/tools/assistant/translations/translations.pro @@ -46,6 +46,7 @@ TRANSLATIONS = \ $$TR_DIR/assistant_da.ts \ $$TR_DIR/assistant_de.ts \ $$TR_DIR/assistant_fr.ts \ + $$TR_DIR/assistant_hu.ts \ $$TR_DIR/assistant_ja.ts \ $$TR_DIR/assistant_pl.ts \ $$TR_DIR/assistant_ru.ts \ diff --git a/tools/assistant/translations/translations_adp.pro b/tools/assistant/translations/translations_adp.pro deleted file mode 100644 index f8da2e3..0000000 --- a/tools/assistant/translations/translations_adp.pro +++ /dev/null @@ -1,41 +0,0 @@ -# Include those manually as they do not contain any directory specification - -FORMS += ../compat/helpdialog.ui \ - ../compat/mainwindow.ui \ - ../compat/tabbedbrowser.ui \ - ../compat/topicchooser.ui - -SOURCES += ../compat/main.cpp \ - ../compat/helpwindow.cpp \ - ../compat/topicchooser.cpp \ - ../compat/docuparser.cpp \ - ../compat/index.cpp \ - ../compat/profile.cpp \ - ../compat/config.cpp \ - ../compat/helpdialog.cpp \ - ../compat/mainwindow.cpp \ - ../compat/tabbedbrowser.cpp \ - ../compat/fontsettingsdialog.cpp - -SOURCES += ../../shared/fontpanel/fontpanel.cpp - -HEADERS += ../compat/helpwindow.h \ - ../compat/topicchooser.h \ - ../compat/docuparser.h \ - ../compat/index.h \ - ../compat/profile.h \ - ../compat/helpdialog.h \ - ../compat/mainwindow.h \ - ../compat/tabbedbrowser.h \ - ../compat/config.h \ - ../compat/fontsettingsdialog.h - - -TR_DIR = $$PWD/../../../translations -TRANSLATIONS = \ - $$TR_DIR/assistant_adp_de.ts \ - $$TR_DIR/assistant_adp_ja.ts \ - $$TR_DIR/assistant_adp_pl.ts \ - $$TR_DIR/assistant_adp_ru.ts \ - $$TR_DIR/assistant_adp_zh_CN.ts \ - $$TR_DIR/assistant_adp_zh_TW.ts diff --git a/tools/configure/configure.pro b/tools/configure/configure.pro index 91de7c2..d926a76 100644 --- a/tools/configure/configure.pro +++ b/tools/configure/configure.pro @@ -119,3 +119,4 @@ DEFINES += COMMERCIAL_VERSION INCLUDEPATH += $$QT_SOURCE_TREE/src/corelib/arch/generic \ $$QT_SOURCE_TREE/include/QtCore \ + $$QT_SOURCE_TREE/tools/shared diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index b35f454..ee49bbf 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -195,10 +195,37 @@ Configure::Configure( int& argc, char** argv ) } } + // make patch_capabilities and createpackage scripts for Symbian that can be used from the shadow build + QFile patch_capabilities(buildPath + "/bin/patch_capabilities"); + if(patch_capabilities.open(QFile::WriteOnly)) { + QTextStream stream(&patch_capabilities); + stream << "#!/usr/bin/perl -w" << endl + << "require \"" << sourcePath + "/bin/patch_capabilities\";" << endl; + } + QFile patch_capabilities_bat(buildPath + "/bin/patch_capabilities.bat"); + if(patch_capabilities_bat.open(QFile::WriteOnly)) { + QTextStream stream(&patch_capabilities_bat); + stream << "@echo off" << endl + << "call " << fixSeparators(sourcePath) << fixSeparators("/bin/patch_capabilities.bat %*") << endl; + patch_capabilities_bat.close(); + } + QFile createpackage(buildPath + "/bin/createpackage"); + if(createpackage.open(QFile::WriteOnly)) { + QTextStream stream(&createpackage); + stream << "#!/usr/bin/perl -w" << endl + << "require \"" << sourcePath + "/bin/createpackage\";" << endl; + } + QFile createpackage_bat(buildPath + "/bin/createpackage.bat"); + if(createpackage_bat.open(QFile::WriteOnly)) { + QTextStream stream(&createpackage_bat); + stream << "@echo off" << endl + << "call " << fixSeparators(sourcePath) << fixSeparators("/bin/createpackage.bat %*") << endl; + createpackage_bat.close(); + } + // For Windows CE and shadow builds we need to copy these to the // build directory. QFile::copy(sourcePath + "/bin/setcepaths.bat" , buildPath + "/bin/setcepaths.bat"); - //copy the mkspecs buildDir.mkpath("mkspecs"); if(!Environment::cpdir(sourcePath + "/mkspecs", buildPath + "/mkspecs")){ @@ -248,6 +275,7 @@ Configure::Configure( int& argc, char** argv ) dictionary[ "PHONON_BACKEND" ] = "yes"; dictionary[ "MULTIMEDIA" ] = "yes"; dictionary[ "AUDIO_BACKEND" ] = "auto"; + dictionary[ "WMSDK" ] = "auto"; dictionary[ "DIRECTSHOW" ] = "no"; dictionary[ "WEBKIT" ] = "auto"; dictionary[ "DECLARATIVE" ] = "auto"; @@ -701,9 +729,6 @@ void Configure::parseCmdLine() } else if ( configCmdLine.at(i) == "-opengl-es-cm" ) { dictionary[ "OPENGL" ] = "yes"; dictionary[ "OPENGL_ES_CM" ] = "yes"; - } else if ( configCmdLine.at(i) == "-opengl-es-cl" ) { - dictionary[ "OPENGL" ] = "yes"; - dictionary[ "OPENGL_ES_CL" ] = "yes"; } else if ( configCmdLine.at(i) == "-opengl-es-2" ) { dictionary[ "OPENGL" ] = "yes"; dictionary[ "OPENGL_ES_2" ] = "yes"; @@ -964,6 +989,7 @@ void Configure::parseCmdLine() if(i==argCount) break; qmakeDefines += "QT_NAMESPACE="+configCmdLine.at(i); + dictionary[ "QT_NAMESPACE" ] = configCmdLine.at(i); } else if( configCmdLine.at(i) == "-qtlibinfix" ) { ++i; if(i==argCount) @@ -1071,6 +1097,12 @@ void Configure::parseCmdLine() dictionary[ "QT_INSTALL_PLUGINS" ] = configCmdLine.at(i); } + else if( configCmdLine.at(i) == "-importdir" ) { + ++i; + if(i==argCount) + break; + dictionary[ "QT_INSTALL_IMPORTS" ] = configCmdLine.at(i); + } else if( configCmdLine.at(i) == "-datadir" ) { ++i; if(i==argCount) @@ -1171,7 +1203,8 @@ void Configure::parseCmdLine() dictionary[ "QMAKESPEC" ].endsWith( "-msvc2002" ) || dictionary[ "QMAKESPEC" ].endsWith( "-msvc2003" ) || dictionary[ "QMAKESPEC" ].endsWith( "-msvc2005" ) || - dictionary[ "QMAKESPEC" ].endsWith( "-msvc2008" )) { + dictionary[ "QMAKESPEC" ].endsWith( "-msvc2008" ) || + dictionary[ "QMAKESPEC" ].endsWith( "-msvc2010" )) { if ( dictionary[ "MAKE" ].isEmpty() ) dictionary[ "MAKE" ] = "nmake"; dictionary[ "QMAKEMAKEFILE" ] = "Makefile.win32"; } else if ( dictionary[ "QMAKESPEC" ] == QString( "win32-g++" ) ) { @@ -1488,6 +1521,7 @@ void Configure::applySpecSpecifics() dictionary[ "QT_HOST_PREFIX" ] = dictionary[ "QT_INSTALL_PREFIX" ]; dictionary[ "QT_INSTALL_PREFIX" ] = ""; dictionary[ "QT_INSTALL_PLUGINS" ] = "\\resource\\qt\\plugins"; + dictionary[ "QT_INSTALL_IMPORTS" ] = "\\resource\\qt\\imports"; dictionary[ "QT_INSTALL_TRANSLATIONS" ] = "\\resource\\qt\\translations"; dictionary[ "ARM_FPU_TYPE" ] = "softvfp"; dictionary[ "SQL_SQLITE" ] = "yes"; @@ -1516,7 +1550,6 @@ void Configure::applySpecSpecifics() dictionary[ "QT_ICONV" ] = "no"; dictionary["DECORATIONS"] = "default windows styled"; - dictionary[ "QMAKEADDITIONALARGS" ] = "-unix"; } } @@ -1565,7 +1598,7 @@ bool Configure::displayHelp() desc("Usage: configure [-buildkey <key>]\n" // desc("Usage: configure [-prefix dir] [-bindir <dir>] [-libdir <dir>]\n" // "[-docdir <dir>] [-headerdir <dir>] [-plugindir <dir>]\n" -// "[-datadir <dir>] [-translationdir <dir>]\n" +// "[-importdir <dir>] [-datadir <dir>] [-translationdir <dir>]\n" // "[-examplesdir <dir>] [-demosdir <dir>][-buildkey <key>]\n" "[-release] [-debug] [-debug-and-release] [-shared] [-static]\n" "[-no-fast] [-fast] [-no-exceptions] [-exceptions]\n" @@ -1605,6 +1638,7 @@ bool Configure::displayHelp() desc( "-docdir <dir>", "Documentation will be installed to dir\n(default PREFIX/doc)"); desc( "-headerdir <dir>", "Headers will be installed to dir\n(default PREFIX/include)"); desc( "-plugindir <dir>", "Plugins will be installed to dir\n(default PREFIX/plugins)"); + desc( "-importdir <dir>", "Imports for QML will be installed to dir\n(default PREFIX/imports)"); desc( "-datadir <dir>", "Data used by Qt programs will be installed to dir\n(default PREFIX)"); desc( "-translationdir <dir>","Translations of Qt programs will be installed to dir\n(default PREFIX/translations)\n"); desc( "-examplesdir <dir>", "Examples will be installed to dir\n(default PREFIX/examples)"); @@ -1826,7 +1860,6 @@ bool Configure::displayHelp() desc("CETEST", "yes", "-cetest", "Compile Windows CE remote test application"); desc( "-signature <file>", "Use file for signing the target project"); desc("OPENGL_ES_CM", "no", "-opengl-es-cm", "Enable support for OpenGL ES Common"); - desc("OPENGL_ES_CL", "no", "-opengl-es-cl", "Enable support for OpenGL ES Common Lite"); desc("OPENGL_ES_2", "no", "-opengl-es-2", "Enable support for OpenGL ES 2.0"); desc("DIRECTSHOW", "no", "-phonon-wince-ds9", "Enable Phonon Direct Show 9 backend for Windows CE"); @@ -1872,12 +1905,20 @@ bool Configure::findFile( const QString &fileName ) const QString file = fileName.toLower(); const QString pathEnvVar = QString::fromLocal8Bit(getenv("PATH")); const QString mingwPath = dictionary["QMAKESPEC"].endsWith("-g++") ? - findFileInPaths("mingw32-g++.exe", pathEnvVar) : QString(); + findFileInPaths("g++.exe", pathEnvVar) : QString(); QString paths; if (file.endsWith(".h")) { - if (!mingwPath.isNull() && !findFileInPaths(file, mingwPath + QLatin1String("/../include")).isNull()) - return true; + if (!mingwPath.isNull()) { + if (!findFileInPaths(file, mingwPath + QLatin1String("/../include")).isNull()) + return true; + //now let's try the additional compiler path + QDir mingwLibDir = mingwPath + QLatin1String("/../lib/gcc/mingw32"); + foreach(const QFileInfo &version, mingwLibDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { + if (!findFileInPaths(file, version.absoluteFilePath() + QLatin1String("/include")).isNull()) + return true; + } + } paths = QString::fromLocal8Bit(getenv("INCLUDE")); } else if ( file.endsWith( ".lib" ) || file.endsWith( ".a" ) ) { if (!mingwPath.isNull() && !findFileInPaths(file, mingwPath + QLatin1String("/../lib")).isNull()) @@ -1956,7 +1997,7 @@ bool Configure::checkAvailability(const QString &part) { bool available = false; if (part == "STYLE_WINDOWSXP") - available = (findFile("uxtheme.h")); + available = findFile("uxtheme.h"); else if (part == "ZLIB") available = findFile("zlib.h"); @@ -2007,18 +2048,16 @@ bool Configure::checkAvailability(const QString &part) available = (dictionary[ "ARCHITECTURE" ] == "windowsce"); else if (part == "OPENGL_ES_CM") available = (dictionary[ "ARCHITECTURE" ] == "windowsce"); - else if (part == "OPENGL_ES_CL") - available = (dictionary[ "ARCHITECTURE" ] == "windowsce"); else if (part == "OPENGL_ES_2") available = (dictionary[ "ARCHITECTURE" ] == "windowsce"); else if (part == "DIRECTSHOW") available = (dictionary[ "ARCHITECTURE" ] == "windowsce"); else if (part == "SSE2") - available = (dictionary.value("QMAKESPEC") != "win32-msvc") && (dictionary.value("QMAKESPEC") != "win32-g++"); + available = (dictionary.value("QMAKESPEC") != "win32-msvc"); else if (part == "3DNOW" ) - available = (dictionary.value("QMAKESPEC") != "win32-msvc") && (dictionary.value("QMAKESPEC") != "win32-icc") && findFile("mm3dnow.h") && (dictionary.value("QMAKESPEC") != "win32-g++"); + available = (dictionary.value("QMAKESPEC") != "win32-msvc") && (dictionary.value("QMAKESPEC") != "win32-icc") && findFile("mm3dnow.h"); else if (part == "MMX" || part == "SSE") - available = (dictionary.value("QMAKESPEC") != "win32-msvc") && (dictionary.value("QMAKESPEC") != "win32-g++"); + available = (dictionary.value("QMAKESPEC") != "win32-msvc"); else if (part == "OPENSSL") available = findFile("openssl\\ssl.h"); else if (part == "DBUS") @@ -2047,29 +2086,33 @@ bool Configure::checkAvailability(const QString &part) && dictionary.value("QMAKESPEC") != "win32-msvc2002" && dictionary.value("EXCEPTIONS") == "yes"; } else if (part == "PHONON") { - available = findFile("vmr9.h") && findFile("dshow.h") && findFile("dmo.h") && findFile("dmodshow.h") - && (findFile("strmiids.lib") || findFile("libstrmiids.a")) - && (findFile("dmoguids.lib") || findFile("libdmoguids.a")) - && (findFile("msdmo.lib") || findFile("libmsdmo.a")) - && findFile("d3d9.h"); - - if (!available) { - cout << "All the required DirectShow/Direct3D files couldn't be found." << endl - << "Make sure you have either the platform SDK AND the DirectShow SDK or the Windows SDK installed." << endl - << "If you have the DirectShow SDK installed, please make sure that you have run the <path to SDK>\\SetEnv.Cmd script." << endl; - if (!findFile("vmr9.h")) cout << "vmr9.h not found" << endl; - if (!findFile("dshow.h")) cout << "dshow.h not found" << endl; - if (!findFile("strmiids.lib")) cout << "strmiids.lib not found" << endl; - if (!findFile("dmoguids.lib")) cout << "dmoguids.lib not found" << endl; - if (!findFile("msdmo.lib")) cout << "msdmo.lib not found" << endl; - if (!findFile("d3d9.h")) cout << "d3d9.h not found" << endl; - } - } else if (part == "MULTIMEDIA" || part == "SCRIPT" || part == "SCRIPTTOOLS") { + if (dictionary.contains("XQMAKESPEC") && dictionary["XQMAKESPEC"].startsWith("symbian")) { + available = true; + } else { + available = findFile("vmr9.h") && findFile("dshow.h") && findFile("dmo.h") && findFile("dmodshow.h") + && (findFile("strmiids.lib") || findFile("libstrmiids.a")) + && (findFile("dmoguids.lib") || findFile("libdmoguids.a")) + && (findFile("msdmo.lib") || findFile("libmsdmo.a")) + && findFile("d3d9.h"); + + if (!available) { + cout << "All the required DirectShow/Direct3D files couldn't be found." << endl + << "Make sure you have either the platform SDK AND the DirectShow SDK or the Windows SDK installed." << endl + << "If you have the DirectShow SDK installed, please make sure that you have run the <path to SDK>\\SetEnv.Cmd script." << endl; + if (!findFile("vmr9.h")) cout << "vmr9.h not found" << endl; + if (!findFile("dshow.h")) cout << "dshow.h not found" << endl; + if (!findFile("strmiids.lib")) cout << "strmiids.lib not found" << endl; + if (!findFile("dmoguids.lib")) cout << "dmoguids.lib not found" << endl; + if (!findFile("msdmo.lib")) cout << "msdmo.lib not found" << endl; + if (!findFile("d3d9.h")) cout << "d3d9.h not found" << endl; + } + } + } else if (part == "WMSDK") { + available = findFile("wmsdk.h"); + } else if (part == "MULTIMEDIA" || part == "SCRIPT" || part == "SCRIPTTOOLS" || part == "DECLARATIVE") { available = true; } else if (part == "WEBKIT") { - available = (dictionary.value("QMAKESPEC") == "win32-msvc2005") || (dictionary.value("QMAKESPEC") == "win32-msvc2008") || (dictionary.value("QMAKESPEC") == "win32-g++"); - } else if (part == "DECLARATIVE") { - available = QFile::exists(sourcePath + "/src/declarative/qml/qmlcomponent.h"); + available = (dictionary.value("QMAKESPEC") == "win32-msvc2005") || (dictionary.value("QMAKESPEC") == "win32-msvc2008") || (dictionary.value("QMAKESPEC") == "win32-msvc2010") || (dictionary.value("QMAKESPEC") == "win32-g++"); } else if (part == "AUDIO_BACKEND") { available = true; if (dictionary.contains("XQMAKESPEC") && dictionary["XQMAKESPEC"].startsWith("symbian")) { @@ -2195,7 +2238,7 @@ void Configure::autoDetection() if (dictionary["SCRIPT"] == "auto") dictionary["SCRIPT"] = checkAvailability("SCRIPT") ? "yes" : "no"; if (dictionary["SCRIPTTOOLS"] == "auto") - dictionary["SCRIPTTOOLS"] = checkAvailability("SCRIPTTOOLS") ? "yes" : "no"; + dictionary["SCRIPTTOOLS"] = dictionary["SCRIPT"] == "yes" ? "yes" : "no"; if (dictionary["XMLPATTERNS"] == "auto") dictionary["XMLPATTERNS"] = checkAvailability("XMLPATTERNS") ? "yes" : "no"; if (dictionary["PHONON"] == "auto") @@ -2203,9 +2246,11 @@ void Configure::autoDetection() if (dictionary["WEBKIT"] == "auto") dictionary["WEBKIT"] = checkAvailability("WEBKIT") ? "yes" : "no"; if (dictionary["DECLARATIVE"] == "auto") - dictionary["DECLARATIVE"] = checkAvailability("DECLARATIVE") ? "yes" : "no"; + dictionary["DECLARATIVE"] = dictionary["SCRIPT"] == "yes" ? "yes" : "no"; if (dictionary["AUDIO_BACKEND"] == "auto") dictionary["AUDIO_BACKEND"] = checkAvailability("AUDIO_BACKEND") ? "yes" : "no"; + if (dictionary["WMSDK"] == "auto") + dictionary["WMSDK"] = checkAvailability("WMSDK") ? "yes" : "no"; // Qt/WinCE remote test application if (dictionary["CETEST"] == "auto") @@ -2249,15 +2294,23 @@ bool Configure::verifyConfiguration() if(_getch() == 3) // _Any_ keypress w/no echo(eat <Enter> for stdout) exit(0); // Exit cleanly for Ctrl+C } - if (0 != dictionary["ARM_FPU_TYPE"].size()) - { - QStringList l= QStringList() - << "softvfp" - << "softvfp+vfpv2" - << "vfpv2"; - if (!(l.contains(dictionary["ARM_FPU_TYPE"]))) - cout << QString("WARNING: Using unsupported fpu flag: %1").arg(dictionary["ARM_FPU_TYPE"]) << endl; - } + if (0 != dictionary["ARM_FPU_TYPE"].size()) { + QStringList l= QStringList() + << "softvfp" + << "softvfp+vfpv2" + << "vfpv2"; + if (!(l.contains(dictionary["ARM_FPU_TYPE"]))) + cout << QString("WARNING: Using unsupported fpu flag: %1").arg(dictionary["ARM_FPU_TYPE"]) << endl; + } + if (dictionary["DECLARATIVE"] == "yes" && dictionary["SCRIPT"] == "no") { + cout << "WARNING: To be able to compile QtDeclarative we need to also compile the" << endl + << "QtScript module. If you continue, we will turn on the QtScript module." << endl + << "(Press any key to continue..)"; + if(_getch() == 3) // _Any_ keypress w/no echo(eat <Enter> for stdout) + exit(0); // Exit cleanly for Ctrl+C + + dictionary["SCRIPT"] = "yes"; + } return true; } @@ -2330,7 +2383,7 @@ void Configure::generateBuildKey() + buildSymbianKey + "\"\n" "#else\n" // Debug builds - "# if (defined(_DEBUG) || defined(DEBUG))\n" + "# if (!QT_NO_DEBUG)\n" "# if (defined(WIN64) || defined(_WIN64) || defined(__WIN64__))\n" + build64Key.arg("debug") + "\"\n" "# else\n" @@ -2541,11 +2594,6 @@ void Configure::generateOutputVars() qtConfig += "egl"; } - if ( dictionary["OPENGL_ES_CL"] == "yes" ) { - qtConfig += "opengles1cl"; - qtConfig += "egl"; - } - if ( dictionary["OPENVG"] == "yes" ) { qtConfig += "openvg"; qtConfig += "egl"; @@ -2606,8 +2654,14 @@ void Configure::generateOutputVars() if (dictionary["WEBKIT"] == "yes") qtConfig += "webkit"; - if (dictionary["DECLARATIVE"] == "yes") + if (dictionary["DECLARATIVE"] == "yes") { + if (dictionary[ "SCRIPT" ] == "no") { + cout << "QtDeclarative was requested, but it can't be built due to QtScript being " + "disabled." << endl; + dictionary[ "DONE" ] = "error"; + } qtConfig += "declarative"; + } if( dictionary[ "NATIVE_GESTURES" ] == "yes" ) qtConfig += "native-gestures"; @@ -2653,6 +2707,8 @@ void Configure::generateOutputVars() dictionary[ "QT_INSTALL_BINS" ] = qipempty ? "" : fixSeparators( dictionary[ "QT_INSTALL_PREFIX" ] + "/bin" ); if( !dictionary[ "QT_INSTALL_PLUGINS" ].size() ) dictionary[ "QT_INSTALL_PLUGINS" ] = qipempty ? "" : fixSeparators( dictionary[ "QT_INSTALL_PREFIX" ] + "/plugins" ); + if( !dictionary[ "QT_INSTALL_IMPORTS" ].size() ) + dictionary[ "QT_INSTALL_IMPORTS" ] = qipempty ? "" : fixSeparators( dictionary[ "QT_INSTALL_PREFIX" ] + "/imports" ); if( !dictionary[ "QT_INSTALL_DATA" ].size() ) dictionary[ "QT_INSTALL_DATA" ] = qipempty ? "" : fixSeparators( dictionary[ "QT_INSTALL_PREFIX" ] ); if( !dictionary[ "QT_INSTALL_TRANSLATIONS" ].size() ) @@ -2855,6 +2911,9 @@ void Configure::generateCachefile() if(!dictionary["ARM_FPU_TYPE"].isEmpty()) { configStream<<"MMP_RULES += \"ARMFPU "<< dictionary["ARM_FPU_TYPE"]<< "\""; } + if (!dictionary["QT_NAMESPACE"].isEmpty()) { + configStream << "#namespaces" << endl << "QT_NAMESPACE = " << dictionary["QT_NAMESPACE"] << endl; + } configStream.flush(); configFile.close(); @@ -2998,14 +3057,15 @@ void Configure::generateConfigfiles() if(dictionary["S60"] == "no") qconfigList += "QT_NO_S60"; if(dictionary["NATIVE_GESTURES"] == "no") qconfigList += "QT_NO_NATIVE_GESTURES"; + if(dictionary["OPENGL_ES_CM"] == "no" && + dictionary["OPENGL_ES_2"] == "no" && + dictionary["OPENVG"] == "no") qconfigList += "QT_NO_EGL"; + if(dictionary["OPENGL_ES_CM"] == "yes" || - dictionary["OPENGL_ES_CL"] == "yes" || dictionary["OPENGL_ES_2"] == "yes") qconfigList += "QT_OPENGL_ES"; if(dictionary["OPENGL_ES_CM"] == "yes") qconfigList += "QT_OPENGL_ES_1"; if(dictionary["OPENGL_ES_2"] == "yes") qconfigList += "QT_OPENGL_ES_2"; - if(dictionary["OPENGL_ES_CL"] == "yes") qconfigList += "QT_OPENGL_ES_1_CL"; - if(dictionary["SQL_MYSQL"] == "yes") qconfigList += "QT_SQL_MYSQL"; if(dictionary["SQL_ODBC"] == "yes") qconfigList += "QT_SQL_ODBC"; if(dictionary["SQL_OCI"] == "yes") qconfigList += "QT_SQL_OCI"; @@ -3159,6 +3219,7 @@ void Configure::generateConfigfiles() << "static const char qt_configure_libraries_path_str [512 + 12] = \"qt_libspath=" << QString(dictionary["QT_INSTALL_LIBS"]).replace( "\\", "\\\\" ) << "\";" << endl << "static const char qt_configure_binaries_path_str [512 + 12] = \"qt_binspath=" << QString(dictionary["QT_INSTALL_BINS"]).replace( "\\", "\\\\" ) << "\";" << endl << "static const char qt_configure_plugins_path_str [512 + 12] = \"qt_plugpath=" << QString(dictionary["QT_INSTALL_PLUGINS"]).replace( "\\", "\\\\" ) << "\";" << endl + << "static const char qt_configure_imports_path_str [512 + 12] = \"qt_impspath=" << QString(dictionary["QT_INSTALL_IMPORTS"]).replace( "\\", "\\\\" ) << "\";" << endl << "static const char qt_configure_data_path_str [512 + 12] = \"qt_datapath=" << QString(dictionary["QT_INSTALL_DATA"]).replace( "\\", "\\\\" ) << "\";" << endl << "static const char qt_configure_translations_path_str [512 + 12] = \"qt_trnspath=" << QString(dictionary["QT_INSTALL_TRANSLATIONS"]).replace( "\\", "\\\\" ) << "\";" << endl << "static const char qt_configure_examples_path_str [512 + 12] = \"qt_xmplpath=" << QString(dictionary["QT_INSTALL_EXAMPLES"]).replace( "\\", "\\\\" ) << "\";" << endl @@ -3173,6 +3234,7 @@ void Configure::generateConfigfiles() << "static const char qt_configure_libraries_path_str [512 + 12] = \"qt_libspath=" << fixSeparators(dictionary[ "QT_HOST_PREFIX" ] + "/lib").replace( "\\", "\\\\" ) <<"\";" << endl << "static const char qt_configure_binaries_path_str [512 + 12] = \"qt_binspath=" << fixSeparators(dictionary[ "QT_HOST_PREFIX" ] + "/bin").replace( "\\", "\\\\" ) <<"\";" << endl << "static const char qt_configure_plugins_path_str [512 + 12] = \"qt_plugpath=" << fixSeparators(dictionary[ "QT_HOST_PREFIX" ] + "/plugins").replace( "\\", "\\\\" ) <<"\";" << endl + << "static const char qt_configure_imports_path_str [512 + 12] = \"qt_impspath=" << fixSeparators(dictionary[ "QT_HOST_PREFIX" ] + "/imports").replace( "\\", "\\\\" ) <<"\";" << endl << "static const char qt_configure_data_path_str [512 + 12] = \"qt_datapath=" << fixSeparators(dictionary[ "QT_HOST_PREFIX" ]).replace( "\\", "\\\\" ) <<"\";" << endl << "static const char qt_configure_translations_path_str [512 + 12] = \"qt_trnspath=" << fixSeparators(dictionary[ "QT_HOST_PREFIX" ] + "/translations").replace( "\\", "\\\\" ) <<"\";" << endl << "static const char qt_configure_examples_path_str [512 + 12] = \"qt_xmplpath=" << fixSeparators(dictionary[ "QT_HOST_PREFIX" ] + "/example").replace( "\\", "\\\\" ) <<"\";" << endl @@ -3188,6 +3250,7 @@ void Configure::generateConfigfiles() << "#define QT_CONFIGURE_LIBRARIES_PATH qt_configure_libraries_path_str + 12;" << endl << "#define QT_CONFIGURE_BINARIES_PATH qt_configure_binaries_path_str + 12;" << endl << "#define QT_CONFIGURE_PLUGINS_PATH qt_configure_plugins_path_str + 12;" << endl + << "#define QT_CONFIGURE_IMPORTS_PATH qt_configure_imports_path_str + 12;" << endl << "#define QT_CONFIGURE_DATA_PATH qt_configure_data_path_str + 12;" << endl << "#define QT_CONFIGURE_TRANSLATIONS_PATH qt_configure_translations_path_str + 12;" << endl << "#define QT_CONFIGURE_EXAMPLES_PATH qt_configure_examples_path_str + 12;" << endl @@ -3334,6 +3397,7 @@ void Configure::displayConfig() cout << "Headers installed to........" << dictionary[ "QT_INSTALL_HEADERS" ] << endl; cout << "Libraries installed to......" << dictionary[ "QT_INSTALL_LIBS" ] << endl; cout << "Plugins installed to........" << dictionary[ "QT_INSTALL_PLUGINS" ] << endl; + cout << "Imports installed to........" << dictionary[ "QT_INSTALL_IMPORTS" ] << endl; cout << "Binaries installed to......." << dictionary[ "QT_INSTALL_BINS" ] << endl; cout << "Docs installed to..........." << dictionary[ "QT_INSTALL_DOCS" ] << endl; cout << "Data installed to..........." << dictionary[ "QT_INSTALL_DATA" ] << endl; @@ -3393,7 +3457,7 @@ void Configure::displayConfig() cout << "NOTE: When linking against OpenSSL, you can override the default" << endl; cout << "library names through OPENSSL_LIBS." << endl; cout << "For example:" << endl; - cout << " configure -openssl-linked OPENSSL_LIBS='-lssleay32 -llibeay32'" << endl; + cout << " configure -openssl-linked OPENSSL_LIBS=\"-lssleay32 -llibeay32\"" << endl; } if( dictionary[ "ZLIB_FORCED" ] == "yes" ) { QString which_zlib = "supplied"; @@ -3464,14 +3528,15 @@ void Configure::buildQmake() args += makefile; cout << "Creating qmake..." << endl; - int exitCode = 0; - if( exitCode = Environment::execute(args, QStringList(), QStringList()) ) { + int exitCode = Environment::execute(args, QStringList(), QStringList()); + if( exitCode ) { args.clear(); args += dictionary[ "MAKE" ]; args += "-f"; args += makefile; args += "clean"; - if( exitCode = Environment::execute(args, QStringList(), QStringList())) { + exitCode = Environment::execute(args, QStringList(), QStringList()); + if(exitCode) { cout << "Cleaning qmake failed, return code " << exitCode << endl << endl; dictionary[ "DONE" ] = "error"; } else { @@ -3479,7 +3544,8 @@ void Configure::buildQmake() args += dictionary[ "MAKE" ]; args += "-f"; args += makefile; - if (exitCode = Environment::execute(args, QStringList(), QStringList())) { + exitCode = Environment::execute(args, QStringList(), QStringList()); + if (exitCode) { cout << "Building qmake failed, return code " << exitCode << endl << endl; dictionary[ "DONE" ] = "error"; } @@ -3523,8 +3589,8 @@ void Configure::buildHostTools() QDir().mkpath(toolBuildPath); QDir::setCurrent(toolSourcePath); - int exitCode = 0; - if (exitCode = Environment::execute(args, QStringList(), QStringList())) { + int exitCode = Environment::execute(args, QStringList(), QStringList()); + if (exitCode) { cout << "qmake failed, return code " << exitCode << endl << endl; dictionary["DONE"] = "error"; break; @@ -3534,18 +3600,21 @@ void Configure::buildHostTools() args.clear(); args += dictionary["MAKE"]; QDir::setCurrent(toolBuildPath); - if (exitCode = Environment::execute(args, QStringList(), QStringList())) { + exitCode = Environment::execute(args, QStringList(), QStringList()); + if (exitCode) { args.clear(); args += dictionary["MAKE"]; args += "clean"; - if(exitCode = Environment::execute(args, QStringList(), QStringList())) { + exitCode = Environment::execute(args, QStringList(), QStringList()); + if(exitCode) { cout << "Cleaning " << hostToolsDirs.at(i) << " failed, return code " << exitCode << endl << endl; dictionary["DONE"] = "error"; break; } else { args.clear(); args += dictionary["MAKE"]; - if (exitCode = Environment::execute(args, QStringList(), QStringList())) { + exitCode = Environment::execute(args, QStringList(), QStringList()); + if (exitCode) { cout << "Building " << hostToolsDirs.at(i) << " failed, return code " << exitCode << endl << endl; dictionary["DONE"] = "error"; break; diff --git a/tools/configure/environment.cpp b/tools/configure/environment.cpp index e93f9a0..943a8a2 100644 --- a/tools/configure/environment.cpp +++ b/tools/configure/environment.cpp @@ -73,13 +73,14 @@ struct CompilerInfo{ } compiler_info[] = { // The compilers here are sorted in a reversed-preferred order {CC_BORLAND, "Borland C++", 0, "bcc32.exe"}, - {CC_MINGW, "MinGW (Minimalist GNU for Windows)", 0, "mingw32-gcc.exe"}, + {CC_MINGW, "MinGW (Minimalist GNU for Windows)", 0, "g++.exe"}, {CC_INTEL, "Intel(R) C++ Compiler for 32-bit applications", 0, "icl.exe"}, // xilink.exe, xilink5.exe, xilink6.exe, xilib.exe {CC_MSVC6, "Microsoft (R) 32-bit C/C++ Optimizing Compiler (6.x)", "Software\\Microsoft\\VisualStudio\\6.0\\Setup\\Microsoft Visual C++\\ProductDir", "cl.exe"}, // link.exe, lib.exe {CC_NET2002, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2002 (7.0)", "Software\\Microsoft\\VisualStudio\\7.0\\Setup\\VC\\ProductDir", "cl.exe"}, // link.exe, lib.exe {CC_NET2003, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2003 (7.1)", "Software\\Microsoft\\VisualStudio\\7.1\\Setup\\VC\\ProductDir", "cl.exe"}, // link.exe, lib.exe {CC_NET2005, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2005 (8.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\8.0", "cl.exe"}, // link.exe, lib.exe {CC_NET2008, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2008 (9.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\9.0", "cl.exe"}, // link.exe, lib.exe + {CC_NET2010, "Microsoft (R) 32-bit C/C++ Optimizing Compiler.NET 2010 (10.0)", "Software\\Microsoft\\VisualStudio\\SxS\\VC7\\10.0", "cl.exe"}, // link.exe, lib.exe {CC_UNKNOWN, "Unknown", 0, 0}, }; @@ -105,6 +106,9 @@ QString Environment::detectQMakeSpec() { QString spec; switch (detectCompiler()) { + case CC_NET2010: + spec = "win32-msvc2010"; + break; case CC_NET2008: spec = "win32-msvc2008"; break; @@ -357,7 +361,7 @@ int Environment::execute(QStringList arguments, const QStringList &additionalEnv QString args = qt_create_commandline(program, arguments); QByteArray envlist = qt_create_environment(fullEnv); - DWORD exitCode = -1; + DWORD exitCode = DWORD(-1); PROCESS_INFORMATION procInfo; memset(&procInfo, 0, sizeof(procInfo)); @@ -378,7 +382,7 @@ int Environment::execute(QStringList arguments, const QStringList &additionalEnv } - if (exitCode == -1) { + if (exitCode == DWORD(-1)) { switch(GetLastError()) { case E2BIG: cerr << "execute: Argument list exceeds 1024 bytes" << endl; diff --git a/tools/configure/environment.h b/tools/configure/environment.h index b1cbe3a..16af8df 100644 --- a/tools/configure/environment.h +++ b/tools/configure/environment.h @@ -56,7 +56,8 @@ enum Compiler { CC_NET2002 = 0x70, CC_NET2003 = 0x71, CC_NET2005 = 0x80, - CC_NET2008 = 0x90 + CC_NET2008 = 0x90, + CC_NET2010 = 0x91 }; struct CompilerInfo; diff --git a/tools/designer/src/components/formeditor/formeditor.pri b/tools/designer/src/components/formeditor/formeditor.pri index bbe96d5..b1a9318 100644 --- a/tools/designer/src/components/formeditor/formeditor.pri +++ b/tools/designer/src/components/formeditor/formeditor.pri @@ -8,6 +8,7 @@ FORMS += $$PWD/deviceprofiledialog.ui \ $$PWD/templateoptionspage.ui HEADERS += $$PWD/qdesigner_resource.h \ + $$PWD/qdesignerundostack.h \ $$PWD/formwindow.h \ $$PWD/formwindow_widgetstack.h \ $$PWD/formwindow_dnditem.h \ @@ -41,6 +42,7 @@ HEADERS += $$PWD/qdesigner_resource.h \ $$PWD/templateoptionspage.h SOURCES += $$PWD/qdesigner_resource.cpp \ + $$PWD/qdesignerundostack.cpp \ $$PWD/formwindow.cpp \ $$PWD/formwindow_widgetstack.cpp \ $$PWD/formwindow_dnditem.cpp \ diff --git a/tools/designer/src/components/formeditor/formeditor.qrc b/tools/designer/src/components/formeditor/formeditor.qrc index 83cc9c7..6510814 100644 --- a/tools/designer/src/components/formeditor/formeditor.qrc +++ b/tools/designer/src/components/formeditor/formeditor.qrc @@ -63,6 +63,7 @@ <file>images/qtlogo.png</file> <file>images/qt3logo.png</file> <file>images/resetproperty.png</file> + <file>images/cleartext.png</file> <file>images/sort.png</file> <file>images/edit.png</file> <file>images/reload.png</file> diff --git a/tools/designer/src/components/formeditor/formwindow.cpp b/tools/designer/src/components/formeditor/formwindow.cpp index 9fd084d..15775f6 100644 --- a/tools/designer/src/components/formeditor/formwindow.cpp +++ b/tools/designer/src/components/formeditor/formwindow.cpp @@ -399,8 +399,7 @@ void FormWindow::setCursorToAll(const QCursor &c, QWidget *start) void FormWindow::init() { if (FormWindowManager *manager = qobject_cast<FormWindowManager*> (core()->formWindowManager())) { - m_commandHistory = new QUndoStack(this); - manager->undoGroup()->addStack(m_commandHistory); + manager->undoGroup()->addStack(m_undoStack.qundoStack()); } m_blockSelectionChanged = false; @@ -429,9 +428,8 @@ void FormWindow::init() m_mainContainer = 0; m_currentWidget = 0; - connect(m_commandHistory, SIGNAL(indexChanged(int)), this, SLOT(updateDirty())); - connect(m_commandHistory, SIGNAL(indexChanged(int)), this, SIGNAL(changed())); - connect(m_commandHistory, SIGNAL(indexChanged(int)), this, SLOT(checkSelection())); + connect(&m_undoStack, SIGNAL(changed()), this, SIGNAL(changed())); + connect(&m_undoStack, SIGNAL(changed()), this, SLOT(checkSelection())); core()->metaDataBase()->add(this); @@ -484,6 +482,7 @@ void FormWindow::setMainContainer(QWidget *w) sheet->setVisible(sheet->indexOf(QLatin1String("windowTitle")), true); sheet->setVisible(sheet->indexOf(QLatin1String("windowIcon")), true); sheet->setVisible(sheet->indexOf(QLatin1String("windowModality")), true); + sheet->setVisible(sheet->indexOf(QLatin1String("windowOpacity")), true); sheet->setVisible(sheet->indexOf(QLatin1String("windowFilePath")), true); // ### generalize } @@ -1226,14 +1225,14 @@ void FormWindow::insertWidget(QWidget *w, const QRect &rect, QWidget *container, if (w->parentWidget() != container) { ReparentWidgetCommand *cmd = new ReparentWidgetCommand(this); cmd->init(w, container); - m_commandHistory->push(cmd); + m_undoStack.push(cmd); } - m_commandHistory->push(geom_cmd); + m_undoStack.push(geom_cmd); InsertWidgetCommand *cmd = new InsertWidgetCommand(this); cmd->init(w, already_in_form); - m_commandHistory->push(cmd); + m_undoStack.push(cmd); endCommand(); @@ -1276,12 +1275,10 @@ void FormWindow::resizeWidget(QWidget *widget, const QRect &geometry) Q_ASSERT(isDescendant(this, widget)); QRect r = geometry; - if (m_lastIndex > m_commandHistory->index()) - m_lastIndex = -1; SetPropertyCommand *cmd = new SetPropertyCommand(this); cmd->init(widget, QLatin1String("geometry"), r); cmd->setText(tr("Resize")); - m_commandHistory->push(cmd); + m_undoStack.push(cmd); } void FormWindow::raiseChildSelections(QWidget *w) @@ -1427,26 +1424,125 @@ int FormWindow::calcValue(int val, bool forward, bool snap, int snapOffset) cons return (forward ? val + 1 : val - 1); } -QRect FormWindow::applyValue(const QRect &rect, int val, int key, bool size) const +// ArrowKeyOperation: Stores a keyboard move or resize (Shift pressed) +// operation. +struct ArrowKeyOperation { + ArrowKeyOperation() : resize(false), distance(0), arrowKey(Qt::Key_Left) {} + + QRect apply(const QRect &in) const; + + bool resize; // Resize: Shift-Key->drag bottom/right corner, else just move + int distance; + int arrowKey; +}; + +} // namespace + +QT_END_NAMESPACE +Q_DECLARE_METATYPE(qdesigner_internal::ArrowKeyOperation) +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +QRect ArrowKeyOperation::apply(const QRect &rect) const { QRect r = rect; - if (size) { - if (key == Qt::Key_Left || key == Qt::Key_Right) - r.setWidth(val); + if (resize) { + if (arrowKey == Qt::Key_Left || arrowKey == Qt::Key_Right) + r.setWidth(r.width() + distance); else - r.setHeight(val); + r.setHeight(r.height() + distance); } else { - if (key == Qt::Key_Left || key == Qt::Key_Right) - r.moveLeft(val); + if (arrowKey == Qt::Key_Left || arrowKey == Qt::Key_Right) + r.moveLeft(r.x() + distance); else - r.moveTop(val); + r.moveTop(r.y() + distance); } return r; } +QDebug operator<<(QDebug in, const ArrowKeyOperation &op) +{ + in.nospace() << "Resize=" << op.resize << " dist=" << op.distance << " Key=" << op.arrowKey << ' '; + return in; +} + +// ArrowKeyPropertyHelper: Applies a struct ArrowKeyOperation +// (stored as new value) to a list of widgets using to calculate the +// changed geometry of the widget in setValue(). Thus, the 'newValue' +// of the property command is the relative move distance, which is the same +// for all widgets (although resulting in different geometries for the widgets). +// The command merging can then work as it would when applying the same text +// to all QLabels. + +class ArrowKeyPropertyHelper : public PropertyHelper { +public: + ArrowKeyPropertyHelper(QObject* o, SpecialProperty sp, + QDesignerPropertySheetExtension *s, int i) : + PropertyHelper(o, sp, s, i) {} + + virtual Value setValue(QDesignerFormWindowInterface *fw, const QVariant &value, bool changed, unsigned subPropertyMask); +}; + +PropertyHelper::Value ArrowKeyPropertyHelper::setValue(QDesignerFormWindowInterface *fw, const QVariant &value, bool changed, unsigned subPropertyMask) +{ + // Apply operation to obtain the new geometry value. + QWidget *w = qobject_cast<QWidget*>(object()); + const ArrowKeyOperation operation = qvariant_cast<ArrowKeyOperation>(value); + const QRect newGeom = operation.apply(w->geometry()); + return PropertyHelper::setValue(fw, QVariant(newGeom), changed, subPropertyMask); +} + +// ArrowKeyPropertyCommand: Helper factory overwritten to create +// ArrowKeyPropertyHelper and a merge operation that merges values of +// the same direction. +class ArrowKeyPropertyCommand: public SetPropertyCommand { +public: + explicit ArrowKeyPropertyCommand(QDesignerFormWindowInterface *fw, + QUndoCommand *p = 0); + + void init(QWidgetList &l, const ArrowKeyOperation &op); + +protected: + virtual PropertyHelper *createPropertyHelper(QObject *o, SpecialProperty sp, + QDesignerPropertySheetExtension *s, int i) const + { return new ArrowKeyPropertyHelper(o, sp, s, i); } + virtual QVariant mergeValue(const QVariant &newValue); +}; + +ArrowKeyPropertyCommand::ArrowKeyPropertyCommand(QDesignerFormWindowInterface *fw, + QUndoCommand *p) : + SetPropertyCommand(fw, p) +{ + static const int mid = qRegisterMetaType<qdesigner_internal::ArrowKeyOperation>(); + Q_UNUSED(mid) +} + +void ArrowKeyPropertyCommand::init(QWidgetList &l, const ArrowKeyOperation &op) +{ + QObjectList ol; + foreach(QWidget *w, l) + ol.push_back(w); + SetPropertyCommand::init(ol, QLatin1String("geometry"), qVariantFromValue(op)); + + setText(op.resize ? FormWindow::tr("Key Resize") : FormWindow::tr("Key Move")); +} + +QVariant ArrowKeyPropertyCommand::mergeValue(const QVariant &newMergeValue) +{ + // Merge move operations of the same arrow key + if (!qVariantCanConvert<ArrowKeyOperation>(newMergeValue)) + return QVariant(); + ArrowKeyOperation mergedOperation = qvariant_cast<ArrowKeyOperation>(newValue()); + const ArrowKeyOperation newMergeOperation = qvariant_cast<ArrowKeyOperation>(newMergeValue); + if (mergedOperation.resize != newMergeOperation.resize || mergedOperation.arrowKey != newMergeOperation.arrowKey) + return QVariant(); + mergedOperation.distance += newMergeOperation.distance; + return qVariantFromValue(mergedOperation); +} + void FormWindow::handleArrowKeyEvent(int key, Qt::KeyboardModifiers modifiers) { - bool startMacro = false; const QDesignerFormWindowCursorInterface *c = cursor(); if (!c->hasSelection()) return; @@ -1479,57 +1575,14 @@ void FormWindow::handleArrowKeyEvent(int key, Qt::KeyboardModifiers modifiers) const int newValue = calcValue(oldValue, forward, snap, snapPoint); - const int offset = newValue - oldValue; - - const int selCount = selection.count(); - // check if selection is the same as last time - if (selCount != m_moveSelection.count() || - m_lastUndoIndex != m_commandHistory->index()) { - m_moveSelection.clear(); - startMacro = true; - } else { - for (int index = 0; index < selCount; ++index) { - if (m_moveSelection[index]->object() != selection.at(index)) { - m_moveSelection.clear(); - startMacro = true; - break; - } - } - } - - if (startMacro) - beginCommand(tr("Key Move")); - - for (int index = 0; index < selCount; ++index) { - QWidget *w = selection.at(index); - const QRect oldGeom = w->geometry(); - const QRect geom = applyValue(oldGeom, getValue(oldGeom, key, size) + offset, key, size); - - SetPropertyCommand *cmd = 0; + ArrowKeyOperation operation; + operation.resize = modifiers & Qt::ShiftModifier; + operation.distance = newValue - oldValue; + operation.arrowKey = key; - if (m_moveSelection.count() > index) - cmd = m_moveSelection[index]; - - if (!cmd) { - cmd = new SetPropertyCommand(this); - cmd->init(w, QLatin1String("geometry"), geom); - cmd->setText(tr("Key Move")); - m_commandHistory->push(cmd); - - if (m_moveSelection.count() > index) - m_moveSelection.replace(index, cmd); - else - m_moveSelection.append(cmd); - } else { - cmd->setNewValue(geom); - cmd->redo(); - } - } - - if (startMacro) { - endCommand(); - m_lastUndoIndex = m_commandHistory->index(); - } + ArrowKeyPropertyCommand *cmd = new ArrowKeyPropertyCommand(this); + cmd->init(selection, operation); + m_undoStack.push(cmd); } bool FormWindow::handleKeyReleaseEvent(QWidget *, QWidget *, QKeyEvent *e) @@ -1808,7 +1861,7 @@ void FormWindow::paste(PasteMode pasteMode) foreach (QWidget *w, clipboard.m_widgets) { InsertWidgetCommand *cmd = new InsertWidgetCommand(this); cmd->init(w); - m_commandHistory->push(cmd); + m_undoStack.push(cmd); selectWidget(w); } } @@ -1818,7 +1871,7 @@ void FormWindow::paste(PasteMode pasteMode) ensureUniqueObjectName(a); AddActionCommand *cmd = new AddActionCommand(this); cmd->init(a); - m_commandHistory->push(cmd); + m_undoStack.push(cmd); } endCommand(); } while (false); @@ -1954,14 +2007,12 @@ void FormWindow::breakLayout(QWidget *w) void FormWindow::beginCommand(const QString &description) { - if (m_lastIndex > m_commandHistory->index()) - m_lastIndex = -1; - m_commandHistory->beginMacro(description); + m_undoStack.beginMacro(description); } void FormWindow::endCommand() { - m_commandHistory->endMacro(); + m_undoStack.endMacro(); } void FormWindow::raiseWidgets() @@ -1976,7 +2027,7 @@ void FormWindow::raiseWidgets() foreach (QWidget *widget, widgets) { RaiseWidgetCommand *cmd = new RaiseWidgetCommand(this); cmd->init(widget); - m_commandHistory->push(cmd); + m_undoStack.push(cmd); } endCommand(); } @@ -1993,7 +2044,7 @@ void FormWindow::lowerWidgets() foreach (QWidget *widget, widgets) { LowerWidgetCommand *cmd = new LowerWidgetCommand(this); cmd->init(widget); - m_commandHistory->push(cmd); + m_undoStack.push(cmd); } endCommand(); } @@ -2374,20 +2425,12 @@ FormWindow *FormWindow::findFormWindow(QWidget *w) bool FormWindow::isDirty() const { - return m_dirty; + return m_undoStack.isDirty(); } void FormWindow::setDirty(bool dirty) { - m_dirty = dirty; - - if (!m_dirty) - m_lastIndex = m_commandHistory->index(); -} - -void FormWindow::updateDirty() -{ - m_dirty = m_commandHistory->index() != m_lastIndex; + m_undoStack.setDirty(dirty); } QWidget *FormWindow::containerAt(const QPoint &pos) @@ -2756,7 +2799,7 @@ bool FormWindow::dropDockWidget(QDesignerDnDItemInterface *item, const QPoint &g qVariantSetValue(v, e); SetPropertyCommand *cmd = new SetPropertyCommand(this); cmd->init(widget, dockWidgetAreaName, v); - m_commandHistory->push(cmd); + m_undoStack.push(cmd); } endCommand(); @@ -2920,6 +2963,12 @@ QWidget *FormWindow::formContainer() const return m_widgetStack->formContainer(); } +QUndoStack *FormWindow::commandHistory() const +{ + return const_cast<QDesignerUndoStack &>(m_undoStack).qundoStack(); +} + } // namespace QT_END_NAMESPACE + diff --git a/tools/designer/src/components/formeditor/formwindow.h b/tools/designer/src/components/formeditor/formwindow.h index 3eee476..dc0026f 100644 --- a/tools/designer/src/components/formeditor/formwindow.h +++ b/tools/designer/src/components/formeditor/formwindow.h @@ -43,6 +43,7 @@ #define FORMWINDOW_H #include "formeditor_global.h" +#include "qdesignerundostack.h" #include <formwindowbase_p.h> // Qt @@ -64,7 +65,6 @@ class QLabel; class QTimer; class QAction; class QMenu; -class QUndoStack; class QRubberBand; namespace qdesigner_internal { @@ -165,9 +165,7 @@ public: void manageWidget(QWidget *w); void unmanageWidget(QWidget *w); - inline QUndoStack *commandHistory() const - { return m_commandHistory; } - + virtual QUndoStack *commandHistory() const; void beginCommand(const QString &description); void endCommand(); @@ -238,7 +236,6 @@ protected: private slots: void selectionChangedTimerDone(); - void updateDirty(); void checkSelection(); void checkSelectionNow(); void slotSelectWidget(QAction *); @@ -263,7 +260,6 @@ private: int getValue(const QRect &rect, int key, bool size) const; int calcValue(int val, bool forward, bool snap, int snapOffset) const; - QRect applyValue(const QRect &rect, int val, int key, bool size) const; void handleClickSelection(QWidget *managedWidget, unsigned mouseFlags); bool frameNeeded(QWidget *w) const; @@ -338,7 +334,7 @@ private: QPoint m_startPos; - QUndoStack *m_commandHistory; + QDesignerUndoStack m_undoStack; QString m_fileName; @@ -352,9 +348,6 @@ private: QTimer *m_checkSelectionTimer; QTimer *m_geometryChangedTimer; - int m_dirty; - int m_lastIndex; - FormWindowWidgetStack *m_widgetStack; WidgetEditorTool *m_widgetEditor; @@ -368,8 +361,6 @@ private: QString m_exportMacro; QStringList m_includeHints; - QList<SetPropertyCommand*> m_moveSelection; - int m_lastUndoIndex; QPoint m_contextMenuPosition; private: diff --git a/tools/designer/src/components/formeditor/formwindowmanager.cpp b/tools/designer/src/components/formeditor/formwindowmanager.cpp index 88b4ac5..ce809ff 100644 --- a/tools/designer/src/components/formeditor/formwindowmanager.cpp +++ b/tools/designer/src/components/formeditor/formwindowmanager.cpp @@ -523,10 +523,11 @@ void FormWindowManager::setupActions() connect(m_actionShowFormWindowSettingsDialog, SIGNAL(triggered()), this, SLOT(slotActionShowFormWindowSettingsDialog())); m_actionShowFormWindowSettingsDialog->setEnabled(false); - +#ifdef Q_WS_X11 m_actionCopy->setIcon(QIcon::fromTheme("edit-copy", m_actionCopy->icon())); m_actionCut->setIcon(QIcon::fromTheme("edit-cut", m_actionCut->icon())); m_actionPaste->setIcon(QIcon::fromTheme("edit-paste", m_actionPaste->icon())); + m_actionDelete->setIcon(QIcon::fromTheme("edit-delete", m_actionDelete->icon())); // These do not currently exist, but will allow theme authors to fill in the gaps m_actionBreakLayout->setIcon(QIcon::fromTheme("designer-break-layout", m_actionBreakLayout->icon())); @@ -536,6 +537,7 @@ void FormWindowManager::setupActions() m_actionSplitHorizontal->setIcon(QIcon::fromTheme("designer-split-horizontal", m_actionSplitHorizontal->icon())); m_actionSplitVertical->setIcon(QIcon::fromTheme("designer-split-vertical", m_actionSplitVertical->icon())); m_actionAdjustSize->setIcon(QIcon::fromTheme("designer-adjust-size", m_actionAdjustSize->icon())); +#endif } void FormWindowManager::slotActionCutActivated() diff --git a/tools/designer/src/components/formeditor/images/cleartext.png b/tools/designer/src/components/formeditor/images/cleartext.png Binary files differnew file mode 100644 index 0000000..74133ba --- /dev/null +++ b/tools/designer/src/components/formeditor/images/cleartext.png diff --git a/tools/designer/src/components/formeditor/qdesigner_resource.cpp b/tools/designer/src/components/formeditor/qdesigner_resource.cpp index b659179..1d78695 100644 --- a/tools/designer/src/components/formeditor/qdesigner_resource.cpp +++ b/tools/designer/src/components/formeditor/qdesigner_resource.cpp @@ -53,7 +53,6 @@ #include "qtresourcemodel_p.h" #include "qmdiarea_container.h" #include "qwizard_container.h" -#include "itemview_propertysheet.h" #include "layout_propertysheet.h" #include <ui4_p.h> @@ -106,8 +105,6 @@ #include <QtGui/QMenuBar> #include <QtGui/QFileDialog> #include <QtGui/QHeaderView> -#include <QtGui/QTreeView> -#include <QtGui/QTableView> #include <QtGui/QWizardPage> #include <private/qlayoutengine_p.h> @@ -1275,10 +1272,6 @@ DomWidget *QDesignerResource::createDom(QWidget *widget, DomWidget *ui_parentWid w = saveWidget(dockWidget, ui_parentWidget); else if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) w = saveWidget(widget, container, ui_parentWidget); - else if (QTreeView *treeView = qobject_cast<QTreeView*>(widget)) - w = saveWidget(treeView, ui_parentWidget); - else if (QTableView *tableView = qobject_cast<QTableView*>(widget)) - w = saveWidget(tableView, ui_parentWidget); else if (QWizardPage *wizardPage = qobject_cast<QWizardPage*>(widget)) w = saveWidget(wizardPage, ui_parentWidget); else @@ -1553,60 +1546,6 @@ DomWidget *QDesignerResource::saveWidget(QDesignerDockWidget *dockWidget, DomWid return ui_widget; } -DomWidget *QDesignerResource::saveWidget(QTreeView *treeView, DomWidget *ui_parentWidget) -{ - DomWidget *ui_widget = QAbstractFormBuilder::createDom(treeView, ui_parentWidget, true); - - QDesignerPropertySheetExtension *sheet - = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), treeView); - ItemViewPropertySheet *itemViewSheet = static_cast<ItemViewPropertySheet*>(sheet); - - if (itemViewSheet) { - QHash<QString,QString> nameMap = itemViewSheet->propertyNameMap(); - foreach (const QString &fakeName, nameMap.keys()) { - int index = itemViewSheet->indexOf(fakeName); - if (sheet->isChanged(index)) { - DomProperty *domAttr = createProperty(treeView->header(), nameMap.value(fakeName), - itemViewSheet->property(index)); - domAttr->setAttributeName(fakeName); - ui_widget->setElementAttribute(ui_widget->elementAttribute() << domAttr); - } - } - } - - return ui_widget; -} - -DomWidget *QDesignerResource::saveWidget(QTableView *tableView, DomWidget *ui_parentWidget) -{ - DomWidget *ui_widget = QAbstractFormBuilder::createDom(tableView, ui_parentWidget, true); - - QDesignerPropertySheetExtension *sheet - = qt_extension<QDesignerPropertySheetExtension*>(core()->extensionManager(), tableView); - ItemViewPropertySheet *itemViewSheet = static_cast<ItemViewPropertySheet*>(sheet); - - if (itemViewSheet) { - QHash<QString,QString> nameMap = itemViewSheet->propertyNameMap(); - foreach (const QString &fakeName, nameMap.keys()) { - int index = itemViewSheet->indexOf(fakeName); - if (sheet->isChanged(index)) { - DomProperty *domAttr; - if (fakeName.startsWith(QLatin1String("horizontal"))) { - domAttr = createProperty(tableView->horizontalHeader(), nameMap.value(fakeName), - itemViewSheet->property(index)); - } else { - domAttr = createProperty(tableView->verticalHeader(), nameMap.value(fakeName), - itemViewSheet->property(index)); - } - domAttr->setAttributeName(fakeName); - ui_widget->setElementAttribute(ui_widget->elementAttribute() << domAttr); - } - } - } - - return ui_widget; -} - static void saveStringProperty(DomProperty *property, const PropertySheetStringValue &value) { DomString *str = new DomString(); diff --git a/tools/designer/src/components/formeditor/qdesigner_resource.h b/tools/designer/src/components/formeditor/qdesigner_resource.h index 33b5b88..47dd263 100644 --- a/tools/designer/src/components/formeditor/qdesigner_resource.h +++ b/tools/designer/src/components/formeditor/qdesigner_resource.h @@ -64,8 +64,6 @@ class QTabWidget; class QStackedWidget; class QToolBox; class QToolBar; -class QTreeView; -class QTableView; class QDesignerDockWidget; class QLayoutWidget; class QWizardPage; @@ -138,8 +136,6 @@ protected: DomWidget *saveWidget(QWidget *widget, QDesignerContainerExtension *container, DomWidget *ui_parentWidget); DomWidget *saveWidget(QToolBar *toolBar, DomWidget *ui_parentWidget); DomWidget *saveWidget(QDesignerDockWidget *dockWidget, DomWidget *ui_parentWidget); - DomWidget *saveWidget(QTreeView *treeView, DomWidget *ui_parentWidget); - DomWidget *saveWidget(QTableView *tableView, DomWidget *ui_parentWidget); DomWidget *saveWidget(QWizardPage *wizardPage, DomWidget *ui_parentWidget); virtual DomCustomWidgets *saveCustomWidgets(); diff --git a/tools/designer/src/components/formeditor/qdesignerundostack.cpp b/tools/designer/src/components/formeditor/qdesignerundostack.cpp new file mode 100644 index 0000000..007031d --- /dev/null +++ b/tools/designer/src/components/formeditor/qdesignerundostack.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesignerundostack.h" + +#include <QtGui/QUndoStack> +#include <QtGui/QUndoCommand> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +QDesignerUndoStack::QDesignerUndoStack(QObject *parent) : + QObject(parent), + m_undoStack(new QUndoStack), + m_fakeDirty(false) +{ + connect(m_undoStack, SIGNAL(indexChanged(int)), this, SIGNAL(changed())); +} + +QDesignerUndoStack::~QDesignerUndoStack() +{ // QUndoStack is managed by the QUndoGroup +} + +void QDesignerUndoStack::push(QUndoCommand * cmd) +{ + m_undoStack->push(cmd); +} + +void QDesignerUndoStack::beginMacro(const QString &text) +{ + m_undoStack->beginMacro(text); +} + +void QDesignerUndoStack::endMacro() +{ + m_undoStack->endMacro(); +} + +int QDesignerUndoStack::index() const +{ + return m_undoStack->index(); +} + +const QUndoStack *QDesignerUndoStack::qundoStack() const +{ + return m_undoStack; +} +QUndoStack *QDesignerUndoStack::qundoStack() +{ + return m_undoStack; +} + +bool QDesignerUndoStack::isDirty() const +{ + return m_fakeDirty || !m_undoStack->isClean(); +} + +void QDesignerUndoStack::setDirty(bool v) +{ + if (isDirty() == v) + return; + if (v) { + m_fakeDirty = true; + emit changed(); + } else { + m_fakeDirty = false; + m_undoStack->setClean(); + } +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/assistant/compat/lib/qassistantclient.h b/tools/designer/src/components/formeditor/qdesignerundostack.h index fc8bb5b..5451ad8 100644 --- a/tools/assistant/compat/lib/qassistantclient.h +++ b/tools/designer/src/components/formeditor/qdesignerundostack.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Assistant of the Qt Toolkit. +** This file is part of the Qt Designer of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage @@ -39,62 +39,52 @@ ** ****************************************************************************/ -#ifndef QASSISTANTCLIENT_H -#define QASSISTANTCLIENT_H +#ifndef QDESIGNERUNDOSTACK_H +#define QDESIGNERUNDOSTACK_H #include <QtCore/QObject> -#include <QtCore/QStringList> -#include <QtCore/QProcess> -#include <QtCore/qglobal.h> -#include <QtAssistant/qassistantclient_global.h> - -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE +class QUndoStack; +class QUndoCommand; -class QTcpSocket; +namespace qdesigner_internal { -class QT_ASSISTANT_CLIENT_EXPORT QAssistantClient : public QObject +/* QDesignerUndoStack: A QUndoStack extended by a way of setting it to + * "dirty" indepently of commands (by modifications without commands + * such as resizing). Accomplished via bool m_fakeDirty flag. The + * lifecycle of the QUndoStack is managed by the QUndoGroup. */ +class QDesignerUndoStack : public QObject { + Q_DISABLE_COPY(QDesignerUndoStack) Q_OBJECT - Q_PROPERTY( bool open READ isOpen ) - public: - QAssistantClient( const QString &path, QObject *parent = 0); - ~QAssistantClient(); + explicit QDesignerUndoStack(QObject *parent = 0); + virtual ~QDesignerUndoStack(); - bool isOpen() const; + void push(QUndoCommand * cmd); + void beginMacro(const QString &text); + void endMacro(); + int index() const; - void setArguments( const QStringList &args ); + const QUndoStack *qundoStack() const; + QUndoStack *qundoStack(); -public Q_SLOTS: - virtual void openAssistant(); - virtual void closeAssistant(); - virtual void showPage( const QString &page ); + bool isDirty() const; -Q_SIGNALS: - void assistantOpened(); - void assistantClosed(); - void error( const QString &msg ); +signals: + void changed(); -private Q_SLOTS: - void socketConnected(); - void socketConnectionClosed(); - void readPort(); - void procError(QProcess::ProcessError err); - void socketError(); - void readStdError(); +public slots: + void setDirty(bool); private: - QTcpSocket *socket; - QProcess *proc; - quint16 port; - QString host, assistantCommand, pageBuffer; - bool opened; + QUndoStack *m_undoStack; + bool m_fakeDirty; }; -QT_END_NAMESPACE +} // namespace qdesigner_internal -QT_END_HEADER +QT_END_NAMESPACE -#endif +#endif // QDESIGNERUNDOSTACK_H diff --git a/tools/designer/src/components/propertyeditor/brushpropertymanager.cpp b/tools/designer/src/components/propertyeditor/brushpropertymanager.cpp index 6e9a698..2300b47 100644 --- a/tools/designer/src/components/propertyeditor/brushpropertymanager.cpp +++ b/tools/designer/src/components/propertyeditor/brushpropertymanager.cpp @@ -119,21 +119,31 @@ Qt::BrushStyle BrushPropertyManager::brushStyleIndexToStyle(int brushStyleIndex) return Qt::NoBrush; } + +typedef QMap<int, QIcon> EnumIndexIconMap; + +static void clearBrushIcons(); +Q_GLOBAL_STATIC_WITH_INITIALIZER(EnumIndexIconMap, brushIcons, qAddPostRoutine(clearBrushIcons)) + +static void clearBrushIcons() +{ + brushIcons()->clear(); +} + const BrushPropertyManager::EnumIndexIconMap &BrushPropertyManager::brushStyleIcons() { // Create a map of icons for the brush style editor - static EnumIndexIconMap rc; - if (rc.empty()) { + if (brushIcons()->empty()) { const int brushStyleCount = sizeof(brushStyles)/sizeof(const char *); QBrush brush(Qt::black); const QIcon solidIcon = QtPropertyBrowserUtils::brushValueIcon(brush); for (int i = 0; i < brushStyleCount; i++) { const Qt::BrushStyle style = brushStyleIndexToStyle(i); brush.setStyle(style); - rc.insert(i, QtPropertyBrowserUtils::brushValueIcon(brush)); + brushIcons()->insert(i, QtPropertyBrowserUtils::brushValueIcon(brush)); } } - return rc; + return *(brushIcons()); } QString BrushPropertyManager::brushStyleIndexToString(int brushStyleIndex) diff --git a/tools/designer/src/components/propertyeditor/propertyeditor.cpp b/tools/designer/src/components/propertyeditor/propertyeditor.cpp index b171ddc..a8ca8ad 100644 --- a/tools/designer/src/components/propertyeditor/propertyeditor.cpp +++ b/tools/designer/src/components/propertyeditor/propertyeditor.cpp @@ -79,6 +79,7 @@ #include <QtGui/QToolButton> #include <QtGui/QActionGroup> #include <QtGui/QLabel> +#include <QtGui/QPainter> #include <QtCore/QDebug> #include <QtCore/QTextStream> @@ -98,6 +99,53 @@ QT_BEGIN_NAMESPACE // --------------------------------------------------------------------------------- namespace qdesigner_internal { + +// ----------- ElidingLabel +// QLabel does not support text eliding so we need a helper class + +class ElidingLabel : public QWidget +{ +public: + ElidingLabel(const QString &text = QString(), QWidget *parent = 0) + : QWidget(parent), + m_text(text), + m_mode(Qt::ElideRight) { + setContentsMargins(3, 2, 3, 2); + } + QSize sizeHint() const; + void paintEvent(QPaintEvent *e); + void setText(const QString &text) { + m_text = text; + updateGeometry(); + } + void setElidemode(Qt::TextElideMode mode) { + m_mode = mode; + updateGeometry(); + } +private: + QString m_text; + Qt::TextElideMode m_mode; +}; + +QSize ElidingLabel::sizeHint() const +{ + QSize size = fontMetrics().boundingRect(m_text).size(); + size += QSize(contentsMargins().left() + contentsMargins().right(), + contentsMargins().top() + contentsMargins().bottom()); + return size; +} + +void ElidingLabel::paintEvent(QPaintEvent *) { + QPainter painter(this); + painter.setPen(QColor(0, 0, 0, 60)); + painter.setBrush(QColor(255, 255, 255, 40)); + painter.drawRect(rect().adjusted(0, 0, -1, -1)); + painter.setPen(palette().windowText().color()); + painter.drawText(contentsRect(), Qt::AlignLeft, + fontMetrics().elidedText(m_text, Qt::ElideRight, width(), 0)); +} + + // ----------- PropertyEditor::Strings PropertyEditor::Strings::Strings() : @@ -186,7 +234,7 @@ PropertyEditor::PropertyEditor(QDesignerFormEditorInterface *core, QWidget *pare m_coloringAction(new QAction(createIconSet(QLatin1String("color.png")), tr("Color Groups"), this)), m_treeAction(new QAction(tr("Tree View"), this)), m_buttonAction(new QAction(tr("Drop Down Button View"), this)), - m_classLabel(new QLabel), + m_classLabel(new ElidingLabel), m_sorting(false), m_coloring(false), m_brightness(false) @@ -223,11 +271,6 @@ PropertyEditor::PropertyEditor(QDesignerFormEditorInterface *core, QWidget *pare actionGroup->addAction(m_buttonAction); connect(actionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotViewTriggered(QAction*))); - QWidget *classWidget = new QWidget; - QHBoxLayout *l = new QHBoxLayout(classWidget); - l->setContentsMargins(5, 0, 5, 0); - l->addWidget(m_classLabel); - // Add actions QActionGroup *addDynamicActionGroup = new QActionGroup(this); connect(addDynamicActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotAddDynamicProperty(QAction*))); @@ -269,7 +312,6 @@ PropertyEditor::PropertyEditor(QDesignerFormEditorInterface *core, QWidget *pare #endif // Assemble toolbar QToolBar *toolBar = new QToolBar; - toolBar->addWidget(classWidget); toolBar->addWidget(m_filterWidget); toolBar->addWidget(createDropDownButton(m_addDynamicAction)); toolBar->addAction(m_removeDynamicAction); @@ -292,6 +334,8 @@ PropertyEditor::PropertyEditor(QDesignerFormEditorInterface *core, QWidget *pare QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(toolBar); + layout->addWidget(m_classLabel); + layout->addSpacerItem(new QSpacerItem(0,1)); layout->addWidget(m_stackedWidget); layout->setMargin(0); layout->setSpacing(0); @@ -778,9 +822,14 @@ void PropertyEditor::updateToolBarLabel() className = realClassName(m_object); } - QString classLabelText = objectName; - classLabelText += QLatin1Char('\n'); + m_classLabel->setVisible(!objectName.isEmpty() || !className.isEmpty()); + m_classLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + QString classLabelText; + if (!objectName.isEmpty()) + classLabelText += objectName + QLatin1String(" : "); classLabelText += className; + m_classLabel->setText(classLabelText); m_classLabel->setToolTip(tr("Object: %1\nClass: %2").arg(objectName).arg(className)); } @@ -1175,11 +1224,11 @@ void PropertyEditor::slotValueChanged(QtProperty *property, const QVariant &valu Q_ASSERT(ok); QVariant v; qVariantSetValue(v, e); - emit propertyValueChanged(property->propertyName(), v, true); + emitPropertyValueChanged(property->propertyName(), v, true); return; } - emit propertyValueChanged(property->propertyName(), value, enableSubPropertyHandling); + emitPropertyValueChanged(property->propertyName(), value, enableSubPropertyHandling); } bool PropertyEditor::isDynamicProperty(const QtBrowserItem* item) const diff --git a/tools/designer/src/components/propertyeditor/propertyeditor.h b/tools/designer/src/components/propertyeditor/propertyeditor.h index 5869c94..f0ea94f 100644 --- a/tools/designer/src/components/propertyeditor/propertyeditor.h +++ b/tools/designer/src/components/propertyeditor/propertyeditor.h @@ -62,9 +62,7 @@ class QtTreePropertyBrowser; class QtProperty; class QtVariantProperty; class QtBrowserItem; - class QStackedWidget; -class QLabel; namespace qdesigner_internal { @@ -72,6 +70,7 @@ class StringProperty; class DesignerPropertyManager; class DesignerEditorFactory; class FilterWidget; +class ElidingLabel; class QT_PROPERTYEDITOR_EXPORT PropertyEditor: public QDesignerPropertyEditor { @@ -186,7 +185,7 @@ private: QAction *m_coloringAction; QAction *m_treeAction; QAction *m_buttonAction; - QLabel *m_classLabel; + ElidingLabel *m_classLabel; bool m_sorting; bool m_coloring; diff --git a/tools/designer/src/components/widgetbox/widgetbox.cpp b/tools/designer/src/components/widgetbox/widgetbox.cpp index 512d6ba..091135a 100644 --- a/tools/designer/src/components/widgetbox/widgetbox.cpp +++ b/tools/designer/src/components/widgetbox/widgetbox.cpp @@ -74,7 +74,10 @@ WidgetBox::WidgetBox(QDesignerFormEditorInterface *core, QWidget *parent, Qt::Wi FilterWidget *filterWidget = new FilterWidget(0, FilterWidget::LayoutAlignNone); filterWidget->setRefuseFocus(true); connect(filterWidget, SIGNAL(filterChanged(QString)), m_view, SLOT(filter(QString))); - l->addWidget(filterWidget); + + QToolBar *toolBar = new QToolBar(this); + toolBar->addWidget(filterWidget); + l->addWidget(toolBar); // View connect(m_view, SIGNAL(pressed(QString,QString,QPoint)), diff --git a/tools/designer/src/components/widgetbox/widgetboxcategorylistview.cpp b/tools/designer/src/components/widgetbox/widgetboxcategorylistview.cpp index 674c3a8..1a8611c 100644 --- a/tools/designer/src/components/widgetbox/widgetboxcategorylistview.cpp +++ b/tools/designer/src/components/widgetbox/widgetboxcategorylistview.cpp @@ -88,11 +88,15 @@ namespace qdesigner_internal { struct WidgetBoxCategoryEntry { WidgetBoxCategoryEntry(); - explicit WidgetBoxCategoryEntry(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon, bool editable); + explicit WidgetBoxCategoryEntry(const QDesignerWidgetBoxInterface::Widget &widget, + const QString &filter, + const QIcon &icon, + bool editable); QDesignerWidgetBoxInterface::Widget widget; QString toolTip; QString whatsThis; + QString filter; QIcon icon; bool editable; }; @@ -103,8 +107,11 @@ WidgetBoxCategoryEntry::WidgetBoxCategoryEntry() : { } -WidgetBoxCategoryEntry::WidgetBoxCategoryEntry(const QDesignerWidgetBoxInterface::Widget &w, const QIcon &i, bool e) : +WidgetBoxCategoryEntry::WidgetBoxCategoryEntry(const QDesignerWidgetBoxInterface::Widget &w, + const QString &filterIn, + const QIcon &i, bool e) : widget(w), + filter(filterIn), icon(i), editable(e) { @@ -142,6 +149,7 @@ public: private: typedef QList<WidgetBoxCategoryEntry> WidgetBoxCategoryEntrys; + QRegExp m_classNameRegExp; QDesignerFormEditorInterface *m_core; WidgetBoxCategoryEntrys m_items; QListView::ViewMode m_viewMode; @@ -149,9 +157,11 @@ private: WidgetBoxCategoryModel::WidgetBoxCategoryModel(QDesignerFormEditorInterface *core, QObject *parent) : QAbstractListModel(parent), + m_classNameRegExp(QLatin1String("<widget +class *= *\"([^\"]+)\"")), m_core(core), m_viewMode(QListView::ListMode) { + Q_ASSERT(m_classNameRegExp.isValid()); } QListView::ViewMode WidgetBoxCategoryModel::viewMode() const @@ -205,8 +215,14 @@ bool WidgetBoxCategoryModel::removeCustomWidgets() void WidgetBoxCategoryModel::addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon,bool editable) { - // build item - WidgetBoxCategoryEntry item(widget, icon, editable); + // build item. Filter on name + class name if it is different and not a layout. + QString filter = widget.name(); + if (!filter.contains(QLatin1String("Layout")) && m_classNameRegExp.indexIn(widget.domXml()) != -1) { + const QString className = m_classNameRegExp.cap(1); + if (!filter.contains(className)) + filter += className; + } + WidgetBoxCategoryEntry item(widget, filter, icon, editable); const QDesignerWidgetDataBaseInterface *db = m_core->widgetDataBase(); const int dbIndex = db->indexOfClassName(widget.name()); if (dbIndex != -1) { @@ -255,7 +271,7 @@ QVariant WidgetBoxCategoryModel::data(const QModelIndex &index, int role) const case Qt::WhatsThisRole: return QVariant(item.whatsThis); case FilterRole: - return item.widget.name(); + return item.filter; } return QVariant(); } diff --git a/tools/designer/src/designer/designer.pro b/tools/designer/src/designer/designer.pro index 2050c72..8590c7b 100644 --- a/tools/designer/src/designer/designer.pro +++ b/tools/designer/src/designer/designer.pro @@ -14,10 +14,8 @@ INCLUDEPATH += \ ../lib/uilib \ extra -LIBS += -L../../lib \ - -L../../../../lib \ - -lQtDesignerComponents \ - -lQtDesigner +QMAKE_LIBDIR += ../../lib ../../../../lib +LIBS += -lQtDesignerComponents -lQtDesigner RESOURCES += designer.qrc diff --git a/tools/designer/src/designer/mainwindow.cpp b/tools/designer/src/designer/mainwindow.cpp index c27e2b4..86bc47e 100644 --- a/tools/designer/src/designer/mainwindow.cpp +++ b/tools/designer/src/designer/mainwindow.cpp @@ -75,7 +75,7 @@ static void addActionsToToolBar(const ActionList &actions, QToolBar *t) const ActionList::const_iterator cend = actions.constEnd(); for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it) { QAction *action = *it; - if (!action->icon().isNull()) + if (action->property(QDesignerActions::defaultToolbarPropertyName).toBool()) t->addAction(action); } } @@ -113,6 +113,8 @@ void MainWindowBase::closeEvent(QCloseEvent *e) QList<QToolBar *> MainWindowBase::createToolBars(const QDesignerActions *actions, bool singleToolBar) { + // Note that whenever you want to add a new tool bar here, you also have to update the default + // action groups added to the toolbar manager in the mainwindow constructor QList<QToolBar *> rc; if (singleToolBar) { //: Not currently used (main tool bar) @@ -252,6 +254,22 @@ ToolBarManager::ToolBarManager(QMainWindow *configureableMainWindow, m_manager->addAction(action, dockTitle); } + QString category(tr("File")); + foreach(QAction *action, actions->fileActions()->actions()) + m_manager->addAction(action, category); + + category = tr("Edit"); + foreach(QAction *action, actions->editActions()->actions()) + m_manager->addAction(action, category); + + category = tr("Tools"); + foreach(QAction *action, actions->toolActions()->actions()) + m_manager->addAction(action, category); + + category = tr("Form"); + foreach(QAction *action, actions->formActions()->actions()) + m_manager->addAction(action, category); + m_manager->addAction(m_configureAction, tr("Toolbars")); updateToolBarMenu(); } diff --git a/tools/designer/src/designer/qdesigner_actions.cpp b/tools/designer/src/designer/qdesigner_actions.cpp index 887ba98..86b6214 100644 --- a/tools/designer/src/designer/qdesigner_actions.cpp +++ b/tools/designer/src/designer/qdesigner_actions.cpp @@ -107,6 +107,8 @@ QT_BEGIN_NAMESPACE using namespace qdesigner_internal; +const char *QDesignerActions::defaultToolbarPropertyName = "__qt_defaultToolBarAction"; + //#ifdef Q_WS_MAC # define NONMODAL_PREVIEW //#endif @@ -200,9 +202,15 @@ QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) #endif m_previewManager(0) { +#ifdef Q_WS_X11 m_newFormAction->setIcon(QIcon::fromTheme("document-new", m_newFormAction->icon())); m_openFormAction->setIcon(QIcon::fromTheme("document-open", m_openFormAction->icon())); m_saveFormAction->setIcon(QIcon::fromTheme("document-save", m_saveFormAction->icon())); + m_saveFormAsAction->setIcon(QIcon::fromTheme("document-save-as", m_saveFormAsAction->icon())); + m_printPreviewAction->setIcon(QIcon::fromTheme("document-print", m_printPreviewAction->icon())); + m_closeFormAction->setIcon(QIcon::fromTheme("window-close", m_closeFormAction->icon())); + m_quitAction->setIcon(QIcon::fromTheme("application-exit", m_quitAction->icon())); +#endif Q_ASSERT(m_core != 0); qdesigner_internal::QDesignerFormWindowManager *ifwm = qobject_cast<qdesigner_internal::QDesignerFormWindowManager *>(m_core->formWindowManager()); @@ -230,6 +238,10 @@ QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) m_helpActions = createHelpActions(); + m_newFormAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + m_openFormAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + m_saveFormAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + QDesignerFormWindowManagerInterface *formWindowManager = m_core->formWindowManager(); Q_ASSERT(formWindowManager != 0); @@ -316,6 +328,9 @@ QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) m_editActions->addAction(formWindowManager->actionLower()); m_editActions->addAction(formWindowManager->actionRaise()); + formWindowManager->actionLower()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionRaise()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + // // edit mode actions // @@ -332,6 +347,7 @@ QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) connect(m_editWidgetsAction, SIGNAL(triggered()), this, SLOT(editWidgetsSlot())); m_editWidgetsAction->setChecked(true); m_editWidgetsAction->setEnabled(false); + m_editWidgetsAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true); m_toolActions->addAction(m_editWidgetsAction); connect(formWindowManager, SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), @@ -343,6 +359,7 @@ QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast<QDesignerFormEditorPluginInterface*>(plugin)) { if (QAction *action = formEditorPlugin->action()) { m_toolActions->addAction(action); + action->setProperty(QDesignerActions::defaultToolbarPropertyName, true); action->setCheckable(true); } } @@ -370,6 +387,15 @@ QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) m_formActions->addAction(formWindowManager->actionSimplifyLayout()); m_formActions->addAction(createSeparator(this)); + formWindowManager->actionHorizontalLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionVerticalLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionSplitHorizontal()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionSplitVertical()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionGridLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionFormLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionBreakLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionAdjustSize()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + m_previewFormAction->setShortcut(tr("CTRL+R")); m_formActions->addAction(m_previewFormAction); connect(m_previewManager, SIGNAL(firstPreviewOpened()), this, SLOT(updateCloseAction())); @@ -490,13 +516,13 @@ QAction *QDesignerActions::createRecentFilesMenu() } updateRecentFileActions(); menu->addSeparator(); - act = new QAction(tr("Clear &Menu"), this); + act = new QAction(QIcon::fromTheme("edit-clear"), tr("Clear &Menu"), this); act->setObjectName(QLatin1String("__qt_action_clear_menu_")); connect(act, SIGNAL(triggered()), this, SLOT(clearRecentFiles())); m_recentFilesActions->addAction(act); menu->addAction(act); - act = new QAction(tr("&Recent Forms"), this); + act = new QAction(QIcon::fromTheme("document-open-recent"), tr("&Recent Forms"), this); act->setMenu(menu); return act; } diff --git a/tools/designer/src/designer/qdesigner_actions.h b/tools/designer/src/designer/qdesigner_actions.h index 9dfcef1..d8f9e42 100644 --- a/tools/designer/src/designer/qdesigner_actions.h +++ b/tools/designer/src/designer/qdesigner_actions.h @@ -113,6 +113,10 @@ public: QString uiExtension() const; + // Boolean dynamic property set on actions to + // show them in the default toolbar layout + static const char *defaultToolbarPropertyName; + public slots: void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); void createForm(); diff --git a/tools/designer/src/designer/qdesigner_workbench.cpp b/tools/designer/src/designer/qdesigner_workbench.cpp index b65ce7e..168c468 100644 --- a/tools/designer/src/designer/qdesigner_workbench.cpp +++ b/tools/designer/src/designer/qdesigner_workbench.cpp @@ -419,6 +419,7 @@ void QDesignerWorkbench::switchToDockedMode() m_mode = DockedMode; const QDesignerSettings settings(m_core); m_dockedMainWindow = new DockedMainWindow(this, m_toolbarMenu, m_toolWindows); + m_dockedMainWindow->setUnifiedTitleAndToolBarOnMac(true); m_dockedMainWindow->setCloseEventPolicy(MainWindowBase::EmitCloseEventSignal); connect(m_dockedMainWindow, SIGNAL(closeEventReceived(QCloseEvent*)), this, SLOT(handleCloseEvent(QCloseEvent*))); connect(m_dockedMainWindow, SIGNAL(fileDropped(QString)), this, SLOT(slotFileDropped(QString))); diff --git a/tools/designer/src/lib/sdk/abstractformeditor.cpp b/tools/designer/src/lib/sdk/abstractformeditor.cpp index 5353cab..c301f46 100644 --- a/tools/designer/src/lib/sdk/abstractformeditor.cpp +++ b/tools/designer/src/lib/sdk/abstractformeditor.cpp @@ -71,7 +71,6 @@ static void initResources() { Q_INIT_RESOURCE(shared); Q_INIT_RESOURCE(ClamshellPhone); - Q_INIT_RESOURCE(PDAPhone); Q_INIT_RESOURCE(PortableMedia); Q_INIT_RESOURCE(S60_nHD_Touchscreen); Q_INIT_RESOURCE(S60_QVGA_Candybar); @@ -79,8 +78,6 @@ static void initResources() Q_INIT_RESOURCE(SmartPhone); Q_INIT_RESOURCE(SmartPhoneWithButtons); Q_INIT_RESOURCE(TouchscreenPhone); - Q_INIT_RESOURCE(Trolltech_Keypad); - Q_INIT_RESOURCE(Trolltech_Touchscreen); } QT_BEGIN_NAMESPACE diff --git a/tools/designer/src/lib/shared/filterwidget.cpp b/tools/designer/src/lib/shared/filterwidget.cpp index 6c73a08..a501c02 100644 --- a/tools/designer/src/lib/shared/filterwidget.cpp +++ b/tools/designer/src/lib/shared/filterwidget.cpp @@ -44,13 +44,17 @@ #include <QtGui/QVBoxLayout> #include <QtGui/QHBoxLayout> -#include <QtGui/QPushButton> #include <QtGui/QLineEdit> #include <QtGui/QFocusEvent> #include <QtGui/QPalette> #include <QtGui/QCursor> +#include <QtGui/QToolButton> +#include <QtGui/QPainter> +#include <QtGui/QStyle> +#include <QtGui/QStyleOption> #include <QtCore/QDebug> +#include <QtCore/QPropertyAnimation> enum { debugFilter = 0 }; @@ -61,12 +65,47 @@ namespace qdesigner_internal { HintLineEdit::HintLineEdit(QWidget *parent) : QLineEdit(parent), m_defaultFocusPolicy(focusPolicy()), - m_hintColor(QColor(0xbbbbbb)), - m_refuseFocus(false), - m_showingHintText(false) + m_refuseFocus(false) { } +IconButton::IconButton(QWidget *parent) + : QToolButton(parent) +{ + setCursor(Qt::ArrowCursor); +} + +void IconButton::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + // Note isDown should really use the active state but in most styles + // this has no proper feedback + QIcon::Mode state = QIcon::Disabled; + if (isEnabled()) + state = isDown() ? QIcon::Selected : QIcon::Normal; + QPixmap iconpixmap = icon().pixmap(QSize(ICONBUTTON_SIZE, ICONBUTTON_SIZE), + state, QIcon::Off); + QRect pixmapRect = QRect(0, 0, iconpixmap.width(), iconpixmap.height()); + pixmapRect.moveCenter(rect().center()); + painter.setOpacity(m_fader); + painter.drawPixmap(pixmapRect, iconpixmap); +} + +void IconButton::animateShow(bool visible) +{ + if (visible) { + QPropertyAnimation *animation = new QPropertyAnimation(this, "fader"); + animation->setDuration(160); + animation->setEndValue(1.0); + animation->start(QAbstractAnimation::DeleteWhenStopped); + } else { + QPropertyAnimation *animation = new QPropertyAnimation(this, "fader"); + animation->setDuration(160); + animation->setEndValue(0.0); + animation->start(QAbstractAnimation::DeleteWhenStopped); + } +} + bool HintLineEdit::refuseFocus() const { return m_refuseFocus; @@ -111,92 +150,53 @@ void HintLineEdit::focusInEvent(QFocusEvent *e) } } - hideHintText(); QLineEdit::focusInEvent(e); } -void HintLineEdit::focusOutEvent(QFocusEvent *e) -{ - if (debugFilter) - qDebug() << Q_FUNC_INFO; - // Focus out: Switch to displaying the hint text unless there is user input - showHintText(); - QLineEdit::focusOutEvent(e); -} - -QString HintLineEdit::hintText() const +// ------------------- FilterWidget +FilterWidget::FilterWidget(QWidget *parent, LayoutMode lm) : + QWidget(parent), + m_editor(new HintLineEdit(this)), + m_button(new IconButton(m_editor)), + m_buttonwidth(0) { - return m_hintText; -} + m_editor->setPlaceholderText(tr("Filter")); -void HintLineEdit::setHintText(const QString &ht) -{ - if (ht == m_hintText) - return; - hideHintText(); - m_hintText = ht; - if (!hasFocus() && !ht.isEmpty()) - showHintText(); -} + // Let the style determine minimum height for our widget + QSize size(ICONBUTTON_SIZE + 6, ICONBUTTON_SIZE + 2); -void HintLineEdit::showHintText(bool force) -{ - if (m_showingHintText || m_hintText.isEmpty()) - return; - if (force || text().isEmpty()) { - m_showingHintText = true; - setText(m_hintText); - setTextColor(m_hintColor, &m_textColor); - } -} -void HintLineEdit::hideHintText() -{ - if (m_showingHintText && !m_hintText.isEmpty()) { - m_showingHintText = false; - setText(QString()); - setTextColor(m_textColor); + // Note KDE does not reserve space for the highlight color + if (style()->inherits("OxygenStyle")) { + size = size.expandedTo(QSize(24, 0)); } -} -bool HintLineEdit::isShowingHintText() const -{ - return m_showingHintText; -} - -QString HintLineEdit::typedText() const -{ - return m_showingHintText ? QString() : text(); -} + // Make room for clear icon + QMargins margins = m_editor->textMargins(); + if (layoutDirection() == Qt::LeftToRight) + margins.setRight(size.width()); + else + margins.setLeft(size.width()); -void HintLineEdit::setTextColor(const QColor &newColor, QColor *oldColor) -{ - QPalette pal = palette(); - if (oldColor) - *oldColor = pal.color(QPalette::Text); - pal.setColor(QPalette::Text, newColor); - setPalette(pal);} + m_editor->setTextMargins(margins); -// ------------------- FilterWidget -FilterWidget::FilterWidget(QWidget *parent, LayoutMode lm) : - QWidget(parent), - m_button(new QPushButton), - m_editor(new HintLineEdit) -{ - m_editor->setHintText(tr("<Filter>")); QHBoxLayout *l = new QHBoxLayout(this); l->setMargin(0); l->setSpacing(0); - if (lm == LayoutAlignRight) l->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); l->addWidget(m_editor); - m_button->setIcon(createIconSet(QLatin1String("resetproperty.png"))); - m_button->setIconSize(QSize(8, 8)); - m_button->setFlat(true); - l->addWidget(m_button); + // KDE has custom icons for this. Notice that icon namings are counter intuitive + // If these icons are not avaiable we use the freedesktop standard name before + // falling back to a bundled resource + QIcon icon = QIcon::fromTheme(layoutDirection() == Qt::LeftToRight ? + QLatin1String("edit-clear-locationbar-rtl") : + QLatin1String("edit-clear-locationbar-ltr"), + QIcon::fromTheme("edit-clear", createIconSet(QLatin1String("cleartext.png")))); + m_button->setIcon(icon); + m_button->setToolTip(tr("Clear text")); connect(m_button, SIGNAL(clicked()), this, SLOT(reset())); connect(m_editor, SIGNAL(textChanged(QString)), this, SLOT(checkButton(QString))); connect(m_editor, SIGNAL(textEdited(QString)), this, SIGNAL(filterChanged(QString))); @@ -204,25 +204,40 @@ FilterWidget::FilterWidget(QWidget *parent, LayoutMode lm) : QString FilterWidget::text() const { - return m_editor->typedText(); + return m_editor->text(); } -void FilterWidget::checkButton(const QString &) +void FilterWidget::checkButton(const QString &text) { - m_button->setEnabled(!text().isEmpty()); + if (m_oldText.isEmpty() || text.isEmpty()) + m_button->animateShow(!m_editor->text().isEmpty()); + m_oldText = text; } void FilterWidget::reset() { if (debugFilter) qDebug() << Q_FUNC_INFO; - if (!text().isEmpty()) { + + if (!m_editor->text().isEmpty()) { // Editor has lost focus once this is pressed - m_editor->showHintText(true); + m_editor->clear(); emit filterChanged(QString()); } } +void FilterWidget::resizeEvent(QResizeEvent *) +{ + QRect contentRect = m_editor->rect(); + if (layoutDirection() == Qt::LeftToRight) { + const int iconoffset = m_editor->textMargins().right() + 4; + m_button->setGeometry(contentRect.adjusted(m_editor->width() - iconoffset, 0, 0, 0)); + } else { + const int iconoffset = m_editor->textMargins().left() + 4; + m_button->setGeometry(contentRect.adjusted(0, 0, -m_editor->width() + iconoffset, 0)); + } +} + bool FilterWidget::refuseFocus() const { return m_editor->refuseFocus(); diff --git a/tools/designer/src/lib/shared/filterwidget_p.h b/tools/designer/src/lib/shared/filterwidget_p.h index 025d708..8ca2073 100644 --- a/tools/designer/src/lib/shared/filterwidget_p.h +++ b/tools/designer/src/lib/shared/filterwidget_p.h @@ -58,58 +58,55 @@ #include <QtGui/QWidget> #include <QtGui/QLineEdit> #include <QtGui/QColor> +#include <QtGui/QToolButton> QT_BEGIN_NAMESPACE -class QPushButton; +class QToolButton; namespace qdesigner_internal { -/* A line edit that displays a grayed hintText (like "Type Here to Filter") - * when not focused and empty. When connecting to the changed signals and - * querying text, one has to be aware that the text is set to that hint - * text if isShowingHintText() returns true (that is, does not contain - * valid user input). This widget should never have initial focus +/* This widget should never have initial focus * (ie, be the first widget of a dialog, else, the hint cannot be displayed. * For situations, where it is the only focusable control (widget box), * there is a special "refuseFocus()" mode, in which it clears the focus * policy and focusses explicitly on click (note that setting Qt::ClickFocus * is not sufficient for that as an ActivationFocus will occur). */ +#define ICONBUTTON_SIZE 16 + class QDESIGNER_SHARED_EXPORT HintLineEdit : public QLineEdit { Q_OBJECT public: explicit HintLineEdit(QWidget *parent = 0); - QString hintText() const; - - bool isShowingHintText() const; - - // Convenience for accessing the text that returns "" in case of isShowingHintText(). - QString typedText() const; - bool refuseFocus() const; void setRefuseFocus(bool v); -public slots: - void setHintText(const QString &ht); - void showHintText(bool force = false); - void hideHintText(); - protected: virtual void mousePressEvent(QMouseEvent *event); virtual void focusInEvent(QFocusEvent *e); - virtual void focusOutEvent(QFocusEvent *e); private: - void setTextColor(const QColor &newColor, QColor *oldColor = 0); - const Qt::FocusPolicy m_defaultFocusPolicy; - const QColor m_hintColor; - QColor m_textColor; bool m_refuseFocus; - QString m_hintText; - bool m_showingHintText; +}; + +// IconButton: This is a simple helper class that represents clickable icons + +class IconButton: public QToolButton +{ + Q_OBJECT + Q_PROPERTY(float fader READ fader WRITE setFader) +public: + IconButton(QWidget *parent); + void paintEvent(QPaintEvent *event); + float fader() { return m_fader; } + void setFader(float value) { m_fader = value; update(); } + void animateShow(bool visible); + +private: + float m_fader; }; // FilterWidget: For filtering item views, with reset button Uses HintLineEdit. @@ -128,7 +125,7 @@ public: explicit FilterWidget(QWidget *parent = 0, LayoutMode lm = LayoutAlignRight); QString text() const; - + void resizeEvent(QResizeEvent *); bool refuseFocus() const; // see HintLineEdit void setRefuseFocus(bool v); @@ -142,8 +139,10 @@ private slots: void checkButton(const QString &text); private: - QPushButton *m_button; HintLineEdit *m_editor; + IconButton *m_button; + int m_buttonwidth; + QString m_oldText; }; } // namespace qdesigner_internal diff --git a/tools/designer/src/lib/shared/formwindowbase.cpp b/tools/designer/src/lib/shared/formwindowbase.cpp index 2c5efbf..5292f5f 100644 --- a/tools/designer/src/lib/shared/formwindowbase.cpp +++ b/tools/designer/src/lib/shared/formwindowbase.cpp @@ -72,6 +72,7 @@ #include <QtGui/QStatusBar> #include <QtGui/QMenu> #include <QtGui/QAction> +#include <QtGui/QLabel> QT_BEGIN_NAMESPACE @@ -181,7 +182,17 @@ void FormWindowBase::reloadProperties() QMapIterator<int, bool> itIndex(itSheet.value()); while (itIndex.hasNext()) { const int index = itIndex.next().key(); - sheet->setProperty(index, sheet->property(index)); + const QVariant newValue = sheet->property(index); + if (qobject_cast<QLabel *>(sheet->object()) && sheet->propertyName(index) == QLatin1String("text")) { + const PropertySheetStringValue newString = qVariantValue<PropertySheetStringValue>(newValue); + // optimize a bit, reset only if the text value might contain a reference to qt resources + // (however reloading of icons other than taken from resources might not work here) + if (newString.value().contains(QLatin1String(":/"))) { + const QVariant resetValue = qVariantFromValue(PropertySheetStringValue()); + sheet->setProperty(index, resetValue); + } + } + sheet->setProperty(index, newValue); } if (QTabWidget *tabWidget = qobject_cast<QTabWidget *>(sheet->object())) { const int count = tabWidget->count(); diff --git a/tools/designer/src/lib/shared/previewconfigurationwidget.cpp b/tools/designer/src/lib/shared/previewconfigurationwidget.cpp index e07d155..d116d58 100644 --- a/tools/designer/src/lib/shared/previewconfigurationwidget.cpp +++ b/tools/designer/src/lib/shared/previewconfigurationwidget.cpp @@ -41,7 +41,7 @@ /* It is possible to link the skins as resources into Designer by specifying: * QVFB_ROOT=$$QT_SOURCE_TREE/tools/qvfb - * RESOURCES += $$QVFB_ROOT/ClamshellPhone.qrc $$QVFB_ROOT/PDAPhone.qrc ... + * RESOURCES += $$QVFB_ROOT/ClamshellPhone.qrc $$QVFB_ROOT/TouchScreenPhone.qrc ... * in lib/shared/shared.pri. However, this exceeds a limit of Visual Studio 6. */ #include "previewconfigurationwidget_p.h" diff --git a/tools/designer/src/lib/shared/qdesigner_formwindowcommand.cpp b/tools/designer/src/lib/shared/qdesigner_formwindowcommand.cpp index 8c55d26..490373e 100644 --- a/tools/designer/src/lib/shared/qdesigner_formwindowcommand.cpp +++ b/tools/designer/src/lib/shared/qdesigner_formwindowcommand.cpp @@ -62,8 +62,10 @@ QT_BEGIN_NAMESPACE namespace qdesigner_internal { // ---- QDesignerFormWindowCommand ---- -QDesignerFormWindowCommand::QDesignerFormWindowCommand(const QString &description, QDesignerFormWindowInterface *formWindow) - : QUndoCommand(description), +QDesignerFormWindowCommand::QDesignerFormWindowCommand(const QString &description, + QDesignerFormWindowInterface *formWindow, + QUndoCommand *parent) + : QUndoCommand(description, parent), m_formWindow(formWindow) { } diff --git a/tools/designer/src/lib/shared/qdesigner_formwindowcommand_p.h b/tools/designer/src/lib/shared/qdesigner_formwindowcommand_p.h index d8cd018..d73d70c 100644 --- a/tools/designer/src/lib/shared/qdesigner_formwindowcommand_p.h +++ b/tools/designer/src/lib/shared/qdesigner_formwindowcommand_p.h @@ -70,7 +70,9 @@ class QDESIGNER_SHARED_EXPORT QDesignerFormWindowCommand: public QUndoCommand { public: - QDesignerFormWindowCommand(const QString &description, QDesignerFormWindowInterface *formWindow); + QDesignerFormWindowCommand(const QString &description, + QDesignerFormWindowInterface *formWindow, + QUndoCommand *parent = 0); virtual void undo(); virtual void redo(); diff --git a/tools/designer/src/lib/shared/qdesigner_propertycommand.cpp b/tools/designer/src/lib/shared/qdesigner_propertycommand.cpp index 822c14b..6cc054c 100644 --- a/tools/designer/src/lib/shared/qdesigner_propertycommand.cpp +++ b/tools/designer/src/lib/shared/qdesigner_propertycommand.cpp @@ -926,8 +926,9 @@ bool PropertyListCommand::PropertyDescription::equals(const PropertyDescription // ---- PropertyListCommand -PropertyListCommand::PropertyListCommand(QDesignerFormWindowInterface *formWindow) : - QDesignerFormWindowCommand(QString(), formWindow) +PropertyListCommand::PropertyListCommand(QDesignerFormWindowInterface *formWindow, + QUndoCommand *parent) : + QDesignerFormWindowCommand(QString(), formWindow, parent) { } @@ -966,10 +967,17 @@ bool PropertyListCommand::add(QObject *object, const QString &propertyName) if (!match || m_propertyDescription.m_specialProperty == SP_ObjectName) return false; } - m_propertyHelperList.push_back(PropertyHelper(object, m_propertyDescription.m_specialProperty, sheet, index)); + + const PropertyHelperPtr ph(createPropertyHelper(object, m_propertyDescription.m_specialProperty, sheet, index)); + m_propertyHelperList.push_back(ph); return true; } +PropertyHelper *PropertyListCommand::createPropertyHelper(QObject *object, SpecialProperty sp, + QDesignerPropertySheetExtension *sheet, int sheetIndex) const +{ + return new PropertyHelper(object, sp, sheet, sheetIndex); +} // Init from a list and make sure referenceObject is added first to obtain the right property group bool PropertyListCommand::initList(const ObjectList &list, const QString &apropertyName, QObject *referenceObject) @@ -993,19 +1001,19 @@ bool PropertyListCommand::initList(const ObjectList &list, const QString &aprope QObject* PropertyListCommand::object(int index) const { Q_ASSERT(index < m_propertyHelperList.size()); - return m_propertyHelperList[index].object(); + return m_propertyHelperList.at(index)->object(); } QVariant PropertyListCommand::oldValue(int index) const { Q_ASSERT(index < m_propertyHelperList.size()); - return m_propertyHelperList[index].oldValue(); + return m_propertyHelperList.at(index)->oldValue(); } void PropertyListCommand::setOldValue(const QVariant &oldValue, int index) { Q_ASSERT(index < m_propertyHelperList.size()); - m_propertyHelperList[index].setOldValue(oldValue); + m_propertyHelperList.at(index)->setOldValue(oldValue); } // ----- SetValueFunction: Set a new value when applied to a PropertyHelper. class SetValueFunction { @@ -1065,9 +1073,10 @@ template <class PropertyListIterator, class Function> bool updatedPropertyEditor = false; for (PropertyListIterator it = begin; it != end; ++it) { - if (QObject* object = it->object()) { // Might have been deleted in the meantime - const PropertyHelper::Value newValue = function(*it); - updateMask |= it->updateMask(); + PropertyHelper *ph = it->data(); + if (QObject* object = ph->object()) { // Might have been deleted in the meantime + const PropertyHelper::Value newValue = function( *ph ); + updateMask |= ph->updateMask(); // Update property editor if it is the current object if (!updatedPropertyEditor && propertyEditor && object == propertyEditor->object()) { propertyEditor->setPropertyValue(propertyName, newValue.first, newValue.second); @@ -1084,9 +1093,11 @@ template <class PropertyListIterator, class Function> unsigned PropertyListCommand::setValue(QVariant value, bool changed, unsigned subPropertyMask) { if(debugPropertyCommands) - qDebug() << "PropertyListCommand::setValue(" << value << changed << subPropertyMask << ')'; + qDebug() << "PropertyListCommand::setValue(" << value + << changed << subPropertyMask << ')'; return changePropertyList(formWindow()->core(), - m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(), + m_propertyDescription.m_propertyName, + m_propertyHelperList.begin(), m_propertyHelperList.end(), SetValueFunction(formWindow(), PropertyHelper::Value(value, changed), subPropertyMask)); } @@ -1146,15 +1157,16 @@ bool PropertyListCommand::canMergeLists(const PropertyHelperList& other) const if (m_propertyHelperList.size() != other.size()) return false; for (int i = 0; i < m_propertyHelperList.size(); i++) { - if (!m_propertyHelperList[i].canMerge(other[i])) + if (!m_propertyHelperList.at(i)->canMerge(*other.at(i))) return false; } return true; } // ---- SetPropertyCommand ---- -SetPropertyCommand::SetPropertyCommand(QDesignerFormWindowInterface *formWindow) - : PropertyListCommand(formWindow), +SetPropertyCommand::SetPropertyCommand(QDesignerFormWindowInterface *formWindow, + QUndoCommand *parent) + : PropertyListCommand(formWindow, parent), m_subPropertyMask(SubPropertyAll) { } @@ -1210,7 +1222,7 @@ unsigned SetPropertyCommand::subPropertyMask(const QVariant &newValue, QObject * void SetPropertyCommand::setDescription() { if (propertyHelperList().size() == 1) { - setText(QApplication::translate("Command", "Changed '%1' of '%2'").arg(propertyName()).arg(propertyHelperList()[0].object()->objectName())); + setText(QApplication::translate("Command", "Changed '%1' of '%2'").arg(propertyName()).arg(propertyHelperList().at(0)->object()->objectName())); } else { int count = propertyHelperList().size(); setText(QApplication::translate("Command", "Changed '%1' of %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(propertyName())); @@ -1231,6 +1243,11 @@ int SetPropertyCommand::id() const return 1976; } +QVariant SetPropertyCommand::mergeValue(const QVariant &newValue) +{ + return newValue; +} + bool SetPropertyCommand::mergeWith(const QUndoCommand *other) { if (id() != other->id() || !formWindow()->isDirty()) @@ -1248,7 +1265,10 @@ bool SetPropertyCommand::mergeWith(const QUndoCommand *other) !canMergeLists(cmd->propertyHelperList())) return false; - m_newValue = cmd->newValue(); + const QVariant newValue = mergeValue(cmd->newValue()); + if (!newValue.isValid()) + return false; + m_newValue = newValue; m_subPropertyMask |= cmd->m_subPropertyMask; if(debugPropertyCommands) qDebug() << "SetPropertyCommand::mergeWith() succeeded " << propertyName(); @@ -1289,7 +1309,7 @@ bool ResetPropertyCommand::init(const ObjectList &list, const QString &aproperty void ResetPropertyCommand::setDescription() { if (propertyHelperList().size() == 1) { - setText(QApplication::translate("Command", "Reset '%1' of '%2'").arg(propertyName()).arg(propertyHelperList()[0].object()->objectName())); + setText(QApplication::translate("Command", "Reset '%1' of '%2'").arg(propertyName()).arg(propertyHelperList().at(0)->object()->objectName())); } else { int count = propertyHelperList().size(); setText(QApplication::translate("Command", "Reset '%1' of %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(propertyName())); diff --git a/tools/designer/src/lib/shared/qdesigner_propertycommand_p.h b/tools/designer/src/lib/shared/qdesigner_propertycommand_p.h index f6b7262..75b23ca 100644 --- a/tools/designer/src/lib/shared/qdesigner_propertycommand_p.h +++ b/tools/designer/src/lib/shared/qdesigner_propertycommand_p.h @@ -58,6 +58,7 @@ #include <QtCore/QVariant> #include <QtCore/QList> #include <QtCore/QPair> +#include <QtCore/QSharedPointer> QT_BEGIN_NAMESPACE @@ -77,11 +78,12 @@ enum SpecialProperty { //Determine special property enum SpecialProperty getSpecialProperty(const QString& propertyName); - // A helper class for applying properties to objects. // Can be used for Set commands (setValue(), restoreOldValue()) or // Reset Commands restoreDefaultValue(), restoreOldValue()). -class PropertyHelper { +// +class QDESIGNER_SHARED_EXPORT PropertyHelper { + Q_DISABLE_COPY(PropertyHelper) public: // A pair of Value and changed flag typedef QPair<QVariant, bool> Value; @@ -92,11 +94,13 @@ public: SpecialProperty specialProperty, QDesignerPropertySheetExtension *sheet, int index); + virtual ~PropertyHelper() {} QObject *object() const { return m_object; } SpecialProperty specialProperty() const { return m_specialProperty; } - // set a new value - Value setValue(QDesignerFormWindowInterface *fw, const QVariant &value, bool changed, unsigned subPropertyMask); + // set a new value. Can be overwritten to perform a transformation (see + // handling of Arrow key move in FormWindow class). + virtual Value setValue(QDesignerFormWindowInterface *fw, const QVariant &value, bool changed, unsigned subPropertyMask); // restore old value Value restoreOldValue(QDesignerFormWindowInterface *fw); @@ -147,7 +151,7 @@ class QDESIGNER_SHARED_EXPORT PropertyListCommand : public QDesignerFormWindowCo public: typedef QList<QObject *> ObjectList; - explicit PropertyListCommand(QDesignerFormWindowInterface *formWindow); + explicit PropertyListCommand(QDesignerFormWindowInterface *formWindow, QUndoCommand *parent = 0); QObject* object(int index = 0) const; @@ -159,8 +163,8 @@ public: virtual void undo(); protected: - typedef QList<PropertyHelper> PropertyHelperList; - + typedef QSharedPointer<PropertyHelper> PropertyHelperPtr; + typedef QList<PropertyHelperPtr> PropertyHelperList; // add an object bool add(QObject *object, const QString &propertyName); @@ -204,6 +208,10 @@ protected: }; const PropertyDescription &propertyDescription() const { return m_propertyDescription; } +protected: + virtual PropertyHelper *createPropertyHelper(QObject *o, SpecialProperty sp, + QDesignerPropertySheetExtension *sheet, int sheetIndex) const; + private: PropertyDescription m_propertyDescription; PropertyHelperList m_propertyHelperList; @@ -215,7 +223,7 @@ class QDESIGNER_SHARED_EXPORT SetPropertyCommand: public PropertyListCommand public: typedef QList<QObject *> ObjectList; - explicit SetPropertyCommand(QDesignerFormWindowInterface *formWindow); + explicit SetPropertyCommand(QDesignerFormWindowInterface *formWindow, QUndoCommand *parent = 0); bool init(QObject *object, const QString &propertyName, const QVariant &newValue); bool init(const ObjectList &list, const QString &propertyName, const QVariant &newValue, @@ -232,6 +240,10 @@ public: bool mergeWith(const QUndoCommand *other); virtual void redo(); + +protected: + virtual QVariant mergeValue(const QVariant &newValue); + private: unsigned subPropertyMask(const QVariant &newValue, QObject *referenceObject); void setDescription(); diff --git a/tools/designer/src/lib/shared/qdesigner_propertyeditor.cpp b/tools/designer/src/lib/shared/qdesigner_propertyeditor.cpp index e89c47c..9a1739e 100644 --- a/tools/designer/src/lib/shared/qdesigner_propertyeditor.cpp +++ b/tools/designer/src/lib/shared/qdesigner_propertyeditor.cpp @@ -92,7 +92,8 @@ static const PropertyNameTypeMap &stringPropertyTypes() } QDesignerPropertyEditor::QDesignerPropertyEditor(QWidget *parent, Qt::WindowFlags flags) : - QDesignerPropertyEditorInterface(parent, flags) + QDesignerPropertyEditorInterface(parent, flags), + m_propertyChangedForwardingBlocked(false) { // Make old signal work for compatibility connect(this, SIGNAL(propertyChanged(QString,QVariant)), this, SLOT(slotPropertyChanged(QString,QVariant))); @@ -147,9 +148,20 @@ QDesignerPropertyEditor::StringPropertyParameters QDesignerPropertyEditor::textP return StringPropertyParameters(ValidationSingleLine, true); } +void QDesignerPropertyEditor::emitPropertyValueChanged(const QString &name, const QVariant &value, bool enableSubPropertyHandling) +{ + // Avoid duplicate signal emission - see below + m_propertyChangedForwardingBlocked = true; + emit propertyValueChanged(name, value, enableSubPropertyHandling); + emit propertyChanged(name, value); + m_propertyChangedForwardingBlocked = false; +} + void QDesignerPropertyEditor::slotPropertyChanged(const QString &name, const QVariant &value) { - emit propertyValueChanged(name, value, true); + // Forward signal from Integration using the old interfaces. + if (!m_propertyChangedForwardingBlocked) + emit propertyValueChanged(name, value, true); } } diff --git a/tools/designer/src/lib/shared/qdesigner_propertyeditor_p.h b/tools/designer/src/lib/shared/qdesigner_propertyeditor_p.h index cdd53f0..27078f2 100644 --- a/tools/designer/src/lib/shared/qdesigner_propertyeditor_p.h +++ b/tools/designer/src/lib/shared/qdesigner_propertyeditor_p.h @@ -79,7 +79,6 @@ public: static StringPropertyParameters textPropertyValidationMode(QDesignerFormEditorInterface *core, const QObject *object, const QString &propertyName, bool isMainContainer); - Q_SIGNALS: void propertyValueChanged(const QString &name, const QVariant &value, bool enableSubPropertyHandling); void resetProperty(const QString &name); @@ -97,6 +96,13 @@ public Q_SLOTS: private Q_SLOTS: void slotPropertyChanged(const QString &name, const QVariant &value); + +protected: + void emitPropertyValueChanged(const QString &name, const QVariant &value, bool enableSubPropertyHandling); + +private: + bool m_propertyChangedForwardingBlocked; + }; } // namespace qdesigner_internal diff --git a/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp b/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp index b4b962c..08fedd2 100644 --- a/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp +++ b/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp @@ -271,6 +271,7 @@ bool QDesignerPropertySheetPrivate::isReloadableProperty(int index) const { return isResourceProperty(index) || propertyType(index) == QDesignerPropertySheet::PropertyStyleSheet + || propertyType(index) == QDesignerPropertySheet::PropertyText || q->property(index).type() == QVariant::Url; } @@ -549,6 +550,7 @@ QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyTypeFromNam propertyTypeHash.insert(QLatin1String("windowModality"), PropertyWindowModality); propertyTypeHash.insert(QLatin1String("windowModified"), PropertyWindowModified); propertyTypeHash.insert(QLatin1String("styleSheet"), PropertyStyleSheet); + propertyTypeHash.insert(QLatin1String("text"), PropertyText); } return propertyTypeHash.value(name, PropertyNone); } @@ -610,8 +612,9 @@ QDesignerPropertySheet::QDesignerPropertySheet(QObject *object, QObject *parent) createFakeProperty(QLatin1String("whatsThis")); createFakeProperty(QLatin1String("acceptDrops")); createFakeProperty(QLatin1String("dragEnabled")); - // windowModality is visible only for the main container, in which case the form windows enables it on loading + // windowModality/Opacity is visible only for the main container, in which case the form windows enables it on loading setVisible(createFakeProperty(QLatin1String("windowModality")), false); + setVisible(createFakeProperty(QLatin1String("windowOpacity"), double(1.0)), false); if (qobject_cast<const QToolBar *>(d->m_object)) { // prevent toolbars from being dragged off createFakeProperty(QLatin1String("floatable"), QVariant(true)); } else { @@ -719,10 +722,11 @@ int QDesignerPropertySheet::addDynamicProperty(const QString &propName, const QV else if (value.type() == QVariant::Pixmap) v = qVariantFromValue(qdesigner_internal::PropertySheetPixmapValue()); else if (value.type() == QVariant::String) - v = qVariantFromValue(qdesigner_internal::PropertySheetStringValue()); - else if (value.type() == QVariant::KeySequence) - v = qVariantFromValue(qdesigner_internal::PropertySheetKeySequenceValue()); - + v = qVariantFromValue(qdesigner_internal::PropertySheetStringValue(value.toString())); + else if (value.type() == QVariant::KeySequence) { + const QKeySequence keySequence = qVariantValue<QKeySequence>(value); + v = qVariantFromValue(qdesigner_internal::PropertySheetKeySequenceValue(keySequence)); + } if (d->m_addIndex.contains(propName)) { const int idx = d->m_addIndex.value(propName); @@ -1127,7 +1131,7 @@ void QDesignerPropertySheet::setProperty(int index, const QVariant &value) } } - if (isDynamicProperty(index)) { + if (isDynamicProperty(index) || isDefaultDynamicProperty(index)) { if (d->isResourceProperty(index)) d->setResourceProperty(index, value); if (d->isStringProperty(index)) @@ -1197,10 +1201,17 @@ bool QDesignerPropertySheet::reset(int index) } else if (isDynamic(index)) { const QString propName = propertyName(index); const QVariant oldValue = d->m_addProperties.value(index); - const QVariant newValue = d->m_info.value(index).defaultValue; + const QVariant defaultValue = d->m_info.value(index).defaultValue; + QVariant newValue = defaultValue; + if (d->isStringProperty(index)) { + newValue = qVariantFromValue(qdesigner_internal::PropertySheetStringValue(newValue.toString())); + } else if (d->isKeySequenceProperty(index)) { + const QKeySequence keySequence = qVariantValue<QKeySequence>(newValue); + newValue = qVariantFromValue(qdesigner_internal::PropertySheetKeySequenceValue(keySequence)); + } if (oldValue == newValue) return true; - d->m_object->setProperty(propName.toUtf8(), newValue); + d->m_object->setProperty(propName.toUtf8(), defaultValue); d->m_addProperties[index] = newValue; return true; } else if (!d->m_info.value(index).defaultValue.isNull()) { @@ -1451,8 +1462,13 @@ bool QDesignerPropertySheet::isVisible(int index) const } if (isFakeProperty(index)) { - if (type == PropertyWindowModality) // Hidden for child widgets + switch (type) { + case PropertyWindowModality: // Hidden for child widgets + case PropertyWindowOpacity: return d->m_info.value(index).visible; + default: + break; + } return true; } diff --git a/tools/designer/src/lib/shared/qdesigner_propertysheet_p.h b/tools/designer/src/lib/shared/qdesigner_propertysheet_p.h index 9db7367..0105eac 100644 --- a/tools/designer/src/lib/shared/qdesigner_propertysheet_p.h +++ b/tools/designer/src/lib/shared/qdesigner_propertysheet_p.h @@ -176,7 +176,8 @@ public: PropertyWindowIconText, PropertyWindowModality, PropertyWindowModified, - PropertyStyleSheet + PropertyStyleSheet, + PropertyText }; enum ObjectType { ObjectNone, ObjectLabel, ObjectLayout, ObjectLayoutWidget, ObjectQ3GroupBox }; diff --git a/tools/designer/src/lib/shared/qtresourceview.cpp b/tools/designer/src/lib/shared/qtresourceview.cpp index c15942f..18fd07b 100644 --- a/tools/designer/src/lib/shared/qtresourceview.cpp +++ b/tools/designer/src/lib/shared/qtresourceview.cpp @@ -377,7 +377,8 @@ void QtResourceViewPrivate::createPaths() if (!m_resourceModel) return; - const QString root(QLatin1Char(':')); + // Resource root up until 4.6 was ':', changed to ":/" as of 4.7 + const QString root(QLatin1String(":/")); QMap<QString, QString> contents = m_resourceModel->contents(); QMapIterator<QString, QString> itContents(contents); @@ -420,7 +421,7 @@ void QtResourceViewPrivate::filterOutResources() // 3) we hide these items which has pathToVisible value false. const bool matchAll = m_filterPattern.isEmpty(); - const QString root(QLatin1Char(':')); + const QString root(QLatin1String(":/")); QQueue<QString> pathQueue; pathQueue.enqueue(root); @@ -664,6 +665,8 @@ QString QtResourceView::selectedResource() const void QtResourceView::selectResource(const QString &resource) { + if (resource.isEmpty()) + return; QFileInfo fi(resource); QDir dir = fi.absoluteDir(); if (fi.isDir()) diff --git a/tools/designer/src/lib/uilib/properties.cpp b/tools/designer/src/lib/uilib/properties.cpp index 8eccee1..615aa8a 100644 --- a/tools/designer/src/lib/uilib/properties.cpp +++ b/tools/designer/src/lib/uilib/properties.cpp @@ -655,16 +655,21 @@ DomProperty *variantToDomProperty(QAbstractFormBuilder *afb, const QMetaObject * case QVariant::Brush: dom_prop->setElementBrush(afb->saveBrush(qvariant_cast<QBrush>(v))); break; - default: + default: { + const bool hadAttributeStdset = dom_prop->hasAttributeStdset(); + const bool attributeStdset = dom_prop->attributeStdset(); delete dom_prop; if (afb->resourceBuilder()->isResourceType(v)) { dom_prop = afb->resourceBuilder()->saveResource(afb->workingDirectory(), v); - if (dom_prop) + if (dom_prop) { dom_prop->setAttributeName(pname); + if (hadAttributeStdset) + dom_prop->setAttributeStdset(attributeStdset); + } break; } uiLibWarning(msgCannotWriteProperty(pname, v)); - return 0; + } return 0; } return dom_prop; } diff --git a/tools/designer/src/plugins/plugins.pro b/tools/designer/src/plugins/plugins.pro index baf5261..cf4fa8a 100644 --- a/tools/designer/src/plugins/plugins.pro +++ b/tools/designer/src/plugins/plugins.pro @@ -7,3 +7,4 @@ win32:!contains(QT_EDITION, OpenSource):SUBDIRS += activeqt # contains(QT_CONFIG, opengl): SUBDIRS += tools/view3d contains(QT_CONFIG, webkit): SUBDIRS += qwebview contains(QT_CONFIG, phonon): SUBDIRS += phononwidgets +contains(QT_CONFIG, declarative): SUBDIRS += qdeclarativeview diff --git a/tools/designer/src/plugins/qdeclarativeview/qdeclarativeview.pro b/tools/designer/src/plugins/qdeclarativeview/qdeclarativeview.pro new file mode 100644 index 0000000..b8abe87 --- /dev/null +++ b/tools/designer/src/plugins/qdeclarativeview/qdeclarativeview.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +TARGET = qdeclarativeview +CONFIG += qt warn_on plugin designer +QT += declarative + +include(../plugins.pri) +build_all:!build_pass { + CONFIG -= build_all + CONFIG += release +} + +SOURCES += qdeclarativeview_plugin.cpp +HEADERS += qdeclarativeview_plugin.h diff --git a/tools/designer/src/plugins/qdeclarativeview/qdeclarativeview_plugin.cpp b/tools/designer/src/plugins/qdeclarativeview/qdeclarativeview_plugin.cpp new file mode 100644 index 0000000..b352a9b --- /dev/null +++ b/tools/designer/src/plugins/qdeclarativeview/qdeclarativeview_plugin.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeview_plugin.h" + +#include <QtDesigner/QExtensionFactory> +#include <QtDesigner/QExtensionManager> + +#include <QtCore/qplugin.h> +#include <QtDeclarative/QDeclarativeView> + +static const char toolTipC[] = "QtDeclarative view widget"; + +QT_BEGIN_NAMESPACE + +QDeclarativeViewPlugin::QDeclarativeViewPlugin(QObject *parent) : + QObject(parent), + m_initialized(false) +{ +} + +QString QDeclarativeViewPlugin::name() const +{ + return QLatin1String("QDeclarativeView"); +} + +QString QDeclarativeViewPlugin::group() const +{ + return QLatin1String("Display Widgets"); +} + +QString QDeclarativeViewPlugin::toolTip() const +{ + return QString(QLatin1String(toolTipC)); +} + +QString QDeclarativeViewPlugin::whatsThis() const +{ + return QString(QLatin1String(toolTipC)); +} + +QString QDeclarativeViewPlugin::includeFile() const +{ + return QLatin1String("QtDeclarative/QDeclarativeView"); +} + +QIcon QDeclarativeViewPlugin::icon() const +{ + return QIcon(); +} + +bool QDeclarativeViewPlugin::isContainer() const +{ + return false; +} + +QWidget *QDeclarativeViewPlugin::createWidget(QWidget *parent) +{ + return new QDeclarativeView(parent); +} + +bool QDeclarativeViewPlugin::isInitialized() const +{ + return m_initialized; +} + +void QDeclarativeViewPlugin::initialize(QDesignerFormEditorInterface * /*core*/) +{ + if (m_initialized) + return; + + m_initialized = true; +} + +QString QDeclarativeViewPlugin::domXml() const +{ + return QLatin1String("\ + <ui language=\"c++\">\ + <widget class=\"QDeclarativeView\" name=\"declarativeView\">\ + <property name=\"geometry\">\ + <rect>\ + <x>0</x>\ + <y>0</y>\ + <width>300</width>\ + <height>200</height>\ + </rect>\ + </property>\ + </widget>\ + </ui>"); +} + +Q_EXPORT_PLUGIN2(customwidgetplugin, QDeclarativeViewPlugin) + +QT_END_NAMESPACE diff --git a/tools/designer/src/plugins/qdeclarativeview/qdeclarativeview_plugin.h b/tools/designer/src/plugins/qdeclarativeview/qdeclarativeview_plugin.h new file mode 100644 index 0000000..2f13f16 --- /dev/null +++ b/tools/designer/src/plugins/qdeclarativeview/qdeclarativeview_plugin.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEVIEW_PLUGIN_H +#define QDECLARATIVEVIEW_PLUGIN_H + +#include <QtDesigner/QDesignerCustomWidgetInterface> + +QT_BEGIN_NAMESPACE + +class QDeclarativeViewPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) +public: + QDeclarativeViewPlugin(QObject *parent = 0); + + virtual QString name() const; + virtual QString group() const; + virtual QString toolTip() const; + virtual QString whatsThis() const; + virtual QString includeFile() const; + virtual QIcon icon() const; + virtual bool isContainer() const; + virtual QWidget *createWidget(QWidget *parent); + virtual bool isInitialized() const; + virtual void initialize(QDesignerFormEditorInterface *core); + virtual QString domXml() const; + +private: + bool m_initialized; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEVIEW_PLUGIN_H diff --git a/tools/designer/translations/translations.pro b/tools/designer/translations/translations.pro index a1b99fd..103c1fe 100644 --- a/tools/designer/translations/translations.pro +++ b/tools/designer/translations/translations.pro @@ -132,6 +132,7 @@ TRANSLATIONS = \ $$TR_DIR/designer_cs.ts \ $$TR_DIR/designer_de.ts \ $$TR_DIR/designer_fr.ts \ + $$TR_DIR/designer_hu.ts \ $$TR_DIR/designer_ja.ts \ $$TR_DIR/designer_pl.ts \ $$TR_DIR/designer_ru.ts \ diff --git a/tools/linguist/lconvert/main.cpp b/tools/linguist/lconvert/main.cpp index 3a30027..543c405 100644 --- a/tools/linguist/lconvert/main.cpp +++ b/tools/linguist/lconvert/main.cpp @@ -48,6 +48,8 @@ #include <iostream> +QT_USE_NAMESPACE + static int usage(const QStringList &args) { Q_UNUSED(args); diff --git a/tools/linguist/linguist.pro b/tools/linguist/linguist.pro index 85ecd5a..248c89e 100644 --- a/tools/linguist/linguist.pro +++ b/tools/linguist/linguist.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs SUBDIRS = \ - linguist \ lrelease \ lupdate \ lconvert +!no-png:!contains(QT_CONFIG, no-gui):SUBDIRS += linguist diff --git a/tools/linguist/linguist/linguist.pro b/tools/linguist/linguist/linguist.pro index 693bc71..4f7ed8a 100644 --- a/tools/linguist/linguist/linguist.pro +++ b/tools/linguist/linguist/linguist.pro @@ -9,7 +9,7 @@ CONFIG += qt \ uitools DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII -build_all:!build_pass { +build_all:!build_pass { CONFIG -= build_all CONFIG += release } @@ -42,7 +42,7 @@ SOURCES += \ statistics.cpp \ translatedialog.cpp \ translationsettingsdialog.cpp \ - ../shared/simtexth.cpp + ../shared/simtexth.cpp HEADERS += \ batchtranslationdialog.h \ @@ -71,7 +71,7 @@ contains(QT_PRODUCT, OpenSource.*):DEFINES *= QT_OPENSOURCE DEFINES += QT_KEYWORDS TARGET = linguist win32:RC_FILE = linguist.rc -mac { +mac { static:CONFIG -= global_init_link_order ICON = linguist.icns TARGET = Linguist @@ -100,6 +100,7 @@ TRANSLATIONS = \ $$TR_DIR/linguist_cs.ts \ $$TR_DIR/linguist_de.ts \ $$TR_DIR/linguist_fr.ts \ + $$TR_DIR/linguist_hu.ts \ $$TR_DIR/linguist_ja.ts \ $$TR_DIR/linguist_pl.ts \ $$TR_DIR/linguist_ru.ts \ diff --git a/tools/linguist/linguist/mainwindow.cpp b/tools/linguist/linguist/mainwindow.cpp index 321fe8c..1611699 100644 --- a/tools/linguist/linguist/mainwindow.cpp +++ b/tools/linguist/linguist/mainwindow.cpp @@ -1810,28 +1810,50 @@ QString MainWindow::friendlyString(const QString& str) return f.simplified(); } +static inline void setThemeIcon(QAction *action, const char *name, const char *fallback) +{ + const QIcon fallbackIcon(MainWindow::resourcePrefix() + QLatin1String(fallback)); +#ifdef Q_WS_X11 + action->setIcon(QIcon::fromTheme(QLatin1String(name), fallbackIcon)); +#else + Q_UNUSED(name) + action->setIcon(fallbackIcon); +#endif +} + void MainWindow::setupMenuBar() { + // There are no fallback icons for these +#ifdef Q_WS_X11 + m_ui.menuRecentlyOpenedFiles->setIcon(QIcon::fromTheme(QLatin1String("document-open-recent"))); + m_ui.actionCloseAll->setIcon(QIcon::fromTheme(QLatin1String("window-close"))); + m_ui.actionExit->setIcon(QIcon::fromTheme(QLatin1String("application-exit"))); + m_ui.actionSelectAll->setIcon(QIcon::fromTheme(QLatin1String("edit-select-all"))); +#endif + + // Prefer theme icons when available for these actions + setThemeIcon(m_ui.actionOpen, "document-open", "/fileopen.png"); + setThemeIcon(m_ui.actionOpenAux, "document-open", "/fileopen.png"); + setThemeIcon(m_ui.actionSave, "document-save", "/filesave.png"); + setThemeIcon(m_ui.actionSaveAll, "document-save", "/filesave.png"); + setThemeIcon(m_ui.actionPrint, "document-print", "/print.png"); + setThemeIcon(m_ui.actionRedo, "edit-redo", "/redo.png"); + setThemeIcon(m_ui.actionUndo, "edit-undo", "/undo.png"); + setThemeIcon(m_ui.actionCut, "edit-cut", "/editcut.png"); + setThemeIcon(m_ui.actionCopy, "edit-copy", "/editcopy.png"); + setThemeIcon(m_ui.actionPaste, "edit-paste", "/editpaste.png"); + setThemeIcon(m_ui.actionFind, "edit-find", "/searchfind.png"); + + // No well defined theme icons for these actions m_ui.actionAccelerators->setIcon(QIcon(resourcePrefix() + QLatin1String("/accelerator.png"))); m_ui.actionOpenPhraseBook->setIcon(QIcon(resourcePrefix() + QLatin1String("/book.png"))); m_ui.actionDoneAndNext->setIcon(QIcon(resourcePrefix() + QLatin1String("/doneandnext.png"))); - m_ui.actionCopy->setIcon(QIcon(resourcePrefix() + QLatin1String("/editcopy.png"))); - m_ui.actionCut->setIcon(QIcon(resourcePrefix() + QLatin1String("/editcut.png"))); - m_ui.actionPaste->setIcon(QIcon(resourcePrefix() + QLatin1String("/editpaste.png"))); - m_ui.actionOpen->setIcon(QIcon(resourcePrefix() + QLatin1String("/fileopen.png"))); - m_ui.actionOpenAux->setIcon(QIcon(resourcePrefix() + QLatin1String("/fileopen.png"))); - m_ui.actionSaveAll->setIcon(QIcon(resourcePrefix() + QLatin1String("/filesave.png"))); - m_ui.actionSave->setIcon(QIcon(resourcePrefix() + QLatin1String("/filesave.png"))); m_ui.actionNext->setIcon(QIcon(resourcePrefix() + QLatin1String("/next.png"))); m_ui.actionNextUnfinished->setIcon(QIcon(resourcePrefix() + QLatin1String("/nextunfinished.png"))); m_ui.actionPhraseMatches->setIcon(QIcon(resourcePrefix() + QLatin1String("/phrase.png"))); m_ui.actionEndingPunctuation->setIcon(QIcon(resourcePrefix() + QLatin1String("/punctuation.png"))); m_ui.actionPrev->setIcon(QIcon(resourcePrefix() + QLatin1String("/prev.png"))); m_ui.actionPrevUnfinished->setIcon(QIcon(resourcePrefix() + QLatin1String("/prevunfinished.png"))); - m_ui.actionPrint->setIcon(QIcon(resourcePrefix() + QLatin1String("/print.png"))); - m_ui.actionRedo->setIcon(QIcon(resourcePrefix() + QLatin1String("/redo.png"))); - m_ui.actionFind->setIcon(QIcon(resourcePrefix() + QLatin1String("/searchfind.png"))); - m_ui.actionUndo->setIcon(QIcon(resourcePrefix() + QLatin1String("/undo.png"))); m_ui.actionPlaceMarkerMatches->setIcon(QIcon(resourcePrefix() + QLatin1String("/validateplacemarkers.png"))); m_ui.actionWhatsThis->setIcon(QIcon(resourcePrefix() + QLatin1String("/whatsthis.png"))); @@ -2370,7 +2392,7 @@ static bool haveMnemonic(const QString &str) // because we get a lot of false positives. if (c != '&' && c != ' ' && QChar(c).isPrint()) { const ushort *pp = p; - for (; *p < 256 && ::isalpha(*p); p++) ; + for (; *p < 256 && isalpha(*p); p++) ; if (pp == p || *p != ';') return true; // This looks like a HTML &entity;, so ignore it. As a HTML string diff --git a/tools/linguist/linguist/mainwindow.ui b/tools/linguist/linguist/mainwindow.ui index 450ce89..4edde5e 100644 --- a/tools/linguist/linguist/mainwindow.ui +++ b/tools/linguist/linguist/mainwindow.ui @@ -679,7 +679,7 @@ <string>About Qt</string> </property> <property name="whatsThis"> - <string>Display information about the Qt toolkit by Trolltech.</string> + <string>Display information about the Qt toolkit by Nokia.</string> </property> <property name="menuRole"> <enum>QAction::AboutQtRole</enum> diff --git a/tools/linguist/linguist/messagemodel.cpp b/tools/linguist/linguist/messagemodel.cpp index 4e2b473..39ba9fd 100644 --- a/tools/linguist/linguist/messagemodel.cpp +++ b/tools/linguist/linguist/messagemodel.cpp @@ -402,7 +402,7 @@ bool DataModel::setLanguageAndCountry(QLocale::Language lang, QLocale::Country c if (lang == QLocale::C || uint(lang) > uint(QLocale::LastLanguage)) // XXX does this make any sense? lang = QLocale::English; QByteArray rules; - bool ok = getNumerusInfo(lang, country, &rules, &m_numerusForms); + bool ok = getNumerusInfo(lang, country, &rules, &m_numerusForms, 0); m_localizedLanguage = QCoreApplication::translate("MessageEditor", QLocale::languageToString(lang).toAscii()); m_countRefNeeds.clear(); for (int i = 0; i < rules.size(); ++i) { diff --git a/tools/linguist/lupdate/lupdate.h b/tools/linguist/lupdate/lupdate.h index 70332cd..136884b 100644 --- a/tools/linguist/lupdate/lupdate.h +++ b/tools/linguist/lupdate/lupdate.h @@ -79,6 +79,7 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat bool loadJava(Translator &translator, const QString &filename, ConversionData &cd); bool loadQScript(Translator &translator, const QString &filename, ConversionData &cd); bool loadUI(Translator &translator, const QString &filename, ConversionData &cd); +bool loadQml(Translator &translator, const QString &filename, ConversionData &cd); QT_END_NAMESPACE diff --git a/tools/linguist/lupdate/lupdate.pro b/tools/linguist/lupdate/lupdate.pro index ccc2d47..3ed909a 100644 --- a/tools/linguist/lupdate/lupdate.pro +++ b/tools/linguist/lupdate/lupdate.pro @@ -15,6 +15,9 @@ build_all:!build_pass { include(../shared/formats.pri) include(../shared/proparser.pri) +include($$QT_SOURCE_TREE/src/declarative/qml/parser/parser.pri) +INCLUDEPATH += $$QT_SOURCE_TREE/src/declarative/qml $$QT_BUILD_TREE/include/QtDeclarative + SOURCES += \ main.cpp \ merge.cpp \ @@ -23,6 +26,7 @@ SOURCES += \ cpp.cpp \ java.cpp \ qscript.cpp \ + qdeclarative.cpp \ ui.cpp HEADERS += \ diff --git a/tools/linguist/lupdate/main.cpp b/tools/linguist/lupdate/main.cpp index b2bfd7c..6c9157a 100644 --- a/tools/linguist/lupdate/main.cpp +++ b/tools/linguist/lupdate/main.cpp @@ -83,7 +83,7 @@ static void printUsage() printOut(QObject::tr( "Usage:\n" " lupdate [options] [project-file]...\n" - " lupdate [options] [source-file|path]... -ts ts-files\n\n" + " lupdate [options] [source-file|path|@lst-file]... -ts ts-files|@lst-file\n\n" "lupdate is part of Qt's Linguist tool chain. It extracts translatable\n" "messages from Qt UI files, C++, Java and JavaScript/QtScript source code.\n" "Extracted messages are stored in textual translation source files (typically\n" @@ -132,6 +132,8 @@ static void printUsage() " Specify the codec assumed for tr() calls. Effective only with -ts.\n" " -version\n" " Display the version of lupdate and exit.\n" + " @lst-file\n" + " Read additional file names (one per line) from lst-file.\n" ).arg(m_defaultExtensions)); } @@ -267,6 +269,8 @@ static void processSources(Translator &fetchedTor, else if (it->endsWith(QLatin1String(".js"), Qt::CaseInsensitive) || it->endsWith(QLatin1String(".qs"), Qt::CaseInsensitive)) loadQScript(fetchedTor, *it, cd); + else if (it->endsWith(QLatin1String(".qml"), Qt::CaseInsensitive)) + loadQml(fetchedTor, *it, cd); else sourceFilesCpp << *it; } @@ -405,7 +409,7 @@ static void processProjects( int main(int argc, char **argv) { QCoreApplication app(argc, argv); - m_defaultExtensions = QLatin1String("ui,c,c++,cc,cpp,cxx,ch,h,h++,hh,hpp,hxx"); + m_defaultExtensions = QLatin1String("java,jui,ui,c,c++,cc,cpp,cxx,ch,h,h++,hh,hpp,hxx,js,qs,qml"); QStringList args = app.arguments(); QStringList tsFileNames; @@ -560,73 +564,93 @@ int main(int argc, char **argv) return 1; } + QStringList files; + if (arg.startsWith(QLatin1String("@"))) { + QFile lstFile(arg.mid(1)); + if (!lstFile.open(QIODevice::ReadOnly)) { + qWarning("lupdate error: List file '%s' is not readable", + qPrintable(lstFile.fileName())); + return 1; + } + while (!lstFile.atEnd()) + files << QString::fromLocal8Bit(lstFile.readLine().trimmed()); + } else { + files << arg; + } if (metTsFlag) { - bool found = false; - foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) { - if (arg.endsWith(QLatin1Char('.') + fmt.extension, Qt::CaseInsensitive)) { - QFileInfo fi(arg); - if (!fi.exists() || fi.isWritable()) { - tsFileNames.append(QFileInfo(arg).absoluteFilePath()); - } else { - qWarning("lupdate warning: For some reason, '%s' is not writable.\n", - qPrintable(arg)); + foreach (const QString &file, files) { + bool found = false; + foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) { + if (file.endsWith(QLatin1Char('.') + fmt.extension, Qt::CaseInsensitive)) { + QFileInfo fi(file); + if (!fi.exists() || fi.isWritable()) { + tsFileNames.append(QFileInfo(file).absoluteFilePath()); + } else { + qWarning("lupdate warning: For some reason, '%s' is not writable.\n", + qPrintable(file)); + } + found = true; + break; } - found = true; - break; + } + if (!found) { + qWarning("lupdate error: File '%s' has no recognized extension\n", + qPrintable(file)); + return 1; } } - if (!found) { - qWarning("lupdate error: File '%s' has no recognized extension\n", - qPrintable(arg)); - return 1; - } - } else if (arg.endsWith(QLatin1String(".pro"), Qt::CaseInsensitive) - || arg.endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) { - proFiles << arg; numFiles++; } else { - QFileInfo fi(arg); - if (!fi.exists()) { - qWarning("lupdate error: File '%s' does not exists\n", qPrintable(arg)); - return 1; - } else if (fi.isDir()) { - if (options & Verbose) - printOut(QObject::tr("Scanning directory '%1'...").arg(arg)); - QDir dir = QDir(fi.filePath()); - projectRoots.insert(dir.absolutePath() + QLatin1Char('/')); - if (extensionsNameFilters.isEmpty()) { - foreach (QString ext, extensions.split(QLatin1Char(','))) { - ext = ext.trimmed(); - if (ext.startsWith(QLatin1Char('.'))) - ext.remove(0, 1); - extensionsNameFilters.insert(ext); - } + foreach (const QString &file, files) { + QFileInfo fi(file); + if (!fi.exists()) { + qWarning("lupdate error: File '%s' does not exists\n", qPrintable(file)); + return 1; } - QDir::Filters filters = QDir::Files | QDir::NoSymLinks; - if (recursiveScan) - filters |= QDir::AllDirs | QDir::NoDotAndDotDot; - QFileInfoList fileinfolist; - recursiveFileInfoList(dir, extensionsNameFilters, filters, &fileinfolist); - int scanRootLen = dir.absolutePath().length(); - foreach (const QFileInfo &fi, fileinfolist) { - QString fn = QDir::cleanPath(fi.absoluteFilePath()); - sourceFiles << fn; - - if (!fn.endsWith(QLatin1String(".java")) - && !fn.endsWith(QLatin1String(".ui")) - && !fn.endsWith(QLatin1String(".js")) - && !fn.endsWith(QLatin1String(".qs"))) { - int offset = 0; - int depth = 0; - do { - offset = fn.lastIndexOf(QLatin1Char('/'), offset - 1); - QString ffn = fn.mid(offset + 1); - allCSources.insert(ffn, fn); - } while (++depth < 3 && offset > scanRootLen); + if (file.endsWith(QLatin1String(".pro"), Qt::CaseInsensitive) + || file.endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) { + proFiles << file; + } else if (fi.isDir()) { + if (options & Verbose) + printOut(QObject::tr("Scanning directory '%1'...").arg(file)); + QDir dir = QDir(fi.filePath()); + projectRoots.insert(dir.absolutePath() + QLatin1Char('/')); + if (extensionsNameFilters.isEmpty()) { + foreach (QString ext, extensions.split(QLatin1Char(','))) { + ext = ext.trimmed(); + if (ext.startsWith(QLatin1Char('.'))) + ext.remove(0, 1); + extensionsNameFilters.insert(ext); + } + } + QDir::Filters filters = QDir::Files | QDir::NoSymLinks; + if (recursiveScan) + filters |= QDir::AllDirs | QDir::NoDotAndDotDot; + QFileInfoList fileinfolist; + recursiveFileInfoList(dir, extensionsNameFilters, filters, &fileinfolist); + int scanRootLen = dir.absolutePath().length(); + foreach (const QFileInfo &fi, fileinfolist) { + QString fn = QDir::cleanPath(fi.absoluteFilePath()); + sourceFiles << fn; + + if (!fn.endsWith(QLatin1String(".java")) + && !fn.endsWith(QLatin1String(".jui")) + && !fn.endsWith(QLatin1String(".ui")) + && !fn.endsWith(QLatin1String(".js")) + && !fn.endsWith(QLatin1String(".qs")) + && !fn.endsWith(QLatin1String(".qml"))) { + int offset = 0; + int depth = 0; + do { + offset = fn.lastIndexOf(QLatin1Char('/'), offset - 1); + QString ffn = fn.mid(offset + 1); + allCSources.insert(ffn, fn); + } while (++depth < 3 && offset > scanRootLen); + } } + } else { + sourceFiles << QDir::cleanPath(fi.absoluteFilePath());; } - } else { - sourceFiles << QDir::cleanPath(fi.absoluteFilePath());; } numFiles++; } diff --git a/tools/linguist/lupdate/qdeclarative.cpp b/tools/linguist/lupdate/qdeclarative.cpp new file mode 100644 index 0000000..a734e99 --- /dev/null +++ b/tools/linguist/lupdate/qdeclarative.cpp @@ -0,0 +1,240 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "lupdate.h" + +#include <translator.h> + +#include <QtCore/QDebug> +#include <QtCore/QFile> +#include <QtCore/QString> + +#include "parser/qdeclarativejsengine_p.h" +#include "parser/qdeclarativejsparser_p.h" +#include "parser/qdeclarativejslexer_p.h" +#include "parser/qdeclarativejsnodepool_p.h" +#include "parser/qdeclarativejsastvisitor_p.h" +#include "parser/qdeclarativejsast_p.h" + +#include <QCoreApplication> +#include <QFile> +#include <QFileInfo> +#include <QtDebug> +#include <QStringList> + +#include <iostream> +#include <cstdlib> + +QT_BEGIN_NAMESPACE + +using namespace QDeclarativeJS; + +class FindTrCalls: protected AST::Visitor +{ +public: + void operator()(Translator *translator, const QString &fileName, AST::Node *node) + { + m_translator = translator; + m_fileName = fileName; + m_component = QFileInfo(fileName).baseName(); //matches qsTr usage in QScriptEngine + accept(node); + } + +protected: + using AST::Visitor::visit; + using AST::Visitor::endVisit; + + void accept(AST::Node *node) + { AST::Node::acceptChild(node, this); } + + virtual void endVisit(AST::CallExpression *node) + { + if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(node->base)) { + if (idExpr->name->asString() == QLatin1String("qsTr") || + idExpr->name->asString() == QLatin1String("QT_TR_NOOP")) { + if (node->arguments && AST::cast<AST::StringLiteral *>(node->arguments->expression)) { + AST::StringLiteral *literal = AST::cast<AST::StringLiteral *>(node->arguments->expression); + const QString source = literal->value->asString(); + + QString comment; + bool plural = false; + AST::ArgumentList *commentNode = node->arguments->next; + if (commentNode) { + literal = AST::cast<AST::StringLiteral *>(commentNode->expression); + comment = literal->value->asString(); + + AST::ArgumentList *nNode = commentNode->next; + if (nNode) { + AST::NumericLiteral *numLiteral = AST::cast<AST::NumericLiteral *>(nNode->expression); + if (numLiteral) { + plural = true; + } + } + } + + TranslatorMessage msg(m_component, source, + comment, QString(), m_fileName, + node->firstSourceLocation().startLine, QStringList(), + TranslatorMessage::Unfinished, plural); + m_translator->extend(msg); + } + } else if (idExpr->name->asString() == QLatin1String("qsTranslate") || + idExpr->name->asString() == QLatin1String("QT_TRANSLATE_NOOP")) { + if (node->arguments && AST::cast<AST::StringLiteral *>(node->arguments->expression)) { + AST::StringLiteral *literal = AST::cast<AST::StringLiteral *>(node->arguments->expression); + const QString context = literal->value->asString(); + + QString source; + QString comment; + bool plural = false; + AST::ArgumentList *sourceNode = node->arguments->next; + if (sourceNode) { + literal = AST::cast<AST::StringLiteral *>(sourceNode->expression); + source = literal->value->asString(); + AST::ArgumentList *commentNode = sourceNode->next; + if (commentNode) { + literal = AST::cast<AST::StringLiteral *>(commentNode->expression); + comment = literal->value->asString(); + + AST::ArgumentList *nNode = commentNode->next; + if (nNode) { + AST::NumericLiteral *numLiteral = AST::cast<AST::NumericLiteral *>(nNode->expression); + if (numLiteral) { + plural = true; + } + } + } + } + + TranslatorMessage msg(context, source, + comment, QString(), m_fileName, + node->firstSourceLocation().startLine, QStringList(), + TranslatorMessage::Unfinished, plural); + m_translator->extend(msg); + } + + } + } + } + +private: + Translator *m_translator; + QString m_fileName; + QString m_component; +}; + +QString createErrorString(const QString &filename, const QString &code, Parser &parser) +{ + // print out error + QStringList lines = code.split(QLatin1Char('\n')); + lines.append(QLatin1String("\n")); // sentinel. + QString errorString; + + foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) { + + if (m.isWarning()) + continue; + + QString error = filename + QLatin1Char(':') + QString::number(m.loc.startLine) + + QLatin1Char(':') + QString::number(m.loc.startColumn) + QLatin1String(": error: ") + + m.message + QLatin1Char('\n'); + + int line = 0; + if (m.loc.startLine > 0) + line = m.loc.startLine - 1; + + const QString textLine = lines.at(line); + + error += textLine + QLatin1Char('\n'); + + int column = m.loc.startColumn - 1; + if (column < 0) + column = 0; + + column = qMin(column, textLine.length()); + + for (int i = 0; i < column; ++i) { + const QChar ch = textLine.at(i); + if (ch.isSpace()) + error += ch.unicode(); + else + error += QLatin1Char(' '); + } + error += QLatin1String("^\n"); + errorString += error; + } + return errorString; +} + +bool loadQml(Translator &translator, const QString &filename, ConversionData &cd) +{ + cd.m_sourceFileName = filename; + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + cd.appendError(QString::fromLatin1("Cannot open %1: %2") + .arg(filename, file.errorString())); + return false; + } + + const QString code = QTextStream(&file).readAll(); + + Engine driver; + Parser parser(&driver); + + NodePool nodePool(filename, &driver); + driver.setNodePool(&nodePool); + + Lexer lexer(&driver); + lexer.setCode(code, /*line = */ 1); + driver.setLexer(&lexer); + + if (parser.parse()) { + FindTrCalls trCalls; + trCalls(&translator, filename, parser.ast()); + } else { + QString error = createErrorString(filename, code, parser); + cd.appendError(error); + return false; + } + return true; +} + +QT_END_NAMESPACE diff --git a/tools/linguist/lupdate/qscript.cpp b/tools/linguist/lupdate/qscript.cpp index 6f34c2b..33276e6 100644 --- a/tools/linguist/lupdate/qscript.cpp +++ b/tools/linguist/lupdate/qscript.cpp @@ -40,6 +40,26 @@ ** ****************************************************************************/ + +#define Q_SCRIPT_REGEXPLITERAL_RULE1 7 + +#define Q_SCRIPT_REGEXPLITERAL_RULE2 8 + +#include <translator.h> + +#include <QtCore/qdebug.h> +#include <QtCore/qnumeric.h> +#include <QtCore/qstring.h> +#include <QtCore/qtextcodec.h> +#include <QtCore/qvariant.h> + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +QT_BEGIN_NAMESPACE + class QScriptGrammar { public: @@ -174,7 +194,6 @@ public: } }; - const char *const QScriptGrammar::spell [] = { "end of file", "&", "&&", "&=", "break", "case", "catch", ":", ";", "continue", "default", "delete", "/", "/=", "do", ".", "else", "=", "==", "===", @@ -747,26 +766,6 @@ const int QScriptGrammar::action_check [] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; - -#define Q_SCRIPT_REGEXPLITERAL_RULE1 7 - -#define Q_SCRIPT_REGEXPLITERAL_RULE2 8 - -#include <translator.h> - -#include <QtCore/qdebug.h> -#include <QtCore/qnumeric.h> -#include <QtCore/qstring.h> -#include <QtCore/qtextcodec.h> -#include <QtCore/qvariant.h> - -#include <ctype.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -QT_BEGIN_NAMESPACE - static void recordMessage( Translator *tor, const QString &context, const QString &text, const QString &comment, const QString &extracomment, bool plural, const QString &fileName, int lineNo) diff --git a/tools/linguist/shared/numerus.cpp b/tools/linguist/shared/numerus.cpp index d45dfed..6066732 100644 --- a/tools/linguist/shared/numerus.cpp +++ b/tools/linguist/shared/numerus.cpp @@ -64,7 +64,7 @@ static const uchar icelandicRules[] = static const uchar irishStyleRules[] = { Q_EQ, 1, Q_NEWRULE, Q_EQ, 2 }; -static const uchar slovakRules[] = +static const uchar slovakStyleRules[] = { Q_EQ, 1, Q_NEWRULE, Q_BETWEEN, 2, 4 }; static const uchar macedonianRules[] = @@ -100,7 +100,7 @@ static const uchar arabicRules[] = Q_EQ, 1, Q_NEWRULE, Q_EQ, 2, Q_NEWRULE, Q_MOD_100 | Q_BETWEEN, 3, 10, Q_NEWRULE, - Q_MOD_100 | Q_NOT | Q_BETWEEN, 0, 2 }; + Q_MOD_100 | Q_GEQ, 11 }; static const uchar tagalogRules[] = { Q_LEQ, 1, Q_NEWRULE, Q_MOD_10 | Q_EQ, 4, Q_OR, Q_MOD_10 | Q_EQ, 6, Q_OR, Q_MOD_10 | Q_EQ, 9 }; @@ -114,7 +114,7 @@ static const char * const frenchStyleForms[] = { "Singular", "Plural", 0 }; static const char * const icelandicForms[] = { "Singular", "Plural", 0 }; static const char * const latvianForms[] = { "Singular", "Plural", "Nullar", 0 }; static const char * const irishStyleForms[] = { "Singular", "Dual", "Plural", 0 }; -static const char * const slovakForms[] = { "Singular", "Paucal", "Plural", 0 }; +static const char * const slovakStyleForms[] = { "Singular", "Paucal", "Plural", 0 }; static const char * const macedonianForms[] = { "Singular", "Dual", "Plural", 0 }; static const char * const lithuanianForms[] = { "Singular", "Paucal", "Plural", 0 }; static const char * const russianStyleForms[] = { "Singular", "Dual", "Plural", 0 }; @@ -279,7 +279,7 @@ static const QLocale::Language irishStyleLanguages[] = { QLocale::Sanskrit, EOL }; -static const QLocale::Language slovakLanguages[] = { QLocale::Slovak, QLocale::Czech, EOL }; +static const QLocale::Language slovakStyleLanguages[] = { QLocale::Slovak, QLocale::Czech, EOL }; static const QLocale::Language macedonianLanguage[] = { QLocale::Macedonian, EOL }; static const QLocale::Language lithuanianLanguage[] = { QLocale::Lithuanian, EOL }; static const QLocale::Language russianStyleLanguages[] = { @@ -318,28 +318,45 @@ struct NumerusTableEntry { const char * const *forms; const QLocale::Language *languages; const QLocale::Country *countries; + const char * const gettextRules; }; static const NumerusTableEntry numerusTable[] = { - { 0, 0, japaneseStyleForms, japaneseStyleLanguages, 0 }, - { englishStyleRules, sizeof(englishStyleRules), englishStyleForms, englishStyleLanguages, 0 }, + { 0, 0, japaneseStyleForms, japaneseStyleLanguages, 0, "nplurals=1; plural=0;" }, + { englishStyleRules, sizeof(englishStyleRules), englishStyleForms, englishStyleLanguages, 0, + "nplurals=2; plural=(n != 1);" }, { frenchStyleRules, sizeof(frenchStyleRules), frenchStyleForms, frenchStyleLanguages, - frenchStyleCountries }, - { latvianRules, sizeof(latvianRules), latvianForms, latvianLanguage, 0 }, - { icelandicRules, sizeof(icelandicRules), icelandicForms, icelandicLanguage, 0 }, - { irishStyleRules, sizeof(irishStyleRules), irishStyleForms, irishStyleLanguages, 0 }, - { slovakRules, sizeof(slovakRules), slovakForms, slovakLanguages, 0 }, - { macedonianRules, sizeof(macedonianRules), macedonianForms, macedonianLanguage, 0 }, - { lithuanianRules, sizeof(lithuanianRules), lithuanianForms, lithuanianLanguage, 0 }, - { russianStyleRules, sizeof(russianStyleRules), russianStyleForms, russianStyleLanguages, 0 }, - { polishRules, sizeof(polishRules), polishForms, polishLanguage, 0 }, - { romanianRules, sizeof(romanianRules), romanianForms, romanianLanguages, 0 }, - { slovenianRules, sizeof(slovenianRules), slovenianForms, slovenianLanguage, 0 }, - { malteseRules, sizeof(malteseRules), malteseForms, malteseLanguage, 0 }, - { welshRules, sizeof(welshRules), welshForms, welshLanguage, 0 }, - { arabicRules, sizeof(arabicRules), arabicForms, arabicLanguage, 0 }, - { tagalogRules, sizeof(tagalogRules), tagalogForms, tagalogLanguage, 0 }, - { catalanRules, sizeof(catalanRules), catalanForms, catalanLanguage, 0 } + frenchStyleCountries, "nplurals=2; plural=(n > 1);" }, + { latvianRules, sizeof(latvianRules), latvianForms, latvianLanguage, 0, + "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);" }, + { icelandicRules, sizeof(icelandicRules), icelandicForms, icelandicLanguage, 0, + "nplurals=2; plural=(n%10==1 && n%100!=11 ? 0 : 1);" }, + { irishStyleRules, sizeof(irishStyleRules), irishStyleForms, irishStyleLanguages, 0, + "nplurals=3; plural=(n==1 ? 0 : n==2 ? 1 : 2);" }, + { slovakStyleRules, sizeof(slovakStyleRules), slovakStyleForms, slovakStyleLanguages, 0, + "nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);" }, + { macedonianRules, sizeof(macedonianRules), macedonianForms, macedonianLanguage, 0, + "nplurals=3; plural=(n%100==1 ? 0 : n%100==2 ? 1 : 2);" }, + { lithuanianRules, sizeof(lithuanianRules), lithuanianForms, lithuanianLanguage, 0, + "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);" }, + { russianStyleRules, sizeof(russianStyleRules), russianStyleForms, russianStyleLanguages, 0, + "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" }, + { polishRules, sizeof(polishRules), polishForms, polishLanguage, 0, + "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" }, + { romanianRules, sizeof(romanianRules), romanianForms, romanianLanguages, 0, + "nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2);" }, + { slovenianRules, sizeof(slovenianRules), slovenianForms, slovenianLanguage, 0, + "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);" }, + { malteseRules, sizeof(malteseRules), malteseForms, malteseLanguage, 0, + "nplurals=4; plural=(n==1 ? 0 : (n==0 || (n%100>=1 && n%100<=10)) ? 1 : (n%100>=11 && n%100<=19) ? 2 : 3);" }, + { welshRules, sizeof(welshRules), welshForms, welshLanguage, 0, + "nplurals=5; plural=(n==0 ? 0 : n==1 ? 1 : (n>=2 && n<=5) ? 2 : n==6 ? 3 : 4);" }, + { arabicRules, sizeof(arabicRules), arabicForms, arabicLanguage, 0, + "nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : (n%100>=3 && n%100<=10) ? 3 : n%100>=11 ? 4 : 5);" }, + { tagalogRules, sizeof(tagalogRules), tagalogForms, tagalogLanguage, 0, + "nplurals=3; plural=(n==1 ? 0 : (n%10==4 || n%10==6 || n%10== 9) ? 1 : 2);" }, + { catalanRules, sizeof(catalanRules), catalanForms, catalanLanguage, 0, + "nplurals=3; plural=(n==1 ? 0 : (n==11 || n/1000==11 || n/1000000==11 || n/1000000000==11) ? 1 : 2);" }, }; static const int NumerusTableSize = sizeof(numerusTable) / sizeof(numerusTable[0]); @@ -352,7 +369,7 @@ static const uchar magic[MagicLength] = { }; bool getNumerusInfo(QLocale::Language language, QLocale::Country country, - QByteArray *rules, QStringList *forms) + QByteArray *rules, QStringList *forms, const char **gettextRules) { while (true) { for (int i = 0; i < NumerusTableSize; ++i) { @@ -365,6 +382,8 @@ bool getNumerusInfo(QLocale::Language language, QLocale::Country country, *rules = QByteArray::fromRawData(reinterpret_cast<const char *>(entry.rules), entry.rulesSize); } + if (gettextRules) + *gettextRules = entry.gettextRules; if (forms) { forms->clear(); for (int k = 0; entry.forms[k]; ++k) diff --git a/tools/linguist/shared/po.cpp b/tools/linguist/shared/po.cpp index 3354d61..99a8751 100644 --- a/tools/linguist/shared/po.cpp +++ b/tools/linguist/shared/po.cpp @@ -45,6 +45,7 @@ #include <QtCore/QIODevice> #include <QtCore/QHash> #include <QtCore/QString> +#include <QtCore/QTextCodec> #include <QtCore/QTextStream> #include <ctype.h> @@ -201,55 +202,54 @@ public: public: - QString id; - QString context; - QString tscomment; - QString oldTscomment; - QString lineNumber; - QString fileName; - QString references; - QString translatorComments; - QString automaticComments; - QString msgId; - QString oldMsgId; - QStringList msgStr; + QByteArray id; + QByteArray context; + QByteArray tscomment; + QByteArray oldTscomment; + QByteArray lineNumber; + QByteArray fileName; + QByteArray references; + QByteArray translatorComments; + QByteArray automaticComments; + QByteArray msgId; + QByteArray oldMsgId; + QList<QByteArray> msgStr; bool isPlural; bool isFuzzy; QHash<QString, QString> extra; }; -static bool isTranslationLine(const QString &line) +static bool isTranslationLine(const QByteArray &line) { - return line.startsWith(QLatin1String("#~ msgstr")) - || line.startsWith(QLatin1String("msgstr")); + return line.startsWith("#~ msgstr") || line.startsWith("msgstr"); } -static QString slurpEscapedString(const QStringList &lines, int & l, - int offset, const QString &prefix, ConversionData &cd) +static QByteArray slurpEscapedString(const QList<QByteArray> &lines, int &l, + int offset, const QByteArray &prefix, ConversionData &cd) { - QString msg; + QByteArray msg; int stoff; for (; l < lines.size(); ++l) { - const QString &line = lines.at(l); + const QByteArray &line = lines.at(l); if (line.isEmpty() || !line.startsWith(prefix)) break; - while (line[offset].isSpace()) // No length check, as string has no trailing spaces. + while (isspace(line[offset])) // No length check, as string has no trailing spaces. offset++; - if (line[offset].unicode() != '"') + if (line[offset] != '"') break; offset++; forever { if (offset == line.length()) goto premature_eol; - ushort c = line[offset++].unicode(); + uchar c = line[offset++]; if (c == '"') { if (offset == line.length()) break; - while (line[offset].isSpace()) + while (isspace(line[offset])) offset++; - if (line[offset++].unicode() != '"') { + if (line[offset++] != '"') { cd.appendError(QString::fromLatin1( "PO parsing error: extra characters on line %1.") .arg(l + 1)); @@ -260,34 +260,34 @@ static QString slurpEscapedString(const QStringList &lines, int & l, if (c == '\\') { if (offset == line.length()) goto premature_eol; - c = line[offset++].unicode(); + c = line[offset++]; switch (c) { case 'r': - msg += QLatin1Char('\r'); // Maybe just throw it away? + msg += '\r'; // Maybe just throw it away? break; case 'n': - msg += QLatin1Char('\n'); + msg += '\n'; break; case 't': - msg += QLatin1Char('\t'); + msg += '\t'; break; case 'v': - msg += QLatin1Char('\v'); + msg += '\v'; break; case 'a': - msg += QLatin1Char('\a'); + msg += '\a'; break; case 'b': - msg += QLatin1Char('\b'); + msg += '\b'; break; case 'f': - msg += QLatin1Char('\f'); + msg += '\f'; break; case '"': - msg += QLatin1Char('"'); + msg += '"'; break; case '\\': - msg += QLatin1Char('\\'); + msg += '\\'; break; case '0': case '1': @@ -298,28 +298,28 @@ static QString slurpEscapedString(const QStringList &lines, int & l, case '6': case '7': stoff = offset - 1; - while ((c = line[offset].unicode()) >= '0' && c <= '7') + while ((c = line[offset]) >= '0' && c <= '7') if (++offset == line.length()) goto premature_eol; - msg += QChar(line.mid(stoff, offset - stoff).toUInt(0, 8)); + msg += line.mid(stoff, offset - stoff).toUInt(0, 8); break; case 'x': stoff = offset; - while (isxdigit(line[offset].unicode())) + while (isxdigit(line[offset])) if (++offset == line.length()) goto premature_eol; - msg += QChar(line.mid(stoff, offset - stoff).toUInt(0, 16)); + msg += line.mid(stoff, offset - stoff).toUInt(0, 16); break; default: cd.appendError(QString::fromLatin1( "PO parsing error: invalid escape '\\%1' (line %2).") - .arg(QChar(c)).arg(l + 1)); - msg += QLatin1Char('\\'); - msg += QChar(c); + .arg(QChar((uint)c)).arg(l + 1)); + msg += '\\'; + msg += c; break; } } else { - msg += QChar(c); + msg += c; } } offset = prefix.size(); @@ -330,36 +330,61 @@ static QString slurpEscapedString(const QStringList &lines, int & l, premature_eol: cd.appendError(QString::fromLatin1( "PO parsing error: premature end of line %1.").arg(l + 1)); - return QString(); + return QByteArray(); } -static void slurpComment(QString &msg, const QStringList &lines, int & l) +static void slurpComment(QByteArray &msg, const QList<QByteArray> &lines, int & l) { - const QChar newline = QLatin1Char('\n'); - QString prefix = lines.at(l); + QByteArray prefix = lines.at(l); for (int i = 1; ; i++) { - if (prefix.at(i).unicode() != ' ') { + if (prefix.at(i) != ' ') { prefix.truncate(i); break; } } for (; l < lines.size(); ++l) { - const QString &line = lines.at(l); + const QByteArray &line = lines.at(l); if (line.startsWith(prefix)) msg += line.mid(prefix.size()); - else if (line != QLatin1String("#")) + else if (line != "#") break; - msg += newline; + msg += '\n'; } --l; } +static QString makePoHeader(const QString &str) +{ + return QLatin1String("po-header-") + str.toLower().replace(QLatin1Char('-'), QLatin1Char('_')); +} + +static QByteArray QByteArrayList_join(const QList<QByteArray> &that, char sep) +{ + int totalLength = 0; + const int size = that.size(); + + for (int i = 0; i < size; ++i) + totalLength += that.at(i).size(); + + if (size > 0) + totalLength += size - 1; + + QByteArray res; + if (totalLength == 0) + return res; + res.reserve(totalLength); + for (int i = 0; i < that.size(); ++i) { + if (i) + res += sep; + res += that.at(i); + } + return res; +} + bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) { - const QChar quote = QLatin1Char('"'); - const QChar newline = QLatin1Char('\n'); - QTextStream in(&dev); - in.setCodec(cd.m_codecForSource.isEmpty() ? QByteArray("UTF-8") : cd.m_codecForSource); + QTextCodec *codec = QTextCodec::codecForName( + cd.m_codecForSource.isEmpty() ? QByteArray("UTF-8") : cd.m_codecForSource); bool error = false; // format of a .po file entry: @@ -380,25 +405,23 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) // ... // we need line based lookahead below. - QStringList lines; - while (!in.atEnd()) - lines.append(in.readLine().trimmed()); - lines.append(QString()); + QList<QByteArray> lines; + while (!dev.atEnd()) + lines.append(dev.readLine().trimmed()); + lines.append(QByteArray()); - int l = 0; + int l = 0, lastCmtLine = -1; PoItem item; for (; l != lines.size(); ++l) { - QString line = lines.at(l); + QByteArray line = lines.at(l); if (line.isEmpty()) continue; if (isTranslationLine(line)) { - bool isObsolete = line.startsWith(QLatin1String("#~ msgstr")); - const QString prefix = QLatin1String(isObsolete ? "#~ " : ""); + bool isObsolete = line.startsWith("#~ msgstr"); + const QByteArray prefix = isObsolete ? "#~ " : ""; while (true) { - int idx = line.indexOf(QLatin1Char(' '), prefix.length()); - QString str = slurpEscapedString(lines, l, idx, prefix, cd); - str.replace(QChar(Translator::TextVariantSeparator), - QChar(Translator::BinaryVariantSeparator)); + int idx = line.indexOf(' ', prefix.length()); + QByteArray str = slurpEscapedString(lines, l, idx, prefix, cd); item.msgStr.append(str); if (l + 1 >= lines.size() || !isTranslationLine(lines.at(l + 1))) break; @@ -406,31 +429,109 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) line = lines.at(l); } if (item.msgId.isEmpty()) { - QRegExp rx(QLatin1String("\\bX-Language: ([^\n]*)\n")); - int idx = rx.indexIn(item.msgStr.first()); - if (idx >= 0) { - translator.setLanguageCode(rx.cap(1)); - item.msgStr.first().remove(idx, rx.matchedLength()); + QHash<QString, QByteArray> extras; + QList<QByteArray> hdrOrder; + QByteArray pluralForms; + foreach (const QByteArray &hdr, item.msgStr.first().split('\n')) { + if (hdr.isEmpty()) + continue; + int idx = hdr.indexOf(':'); + if (idx < 0) { + cd.appendError(QString::fromLatin1("Unexpected PO header format '%1'\n") + .arg(QString::fromLatin1(hdr))); + error = true; + break; + } + QByteArray hdrName = hdr.left(idx).trimmed(); + QByteArray hdrValue = hdr.mid(idx + 1).trimmed(); + hdrOrder << hdrName; + if (hdrName == "X-Language") { + translator.setLanguageCode(QString::fromLatin1(hdrValue)); + } else if (hdrName == "X-Source-Language") { + translator.setSourceLanguageCode(QString::fromLatin1(hdrValue)); + } else if (hdrName == "Plural-Forms") { + pluralForms = hdrValue; + } else if (hdrName == "MIME-Version") { + // just assume it is 1.0 + } else if (hdrName == "Content-Type") { + if (cd.m_codecForSource.isEmpty()) { + if (!hdrValue.startsWith("text/plain; charset=")) { + cd.appendError(QString::fromLatin1("Unexpected Content-Type header '%1'\n") + .arg(QString::fromLatin1(hdrValue))); + error = true; + // This will avoid a flood of conversion errors. + codec = QTextCodec::codecForName("latin1"); + } else { + QByteArray cod = hdrValue.mid(20); + QTextCodec *cdc = QTextCodec::codecForName(cod); + if (!cdc) { + cd.appendError(QString::fromLatin1("Unsupported codec '%1'\n") + .arg(QString::fromLatin1(cod))); + error = true; + // This will avoid a flood of conversion errors. + codec = QTextCodec::codecForName("latin1"); + } else { + codec = cdc; + } + } + } + } else if (hdrName == "Content-Transfer-Encoding") { + if (hdrValue != "8bit") { + cd.appendError(QString::fromLatin1("Unexpected Content-Transfer-Encoding '%1'\n") + .arg(QString::fromLatin1(hdrValue))); + return false; + } + } else if (hdrName == "X-Virgin-Header") { + // legacy + } else { + extras[makePoHeader(QString::fromLatin1(hdrName))] = hdrValue; + } } - QRegExp rx2(QLatin1String("\\bX-Source-Language: ([^\n]*)\n")); - int idx2 = rx2.indexIn(item.msgStr.first()); - if (idx2 >= 0) { - translator.setSourceLanguageCode(rx2.cap(1)); - item.msgStr.first().remove(idx2, rx2.matchedLength()); + if (!pluralForms.isEmpty()) { + if (translator.languageCode().isEmpty()) { + extras[makePoHeader(QLatin1String("Plural-Forms"))] = pluralForms; + } else { + // FIXME: have fun with making a consistency check ... + } } - if (item.msgStr.first().indexOf( - QRegExp(QLatin1String("\\bX-Virgin-Header:[^\n]*\n"))) >= 0) { - item = PoItem(); - continue; + // Eliminate the field if only headers we added are present in standard order. + // Keep in sync with savePO + static const char * const dfltHdrs[] = { + "MIME-Version", "Content-Type", "Content-Transfer-Encoding", + "Plural-Forms", "X-Language", "X-Source-Language" + }; + uint cdh = 0; + for (int cho = 0; cho < hdrOrder.length(); cho++) { + for (;; cdh++) { + if (cdh == sizeof(dfltHdrs)/sizeof(dfltHdrs[0])) { + extras[QLatin1String("po-headers")] = + QByteArrayList_join(hdrOrder, ','); + goto doneho; + } + if (hdrOrder.at(cho) == dfltHdrs[cdh]) { + cdh++; + break; + } + } } + doneho: + if (lastCmtLine != -1) + extras[QLatin1String("po-header_comment")] = + QByteArrayList_join(lines.mid(0, lastCmtLine + 1), '\n'); + for (QHash<QString, QByteArray>::ConstIterator it = extras.constBegin(), + end = extras.constEnd(); + it != end; ++it) + translator.setExtra(it.key(), codec->toUnicode(it.value())); + item = PoItem(); + continue; } // build translator message TranslatorMessage msg; - msg.setContext(item.context); + msg.setContext(codec->toUnicode(item.context)); if (!item.references.isEmpty()) { foreach (const QString &ref, - item.references.split(QRegExp(QLatin1String("\\s")), - QString::SkipEmptyParts)) { + codec->toUnicode(item.references).split( + QRegExp(QLatin1String("\\s")), QString::SkipEmptyParts)) { int pos = ref.lastIndexOf(QLatin1Char(':')); if (pos != -1) msg.addReference(ref.left(pos), ref.mid(pos + 1).toInt()); @@ -438,18 +539,25 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) } else if (isObsolete) { msg.setFileName(QLatin1String(MAGIC_OBSOLETE_REFERENCE)); } - msg.setId(item.id); - msg.setSourceText(item.msgId); - msg.setOldSourceText(item.oldMsgId); - msg.setComment(item.tscomment); - msg.setOldComment(item.oldTscomment); - msg.setExtraComment(item.automaticComments); - msg.setTranslatorComment(item.translatorComments); + msg.setId(codec->toUnicode(item.id)); + msg.setSourceText(codec->toUnicode(item.msgId)); + msg.setOldSourceText(codec->toUnicode(item.oldMsgId)); + msg.setComment(codec->toUnicode(item.tscomment)); + msg.setOldComment(codec->toUnicode(item.oldTscomment)); + msg.setExtraComment(codec->toUnicode(item.automaticComments)); + msg.setTranslatorComment(codec->toUnicode(item.translatorComments)); msg.setPlural(item.isPlural || item.msgStr.size() > 1); - msg.setTranslations(item.msgStr); + QStringList translations; + foreach (const QByteArray &bstr, item.msgStr) { + QString str = codec->toUnicode(bstr); + str.replace(QChar(Translator::TextVariantSeparator), + QChar(Translator::BinaryVariantSeparator)); + translations << str; + } + msg.setTranslations(translations); if (isObsolete) msg.setType(TranslatorMessage::Obsolete); - else if (item.isFuzzy) + else if (item.isFuzzy || (!msg.sourceText().isEmpty() && !msg.isTranslated())) msg.setType(TranslatorMessage::Unfinished); else msg.setType(TranslatorMessage::Finished); @@ -460,18 +568,19 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) //qDebug() << flags << msg.m_extra; translator.append(msg); item = PoItem(); - } else if (line.startsWith(QLatin1Char('#'))) { - switch(line.size() < 2 ? 0 : line.at(1).unicode()) { + } else if (line.startsWith('#')) { + switch (line.size() < 2 ? 0 : line.at(1)) { case ':': item.references += line.mid(3); - item.references += newline; + item.references += '\n'; break; case ',': { QStringList flags = - line.mid(2).split(QRegExp(QLatin1String("[, ]")), - QString::SkipEmptyParts); + QString::fromLatin1(line.mid(2)).split( + QRegExp(QLatin1String("[, ]")), QString::SkipEmptyParts); if (flags.removeOne(QLatin1String("fuzzy"))) item.isFuzzy = true; + flags.removeOne(QLatin1String("qt-format")); TranslatorMessage::ExtraData::const_iterator it = item.extra.find(QLatin1String("po-flags")); if (it != item.extra.end()) @@ -481,103 +590,130 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) break; } case 0: - item.translatorComments += newline; + item.translatorComments += '\n'; break; case ' ': slurpComment(item.translatorComments, lines, l); break; case '.': - if (line.startsWith(QLatin1String("#. ts-context "))) { + if (line.startsWith("#. ts-context ")) { item.context = line.mid(14); - } else if (line.startsWith(QLatin1String("#. ts-id "))) { + } else if (line.startsWith("#. ts-id ")) { item.id = line.mid(9); } else { item.automaticComments += line.mid(3); - item.automaticComments += newline; + item.automaticComments += '\n'; } break; case '|': - if (line.startsWith(QLatin1String("#| msgid "))) { - item.oldMsgId = slurpEscapedString(lines, l, 9, QLatin1String("#| "), cd); - } else if (line.startsWith(QLatin1String("#| msgid_plural "))) { - QString extra = slurpEscapedString(lines, l, 16, QLatin1String("#| "), cd); + if (line.startsWith("#| msgid ")) { + item.oldMsgId = slurpEscapedString(lines, l, 9, "#| ", cd); + } else if (line.startsWith("#| msgid_plural ")) { + QByteArray extra = slurpEscapedString(lines, l, 16, "#| ", cd); if (extra != item.oldMsgId) - item.extra[QLatin1String("po-old_msgid_plural")] = extra; - } else if (line.startsWith(QLatin1String("#| msgctxt "))) { - item.oldTscomment = slurpEscapedString(lines, l, 11, QLatin1String("#| "), cd); + item.extra[QLatin1String("po-old_msgid_plural")] = + codec->toUnicode(extra); + } else if (line.startsWith("#| msgctxt ")) { + item.oldTscomment = slurpEscapedString(lines, l, 11, "#| ", cd); } else { cd.appendError(QString(QLatin1String("PO-format parse error in line %1: '%2'\n")) - .arg(l + 1).arg(lines[l])); + .arg(l + 1).arg(codec->toUnicode(lines[l]))); error = true; } break; case '~': - if (line.startsWith(QLatin1String("#~ msgid "))) { - item.msgId = slurpEscapedString(lines, l, 9, QLatin1String("#~ "), cd); - } else if (line.startsWith(QLatin1String("#~ msgid_plural "))) { - QString extra = slurpEscapedString(lines, l, 16, QLatin1String("#~ "), cd); + if (line.startsWith("#~ msgid ")) { + item.msgId = slurpEscapedString(lines, l, 9, "#~ ", cd); + } else if (line.startsWith("#~ msgid_plural ")) { + QByteArray extra = slurpEscapedString(lines, l, 16, "#~ ", cd); if (extra != item.msgId) - item.extra[QLatin1String("po-msgid_plural")] = extra; + item.extra[QLatin1String("po-msgid_plural")] = + codec->toUnicode(extra); item.isPlural = true; - } else if (line.startsWith(QLatin1String("#~ msgctxt "))) { - item.tscomment = slurpEscapedString(lines, l, 11, QLatin1String("#~ "), cd); + } else if (line.startsWith("#~ msgctxt ")) { + item.tscomment = slurpEscapedString(lines, l, 11, "#~ ", cd); } else { cd.appendError(QString(QLatin1String("PO-format parse error in line %1: '%2'\n")) - .arg(l + 1).arg(lines[l])); + .arg(l + 1).arg(codec->toUnicode(lines[l]))); error = true; } break; default: cd.appendError(QString(QLatin1String("PO-format parse error in line %1: '%2'\n")) - .arg(l + 1).arg(lines[l])); + .arg(l + 1).arg(codec->toUnicode(lines[l]))); error = true; break; } - } else if (line.startsWith(QLatin1String("msgctxt "))) { - item.tscomment = slurpEscapedString(lines, l, 8, QString(), cd); - } else if (line.startsWith(QLatin1String("msgid "))) { - item.msgId = slurpEscapedString(lines, l, 6, QString(), cd); - } else if (line.startsWith(QLatin1String("msgid_plural "))) { - QString extra = slurpEscapedString(lines, l, 13, QString(), cd); + lastCmtLine = l; + } else if (line.startsWith("msgctxt ")) { + item.tscomment = slurpEscapedString(lines, l, 8, QByteArray(), cd); + } else if (line.startsWith("msgid ")) { + item.msgId = slurpEscapedString(lines, l, 6, QByteArray(), cd); + } else if (line.startsWith("msgid_plural ")) { + QByteArray extra = slurpEscapedString(lines, l, 13, QByteArray(), cd); if (extra != item.msgId) - item.extra[QLatin1String("po-msgid_plural")] = extra; + item.extra[QLatin1String("po-msgid_plural")] = codec->toUnicode(extra); item.isPlural = true; } else { cd.appendError(QString(QLatin1String("PO-format error in line %1: '%2'\n")) - .arg(l + 1).arg(lines[l])); + .arg(l + 1).arg(codec->toUnicode(lines[l]))); error = true; } } return !error && cd.errors().isEmpty(); } +static void addPoHeader(Translator::ExtraData &headers, QStringList &hdrOrder, + const char *name, const QString &value) +{ + QString qName = QLatin1String(name); + if (!hdrOrder.contains(qName)) + hdrOrder << qName; + headers[makePoHeader(qName)] = value; +} + bool savePO(const Translator &translator, QIODevice &dev, ConversionData &cd) { + QString str_format = QLatin1String("-format"); + bool ok = true; QTextStream out(&dev); out.setCodec(cd.m_outputCodec.isEmpty() ? QByteArray("UTF-8") : cd.m_outputCodec); - bool first = true; - if (translator.messages().isEmpty() || !translator.messages().first().sourceText().isEmpty()) { - out << - "# SOME DESCRIPTIVE TITLE.\n" - "# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n" - "# This file is distributed under the same license as the PACKAGE package.\n" - "# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n" - "#\n" - "#, fuzzy\n" - "msgid \"\"\n" - "msgstr \"\"\n" - "\"X-Virgin-Header: remove this line if you change anything in the header.\\n\"\n"; - if (!translator.languageCode().isEmpty()) - out << "\"X-Language: " << translator.languageCode() << "\\n\"\n"; - if (!translator.sourceLanguageCode().isEmpty()) - out << "\"X-Source-Language: " << translator.sourceLanguageCode() << "\\n\"\n"; - first = false; + QString cmt = translator.extra(QLatin1String("po-header_comment")); + if (!cmt.isEmpty()) + out << cmt << '\n'; + out << "msgid \"\"\n"; + Translator::ExtraData headers = translator.extras(); + QStringList hdrOrder = translator.extra(QLatin1String("po-headers")).split( + QLatin1Char(','), QString::SkipEmptyParts); + // Keep in sync with loadPO + addPoHeader(headers, hdrOrder, "MIME-Version", QLatin1String("1.0")); + addPoHeader(headers, hdrOrder, "Content-Type", + QLatin1String("text/plain; charset=" + out.codec()->name())); + addPoHeader(headers, hdrOrder, "Content-Transfer-Encoding", QLatin1String("8bit")); + if (!translator.languageCode().isEmpty()) { + QLocale::Language l; + QLocale::Country c; + Translator::languageAndCountry(translator.languageCode(), &l, &c); + const char *gettextRules; + if (getNumerusInfo(l, c, 0, 0, &gettextRules)) + addPoHeader(headers, hdrOrder, "Plural-Forms", QLatin1String(gettextRules)); + addPoHeader(headers, hdrOrder, "X-Language", translator.languageCode()); } + if (!translator.sourceLanguageCode().isEmpty()) + addPoHeader(headers, hdrOrder, "X-Source-Language", translator.sourceLanguageCode()); + QString hdrStr; + foreach (const QString &hdr, hdrOrder) { + hdrStr += hdr; + hdrStr += QLatin1String(": "); + hdrStr += headers.value(makePoHeader(hdr)); + hdrStr += QLatin1Char('\n'); + } + out << poEscapedString(QString(), QString::fromLatin1("msgstr"), true, hdrStr); + foreach (const TranslatorMessage &msg, translator.messages()) { - if (!first) - out << endl; + out << endl; if (!msg.translatorComment().isEmpty()) out << poEscapedLines(QLatin1String("#"), true, msg.translatorComment()); @@ -599,16 +735,36 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &cd) } bool noWrap = false; + bool skipFormat = false; QStringList flags; - if (msg.type() == TranslatorMessage::Unfinished) + if (msg.type() == TranslatorMessage::Unfinished && msg.isTranslated()) flags.append(QLatin1String("fuzzy")); TranslatorMessage::ExtraData::const_iterator itr = msg.extras().find(QLatin1String("po-flags")); if (itr != msg.extras().end()) { - if (itr->split(QLatin1String(", ")).contains(QLatin1String("no-wrap"))) + QStringList atoms = itr->split(QLatin1String(", ")); + foreach (const QString &atom, atoms) + if (atom.endsWith(str_format)) { + skipFormat = true; + break; + } + if (atoms.contains(QLatin1String("no-wrap"))) noWrap = true; flags.append(*itr); } + if (!skipFormat) { + QString source = msg.sourceText(); + // This is fuzzy logic, as we don't know whether the string is + // actually used with QString::arg(). + for (int off = 0; (off = source.indexOf(QLatin1Char('%'), off)) >= 0; ) { + if (++off >= source.length()) + break; + if (source.at(off) == QLatin1Char('n') || source.at(off).isDigit()) { + flags.append(QLatin1String("qt-format")); + break; + } + } + } if (!flags.isEmpty()) out << "#, " << flags.join(QLatin1String(", ")) << '\n'; @@ -626,11 +782,8 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &cd) out << poEscapedString(prefix, QLatin1String("msgid"), noWrap, msg.sourceText()); if (!msg.isPlural()) { QString transl = msg.translation(); - if (first) { - transl.remove(QRegExp(QLatin1String("\\bX-Language:[^\n]*\n"))); - if (!translator.languageCode().isEmpty()) - transl += QLatin1String("X-Language: ") + translator.languageCode() + QLatin1Char('\n'); - } + transl.replace(QChar(Translator::BinaryVariantSeparator), + QChar(Translator::TextVariantSeparator)); out << poEscapedString(prefix, QLatin1String("msgstr"), noWrap, transl); } else { QString plural = msg.extra(QLatin1String("po-msgid_plural")); @@ -646,11 +799,17 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &cd) str); } } - first = false; } return ok; } +static bool savePOT(const Translator &translator, QIODevice &dev, ConversionData &cd) +{ + Translator ttor = translator; + ttor.dropTranslations(); + return savePO(ttor, dev, cd); +} + int initPO() { Translator::FileFormat format; @@ -661,6 +820,13 @@ int initPO() format.fileType = Translator::FileFormat::TranslationSource; format.priority = 1; Translator::registerFileFormat(format); + format.extension = QLatin1String("pot"); + format.description = QObject::tr("GNU Gettext localization template files"); + format.loader = &loadPO; + format.saver = &savePOT; + format.fileType = Translator::FileFormat::TranslationSource; + format.priority = -1; + Translator::registerFileFormat(format); return 1; } diff --git a/tools/linguist/shared/qm.cpp b/tools/linguist/shared/qm.cpp index de1284f..e2c4f4a 100644 --- a/tools/linguist/shared/qm.cpp +++ b/tools/linguist/shared/qm.cpp @@ -564,7 +564,7 @@ bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd) Translator::languageAndCountry(translator.languageCode(), &l, &c); QStringList numerusForms; bool guessPlurals = true; - if (getNumerusInfo(l, c, 0, &numerusForms)) + if (getNumerusInfo(l, c, 0, &numerusForms, 0)) guessPlurals = (numerusForms.count() == 1); QString context, contextUtf8; @@ -704,7 +704,7 @@ static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData QLocale::Country c; Translator::languageAndCountry(translator.languageCode(), &l, &c); QByteArray rules; - if (getNumerusInfo(l, c, &rules, 0)) + if (getNumerusInfo(l, c, &rules, 0, 0)) releaser.setNumerusRules(rules); releaser.setCodecName(translator.codecName()); diff --git a/tools/linguist/shared/translator.cpp b/tools/linguist/shared/translator.cpp index 4331ce6..c86a9dd 100644 --- a/tools/linguist/shared/translator.cpp +++ b/tools/linguist/shared/translator.cpp @@ -45,8 +45,13 @@ #include <stdio.h> #ifdef Q_OS_WIN -#include <io.h> // required for _setmode, to avoid _O_TEXT streams... -#include <fcntl.h> // for _O_BINARY +// required for _setmode, to avoid _O_TEXT streams... +# ifdef Q_OS_WINCE +# include <stdlib.h> +# else +# include <io.h> // for _setmode +# include <fcntl.h> // for _O_BINARY +# endif #endif #include <QtCore/QDebug> @@ -213,7 +218,11 @@ bool Translator::load(const QString &filename, ConversionData &cd, const QString if (filename.isEmpty() || filename == QLatin1String("-")) { #ifdef Q_OS_WIN // QFile is broken for text files +# ifdef Q_OS_WINCE + ::_setmode(stdin, _O_BINARY); +# else ::_setmode(0, _O_BINARY); +# endif #endif if (!file.open(stdin, QIODevice::ReadOnly)) { cd.appendError(QString::fromLatin1("Cannot open stdin!? (%1)") @@ -253,7 +262,11 @@ bool Translator::save(const QString &filename, ConversionData &cd, const QString if (filename.isEmpty() || filename == QLatin1String("-")) { #ifdef Q_OS_WIN // QFile is broken for text files +# ifdef Q_OS_WINCE + ::_setmode(stdout, _O_BINARY); +# else ::_setmode(1, _O_BINARY); +# endif #endif if (!file.open(stdout, QIODevice::WriteOnly)) { cd.appendError(QString::fromLatin1("Cannot open stdout!? (%1)") @@ -652,7 +665,7 @@ void Translator::normalizeTranslations(ConversionData &cd) int numPlurals = 1; if (l != QLocale::C) { QStringList forms; - if (getNumerusInfo(l, c, 0, &forms)) + if (getNumerusInfo(l, c, 0, &forms, 0)) numPlurals = forms.count(); // includes singular } for (int i = 0; i < m_messages.count(); ++i) { diff --git a/tools/linguist/shared/translator.h b/tools/linguist/shared/translator.h index 0b88c07..bb199f0 100644 --- a/tools/linguist/shared/translator.h +++ b/tools/linguist/shared/translator.h @@ -233,7 +233,7 @@ private: }; bool getNumerusInfo(QLocale::Language language, QLocale::Country country, - QByteArray *rules, QStringList *forms); + QByteArray *rules, QStringList *forms, const char **gettextRules); /* This is a quick hack. The proper way to handle this would be diff --git a/tools/linguist/shared/xliff.cpp b/tools/linguist/shared/xliff.cpp index 20303ec..6411426 100644 --- a/tools/linguist/shared/xliff.cpp +++ b/tools/linguist/shared/xliff.cpp @@ -503,6 +503,8 @@ bool XLIFFHandler::startElement(const QString& namespaceURI, m_language.replace(QLatin1Char('-'), QLatin1Char('_')); m_sourceLanguage = atts.value(QLatin1String("source-language")); m_sourceLanguage.replace(QLatin1Char('-'), QLatin1Char('_')); + if (m_sourceLanguage == QLatin1String("en")) + m_sourceLanguage.clear(); } else if (localName == QLatin1String("group")) { if (atts.value(QLatin1String("restype")) == QLatin1String(restypeContext)) { m_context = atts.value(QLatin1String("resname")); diff --git a/tools/pixeltool/qpixeltool.cpp b/tools/pixeltool/qpixeltool.cpp index c684688..f64dfba 100644 --- a/tools/pixeltool/qpixeltool.cpp +++ b/tools/pixeltool/qpixeltool.cpp @@ -356,7 +356,7 @@ void QPixelTool::contextMenuEvent(QContextMenuEvent *e) freeze.setCheckable(true); freeze.setChecked(tmpFreeze); freeze.setShortcut(QKeySequence(Qt::Key_Space)); - QAction autoUpdate(QLatin1String("Continous update"), &menu); + QAction autoUpdate(QLatin1String("Continuous update"), &menu); autoUpdate.setCheckable(true); autoUpdate.setChecked(m_autoUpdate); autoUpdate.setShortcut(QKeySequence(Qt::Key_A)); diff --git a/tools/porting/src/q3porting.xml b/tools/porting/src/q3porting.xml index 7a31d6e..39f341f 100644 --- a/tools/porting/src/q3porting.xml +++ b/tools/porting/src/q3porting.xml @@ -1626,10 +1626,6 @@ <Name>Q3Wizard</Name> </item> <item Type="Qt4Class" > - <Library>QtAssistant</Library> - <Name>QAssistantClient</Name> - </item> - <item Type="Qt4Class" > <Library>QtCore</Library> <Name>QAbstractEventDispatcher</Name> </item> diff --git a/tools/qdbus/qdbus.pro b/tools/qdbus/qdbus.pro index 01cd246..a264882 100644 --- a/tools/qdbus/qdbus.pro +++ b/tools/qdbus/qdbus.pro @@ -1,2 +1,3 @@ TEMPLATE = subdirs -SUBDIRS = qdbus qdbusxml2cpp qdbuscpp2xml qdbusviewer +SUBDIRS = qdbus qdbusxml2cpp qdbuscpp2xml +!contains(QT_CONFIG, no-gui): SUBDIRS += qdbusviewer diff --git a/tools/qdbus/qdbus/qdbus.cpp b/tools/qdbus/qdbus/qdbus.cpp index 48b0dad..ce18cb9 100644 --- a/tools/qdbus/qdbus/qdbus.cpp +++ b/tools/qdbus/qdbus/qdbus.cpp @@ -248,123 +248,153 @@ static QStringList readList(QStringList &args) return retval; } -static void placeCall(const QString &service, const QString &path, const QString &interface, - const QString &member, QStringList args) +static int placeCall(const QString &service, const QString &path, const QString &interface, + const QString &member, const QStringList& arguments, bool try_prop=true) { QDBusInterface iface(service, path, interface, connection); // Don't check whether the interface is valid to allow DBus try to // activate the service if possible. + QList<int> knownIds; + bool matchFound = false; + QStringList args = arguments; QVariantList params; if (!args.isEmpty()) { const QMetaObject *mo = iface.metaObject(); QByteArray match = member.toLatin1(); match += '('; - int midx = -1; for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) { QMetaMethod mm = mo->method(i); QByteArray signature = mm.signature(); - if (signature.startsWith(match)) { - midx = i; - break; - } + if (signature.startsWith(match)) + knownIds += i; } - if (midx == -1) { - fprintf(stderr, "Cannot find '%s.%s' in object %s at %s\n", - qPrintable(interface), qPrintable(member), qPrintable(path), - qPrintable(service)); - exit(1); - } - QMetaMethod mm = mo->method(midx); - QList<QByteArray> types = mm.parameterTypes(); - for (int i = 0; i < types.count(); ++i) { - if (types.at(i).endsWith('&')) { - // reference (and not a reference to const): output argument - // we're done with the inputs - while (types.count() > i) - types.removeLast(); - break; + while (!matchFound) { + args = arguments; // reset + params.clear(); + if (knownIds.isEmpty()) { + // Failed to set property after falling back? + // Bail out without displaying an error + if (!try_prop) + return 1; + if (try_prop && args.size() == 1) { + QStringList proparg; + proparg += interface; + proparg += member; + proparg += args.first(); + if (!placeCall(service, path, "org.freedesktop.DBus.Properties", "Set", proparg, false)) + return 0; + } + fprintf(stderr, "Cannot find '%s.%s' in object %s at %s\n", + qPrintable(interface), qPrintable(member), qPrintable(path), + qPrintable(service)); + return 1; } - } - for (int i = 0; !args.isEmpty() && i < types.count(); ++i) { - int id = QVariant::nameToType(types.at(i)); - if (id == QVariant::UserType) - id = QMetaType::type(types.at(i)); - Q_ASSERT(id); - - QVariant p; - QString argument; - if ((id == QVariant::List || id == QVariant::StringList) - && args.at(0) == QLatin1String("(")) - p = readList(args); - else - p = argument = args.takeFirst(); - - if (id == int(QMetaType::UChar)) { - // special case: QVariant::convert doesn't convert to/from - // UChar because it can't decide if it's a character or a number - p = qVariantFromValue<uchar>(p.toUInt()); - } else if (id < int(QMetaType::User) && id != int(QVariant::Map)) { - p.convert(QVariant::Type(id)); - if (p.type() == QVariant::Invalid) { - fprintf(stderr, "Could not convert '%s' to type '%s'.\n", - qPrintable(argument), types.at(i).constData()); - exit(1); - } - } else if (id == qMetaTypeId<QDBusVariant>()) { - QDBusVariant tmp(p); - p = qVariantFromValue(tmp); - } else if (id == qMetaTypeId<QDBusObjectPath>()) { - QDBusObjectPath path(argument); - if (path.path().isNull()) { - fprintf(stderr, "Cannot pass argument '%s' because it is not a valid object path.\n", - qPrintable(argument)); - exit(1); + QMetaMethod mm = mo->method(knownIds.takeFirst()); + QList<QByteArray> types = mm.parameterTypes(); + for (int i = 0; i < types.count(); ++i) { + if (types.at(i).endsWith('&')) { + // reference (and not a reference to const): output argument + // we're done with the inputs + while (types.count() > i) + types.removeLast(); + break; } - p = qVariantFromValue(path); - } else if (id == qMetaTypeId<QDBusSignature>()) { - QDBusSignature sig(argument); - if (sig.signature().isNull()) { - fprintf(stderr, "Cannot pass argument '%s' because it is not a valid signature.\n", - qPrintable(argument)); - exit(1); + } + + for (int i = 0; !args.isEmpty() && i < types.count(); ++i) { + int id = QVariant::nameToType(types.at(i)); + if (id == QVariant::UserType) + id = QMetaType::type(types.at(i)); + Q_ASSERT(id); + + QVariant p; + QString argument; + if ((id == QVariant::List || id == QVariant::StringList) + && args.at(0) == QLatin1String("(")) + p = readList(args); + else + p = argument = args.takeFirst(); + + if (id == int(QMetaType::UChar)) { + // special case: QVariant::convert doesn't convert to/from + // UChar because it can't decide if it's a character or a number + p = qVariantFromValue<uchar>(p.toUInt()); + } else if (id < int(QMetaType::User) && id != int(QVariant::Map)) { + p.convert(QVariant::Type(id)); + if (p.type() == QVariant::Invalid) { + fprintf(stderr, "Could not convert '%s' to type '%s'.\n", + qPrintable(argument), types.at(i).constData()); + return 1 ; + } + } else if (id == qMetaTypeId<QDBusVariant>()) { + QDBusVariant tmp(p); + p = qVariantFromValue(tmp); + } else if (id == qMetaTypeId<QDBusObjectPath>()) { + QDBusObjectPath path(argument); + if (path.path().isNull()) { + fprintf(stderr, "Cannot pass argument '%s' because it is not a valid object path.\n", + qPrintable(argument)); + return 1; + } + p = qVariantFromValue(path); + } else if (id == qMetaTypeId<QDBusSignature>()) { + QDBusSignature sig(argument); + if (sig.signature().isNull()) { + fprintf(stderr, "Cannot pass argument '%s' because it is not a valid signature.\n", + qPrintable(argument)); + return 1; + } + p = qVariantFromValue(sig); + } else { + fprintf(stderr, "Sorry, can't pass arg of type '%s'.\n", + types.at(i).constData()); + return 1; } - p = qVariantFromValue(sig); - } else { - fprintf(stderr, "Sorry, can't pass arg of type '%s'.\n", - types.at(i).constData()); - exit(1); + params += p; } - params += p; - } - if (params.count() != types.count() || !args.isEmpty()) { - fprintf(stderr, "Invalid number of parameters\n"); - exit(1); - } - } + if (params.count() == types.count() && args.isEmpty()) + matchFound = true; + else if (knownIds.isEmpty()) { + fprintf(stderr, "Invalid number of parameters\n"); + return 1; + } + } // while (!matchFound) + } // if (!args.isEmpty() QDBusMessage reply = iface.callWithArgumentList(QDBus::Block, member, params); if (reply.type() == QDBusMessage::ErrorMessage) { QDBusError err = reply; + // Failed to retrieve property after falling back? + // Bail out without displaying an error + if (!try_prop) + return 1; + if (err.type() == QDBusError::UnknownMethod && try_prop) { + QStringList proparg; + proparg += interface; + proparg += member; + if (!placeCall(service, path, "org.freedesktop.DBus.Properties", "Get", proparg, false)) + return 0; + } if (err.type() == QDBusError::ServiceUnknown) fprintf(stderr, "Service '%s' does not exist.\n", qPrintable(service)); else printf("Error: %s\n%s\n", qPrintable(err.name()), qPrintable(err.message())); - exit(2); + return 2; } else if (reply.type() != QDBusMessage::ReplyMessage) { fprintf(stderr, "Invalid reply type %d\n", int(reply.type())); - exit(1); + return 1; } foreach (QVariant v, reply.arguments()) printArg(v); - exit(0); + return 0; } static bool globServices(QDBusConnectionInterface *bus, const QString &glob) @@ -483,6 +513,7 @@ int main(int argc, char **argv) exit(1); } - placeCall(service, path, interface, member, args); + int ret = placeCall(service, path, interface, member, args); + exit(ret); } diff --git a/tools/qdbus/qdbusviewer/qdbusmodel.cpp b/tools/qdbus/qdbusviewer/qdbusmodel.cpp index befe4b4..f85e288 100644 --- a/tools/qdbus/qdbusviewer/qdbusmodel.cpp +++ b/tools/qdbus/qdbusviewer/qdbusmodel.cpp @@ -75,6 +75,7 @@ struct QDBusItem bool isPrefetched; QString name; QString caption; + QString typeSignature; }; QDomDocument QDBusModel::introspect(const QString &path) @@ -118,6 +119,13 @@ void QDBusModel::addMethods(QDBusItem *parent, const QDomElement &iface) item = new QDBusItem(QDBusModel::MethodItem, child.attribute(QLatin1String("name")), parent); item->caption = QLatin1String("Method: ") + item->name; + //get "type" from <arg> where "direction" is "in" + QDomElement n = child.firstChildElement(); + while (!n.isNull()) { + if (n.attribute(QLatin1String("direction")) == QLatin1String("in")) + item->typeSignature += n.attribute(QLatin1String("type")); + n = n.nextSiblingElement(); + } } else if (child.tagName() == QLatin1String("signal")) { item = new QDBusItem(QDBusModel::SignalItem, child.attribute(QLatin1String("name")), parent); @@ -298,6 +306,12 @@ QString QDBusModel::dBusMethodName(const QModelIndex &index) const return item ? item->name : QString(); } +QString QDBusModel::dBusTypeSignature(const QModelIndex &index) const +{ + QDBusItem *item = static_cast<QDBusItem *>(index.internalPointer()); + return item ? item->typeSignature : QString(); +} + QModelIndex QDBusModel::findObject(const QDBusObjectPath &objectPath) { QStringList path = objectPath.path().split(QLatin1Char('/'), QString::SkipEmptyParts); diff --git a/tools/qdbus/qdbusviewer/qdbusmodel.h b/tools/qdbus/qdbusviewer/qdbusmodel.h index 1a3d8f0..e83c381 100644 --- a/tools/qdbus/qdbusviewer/qdbusmodel.h +++ b/tools/qdbus/qdbusviewer/qdbusmodel.h @@ -72,6 +72,7 @@ public: QString dBusPath(const QModelIndex &index) const; QString dBusInterface(const QModelIndex &index) const; QString dBusMethodName(const QModelIndex &index) const; + QString dBusTypeSignature(const QModelIndex &index) const; void refresh(const QModelIndex &index = QModelIndex()); diff --git a/tools/qdbus/qdbusviewer/qdbusviewer.cpp b/tools/qdbus/qdbusviewer/qdbusviewer.cpp index e9695dc..9878aff 100644 --- a/tools/qdbus/qdbusviewer/qdbusviewer.cpp +++ b/tools/qdbus/qdbusviewer/qdbusviewer.cpp @@ -69,9 +69,16 @@ QDBusViewer::QDBusViewer(const QDBusConnection &connection, QWidget *parent) : c(connection), objectPathRegExp(QLatin1String("\\[ObjectPath: (.*)\\]")) { - services = new QTreeWidget; - services->setRootIsDecorated(false); - services->setHeaderLabels(QStringList(QLatin1String("Services"))); + servicesModel = new QStringListModel(this); + servicesFilterModel = new QSortFilterProxyModel(this); + servicesFilterModel->setSourceModel(servicesModel); + servicesFilterModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + serviceFilterLine = new QLineEdit(this); + serviceFilterLine->setPlaceholderText(tr("Search...")); + servicesView = new QListView(this); + servicesView->setModel(servicesFilterModel); + + connect(serviceFilterLine, SIGNAL(textChanged(QString)), servicesFilterModel, SLOT(setFilterFixedString(QString))); tree = new QTreeView; tree->setContextMenuPolicy(Qt::CustomContextMenu); @@ -86,19 +93,28 @@ QDBusViewer::QDBusViewer(const QDBusConnection &connection, QWidget *parent) : QShortcut *refreshShortcut = new QShortcut(QKeySequence::Refresh, tree); connect(refreshShortcut, SIGNAL(activated()), this, SLOT(refreshChildren())); - QVBoxLayout *topLayout = new QVBoxLayout(this); + QVBoxLayout *layout = new QVBoxLayout(this); + QSplitter *topSplitter = new QSplitter(Qt::Vertical, this); + layout->addWidget(topSplitter); + log = new QTextBrowser; connect(log, SIGNAL(anchorClicked(QUrl)), this, SLOT(anchorClicked(QUrl))); - QHBoxLayout *layout = new QHBoxLayout; - layout->addWidget(services, 1); - layout->addWidget(tree, 2); + QSplitter *splitter = new QSplitter(topSplitter); + splitter->addWidget(servicesView); + + QWidget *servicesWidget = new QWidget; + QVBoxLayout *servicesLayout = new QVBoxLayout(servicesWidget); + servicesLayout->addWidget(serviceFilterLine); + servicesLayout->addWidget(servicesView); + splitter->addWidget(servicesWidget); + splitter->addWidget(tree); - topLayout->addLayout(layout); - topLayout->addWidget(log); + topSplitter->addWidget(splitter); + topSplitter->addWidget(log); - connect(services, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), - this, SLOT(serviceChanged(QTreeWidgetItem*))); + connect(servicesView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(serviceChanged(QModelIndex))); connect(tree, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); @@ -133,12 +149,11 @@ void QDBusViewer::logError(const QString &msg) void QDBusViewer::refresh() { - services->clear(); + servicesModel->removeRows(0, servicesModel->rowCount()); if (c.isConnected()) { const QStringList serviceNames = c.interface()->registeredServiceNames(); - foreach (QString service, serviceNames) - new QTreeWidgetItem(services, QStringList(service)); + servicesModel->setStringList(serviceNames); } } @@ -154,6 +169,7 @@ void QDBusViewer::activate(const QModelIndex &item) sig.mPath = model->dBusPath(item); sig.mInterface = model->dBusInterface(item); sig.mName = model->dBusMethodName(item); + sig.mTypeSig = model->dBusTypeSignature(item); switch (model->itemType(item)) { case QDBusModel::SignalItem: @@ -207,6 +223,17 @@ void QDBusViewer::setProperty(const BusSignature &sig) } +static QString getDbusSignature(const QMetaMethod& method) +{ + // create a D-Bus type signature from QMetaMethod's parameters + QString sig; + for (int i = 0; i < method.parameterTypes().count(); ++i) { + QVariant::Type type = QVariant::nameToType(method.parameterTypes().at(i)); + sig.append(QString::fromLatin1(QDBusMetaType::typeToSignature(type))); + } + return sig; +} + void QDBusViewer::callMethod(const BusSignature &sig) { QDBusInterface iface(sig.mService, sig.mPath, sig.mInterface, c); @@ -217,7 +244,8 @@ void QDBusViewer::callMethod(const BusSignature &sig) for (int i = 0; i < mo->methodCount(); ++i) { const QString signature = QString::fromLatin1(mo->method(i).signature()); if (signature.startsWith(sig.mName) && signature.at(sig.mName.length()) == QLatin1Char('(')) - method = mo->method(i); + if (getDbusSignature(mo->method(i)) == sig.mTypeSig) + method = mo->method(i); } if (!method.signature()) { QMessageBox::warning(this, tr("Unable to find method"), @@ -277,6 +305,7 @@ void QDBusViewer::showContextMenu(const QPoint &point) sig.mPath = model->dBusPath(item); sig.mInterface = model->dBusInterface(item); sig.mName = model->dBusMethodName(item); + sig.mTypeSig = model->dBusTypeSignature(item); QMenu menu; menu.addAction(refreshAction); @@ -379,14 +408,14 @@ void QDBusViewer::dumpMessage(const QDBusMessage &message) log->append(out); } -void QDBusViewer::serviceChanged(QTreeWidgetItem *item) +void QDBusViewer::serviceChanged(const QModelIndex &index) { delete tree->model(); currentService.clear(); - if (!item) + if (!index.isValid()) return; - currentService = item->text(0); + currentService = index.data().toString(); tree->setModel(new QDBusViewModel(currentService, c)); connect(tree->model(), SIGNAL(busError(QString)), this, SLOT(logError(QString))); @@ -397,34 +426,38 @@ void QDBusViewer::serviceRegistered(const QString &service) if (service == c.baseService()) return; - new QTreeWidgetItem(services, QStringList(service)); + servicesModel->insertRows(0, 1); + servicesModel->setData(servicesModel->index(0, 0), service); } -static QTreeWidgetItem *findItem(const QTreeWidget *services, const QString &name) +static QModelIndex findItem(QStringListModel *servicesModel, const QString &name) { - for (int i = 0; i < services->topLevelItemCount(); ++i) { - if (services->topLevelItem(i)->text(0) == name) - return services->topLevelItem(i); - } - return 0; + QModelIndexList hits = servicesModel->match(servicesModel->index(0, 0), Qt::DisplayRole, name); + if (hits.isEmpty()) + return QModelIndex(); + + return hits.first(); } void QDBusViewer::serviceUnregistered(const QString &name) { - delete findItem(services, name); + QModelIndex hit = findItem(servicesModel, name); + if (!hit.isValid()) + return; + servicesModel->removeRows(hit.row(), 1); } void QDBusViewer::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner) { - QTreeWidgetItem *item = findItem(services, name); + QModelIndex hit = findItem(servicesModel, name); - if (!item && oldOwner.isEmpty() && !newOwner.isEmpty()) + if (!hit.isValid() && oldOwner.isEmpty() && !newOwner.isEmpty()) serviceRegistered(name); - else if (item && !oldOwner.isEmpty() && newOwner.isEmpty()) - delete item; - else if (item && !oldOwner.isEmpty() && !newOwner.isEmpty()) { - delete item; + else if (hit.isValid() && !oldOwner.isEmpty() && newOwner.isEmpty()) + servicesModel->removeRows(hit.row(), 1); + else if (hit.isValid() && !oldOwner.isEmpty() && !newOwner.isEmpty()) { + servicesModel->removeRows(hit.row(), 1); serviceRegistered(name); } } diff --git a/tools/qdbus/qdbusviewer/qdbusviewer.h b/tools/qdbus/qdbusviewer/qdbusviewer.h index 207f7a3..d5d1a69 100644 --- a/tools/qdbus/qdbusviewer/qdbusviewer.h +++ b/tools/qdbus/qdbusviewer/qdbusviewer.h @@ -52,6 +52,7 @@ QT_FORWARD_DECLARE_CLASS(QDomElement); struct BusSignature { QString mService, mPath, mInterface, mName; + QString mTypeSig; }; class QDBusViewer: public QWidget @@ -65,7 +66,7 @@ public slots: void about(); private slots: - void serviceChanged(QTreeWidgetItem *item); + void serviceChanged(const QModelIndex &index); void showContextMenu(const QPoint &); void connectionRequested(const BusSignature &sig); void callMethod(const BusSignature &sig); @@ -91,6 +92,10 @@ private: QTreeView *tree; QAction *refreshAction; QTreeWidget *services; + QStringListModel *servicesModel; + QSortFilterProxyModel *servicesFilterModel; + QLineEdit *serviceFilterLine; + QListView *servicesView; QTextBrowser *log; QRegExp objectPathRegExp; }; diff --git a/tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp b/tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp index 8251e2c..d9343e3 100644 --- a/tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp +++ b/tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp @@ -53,14 +53,9 @@ #include "private/qdbusmetaobject_p.h" #include "private/qdbusintrospection_p.h" -#include <sys/types.h> #include <stdio.h> #include <stdlib.h> -#ifdef Q_WS_WIN -#include <process.h> -#endif - #define PROGRAMNAME "qdbusxml2cpp" #define PROGRAMVERSION "0.7" #define PROGRAMCOPYRIGHT "Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)." diff --git a/tools/qdoc3/codemarker.cpp b/tools/qdoc3/codemarker.cpp index ee93080..818a91f 100644 --- a/tools/qdoc3/codemarker.cpp +++ b/tools/qdoc3/codemarker.cpp @@ -177,7 +177,7 @@ const Node *CodeMarker::nodeForString(const QString& string) QString CodeMarker::stringForNode(const Node *node) { if (sizeof(const Node *) == sizeof(ulong)) { - return QString::number(reinterpret_cast<ulong>(node)); + return QString::number(reinterpret_cast<quintptr>(node)); } else { return QString::number(reinterpret_cast<qulonglong>(node)); @@ -457,7 +457,7 @@ bool CodeMarker::insertReimpFunc(FastSection& fs, Node* node, Status status) void CodeMarker::append(QList<Section>& sectionList, const FastSection& fs) { if (!fs.isEmpty()) { - Section section(fs.name,fs.singularMember,fs.pluralMember); + Section section(fs.name,fs.divClass,fs.singularMember,fs.pluralMember); section.members = fs.memberMap.values(); section.reimpMembers = fs.reimpMemberMap.values(); section.inherited = fs.inherited; diff --git a/tools/qdoc3/codemarker.h b/tools/qdoc3/codemarker.h index 1b21753..aab8a9c 100644 --- a/tools/qdoc3/codemarker.h +++ b/tools/qdoc3/codemarker.h @@ -58,6 +58,7 @@ class Tree; struct Section { QString name; + QString divClass; QString singularMember; QString pluralMember; NodeList members; @@ -66,9 +67,11 @@ struct Section Section() { } Section(const QString& name0, + const QString& divClass0, const QString& singularMember0, const QString& pluralMember0) - : name(name0), + : name(name0), + divClass(divClass0), singularMember(singularMember0), pluralMember(pluralMember0) { } void appendMember(Node* node) { members.append(node); } @@ -79,6 +82,7 @@ struct FastSection { const InnerNode *innerNode; QString name; + QString divClass; QString singularMember; QString pluralMember; QMap<QString, Node *> memberMap; @@ -86,20 +90,30 @@ struct FastSection QList<QPair<ClassNode *, int> > inherited; FastSection(const InnerNode *innerNode0, - const QString& name0 = "", - const QString& singularMember0 = "member", - const QString& pluralMember0 = "members") + const QString& name0, + const QString& divClass0, + const QString& singularMember0, + const QString& pluralMember0) : innerNode(innerNode0), name(name0), + divClass(divClass0), singularMember(singularMember0), pluralMember(pluralMember0) { } bool isEmpty() const { - return (memberMap.isEmpty() && inherited.isEmpty() && + return (memberMap.isEmpty() && + inherited.isEmpty() && reimpMemberMap.isEmpty()); } }; +#if 0 + const QString& name0 = "", + const QString& divClass0 = "", + const QString& singularMember0 = "member", + const QString& pluralMember0 = "members") +#endif + class CodeMarker { public: diff --git a/tools/qdoc3/codeparser.cpp b/tools/qdoc3/codeparser.cpp index 3ad3372..65d9572 100644 --- a/tools/qdoc3/codeparser.cpp +++ b/tools/qdoc3/codeparser.cpp @@ -43,11 +43,11 @@ codeparser.cpp */ -#include <QtCore> #include "codeparser.h" #include "node.h" #include "tree.h" #include "config.h" +#include <QDebug> QT_BEGIN_NAMESPACE @@ -59,6 +59,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_MAINCLASS Doc::alias(QLatin1String("mainclass")) #define COMMAND_NONREENTRANT Doc::alias(QLatin1String("nonreentrant")) #define COMMAND_OBSOLETE Doc::alias(QLatin1String("obsolete")) +#define COMMAND_PAGEKEYWORDS Doc::alias(QLatin1String("pagekeywords")) #define COMMAND_PRELIMINARY Doc::alias(QLatin1String("preliminary")) #define COMMAND_INPUBLICGROUP Doc::alias(QLatin1String("inpublicgroup")) #define COMMAND_REENTRANT Doc::alias(QLatin1String("reentrant")) @@ -69,6 +70,7 @@ QT_BEGIN_NAMESPACE QList<CodeParser *> CodeParser::parsers; bool CodeParser::showInternal = false; +QMap<QString,QString> CodeParser::nameToTitle; /*! The constructor adds this code parser to the static @@ -170,6 +172,7 @@ QSet<QString> CodeParser::commonMetaCommands() << COMMAND_MAINCLASS << COMMAND_NONREENTRANT << COMMAND_OBSOLETE + << COMMAND_PAGEKEYWORDS << COMMAND_PRELIMINARY << COMMAND_INPUBLICGROUP << COMMAND_REENTRANT @@ -230,6 +233,9 @@ void CodeParser::processCommonMetaCommand(const Location &location, else if (command == COMMAND_SINCE) { node->setSince(arg); } + else if (command == COMMAND_PAGEKEYWORDS) { + node->addPageKeywords(arg); + } else if (command == COMMAND_SUBTITLE) { if (node->type() == Node::Fake) { FakeNode *fake = static_cast<FakeNode *>(node); @@ -245,10 +251,20 @@ void CodeParser::processCommonMetaCommand(const Location &location, if (node->type() == Node::Fake) { FakeNode *fake = static_cast<FakeNode *>(node); fake->setTitle(arg); + nameToTitle.insert(fake->name(),arg); } else location.warning(tr("Ignored '\\%1'").arg(COMMAND_TITLE)); } } +/*! + Find the page title given the page \a name and return it. + */ +const QString CodeParser::titleFromName(const QString& name) +{ + const QString t = nameToTitle.value(name); + return t; +} + QT_END_NAMESPACE diff --git a/tools/qdoc3/codeparser.h b/tools/qdoc3/codeparser.h index 7b0d0eb..ebba601 100644 --- a/tools/qdoc3/codeparser.h +++ b/tools/qdoc3/codeparser.h @@ -78,6 +78,7 @@ class CodeParser static void initialize(const Config& config); static void terminate(); static CodeParser *parserForLanguage(const QString& language); + static const QString titleFromName(const QString& name); protected: QSet<QString> commonMetaCommands(); @@ -88,6 +89,7 @@ class CodeParser private: static QList<CodeParser *> parsers; static bool showInternal; + static QMap<QString,QString> nameToTitle; }; QT_END_NAMESPACE diff --git a/tools/qdoc3/command.cpp b/tools/qdoc3/command.cpp index 76b483c..b78ad07 100644 --- a/tools/qdoc3/command.cpp +++ b/tools/qdoc3/command.cpp @@ -47,6 +47,8 @@ #include "command.h" +#include <stdlib.h> + QT_BEGIN_NAMESPACE void executeCommand(const Location& location, @@ -69,6 +71,12 @@ void executeCommand(const Location& location, if (space != -1) toolName.truncate(space); +#ifdef QT_BOOTSTRAPPED + int status = system(qPrintable(actualCommand)); + int exitCode = WEXITSTATUS(status); + if (status == -1 || exitCode != EXIT_SUCCESS) + location.fatal(QString("Error executing '$1': $2").arg(toolName).arg(exitCode)); +#else QProcess process; process.start(QLatin1String("sh"), QStringList() << QLatin1String("-c") << actualCommand); @@ -89,6 +97,7 @@ void executeCommand(const Location& location, tr("The tool was invoked like this:\n%1\n" "It emitted these errors:\n%2") .arg(actualCommand).arg(errors)); +#endif } QT_END_NAMESPACE diff --git a/tools/qdoc3/config.cpp b/tools/qdoc3/config.cpp index f62ec24..4d1c378 100644 --- a/tools/qdoc3/config.cpp +++ b/tools/qdoc3/config.cpp @@ -43,7 +43,11 @@ config.cpp */ -#include <QtCore> +#include <QDir> +#include <QVariant> +#include <QFile> +#include <QTemporaryFile> +#include <QTextStream> #include "archiveextractor.h" #include "config.h" @@ -524,8 +528,11 @@ QString Config::findFile(const Location& location, { QStringList::ConstIterator e = fileExtensions.begin(); while (e != fileExtensions.end()) { - QString filePath = findFile(location, files, dirs, fileBase + "." + *e, - userFriendlyFilePath); + QString filePath = findFile(location, + files, + dirs, + fileBase + "." + *e, + userFriendlyFilePath); if (!filePath.isEmpty()) return filePath; ++e; @@ -671,7 +678,9 @@ void Config::load(Location location, const QString& fileName) location.fatal(tr("Cannot open file '%1': %2").arg(fileName).arg(fin.errorString())); } - QString text = fin.readAll(); + QTextStream stream(&fin); + stream.setCodec("UTF-8"); + QString text = stream.readAll(); text += QLatin1String("\n\n"); text += QChar('\0'); fin.close(); diff --git a/tools/qdoc3/config.h b/tools/qdoc3/config.h index 5e7e6f1..c29becc 100644 --- a/tools/qdoc3/config.h +++ b/tools/qdoc3/config.h @@ -140,18 +140,26 @@ class Config #define CONFIG_INDEXES "indexes" #define CONFIG_LANGUAGE "language" #define CONFIG_MACRO "macro" +#define CONFIG_NATURALLANGUAGE "naturallanguage" #define CONFIG_OBSOLETELINKS "obsoletelinks" +#define CONFIG_ONLINE "online" #define CONFIG_OUTPUTDIR "outputdir" +#define CONFIG_OUTPUTENCODING "outputencoding" #define CONFIG_OUTPUTLANGUAGE "outputlanguage" #define CONFIG_OUTPUTFORMATS "outputformats" #define CONFIG_PROJECT "project" #define CONFIG_QHP "qhp" #define CONFIG_QUOTINGINFORMATION "quotinginformation" +#define CONFIG_SCRIPTDIRS "scriptdirs" +#define CONFIG_SCRIPTS "scripts" #define CONFIG_SLOW "slow" #define CONFIG_SHOWINTERNAL "showinternal" #define CONFIG_SOURCEDIRS "sourcedirs" +#define CONFIG_SOURCEENCODING "sourceencoding" #define CONFIG_SOURCES "sources" #define CONFIG_SPURIOUS "spurious" +#define CONFIG_STYLEDIRS "styledirs" +#define CONFIG_STYLES "styles" #define CONFIG_STYLESHEETS "stylesheets" #define CONFIG_TABSIZE "tabsize" #define CONFIG_TAGFILE "tagfile" diff --git a/tools/qdoc3/cppcodemarker.cpp b/tools/qdoc3/cppcodemarker.cpp index 6c33054..c4ee054 100644 --- a/tools/qdoc3/cppcodemarker.cpp +++ b/tools/qdoc3/cppcodemarker.cpp @@ -145,7 +145,7 @@ QString CppCodeMarker::plainFullName(const Node *node, const Node *relative) } else { QString fullName; - for (;;) { + while (node) { fullName.prepend(plainName(node)); if (node->parent() == relative || node->parent()->name().isEmpty()) break; @@ -482,55 +482,66 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, if (style == Summary) { FastSection privateFunctions(classe, "Private Functions", + "", "private function", "private functions"); - FastSection privateSlots(classe, "Private Slots", "private slot", "private slots"); - FastSection privateTypes(classe, "Private Types", "private type", "private types"); + FastSection privateSlots(classe, "Private Slots", "", "private slot", "private slots"); + FastSection privateTypes(classe, "Private Types", "", "private type", "private types"); FastSection protectedFunctions(classe, "Protected Functions", + "", "protected function", "protected functions"); FastSection protectedSlots(classe, "Protected Slots", + "", "protected slot", "protected slots"); FastSection protectedTypes(classe, "Protected Types", + "", "protected type", "protected types"); FastSection protectedVariables(classe, "Protected Variables", + "", "protected type", "protected variables"); FastSection publicFunctions(classe, "Public Functions", + "", "public function", "public functions"); - FastSection publicSignals(classe, "Signals", "signal", "signals"); - FastSection publicSlots(classe, "Public Slots", "public slot", "public slots"); - FastSection publicTypes(classe, "Public Types", "public type", "public types"); + FastSection publicSignals(classe, "Signals", "", "signal", "signals"); + FastSection publicSlots(classe, "Public Slots", "", "public slot", "public slots"); + FastSection publicTypes(classe, "Public Types", "", "public type", "public types"); FastSection publicVariables(classe, "Public Variables", - "public type", + "", + "public variable", "public variables"); - FastSection properties(classe, "Properties", "property", "properties"); + FastSection properties(classe, "Properties", "", "property", "properties"); FastSection relatedNonMembers(classe, "Related Non-Members", + "", "related non-member", "related non-members"); FastSection staticPrivateMembers(classe, "Static Private Members", + "", "static private member", "static private members"); FastSection staticProtectedMembers(classe, "Static Protected Members", + "", "static protected member", "static protected members"); FastSection staticPublicMembers(classe, "Static Public Members", + "", "static public member", "static public members"); - FastSection macros(inner, "Macros", "macro", "macros"); + FastSection macros(inner, "Macros", "", "macro", "macros"); NodeList::ConstIterator r = classe->relatedNodes().begin(); while (r != classe->relatedNodes().end()) { @@ -666,12 +677,12 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, append(sections, macros); } else if (style == Detailed) { - FastSection memberFunctions(classe,"Member Function Documentation"); - FastSection memberTypes(classe,"Member Type Documentation"); - FastSection memberVariables(classe,"Member Variable Documentation"); - FastSection properties(classe,"Property Documentation"); - FastSection relatedNonMembers(classe,"Related Non-Members"); - FastSection macros(classe,"Macro Documentation"); + FastSection memberFunctions(classe,"Member Function Documentation","func","member","members"); + FastSection memberTypes(classe,"Member Type Documentation","types","member","members"); + FastSection memberVariables(classe,"Member Variable Documentation","vars","member","members"); + FastSection properties(classe,"Property Documentation","prop","member","members"); + FastSection relatedNonMembers(classe,"Related Non-Members","relnonmem","member","members"); + FastSection macros(classe,"Macro Documentation","macros","member","members"); NodeList::ConstIterator r = classe->relatedNodes().begin(); while (r != classe->relatedNodes().end()) { @@ -717,7 +728,7 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, append(sections, macros); } else { - FastSection all(classe); + FastSection all(classe,"","","member","members"); QStack<const ClassNode *> stack; stack.push(classe); @@ -747,25 +758,29 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, if (style == Summary || style == Detailed) { FastSection namespaces(inner, "Namespaces", + style == Detailed ? "nmspace" : "", "namespace", "namespaces"); FastSection classes(inner, "Classes", + style == Detailed ? "classes" : "", "class", "classes"); FastSection types(inner, - style == Summary ? - "Types" : "Type Documentation", + style == Summary ? "Types" : "Type Documentation", + style == Detailed ? "types" : "", "type", "types"); FastSection functions(inner, style == Summary ? "Functions" : "Function Documentation", + style == Detailed ? "func" : "", "function", "functions"); FastSection macros(inner, style == Summary ? "Macros" : "Macro Documentation", + style == Detailed ? "macros" : "", "macro", "macros"); @@ -881,7 +896,7 @@ QString CppCodeMarker::addMarkUp(const QString& protectedCode, static QRegExp globalX("[\n{()=] *([a-zA-Z_][a-zA-Z_0-9]*)[ \n]*\\("); static QRegExp multiLineComment("/(?:( )?\\*(?:[^*]+|\\*(?! /))*\\*\\1/)"); multiLineComment.setMinimal(true); - static QRegExp singleLineComment("//(?!!)[^!\n]*"); + static QRegExp singleLineComment("[^:]//(?!!)[^!\\n]*"); static QRegExp preprocessor("(?:^|\n)(#[ \t]*(?:include|if|elif|endif|error|pragma|define" "|warning)(?:(?:\\\\\n|\\n#)[^\n]*)*)"); static QRegExp literals(""(?:[^\\\\&]|\\\\[^\n]|&(?!quot;))*"" @@ -1067,13 +1082,13 @@ QString CppCodeMarker::addMarkUp(const QString& protectedCode, len = multiLineComment.matchedLength(); } else if (mlpos == -1) { - pos = slpos; - len = singleLineComment.matchedLength(); + pos = slpos + 1; + len = singleLineComment.matchedLength() - 1; } else { if (slpos < mlpos) { - pos = slpos; - len = singleLineComment.matchedLength(); + pos = slpos + 1; + len = singleLineComment.matchedLength() - 1; } else { pos = mlpos; @@ -1116,26 +1131,32 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, if (style == Summary) { FastSection qmlproperties(qmlClassNode, "Properties", + "", "property", "properties"); FastSection qmlattachedproperties(qmlClassNode, "Attached Properties", + "", "property", "properties"); FastSection qmlsignals(qmlClassNode, - "Signals", - "signal", - "signals"); + "Signals", + "", + "signal", + "signals"); FastSection qmlattachedsignals(qmlClassNode, - "QML Attached Signals", + "Attached Signals", + "", "signal", "signals"); FastSection qmlmethods(qmlClassNode, "Methods", + "", "method", "methods"); FastSection qmlattachedmethods(qmlClassNode, - "QML Attached Methods", + "Attached Methods", + "", "method", "methods"); @@ -1179,12 +1200,15 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, append(sections,qmlattachedmethods); } else if (style == Detailed) { - FastSection qmlproperties(qmlClassNode, "Property Documentation"); - FastSection qmlattachedproperties(qmlClassNode,"Attached Property Documentation"); - FastSection qmlsignals(qmlClassNode,"Signal Documentation"); - FastSection qmlattachedsignals(qmlClassNode,"Attached Signal Documentation"); - FastSection qmlmethods(qmlClassNode,"Method Documentation"); - FastSection qmlattachedmethods(qmlClassNode,"Attached Method Documentation"); + FastSection qmlproperties(qmlClassNode, "Property Documentation","qmlprop","member","members"); + FastSection qmlattachedproperties(qmlClassNode,"Attached Property Documentation","qmlattprop", + "member","members"); + FastSection qmlsignals(qmlClassNode,"Signal Documentation","qmlsig","member","members"); + FastSection qmlattachedsignals(qmlClassNode,"Attached Signal Documentation","qmlattsig", + "member","members"); + FastSection qmlmethods(qmlClassNode,"Method Documentation","qmlmeth","member","members"); + FastSection qmlattachedmethods(qmlClassNode,"Attached Method Documentation","qmlattmeth", + "member","members"); NodeList::ConstIterator c = qmlClassNode->childNodes().begin(); while (c != qmlClassNode->childNodes().end()) { if ((*c)->subType() == Node::QmlPropertyGroup) { diff --git a/tools/qdoc3/cppcodeparser.cpp b/tools/qdoc3/cppcodeparser.cpp index 9b6a516..13678af 100644 --- a/tools/qdoc3/cppcodeparser.cpp +++ b/tools/qdoc3/cppcodeparser.cpp @@ -43,11 +43,11 @@ cppcodeparser.cpp */ -#include <QtCore> #include <qfile.h> #include <stdio.h> #include <errno.h> +#include <qdebug.h> #include "codechunk.h" #include "config.h" @@ -95,6 +95,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_QMLMETHOD Doc::alias("qmlmethod") #define COMMAND_QMLATTACHEDMETHOD Doc::alias("qmlattachedmethod") #define COMMAND_QMLDEFAULT Doc::alias("default") +#define COMMAND_QMLBASICTYPE Doc::alias("qmlbasictype") #endif QStringList CppCodeParser::exampleFiles; @@ -280,8 +281,8 @@ void CppCodeParser::parseHeaderFile(const Location& location, const QString& filePath, Tree *tree) { - FILE *in = fopen(QFile::encodeName(filePath), "r"); - if (!in) { + QFile in(filePath); + if (!in.open(QIODevice::ReadOnly)) { location.error(tr("Cannot open C++ header file '%1'").arg(filePath)); return; } @@ -294,7 +295,7 @@ void CppCodeParser::parseHeaderFile(const Location& location, matchDeclList(tree->root()); if (!fileTokenizer.version().isEmpty()) tree->setVersion(fileTokenizer.version()); - fclose(in); + in.close(); if (fileLocation.fileName() == "qiterator.h") parseQiteratorDotH(location, filePath); @@ -311,8 +312,8 @@ void CppCodeParser::parseSourceFile(const Location& location, const QString& filePath, Tree *tree) { - FILE *in = fopen(QFile::encodeName(filePath), "r"); - if (!in) { + QFile in(filePath); + if (!in.open(QIODevice::ReadOnly)) { location.error(tr("Cannot open C++ source file '%1' (%2)").arg(filePath).arg(strerror(errno))); return; } @@ -324,7 +325,7 @@ void CppCodeParser::parseSourceFile(const Location& location, readToken(); usedNamespaces.clear(); matchDocsAndStuff(); - fclose(in); + in.close(); } /*! @@ -491,7 +492,7 @@ const FunctionNode *CppCodeParser::findFunctionNode(const QString& synopsis, candidates << overload; } - + /* There are several functions with the correct parameter count, but only one has the correct @@ -536,14 +537,15 @@ QSet<QString> CppCodeParser::topicCommands() << COMMAND_QMLSIGNAL << COMMAND_QMLATTACHEDSIGNAL << COMMAND_QMLMETHOD - << COMMAND_QMLATTACHEDMETHOD; + << COMMAND_QMLATTACHEDMETHOD + << COMMAND_QMLBASICTYPE; #else << COMMAND_VARIABLE; #endif } /*! - Process the topic \a command in context \a doc with argument \a arg. + Process the topic \a command in context \a doc with argument \a arg. */ Node *CppCodeParser::processTopicCommand(const Doc& doc, const QString& command, @@ -728,6 +730,20 @@ Node *CppCodeParser::processTopicCommand(const Doc& doc, } return new QmlClassNode(tre->root(), names[0], classNode); } + else if (command == COMMAND_QMLBASICTYPE) { +#if 0 + QStringList parts = arg.split(" "); + qDebug() << command << parts; + if (parts.size() > 1) { + FakeNode* pageNode = static_cast<FakeNode*>(tre->root()->findNode(parts[1], Node::Fake)); + if (pageNode) { + qDebug() << "FOUND"; + return new QmlBasicTypeNode(pageNode, parts[0]); + } + } +#endif + return new QmlBasicTypeNode(tre->root(), arg); + } else if ((command == COMMAND_QMLSIGNAL) || (command == COMMAND_QMLMETHOD) || (command == COMMAND_QMLATTACHEDSIGNAL) || @@ -896,13 +912,13 @@ QSet<QString> CppCodeParser::otherMetaCommands() << COMMAND_NEXTPAGE << COMMAND_PREVIOUSPAGE << COMMAND_INDEXPAGE -#ifdef QDOC_QML +#ifdef QDOC_QML << COMMAND_STARTPAGE << COMMAND_QMLINHERITS << COMMAND_QMLDEFAULT; -#else +#else << COMMAND_STARTPAGE; -#endif +#endif } /*! @@ -1017,7 +1033,10 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, #ifdef QDOC_QML else if (command == COMMAND_QMLINHERITS) { setLink(node, Node::InheritsLink, arg); - } + if (node->subType() == Node::QmlClass) { + QmlClassNode::addInheritedBy(arg,node); + } + } else if (command == COMMAND_QMLDEFAULT) { QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node); qpgn->setDefault(); @@ -1632,8 +1651,9 @@ bool CppCodeParser::matchNamespaceDecl(InnerNode *parent) */ QString namespaceName = previousLexeme(); NamespaceNode *namespasse = 0; - if (parent) + if (parent) { namespasse = static_cast<NamespaceNode*>(parent->findNode(namespaceName, Node::Namespace)); + } if (!namespasse) { namespasse = new NamespaceNode(parent, namespaceName); namespasse->setAccess(access); @@ -2099,7 +2119,7 @@ bool CppCodeParser::matchDocsAndStuff() } ++a; } -#endif +#endif } NodeList::Iterator n = nodes.begin(); @@ -2248,18 +2268,15 @@ void CppCodeParser::instantiateIteratorMacro(const QString &container, void CppCodeParser::createExampleFileNodes(FakeNode *fake) { QString examplePath = fake->name(); - - // we can assume that this file always exists - QString proFileName = examplePath + "/" + - examplePath.split("/").last() + ".pro"; - + QString proFileName = examplePath + "/" + examplePath.split("/").last() + ".pro"; QString userFriendlyFilePath; + QString fullPath = Config::findFile(fake->doc().location(), exampleFiles, exampleDirs, proFileName, userFriendlyFilePath); - + if (fullPath.isEmpty()) { QString tmp = proFileName; proFileName = examplePath + "/" + "qbuild.pro"; @@ -2270,9 +2287,18 @@ void CppCodeParser::createExampleFileNodes(FakeNode *fake) proFileName, userFriendlyFilePath); if (fullPath.isEmpty()) { - fake->doc().location().warning( - tr("Cannot find file '%1' or '%2'").arg(tmp).arg(proFileName)); - return; + proFileName = examplePath + "/" + examplePath.split("/").last() + ".qmlproject"; + userFriendlyFilePath.clear(); + fullPath = Config::findFile(fake->doc().location(), + exampleFiles, + exampleDirs, + proFileName, + userFriendlyFilePath); + if (fullPath.isEmpty()) { + fake->doc().location().warning( + tr("Cannot find file '%1' or '%2'").arg(tmp).arg(proFileName)); + return; + } } } @@ -2283,14 +2309,6 @@ void CppCodeParser::createExampleFileNodes(FakeNode *fake) QString imagesPath = fullPath + "/images"; QStringList imageFiles = Config::getFilesHere(imagesPath,exampleImageFilter); -#if 0 - qDebug() << "examplePath:" << examplePath; - qDebug() << " exampleFiles" << exampleFiles; - qDebug() << "imagesPath:" << imagesPath; - qDebug() << "fullPath:" << fullPath; - qDebug() << " imageFiles" << imageFiles; -#endif - if (!exampleFiles.isEmpty()) { // move main.cpp and to the end, if it exists QString mainCpp; @@ -2303,14 +2321,14 @@ void CppCodeParser::createExampleFileNodes(FakeNode *fake) i.remove(); } else if (fileName.contains("/qrc_") || fileName.contains("/moc_") - || fileName.contains("/ui_")) + || fileName.contains("/ui_")) i.remove(); } if (!mainCpp.isEmpty()) exampleFiles.append(mainCpp); // add any qmake Qt resource files and qmake project files - exampleFiles += Config::getFilesHere(fullPath, "*.qrc *.pro"); + exampleFiles += Config::getFilesHere(fullPath, "*.qrc *.pro qmldir"); } foreach (const QString &exampleFile, exampleFiles) diff --git a/tools/qdoc3/doc.cpp b/tools/qdoc3/doc.cpp index 17a6efd..5716626 100644 --- a/tools/qdoc3/doc.cpp +++ b/tools/qdoc3/doc.cpp @@ -3036,7 +3036,7 @@ QString Doc::canonicalTitle(const QString &title) QString result; result.reserve(title.size()); - bool slurping = false; + bool dashAppended = false; bool begun = false; int lastAlnum = 0; for (int i = 0; i != title.size(); ++i) { @@ -3047,17 +3047,21 @@ QString Doc::canonicalTitle(const QString &title) if (alnum) { result += QLatin1Char(c); begun = true; - slurping = false; + dashAppended = false; lastAlnum = result.size(); } - else if (!slurping) { + else if (!dashAppended) { if (begun) result += QLatin1Char('-'); - slurping = true; + dashAppended = true; } +#if 0 + // This was screwing things up. else { - // !alnum && slurping -> nothin + result += title[i]; + lastAlnum = result.size(); } +#endif } result.truncate(lastAlnum); return result; diff --git a/tools/qdoc3/doc.h b/tools/qdoc3/doc.h index e98bb26..3e76456 100644 --- a/tools/qdoc3/doc.h +++ b/tools/qdoc3/doc.h @@ -48,6 +48,7 @@ #include <QSet> #include <QString> +#include <QMap> #include "location.h" diff --git a/tools/qdoc3/doc/classic.css b/tools/qdoc3/doc/classic.css new file mode 100644 index 0000000..b8cae8e --- /dev/null +++ b/tools/qdoc3/doc/classic.css @@ -0,0 +1,284 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Arial, Geneva, Helvetica, sans-serif; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} + +h3.fn,span.fn +{ + background-color: #eee; + border-width: 1px; + border-style: solid; + border-color: #ddd; + font-weight: bold; + padding: 6px 0px 6px 10px; + margin: 42px 0px 0px 0px; +} + +hr { + border: 0; + color: #a0a0a0; + background-color: #ccc; + height: 1px; + width: 100%; + text-align: left; + margin: 34px 0px 34px 0px; +} + +table.valuelist { + border-width: 1px 1px 1px 1px; + border-style: solid; + border-color: #dddddd; + border-collapse: collapse; + background-color: #f0f0f0; +} + +table.indextable { + border-width: 1px 1px 1px 1px; + border-style: solid; + border-collapse: collapse; + background-color: #f0f0f0; + border-color:#555; + font-size: 100%; +} + +table td.largeindex { + border-width: 1px 1px 1px 1px; + border-collapse: collapse; + background-color: #f0f0f0; + border-color:#555; + font-size: 120%; +} + +table.valuelist th { + border-width: 1px 1px 1px 2px; + padding: 4px; + border-style: solid; + border-color: #666; + color:white; + background-color:#666; +} + +th.titleheader { + border-width: 1px 0px 1px 0px; + padding: 2px; + border-style: solid; + border-color: #666; + color:white; + background-color:#555; + background-image:url('images/gradient.png')}; + background-repeat: repeat-x; + font-size: 100%; +} + + +th.largeheader { + border-width: 1px 0px 1px 0px; + padding: 4px; + border-style: solid; + border-color: #444; + color:white; + background-color:#555555; + font-size: 120%; +} + +p { + + margin-left: 4px; + margin-top: 8px; + margin-bottom: 8px; +} + +a:link +{ + color: #0046ad; + text-decoration: none +} + +a:visited +{ + color: #672967; + text-decoration: none +} + +a.obsolete +{ + color: #661100; + text-decoration: none +} + +a.compat +{ + color: #661100; + text-decoration: none +} + +a.obsolete:visited +{ + color: #995500; + text-decoration: none +} + +a.compat:visited +{ + color: #995500; + text-decoration: none +} + +body +{ + background: #ffffff; + color: black +} + +table.generic, table.annotated +{ + border-width: 1px; + border-color:#bbb; + border-style:solid; + border-collapse:collapse; +} + +table td.memItemLeft { + width: 180px; + padding: 2px 0px 0px 8px; + margin: 4px; + border-width: 1px; + border-color: #E0E0E0; + border-style: none; + font-size: 100%; + white-space: nowrap +} + +table td.memItemRight { + padding: 2px 8px 0px 8px; + margin: 4px; + border-width: 1px; + border-color: #E0E0E0; + border-style: none; + font-size: 100%; +} + +table tr.odd { + background: #f0f0f0; + color: black; +} + +table tr.even { + background: #e4e4e4; + color: black; +} + +table.annotated th { + padding: 3px; + text-align: left +} + +table.annotated td { + padding: 3px; +} + +table tr pre +{ + padding-top: 0px; + padding-bottom: 0px; + padding-left: 0px; + padding-right: 0px; + border: none; + background: none +} + +tr.qt-style +{ + background: #96E066; + color: black +} + +body pre +{ + padding: 0.2em; + border: #e7e7e7 1px solid; + background: #f1f1f1; + color: black +} + +table tr.qt-code pre +{ + padding: 0.2em; + border: #e7e7e7 1px solid; + background: #f1f1f1; + color: black +} + +span.preprocessor, span.preprocessor a +{ + color: darkblue; +} + +span.comment +{ + color: darkred; + font-style: italic +} + +span.string,span.char +{ + color: darkgreen; +} + +.title +{ + text-align: center +} + +.subtitle +{ + font-size: 0.8em +} + +.small-subtitle +{ + font-size: 0.65em +} + +.qmlitem { + padding: 0; +} + +.qmlname { + white-space: nowrap; +} + +.qmltype { + text-align: center; + font-size: 160%; +} + +.qmlproto { + background-color: #eee; + border-width: 1px; + border-style: solid; + border-color: #ddd; + font-weight: bold; + padding: 6px 10px 6px 10px; + margin: 42px 0px 0px 0px; +} + +.qmlreadonly { + float: right; + color: red +} + +.qmldoc { +} + +*.qmlitem p { +} diff --git a/tools/qdoc3/doc/examples/layoutmanagement.qdocinc b/tools/qdoc3/doc/examples/layoutmanagement.qdocinc new file mode 100644 index 0000000..01f8acf --- /dev/null +++ b/tools/qdoc3/doc/examples/layoutmanagement.qdocinc @@ -0,0 +1,13 @@ +\section1 Layout Classes + +The Qt layout system provides a simple and powerful way of specifying +the layout of child widgets. + +By specifying the logical layout once, you get the following benefits: + +\list + \o Positioning of child widgets. + \o Sensible default sizes for windows. + \o Sensible minimum sizes for windows. + \o ... +\endlist diff --git a/tools/qdoc3/doc/examples/main.cpp b/tools/qdoc3/doc/examples/main.cpp new file mode 100644 index 0000000..e439d3e --- /dev/null +++ b/tools/qdoc3/doc/examples/main.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QApplication> +#include <QPushButton> + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + QPushButton hello("Hello world!"); + hello.resize(100, 30); + + hello.show(); + return app.exec(); +} diff --git a/tools/qdoc3/doc/examples/minimum.qdocconf b/tools/qdoc3/doc/examples/minimum.qdocconf new file mode 100644 index 0000000..e5e9e67 --- /dev/null +++ b/tools/qdoc3/doc/examples/minimum.qdocconf @@ -0,0 +1,42 @@ +# QDoc is a tool that constantly evolves to suit our needs, +# and there are some compatibility issues between old and new +# practices. For that reason, any QDoc configuration file needs to +# include compat.qdocconf. + +#include(compat.qdocconf) + + +# The outputdir variable specifies the directory +# where QDoc will put the generated documentation. + +outputdir = html + + +# The headerdirs variable specifies the directories +# containing the header files associated +# with the .cpp source files used in the documentation. + +headerdirs = . + + +# The sourcedirs variable specifies the +# directories containing the .cpp or .qdoc +# files used in the documentation. + +#sourcedirs = . + + +# The exampledirs variable specifies the directories containing +# the source code of the example files. + +exampledirs = . + + +# The imagedirs variable specifies the +# directories containing the images used in the documentation. + +imagedirs = ./images + + + + diff --git a/tools/qdoc3/doc/examples/objectmodel.qdocinc b/tools/qdoc3/doc/examples/objectmodel.qdocinc new file mode 100644 index 0000000..02b5991 --- /dev/null +++ b/tools/qdoc3/doc/examples/objectmodel.qdocinc @@ -0,0 +1,11 @@ +\section1 Qt Object Model + +The standard C++ object model provides very efficient runtime support +for the object paradigm. But its static nature is inflexibile in +certain problem domains. Graphical user interface programming is a +domain that requires both runtime efficiency and a high level of +flexibility. Qt provides this, by combining the speed of C++ with the +flexibility of the Qt Object Model. + +... + diff --git a/tools/qdoc3/doc/examples/signalandslots.qdocinc b/tools/qdoc3/doc/examples/signalandslots.qdocinc new file mode 100644 index 0000000..cfae43a --- /dev/null +++ b/tools/qdoc3/doc/examples/signalandslots.qdocinc @@ -0,0 +1,9 @@ +\section1 Signals and Slots + +Signals and slots are used for communication between objects. The signals and +slots mechanism is a central feature of Qt and probably the part that differs +most from the features provided by other frameworks. + +\section2 Introduction + +In GUI programming, when we ... diff --git a/tools/qdoc3/doc/files/compat.qdocconf b/tools/qdoc3/doc/files/compat.qdocconf new file mode 100644 index 0000000..5745ed9 --- /dev/null +++ b/tools/qdoc3/doc/files/compat.qdocconf @@ -0,0 +1,31 @@ +alias.i = e +alias.include = input + +macro.0 = "\\\\0" +macro.b = "\\\\b" +macro.n = "\\\\n" +macro.r = "\\\\r" +macro.i = "\\o" +macro.i11 = "\\o{1,1}" +macro.i12 = "\\o{1,2}" +macro.i13 = "\\o{1,3}" +macro.i14 = "\\o{1,4}" +macro.i15 = "\\o{1,5}" +macro.i16 = "\\o{1,6}" +macro.i17 = "\\o{1,7}" +macro.i18 = "\\o{1,8}" +macro.i19 = "\\o{1,9}" +macro.i21 = "\\o{2,1}" +macro.i31 = "\\o{3,1}" +macro.i41 = "\\o{4,1}" +macro.i51 = "\\o{5,1}" +macro.i61 = "\\o{6,1}" +macro.i71 = "\\o{7,1}" +macro.i81 = "\\o{8,1}" +macro.i91 = "\\o{9,1}" +macro.img = "\\image" +macro.endquote = "\\endquotation" +macro.relatesto = "\\relates" + +spurious = "Missing comma in .*" \ + "Missing pattern .*" diff --git a/tools/qdoc3/doc/files/qt.qdocconf b/tools/qdoc3/doc/files/qt.qdocconf new file mode 100644 index 0000000..942d023 --- /dev/null +++ b/tools/qdoc3/doc/files/qt.qdocconf @@ -0,0 +1,115 @@ +include(compat.qdocconf) +include(macros.qdocconf) +include(qt-cpp-ignore.qdocconf) +include(qt-html-templates.qdocconf) +include(qt-defines.qdocconf) + +project = Qt +versionsym = +version = %VERSION% +description = Qt Reference Documentation +url = http://qt.nokia.com/doc/4.6 + +edition.Console.modules = QtCore QtDBus QtNetwork QtScript QtSql QtXml \ + QtXmlPatterns QtTest +edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript QtScriptTools QtSql QtSvg \ + QtWebKit QtXml QtXmlPatterns Qt3Support QtHelp \ + QtDesigner QtAssistant QAxContainer Phonon \ + QAxServer QtUiTools QtTest QtDBus +edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest +edition.DesktopLight.groups = -graphicsview-api + +qhp.projects = Qt + +qhp.Qt.file = qt.qhp +qhp.Qt.namespace = com.trolltech.qt.460 +qhp.Qt.virtualFolder = qdoc +qhp.Qt.indexTitle = Qt Reference Documentation +qhp.Qt.indexRoot = + +# Files not referenced in any qdoc file (last four are needed by qtdemo) +# See also extraimages.HTML +qhp.Qt.extraFiles = classic.css \ + images/qt-logo.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + images/stylesheet-coffee-plastique.png + +qhp.Qt.filterAttributes = qt 4.6.0 qtrefdoc +qhp.Qt.customFilters.Qt.name = Qt 4.6.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.6.0 +qhp.Qt.subprojects = classes overviews examples +qhp.Qt.subprojects.classes.title = Classes +qhp.Qt.subprojects.classes.indexTitle = Qt's Classes +qhp.Qt.subprojects.classes.selectors = class fake:headerfile +qhp.Qt.subprojects.classes.sortPages = true +qhp.Qt.subprojects.overviews.title = Overviews +qhp.Qt.subprojects.overviews.indexTitle = All Overviews and HOWTOs +qhp.Qt.subprojects.overviews.selectors = fake:page,group,module +qhp.Qt.subprojects.examples.title = Tutorials and Examples +qhp.Qt.subprojects.examples.indexTitle = Qt Examples +qhp.Qt.subprojects.examples.selectors = fake:example + +language = Cpp + +headerdirs = $QTDIR/src \ + $QTDIR/extensions/activeqt \ + $QTDIR/tools/assistant/lib \ + $QTDIR/tools/assistant/compat/lib \ + $QTDIR/tools/designer/src/uitools \ + $QTDIR/tools/designer/src/lib/extension \ + $QTDIR/tools/designer/src/lib/sdk \ + $QTDIR/tools/designer/src/lib/uilib \ + $QTDIR/tools/qtestlib/src \ + $QTDIR/tools/qdbus/src +sourcedirs = $QTDIR/src \ + $QTDIR/doc/src \ + $QTDIR/extensions/activeqt \ + $QTDIR/tools/assistant/lib \ + $QTDIR/tools/assistant/compat/lib \ + $QTDIR/tools/designer/src/uitools \ + $QTDIR/tools/designer/src/lib/extension \ + $QTDIR/tools/designer/src/lib/sdk \ + $QTDIR/tools/designer/src/lib/uilib \ + $QTDIR/tools/qtestlib/src \ + $QTDIR/tools/qdbus + +excludedirs = $QTDIR/src/3rdparty/clucene \ + $QTDIR/src/3rdparty/des \ + $QTDIR/src/3rdparty/freetype \ + $QTDIR/src/3rdparty/harfbuzz \ + $QTDIR/src/3rdparty/kdebase \ + $QTDIR/src/3rdparty/libjpeg \ + $QTDIR/src/3rdparty/libmng \ + $QTDIR/src/3rdparty/libpng \ + $QTDIR/src/3rdparty/libtiff \ + $QTDIR/src/3rdparty/md4 \ + $QTDIR/src/3rdparty/md5 \ + $QTDIR/src/3rdparty/patches \ + $QTDIR/src/3rdparty/sha1 \ + $QTDIR/src/3rdparty/sqlite \ + $QTDIR/src/3rdparty/webkit/JavaScriptCore \ + $QTDIR/src/3rdparty/webkit/WebCore \ + $QTDIR/src/3rdparty/wintab \ + $QTDIR/src/3rdparty/zlib \ + $QTDIR/doc/src/snippets \ + $QTDIR/src/3rdparty/phonon/gstreamer \ + $QTDIR/src/3rdparty/phonon/ds9 \ + $QTDIR/src/3rdparty/phonon/qt7 \ + $QTDIR/src/3rdparty/phonon/waveout + +sources.fileextensions = "*.cpp *.qdoc *.mm" +examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" + +exampledirs = $QTDIR/doc/src \ + $QTDIR/examples \ + $QTDIR/examples/tutorials \ + $QTDIR \ + $QTDIR/qmake/examples \ + $QTDIR/src/3rdparty/webkit/WebKit/qt/docs +imagedirs = $QTDIR/doc/src/images \ + $QTDIR/examples +outputdir = $QTDIR/doc/html +tagfile = $QTDIR/doc/html/qt.tags +base = file:$QTDIR/doc/html diff --git a/tools/qdoc3/doc/images/happy.gif b/tools/qdoc3/doc/images/happy.gif Binary files differnew file mode 100644 index 0000000..a4597f6 --- /dev/null +++ b/tools/qdoc3/doc/images/happy.gif diff --git a/tools/qdoc3/doc/images/happyguy.jpg b/tools/qdoc3/doc/images/happyguy.jpg Binary files differnew file mode 100644 index 0000000..e860479 --- /dev/null +++ b/tools/qdoc3/doc/images/happyguy.jpg diff --git a/tools/qdoc3/doc/images/qt-logo.png b/tools/qdoc3/doc/images/qt-logo.png Binary files differnew file mode 100644 index 0000000..14ddf2a --- /dev/null +++ b/tools/qdoc3/doc/images/qt-logo.png diff --git a/tools/qdoc3/doc/images/training.jpg b/tools/qdoc3/doc/images/training.jpg Binary files differnew file mode 100644 index 0000000..c2ce5c3 --- /dev/null +++ b/tools/qdoc3/doc/images/training.jpg diff --git a/tools/qdoc3/doc/qdoc-manual.qdoc b/tools/qdoc3/doc/qdoc-manual.qdoc new file mode 100644 index 0000000..482af46 --- /dev/null +++ b/tools/qdoc3/doc/qdoc-manual.qdoc @@ -0,0 +1,8767 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page index.html + \nextpage QDoc Manual + + \title QDoc Manual - Table of Contents + + \list + \o \l{QDoc Manual} + \o \l{QDoc Commands} + \list + \o \l{Markup Commands} + \o \l{Text Formatting Commands} + \o \l{Document Structuring Commands} + \o \l{Verbatim Code Commands} + \o \l{Quoting External Code Commands} + \list + \o \l{Example File} + \endlist + \o \l{Linking Commands} + \o \l{Graphic Commands} + \o \l{Container Commands} + \o \l{Document Contents Commands} + \o \l{Miscellaneous Commands} + \list + \o \l{signalandslots.qdocinc} + \o \l{objectmodel.qdocinc} + \o \l{layoutmanagement.qdocinc} + \endlist + \o \l{Topical Commands} + \o \l{Contextual Commands} + \o \l{Navigation Commands} + \o \l{Status Commands} + \o \l{Thread Support Commands} + \o \l{Relating Commands} + \o \l{Grouping Commands} + \o \l{Title Commands} + \endlist + \o \l{QDoc Configuration} + \list + \o \l{General Configuration Variables} + \o \l{Creating Help Project Files} + \o \l{C++ Specific Configuration Variables} + \o \l{HTML Specific Configuration Variables} + \o \l{Supporting Derived Projects} + \o \l{QDoc Compatibility} + \o \l{qt.qdocconf} + \o \l{minimum.qdocconf} + \endlist + \o \l{QDoc Commands - Alphabetical List} + \endlist +*/ + +/*! + \page 01-qdoc-manual.html + \contentspage QDoc Manual - Table of Contents + \previouspage QDoc Manual - Table of Contents + \nextpage QDoc Commands + + \title QDoc Manual + + QDoc is the internal tool used by Qt Development Frameworks for generating + documentation. This document is a reference for QDoc command syntax and + configuration. + + \section1 Overview + + \list I + \o \section2 \l {QDoc Commands} + + \l {QDoc Commands - Alphabetical List}{A complete alphabetical + list}. + + There are two main categories of commands for QDoc: markup + commands and meta-commands. + + The markup commands indicate the generated documentation's + appearance and logical structure. The meta-commands provide + information about the document as well as the documented + item. The meta-commands can be further categorized as topical + commands and contextual commands. + + \list + \o \l {Markup Commands} + \list + \o \l {Text Formatting Commands}{Text Formatting} + \o \l {Document Structuring Commands}{Document Structuring} + \o \l {Verbatim Code Commands}{Verbatim Code} + \o \l {Quoting External Code Commands}{Quoting External Code} + \o \l {Linking Commands}{Linking} + \o \l {Graphic Commands}{Graphic} + \o \l {Container Commands}{Container} + \o \l {Document Contents Commands}{Document Contents} + \o \l {Miscellaneous Commands}{Miscellaneous} + \endlist + \o \l {Topical Commands} + \o \l {Contextual Commands} + \list + \o \l {Navigation Commands}{Navigation} + \o \l {Status Commands}{Status} + \o \l {Thread Support Commands}{Thread Support} + \o \l {Relating Commands}{Relating} + \o \l {Grouping Commands}{Grouping} + \o \l {Title Commands}{Title} + \endlist + \endlist + \endlist + + \list II + \o \section2 \l {QDoc Configuration} + + When running QDoc to generate the documentation, you must + specify a configuration file on the command line. The + configuration file is a list of entries of entries of the form + "variable = value". + + \list + \o \l {Configuration Variables} + \o \l {Configuration File Examples} + \endlist + + Some particular configuration variables allow you to use QDoc + to support Qt-based projects; i.e to make projects, such as Qt + Solutions, contain references to the online Qt documentation. + + \list + \o \l {Supporting Derived Projects} + \endlist + + QDoc is a tool that constantly evolves to suit our needs, for + that reason there are some compatibility issues between old and + new practices. + + \list + \o \l {QDoc Compatibility} + \endlist + \endlist +*/ + +/*! + \page 02-qdoc-commands.html + \previouspage QDoc Manual + \contentspage QDoc Manual - Table of Contents + \nextpage Markup Commands + + \title QDoc Commands + + There are two main categories of commands for QDoc: markup + commands and meta-commands. + + The markup commands indicate the generated documentation's visual + appearance and logical structure. The meta-commands provide + information about the documentation unit as well as the documented + item. The meta-commands can be further categorized as topical + commands and contextual commands. + + \section1 Alphabetical List + + A complete \l{QDoc Commands - Alphabetical List } + {alphabetical list of the QDoc commands}. + + \section1 Categories + + \list + \o \l {Markup Commands} + \o \l {Topical Commands} + \o \l {Contextual Commands} + \endlist +*/ + +/*! + \page 03-qdoc-commands-markup.html + \contentspage QDoc Manual - Table of Contents + \previouspage QDoc Commands + \nextpage Text Formatting Commands + + \title Markup Commands + + The markup commands indicate the generated documentation's visual + appearance and logical structure. + + \section1 Alphabetical List + + \l {04-qdoc-commands-textformatting.html#backslash}{\\\\}, + \l {04-qdoc-commands-textformatting.html#a}{\\a}, + \l {11-qdoc-commands-documentcontents.html#abstract}{\\abstract}, + \l {06-qdoc-commands-verbatimcode.html#badcode}{\\badcode}, + \l {04-qdoc-commands-textformatting.html#bold}{\\bold}, + \l {11-qdoc-commands-documentcontents.html#brief}{\\brief}, + \l {04-qdoc-commands-textformatting.html#c}{\\c}, + \l {09-qdoc-commands-graphic.html#caption}{\\caption}, + \l {05-qdoc-commands-documentstructuring.html#chapter}{\\chapter}, + \l {06-qdoc-commands-verbatimcode.html#code}{\\code}, + \l {07-0-qdoc-commands-quoting.html#codeline}{\\codeline}, + \l {07-0-qdoc-commands-quoting.html#dots}{\\dots}, + \l {12-0-qdoc-commands-miscellaneous.html#else}{\\else}, + \l {12-0-qdoc-commands-miscellaneous.html#endif}{\\endif}, + \l {12-0-qdoc-commands-miscellaneous.html#expire}{\\expire}, + \l {11-qdoc-commands-documentcontents.html#footnote}{\\footnote}, + \l {12-0-qdoc-commands-miscellaneous.html#generatelist}{\\generatelist}, + \l {10-qdoc-commands-container.html#header}{\\header}, + \l {04-qdoc-commands-textformatting.html#i}{\\i}, + \l {12-0-qdoc-commands-miscellaneous.html#if}{\\if}, + \l {09-qdoc-commands-graphic.html#image}{\\image}, + \l {12-0-qdoc-commands-miscellaneous.html#include}{\\include}, + \l {09-qdoc-commands-graphic.html#inlineimage}{\\inlineimage}, + \l {08-qdoc-commands-linking.html#keyword}{\\keyword}, + \l {08-qdoc-commands-linking.html#l}{\\l}, + \l {11-qdoc-commands-documentcontents.html#legalese}{\\legalese}, + \l {10-qdoc-commands-container.html#list}{\\list}, + \l {12-0-qdoc-commands-miscellaneous.html#meta}{\\meta}, + \l {06-qdoc-commands-verbatimcode.html#newcode}{\\newcode}, + \l {10-qdoc-commands-container.html#o}{\\o}, + \l {06-qdoc-commands-verbatimcode.html#oldcode}{\\oldcode}, + \l {12-0-qdoc-commands-miscellaneous.html#omit}{\\omit}, + \l {05-qdoc-commands-documentstructuring.html#part}{\\part}, + \l {07-0-qdoc-commands-quoting.html#printline}{\\printline}, + \l {07-0-qdoc-commands-quoting.html#printto}{\\printto}, + \l {07-0-qdoc-commands-quoting.html#printuntil}{\\printuntil}, + \l {11-qdoc-commands-documentcontents.html#quotation}{\\quotation}, + \l {07-0-qdoc-commands-quoting.html#quotefile}{\\quotefile}, + \l {07-0-qdoc-commands-quoting.html#quotefromfile}{\\quotefromfile}, + \l {12-0-qdoc-commands-miscellaneous.html#raw}{\\raw}, + \l {10-qdoc-commands-container.html#row}{\\row}, + \l {08-qdoc-commands-linking.html#sa}{\\sa}, + \l {05-qdoc-commands-documentstructuring.html#sectionOne}{\\section1}, + \l {05-qdoc-commands-documentstructuring.html#sectionTwo}{\\section2}, + \l {05-qdoc-commands-documentstructuring.html#sectionThree}{\\section3}, + \l {05-qdoc-commands-documentstructuring.html#sectionFour}{\\section4}, + \l {07-0-qdoc-commands-quoting.html#skipline}{\\skipline}, + \l {07-0-qdoc-commands-quoting.html#skipto}{\\skipto}, + \l {07-0-qdoc-commands-quoting.html#skipuntil}{\\skipuntil}, + \l {07-0-qdoc-commands-quoting.html#snippet}{\\snippet}, + \l {04-qdoc-commands-textformatting.html#sub}{\\sub}, + \l {04-qdoc-commands-textformatting.html#sup}{\\sup}, + \l {10-qdoc-commands-container.html#table}{\\table}, + \l {11-qdoc-commands-documentcontents.html#tableofcontents} + {\\tableofcontents}, + \l {08-qdoc-commands-linking.html#target}{\\target}, + \l {04-qdoc-commands-textformatting.html#tt}{\\tt}, + \l {04-qdoc-commands-textformatting.html#underline}{\\underline}, + \l {12-0-qdoc-commands-miscellaneous.html#raw}{\\unicode}, + \l {11-qdoc-commands-documentcontents.html#warning}{\\warning} + + \section1 Categories + \list + \o \l {Text Formatting Commands} + \o \l {Document Structuring Commands} + \o \l {Verbatim Code Commands} + \o \l {Quoting External Code Commands} + \o \l {Linking Commands} + \o \l {Graphic Commands} + \o \l {Container Commands} + \o \l {Document Contents Commands} + \o \l {Miscellaneous Commands} + \endlist + +*/ + +/*! + \page 04-qdoc-commands-textformatting.html + \contentspage QDoc Manual - Table of Contents + \previouspage Markup Commands + \nextpage Document Structuring Commands + + \title Text Formatting Commands + + The text formatting commands indicate how the regular text in the + documentation is rendered. + + \section1 Alphabetical List + + \l {04-qdoc-commands-textformatting.html#backslash}{\\\\}, + \l {04-qdoc-commands-textformatting.html#a}{\\a}, + \l {04-qdoc-commands-textformatting.html#bold}{\\bold}, + \l {04-qdoc-commands-textformatting.html#c}{\\c}, + \l {04-qdoc-commands-textformatting.html#i}{\\i}, + \l {04-qdoc-commands-textformatting.html#sub}{\\sub}, + \l {04-qdoc-commands-textformatting.html#sup}{\\sup}, + \l {04-qdoc-commands-textformatting.html#tt}{\\tt}, + \l {04-qdoc-commands-textformatting.html#underline}{\\underline} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + + \o \bold \\\\ \target backslash + \o \bold {The \\\\ command expands to a single backslash.} + + QDoc commands always start with a backslash alone. To + display an actual backslash in the text you need to type + two of the kind. If you want to display two backslashes, + you need to type four, and so forth. For example: + + \code + / *! + The \\\\ command is useful if you want a + backslash to appear verbatim, for example, + writing C:\\windows\\home\\. + * / + \endcode + + will be rendered as + + \quotation + The \\\\ command is useful if you want a + backslash to appear verbatim, for example, + writing C:\\windows\\home\\. + \endquotation + + However, if you want your text to appear in a typewriter + font as well, you can use the \l {c}{\\c} command instead, + which accepts and renders the backslash as any other + character. For example: + + \code + / *! + The \\c command is useful if you want a + backslash to appear verbatim, and the word + that contains it written in a typewriter font, + like this: \c {C:\windows\home\}. + * / + \endcode + + will be rendered as + + \quotation + The \\c command is useful if you want a + backslash to appear verbatim, and the word + that contains it written in a typewriter font, + like this: \c {C:\windows\home\}. + \endquotation + + \row + \o \bold \\a \target a + \o \bold {The \\a command indicates that the next word + is a parameter when documenting functions.} + + Warnings are emitted when function parameters are + undocumented or misspelled, so whenever you write + documentation for functions you should make sure you + mention all the parameters and precede each of these by the + \\a command. The parameter is then rendered in italic. For + example: + + \code + / *! + Constructs a line edit containing the text + \a contents. + + The \a parent parameter is sent to the + QWidget constructor. + * / + + QLineEdit::QLineEdit(const QString &contents, QWidget *parent) + :QWidget(parent) + { + ... + } + + \endcode + + will be rendered as + + \quotation + \bold {QLineEdit::QLineEdit ( const QString & + contents, QWidget *parent )} + + Constructs a line edit containing the text \a contents. + + The \a parent parameter is sent to the QWidget + constructor. + + \endquotation + + The \\a command follows the same conventions as the \l + {i}{\\i} command for \l {argument}{punctuation, parentheses + and use of braces} for the argument. However, a parameter + is always a single word, so braces are rarely + necessary. And for the same reason, parentheses seldom + occur. + + \row + \o \bold \\c \target c + \o \bold {The \\c command can be used to render variables, + user-defined classes and C++ keywords like \c int, + \c for, etc.} + + The command renders its argument using a typewriter font. For + example: + + \code + / *! + The \c AnalogClock class provides a clock widget with hour + and minute hands that is automatically updated every + few seconds. + * / + \endcode + + will be rendered as + + \quotation + The \c AnalogClock class provides a clock widget with hour + and minute hands that is automatically updated every + few seconds. + \endquotation + + The \\c command follows the same conventions as the \l + {i}{\\i} command for \l {argument}{punctuation, parentheses + and use of braces} for the argument. + + The \\c command accepts the special character \c \ within + its argument, i.e. it renders it as a normal character. So + if you want to use nested commands, you must use the \l + {tt}{teletype (\\tt)} command instead. + + See also \l {tt}{\\tt} and \l {code}{\\code}. + + \row + \o \bold \\tt \target tt + \o \bold {The \\tt command can be used to render variables, + user-defined classes and C++ keywords like \c int, \c + for, etc.} + + The \\tt command behaves just like the \l {c}{\\c} command, + except that \\tt parses QDoc commands (like \l {i}{\\i}, \l + {bold}{\\bold} and \l {underline}{\\underline}) contained + within its argument. + + The command renders its argument using a monospace + font. For example: + + \code + / *! + After \c setupUi() populates the main container with + child widgets it scans the main container's list of + slots for names with the form + \tt{on_\i{objectName}_\i{signalName}().} + * / + \endcode + + will be rendered as + + \quotation + After \c setupUi() populates the main container with + child widgets it scans the main container's list of + slots for names with the form + \tt{on_\i{objectName}_\i{signalName}().} + \endquotation + + The \\tt command follows the same conventions as the \l + {i}{\\i} command for \l {argument}{punctuation, parentheses + and use of braces} for the argument. + + See also \l {c}{\\c}. + + \row + \o \bold \\bold \target bold + \o \bold {The \\bold command renders its argument using + a bold font.} + + For example: + + \code + / *! + This is regular text; \bold {this text is + rendered using the \\bold command}. + * / + \endcode + + will be rendered as + + \quotation + This is regular text; \bold {this text is rendered using + the \\bold command}. + \endquotation + + The command follows the same conventions as the \l {i}{\\i} + command for \l {argument}{punctuation, parentheses and use + of braces} for the argument. + + \row + \o \bold \\i \target i + \o \bold {The \\i command renders its argument in italic.} + + \warning This is preliminary functionality. For + more information, see the \l + {26-qdoc-commands-compatibility.html#i-versus-e}{compatibility} + section. + + \target argument + Normally, a command argument ends at the next whitespace [1], + but braces can be used to group words [2]. For example: + + \code + / *! + Here, we render \i {a few words} in italic. + * / + \endcode + + will be rendered as + + \quotation + Here, we render \i {a few words} in italic. + \endquotation + + If you want to use other QDoc commands within an argument + that contains spaces, you always need to enclose the + argument with braces. But QDoc is smart enough to count + parentheses [3], so you don't need braces in cases like this: + + \code + / *! + An argument can sometimes contain whitespaces, + for example: \i QPushButton(tr("A Brand New Button")) + * / + \endcode + + will be rendered as + + \quotation + An argument can sometimes contain whitespaces, + for example: \i QPushButton(tr("A Brand New Button")) + \endquotation + + Finally, trailing punctuation is not included in an + argument [4], nor is 's [5] + + \raw HTML + <table align="center" cellpadding="2" + cellspacing="1" border="0"> + <tr valign="top" bgcolor="#a2c511"> + <th></th> + <th>QDoc Syntax</th> + <th>Generated Documentation</th> + </tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td>1</td> + <td>A variation of a command button is a \i menu + button.</td> + <td>A variation of a command button is a <i>menu</i> + button.</td> + </tr> + + <tr valign="top" bgcolor="#c0c0c0"> + <td>2</td> + <td>The QPushButton widget provides a + \i {command button}.</td> + <td>The QPushButton widget provides a + <i>command button</i>.</td> + </tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td>3</td> + <td>Another class of buttons are option buttons + \i (see QRadioButton).</td> + <td>Another class of buttons are option buttons + <i> (see QRadioButton)</i>.</td> + </tr> + + <tr valign="top" bgcolor="#c0c0c0"> + <td>4</td> + <td>A push button emits the signal \i clicked().</td> + <td>A push button emits the signal <i>clicked</i>().</td> + </tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td>5</td> + <td>The \i QPushButton's checked property is + false by default.</td> + <td>The <i>QPushButton</i>'s checked property is + false by default.</td> + </tr> + + </table> + \endraw + + \row + \o \bold \\sub \target sub + \o \bold {The \\sub command renders its argument lower + than the baseline of the regular text, using a smaller font.} + + For example: + + \code + / *! + Definition (Range): Consider the sequence + {x\sub n}\sub {n > 1} . The set + + {x\sub 2, x\sub 3, x\sub 4, ...} = {x\sub n ; n = 2, 3, 4, ...} + + is called the range of the sequence. + * / + \endcode + + will be rendered as + + \quotation + Definition (Range): Consider the sequence + {x\sub n}\sub {n > 1} . The set + + {x\sub 2, x\sub 3, x\sub 4, ...} = {x\sub n ; n = 2, 3, 4, ...} + + is called the range of the sequence. + \endquotation + + The \\sub command follows the same conventions as the \l + {i}{\\i} command for \l {argument}{punctuation, parentheses + and use of braces} for the argument. + + \row + \o \bold \\sup \target sup + \o \bold {The \\sup command renders its argument higher than + the baseline of the regular text, using a smaller font.} + + For example: + + \code + / *! + The series + + 1 + a + a\sup 2 + a\sup 3 + a\sup 4 + ... + + is called the \i {geometric series}. + * / + \endcode + + will be rendered as + + \quotation + The series + + 1 + a + a\sup 2 + a\sup 3 + a\sup 4 + ... + + is called the \i {geometric series}. + \endquotation + + The \\sup command follows the same conventions as the \l + {i}{\\i} command for \l {argument}{punctuation, parentheses + and use of braces} for the argument. + + \row + \o \bold \\underline \target underline + \o \bold {The \\underline command renders its argument underlined.} + + For example: + + \code + / *! + The \underline {F}ile menu gives the users the possibility + to open, and edit, an existing file, save a new or modified + file, and exit the application. + * / + \endcode + + will be rendered as + + \quotation + The \underline {F}ile menu gives the users the possibility + to open, and edit, an existing file, save a new or modified + file, and exit the application. + \endquotation + + The \\underline command follows the same conventions as the + \l {i}{\\i} command for \l {argument}{punctuation, + parentheses and use of braces} for the argument. \endtable +*/ + +/*! + \page 05-qdoc-commands-documentstructuring.html + \previouspage Text Formatting Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Verbatim Code Commands + + \title Document Structuring Commands + + The document structuring commands divide the documentation into + sections. In total, there are six levels of sections in QDoc: \c + \part, \c \chapter, \c \section1, \c \section2, \c \section3 and + \c \section4. \c \section1 to \c \section4 correspond to the + traditional section, subsection, subsubsection and + subsubsubsection. + + \section1 Alphabetical List + + \l {05-qdoc-commands-documentstructuring.html#chapter}{\\chapter}, + \l {05-qdoc-commands-documentstructuring.html#part}{\\part}, + \l {05-qdoc-commands-documentstructuring.html#sectionOne}{\\section1}, + \l {05-qdoc-commands-documentstructuring.html#sectionTwo}{\\section2}, + \l {05-qdoc-commands-documentstructuring.html#sectionThree}{\\section3}, + \l {05-qdoc-commands-documentstructuring.html#sectionFour}{\\section4} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\part \target part + \o \bold {The \\part command is intended for use in + larger documents, and divides the document into parts.} + + In general a document structuring command considers + everything that follows it until the first line break as + its argument. The argument is rendered as the unit's + title. If the title needs to be spanned over several lines, + make sure that each line (except the last one) is ended + with a backslash. + + In total, there are six levels of sections in QDoc: \c + \part, \c \chapter, \c \section1, \c \section2, \c + \section3 and \c \section4. \c \section1 to \c \section4 + correspond to the traditional section, subsection, + subsubsection and subsubsubsection. + + There is a strict ordering of the section units: + + \code + part + | + chapter + | + section1 + | + section2 + | + section3 + | + section4 + \endcode + + For example, a \c section1 unit can only appear as the top + level section or inside a \c chapter unit. Skipping a + section unit, for example from \c part to \c section1, is + not allowed. + + You can \i begin with either of the three: \c part, \c + chapter or \c section1. For example: + + + \code + / *! + \part Basic Qt + + This is the first part. + + + \chapter Getting Started + + This is the first part's first chapter. + + + \section1 Hello Qt + + This is the first chapter's first section. + + + \section1 Making Connections + + This is the first chapter's second section. + + + \section1 Using the Reference Documentation + + This is the first chapter's third section. + + + \chapter Creating Dialogs + + This is the first part's second chapter. + + + \section1 Subclassing QDialog + + This is the second chapter's first section. + + ... + + + \part Intermediate Qt + + This is the second part. + + + \chapter Layout Management + + This is the second part's first chapter. + + + \section1 Basic Layouts + + This is the first chapter's first section. + + ... + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <a name="Basic Qt"> + <h1>Basic Qt</h1> + </a> + <p>This is the first part.</p> + + <a name="Getting started"> + <h2>Getting Started</h2> + </a> + This is the first part's first chapter.</p> + + <a name="Hello Qt"> + <h3>Hello Qt</h3> + </a> + <p>This is the first chapter's first section.</p> + + <a name="Making Connections"> + <h3>Making Connections</h3> + </a> + <p>This is the first chapter's second section.</p> + + <a name="Using the Reference Documentation"> + <h3>Using the Reference Documentation</h3> + </a> + <p>This is the first chapter's third section.</p> + + <a name="Creating Dialogs"> + <h2>Creating Dialogs</h2> + </a> + <p>This is the first part's second chapter.</p> + + <a name="Subclassing QDialog"> + <h3>Subclassing QDialog</h3> + </a> + <p>This is the second chapter's first section.</p> + + ... + + <a name="Intermediate Qt"> + <h1>Intermediate Qt</h1> + </a> + <p>This is the second part.</p> + + <a name="Layout Management"> + <h2>Layout Management</h2> + </a> + <p>This is the second part's first chapter.</p> + + <a name="Basic Layouts"> + <h3>Basic Layouts</h3> + </a> + <p>This is the first chapter's first section.</p> + + ... + + \endraw + \endquotation + + Each section level is a logical unit within the + document. Its title will appear on the table of contents + generated by the \l + {11-qdoc-commands-documentcontents.html#tableofcontents} + {\\tableofcontents} command. For example: + + \code + / *! + Contents: + + \tableofcontents + + ... + * / + \endcode + + will expand to + + \quotation + \raw HTML + <p>Contents:</p> + + <ul> + <li><a href="#Basic Qt">Basic Qt</a></li> + <ul> + <li><a href="#Getting Started">Getting Started</a></li> + <ul> + <li><a href="#Hello Qt">Hello Qt</a></li> + <li><a href="#Making Connections"> + Making Connections</a></li> + <li><a href="#Using the Reference Documentation"> + Using the Reference Documentation</a></li> + </ul> + <li><a href="#Creating Dialogs">Creating Dialogs</a></li> + <ul> + <li><a href="#Subclassing QDialog"> + Subclassing QDialog</a></li> + </ul> + </ul> + <li><a href="#Intermediate Qt">Intermediate Qt</a></li> + <ul> + <li><a href="#Layout Management"> + Layout Management</a></li> + <ul> + <li><a href="#Basic Layouts">Basic Layouts</a></li> + </ul> + </ul> + </ul> + + ... + \endraw + \endquotation + + \row + \o \bold \\chapter \target chapter + \o \bold {The \\chapter command is intended for use in + larger documents, and divides the document into chapters.} + + See \l{part}{\\part} for an explanation of the various + section units, command argument and rendering. + + \row + \o \bold \\section1 \target sectionOne + \o \bold {The \\section1 command starts a new section.} + + See \l{part}{\\part} for an explanation of the various + section units, command argument and rendering. + \row + \o \bold \\section2 \target sectionTwo + \o \bold {The \\section2 command starts a new section.} + + See \l{part}{\\part} for an explanation of the various + section units, command argument and rendering. + + \row + \o \bold \\section3 \target sectionThree + \o \bold {The \\section3 command starts a new section.} + + See \l{part}{\\part} for an explanation of the various + section units, command argument and rendering. + + \row + \o \bold \\section4 \target sectionFour + \o \bold {The \\section4 command starts a new section.} + + See \l{part}{\\part} for an explanation of the various + section units, command argument and rendering. + + \endtable +*/ + +/*! + \page 06-qdoc-commands-verbatimcode.html + \previouspage Document Structuring Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Quoting External Code Commands + + \title Verbatim Code Commands + + The following commands are used to render verbatim code within the + documentation. The code is rendered on a new line, using a + typewriter font and the standard indentation. + + \bold{Note:} Although all of these commands can be used to present + C++ code, the \l{07-0-qdoc-commands-quoting.html#snippet}{\\snippet} + and \l{07-0-qdoc-commands-quoting.html#codeline}{\\codeline} commands + should be used in preference to + the others when presenting valid code. This allows auxilliary tools + for Qt language bindings to substitute the relevant code snippets in + place of the C++ ones. + + \section1 Alphabetical List + + \l {06-qdoc-commands-verbatimcode.html#badcode}{\\badcode}, + \l {06-qdoc-commands-verbatimcode.html#code}{\\code}, + \l {06-qdoc-commands-verbatimcode.html#newcode}{\\newcode}, + \l {06-qdoc-commands-verbatimcode.html#oldcode}{\\oldcode} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\code \target code + \o \bold {The \\code command and the corresponding + \\endcode command delimit a piece of verbatim code.} + + Whereas the \l {c}{\\c} command can be used for short code + fragments within a sentence, the \\code command is for + longer code snippets and renders the code verbatim in a + separate paragraph using a typewriter font and the standard + indentation. + + When processing any of the \\code, \l {badcode}{\\badcode}, + \l {newcode}{\\newcode} and \l {oldcode}{\\oldcode} + commands, QDoc basically removes all indentation that is + common for the verbatim code blocks within a \c{/}\c{*!} ... + \c{*}\c{/} comment before it adds the standard + indentation. For that reason the recommended style is to + use 8 spaces for the verbatim code contained within these + commands (note that this doesn't apply to externally + quoted code using the \l {quotefromfile}{\\quotefromfile} + or \l {quotefile}{\\quotefile} command). + + For example: + + \code + / *! + \code + #include <QApplication> + #include <QPushButton> + + int main(int argc, char *argv[]) + { + ... + } + \ endcode + * / + \endcode + + will be rendered as + + \code + #include <QApplication> + #include <QPushButton> + + int main(int argc, char *argv[]) + { + ... + } + \endcode + + Other QDoc commands are disabled within + \\code... \\endcode, and the special character '\\' is + accepted and rendered like the rest of the code. + + You need to type the code manually between the \\code and + \\endcode commands. If you want to include code snippets + from a particular file, use the \l + {07-0-qdoc-commands-quoting.html#quotefromfile}{\\quotefromfile} + command instead. + + See also \l {c}{\\c}, \l + {07-0-qdoc-commands-quoting.html#quotefromfile}{\\quotefromfile}, + \l {badcode}{\\badcode}, \l {newcode}{\\newcode} and \l + {oldcode}{\\oldcode}. + + \row + \o \bold \\badcode \target badcode + \o \bold {The \\badcode command and the corresponding + \\endcode command delimit a piece of code that doesn't + compile or is wrong for some other reason.} + + The \\badcode command is similar the \l {code}{\\code} + command, but renders the code using a grey font instead of + black (the default). + + Like the \l {code}{\\code} command, it renders its code on + a new line in the documentation using a typewriter font and + the standard indentation. For example: + + \code + / *! + The statement below is rendered using the + regular \\code command: + + \code + statusbar()->message(tr("Host %1 found").arg(hostName)); + \ endcode + + While the following statement is rendered using + the \\badcode command: + + \badcode + statusbar()->message(tr("Host" + hostName + " found")); + \ endcode + * / + \endcode + + will be rendered as + + \quotation + The statement below is rendered using the + regular \\code command: + + \code + statusbar()->message(tr("Host %1 found").arg(hostName)); + \endcode + + While the following statement is rendered using + the \\badcode command: + + \badcode + statusbar()->message(tr("Host" + hostName + " found")); + \endcode + \endquotation + + Other QDoc commands are disabled within + \\badcode... \\endcode, and the special character '\\' is + accepted and rendered like the rest of the code. + + See also \l {code}{\\code}, \l {newcode}{\\newcode} and \l + {oldcode}{\\oldcode}. + + \row + \o \bold \\newcode \target newcode + \o \bold {The \\newcode command, and the associated \\oldcode + and \\endcode commands, indicate how to port a piece of + code to a new version of an API.} + + The \\newcode command, and its companion the \\oldcode + command, is a convenience combination of the \l + {code}{\\code} and \l {badcode}{\\badcode} commands: The + combination provides a text relating the two code snippets + to each other. The command requires a preceding \\oldcode + statement. + + Like the \l {code}{\\code} and \l {badcode}{\\badcode} + commands, the \\newcode command renders its code on a new + line in the documentation using a typewriter font and the + standard indentation. For example: + + \code + / *! + \oldcode + if (printer->setup(parent)) + ... + \newcode + QPrintDialog dialog(printer, parent); + if (dialog.exec()) + ... + \ endcode + * / + \endcode + + is rendered like this: + + \quotation + \oldcode + if (printer->setup(parent)) + ... + \newcode + QPrintDialog dialog(printer, parent); + if (dialog.exec()) + ... + \endcode + \endquotation + + Other QDoc commands are disabled within + \\oldcode ... \\endcode, and the '\\' character doesn't need + to be escaped. + + \row + \o \bold \\oldcode \target oldcode + \o \bold {The \\oldcode command requires a corresponding + \\newcode statement; otherwise QDoc fails to parse the command + and emits a warning.} + + See also \l {newcode}{\\newcode} and \l {badcode}{\\badcode}. + \endtable +*/ + +/*! + \page 07-0-qdoc-commands-quoting.html + \previouspage Verbatim Code Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Linking Commands + + \title Quoting External Code Commands + + The following commands enable quoting from files in the + documentation: You can make QDoc include the complete contents of + a file, or you can quote specific parts of the file and skip + others. The typical use of the latter is to quote a file chunk by + chunk. + + \bold{Note:} Although all of these commands can be used to present + C++ code, the \l{#snippet}{\\snippet} and \l{#codeline}{\\codeline} + commands should be used in preference to + the others when presenting valid code. This allows auxilliary tools + for Qt language bindings to substitute the relevant code snippets in + place of the C++ ones. + + \section1 Alphabetical List + + \l {07-0-qdoc-commands-quoting.html#codeline}{\\codeline}, + \l {07-0-qdoc-commands-quoting.html#dots}{\\dots}, + \l {07-0-qdoc-commands-quoting.html#printline}{\\printline}, + \l {07-0-qdoc-commands-quoting.html#printto}{\\printto}, + \l {07-0-qdoc-commands-quoting.html#printuntil}{\\printuntil}, + \l {07-0-qdoc-commands-quoting.html#quotefile}{\\quotefile}, + \l {07-0-qdoc-commands-quoting.html#quotefromfile}{\\quotefromfile}, + \l {07-0-qdoc-commands-quoting.html#skipline}{\\skipline}, + \l {07-0-qdoc-commands-quoting.html#skipto}{\\skipto}, + \l {07-0-qdoc-commands-quoting.html#skipuntil}{\\skipuntil}, + \l {07-0-qdoc-commands-quoting.html#snippet}{\\snippet} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\quotefile \target quotefile + \o \bold {The \\quotefile command expands to the complete + contents of the file given as argument.} + + The command considers the rest of the line as part of its + argument, make sure to follow the file name with a line + break. + + The file's contents is rendered in a separate paragraph, + using a typewriter font and the standard indentation. The + code is shown verbatim. + + For example: + + \code + / *! + This is a simple "Hello world" example: + + \quotefile examples/main.cpp + + It contains only the bare minimum you need + to get a Qt application up and running. + * / + \endcode + + will be rendered as + + \quotation + This is a simple "Hello world" example: + + \quotefile examples/main.cpp + + It contains only the bare minimum you need to get a Qt + application up and running. + \endquotation + + \warning If you use the \l {QDoc + Compatibility}{compat.qdocconf} file this command is called + \\include. + + See also \l {quotefromfile}{\\quotefromfile} and \l + {code}{\\code}. + + \row + \o \bold \\quotefromfile \target quotefromfile + \o \bold {The \\quotefromfile command opens the file + given as argument for quoting.} + + The command considers the rest of the line as part of its + argument, make sure to follow the file name with a line + break. + + The command is intended for use when quoting parts from + file with the walkthrough commands: \l + {printline}{\\printline}, \l {printto}{\\printto}, \l + {printuntil}{\\printuntil}, \l {skipline}{\\skipline}, \l + {skipto}{\\skipto}, \l {skipuntil}{\\skipuntil}. This + enables you to quote specific portions of a file. For + example: + + \code + / *! + The whole application is contained within + the \c main() function: + + \quotefromfile examples/main.cpp + + \skipto main + \printuntil app(argc, argv) + + First we create a QApplication object using + the \c argc and \c argv parameters. + + \skipto QPushButton + \printuntil resize + + Then we create a QPushButton, and give it a reasonable + size using the QWidget::resize() function. + + ... + * / + \endcode + + will be rendered as + + \quotation + The whole application is contained within + the \c main() function: + + \quotefromfile examples/main.cpp + + \skipto main + \printuntil app(argc, argv) + + First we create a QApplication object using the \c argc + and \c argv parameters. + + \skipto QPushButton + \printuntil resize + + Then we create a QPushButton, and give it a reasonable + size using the QWidget::resize() function. + + ... + \endquotation + + (\l {Example File}{The complete example file...}) + + QDoc remembers which file it's quoting, and the current + position within that file (see \l {file}{\\printline} for + more information). There is no need to "close" the file. + + Earlier we called this command \\quotefile. For more + information, see the \l + {26-qdoc-commands-compatibility.html#quotefromfile-versus-quotefile} + {compatibility} section. + + See also \l {quotefile}{\\quotefile}, \l {code}{\\code} and + \l {dots}{\\dots}. + + \row + \o \bold \\printline \target printline + \o \bold {The \\printline command expands to the line + from the current position to the next non-blank line of + the current souce file.} + + To ensure that the documentation always is synchronized + with the source file, a substring of the line must be + specified as an argument to the command. Note that the + command considers the rest of the line as part of its + argument, make sure to follow the substring with a line + break. + + The line from the source file is rendered as a separate + paragraph, using a typewriter font and the standard + indentation. The code is shown verbatim. + + For example: + + \code + / *! + There has to be exactly one QApplication object + in every GUI application that uses Qt. + + \quotefromfile examples/main.cpp + + \printline QApplication + + This line includes the QApplication class + definition. QApplication manages various + application-wide resources, such as the + default font and cursor. + + \printline QPushButton + + This line includes the QPushButton class + definition. The QPushButton widget provides a command + button. + + \printline main + + The main function... + * / + \endcode + + will be rendered as + + \quotation + There has to be exactly one QApplication object + in every GUI application that uses Qt. + + \quotefromfile examples/main.cpp + + \skipto QApplication + \printline QApplication + + This line includes the QApplication class + definition. QApplication manages various + application-wide resources, such as the + default font and cursor. + + \printline QPushButton + + This line includes the QPushButton class + definition. The QPushButton widget provides a command + button. + + \printline main + + The main function... + \endquotation + + (\l {Example File}{The complete example file...}) + + \target file + + QDoc reads the file sequentially. To move the current + position forward you can use either of the \l + {skipline}{\\skip...} commands. To move the current + position backward, you can use the \l + {quotefromfile}{\\quotefromfile} command again. + + \target substring + + If the substring argument is surrounded by slashes it is + interpreted as a \l {regular expression}. + + For example: + + \code + / *! + \quotefromfile widgets/scribble/mainwindow.cpp + + \skipto closeEvent + \printuntil /^\}/ + + Close events are sent to widgets that the users want to + close, usually by clicking \c File|Exit or by clicking + the \c X title bar button. By reimplementing the event + handler, we can intercept attempts to close the + application. + * / + \endcode + + will be rendered as + + \quotation + \quotefromfile widgets/scribble/mainwindow.cpp + + \skipto closeEvent + \printuntil /^\}/ + + Close events are sent to widgets that the users want to + close, usually by clicking \c File|Exit or by clicking + the \c X title bar button. By reimplementing the event + handler, we can intercept attempts to close the + application. + \endquotation + + (\l {widgets/scribble}{The complete example file...}) + + The regular expression \c /^\}/ makes QDoc print until the + first '}' character occurring at the beginning of the line + without indentation. /.../ encloses the regular expression, + and '^' means the beginning of the line. The '}' character + must be escaped since it is a special character in regular + expressions. + + QDoc will emit a warning if the specified substring or + regular expression cannot be located, i.e. if the source + code has changed. + + See also \l {printto}{\\printto} and \l + {printuntil}{\\printuntil}. + + \row + \o \bold \\printto \target printto + \o \bold {The \\printto command expands to all the lines + from the current position up to and \i excluding the + next line containing a given substring.} + + The command considers the rest of the line as part of its + argument, make sure to follow the substring with a line + break. The command also follows the same conventions for \l + {file}{positioning} and \l {substring}{argument} as the \l + {printline}{\\printline} command. + + The lines from the source file are rendered in a separate + paragraph, using a typewriter font and the standard + indentation. The code is shown verbatim. + + For example: + + \code + / *! + The whole application is contained within the + \c main() function: + + \quotefromfile examples/main.cpp + \printto hello + + First we create a QApplication object using the \c argc and + \c argv parameters... + * / + \endcode + + will be rendered as + + \quotation + The whole application is contained within the + \c main() function: + + \quotefromfile examples/main.cpp + \skipto main + \printto hello + + First we create a QApplication object using the \c argc + and \c argv parameters... + \endquotation + + (\l {Example File}{The complete example file...}) + + See also \l {printline}{\\printline} and \l + {printuntil}{\\printuntil}. + + \row + \o \bold \\printuntil \target printuntil + \o \bold {The \\printuntil command expands to all the lines + from the current position up to and \i including the next line + containing a given substring.} + + The command considers the rest of the line as part of its + argument, make sure to follow the substring with a line + break. The command also follows the same conventions for \l + {file}{positioning} and \l {substring}{argument} as the \l + {printline}{\\printline} command. + + The lines from the source file are rendered in a separate + paragraph, using a typewriter font and the standard + indentation. The code is shown verbatim. + + For example: + + \code + / *! + The whole application is contained within the + \c main() function: + + \quotefromfile examples/main.cpp + \skipto main + \printuntil hello + + First we create a QApplication object using the + \c argc and \c argv parameters, then we create + a QPushButton. + * / + \endcode + + will be rendered as + + \quotation + The whole application is contained within the + \c main() function: + + \quotefromfile examples/main.cpp + \skipto main + \printuntil hello + + First we create a \l + {http://qt.nokia.com/doc/4.0/qapplication}{QApplication} + object using the \c argc and \c argv parameters, then we + create a \l + {http://qt.nokia.com/doc/4.0/qpushbutton}{QPushButton}. + \endquotation + + (\l {Example File}{The complete example file...}) + + See also \l {printline}{\\printline} and \l + {printto}{\\printto}. + + \row + \o \bold \\skipline \target skipline + \o \bold {The \\skipline command ignores the next non-blank + line in the current source file.} + + Doc reads the file sequentially, and the \\skipline command + is used to move the current position (omitting a line of + the source file). See the remark about \l {file}{file + positioning} above. + + The command considers the rest of the line as part of its + argument, make sure to follow the substring with a line + break. The command also follows the same conventions for \l + {substring}{argument} as the \l {printline}{\\printline} + command, and it is used in conjunction with the \l + {quotefromfile}{\\quotefromfile} command. For example: + + \code + / *! + QPushButton is a GUI push button that the user + can press and release. + + \quotefromfile examples/main.cpp + \skipline QApplication + \printline QPushButton + + This line includes the QPushButton class + definition. For each class that is part of the + public Qt API, there exists a header file of + the same name that contains its definition. + * / + \endcode + + will be rendered as + + \quotation + \l + QPushButton is a GUI push button that the user + can press and release. + + \quotefromfile examples/main.cpp + \skipto QApplication + \skipline QApplication + \printline QPushButton + + This line includes the QPushButton class + definition. For each class that is part of the public + Qt API, there exists a header file of the same name + that contains its definition. + \endquotation + + (\l {Example File}{The complete example file...}) + + See also \l {skipto}{\\skipto}, \l + {skipuntil}{\\skipuntil} and \l {dots}{\\dots}. + + \row + \o \bold \\skipto \target skipto + \o \bold {The \\skipto command ignores all the lines from the + current position up to and \i excluding the next line + containing a given substring.} + + QDoc reads the file sequentially, and the \\skipto command + is used to move the current position (omitting one or + several lines of the source file). See the remark about \l + {file}{file positioning} above. + + The command considers the rest of the line as part of its + argument, make sure to follow the substring with a line + break. + + The command also follows the same conventions for \l + {substring}{argument} as the \l {printline}{\\printline} + command, and it is used in conjunction with the \l + {quotefromfile}{\\quotefromfile} command. For example: + + \code + / *! + The whole application is contained within + the \c main() function: + + \quotefromfile examples/main.cpp + \skipto main + \printuntil } + + First we create a QApplication object. There + has to be exactly one such object in + every GUI application that uses Qt. Then + we create a QPushButton, resize it to a reasonable + size... + * / + \endcode + + will be rendered as + + \quotation + The whole application is contained within + the \c main() function: + + \quotefromfile examples/main.cpp + \skipto main + \printuntil } + + First we create a QApplication object. There has to be + exactly one such object in every GUI application that + uses Qt. Then we create a QPushButton, resize it to a + reasonable size ... + \endquotation + + (\l {Example File}{The complete example file...}) + + See also \l {skipline}{\\skipline}, \l + {skipuntil}{\\skipuntil} and \l {dots}{\\dots}. + + \row + \o \bold \\skipuntil \target skipuntil + \o \bold {The \\skipuntil command ignores all the lines from + the current position up to and \i including the next line + containing a given substring.} + + QDoc reads the file sequentially, and the \\skipuntil + command is used to move the current position (omitting one + or several lines of the source file). See the remark about + \l {file}{file positioning} above. + + The command considers the rest of the line as part of its + argument, make sure to follow the substring with a line + break. + + The command also follows the same conventions for \l + {substring}{argument} as the \l {printline}{\\printline} + command, and it is used in conjunction with the \l + {quotefromfile}{\\quotefromfile} command. For example: + + \code + / *! + The first thing we did in the \c main() function + was to create a QApplication object \c app. + + \quotefromfile examples/main.cpp + \skipuntil show + \dots + \printuntil } + + In the end we must remember to make \c main() pass the + control to Qt. QCoreApplication::exec() will return when + the application exits... + * / + \endcode + + will be rendered as + + \quotation + The first thing we did in the \c main() function was to + create a QApplication object \c app. + + \quotefromfile examples/main.cpp + \skipuntil show + \dots + \printuntil } + + In the end we must remember to make \c main() pass the + control to Qt. QCoreApplication::exec() + will return when the application exits... + \endquotation + + (\l {Example File}{The complete example file...}) + + See also \l {skipline}{\\skipline}, \l {skipto}{\\skipto} + and \l {dots}{\\dots}. + + \row + \o \bold \\dots \target dots + \o \bold {The \\dots command indicates that parts of the + source file have been omitted when quoting a file.} + + The command is used in conjunction with the \l + {quotefromfile}{\\quotefromfile} command, and should be + stated on its own line. The dots are rendered on a new + line, using a typewriter font. For example: + + \code + / *! + \quotefromfile examples/main.cpp + \skipto main + \printuntil { + \dots + \skipuntil exec + \printline } + * / + \endcode + + will be rendered as + + \quotefromfile examples/main.cpp + \skipto main + \printuntil { + \dots + \skipuntil exec + \printline } + + (\l {Example File}{The complete example file...}) + + The default indentation is 4 spaces, but this can be + adjusted using the command's optional argument. For + example: + + \code + / *! + \dots 0 + \dots + \dots 8 + \dots 12 + \dots 16 + * / + \endcode + + will be rendered as + + \dots 0 + \dots + \dots 8 + \dots 12 + \dots 16 + + See also \l {skipline}{\\skipline}, \l + {skipto}{\\skipto} and \l {skipuntil}{\\skipuntil}. + + \row + \o \bold \\snippet \target snippet + \o \bold {The \\snippet command causes a code snippet to be included + verbatim as preformatted text, which may be syntax highlighted.} + + Each code snippet are referenced by the file that holds it and by + a unique identifier for that file. Snippet files are typically + stored in a \c{snippets} directory inside the documentation + directory (e.g., \c{$QTDIR/doc/src/snippets}). + + For example, the following documentation references a snippet in + a file residing in a subdirectory of the documentation directory: + + \code + \snippet snippets/textdocument-resources/main.cpp Adding a resource + \endcode + + The text following the file name is the unique identifier for the + snippet. This is used to delimit the quoted code in the relevant + snippet file as shown in the following example that corresponds to + the above \c{\\snippet} command: + + \dots + \code + QImage image(64, 64, QImage::Format_RGB32); + image.fill(qRgb(255, 160, 128)); + + //! [Adding a resource] + document->addResource(QTextDocument::ImageResource, + QUrl("mydata://image.png"), QVariant(image)); + //! [Adding a resource] + \endcode + \dots + \row + \o \bold \\codeline \target codeline + \o \bold{The \\codeline command inserts a blank line of preformatted + text. It is used to insert gaps between snippets without closing + the current preformatted text area and opening a new one.} + \endtable +*/ + +/*! + \page 07-1-example.html + \previouspage Quoting External Code Commands + \contentspage QDoc Manual - Table of Contents + + \title Example File + + \quotefile examples/main.cpp +*/ + +/*! + \page 08-qdoc-commands-linking.html + \previouspage Quoting External Code Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Graphic Commands + + \title Linking Commands + + The linking commands make it possible to create hyperlinks to + classes, functions, header files and examples. They also make it + possible to link to targets within a document, as well as to other + documents and URLs. + + \section1 Alphabetical List + + \l {08-qdoc-commands-linking.html#keyword}{\\keyword}, + \l {08-qdoc-commands-linking.html#l}{\\l}, + \l {08-qdoc-commands-linking.html#sa}{\\sa}, + \l {08-qdoc-commands-linking.html#target}{\\target} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\l \target l + \o \bold {The \\l command is used to create hyperlinks. } + + The command's general syntax is + + \code + \l {link target}{link text} + \endcode + + For example: + + \code + / *! + Read the \l {http://qt.nokia.com/doc/4.0/} + {Qt's Reference Documentation} carefully. + * / + \endcode + + will be rendered as + + \quotation + Read the \l {http://qt.nokia.com/doc/4.0/} + {Qt's Reference Documentation} carefully. + \endquotation + + If the link target is equivalent to the link text, the + second argument can be omitted. + + For example, if you have documentation like: + + \code + / *! + \target assertions + + Assertions make some statement about the text at the + point where they occur in the regexp but they do not + match any characters. + + ... + + Regexps are built up from expressions, quantifiers, and + \l {assertions}{assertions}. + * / + \endcode + + you can rewrite it as + + \code + / *! + \target assertions + + Assertions make some statement about the text at the + point where they occur in the regexp but they do not + match any characters. + + ... + + Regexps are built up from expressions, quantifiers, and + \l assertions. + * / + \endcode + + For the one-parameter version the braces can often + be omitted. See the \l {i}{\\i} command for the \l + {argument}{argument conventions}. + + The \\l command supports several kinds of links: + + \list + \o \c {\l QWidget} - a defined \l {class}{\\class} + \o \c {\l QWidget::sizeHint()} - a defined member + function (\l {fn}{\\fn}) + \o \c {\l <QtGlobal>} - a defined \l {headerfile}{\\headerfile} + \o \c {\l widgets/wiggly} - a defined + \l {example-command}{\\example} + \o \c {\l {QWidget Class Reference}} - a defined \l {title}{\\title} + \o \c {\l {Introduction}}- a defined \l{part}{\\part}, + \l{chapter}{\\chapter} or \l {sectionOne}{\\section...} + \o \c {\l fontmatching} - a defined \l {target}{\\target} + \o \c {\l {Shared Classes}} - a defined \l {keyword}{\\keyword} + \o \c {\l network.html} - a defined \l {page}{\\page} + \o \c {\l http://www.trolltech.com/} - a URL + \endlist + + QDoc also tries to make a link out of any words that don't + resemble any normal English words, for example Qt class + names or functions, like QWidget or QWidget::sizeHint(). In + these cases, the \\l command can actually be omitted, but + by using the command, you ensure that QDoc will emit a + warning if it cannot find the link target. In addition, if + you only want the function name to appear in the link, you + can use the following syntax: + + \list + \o \c {\l {QWidget::}{sizeHint()}} + \endlist + + See also \l {sa}{\\sa}, \l {target}{\\target} and \l + {keyword}{\\keyword}. + + \row + \o \bold \\sa \target sa + \o \bold {The \\sa command defines a list of links that will + be rendered in a separate "See also" section at the bottom + of the documentation.} + + The command takes a comma-separated list of links as its + argument. If the line ends with a comma, you can continue + on a second line. The general syntax is: + + \code + \sa {the first link}, {the second link}, + {the third link}, ... + \endcode + + QDoc will automatically try to generate "See also" links + interconnecting a property's various functions. For + example, an setVisible() function will automatically get a + link to visible() and vice versa. + + In general, QDoc will generate "See also" links that + interconnect the functions that access the same + property. It recognizes four different syntax versions: + + \list + \o \c property() + \o \c setProperty() + \o \c isProperty() + \o \c hasProperty() + \endlist + + The \\sa command supports the same kind + of links as the \l {l}{\\l} command. For example: + + \code + / *! + Appends the actions \a actions to this widget's + list of actions. + + \sa removeAction(), QMenu, addAction() + * / + void QWidget::addActions(QList<QAction *> actions) + { + ... + } + \endcode + + will be rendered as + + \quotation + \bold {void QWidget::addActions ( QList<QAction*> + \i actions )} + + Appends the actions \i actions to this widget's + list of actions. + + See also \l {QWidget::removeAction()}{removeAction()}, + \l QMenu, and \l {QWidget::addAction()}{addAction()}. + \endquotation + + See also \l {l}{\\l}, \l {target}{\\target} and \l + {keyword}{\\keyword}. + + \row + \o \bold \\target \target target + \o \bold {The \\target command defines an explicit point in the + documentation that you can later link to using the \l {l}{\\l} + and \l {sa}{\\sa} commands.} + + The command considers the rest of the line as part of its + argument, make sure to follow the target name with a line + break. + + For example: + + \code + / *! + \target capturing parentheses + \section1 Capturing Text + + Parentheses allow us to group elements together so that + we can quantify and capture them. + + ... + * / + \endcode + + can be referenced with + + \list + \o \c {\l {capturing parentheses}} + (from elsewhere in the same comment) + \o \c {\l qregexp.html#capturing-parentheses} + (from anywhere else) + \endlist + + within a documentation unit, and with + + \list + \o \c {\l http://www.trolltech.com/4.0/doc/html/qregexp.html#capturing-parentheses} + \endlist + + on a more global scale. + + If the target name does't contain any spaces, the brackets can + be omitted as well. + + See also \l {l}{\\l}, \l {sa}{\\sa} and \l + {keyword}{\\keyword}. + + \row + \o \bold \\keyword \target keyword + \o \bold {The \\keyword command defines an explicit point in the + documentation that you can later link to using the \l {l}{\\l} + and \l {sa}{\\sa} commands.} + + Keywords must be unique within the entire set of + documentation processed in on QDoc run. The command + considers the rest of the line as part of its argument, + make sure to follow the keyword with a line break. + + The \\keyword command is similar to \l {target}{\\target}, + but stronger. A keyword can be referenced from anywhere + using a simple syntax. For example: + + \code + / *! + \class QRegExp + \reentrant + \brief The QRegExp class provides pattern + matching using regular expressions. + \ingroup tools + \ingroup misc + \ingroup shared + \mainclass + + \keyword regular expression + + Regular expressions, or "regexps", provide a way to + find patterns within text. + + ... + * / + \endcode + + can be referenced like this + + \code + / *! + When a string is surrounded by slashes, it's + interpreted as a \l regular expression. + * / + \endcode + + which will be rendered as + + \quotation + When a string is surrounded by slashes, it's + interpreted as a \l {regular expression}. + \endquotation + + If the keyword does't contain any spaces, the brackets can + be omitted as well. + + See also \l {l}{\\l}, \l {sa}{\\sa} and \l + {target}{\\target}. + \endtable +*/ + +/*! + \page 09-qdoc-commands-graphic.html + \previouspage Linking Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Container Commands + + \title Graphic Commands + + The graphic commands makes it possible to include images in the + documentation. The images can be rendered as separate paragraphs, + or within running text. + + \section1 Alphabetical List + + \l {09-qdoc-commands-graphic.html#caption}{\\caption}, + \l {09-qdoc-commands-graphic.html#image}{\\image}, + \l {09-qdoc-commands-graphic.html#inlineimage}{\\inlineimage} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\image \target image + \o \bold {The \\image command expands to the image specified by its + argument, and renders it centered as a separate paragraph.} + + The \\image command replaces the old \\img command. For more + information, see the \l + {26-qdoc-commands-compatibility.html#image-versus-img} + {compatibility} section. + + The command takes two arguments. The first is the name of + the image file. The second argument is optional and is a + simple description of the image equivalent to the HTML + alt="" in an image tag. The description is used for + tooltips, and when a browser doesn't support images like + the Lynx text browser. + + The command considers the rest of the line after the file + name its second argument, make sure that you follow the + filename or description with a line break. Braces are only + necessary if the description spans several lines. + + For example: + + \code + / *! + Qt by Trolltech is a C++ toolkit for cross-platform GUI + application development. + + \image happyguy.jpg "Happy guy" + + Qt provides single-source portability across Microsoft + Windows, Mac OS X, Linux, and all major commercial Unix + variants. It is also available for embedded devices. + * / + \endcode + + will be rendered as + + \quotation + Qt by Trolltech is a C++ toolkit for cross-platform GUI + application development. + + \image happyguy.jpg image "Happy guy" + + Qt provides single-source portability across Microsoft + Windows, Mac OS X, Linux, and all major commercial Unix + variants. It is also available for embedded devices. + \endquotation + + See also \l {inlineimage}{\\inlineimage} and \l + {caption}{\\caption}. + + \row + \o \bold \\inlineimage \target inlineimage + \o \bold {The \\inlineimage command expands to the image + specified by its argument; the image is rendered inline + with the rest of the text.} + + The command takes two arguments. The first is the name of + the image file. The second argument is optional and is a + simple description of the image equivalent to the HTML + alt="" in an image tag. The description is used for + tooltips, and when a browser doesn't support images like + the Lynx text browser. + + The most common use of the \\inlineimage command is in + lists and tables. For example: + + \code + / *! + \list 1 + \o \inlineimage happy.gif Oh so happy! + \o \inlineimage happy.gif Oh so happy! + \o \inlineimage happy.gif Oh so happy! + \endlist + * / + \endcode + + will be rendered as + + \list 1 + \o \inlineimage happy.gif Oh so happy! + \o \inlineimage happy.gif Oh so happy! + \o \inlineimage happy.gif Oh so happy! + \endlist + + And + + \code + / *! + \table + \header + \o Trolltech + \o Trolltech + \row + \o \inlineimage happy.gif Oh so happy! + \o \inlineimage happy.gif Oh so happy! + \row + \o \inlineimage happy.gif Oh so happy! + \o \inlineimage happy.gif Oh so happy! + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + <table align="center" cellpadding="2" + cellspacing="1" border="0"> + <tr valign="top" bgcolor="#a2c511"> + <th>Trolltech</th> + <th>Trolltech</th> + </tr> + + <tr valign="top" bgcolor="#f0f0f0"> + <td><img src="images/happy.gif" alt="Oh so happy!" /> + </td> + <td><img src="images/happy.gif" alt="Oh so happy!" /> + </td> + </tr> + + <tr valign="top" bgcolor="#f0f0f0"> + <td><img src="images/happy.gif" alt="Oh so happy!"/> + </td> + <td><img src="images/happy.gif" alt="Oh so happy!" /> + </td> + </tr> + + </table> + \endraw + + The command can also be used to insert an image + inline with the regular text. For example: + + \code + / *! + \inlineimage training.jpg Training by Trolltech + The Qt Programming course is offered as a + five day Open Enrollment Course. The classes + are open to the public.While the course is open + to anyone who wants to learn, attendees should + have significant experience in C++ development + to derive maximum benefit from the course. + * / + \endcode + + will be rendered as + + \quotation + \inlineimage training.jpg Training by Trolltech + The Qt Programming course is offered as a + five day Open Enrollment Course. The classes + are open to the public.While the course is open + to anyone who wants to learn, attendees should + have significant experience in C++ development + to derive maximum benefit from the course. + \endquotation + + See also \l {image}{\\image} and \l {caption}{\\caption}. + + \row + \o \bold \\caption \target caption + \o \bold {The \\caption command provides a caption for an image.} + + The command follows the same conventions for parentheses and use + of braces for its \l argument as the \l {i}{\\i} command. + + \warning This is preliminary functionality. The + command is not fully implemented. + + See also \l {image}{\\image} and \l + {inlineimage}{\\inlineimage} + + \endtable +*/ + +/*! + \page 10-qdoc-commands-container.html + \previouspage Graphic Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Document Contents Commands + + \title Container Commands + + The container commands create tables and lists with associated + items and contents. A list is rendered left aligned as a separate + paragraph. A table is rendered centered as a separate paragraph, + and its width depends on its content. + + \section1 Alphabetical List + + \l {10-qdoc-commands-container.html#header}{\\header}, + \l {10-qdoc-commands-container.html#list}{\\list}, + \l {10-qdoc-commands-container.html#o}{\\o}, + \l {10-qdoc-commands-container.html#omitvalue}{\\omitvalue}, + \l {10-qdoc-commands-container.html#row}{\\row}, + \l {10-qdoc-commands-container.html#table}{\\table}, + \l {10-qdoc-commands-container.html#value}{\\value} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\table \target table + \o \bold {The \\table command and the corresponding \\endtable + command delimit the contents of a table.} + + The command accepts a single argument specifying the + table's width in percentage: + + \code + / *! + \table 100 % + + ... + + \endtable + * / + \endcode + + The code above ensures that the table will fill all + available space. If the table's width is smaller than 100 %, + the table will be centered in the generated documentation. + + A table can contain headers, rows and columns. A row starts + with a \l {row}{\\row} command and consists of cells, which + starts with a \l {o}{\\o} command. There is also a \l + {header}{\\header} command which is a special kind of row + with a special formatting. For example: + + \code + / *! + \table + \header + \o Qt Core Feature + \o Brief Description + \row + \o \l {Signal and Slots} + \o Signals and slots are used for communication + between objects. + \row + \o \l {Layout Management} + \o The Qt layout system provides a simple + and powerful way of specifying the layout + of child widgets. + \row + \o \l {Drag and Drop} + \o Drag and drop provides a simple visual + mechanism which users can use to transfer + information between and within applications. + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + <table align="center" cellpadding="2" + cellspacing="1" border="0"> + <tr valign="top" bgcolor="#a2c511"> + <th>Qt Core Feature</th> + <th>Brief Description</th> + </tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td> + <a href="http://qt.nokia.com/doc/4.0/signalsandslots.html"> + Signals and Slots</a> + </td> + <td>Signals and slots are used for communication + between objects.</td> + </tr> + + <tr valign="top" bgcolor="#c0c0c0"> + <td> + <a href=http://qt.nokia.com/doc/4.0/layout.html"> + Layout Management</a></td> + <td>The Qt layout system provides a simple + and powerful way of specifying the layout + of child widgets.</td> + </tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td> + <a href=http://qt.nokia.com/doc/4.0/dnd.html"> + Drag and Drop</a></td> + <td>Drag and drop provides a simple visual + mechanism which users can use to transfer + information between and within applications.</td> + </tr> + + </table> + \endraw + + You can also make cells span several rows and columns. For + example: + + \code + / *! + \table + \header + \o {3,1} This header cell spans three columns + but only one row. + \row + \o {2, 1} This table cell spans two columns + but only one row + \o {1, 2} This table cell spans only one column, + but two rows. + \row + \o A regular table cell + \o A regular table cell + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + <table align="center" cellpadding="2" cellspacing="1" + border="0"> + + <tr valign="top" bgcolor="#a2c511"> + <th colspan="3" rowspan=" 1"> + This header cell spans three columns but only one row + </th> + </tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td colspan="2" rowspan=" 1"> + This table cell spans two columns but only one row + </td> + <td rowspan=" 2"> + This table cell spans only one column, but two rows. + </td> + </tr> + + <tr valign="top" bgcolor="#c0c0c0"> + <td>A regular table cell</td> + <td>A regular table cell</td> + </tr> + + </table> + \endraw + + See also \l {header}{\\header}, \l {row}{\\row} and \l {o}{\\o}. + + \row + \o \bold \\header \target header + \o \bold {The \\header command indicates that the following + table cells are the current table's column headers.} + + The command can only be used within the \l{table} + {\\table...\\endtable} commands. A header can contain + several cells. A cell is created with the \l {o}{\\o} + command. + + A header cell's text is centered within the table cell and + rendered using a bold font. For example: + + \code + / *! + \table + \header + \o Qt Core Feature + \o Brief Description + \row + \o \l {Signal and Slots} + \o Signals and slots are used for communication + between objects. + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + <table align="center" cellpadding="2" + cellspacing="1" border="0"> + <tr valign="top" bgcolor="#a2c511"> + <th>Qt Core Feature</th> + <th>Brief Description</th> + </tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td> + <a href="http://qt.nokia.com/doc/4.0/signalsandslots.html"> + Signals and Slots</a> + </td> + <td>Signals and slots are used for communication + between objects.</td> + </tr> + </table> + \endraw + + See also \l {table}{\\table}, \l {row}{\\row} and \l {o}{\\o}. + + \row + \o \bold \\row \target row + \o \bold {The \\row command indicates that the following table + cells belong to the same row in the current table.} + + The command can only be used within the \l{table} + {\\table...\\endtable} commands. A row can contain + several cells. A cell is created with the \l {o}{\\o} + command. + + The background cell color of each row alternate between two + shades of grey, making it easier to distinguish the rows + from each other. The cells' contents is left aligned. + + For example: + + \code + / *! + \table + \header + \o Qt Core Feature + \o Brief Description + \row + \o \l {Signal and Slots} + \o Signals and slots are used for communication + between objects. + \row + \o \l {Layout Management} + \o The Qt layout system provides a simple + and powerful way of specifying the layout + of child widgets. + \row + \o \l {Drag and Drop} + \o Drag and drop provides a simple visual + mechanism which users can use to transfer + information between and within applications. + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + <table align="center" cellpadding="2" + cellspacing="1" border="0"> + <tr valign="top" bgcolor="#a2c511"> + <th>Qt Core Feature</th> + <th>Brief Description</th> + </tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td> + <a href="http://qt.nokia.com/doc/4.0/signalsandslots.html"> + Signals and Slots</a> + </td> + <td>Signals and slots are used for communication + between objects.</td> + </tr> + + <tr valign="top" bgcolor="#c0c0c0"> + <td> + <a href=http://qt.nokia.com/doc/4.0/layout.html"> + Layout Management</a></td> + <td>The Qt layout system provides a simple + and powerful way of specifying the layout + of child widgets.</td> + </tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td> + <a href=http://qt.nokia.com/doc/4.0/dnd.html"> + Drag and Drop</a></td> + <td>Drag and drop provides a simple visual + mechanism which users can use to transfer + information between and within applications.</td> + </tr> + + </table> + \endraw + + See also \l {table}{\\table}, \l {header}{\\header} and \l + {o}{\\o}. + + \row + \o \bold \\value \target value + \o \bold {The \\value command starts the documentation of a C++ enum + item}. + + The command's first argument is the enum item. Then follows + its associated description. The description argument ends + at the next blank line or \\value. The arguments are + rendered within a table. + + The documentation will be located in the associated class, + header file or namespace documentation. See the \l + {enum}{\\enum} documentation for an example. + + See also \l {enum}{\\enum} and \l {omitvalue}{\\omitvalue}. + + \row + \o \bold \\omitvalue \target omitvalue + \o \bold {The \\omitvalue command excludes a C++ enum item + from the documentation}. + + The command's only argument is the name of the enum item + that will be omitted. See the \l {enum}{\\enum} + documentation for an example. + + See also \l {enum}{\\enum} and \l {value}{\\value}. + + \row + \o \bold \\list \target list + \o \bold {The \\list command and the corresponding \\endlist + command delimit a list of items.} + + You need to create each list item explicitly using the \l + {o}{\\o} command. A list can contain one or more items; it + can also be nested. For example: + + \code + / *! + \list + \o Qt Reference Documentation: Getting Started + \list + \o How to Learn Qt + \o Installation + \list + \o Qt/X11 + \o Qt/Windows + \o Qt/Mac + \o Qt/Embedded + \endlist + \o Tutorial and Examples + \endlist + \endlist + * / + \endcode + + will be rendered as + + \list + \o Qt Reference Documentation: Getting Started + \list + \o How to Learn Qt + \o Installation + \list + \o Qt/X11 + \o Qt/Windows + \o Qt/Mac + \o Qt/Embedded + \endlist + \o Tutorial and Examples + \endlist + \endlist + + The \\list command takes an optional argument providing + alternative appearances for the list items. For example: + + \code + / *! + \list + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + * / + \endcode + + will render the list items with bullets (the default): + + \list + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + + If you provide 'A' as an argument to the \\list command, + the bullets are replaced with characters following in + alphabetical order: + + \list A + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + + If you replace 'A' with '1', the list items are rendered + with numbers following in ascending order: + + \list 1 + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + + \endlist + + If you provide 'i' as the argument, the default bullets are + replaced with roman numerals: + + \list i + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + + Or finally, you can make the list items appear with roman + numbers following in ascending order if you provide 'I' as + the optional argument: + + \list I + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + + You can also make the listing start at any character or + number by simply provide the number or character you want + to start at. For example: + + \code + / *! + \list G + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + * / + \endcode + + will be rendered as + + \list G + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + + See also \l {o}{\\o}. + + \row + \o \bold \\o \target o + \o \bold {The \\o command announce a table or list item.} + + Earlier we used the \l {i}{\\i} command for this purpose. For more + information see the \l + {26-qdoc-commands-compatibility.html#o-versus-i}{compatibility} + section. + + The command can only be used within the \l{table} + {\\table...\\endtable} or \l{list}{\\list... \\endlist} + commands. + + It considers everything until the next occurrence + of the \\o command, or the currently applicable \l + {table}{\\endtable} or \l {list}{\\endlist} command, as its + argument. For examples, see \l {table}{\\table} and \l + {list}{\\list}. + + If the command is used within a table, you can in addition + specify how many rows or columns the item should span. For + example: + + \code + / *! + \table + \header + \o {3,1} This header cell spans three columns + but only one row. + \row + \o {2, 1} This table item spans two columns + but only one row + \o {1, 2} This table item spans only one column, + but two rows. + \row + \o A regular table item + \o A regular table item + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + <table align="center" cellpadding="2" cellspacing="1" + border="0"> + + <tr valign="top" bgcolor="#a2c511"> + <th colspan="3" rowspan=" 1"> + This header cell spans three columns but only one row + </th> + </tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td colspan="2" rowspan=" 1"> + This table item spans two columns but only one row + </td> + <td rowspan=" 2"> + This table item spans only one column, but two rows. + </td> + </tr> + + <tr valign="top" bgcolor="#c0c0c0"> + <td>A regular table item</td> + <td>A regular table item</td> + </tr> + + </table> + \endraw + + If not specified, the item will span one column and one row. + + See also \l {table}{\\table}, \l {header}{\\header}, + \l {list}{\\list} and \l {o}{\\o}. + \endtable +*/ + +/*! + \page 11-qdoc-commands-documentcontents.html + \previouspage Container Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Miscellaneous Commands + + \title Document Contents Commands + + The document contents commands identify parts of the documentation, + i.e. parts with a special rendering, conceptual meaning or + function. + + \section1 Alphabetical List + + \l {11-qdoc-commands-documentcontents.html#abstract}{\\abstract}, + \l {11-qdoc-commands-documentcontents.html#brief}{\\brief}, + \l {11-qdoc-commands-documentcontents.html#footnote}{\\footnote}, + \l {11-qdoc-commands-documentcontents.html#legalese}{\\legalese}, + \l {11-qdoc-commands-documentcontents.html#tableofcontents} + {\\tableofcontents}, + \l {11-qdoc-commands-documentcontents.html#quotation}{\\quotation}, + \l {11-qdoc-commands-documentcontents.html#warning}{\\warning} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\abstract \target abstract + \o \bold {The \\abstract command and the corresponding \\endabstract + command delimit a document's abstract section.} + + The abstract section is rendered as an indented italicized + paragraph. + + \warning This is preliminary funcionality. The + command is not fully implemented. Currently, the abstract + section is rendered as a regular HTML paragraph. For + example: + + \code + / *! + \abstract + Qt by Trolltech is a C++ toolkit for cross-platform + GUI application development. Qt provides + single-source portability across Microsoft Windows, + Mac OS X, Linux, and all major commercial Unix + variants. It is also available for embedded + devices. + \endabstract + * / + \endcode + + will be rendered as + + \abstract + Qt by Trolltech is a C++ toolkit for cross-platform GUI + application development. Qt provides single-source + portability across Microsoft Windows, Mac OS X, Linux, + and all major commercial Unix variants. It is also + available for embedded devices. + \endabstract + + \row + \o \bold \\quotation \target quotation + \o \bold { The \\quotation command and the corresponding + \\endquotation command delimit a quotation remark.} + + This command replaces the old \\quote command. For more + information see the \l + {26-qdoc-commands-compatibility.html#quotation-versus-quote} + {compatibility} section. + + The remark is rendered as a separate centered + paragraph. For example: + + \code + / *! + While the prospect of a significantly broader market is + good news for Firstlogic, the notion also posed some + challenges. Dave Dobson, director of technology for the La + Crosse, Wisconsin-based company, said: + + + \quotation + As our solutions were being adopted into new + environments, we saw an escalating need for easier + integration with a wider range of enterprise + applications. + \endquotation + * / + \endcode + + will be rendered as + + While the prospect of a significantly broader market is + good news for Firstlogic, the notion also posed some + challenges. Dave Dobson, director of technology for the La + Crosse, Wisconsin-based company, said: + + \quotation + As our solutions were being adopted into new + environments, we saw an escalating need for easier + integration with a wider range of enterprise + applications. + \endquotation + + \row + \o \bold \\footnote \target footnote + \o \bold {The \\footnote command and the corresponding + \\endfootnote command delimit a footnote.} + + The footnote follows the standard conventions, rendered at the + bottom of the page. + + \warning This is preliminary funcionality. The + command is not fully implemented. + + For example: + + \code + / *! + In Qt 4 we have tried to simplify the constructors of + QObject/QWidget subclasses. This makes subclassing + easier, at the same time as it helps make the Qt + library more efficient. + + \footnote + Constructors no longer take a "const char *name" + parameter. If you want to specify a name for a QObject, + you must call QObject::setObjectName() after + construction. The object name is now a QString. + \endfootnote + + QWidget's WFlags data type has been split in two: + Qt::WindowFlags specifies low-level window flags (the + type of window and the frame style), whereas + Qt::WidgetAttribute specifies various higher-level + attributes about the widget (e.g., + WA_StaticContents). + * / + \endcode + + will be rendered as + + \quotation + In Qt 4 we have tried to simplify the constructors of + QObject/QWidget subclasses. This makes subclassing + easier, at the same time as it helps make the Qt + library more efficient. + + \footnote + Constructors no longer take a "const char *name" + parameter. If you want to specify a name for a QObject, + you must call QObject::setObjectName() after + construction. The object name is now a QString. + \endfootnote + + QWidget's WFlags data type has been split in two: + Qt::WindowFlags specifies low-level window flags (the + type of window and the frame style), whereas + Qt::WidgetAttribute specifies various higher-level + attributes about the widget (e.g., + WA_StaticContents). + \endquotation + + \row + \o \bold \\tableofcontents \target tableofcontents + \o \bold {The \\tableofcontents command generates a + table displaying the titles of the current documentation + unit's parts, chapters, sections, etc.} + + The command accepts a single optional argument: + + \code + \tableofcontents sectionN + \endcode + + where \c sectionN is the deepest section to include (by + default all sections are included). + + For example, it the documentation unit's structure looks + something like this: + + \quotation + \raw HTML + <a name="Basic Qt"> + <h1>Basic Qt</h1> + </a> + <p>This is the first part.</p> + + <a name="Getting started"> + <h2>Getting Started</h2> + </a> + This is the first part's first chapter.</p> + + <a name="Hello Qt"> + <h3>Hello Qt</h3> + </a> + <p>This is the first chapter's first section.</p> + + <a name="Making Connections"> + <h3>Making Connections</h3> + </a> + <p>This is the first chapter's second section.</p> + + <a name="Using the Reference Documentation"> + <h3>Using the Reference Documentation</h3> + </a> + <p>This is the first chapter's third section.</p> + + <a name="Creating Dialogs"> + <h2>Creating Dialogs</h2> + </a> + <p>This is the first part's second chapter.</p> + + <a name="Subclassing QDialog"> + <h3>Subclassing QDialog</h3> + </a> + <p>This is the second chapter's first section.</p> + + ... + + <a name="Intermediate Qt"> + <h1>Intermediate Qt</h1> + </a> + <p>This is the second part.</p> + + <a name="Layout Management"> + <h2>Layout Management</h2> + </a> + <p>This is the second part's first chapter.</p> + + <a name="Basic Layouts"> + <h3>Basic Layouts</h3> + </a> + <p>This is the first chapter's first section.</p> + + ... + + \endraw + \endquotation + + Then + + \code + / *! + Contents: + + \tableofcontents + + ... + * / + \endcode + + will expand to + + \quotation + \raw HTML + <p>Contents:</p> + + <ul> + <li><a href="#Basic Qt">Basic Qt</a></li> + <ul> + <li><a href="#Getting Started">Getting Started</a></li> + <ul> + <li><a href="#Hello Qt">Hello Qt</a></li> + <li><a href="#Making Connections"> + Making Connections</a></li> + <li><a href="#Using the Reference Documentation"> + Using the Reference Documentation</a></li> + </ul> + <li><a href="#Creating Dialogs">Creating Dialogs</a></li> + <ul> + <li><a href="#Subclassing QDialog"> + Subclassing QDialog</a></li> + </ul> + </ul> + <li><a href="#Intermediate Qt">Intermediate Qt</a></li> + <ul> + <li><a href="#Layout Management">Layout Management</a></li> + <ul> + <li><a href="#Basic Layouts">Basic Layouts</a></li> + </ul> + </ul> + </ul> + + ... + \endraw + \endquotation + + Each table entry becomes a link to the corresponding part, + chapter or section. + + \row + \o \bold \\brief \target brief + \o \bold {The \\brief command introduces a one-sentence + description of a class, namespace, header file, property + or variable.} + + The brief text is used to introduce the documentation of + the associated object, and in lists generated using the \l + {generatelist}{\\generatelist} command. + + The \\brief command can be used in two significant + different ways: \l {brief class}{One for classes, + namespaces and header files}, and \l {brief property}{one + for properties and variables}. + + \target brief property + + When the \\brief command is used to describe a property or + a variable, the brief text must only be a sentence fragment + and start with "whether" (for boolean properties and + variables) or "the" (for any other property or variable). + + For example the boolean QWidget::isWindow property: + + \code + / *! + \property QWidget::isActiveWindow + \brief whether this widget's window is the active window + + The active window is the window that contains the widget that + has keyboard focus. + + When popup windows are visible, this property is true + for both the active window \e and for the popup. + + \sa activateWindow(), QApplication::activeWindow() + * / + \endcode + + and the QWidget::geometry property + + \code + / *! + \property QWidget::geometry + \brief the geometry of the widget relative to its parent and + excluding the window frame + + When changing the geometry, the widget, if visible, + receives a move event (moveEvent()) and/or a resize + event (resizeEvent()) immediately. + + ... + + \sa frameGeometry(), rect(), ... + * / + \endcode + + The latter will be rendered as + + \quotation + \raw HTML + <h3>geometry : + <a href="http://qt.nokia.com/doc/4.0/qrect.html">QRect</a> + </h3> + \endraw + + This property holds the geometry of the widget relative + to its parent and excluding the window frame. + + ... + + Access functions: + \list + \o \bold {const QRect & geometry () const} + \o \bold {void setGeometry ( int x, int y, int w, int h )} + \o \bold {void setGeometry ( const QRect & )} + \endlist + + See also \l + {QWidget::frameGeometry()}{frameGeometry()}, \l + {QWidget::rect()}{rect()}, ... + \endquotation + + \target brief class + + When the \\brief command is used to describe a class, the + brief text should be a complete sentence and must start + like this: + + \code + The <classname> class is|provides|contains|specifies... + \endcode + + and likewise when the command is used for namespaces or + header files. + + \warning The brief statement is used as the first + paragraph of the detailed description. Do not repeat the + sentence. + + For example: + + \code + / *! + \class PreviewWindow + \brief The PreviewWindow class is a custom widget + displaying the names of its currently set + window flags in a read-only text editor. + + The PreviewWindow class inherits QWidget. The widget + displays the names of its window flags set with the + setWindowFlags() function. It is also provided with a + QPushButton that closes the window. + + ... + + \sa QWidget + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h1>PreviewWindow Class Reference</h1> + \endraw + + The PreviewWindow class is a custom widget displaying + the names of its currently set window flags in a + read-only text editor. \l {preview window}{More...} + + \raw HTML + <h3>Properties</h3> + \endraw + + \list + \o 52 properties inherited from QWidget + \o 1 property inherited from QObject + \endlist + + \raw HTML + <h3>Public Functions</h3> + \endraw + + \list + \o \l {constructor}{PreviewWindow}(QWidget *parent = 0) + \o void \l {function}{setWindowFlags}(Qt::WindowFlags flags) + \endlist + + \list + \o 183 public functions inherited from QWidget + \o 28 public functions inherited from QObject + \endlist + + \raw HTML + <h3>Public Slots</h3> + \endraw + + \list + \o 17 public slots inherited from QWidget + \o 1 public slot inherited from QObject + \endlist + + \raw HTML + <h3>Additional Inherited Members</h3> + \endraw + + \list + \o 1 signal inherited from QWidget + \o 1 signal inherited from QObject + \o 4 static public members inherited from QWidget + \o 4 static public members inherited from QObject + \o 39 protected functions inherited from QWidget + \o 7 protected functions inherited from QObject + \endlist + + \target preview window + + \raw HTML + <hr /> + <h2>Detailed Description</h2> + \endraw + The PreviewWindow class is a custom widget displaying + the names of its currently set window flags in a + read-only text editor. + + The PreviewWindow class inherits QWidget. The widget + displays the names of its window flags set with the \l + {function}{setWindowFlags()} function. It is also + provided with a QPushButton that closes the window. + + ... + + See also QWidget. + + \raw HTML + <hr /> + <h2>Member Function Documentation</h2> + \endraw + + \target constructor + \raw HTML + <h3>PreviewWindow(QWidget *parent = 0)</h3> + \endraw + + Constructs a preview window widget with \i parent. + + \target function + \raw HTML + <h3>setWindowFlags(Qt::WindowFlags flags)</h3> + \endraw + + Sets the widgets flags using the + QWidget::setWindowFlags() function. + + Then runs through the available window flags, + creating a text that contains the names of the flags + that matches the flags parameter, displaying + the text in the widgets text editor. + \endquotation + + Using \\brief with a namespace can for example look like this: + + \code + / *! + \namespace Qt + + \brief The Qt namespace contains miscellaneous identifiers + used throughout the Qt library. + * / + \endcode + + and finally using \\brief with a header file can look + something like this: + + \code + / *! + \headerfile <QtGlobal> + \title Global Qt Declarations + + \brief The <QtGlobal> header file provides basic + declarations and is included by all other Qt headers. + + \sa <QtAlgorithms> + * / + \endcode + + See also \l{property}{\\property}, \l{class}{\\class}, + \l{namespace}{\\namespace} and \l{headerfile}{\\headerfile}. + + \row + \o \bold \\legalese \target legalese + \o \bold {The \\legalese command, and the corresponding \\endlegalese + command, delimit a licence agreement.} + + If the \\endlegalese command is omitted, QDoc will still + process the \\legalese command but considers the rest of + the documentation page as the license agreement. + + Ideally, the license documentation is located where the + licensed code is used. + + Later the documentation identified by the \\legalese + command can be accumulated into a list using the \l + {generatelist}{\\generatelist} command with the \c legalese + argument. This is useful to generate an overview of all the + licenses associated with the source code. + + For example: + + \code + \ * ! + ... + + On X11, Qt also supports drops via the Motif Drag \& + Drop Protocol. The implementation incorporates some + code that was originally written by Daniel Dardailler, + and adapted for Qt by Matt Koss \<koss@napri.sk\> and + Trolltech. Here is the original copyright notice: + + \legalese + \code + + Copyright 1996 Daniel Dardailler. + + Permission to use, copy, modify, distribute, and sell + this software for any purpose is hereby granted without + fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this + permission notice appear in supporting documentation, + and that the name of Daniel Dardailler not be used in + advertising or publicity pertaining to distribution of + the software without specific, written prior + permission. Daniel Dardailler makes no representations + about the suitability of this software for any + purpose. It is provided "as is" without express or + implied warranty. + + Modifications Copyright 1999 Matt Koss, under the same + license as above. + + \ endcode + \endlegalese + * / + \endcode + + will be rendered as + + \quotation + ... + + On X11, Qt also supports drops via the Motif Drag \& + Drop Protocol. The implementation incorporates some + code that was originally written by Daniel Dardailler, + and adapted for Qt by Matt Koss \<koss@napri.sk\> and + Trolltech. Here is the original copyright notice: + + \legalese + \code + + Copyright 1996 Daniel Dardailler. + + Permission to use, copy, modify, distribute, and sell + this software for any purpose is hereby granted without + fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this + permission notice appear in supporting documentation, + and that the name of Daniel Dardailler not be used in + advertising or publicity pertaining to distribution of + the software without specific, written prior + permission. Daniel Dardailler makes no representations + about the suitability of this software for any + purpose. It is provided "as is" without express or + implied warranty. + + Modifications Copyright 1999 Matt Koss, under the same + license as above. + + \endcode + \endlegalese + \endquotation + + \row + \o \bold \\warning \target warning + \o \bold {The \\warning command renders a "Warning:" prefix to + the command's argument.} + + For example: + + \code + / *! + Qt::HANDLE is a platform-specific handle type + for system objects. This is equivalent to + \c{void *} on Windows and Mac OS X, and to + \c{unsigned long} on X11. + + \warning Using this type is not portable. + * / + \endcode + + will be rendered as + + \quotation + Qt::HANDLE is a platform-specific handle type + for system objects. This is equivalent to + \c{void *} on Windows and Mac OS X, and to + \c{unsigned long} on X11. + + \warning Using this type is not portable. + \endquotation + \endtable +*/ + +/*! + \page 12-0-qdoc-commands-miscellaneous.html + \previouspage Document Contents Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Topical Commands + + \title Miscellaneous Commands + + These commands provide miscellaneous functions + connected to the visual appearance of the documentation, and to the + process of generating the documentation. + + \section1 Alphabetical List + + \l {12-0-qdoc-commands-miscellaneous.html#else}{\\else}, + \l {12-0-qdoc-commands-miscellaneous.html#endif}{\\endif}, + \l {12-0-qdoc-commands-miscellaneous.html#expire}{\\expire}, + \l {12-0-qdoc-commands-miscellaneous.html#generatelist}{\\generatelist}, + \l {12-0-qdoc-commands-miscellaneous.html#if}{\\if}, + \l {12-0-qdoc-commands-miscellaneous.html#include}{\\include}, + \l {12-0-qdoc-commands-miscellaneous.html#meta}{\\meta}, + \l {12-0-qdoc-commands-miscellaneous.html#omit}{\\omit}, + \l {12-0-qdoc-commands-miscellaneous.html#raw}{\\raw}, + \l {12-0-qdoc-commands-miscellaneous.html#raw}{\\unicode} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\expire \target expire + \o \bold {The \\expire command allows you to define an expiration + date for your documentation.} + + When using the \\expire command, QDoc will emit a warning + when the current date is larger than the specified + date. The command accepts one argument; the argument's + format is yyyy-mm-dd. For example: + + \code + / *! + \page porting.html + + \title Porting to Qt 3.x + + \expire 2004-12-31 + + This document describes porting applications from Qt + 2.x to Qt 3.x. + + The Qt 3.x series is not binary compatible with the + 2.x series. + ... + * / + \endcode + + If you run QDoc on 4 July 2005, it will emit the warning + + \quotation + porting.qdoc:6: Documentation expired 185 days ago + \endquotation + + \row + \o \bold \\generatelist \target generatelist + \o \bold {The \\generatelist command expands to a list of + various documentation or links to documentation.} + + For example in the Qt Reference Documentation: + + \code + / *! + \page classes.html + \title All Qt Classes (main index) + + For a shorter list that only includes the most + frequently used classes, see \l{Qt's Main Classes}. For + a list of Qt 3 support classes, see \l{Qt3Support + Classes}. + + \generatelist classes + * / + \endcode + + is used to generate \l {All Qt Classes (main index)}. + + The command accepts the following arguments: + + \target table example + + \list + \o \c annotatedclasses + + The \c annotatedclasses argument provides a table + containing the names of all the classes, and a + description of each class. Each class name is a link to + the class's reference documentation. + + For example: + + \quotation + \raw HTML + <table align="center" cellpadding="2" + cellspacing="1" border="0"> + + <tr valign="top" bgcolor="#d0d0d0"> + <td> + <a href="http://qt.nokia.com/doc/4.0/qdial.html"> + QDial</a> + </td> + <td>Rounded range control (like a speedometer + or potentiometer)</td> + </tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td> + <a href="http://qt.nokia.com/doc/4.0/qdialog.html"> + QDialog</a> + </td> + <td>The base class of dialog windows</td> + </tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td> + <a href="http://qt.nokia.com/doc/4.0/qdir.html"> + QDir</a> + </td> + <td>Access to directory structures and their + contents</td> + </tr> + </table> + \endraw + \endquotation + + A class is identified within the documentation by the + the \l {class}{\\class} command, and the descriptions + are based on the argument of the \l {brief}{\\brief} + commands in the class documentation. + + \target list example + + \o \c classes + + The \c classes argument provides a complete alphabetical + list of the classes. Each class name is a link to the + class's reference documentation. + + For example: + + \quotation + \raw HTML + <p><table width="100%"> + + <tr> + <td align="right"><b>A </b></td> + <td><a href="http://qt.nokia.com/doc/4.0/qabstractbutton.html">QAbstractButton</a></td> + + <td align="right"></td> + <td><a href="http://qt.nokia.com/doc/4.0/qabstractextensionmanager.html">QAbstractExtensionManager</a></td> + + <td align="right"></td> + <td><a href="http://qt.nokia.com/doc/4.0/qabstractitemmodel.html">QAbstractItemModel</a></td> + </tr> + + <tr> + <td align="right"></td> + <td><a href="http://qt.nokia.com/doc/4.0/qabstracteventdispatcher.html">QAbstractEventDispatcher</a></td> + + <td align="right"></td> + <td><a href="http://qt.nokia.com/doc/4.0/qabstractformbuilder.html">QAbstractFormBuilder</a></td> + + <td align="right"></td> + <td><a href="http://qt.nokia.com/doc/4.0/qabstractitemview.html">QAbstractItemView</a></td> + </tr> + + <tr> + <td align="right"></td> + <td><a href="http://qt.nokia.com/doc/4.0/qabstractextensionfactory.html">QAbstractExtensionFactory</a></td> + + <td align="right"></td> + <td><a href="http://qt.nokia.com/doc/4.0/qabstractitemdelegate.html">QAbstractItemDelegate</a></td> + + <td align="right"></td> + <td><a href="http://qt.nokia.com/doc/4.0/qabstractlistmodel.html">QAbstractListModel</a></td> + </tr> + </table></p> + \endraw + \endquotation + + A class is identified within the documentation by the + the \l {class}{\\class} command. + + \o \c classesbymodule + + This particular argument requests an additional argument, + i.e. a specification of the module. + + For example: + + \code + / *! + \page qtgui.html + \contentspage Qt Classes by Module + \previouspage QtCore Classes + \nextpage QtNetwork Classes + + \title QtGui Classes + + \keyword QtGui + + \generatelist {classesbymodule QtGui} + * / + \endcode + + Together, these arguments provide a table containing the + classes considered members of the specified module, + accompanied with a brief description. Each class name is + a link to the class's reference documentation. + + The generated table is rendered similarily to the one + generated when using the \l {table example}{\c + annotatedclasses} argument. + + For the basic classes in Qt, a class's module is + determined by its location, i.e. its directory. However, + for extensions, like ActiveQt and Qt Designer, a class + is related to a module with the \l + {inmodule}{\\inmodule} command. + + \o \c classesbyedition + + This particular argument requests an additional argument, + i.e. a specification of the edition. + + For example: + + \code + / *! + \page console-edition-classes.html + \title Qt Console Edition Classes + + \generatelist{classesbyedition Console} + * / + \endcode + + Together, these arguments provide a table containing the + classes considered members of the specified edition, + accompanied with a brief description. Each class name is + a link to the class's reference documentation. + + The edition a given class can be found in is determined by + the module it belongs to. + + \o \c compatclasses + + The \c compatclasses argument provides a complete and + alphabetical list of the support classes. A support + class is identified within the documentation by the \l + {compat}{\\compat} command. Each class name is a link to + the class's reference documentation. The list is + rendered similarily to the list generated by the \l + {list example}{\c classes} argument. + + \warning The \c classesbymodule argument will at some + point replace the this argument. + + \o \c functionindex + + The \c functionindex argument provides a complete + alphabetical list of all the documented member + functions. + + For example: + + \quotation + \raw HTML + <p><center><font size="+1"><b><a href="#a">A</a> <a href="#b">B</a> <a href="#c">C</a> <a href="#d">D</a> <a href="#e">E</a> <a href="#f">F</a> <a href="#g">G</a> <a href="#h">H</a> <a href="#i">I</a> <a href="#j">J</a> <a href="#k">K</a> <a href="#l">L</a> <a href="#m">M</a> <a href="#n">N</a> <a href="#o">O</a> <a href="#p">P</a> <a href="#q">Q</a> <a href="#r">R</a> <a href="#s">S</a> <a href="#t">T</a> <a href="#u">U</a> <a href="#v">V</a> <a href="#w">W</a> <a href="#x">X</a> <a href="#y">Y</a> <a href="#z">Z</a> </b></font></center></p> + + <p>DTDHandler: <a href="http://qt.nokia.com/doc/4.0/qxmlreader.html#DTDHandler">QXmlReader</a></p> + + <p>QAXCLASS: <a href="http://qt.nokia.com/doc/4.0/qaxfactory.html#QAXCLASS">global</a></p> + + <p>QAXFACTORY_BEGIN: <a href="http://qt.nokia.com/doc/4.0/qaxfactory.html#QAXFACTORY_BEGIN">global</a></p> + + <p>QAXFACTORY_DEFAULT: <a href="http://qt.nokia.com/doc/4.0/qaxfactory.html#QAXFACTORY_DEFAULT">global</a></p> + + <p>QAXFACTORY_END: <a href="http://qt.nokia.com/doc/4.0/qaxfactory.html#QAXFACTORY_END">global</a></p> + + \endraw + + ... + \endquotation + + \o \c legalese + + The \c legalese argument provides a complete list of all + the licenses. The licenses are identified within the + documentation using the \l {legalese}{\\legalese} + command. + + For example: + + \quotation + \raw HTML + <hr /> + <p> + Copyright (c) 1989 The Regents of the + University of California. All rights reserved. + </p> + + <p> + Redistribution and use in source and binary + forms are permitted provided that the above + copyright notice and this paragraph are + duplicated in all such forms and that any + documentation, advertising materials, and other + materials related to such distribution and use + acknowledge that the software was developed by + the University of California, Berkeley... + </p> + + <ul> + <li> + <a href="http://qt.nokia.com/doc/4.0/qdate.html#weekNumber">QDate::weekNumber()</a> + </li> + </ul> + + <hr /> + <p> + Copyright (c) 1991 by AT&T. + </p> + + <p> + Permission to use, copy, modify, and distribute + this software for any purpose without fee is + hereby granted, provided that this entire notice + is included in all copies of any software which + is or includes a copy or modification of this + software and in all copies of the supporting + documentation for such software... + </p> + + <ul> + <li> + <a href="http://qt.nokia.com/doc/4.0/qlocale.html">QLocale</a> + </li> + </ul> + <hr /> + \endraw + ... + \endquotation + + \o \c mainclasses + + The \c mainclasses argument provides a complete + alphabetical list of the main classes. Each class name + is a link to the class's reference documentation. A + class is related to the group of main classes by using + the \l {mainclass}{\\mainclass} command. + + The list is rendered similarily to the list generated by + the \l {list example}{\c classes} argument. + + \o \c overviews + + The \c overviews argument provides a complete + alphabetical overview of the documentation. Each list + entry is a link to the respective documentation page. + + The list includes pages declared using commands like \l + {page}{\\page} and \l {group}{\\group}. The list omits + examples and classes, and only lists the first page of + documentation that contains two or more pages using + commands like \l {nextpage}{\\nextpage}. + + For example: + + \quotation + \raw HTML + <ul> + + <li> + <a href="http://qt.nokia.com/doc/4.0/qtalgorithms.html"> + <QtAlgorithms> - Generic Algorithms + </a> + </li> + + <li> + <a href="http://qt.nokia.com/doc/4.0/qtglobal.html"> + <QtGlobal> - Global Qt Declarations + </a> + </li> + + <li> + <a href="http://qt.nokia.com/doc/4.0/qaxserver-demo-simple.html"> + A standard ActiveX and the "simple" ActiveQt widget + </a> + </li> + + <li> + <a href="http://qt.nokia.com/doc/4.0/aboutqt.html"> + About Qt + </a> + </li> + + <li> + <a href="http://qt.nokia.com/doc/4.0/trolltech.html"> + About Trolltech + </a> + </li> + + <li> + <a href="http://qt.nokia.com/doc/4.0/abstractwidgets.html"> + Abstract Widget Classes + </a> + </li> + + <li> + <a href="http://qt.nokia.com/doc/4.0/accessibility.html"> + Accessibility Classes + </a> + </li> + ... + </ul> + \endraw + \endquotation + + \o \c related + + The \c related argument is used in combination with the + \l {group}{\\group} command to list all the overviews + related to the given group. Each list entry is a link to + the respective documentation page. + + \o \c relatedinline + + The \c related argument is used in combination with the + \l {group}{\\group} command to collect all documentation + related to the given group. The various documentation + snippets are copied directly into the group page. + + \o \c service + + The \c service argument provides a complete alphabetical + list of the services. Each service name is a link to the + service's reference documentation. + + A service is identified within the documentation by the + \l {service}{\\service} command. + + \endlist + + + \row + \o \bold \\if \target if + \o \bold {The \\if command and the corresponding \\endif command + enclose parts of a QDoc comment that only will be included if + the condition specified by the command's argument is true.} + + The command reads the rest of the line and parses it as an + C++ #if statement. For example: + + \code + / *! + \if defined(opensourceedition) + + \bold{Note:} This edition is for the development of + \l{Qt Open Source Edition}{Free and Open Source} + software only; see \l{Qt Commercial Editions}. + + \endif + * / + \endcode + + This QDoc comment will only be rendered if the \c + opensourceedition preprocessor symbol is defined, and + specified in the \l {definesvariable}{defines} variable in + the configuration file to make QDoc process + the code within #ifdef and #endif: + + \code + defines = opensourceedition + \endcode + + You can also define the preprocessor symbol manually on the + command line. For more information see the documentation of + the \l {definesvariable}{defines} variable. + + See also \l{endif}{\\endif}, \l{else}{\\else}, \l + {definesvariable}{defines} and \l falsehoods. + + \row + \o \bold \\endif \target endif + \o \bold {The \\endif command and the corresponding \\if command + enclose parts of a QDoc comment that will be included if + the condition specified by the \l {if}{\\if} command's + argument is true.} + + For more information, see the documentation of the \l + {if}{\\if} command. + + See also \l{if}{\\if}, \l{else}{\\else}, \l + {definesvariable}{defines} and \l falsehoods. + + \row + \o \bold \\else \target else + \o \bold {The \\else command specifies an alternative if the + condition in the \l {if}{\\if} command is false.} + + The \\else command can only be used within \l + {if}{\\if...\\endif} commands, but is useful when there is + only two alternatives. For example: + + \code + / *! + The Qt 3 support library is provided to keep old + source code working. + + In addition to the \c Qt3Support classes, Qt 4 provides + compatibility functions when it's possible for an old + API to cohabit with the new one. + + \if !defined(QT3_SUPPORT) + \if defined(QT3_SUPPORTWARNINGS) + The compiler emits a warning when a + compatibility function is called. (This works + only with GCC 3.2+ and MSVC 7.) + \else + To use the Qt 3 support library, you need to + have the line QT += qt3support in your .pro + file (qmake automatically define the + QT3_SUPPORT symbol, turning on compatibility + function support). + + You can also define the symbol manually (e.g., + if you don't want to link against the \c + Qt3Support library), or you can define \c + QT3_SUPPORT_WARNINGS instead, telling the + compiler to emit a warning when a compatibility + function is called. (This works only with GCC + 3.2+ and MSVC 7.) + \endif + \endif + * / + \endcode + + If the \c QT3_SUPPORT is defined, the comment will be rendered + as + + \quotation + The Qt 3 support library is provided to keep old source + code working. + + In addition to the Qt3Support classes, Qt 4 provides + compatibility functions when it's possible for an old + API to cohabit with the new one. + \endquotation + + If \c QT3_SUPPORT isn't defined but \c QT3_SUPPORT_WARNINGS + is, the comment will be rendered as + + \quotation + The Qt 3 support library is provided to keep old source + code working. + + In addition to the Qt3Support classes, Qt 4 provides + compatibility functions when it's possible for an old + API to cohabit with the new one. + + The compiler emits a warning when a compatibility + function is called. (This works only with GCC 3.2+ and + MSVC 7.) + \endquotation + + If none of the symbols are defined, the comment will be + rendered as + + \quotation + The Qt 3 support library is provided to keep old + source code working. + + In addition to the \c Qt3Support classes, Qt 4 provides + compatibility functions when it's possible for an old + API to cohabit with the new one. + + To use the Qt 3 support library, you need to have the + line QT += qt3support in your .pro file (qmake + automatically define the QT3_SUPPORT symbol, turning on + compatibility function support). + + You can also define the symbol manually (e.g., if you + don't want to link against the \c Qt3Support library), + or you can define \c QT3_SUPPORT_WARNINGS instead, + telling the compiler to emit a warning when a + compatibility function is called. (This works only with + GCC 3.2+ and MSVC 7.) + \endquotation + + See also \l{if}{\\if}, \l{endif}{\\endif}, \l + {definesvariable}{defines} and \l falsehoods. + + \row + \o \bold \\include \target include + \o \bold {The \\include command expands to the contents of the + file specified by the command's argument.} + + \warning This is preliminary functionality. For more + information, see the \l + {26-qdoc-commands-compatibility.html#include-versus-input} + {compatibility} section. + + The command takes a file name as an argument, and is + useful when some piece of the documentation is used + repeatedly: Move the repetetive text into a separate file, + and use the \\include command whenever you want to insert + the separate documentation. + + The contents of such a file should follow QDoc syntax, + excluding the enclosing \c{/}\c{*!} ... \c{*}\c{/} marks. + To ensure that QDoc won't attempt to read the file as a + stand-alone piece of documentation, we recommend that you + use the \c .qdocinc extension. + + For example: + + \code + / *! + \page corefeatures.html + \title Core Features + + \include examples/signalandslots.qdocinc + \include examples/objectmodel.qdocinc + \include examples/layoutmanagement.qdocinc + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h1>Core Features</h1> + \endraw + + \include examples/signalandslots.qdocinc + \include examples/objectmodel.qdocinc + \include examples/layoutmanagement.qdocinc + \endquotation + + Here is the actual \c .qdocinc files: \l + signalandslots.qdocinc, \l objectmodel.qdocinc, \l + layoutmanagement.qdocinc + + \row + \o \bold \\meta \target meta + \o \bold {The \\meta command is the QDoc equivalent to the HTML + \c meta tag.} + + The command accepts two arguments: The first argument (the + following word) is equivalent to the HTML meta tag's \i + name variable, and the second argument (the rest of the + line) is equivalent to the tag's \i contents variable. + + For example: + + \code + / *! + \meta author Summerfield + + \section1 Automatic Dialogs + + \abstract + This article shows how to maintain sets of + "attributes" (QVariant values), and how to allow + users to view and edit them using dialogs that are + created dynamically based on the attributes and + their types. + \endabstract + + The Attributes class described in this article holds a + set of QVariants, and can create a dialog to present + the QVariants to the user in an appropriate way. + + ... + * / + \endcode + + will be included in the generated HTML page as + + \code + <head> + ... + <meta name="author" content="Summerfield" /> + ... + </head> + \endcode + + \row + \o \bold \\omit \target omit + \o \bold {The \\omit command and the correspondning \\endomit + command delimit parts of the documentation that + you want QDoc to skip.} + + For example: + + \code + / *! + \table + \row + \o Basic Widgets + \o Basic GUI widgets such as buttons, comboboxes + and scrollbars. + + \omit + \row + \o Component Model + \o Interfaces and helper classes for the Qt + Component Model. + \endomit + + \row + \o Database Classes + \o Database related classes, e.g. for SQL databases. + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + <table align="center" cellpadding="2" + cellspacing="1" border="0"> + + <tr valign="top" bgcolor="#d0d0d0"> + <td>Basic Widgets</td> + <td>Basic GUI widgets such as buttons, comboboxes + and scrollbars.</td> + </tr> + + <tr valign="top" bgcolor="#c0c0c0"> + <td>Database Classes</td> + <td>Database related classes, e.g. for SQL databases.</td> + </tr> + </table> + \endraw + + + \row + \o \bold \\raw \target raw + \o \bold {The \\raw command and the corresponding + \\endraw command delimit a block of raw mark-up language code.} + + The command takes an argument specifying the code's format; + currently the only supported format is HTML. + + The \\raw command is useful if you want some special HTML + effects in your documentation. For example: + + \code + / *! + Qt has some predefined QColor objects. For example: + + \raw HTML + <style type="text/css" id="colorstyles"> + #blue { background-color: #0000ff; color: #ffffff } + #darkBlue { background-color: #000080; color: #ffffff } + #cyan { background-color: #00ffff; color: #000000 } + </style> + + <p> + <tt id="blue">Blue(#0000ff)</tt>, + <tt id="darkBlue">dark blue(#000080)</tt> and + <tt id="cyan">cyan(#00ffff)</tt>. + \endraw + * / + \endcode + + will be rendered as + + \quotation + Qt has some predefined QColor objects. For example: + + \raw HTML + <style type="text/css" id="colorstyles"> + #blue { background-color: #0000ff; color: #ffffff } + #darkBlue { background-color: #000080; color: #ffffff } + #cyan { background-color: #00ffff; color: #000000 } + </style> + + <p> + <tt id="blue">Blue(#0000ff)</tt>, + <tt id="darkBlue">dark blue(#000080)</tt> and + <tt id="cyan">cyan(#00ffff)</tt>. + \endraw + \endquotation + + \row + \o \bold \\unicode \target unicode + \o \bold {The \\unicode command allows you to insert an + arbitrary Unicode character in the document.} + + The command takes an argument specifying the character as + an integer. By default, base 10 is assumed, unless a '0x' + or '0' prefix is specified (for base 16 and 8, + respectively). For example: + + \code + O G\unicode{0xEA}nio e as Rosas + + \unicode 0xC0 table en famille avec 15 \unicode 0x20AC par jour + + \unicode 0x3A3 \i{a}\sub{\i{i}} + \endcode + + will be rendered as + + \quotation + O G\unicode{0xEA}nio e as Rosas + + \unicode 0xC0 table en famille avec 15 \unicode 0x20AC par jour + + \unicode 0x3A3 \i{a}\sub{\i{i}} + \endquotation + + The \\raw command follows the same conventions as the \l + {i}{\\i} command for \l {argument}{punctuation and use of + braces} for the argument. + \endtable +*/ + +/*! + \page 12-1-signalandslots.html + \previouspage Miscellaneous Commands + \contentspage QDoc Manual - Table of Contents + + \title signalandslots.qdocinc + + \quotefile examples/signalandslots.qdocinc +*/ + +/*! + \page 12-2-objectmodel.html + \previouspage Miscellaneous Commands + \contentspage QDoc Manual - Table of Contents + + \title objectmodel.qdocinc + + \quotefile examples/objectmodel.qdocinc +*/ + +/*! + \page 12-3-layoutmanagement.html + \previouspage Miscellaneous Commands + \contentspage QDoc Manual - Table of Contents + + \title layoutmanagement.qdocinc + + \quotefile examples/layoutmanagement.qdocinc +*/ + +/*! + \page 13-qdoc-commands-topical.html + \previouspage Miscellaneous Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Contextual Commands + + \title Topical Commands + + The topical commands tell QDoc what is being documented + (i.e. existing units like classes, functions and examples), and + some of the commands allows you to create extra pages. + + \section1 Alphabetical List + + \l {13-qdoc-commands-topical.html#class}{\\class}, + \l {13-qdoc-commands-topical.html#enum}{\\enum}, + \l {13-qdoc-commands-topical.html#example-command}{\\example}, + \l {13-qdoc-commands-topical.html#externalpage}{\\externalpage}, + \l {13-qdoc-commands-topical.html#fn}{\\fn}, + \l {13-qdoc-commands-topical.html#group}{\\group}, + \l {13-qdoc-commands-topical.html#headerfile}{\\headerfile}, + \l {13-qdoc-commands-topical.html#macro}{\\macro}, + \l {13-qdoc-commands-topical.html#module}{\\module}, + \l {13-qdoc-commands-topical.html#namespace}{\\namespace}, + \l {13-qdoc-commands-topical.html#page}{\\page}, + \l {13-qdoc-commands-topical.html#property}{\\property}, + \l {13-qdoc-commands-topical.html#service}{\\service}, + \l {13-qdoc-commands-topical.html#typedef}{\\typedef}, + \l {13-qdoc-commands-topical.html#variable}{\\variable}, + + \section1 General Description + + When QDoc is processing a comment, it will try to connect the + documentation to the source code. For that reason it will first + look for the topical commands. If there is no such command, it + will try to tie the documentation to the immediately following + code. If there is no topical command, and the documentation cannot + be tied to following code, the documentation is simply lost. + + \target topical argument + + The documented unit's name is passed as the unique argument for + all the topical commands. The argument's naming convention is the + documented unit's complete name. For example: + + \code + \enum QComboBox::InsertPolicy + \endcode + + Functions is a special case, the argument's naming convention for + the \l {fn}{\\fn} command is that of the function's definition + outside the class definition. For example: + + \code + \fn void PreviewWindow::setWindowFlags() + \endcode + + A topical command can appear anywhere in a comment, but must stand + alone on its own line. If the argument spans several lines, make + sure that each line (except the last one) is ended with a + backslash. In addition QDoc counts parentheses, which means that + if it encounters a '(' it considers everything until the closing + ')' as its argument. + + If a topical command is repeated with different arguments, the + same documentation will appear for both the units. For example: + + \code + / *! + \fn void PreviewWindow::setWindowFlags() + \fn void ControllerWindow::setWindowFlags() + + Sets the widgets flags using the QWidget::setWindowFlags() + function. + + Then runs through the available window flags, creating a text + that contains the names of the flags that matches the flags + parameter, displaying the text in the widgets text editor. + * / + \endcode + + The \c PreviewWindow::setWindowFlags() and \c + ControllerWindow::setWindowFlags() functions will get the same + documentation. + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\class \target class + \o \bold {The \\class command tells QDoc that a class is + part of the public API, and lets you enter a detailed + description.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument, and supports + nested classes, for example: + + \code + / *! + \class QMap::iterator + + \brief The QMap::iterator class provides an STL-style + non-const iterator for QMap and QMultiMap. + + QMap features both \l{STL-style iterators} and + \l{Java-style iterators}. The STL-style iterators ... + * / + \endcode + + The generated HTML documentation for the specified class is + put in \c <lower-case>classname.html. For example, the + documentation for the \c PreviewWindow class is located in + \c previewwindow.html. + + \target framework + + In addition to render the detailed description, the \\class + comand will generate the documentation framework, i.e. a + list of the class's types, properties, functions, signals + and slots with empty documentation. + + The command is typically accompanied with a \l + {brief}{\\brief} command, a \l {mainclass}{\\mainclass} + command, an \l {ingroup}{\\ingroup} command and a \l + {sa}{\\sa} command. For example: + + \code + / *! + \class PreviewWindow + \brief The PreviewWindow class is a custom widget + displaying the names of its currently set + window flags in a read-only text editor. + + \mainclass + \ingroup miscellaneous + + The PreviewWindow class inherits QWidget. The widget + displays the names of its window flags set with the \l + {function}{setWindowFlags()} function. It is also + provided with a QPushButton that closes the window. + + ... + + \sa QWidget + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h1>PreviewWindow Class Reference</h1> + \endraw + + The PreviewWindow class is a custom widget displaying + the names of its currently set window flags in a + read-only text editor. \l {preview window}{More...} + + \raw HTML + <h3>Properties</h3> + \endraw + + \list + \o 52 properties inherited from QWidget + \o 1 property inherited from QObject + \endlist + + \raw HTML + <h3>Public Functions</h3> + \endraw + + \list + \o \l {constructor}{PreviewWindow}(QWidget *parent = 0) + \o void \l {function}{setWindowFlags}(Qt::WindowFlags flags) + \endlist + + \list + \o 183 public functions inherited from QWidget + \o 28 public functions inherited from QObject + \endlist + + \raw HTML + <h3>Public Slots</h3> + \endraw + + \list + \o 17 public slots inherited from QWidget + \o 1 public slot inherited from QObject + \endlist + + \raw HTML + <h3>Additional Inherited Members</h3> + \endraw + + \list + \o 1 signal inherited from QWidget + \o 1 signal inherited from QObject + \o 4 static public members inherited from QWidget + \o 4 static public members inherited from QObject + \o 39 protected functions inherited from QWidget + \o 7 protected functions inherited from QObject + \endlist + + \target preview window + + \raw HTML + <hr /> + <h2>Detailed Description</h2> + \endraw + + The PreviewWindow class is a custom widget displaying + the names of its currently set window flags in a + read-only text editor. + + The PreviewWindow class inherits QWidget. The widget + displays the names of its window flags set with the \l + {function}{setWindowFlags()} function. It is also + provided with a QPushButton that closes the window. + + ... + + See also QWidget. + + \raw HTML + <hr /> + <h2>Member Function Documentation</h2> + \endraw + + \target constructor + \raw HTML + <h3>PreviewWindow(QWidget *parent = 0)</h3> + \endraw + + Constructs a preview window widget with \i parent. + + \target function + \raw HTML + <h3>setWindowFlags(Qt::WindowFlags flags)</h3> + \endraw + + Sets the widgets flags using the + QWidget::setWindowFlags() function. + + Then runs through the available window flags, + creating a text that contains the names of the flags + that matches the flags parameter, displaying + the text in the widgets text editor. + \endquotation + + \row + \o \bold \\enum \target enum + \o \bold {The \\enum command allows you to document a C++ enum.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + The enum items are documented using the \l {value}{\\value} + command. If an item isn't documented, QDoc will emit a + warning. This can be avoided using the \l + {omitvalue}{\\omitvalue} command excluding an item from the + documentation. The enum documentation will be located in + the associated class, header file or namespace + documentation. + + For example: + + \code + enum Corner { + TopLeftCorner = 0x00000, + TopRightCorner = 0x00001, + BottomLeftCorner = 0x00002, + BottomRightCorner = 0x00003 + #if defined(QT3_SUPPORT) && !defined(Q_MOC_RUN) + ,TopLeft = TopLeftCorner, + TopRight = TopRightCorner, + BottomLeft = BottomLeftCorner, + BottomRight = BottomRightCorner + #endif + }; + \endcode + + In case of the Qt::Corner enum, + + \code + / *! + \enum Qt::Corner + + This enum type specifies a corner in a rectangle: + + \value TopLeftCorner + The top-left corner of the rectangle. + \value TopRightCorner + The top-right corner of the rectangle. + \value BottomLeftCorner + The bottom-left corner of the rectangle. + \value BottomRightCorner + The bottom-right corner of the rectangle. + + \omitvalue TopLeft + \omitvalue TopRight + \omitvalue BottomLeft + \omitvalue BottomRight + * / + \endcode + + this associated QDoc comment will be rendered as + + \quotation + \raw HTML + <h3 class="fn"><a name="Corner-enum"></a>enum Qt::Corner</h3> + + <p>This enum type specifies a corner in a rectangle:</p> + + <table border="1" cellpadding="2" cellspacing="1" width="100%"> + <tr> + <th width="25%">Constant</th> + <th width="15%">Value</th> + <th width="60%">Description</th> + </tr> + + <tr> + <td valign="top"><tt>Qt::TopLeftCorner</tt></td> + <td align="center" valign="top"><tt>0x00000</tt></td> + <td valign="top">The top-left corner of the rectangle.</td> + </tr> + + <tr> + <td valign="top"><tt>Qt::TopRightCorner</tt></td> + <td align="center" valign="top"><tt>0x00001</tt></td> + <td valign="top">The top-right corner of the rectangle.</td> + </tr> + + <tr> + <td valign="top"><tt>Qt::BottomLeftCorner</tt></td> + <td align="center" valign="top"><tt>0x00002</tt></td> + <td valign="top">The bottom-left corner of the rectangle.</td> + </tr> + + <tr> + <td valign="top"><tt>Qt::BottomRightCorner</tt></td> + <td align="center" valign="top"><tt>0x00003</tt></td> + <td valign="top">The bottom-right corner of the rectangle.</td> + </tr> + + </table> + \endraw + \endquotation + + in qt.html. + + See also \l {value}{\\value} and \l {omitvalue}{\\omitvalue}. + + \row + \o \bold \\example \target example-command + \o \bold {The \\example command allows you to document an + example.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. In particular + the command's argument is the example's path relative to + the paths listed in the \l exampledirs configuration + variable. + + The documentation will be located in \i + {path-to-example}.html, and QDoc will add a list of all the + example files at the top of this documentation page. + + For example, if \l exampledirs contain \c + $QTDIR/examples/widgets/imageviewer, then + + \code + / *! + \example widgets/imageviewer + \title ImageViewer Example + \subtitle + + The example shows how to combine QLabel and QScrollArea + to display an image. + + ... + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <center><h1>Image Viewer Example</h1></center> + \endraw + + Files: + \list + \o \l{http://qt.nokia.com/doc/4.0/widgets-imageviewer-imageviewer-cpp.html} + {widgets/imageviewer/imageviewer.cpp} + \o \l{http://qt.nokia.com/doc/4.0/widgets-imageviewer-imageviewer-h.html} + {widgets/imageviewer/imageviewer.h} + \o \l{http://qt.nokia.com/doc/4.0/widgets-imageviewer-main-cpp.html} + {widgets/imageviewer/main.cpp} + \endlist + + The example shows how to combine QLabel and QScrollArea + to display an image. + + ... + \endquotation + + in widgets-imageviewer.html. + + \row + \o \bold \\fn \target fn + \o \bold {The \\fn command allows you to document a function.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. In particular + it is important that the return type of the function, + whether it is \c const or not and the complete set of + arguments with type are included in the argument. If the + referenced function doesn't exist, QDoc will emit a + warning. + + Also, the \\fn command is QDoc's default command, i.e. when + no topical command can be found within a QDoc comment, QDoc + tries to tie the documentation to the following code as if + it was function documentation. + + This means that the command normally isn't necessary since + the recommended style is to write the function + documentation directly before the function implementation + in the \c .cpp file. In fact, it should only be used for + inline functions implemented in the \c .h file. + + For example: + + \code + / *! + \fn bool QToolBar::isAreaAllowed(Qt::ToolBarArea area) const + + Returns true if this toolbar is dockable in the given + \a area; otherwise returns false. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3>bool QToolBar::isAreaAllowed(Qt::ToolBarArea area) const + </h3> + \endraw + + Returns true if this toolbar is dockable in the given + \a area; otherwise returns false. + \endquotation + + See also \l {overload}{\\overload}. + + \row + \o \bold \\group \target group + \o \bold {The \\group command creates a separate page that + lists the classes belonging to the group specified by the + command's argument.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. The \\group + command is typically followed by a \l {title}{\\title} + command and a short introduction to the group. The + generated HTML documentation for the specified group is put + in <lower-case>\i{group}.html. + + A class can be related to a group by using the \l + {ingroup}{\\ingroup} command. In addition, overviews can be + related to a group using the same command, but these must + be listed explicitly using the \l + {generatelist}{\\generatelist} command (see example below). + + Each class is listed with a link to the class reference + page and a brief description based on the classes' \l + {brief}{\\brief} texts. For example: + + \code + / *! + \group io + + \title Input/Output and Networking + + These classes are used to handle input and output to + and from external devices, processes, files etc. as + well as manipulating files and directories. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + + <h1>Input/Output and Networking</h1> + + <p>These classes are used to handle input and output + to and from external devices, processes, files etc. as + well as manipulating files and directories.</p> + + <p> + <table width="100%"> + <tr valign="top" bgcolor="#e0e0e0"> + <td><b> + <a href="http://qt.nokia.com/doc/4.0/qabstractsocket.html">QAbstractSocket</a> + </b></td> + <td> + The base functionality common to all socket types + </td></tr> + + <tr valign="top" bgcolor="#e0e0e0"> + <td><b> + <a href="http://qt.nokia.com/doc/4.0/qbuffer.html">QBuffer</a> + </b></td> + <td> + QIODevice interface for a QByteArray + </td></tr> + + <tr valign="top" bgcolor="#e0e0e0"> + <td><b> + <a href="http://qt.nokia.com/doc/4.0/qclipboard.html">QClipboard</a> + </b></td> + <td> + Access to the window system clipboard + </td></tr> + </table> + \endraw + \endquotation + + in io.html. + + Note that overviews related to the given group, must be + listed explicitly using the \l + {generatelist}{\\generatelist} command with the \c related + argument. For example: + + \code + / *! + \group architecture + + \title Architecture + + These documents describe aspects of Qt's architecture + and design, including overviews of core Qt features and + technologies. + + \generatelist{related} + * / + \endcode + + See also \l {ingroup}{\\ingroup} and \l + {generatelist}{\\generatelist}. + + \row + \o \bold \\headerfile \target headerfile + \o \bold {The \\headerfile command allows you to document + global functions, types and macros declared in a header file.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument, and the + generated HTML documentation for the specified header file + is put in <lower-case>\i{headerfilename}.html. + + A function, type or macro can be associated with a + headerfile using the \l {relates}{\\relates} command. + + If the referenced header file doesn't exist, the + \\headerfile command will still create a documentation page + for a header file with the referenced file's name. + + For example: + + \code + / *! + \headerfile <QtAlgorithms> + + \title Generic Algorithms + + \brief The <QtAlgorithms> header file provides + generic template-based algorithms. + + Qt provides a number of global template functions in \c + <QtAlgorithms> that work on containers and perform + well-know algorithms. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <center><h1><QtAlgorithms> - + Generic Algorithms</h1></center> + <p>The <QtAlgorithms> header file provides generic + template-based algorithms. + <a href="13-qdoc-commands-topical.html#header">More...</a> + </p> + + <h3>Functions</h3> + <ul> + <li>RandomAccessIterator + <a href="http://qt.nokia.com/doc/4.0/qlineedit.html#EchoMode-enum">qBinaryFind</a></b> + (RandomAccessIterator begin, RandomAccessIterator end, + const T & value)</li> + <li>...</li></ul> + <hr /> + \endraw + + \target header + + \raw HTML + <h2>Detailed Description</h2> + <p>The <QtAlgorithms> header file provides generic + template-based algorithms. </p> + \endraw + + Qt provides a number of global template functions in \c + <QtAlgorithms> that work on containers and perform + well-know algorithms. + + ... + \endquotation + + in qtalgorithms.html. + + \row + \o \bold \\macro \target macro + \o \bold {The \\macro command allows you to document a C++ macro.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + QDoc recognizes three different macro syntax: function-like + macros like Q_ASSERT(), declaration-style macros like + Q_PROPERTY() and macros without parentheses like Q_OBJECT. + + The \\macro command must be followed by a \l + {relates}{\\relates} command which attaches the + documentation to that of a related class, header file. or + namespace. Otherwise the documentation will be lost. + + For example: + + \code + / *! + \macro void Q_ASSERT(bool test) + \relates <QtGlobal> + + Prints a warning message containing the source code + file name and line number if \a test is false. + + ... + + \sa Q_ASSERT_X(), qFatal(), {Debugging Techniques} + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3>void Q_ASSERT ( bool <i>test</i> )</h3> + \endraw + + Prints a warning message containing the source code + file name and line number if \a test is false. + + ... + + See also Q_ASSERT_X(), qFatal() and \l {Debugging + Techniques}. + \endquotation + + in qtglobal.html. And + + \code + / *! + \macro Q_PROPERTY(...) + \relates QObject + + This macro declares a QObject property. The syntax is: + + ... + + \sa {Qt's Property System} + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3>Q_PROPERTY ( ... )</h3> + \endraw + + This macro declares a QObject property. The syntax is: + + ... + + See also \l {Qt's Property System}. + \endquotation + + in qobject.html. And + + \code + / *! + \macro Q_OBJECT + \relates QObject + + The Q_OBJECT macro must appear in the private section + of a class definition that declares its own signals and + slots or that uses other services provided by Qt's + meta-object system. + + ... + + \sa {Meta-Object System}, {Signals and Slots}, {Qt's + Property System} + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3>Q_OBJECT</h3> + \endraw + + The Q_OBJECT macro must appear in the private section + of a class definition that declares its own signals and + slots or that uses other services provided by Qt's + meta-object system. + + ... + + See also \l {Meta-Object System}, \l {Signals and + Slots} and \l {Qt's Property System}. + \endquotation + + in qobject.html. + + \row + \o \bold \\module \target module + \o \bold {The \\module creates a separate page that lists the + classes belonging to the module specified by the command's + argument.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + A class can be related to a module using the \l + {inmodule}{\\inmodule} command. + + The \\module command is typically followed by the \l + {title}{\\title} and \l {brief}{\\brief} commands. Each + class is listed with a link to the class reference page and + a brief description based on the classes' \l + {brief}{\\brief} texts. + + For example: + + \code + / *! + \module QtNetwork + + \title QtNetwork Module + + \brief The QtNetwork module offers classes that allow + you to write TCP/IP clients and servers. + + The network module provides classes to make network + programming easier and portable. It offers both + high-level classes such as QHttp and QFtp that + implement specific application-level protocols, and + lower-level classes such as QTcpSocket, QTcpServer, and + QUdpSocket. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h1><center>QtNetwork Module</center></h1> + \endraw + + The QtNetwork module offers classes that allow you to + write TCP/IP clients and servers.\l {module + details}{More...} + + \raw HTML + <p> + <table width="100%"> + <tr valign="top" bgcolor="#d0d0d0"> + <td><b> + <a href="http://qt.nokia.com/doc/4.0/qabstractsocket.html">QAbstractSocket</a> + </b></td> + <td> + The base functionality common to all socket types + </td></tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td><b> + <a href="http://qt.nokia.com/doc/4.0/qftp.html">QFtp</a> + </b></td> + <td> + Implementation of the FTP protocol + </td></tr> + + <tr valign="top" bgcolor="#d0d0d0"> + <td>...</td> + <td>...</td> + </tr> + </table> + + <p><hr /></p> + \endraw + + \target module details + + \raw HTML + <h2>Detailed Description</h2> + + <p> + The QtNetwork module offers classes that allow you to + write TCP/IP clients and servers. + </p> + + <p> + The network module provides classes to make network + programming easier and portable. It offers both + high-level classes such as QHttp and QFtp that + implement specific application-level protocols, and + lower-level classes such as QTcpSocket, QTcpServer, and + QUdpSocket. + </p> + \endraw + + ... + + \endquotation + + in qtnetwork.html. + + See also \l {inmodule}{\\inmodule} + + \row + \o \bold \\namespace \target namespace + \o \bold {The \\namespace command allows you to document a C++ + namespace.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + QDoc will generate the same additional links and + documentation for all the members of the namespace as it + does for \l {framework}{classes}. The documentation for + the specified namespace is put in <lower-case>\i + {namespace}.html. + + For example: + + \code + / *! + \namespace Qt + + \brief The Qt namespace contains miscellaneous + identifiers used throughout the Qt library. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <center><h1>Qt Namespace Reference</h1></center> + <p>The Qt namespace contains miscellaneous + identifiers used throughout the Qt library. + <a href="13-qdoc-commands-topical.html#name">More...</a> + </p> + + <pre>#include <Qt></pre> + <ul> + <li> + <a href="http://qt.nokia.com/doc/4.0/qt-qt3.html"> + Qt 3 support members</a></li> + </ul> + + + <h3>Types</h3> + <ul> + <li>flags + <a href="http://qt.nokia.com/doc/4.0/qt.html#AlignmentFlag-enum">Alignment</a></b></li> + <li>...</li></ul> + <hr /> + \endraw + + \target name + + \raw HTML + <h2>Detailed Description</h2> + <p>The Qt namespace contains miscellaneous identifiers + used throughout the Qt library.</p> + \endraw + + ... + \endquotation + + in qt.html. + + \row + \o \bold \\page \target page + \o \bold {The \\page command allows you to create a stand-alone + documentation page.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + The page's title can be set using the \l {title}{\\title} + command. For example: + + \code + / *! + \page aboutqt.html + + \title About Qt + + Qt by Trolltech is a C++ toolkit for cross-platform GUI + application development. Qt provides single-source + portability across Microsoft Windows, Mac OS X, Linux, + and all major commercial Unix variants. (A version of + Qt 4 for embedded Linux will be available in + August/September 2005.) + + Qt provides application developers with all the + functionality needed to build applications with + state-of-the-art graphical user interfaces. Qt is fully + object-oriented, easily extensible, and allows true + component programming. + + ... + * / + \endcode + + will be rendered in its own HTML file: \l{About Qt}. + + \row + \o \bold {\\externalpage} \target externalpage + \o \bold {The \\externalpage command gives a title to + an external URL.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + For example: + + \code + / *! + \externalpage http://www.trolltech.com/products/embedded/index.html + \title Qtopia Core + * / + \endcode + + The QDoc comment above allows you to link to the Qtopia + Core webpage by simply linking to the given title. For + example: + + \code + / *! + The broad scope of the \l {Qtopia Core} API enables it to + be used across a wide variety of development projects. + * / + \endcode + + will be rendered as + + \quotation + The broad scope of the \l + {http://www.trolltech.com/products/embedded/index.html}{Qtopia + Core} API enables it to be used across a wide variety + of development projects. + \endquotation + + To achieve the same result without using the + \\externalpage command, you would have to hard code the + adress into your documentation: + + \code + / *! + The broad scope of the \l + {http://www.trolltech.com/products/embedded/index.html}{Qtopia + Core} API enables it to be used across a wide variety + of development projects. + * / + \endcode + + The \\externalpage command makes it easier to maintain the + documentation. If the adress changes, you only need to change the + argument of the \\externalpage command. + + \row + \o \bold \\property \target property + \o \bold {The \\property command allows you to document a Qt + property.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + A property is defined using the Q_PROPERTY() macro. The + macro takes as arguments the property's name and its set, + reset and get functions. For example: + + \code + Q_PROPERTY(QString state READ state WRITE setState) + \endcode + + The set, reset and get functions don't need to be + documented, documenting the property is sufficient. QDoc + will generate a list of the access function that will + appear in the property documentation which in turn will be + located in the documentation of the class that defines the + property. + + The \\property command is typically accompanied with a \l + {brief}{\\brief} command. In the case of a property, the + \l {brief}{\\brief} command's argument is a sentence + fragment that will be included in a one-sentence + description of the property generated by QDoc. The command + follows the same rules for the \l {brief + property}{description} as the \l {variable}{\\variable} + command. + + For example: + + \code + / *! + \property QPushButton::flat + \brief whether the border is disabled + + This property's default is false. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3>flat : bool</h3> + \endraw + + This property holds whether the border is disabled. + + This property's default is false. + + Access functions: + + \list + \o \bold { bool isFlat () const} + \o \bold { void setFlat ( bool )} + \endlist + + \endquotation + + in qpushbutton.html. And + + \code + / *! + \property QWidget::width + \brief the width of the widget excluding any window frame + + See the \l {Window Geometry} documentation for an + overview of window geometry. + + \sa geometry, height, size + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3>width : const int</h3> + \endraw + + This property holds the width of the widget excluding + any window frame. + + See the \l {Window Geometry} documentation for an + overview of window geometry. + + Access functions: + + \list + \o \bold { int width () const} + \endlist + + See also \l{QWidget::geometry}{geometry}, + \l{QWidget::height}{height}, and \l{QWidget::size}{size}. + \endquotation + + in qwidget.html. + + \row + \o \bold \\service \target service + + \o \bold {The \\service command tells QDoc that a class is a + service class and specifies its alias, i.e. the associated + service's name.} + + The command takes two arguments, the service class's name + and the associated alias. For example: + + \code + / *! + \service TimeService Time + ... + * / + class TimeService : public QCopObjectService + { + ... + } + \endcode + + See also \l {class}{\\class} and \l + {generatelist}{\\generatelist}. + + \row + \o \bold \\typedef \target typedef + \o \bold {The \\typedef command allows you to document a C++ type + definition.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + The documentation will be located in the associated class, + header file or namespace documentation. When documenting a + global type definition, the \\typedef command must be + accompanied with a \l {relates}{\\relates} command. For + example: + + \code + / *! + \typedef QObjectList + \relates QObject + + Synonym for QList<QObject>. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3>typedef QObjectList</h3> + \endraw + + Synonym for QList<QObject>. + \endquotation + + in qobject.html. Another, although more rare, example is + + \code + / *! + \typedef QMsgHandler + \relates QtGlobal + + This is a typedef for a pointer to a function with the + following signature: + + \code + void myMsgHandler(QtMsgType, const char *); + \ endcode + + \sa QtMsgType, qInstallMsgHandler() + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3>typedef QtMsgHandler</h3> + \endraw + + This is a typedef for a pointer to a function with the + following signature: + + \raw HTML + <tt> + <pre> void myMsgHandler(QtMsgType, const char *);</pre> + </tt> + \endraw + + See also QtMsgType and qInstallMsgHandler(). + + \endquotation + + in qtglobal.html. Other type definitions are located in the + documentation of the class that defines it, for example: + + \code + / *! + \typedef QLinkedList::Iterator + + Qt-style synonym for QList::iterator. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3>typedef QLinkedList::Iterator</h3> + \endraw + + Qt-style synonym for QList::iterator. + \endquotation + + in qlinkedlist.html. + + \row + \o \bold \\variable \target variable + \o \bold {The \\variable command allows you to document a + member variable or a constant.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + The \\variable command is typically followed by a \l + {brief}{\\brief} command; QDoc will generate the + documentation for the variable based on the brief + description. The command follows the same rules for the \l + {brief property}{description} as the \l + {property}{\\property} command. + + The documentation will be located in the in the associated + class, header file or namespace documentation. + + In case of a member variable: + + \code + / *! + \variable QStyleOption::palette + \brief the palette that should be used when painting + the control + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3> + <a href="http://qt.nokia.com/doc/4.0/qpalette.html"> + QPalette + </a> + QStyleOption::palette + </h3> + \endraw + + This variable holds the palette that should be used + when painting the control. + \endquotation + + in qstyleoption.html. + + But you can also use the \\variable command to document + constants like for example the \c Type and \c UserType + constants in the QTreeWidgetItem class: + + \code + enum { Type = 0, UserType = 1000 }; + \endcode + + Then + + \code + / *! + \variable QTreeWidgetItem::Type + + The default type for tree widget items. + + \sa UserType, type() + * / + \endcode + + and + + \code + / *! + \variable QTreeWidgetItem::UserType + + The minimum value for custom types. Values below + UserType are reserved by Qt. + + \sa Type, type() + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3> + const int QTreeWidgetItem::Type + </h3> + \endraw + + The default type for tree widget items. + + See also \l {QTreeWidgetItem::UserType}{UserType} and + \l {QTreeWidgetItem::type()}{type()}. + + \raw HTML + <h3> + const int QTreeWidgetItem::UserType + </h3> + \endraw + + The minimum value for custom types. Values below + UserType are reserved by Qt. + + See also \l {QTreeWidgetItem::Type}{Type} and + \l{QTreeWidgetItem::type()}{type()}. + + \endquotation + + in qtreewidget.html. + \endtable +*/ + +/*! + \page 14-qdoc-commands-contextualcommands.html + \previouspage Topical Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Navigation Commands + + \title Contextual Commands + + The contextual commands provide QDoc with information, that it + wouldn't figure out otherwise, about the documented object. For + example whether a class is thread-safe or not. + + These commands can appear anywhere within a QDoc comment. + + \section1 Alphabetical List + + \l {16-qdoc-commands-status.html#compat}{\\compat}, + \l {15-qdoc-commands-navigation.html#contentspage}{\\contentspage}, + \l {15-qdoc-commands-navigation.html#indexpage}{\\indexpage}, + \l {19-qdoc-commands-grouping.html#ingroup}{\\ingroup}, + \l {19-qdoc-commands-grouping.html#inmodule}{\\inmodule}, + \l {16-qdoc-commands-status.html#internal}{\\internal}, + \l {19-qdoc-commands-grouping.html#mainclass}{\\mainclass}, + \l {15-qdoc-commands-navigation.html#nextpage}{\\nextpage}, + \l {17-qdoc-commands-thread.html#nonreentrant}{\\nonreentrant}, + \l {16-qdoc-commands-status.html#obsolete}{\\obsolete}, + \l {18-qdoc-commands-relating.html#overload}{\\overload}, + \l {16-qdoc-commands-status.html#preliminary}{\\preliminary}, + \l {15-qdoc-commands-navigation.html#previouspage}{\\previouspage}, + \l {17-qdoc-commands-thread.html#reentrant}{\\reentrant}, + \l {18-qdoc-commands-relating.html#reimp}{\\reimp}, + \l {18-qdoc-commands-relating.html#relates}{\\relates}, + \l {15-qdoc-commands-navigation.html#startpage}{\\startpage}, + \l {17-qdoc-commands-thread.html#threadsafe}{\\threadsafe}, + \l {20-qdoc-commands-title.html#title}{\\title} + + \section1 Categories + \list + \o \l {Navigation Commands} + \o \l {Status Commands} + \o \l {Thread Support Commands} + \o \l {Relating Commands} + \o \l {Grouping Commands} + \o \l {Title Commands} + \endlist +*/ + +/*! + \page 15-qdoc-commands-navigation.html + \previouspage Contextual Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Status Commands + + \title Navigation Commands + + The navigation commands allow you to link the pages of a multipage + document together. They provide the components of a navigation bar + at the top and bottom of the document. They also provide browser + and search engine support. + + \section1 Alphabetical List + + \l {15-qdoc-commands-navigation.html#contentspage}{\\contentspage}, + \l {15-qdoc-commands-navigation.html#indexpage}{\\indexpage}, + \l {15-qdoc-commands-navigation.html#nextpage}{\\nextpage}, + \l {15-qdoc-commands-navigation.html#previouspage}{\\previouspage}, + \l {15-qdoc-commands-navigation.html#startpage}{\\startpage} + + \section1 General Description + + The QDoc comments below shows a typical example using the + navigation commands. + + \code + / *! + \page basicqt.html + \contentspage {Basic Qt}{Contents} + \nextpage Getting Started + + \indexpage Index + \startpage Basic Qt + + \title Basic Qt + + The Qt toolkit is a C++ class library and a set of tools for + building multiplatform GUI programs using a "write once, + compile anywhere approach". + + Table of contents: + + \list + \o \l {Getting Started} + \o \l {Creating Dialogs} + \o \l {Creating Main Windows} + \endlist + * / + + / *! + \page gettingstarted.html + \previouspage Basic Qt + \contentspage {Basic Qt}{Contents} + \nextpage Creating Dialogs + + \indexpage Index + \startpage Basic Qt + + \title Getting Started + + This chapter shows how to combine basic C++ with the + functionality provided by Qt to create a few small graphical + interface (GUI) applications. + * / + + / *! + \page creatingdialogs.html + \previouspage Getting Started + \contentspage {Basic Qt}{Contents} + + \indexpage Index + \startpage Basic Qt + + \title Creating Dialogs + + This chapter will teach you how to create dialog boxes using Qt. + * / + + / *! + \page index.html + + \indexpage Index + \startpage Basic Qt + + \title Index + + \list + \o \l {Basic Qt} + \o \l {Creating Dialogs} + \o \l {Getting Started} + \endlist + * / + \endcode + + The second page of this multipage document, "Getting Started", + will be rendered as + + \quotation + \raw HTML + <table border="0" cellpadding="0" cellspacing="5" width="100%"> + + <tr> + <p> + [Previous: <a href="15-qdoc-commands-navigation.html#deadlink"> + Basic Qt</a>] + [<a href="15-qdoc-commands-navigation.html#deadlink">Contents</a>] + [Next: <a href="15-qdoc-commands-navigation.html#deadlink"> + Creating Dialogs</a>] + </p> + + <h1 align="center">Getting Started<br /></h1> + + <p> + This chapter shows how to combine basic C++ with the + functionality provided by Qt to create a few small graphical + interface (GUI) applications. + </p> + + <p> + [Previous: <a href="15-qdoc-commands-navigation.html#deadlink"> + Basic Qt</a>] + [<a href="15-qdoc-commands-navigation.html#deadlink">Contents</a>] + [Next: <a href="15-qdoc-commands-navigation.html#deadlink"> + Creating Dialogs</a>] + </p> + + </table> + \endraw + \endquotation + + in creatingdialogs.html. + + In addition, the \l {indexpage}{\\indexpage} and \l + {startpage}{\\startpage} commands specifies links to the page's + index page and start page. These links are used by browsers and + search engines. + + The index page is typically an alphabetical list of the document's + titles and topics, while the start page is the page considered by + the author to be the starting point of a multipage document. + + The links are included in the generated HTML source code but has + no visual effect on the documentation: + + \code + <head> + ... + <link rel="index" href="index.html" /> + <link rel="start" href="basicqt.html" /> + ... + </head> + \endcode + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\previouspage \target previouspage + \o \bold {The \\previouspage command links the current page + to the previous one in an ordered series of documents}. + + The command has two arguments, each enclosed by curly + braces: The first is the link target, i.e. the title of the + previous page, the second is the link text. If the page's + title is equivalent to the link text, the second argument + can be omitted. + + The command must stand alone on its own line. + + In the end, the link is rendered at the top and bottom of + the current page. For an example, see the \l {General + Description} section. + + \row + \o \bold \\nextpage \target nextpage + \o \bold {The \\nextpage command links the current + page to the next page in an ordered series of documents}. + + The command follows the same syntax and argument convention + as the \l {previouspage}{\\previouspage} command. + + For an example, see the \l {General Description} section. + + \row + \o \bold \\startpage \target startpage + \o \bold {The \\startpage command specifies the first document + in a collection of documents.} + + The command must stand alone on its own line, and its + unique argument is the title of the first document. + + QDoc will generate a link to the specified document which + is included in the HTML file but has no visual effect on + the documentation. The generated link type tells browsers + and search engines which document is considered by the + author to be the starting point of the collection. + + For an example, see the \l {General Description} section. + + \row + \o \bold \\contentspage \target contentspage + \o \bold {The \\contentspage command links the current + page to a contents page}. + + The command follows the same syntax and argument convention + as the \l {previouspage}{\\previouspage} command. + + For an example, see the \l {General Description} section. + + \row + \o \bold \\indexpage \target indexpage + \o \bold {The \\indexpage command specifies a document providing + an index for the current document}. + + The command must stand alone on its own line, and its + unique argument is the title of the index document. + + QDoc will generate a link to the specified document which + is included in the HTML file but has no visual effect on + the documentation. The generated link type tells browsers + and search engines which document is considered by the + author to be the index page for the current document. + + For an example, see the \l {General Description} section. + + \endtable +*/ + +/*! + \page 16-qdoc-commands-status.html + \previouspage Navigation Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Thread Support Commands + + \title Status Commands + + The usage commands can indicate whether a documented object is + under development, becoming obsolete, provided for compatibility + reasons or simply not part of the public interface. They can + describe the history of minor versions. And they can also describe + a documented object's ability to handle multithreaded programming. + + \section1 Alphabetical List + + \l {16-qdoc-commands-status.html#compat}{\\compat}, + \l {16-qdoc-commands-status.html#internal}{\\internal}, + \l {16-qdoc-commands-status.html#obsolete}{\\obsolete}, + \l {16-qdoc-commands-status.html#preliminary}{\\preliminary}, + \l {16-qdoc-commands-status.html#since}{\\since} + + \section1 Command Description + + \table + \header + \o Command + \o Description + + \row + \o \bold \\preliminary \target preliminary + \o \bold {The \\preliminary command indicates that the + referenced function is under development.} + + The command must stand on its own line. + + The \\preliminary command expands to a notification in the + function documentation, and marks the function as + preliminary when it appears in lists. For example: + + \code + / *! + \preliminary + + Returns information about the joining properties of the + character (needed for certain languages such as + Arabic). + * / + QChar::Joining QChar::joining() const + { + return ::joining(*this); + } + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3> + <a href="http://qt.nokia.com/doc/4.0/qchar.html#Joining-enum">Joining</a> + QChar::joining () const</h3> + \endraw + + \bold {This function is under development and + is subject to change.} + + Returns information about the joining properties of the + character (needed for certain languages such as + Arabic). + \endquotation + + And the function's entry in QChar's list of functions will + be rendered as + + \quotation + \list + \o ... + \o Joining + \l {http://qt.nokia.com/doc/4.0/qchar.html#Joining-enum} + {joining}() + const \c (preliminary) + \o ... + \endlist + \endquotation + + \row + \o \bold \\obsolete \target obsolete + \o \bold {The \\obsolete command indicates that the referenced + function no longer should be used in new code; + there is no guarantee for how long it will remain in + the library.} + + The command must stand on its own line. + + When generating the reference documentation for a class, + QDoc will create and link to a separate page documenting + its obsolete functions. Usually an equivalent function is + provided as an alternative. + + For example: + + \code + / *! + \fn MyClass::MyObsoleteFunction + \obsolete + + Use MyNewFunction() instead. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h1>Obsolete Members for MyClass</h1> + \endraw + + \bold {The following class members are obsolete.} They + are provided to keep old source code working. We + strongly advise against using them in new code. + + ... + + \list + \o void MyObsoleteFunction() \c (obsolete) + \o ... + \endlist + + \raw HTML + <hr /> + <h2>Member Function Documentation</h2> + <h3>void MyObsoleteFunction ()</h3> + <p>Use MyNewFunction() instead.</p> + \endraw + + ... + \endquotation + + in myclass-obsolete.html + + + \row + \o \bold \\compat \target compat + \o \bold {The \\compat command indicates that the referenced class + or function is part of the support library provided to keep + old source code working.} + + The command must stand on its own line. + + Usually an equivalent function or class is provided as an + alternative. + + If the command is used within the documentation of a class, + the command expands to a warning that the referenced class + is part of the support library. The warning is located on + top of the associated documentation. For example: + + \code + / *! + \class MyQt3SupportClass + \compat + * / + \endcode + + will be rendered as + + \quotation + \bold {This class is part of the Qt 3 support + library.} It is provided to keep old source code + working. We strongly advise against using it in new + code. See the \l + {http://qt.nokia.com/doc/4.0/porting4.html}{Porting + Guide} for more information. + \endquotation + + on the top of the MyQt3SupportClass class reference. + + If the command is used when documenting a function, QDoc + will create and link to a separate page documenting Qt 3 + support members when generating the reference documentation + for the associated class. For example: + + \code + / *! + \fn MyClass::MyQt3SupportMemberFunction + \compat + + Use MyNewFunction() instead. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h1>Qt 3 Support Members for MyClass</h1> + \endraw + + \bold {The following class members are part of the Qt + 3 support layer.} They are provided to help you port + old code to Qt 4. We advise against using them in new + code. + + ... + + \list + \o void MyQt3SupportMemberFunction() + \o ... + \endlist + + \raw HTML + <hr /> + <h2>Member Function Documentation</h2> + <h3>void MyQt3SupportMemberFunction ()</h3> + <p>Use MyNewFunction() instead.</p> + \endraw + + ... + \endquotation + + in myclass-qt3.html + + + \row + \o \bold \\internal \target internal + \o \bold {The \\internal command indicates that the referenced + function is not part of the public interface.} + + The command must stand on its own line. + + QDoc ignores the documentation as well as the documented + item, when generating the associated class reference + documenation. For example: + + \code + / *! + \internal + + Tries to find the decimal separator. If it can't find + it and the thousand delimiter is != '.' it will try to + find a '.'; + * / + int QDoubleSpinBoxPrivate::findDelimiter + (const QString &str, int index) const + { + int dotindex = str.indexOf(delimiter, index); + if (dotindex == -1 && thousand != dot && delimiter != dot) + dotindex = str.indexOf(dot, index); + return dotindex; + } + \endcode + + in qspinbox.cpp, will not be rendered at all. + + \row + \o \bold \\since \target since + \o \bold {The \\since command tells in which minor release + the associated functionality was added.} + + For example: + + \code + / *! + \since 4.1 + + Returns an icon for \a standardIcon. + + ... + + \sa standardIconImplementation(), standardPixmap() + * / + QIcon QStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const + { + } + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3>QIcon QStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const</h3> + \endraw + + This function was introduced in Qt version 4.1 + + Returns an icon for \a standardIcon. + + ... + + See also \l + {QStyle::standardIconImplementation()}{standardIconImplementation()} + and \l {QStyle::standardPixmap()}{standardPixmap()}. + \endquotation + + QDoc generates the "Qt" reference from the \l + {25-qdoc-configuration-derivedprojects.html#project}{\c + project} configuration variable. For that reason this + reference will change according to the current + documentation project. + + See also \l + {25-qdoc-configuration-derivedprojects.html#project}{\c + project}. + + \endtable +*/ + +/*! + \page 17-qdoc-commands-thread.html + \previouspage Status Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Relating Commands + + \title Thread Support Commands + + The thread support commands specify the level of support for + multithreaded programming of a class or function. + + \section1 Alphabetical List + + \l {17-qdoc-commands-thread.html#nonreentrant}{\\nonreentrant}, + \l {17-qdoc-commands-thread.html#reentrant}{\\reentrant}, + \l {17-qdoc-commands-thread.html#threadsafe}{\\threadsafe} + + \section1 General Description + + There are three levels of support for multithreaded programming of + a class or function: \c threadsafe, \c reentrant and \c + nonreentrant. + + The default is \c nonreentrant which means that the associated + class or function cannot be called by multiple threads. \c + Reentrant and \c threadsafe are levels primarily used for classes. + + \c Reentrant means that all the functions in the referenced class + can be called simultaneously by multiple threads, provided that + each invocation of the functions reference unique data. While \c + threadsafe means that all the functions in the referenced class + can be called simultaneously by multiple threads even when each + invocation references shared data. + + When a class is declared \c reentrant or \c threadsafe, using the + \l {reentrant}{\\reentrant} and \l {threadsafe}{\\threadsafe} + commands respectively, functions in the referenced class can be + declared \c nonreentrant, using the \l + {nonreentrant}{\\nonreentrant} command, excluding the functions + from the general view. + + For example: + + \code + / *! + \class QLocale + \brief The QLocale class converts between numbers and their + string representations in various languages. + + \reentrant + \ingroup i18n + \ingroup text + \mainclass + + QLocale is initialized with a language/country pair in its + constructor and offers number-to-string and string-to-number + conversion functions similar to those in QString. + + ... + * / + + / *! + \nonreentrant + + Sets the global default locale to \a locale. These values are + used when a QLocale object is constructed with no + arguments. If this function is not called, the system's locale + is used. + + \warning In a multithreaded application, the default locale + should be set at application startup, before any non-GUI + threads are created. + + \sa system() c() + * / + void QLocale::setDefault(const QLocale &locale) + { + default_d = locale.d; + } + \endcode + + will be rendered as + + \quotation + \raw HTML + <h1><center>QLocale Class Reference</center></h1> + \endraw + + The QLocale class converts between numbers and their string + representations in various languages. More... + + \code + #include <QLocale> + \endcode + + \bold {Note:} All the functions in this class are \l + {threads.html#reentrant}{reentrant}, except \l + {QLocale::setDefault()}{setDefault()}. + + ... + + \raw HTML + <hr /> + <h2>Member Type Documentation</h2> + \endraw + + ... + + \raw HTML + <h3>void QLocale::setDefault ( const QLocale & locale ) </h3> + \endraw + + Sets the global default locale to locale. These values are + used when a QLocale object is constructed with no + arguments. If this function is not called, the system's locale + is used. + + \warning In a multithreaded application, the default locale + should be set at application startup, before any non-GUI + threads are created. + + \warning This function is not reentrant. + + See also \l {QLocale::system()}{system()} and \l + {QLocale::c()}{c()}. + + ... + \endquotation + + As shown above, QDoc generates a notification when a class is + declared reentrant, and lists the exceptions (the declared + nonreentrant functions). A link to the general documentation on \l + {threads.html#reentrant}{reentrancy and thread-safety} is + included. In addition a warning, "\bold Warning: This function is + not reentrant.", is generated in the nonreentrant functions' + documentation. + + QDoc will generate the same notification and warnings when a class + is declared threadsafe. + + For more information see the general documentation on \l + {threads.html#reentrant}{reentrancy and thread-safety}. + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\threadsafe \target threadsafe + \o \bold {The \\threadsafe command indicates that the + associated class or function can be called simultaneously by + multiple threads even when each invocation references + shared data.} + + The command must stand on its own line. + + The generated documentation resulting from using the + \\threadsafe command is similar to the result of using the + \l {reentrant}{\\reentrant} command. For an example, see + the \l {General Description} section. + + See also \l{reentrant}{\\reentrant} and + \l{nonreentrant}{\\nonreentrant}. + + \row + \o \bold \\reentrant \target reentrant + \o \bold {The \\reentrant command indicates that the associated + class or function can be called simultaneously + by multiple threads, provided that each invocation of the + functions reference unique data.} + + The command must stand on its own line. + + For an example, see the \l {General Description} section. + + See also \l{nonreentrant}{\\nonreentrant} and + \l{threadsafe}{\\threadsafe}. + + \row + \o \bold \\nonreentrant \target nonreentrant + \o \bold {The \\nonreentrant command indicates that the + associated class or function cannot be called by + multiple threads.} + + The command must stand on its own line. + + For an example, see the \l {General Description} section. + + See also \l{reentrant}{\\reentrant} and + \l{threadsafe}{\\threadsafe}. + + \endtable +*/ + +/*! + \page 18-qdoc-commands-relating.html + \previouspage Thread Support Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Grouping Commands + + \title Relating Commands + + The relation commands discribe how the documented object relates + to its context: Whether it is an overloaded function, a + reimplemented function or a global function related to a specified + class or header file. + + \section1 Alphabetical List + + \l {18-qdoc-commands-relating.html#overload}{\\overload}, + \l {18-qdoc-commands-relating.html#reimp}{\\reimp}, + \l {18-qdoc-commands-relating.html#relates}{\\relates}, + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\overload \target overload + \o \bold {The \\overload command indicates that the + function is a secondary overload of its name.} + + The command must stand on its own line. + + For any overloaded function (except constructors), QDoc + expects one primary version of the function and all the + the overloads marked with the \bold{\\overload command}. + The primary version should be fully documented. Each + overload can have whatever extra documentation you want + to add for just that overload. + + From Qt 4.5, you can include the function name plus '()' + as a parameter to the \bold{\\overload} command, which + will include a standard \i{This function overloads...} + line of text with a link to the documentation for the + primary version of the function. + + For example: + + \code + / *! + \overload addAction() + + This convenience function creates a new action with an + \a icon and some \a text. The function adds the newly + created action to the menu's list of actions, and + returns it. + + \sa QWidget::addAction() + * / + QAction *QMenu::addAction(const QIcon &icon, const QString &text) + { + QAction *ret = new QAction(icon, text, this); + addAction(ret); + return ret; + } + \endcode + + will be rendered as + + \quotation + \raw HTML + <h3><a href="http://qt.nokia.com/doc/4.0/qaction.html">QAction</a> + * QMenu::addAction ( const QIcon & <i>icon</i>, + const QString & <i>text</i> ) + </h3> + \endraw + + This function overloads \l {http://qt.nokia.com/doc/4.0/qwidget.html#addAction}{addAction()} + + This convenience function creates a new action with an + \i icon and some \i text. The function adds the newly + created action to the menu's list of actions, and + returns it. + + See also + \l {http://qt.nokia.com/doc/4.0/qwidget.html#addAction} + {QWidget::addAction}(). + \endquotation + + If you don't include the function name with the + \bold{\\overlaod} command, then instead of the "This + function overloads..." line with the link to the + documentation for the primary version, you get the old + standard line: + + \quotation + This is an overloaded member function, provided for + convenience. + \endquotation. + + \row + \o \bold \\reimp \target reimp + \o \bold {The \\reimp command indicates that the + referenced function is a reimplementation of a virtual function, + where the reimplementation has no effect on the interface.} + + The command must stand on its own line. + + QDoc will omit the reimplemented function from the class + reference. For example: + + \code + / *! + \reimp + * / + void QToolButton::nextCheckState() + { + Q_D(QToolButton); + if (!d->defaultAction) + QAbstractButton::nextCheckState(); + else + d->defaultAction->trigger(); + } + \endcode + + will not be rendered at all; only a link to the inherited + QAbstractButton::nextCheckState() will appear in the + documentation. + + \row + \o \bold \\relates \target relates + \o \bold {The \\relates command attaches the documentation of + a global function to that of a related class or header file.} + + The command's argument is a class name, an the command (and + its argument) must stand on its own line. + + \code + / *! + \relates QChar + + Reads a char from the stream \a in into char \a chr. + + \sa {Format of the QDataStream operators} + * / + QDataStream &operator>>(QDataStream &in, QChar &chr) + { + quint16 u; + in >> u; + chr.unicode() = ushort(u); + return in; + } + \endcode + + will be rendered with the QChar documentation. + + \endtable +*/ + +/*! + \page 19-qdoc-commands-grouping.html + \previouspage Relating Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Title Commands + + \title Grouping Commands + + The grouping commands relate classes to defined groups and + modules. The groups are used when generating lists of related + classes in the documentation, while the modules are elements of + Qt's structure. + + \section1 Alphabetical List + + \l {19-qdoc-commands-grouping.html#ingroup}{\\ingroup}, + \l {19-qdoc-commands-grouping.html#inmodule}{\\inmodule}, + \l {19-qdoc-commands-grouping.html#mainclass}{\\mainclass}, + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\mainclass \target mainclass + \o \bold {The \\mainclass command relates the documented class to + a group called mainclasses.} + + The command must stand on its own line. + + For example: + + \code + / *! + \class QWidget qwidget.h + \brief The QWidget class is the base class of + all user interface objects. + + \mainclass + + ... + * / + \endcode + + will ensure that the QWidget class is included in the \c + mainclasses group, which means, for example, that the class + will appear on the list created by calling the \l + {generatelist}{\\generatelist} command with the \c + mainclasses argument: + + \l http://qt.nokia.com/doc/4.0/mainclasses.html + + See also \l {generatelist}{\\generatelist}. + + \row + \o \bold \\ingroup \target ingroup + + \o \bold {The \\ingroup command indicates that the given + overview or documented class belongs to a certain group of + related docmentation.} + + A class or overview may belong to many groups. + + The \\ingroup command's argument is a group name, but note + that the command considers the rest of the line as part of + its argument. Make sure that the group name is followed by + a linebreak. For example: + + \code + / *! + \class QDir + \brief The QDir class provides access to directory + structures and their contents. + + \ingroup io + ... + * / + \endcode + + will ensure that the QDir class is included in the \c io + group, which means, for example, that QDir will appear on + the list created by calling the \l {group}{\\group} command + with the \c io argument. + + Note that to list overviews that are related to a given + group, you must generate the list exlicitly by using the \l + {generatelist}{\\generatelist} command with the \c related + argument. + + See also \l {group}{\\group}. + \row + \o \bold \\inmodule \target inmodule + \o \bold {The \\inmodule command relates the documented class + to the module specified by the command's argument.} + + For the basic classes in Qt, a class's module is determined + by its location, i.e. its directory. However, for + extensions, like ActiveQt and Qt Designer, a class needs to + be related to a module explicitly. + + The command's argument is a module name, but note that the + command considers the rest of the line as part of its + argument. Make sure that the module name is followed by a + linebreak. For example: + + \code + /*! + \class QDesignerTaskMenuExtension + \inmodule QtDesigner + * / + \endcode + + will ensure that the QDesignerTaskMenuExtension class is + included in the \c QtDesigner module, which means, for + example, that the class will appear on the list created by + calling the \l {generatelist}{\\generatelist} command with + the \c {{classesbymodule QtDesigner}} argument. + + See also \l {module}{\\module} and \l + {generatelist}{\\generatelist}. + \endtable +*/ + +/*! + \page 20-qdoc-commands-title.html + \previouspage Grouping Commands + \contentspage QDoc Manual - Table of Contents + \nextpage QDoc Configuration + + \title Title Commands + + In general a title command considers everything that follows it + until the first line break as its argument. If the title needs to + be spanned over several lines, make sure to end each line (except + the last one) with a backslash. + + \section1 Alphabetical List + + \l {20-qdoc-commands-title.html#title}{\\title}, + \l {20-qdoc-commands-title.html#subtitle}{\\subtitle} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\title \target title + \o \bold {The \\title command sets the title for a + documentation page, or allows you to override it.} + + For example: + + \code + / *! + \page signalandslots.html + + \title Signals and Slots + + Signals and slots are used for communication between + objects. The signals and slots mechanism is a central + feature of Qt and probably the part that differs most + from the features provided by other frameworks. + + ... + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h1><center>Signal and Slots</center></h1> + \endraw + + Signals and slots are used for communication between + objects. The signals and slots mechanism is a central + feature of Qt and probably the part that differs most + from the features provided by other frameworks. + + ... + \endquotation + See also \l {subtitle}{\\subtitle}. + + \row + \o \bold \\subtitle \target subtitle + \o \bold {The \\subtitle command sets a subtitle for a + documentation page.} + + For example: + + \code + / *! + \page qtopiacore-overview.html + + \title Qtopia Core + \subtitle Qt for Embedded Linux + + Qt/Embedded, the embedded Linux port of Qt, is a + complete and self-contained C++ GUI and platform + development tool for Linux-based embedded development. + + ... + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + <h1><center>Qtopia Core</center></h1> + <h2><center>Qt for Embedded Linux</center></h2> + \endraw + + Qt/Embedded, the embedded Linux port of Qt, is a + complete and self-contained C++ GUI and platform + development tool for Linux-based embedded development. + + ... + \endquotation + + See also \l {title}{\\title}. + \endtable +*/ + +/*! + \page 21-0-qdoc-configuration.html + \previouspage Title Commands + \contentspage QDoc Manual - Table of Contents + \nextpage General Configuration Variables + + \title QDoc Configuration + + \tableofcontents + + \list + \o \l {Supporting Derived Projects} + \o \l {QDoc Compatibility} + \endlist + + When running QDoc to generate the documentation, you must specify + a configuration file on the command line: + + \quotation + \bold {/currentdirectory$ qdoc3 my-documentation.qdocconf} + \endquotation + + \section1 General Description + + The configuration file is a list of entries of entries of the form + \i {"variable = value"}. Using the configuration variables, you + can define where QDoc should find the various source files, images + and examples, where to put generated documentation etc. The + configuration file can also contain directives like \c + include. For an example, see the \l minimum.qdocconf file. + + In addition, you can use some particular configuration variables + to make QDoc support derived projects, i.e make the projects, for + example Qt Solutions, contain links to the online Qt + documentation. These variables are documented in the \l + {Supporting Derived projects} section. In this section you can + also find out how to use these variables to support your derived + projects. + + If some of the variable keys have the same values, they can be set + at the same time. For example: + + \code + {header, source}dirs = kernel + \endcode + + is equivalent to + + \code + headerdirs = kernel + sourcedirs = kernel + \endcode + + A variable's value can be set using either '=' or '+='. The + difference is that '=' overrides any previously set value, while + '+=' only adds the value to the previously set ones. + + In general, some of the variables accepts a list of strings as + their value, while others only accept a single string. If you + provide a variable of the latter type with several strings they + will simply be concatenated. The quotes around the value string + are optional. But applying them allows you to use special + characters like '=' and ' \" ' within the string. For example: + + \code + HTML.postheader = "<a href=\"index.html\">Home</a>" + \endcode + + If an entry spans many lines, use a backslash at the end of every + line but the last: + + \code + sourcedirs = kernel \ + tools \ + widgets + \endcode + + \section1 Configuration Variables + + \section2 Alphabetical List + + \l {22-qdoc-configuration-generalvariables.html#alias}{alias}, + \l {23-qdoc-configuration-cppvariables.html#Cpp.ignoredirectives} + {Cpp.ignoredirectives}, + \l {23-qdoc-configuration-cppvariables.html#Cpp.ignoretoken} + {Cpp.ignoretokens}, + \l {22-qdoc-configuration-generalvariables.html#definesvariable}{defines}, + \l {22-qdoc-configuration-generalvariables.html#edition}{edition}, + \l {22-qdoc-configuration-generalvariables.html#exampledirs}{exampledirs}, + \l {22-qdoc-configuration-generalvariables.html#examples}{examples}, + \l {22-qdoc-configuration-generalvariables.html#examples.fileextensions} + {examples.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#extraimages}{extraimages}, + \l {22-qdoc-configuration-generalvariables.html#falsehoods}{falsehoods}, + \l {22-qdoc-configuration-generalvariables.html#headerdirs}{headerdirs}, + \l {22-qdoc-configuration-generalvariables.html#headers}{headers}, + \l {22-qdoc-configuration-generalvariables.html#headers.fileextensions} + {headers.fileextensions}, + \l {24-qdoc-configuration-htmlvariables.html#HTML.footer}{HTML.footer}, + \l {24-qdoc-configuration-htmlvariables.html#HTML.postheader} + {HTML.postheader}, + \l {24-qdoc-configuration-htmlvariables.html#HTML.style}{HTML.style}, + \l {22-qdoc-configuration-generalvariables.html#imagedirs}{imagedirs}, + \l {22-qdoc-configuration-generalvariables.html#images}{images}, + \l {22-qdoc-configuration-generalvariables.html#images.fileextensions} + {images.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#language}{language}, + \l {22-qdoc-configuration-generalvariables.html#macro}{macro}, + \l {22-qdoc-configuration-generalvariables.html#outputdir}{outputdir}, + \l {22-qdoc-configuration-generalvariables.html#outputformats} + {outputformats}, + \l {22-qdoc-configuration-generalvariables.html#slow}{slow}, + \l {22-qdoc-configuration-generalvariables.html#sourcedirs}{sourcedirs}, + \l {22-qdoc-configuration-generalvariables.html#sources}{sources}, + \l {22-qdoc-configuration-generalvariables.html#sources.fileextensions} + {sources.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#spurious}{spurious}, + \l {22-qdoc-configuration-generalvariables.html#tabsize}{tabsize}, + \l {22-qdoc-configuration-generalvariables.html#version}{version}, + \l {22-qdoc-configuration-generalvariables.html#versionsym}{versionsym} + + \section2 Categories + + \list + \o \l {General Configuration Variables} + \o \l {C++ Specific Configuration Variables} + \o \l {HTML Specific Configuration Variables} + \endlist + + \section1 Configuration File Examples + + \list + \o A minimum configuration file: \l minimum.qdocconf + \o The Qt configuration file: \l qt.qdocconf + \endlist +*/ + +/*! + \page 21-1-minimum-qdocconf.html + \previouspage QDoc Configuration + \contentspage QDoc Manual - Table of Contents + + \title minimum.qdocconf + + \quotefile examples/minimum.qdocconf +*/ + +/*! + \page 21-2-qt-qdocconf.html + \previouspage QDoc Configuration + \contentspage QDoc Manual - Table of Contents + + \title qt.qdocconf + + \quotefile files/qt.qdocconf +*/ + +/*! + \page 22-qdoc-configuration-generalvariables.html + \previouspage QDoc Configuration + \contentspage QDoc Manual - Table of Contents + \nextpage Creating Help Project Files + + \title General Configuration Variables + + With the general QDoc configuration variables, you can define + where QDoc will find the various source files it needs to generate + the documentation, as well as the directory to put the generated + documentation. You can also do some minor manipulation of QDoc + itself, controlling its output and processing behavior. + + \section1 Alphabetical List + + \l {22-qdoc-configuration-generalvariables.html#alias}{alias}, + \l {22-qdoc-configuration-generalvariables.html#codeindent}{codeindent}, + \l {22-qdoc-configuration-generalvariables.html#definesvariable}{defines}, + \l {22-qdoc-configuration-generalvariables.html#edition}{edition}, + \l {22-qdoc-configuration-generalvariables.html#exampledirs}{exampledirs}, + \l {22-qdoc-configuration-generalvariables.html#examples}{examples}, + \l {22-qdoc-configuration-generalvariables.html#examples.fileextensions} + {examples.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#extraimages}{extraimages}, + \l {22-qdoc-configuration-generalvariables.html#falsehoods}{falsehoods}, + \l {22-qdoc-configuration-generalvariables.html#generateindex}{generateindex}, + \l {22-qdoc-configuration-generalvariables.html#headerdirs}{headerdirs}, + \l {22-qdoc-configuration-generalvariables.html#headers}{headers}, + \l {22-qdoc-configuration-generalvariables.html#headers.fileextensions} + {headers.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#imagedirs}{imagedirs}, + \l {22-qdoc-configuration-generalvariables.html#images}{images}, + \l {22-qdoc-configuration-generalvariables.html#images.fileextensions} + {images.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#language}{language}, + \l {22-qdoc-configuration-generalvariables.html#macro}{macro}, + \l {22-qdoc-configuration-generalvariables.html#outputdir}{outputdir}, + \l {22-qdoc-configuration-generalvariables.html#outputformats} + {outputformats}, + \l {22-qdoc-configuration-generalvariables.html#slow}{slow}, + \l {22-qdoc-configuration-generalvariables.html#sourcedirs}{sourcedirs}, + \l {22-qdoc-configuration-generalvariables.html#sources}{sources}, + \l {22-qdoc-configuration-generalvariables.html#sources.fileextensions} + {sources.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#spurious}{spurious}, + \l {22-qdoc-configuration-generalvariables.html#tabsize}{tabsize}, + \l {22-qdoc-configuration-generalvariables.html#tagfile}{tagfile}, + \l {22-qdoc-configuration-generalvariables.html#version}{version}, + \l {22-qdoc-configuration-generalvariables.html#versionsym}{versionsym} + + \section1 Variable Descriptions + + \table + + \header + \o Variable + \o Description + + \row + \o \bold alias \target alias + \o \bold {The \c alias variable renames a QDoc command.} + + The general syntax is \tt {alias.\i{original-command-name} + = \i temporary-command-name}. + + For example: + + \code + alias.i = e + \endcode + + renames the built-in command \\i (italics) to \\e. + + The \c alias variable is often used for compatibility + reasons; for more information see the \l {QDoc + Compatibility}{compatibility section}. + + See also \l macro. + + \row + \o \bold codeindent \target codeindent + \o \bold {The \c codeindent variable specifies the level of + indentation that QDoc uses when writing code snippets.} + + QDoc originally used a hard-coded value of four spaces for + code indentation to ensure that code snippets could be easily + distinguished from surrounding text. Since we can use + \l{HTML Specific Configuration Variables#HTML.stylesheets}{stylesheets} to + adjust the appearance of certain types of HTML elements, this + level of indentation is not always required. + + \row + \o \bold defines \target definesvariable + \o \bold {The \c defines variable specifies the C++ preprocessor + symbols that QDoc will recognize and respond to.} + + When a preprocessor symbol is specified using the \c + defines variable, you can also use the \l {if}{\\if} + command to enclose documentation that only will be included + if the preprocessor symbol is defined. + + The values of the variable are regular expressions (see + QRegExp for details). By default, no symbol is defined, + meaning that code protected with #ifdef...#endif will be + ignored. + + For example: + + \code + defines = Q_QDOC \ + QT_.*_SUPPORT \ + QT_.*_LIB \ + QT_COMPAT \ + QT3_SUPPORT \ + Q_WS_.* \ + Q_OS_.* \ + Q_BYTE_ORDER \ + __cplusplus + \endcode + + ensures that QDoc will process the code that requires these + symbols to be defined. For example: + + \code + #ifdef Q_WS_WIN + HDC getDC() const; + void releaseDC(HDC) const; + #endif + \endcode + + Since the Q_WS_.* regular expression (specified using the + \c defines variable) matches Q_WS_WIN, QDoc will process + the code within #ifdef and #endif in our example. + + You can also define preprocessor symbols manually on the + command line using the -D option. For example: + + \code + currentdirectory$ qdoc3 -Dconsoleedition qt.qdocconf + \endcode + + In this case the -D option ensures that the \c + consoleedition preprocessor symbol is defined when QDoc + processes the source files defined in the qt.qdocconf file. + + See also \l falsehoods and \l {if}{\\if}. + + \row + \o \bold edition \target edition + \o \bold {The \c edition variable specifies which modules are + included in each edition of a package, and provides QDoc + with information to provide class lists for each edition.} + + This feature is mostly used when providing documentation + for Qt packages. + + The \c edition variable is always used with a particular + edition name to define the modules for that edition: + + \code + edition.Console = QtCore QtNetwork QtSql QtXml + edition.Desktop = QtCore QtGui QtNetwork QtOpenGL QtSql QtXml \ + QtDesigner QtAssistant Qt3Support QAxContainer \ + QAxServer + edition.DesktopLight = QtCore QtGui Qt3SupportLight + \endcode + + In the above examples, the \c Console edition only includes + the contents of four modules. Only the classes from these + modules will be used when the + \l{Miscellaneous Commands#generatelist}{generatelist} command + is used to generate a list of classes for this edition: + + \code + \generatelist{classesbyedition Console} + \endcode + + \row + \o \bold exampledirs \target exampledirs + \o \bold {The \c exampledirs variable specifies the directories + containing the source code of the example files.} + + The \l {examples}{\c examples} and \c exampledirs variables + are used by the \l {quotefromfile}{\\quotefromfile}, \l + {quotefile}{\\quotefile} and \l {example}{\\example} + commands. If both the \l {examples}{\c examples} and \c + exampledirs variables are defined, QDoc will search in + both, first in \l {examples}{\c examples} then in \c + exampledirs. + + QDoc will search through the directories in the specified + order, and accept the first matching file it finds. It will + only search in the specified directories, \i not in + subdirectories. + + For example: + + \code + exampledirs = $QTDIR/doc/src \ + $QTDIR/examples \ + $QTDIR \ + $QTDIR/qmake/examples + + examples = $QTDIR/examples/widgets/analogclock/analogclock.cpp + \endcode + + When processing + + \code + \quotefromfile widgets/calculator/calculator.cpp + \endcode + + QDoc will then see if there exists a file called \c + calculator.cpp listed as a value in the \l {examples}{\c + examples} variable. If it doesn't, it will search in the \c + exampledirs variable, and first see if there exists a file + called + + \code + $QTDIR/doc/src/widgets/calculator/calculator.cpp + \endcode + + If it doesn't, QDoc will continue looking for a file + called + + \code + $QTDIR/examples/widgets/calculator/calculator.cpp + \endcode + + and so forth. + + See also \l examples. + + \row + \o \bold examples \target examples + \o \bold {The \c examples variable allows you to specify individual + example files in addition to those located in the directories + specified by the \l {exampledirs}{\c exampledirs} variable.} + + The \c examples and \l {exampledirs}{\c exampledirs} + variables are used by the \l + {quotefromfile}{\\quotefromfile}, \l + {quotefile}{\\quotefile} and \l {example}{\\example} + commands. If both the \c examples and \l {exampledirs}{\c + exampledirs} variables are defined, QDoc will search in + both, first in \c examples then in \l {exampledirs}{\c + exampledirs}. + + QDoc will search through the values listed for the \c + examples variable, in the specified order, and accept + the first one it finds. + + For an extensive example, see the \l {exampledirs}{\c + exampledirs} command. But note that if you know the file is + listed in the \c examples variable, you don't need to + specify its path: + + \code + \quotefromfile calculator.cpp + \endcode + + See also \l exampledirs. + + \row + \o \bold examples.fileextensions \target examples.fileextensions + \o \bold {The \c examples.fileextensions variable specifies the + file extensions that qdoc will look for when collecting example + files for display in the documentation.} + + The default extensions are *.cpp, *.h, *.js, *.xq, *.svg, *.xml + and *.ui. However, if + + The extensions are given as standard wildcard expressions. + You can add a file extension to the filter using '+='. For + example: + + \code + examples.fileextensions += *.qrc + \endcode + + See also \l{headers.fileextensions}. + + \row + \o \bold extraimages \target extraimages + \o \bold {The \c extraimages variable tells QDoc to incorporate + specific images in the generated documentation.} + + QDoc will not recognize images used within HTML (or any + other markup language). If we want the images to be copied + from the directories specified by \l {imagedirs}{\c + imagedirs} (the images in question must be located in these + directories) to the output directory, we must specify the + images using the \c extraimages variable. + + The general syntax is \tt {extraimages.\i{format} = \i + image}. The file extension is optional. + + For example, in \l qt.qdocconf we use a couple of images + within the HTML.postheader variable which value is pure + HTML. For that reason, these images are specified using the + \c extraimages variable: + + \code + extraimages.HTML = qt-logo + \endcode + + See also \l images and \l imagedirs. + + \row + \o \bold falsehoods \target falsehoods + \o \bold {The \c falsehoods variable defines the truth value of + specified preprocessor symbols as false.} + + If this variable is not set for a preprocessor symbol, QDoc + assumes its truth value is true. The exception is '0', + which value always is false. + + QDoc will recognize, and is able to evaluate, the following + preprocessor syntax: + + \code + #ifdef NOTYET + ... + #endif + + #if defined (NOTYET) + ... + #end if + \endcode + + However, faced with unknown syntax like + + \code + #if NOTYET + ... + #endif + \endcode + + QDoc will evaluate it as true by default, \i unless the + preprocessor symbol is specified within the \c falsehoods + variable entry: + + \code + falsehoods = NOTYET + \endcode + + See also \l defines. + + \row + \o \bold generateindex \target generateindex + \o \bold{The \c generateindex variable contains a boolean value that + specifies whether to generate an index file when HTML documentation + is generated.} + + By default, an index file is always generated with HTML documentation, + so this variable is typically only used when disabling this feature + (by setting the value to \c false) or when enabling index generation + for the WebXML output (by setting the value to \c true). + \row + \o \bold headerdirs \target headerdirs + \o \bold {The \c headerdirs variable specifies the directories + containing the header files associated with the \c .cpp source + files used in the documentation.} + + For example: + + \code + headerdirs = $QTDIR/src \ + $QTDIR/extensions/activeqt \ + $QTDIR/extensions/motif \ + $QTDIR/tools/designer/src/lib/extension \ + $QTDIR/tools/designer/src/lib/sdk \ + $QTDIR/tools/designer/src/lib/uilib + \endcode + + When executed, the first QDoc will do is to read through + the headers specified in the \l {headers}{\c headers} + variable, and the ones located in the directories specified + in the \c headerdir variable (including all + subdirectories), building an internal structure of the + classes and their functions. + + Then it will read through the sources specified in the \l + {sources}{\c sources}, and the ones located in the + directories specified in the \l {sourcedirs}{\c sourcedirs} + varible (including all subdirectories), merging the + documentation with the structure it retrieved from the + header files. + + If both the \c headers and \c headerdirs variables are + defined, QDoc will read through both, first \l {headers}{\c + headers} then \c headerdirs. + + In the specified directories, QDoc will only read the files + with the fileextensions specified in the \l + {headers.fileextensions}{\c headers.fileextensions} + variable. The default extensions are *.ch, *.h, *.h++, + *.hh, *.hpp and *.hxx". The files specified by \l + {headers}{\c headers} will be read independent of their + fileextensions. + + See also \l headers and \l headers.fileextensions. + + \row + \o \bold headers \target headers + \o \bold {The \c headers variable allows you to specify individual + header files in addition to those located in the directories + specified by the \l {headerdirs}{\c headerdirs} variable.} + + For example: + + \code + headers = $QTDIR/src/gui/widgets/qlineedit.h \ + $QTDIR/src/gui/widgets/qpushbutton.h + \endcode + + When processing the \c headers variable, QDoc behaves in the + same way as it does when processing the \l {headerdirs}{\c + headerdirs} variable. For more information, see the \l + {headerdirs}{\c headerdirs} variable. + + See also \l headerdirs. + + \row + \o \bold headers.fileextensions \target headers.fileextensions + \o \bold {The \c headers.fileextensions variable specify the + extension used by the headers.} + + When processing the header files specified in the \l + {headerdirs}{\c headerdirs} variable, QDoc will only read + the files with the fileextensions specified in the \c + headers.fileextensions variable. In this way QDoc avoid + spending time reading irrelevant files. + + The default extensions are *.ch, *.h, *.h++, *.hh, *.hpp + and *.hxx. + + The extensions are given as standard wildcard expressions. + You can add a file extension to the filter using '+='. For + example: + + \code + header.fileextensions += *.H + \endcode + + \warning The above assignment may not work as described. + + See also \l headerdirs. + + \row + \o \bold imagedirs \target imagedirs + \o \bold {The \c imagedirs variable specifies the directories + containing the images used in the documentation.} + + The \l {images}{\c images} and \c imagedirs variables are + used by the \l {image}{\\image} and \l + {inlineimage}{\\inlineimage} commands. If both the \l + {images}{\c images} and \c imagedirs variables are defined, + QDoc will search in both, first in \l {images}{\c images} + then in \c imagedirs. + + QDoc will search through the directories in the specified + order, and accept the first matching file it finds. It will + only search in the specified directories, \i not in + subdirectories. + + For example: + + \code + imagedirs = $QTDIR/doc/src/images \ + $QTDIR/examples + + images = $QTDIR/doc/src/images/calculator-example.png + \endcode + + When processing + + \code + \image calculator-example.png + \endcode + + QDoc will then see if there exists a file called + calculator-example.png listed as a value in the \c images + variable. If it doesn't, it will search in the \c imagedirs + variable, and first see if there exists a file called + + \code + $QTDIR/doc/src/images/calculator-example.png + \endcode + + If it doesn't, QDoc will look for a file called + + \code + $QTDIR/examples/calculator-example.png + \endcode + + You can filter the images in an image directory using the + \l {images.fileextensions}{\c images.fileextensions} + variable. The general idea behind the \l + {images.fileextensions}{\c images.fileextensions} variable + is to enable different image format for different output + format. + + \warning The \l {images.fileextensions}{\c + images.fileextensions} variable's functionality is + preliminay since QDoc at this point only support HTML. + + See also \l images and \l images.fileextensions. + + \row + \o \bold images \target images + \o \bold {The \c images variable allows you to specify individual + image files in addition to those located in the directories + specified by the \l {imagedirs}{\c imagedirs} variable.} + + For example: + + \code + images = $QTDIR/doc/src/images/calculator-example.png + \endcode + + When processing the \c images variable, QDoc behaves in the + same way as it does when processing the \l {imagedirs}{\c + imagedirs} variable. For more information, see the \l + {imagedirs}{\c imagedirs} variable. + + See also \l imagedirs and \l images.fileextensions. + + \row + \o \bold images.fileextensions \target images.fileextensions + \o \bold {The images.fileextensions variable filters the files within + an image directory.} + + The variable's values (the extensions) are given as + standard wildcard expressions. The general syntax is: \tt + {images.fileextensions.\i{format} = *.\i{extension}}. + + The idea is to enable different image format for different + output format. For example: + + \code + images.fileextensions.HTML = *.png + images.fileextensions.LOUT = *.eps + \endcode + + Then, when processing the \l {image}{\\image} and \l + {inlineimage}{\\inlineimage} commands, QDoc will only + search for files with extensions specified in the output + format's associated image extension variable. + + \warning This is preliminary functionality since QDoc at + this point only support HTML. + + The default extensions for HTML are *.png, *.jpg, *.jpeg + and *.gif. + + You can add a file extension to the filter using '+='. For + example: + + \code + images.fileextensions.HTML += *.eps + \endcode + + See also \l imagedirs and \l images. + + \row + \o \bold language \target language + \o \bold {The \c language variable specifies the language of the + source code that is used in the documentation.} + + Currently, C++ is the only language that QDoc + understands. It is also the default language, and doesn't + really need to be specified. But for example in \l + qt.qdocconf: + + \code + language = Cpp + \endcode + + identifies the language of the Qt source code as C++. + + \row + \o \bold macro \target macro + \o \bold {The \c macro variable can be used to create your + own QDoc commands.} + + The general syntax is \tt {macro.\i{command} = + "\i{definition}}". The definition can be described using + QDoc syntax. In addition it is possible to provide an HTML + definition by appending .HTML to the variable. + + For example in \l qt.qdocconf: + + \code + macro.gui = "\\bold" + macro.raisedaster.HTML = "<sup>*</sup>" + \endcode + + makes sure that the \\gui command renders its argument using a + bold font, and that \\raisedaster renders a '*'. + + \row + \o \bold naturallanguage \target naturallanguage + \o \bold {The \c naturallanguage variable specifies the natural + language used for the documentation generated by qdoc.} + + For example: + + \code + naturallanguage = zh-Hans + \endcode + + By default, the natural language is \c en for compatibility + with legacy documentation. + + qdoc will add the natural language information to the HTML + it generates, using the \c lang and \c xml:lang attributes. + + See also \l sourceencoding, \l outputencoding, + \l{http://www.w3.org/TR/xhtml1/#C_7}{C.7. The lang and xml:lang Attributes} and + \l{http://www.w3.org/TR/i18n-html-tech-lang/#ri20040429.113217290}{Best Practice 13: Using Hans and Hant codes}. + + \row + \o \bold outputdir \target outputdir + \o \bold {The \c outputdir variable specifies the directory + where QDoc will put the generated documentation.} + + In qt.qdocconf: + + \code + outputdir = $QTDIR/doc/html + \endcode + + locates the generated Qt reference documentation in + $QTDIR/doc/html. For example, the documentation of the + QWidget class is located in + + \code + $QTDIR/doc/html/qwidget.html + \endcode + + The associated images will be put in an \c images subdirectory. + + \warning When running QDoc multiple times using the same output + directory, all files from the previous run will be lost. + + \row + \o \bold outputencoding \target outputencoding + \o \bold {The \c outputencoding variable specifies the encoding + used for the documentation generated by qdoc.} + + For example: + + \code + outputencoding = UTF-8 + \endcode + + By default, the output encoding is \c ISO-8859-1 (Latin1) for + compatibility with legacy documentation. When generating + documentation for some languages, particularly non-European + languages, this is not sufficient and an encoding such as UTF-8 + is required. + + qdoc will encode HTML using this encoding and generate the + correct declarations to indicate to browsers which encoding + is being used. The \l naturallanguage configuration variable + should also be specified to provide browsers with a complete + set of character encoding and language information. + + See also \l outputencoding and \l naturallanguage. + + \row + \o \bold outputformats \target outputformats + \o \bold {The \c outputformats variable specifies the format of + the generated documentation.} + + Currently, QDoc only supports the HTML format. It is also + the default format, and doesn't need to be specified. + + \row + \o \bold qhp \target qhp + \o \bold{The \c qhp variable is used to define the information to be + written out to Qt Help Project (\c{qhp}) files.} + + See the \l{Creating Help Project Files} chapter for information + about this process. + + \row + \o \bold slow \target slow + \o \bold {The \c slow variable specifies whether QDoc should do + time-consuming processing, such as syntax highlighting.} + + By default, this setting is false. + + Example: + + \code + slow = true + \endcode + + Another way to turn on "slowness" is to invoke QDoc with the + \c -slow command-line option. + + \row + \o \bold sourcedirs \target sourcedirs + \o \bold {The \c sourcedirs variable specifies the directories + containing the \c .cpp or \c .qdoc files used in + the documentation.} + + For example in \l qt.qdocconf + + \code + sourcedirs = $QTDIR/src \ + $QTDIR/doc/src \ + $QTDIR/extensions/activeqt \ + $QTDIR/extensions/motif \ + $QTDIR/tools/designer/src/lib/extension \ + $QTDIR/tools/designer/src/lib/sdk \ + $QTDIR/tools/designer/src/lib/uilib + \endcode + + When executed, the first QDoc will do is to read through + the headers specified in the \l {header}{\c header} + variable, and the ones located in the directories specified + in the \c headerdir variable (including all + subdirectories), building an internal structure of the + classes and their functions. + + Then it will read through the sources specified in the \l + {sources}{\c sources}, and the ones located in the + directories specified in the \l {sourcedirs}{\c sourcedirs} + varible (including all subdirectories), merging the + documentation with the structure it retrieved from the + header files. + + If both the \c sources and \c sourcedirs variables are + defined, QDoc will read through both, first \l {sources}{\c + sources} then \c sourcedirs. + + In the specified directories, QDoc will only read the files + with the fileextensions specified in the \l + {sources.fileextensions}{\c sources.fileextensions} + variable. The default extensions are *.c++, *.cc, *.cpp and + *.cxx. The files specified by \l {sources}{\c sources} will + be read independent of their fileextensions. + + See also \l sources and \l sources.fileextensions. + + \row + \o \bold sourceencoding \target sourceencoding + \o \bold {The \c sourceencoding variable specifies the encoding + used for the source code and documentation.} + + For example: + + \code + sourceencoding = UTF-8 + \endcode + + By default, the source encoding is \c ISO-8859-1 (Latin1) for + compatibility with legacy documentation. For some languages, + particularly non-European languages, this is not sufficient + and an encoding such as UTF-8 is required. + + Although qdoc will use the encoding to read source and + documentation files, limitations of C++ compilers may prevent + you from using non-ASCII characters in source code comments. + In cases like these, it is possible to write API documentation + completely in documentation files. + + See also \l naturallanguage and \l outputencoding. + + \row + \o \bold sources \target sources + \o \bold {The \c sources variable allows you to specify + individual source files in addition to those located in the + directories specified by the \l {sourcedir}{\c sourcedir} + variable.} + + For example: + + \code + sources = $QTDIR/src/gui/widgets/qlineedit.cpp \ + $QTDIR/src/gui/widgets/qpushbutton.cpp + \endcode + + When processing the \c sources variable, QDoc behaves in the + same way as it does when processing the \l {sourcedirs}{\c + sourcedirs} variable. For more information, see the \l + {sourcedirs}{\c sourcedirs} variable. + + See also \l sourcedirs. + + \row + \o \bold sources.fileextensions \target sources.fileextensions + \o \bold {The \c sources.fileextensions variable filters the + files within a source directory.} + + When processing the source files specified in the \l + {sourcedirs}{\c sourcedirs} variable, QDoc will only read + the files with the fileextensions specified in the \c + sources.fileextensions variable. In this way QDoc avoid + spending time reading irrelevant files. + + The default extensions are *.c++, *.cc, *.cpp and *.cxx. + + The extensions are given as standard wildcard expressions. + You can add a file extension to the filter using '+='. For + example: + + \code + sources.fileextensions += *.CC + \endcode + + \warning The above assignment may not work as described. + + See also \l sourcedirs and \l sources. + + \row + \o \bold spurious \target spurious + \o \bold {The \c spurious variable excludes specified + QDoc warnings from the output.} + + The warnings are specified using standard wildcard + expressions. For example: + + \code + spurious = "Cannot find .*" \ + "Missing .*" + \endcode + + makes sure that warnings matching either of these + expressions, will not be part of the output when running + QDoc. For example would the following warning be omitted + from the output: + + \code + qt-4.0/src/opengl/qgl_mac.cpp:156: Missing parameter name + \endcode + + \row + \o \bold tabsize \target tabsize + \o \bold {The \c tabsize variable defines the size of a tab + character.} + + For example: + + \code + tabsize = 4 + \endcode + + will give the tab character the size of 4 spaces. + + The default value of the variable is 8, and doesn't need to + be specified. + + \row + \o \bold tagfile \target tagfile + \o \bold{The \c tagfile variable specifies the Doxygen tag file to be written + when HTML is generated.} + \row + \o \bold version \target version + \o \bold {The \c version variable specifies the version number of the + documented software.} + + For example: + + \code + version = 4.0.1 + \endcode + + When a version number is specified (using the \tt{\l + version} or \tt {\l versionsym} variables in a \c .qdocconf + file), it is accessible through the corresponding \\version + command for use in the documentation. + + \warning The \\version command's functionality is not + fully implemented; currently it only works within raw HTML + code. + + See also \l versionsym. + + \row + \o \bold versionsym \target versionsym + \o \bold {The \c versionsym variable specifies a C++ + preprocessor symbol that defines the version number + of the documented software.} + + For example in \l qt.qdocconf: + + \code + versionsym = QT_VERSION_STR + \endcode + + QT_VERSION_STR is defined in qglobal.h as follows + + \code + #define QT_VERSION_STR "4.0.1" + \endcode + + When a version number is specified (using the \tt{\l + version} or \tt {\l versionsym} variables in a \c .qdocconf + file), it is accessible through the corresponding \\version + command for use in the documentation. + + \warning The \\version command's functionality is not fully + implemented; currently it only works within raw HTML code. + + See also \l {version}{\\version}. + + \endtable +*/ + +/*! + \page 22-creating-help-project-files.html + \previouspage General Configuration Variables + \contentspage QDoc Manual - Table of Contents + \nextpage C++ Specific Configuration Variables + + \title Creating Help Project Files + + \section1 Overview + + Starting with Qt 4.4, Qt Assistant uses a different system for managing + Qt documentation that requires QDoc to generate inventories of files in a + format that is similar to the old style DCF format, but with additional + features. + + Instead of hard-coding information about the documentation sets for Qt, + QDoc allows configuration variables to be used to specify which pages are + to be used in each documentation set it generates. These are specified as + subvariables of the \c qch variable with each set declared using a unique + identifier as a subvariable. + + For example, the configuration file for the Qt documentation defines a + \c Qt documentation set by specifying information about the set as + subvariables with the \c{qhp.Qt} prefix: + + \code + qhp.Qt.file = qt.qhp + qhp.Qt.namespace = com.trolltech.qt.440 + qhp.Qt.virtualFolder = qdoc + qhp.Qt.indexTitle = Qt Reference Documentation + qhp.Qt.indexRoot = + qhp.Qt.extraFiles = classic.css images/qt-logo.png + qhp.Qt.filterAttributes = qt 4.4.0 qtrefdoc + qhp.Qt.customFilters.Qt.name = Qt 4.4.0 + qhp.Qt.customFilters.Qt.filterAttributes = qt 4.4.0 + qhp.Qt.subprojects = classes overviews examples + qhp.Qt.subprojects.classes.title = Classes + qhp.Qt.subprojects.classes.indexTitle = Qt's Classes + qhp.Qt.subprojects.classes.selectors = class + qhp.Qt.subprojects.overviews.title = Overviews + qhp.Qt.subprojects.overviews.indexTitle = All Overviews and HOWTOs + qhp.Qt.subprojects.overviews.selectors = fake:page,group,module + qhp.Qt.subprojects.examples.title = Tutorials and Examples + qhp.Qt.subprojects.examples.indexTitle = Qt Examples + qhp.Qt.subprojects.examples.selectors = fake:example + \endcode +*/ + +/*! + \page 23-qdoc-configuration-cppvariables.html + \previouspage Creating Help Project Files + \contentspage QDoc Manual - Table of Contents + \nextpage HTML Specific Configuration Variables + + \title C++ Specific Configuration Variables + + The C++ specific configuration variables are provided to avoid + erroneous documentation due to non-standard C++ constructs. + + \section1 Alphabetical List + + \l {23-qdoc-configuration-cppvariables.html#Cpp.ignoredirectives} + {Cpp.ignoredirectives}, + \l {23-qdoc-configuration-cppvariables.html#Cpp.ignoretoken} + {Cpp.ignoretokens} + + \section1 Variable Descriptions + + \table + + \header + \o Variable + \o Description + + \row + \o \bold Cpp.ignoredirectives \target Cpp.ignoredirectives + \o \bold {The \c Cpp.ignoredirectives variable makes QDoc ignore + the specified non-standard constructs, within C++ source code.} + + If not specified by the \tt {\l Cpp.ignoretokens} or \tt + {\l Cpp.ignoredirectives} variables, non-standard + constructs (typically macros) can result in erroneous + documentation. + + In \l qt.qdocconf: + + \code + Cpp.ignoredirectives = Q_DECLARE_INTERFACE \ + Q_DECLARE_OPERATORS_FOR_FLAGS \ + Q_DECLARE_PRIVATE \ + Q_DECLARE_PUBLIC \ + Q_DISABLE_COPY \ + Q_DUMMY_COMPARISON_OPERATOR \ + Q_ENUMS \ + Q_FLAGS \ + Q_INTERFACES \ + __attribute__ + \endcode + + makes sure that when processing the code below, for + example, QDoc will simply ignore the 'Q_ENUMS' and + 'Q_FLAGS' expressions: + + \code + class Q_CORE_EXPORT Qt { + Q_OBJECT + Q_ENUMS(Orientation TextFormat BackgroundMode + DateFormat ScrollBarPolicy FocusPolicy + ContextMenuPolicy CaseSensitivity + LayoutDirection ArrowType) + Q_ENUMS(ToolButtonStyle) + Q_FLAGS(Alignment) + Q_FLAGS(Orientations) + Q_FLAGS(DockWidgetAreas) + + public: + ... + }; + \endcode + + The Q_OBJECT macro, however, is an exception: QDoc + recognizes this particular non-standard construct, so there + is no need specifying it using the \tt {\l + Cpp.ignoredirectives} variable. + + Regarding the Q_CORE_EXPORT macro; see the documentation of + the \tt {\l Cpp.ignoretokens} variable. + + See also \l Cpp.ignoretokens. + + \row + \o \bold Cpp.ignoretokens \target Cpp.ignoretokens + \o \bold {The \c Cpp.ignoretokens variable makes QDoc ignore + the specified non-standard constructs, within C++ source code.} + + If not specified by the \tt {\l Cpp.ignoretokens} or \tt + {\l Cpp.ignoredirectives} variables, non-standard + constructs (typically macros) can result in erroneous + documentation. + + In \l qt.qdocconf: + + \code + Cpp.ignoretokens = QAXFACTORY_EXPORT \ + QM_EXPORT_CANVAS \ + ... + Q_COMPAT_EXPORT \ + Q_CORE_EXPORT \ + Q_EXPLICIT \ + Q_EXPORT \ + ... + Q_TYPENAME \ + Q_XML_EXPORT + \endcode + + makes sure that when processing the code below, for + example, QDoc will simply ignore the 'Q_CORE_EXPORT' + expression: + + \code + class Q_CORE_EXPORT Qt { + Q_OBJECT + Q_ENUMS(Orientation TextFormat BackgroundMode + DateFormat ScrollBarPolicy FocusPolicy + ContextMenuPolicy CaseSensitivity + LayoutDirection ArrowType) + Q_ENUMS(ToolButtonStyle) + Q_FLAGS(Alignment) + Q_FLAGS(Orientations) + Q_FLAGS(DockWidgetAreas) + + public: + ... + }; + \endcode + + Regarding the Q_OBJECT, Q_ENUMS and Q_FLAGS macros; see the + documentation of the \tt {\l Cpp.ignoredirectives} + variable. + + See also \l Cpp.ignoredirectives. + + \endtable +*/ + + +/*! + \page 24-qdoc-configuration-htmlvariables.html + \previouspage C++ Specific Configuration Variables + \contentspage QDoc Manual - Table of Contents + \nextpage Supporting Derived Projects + + \title HTML Specific Configuration Variables + + The HTML specific configuration variables define the generated + documentation's style, or define the contents of the + documentation's footer or postheader. The format of the variable + values are raw HTML. + + \section1 Alphabetical List + + \l {24-qdoc-configuration-htmlvariables.html#HTML.footer}{HTML.footer}, + \l {24-qdoc-configuration-htmlvariables.html#HTML.postheader} + {HTML.postheader}, + \l {24-qdoc-configuration-htmlvariables.html#HTML.style}{HTML.style}, + \l {24-qdoc-configuration-htmlvariables.html#HTML.stylesheets}{HTML.stylesheets} + + + \section1 Variable Descriptions + + \table + + \header + \o Variable + \o Description + + \row + \o \bold HTML.footer \target HTML.footer + \o \bold {The \c HTML.footer variable defines the content + of the generated HTML documentation's footer.} + + The footer is rendered at the bottom of the generated + documentation page. + + The variable's value is given as raw HTML code enclosed by + quotation marks. Note that if the value spans several + lines, each line needs to be enclosed by quotation marks. + + For example in \l qt.qdocconf: + + \code + HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \ + ... + "</tr></table></div></address>" + \endcode + + The complete variable entry in \l qt.qdocconf provides the + standard footer of the \l + {http://qt.nokia.com/doc/4.0/index.html}{Qt Reference + Documentation}. + + \row + \o \bold HTML.postheader \target HTML.postheader + \o \bold {The \c HTML.postheader variable defines the content + of the generated HTML documentation's postheader.} + + The header is rendered at the top of the generated + documentation page. + + The variable's value is given as raw HTML enclosed by + quotation marks. Note that if the value spans several + lines, each line needs to be enclosed by quotation marks. + + For example in \l qt.qdocconf: + + \code + HTML.postheader = "<table border=\"0\"..." \ + ... + "<img src=\"images/trolltech-logo.png\" \ + "align=\"right\" width=\"203\" height=\"32\""\ + "border=\"0\" />" \ + "</td></tr>" \ + "</table>" + \endcode + + The complete variable entry in \l qt.qdocconf provides the + standard header of the \l + {http://qt.nokia.com/doc/4.0/index.html}{Qt Reference + Documentation}. + + \row + \o \bold HTML.style \target HTML.style + \o \bold {The HTML.style variable defines the style for + the generated HTML documentation.} + + The variable's value is given as raw HTML enclosed by + quotation marks. Note that if the value spans several + lines, each line needs to be enclosed by quotation marks. + + For example in \l qt.qdocconf: + + \code + HTML.style = "h3.fn,span.fn" \ + "{ margin-left: 1cm; text-indent: -1cm; }\n" \ + "a:link { color: #004faf; text-decoration: none }\n" \ + "a:visited" \ + "{ color: #672967; text-decoration: none }\n" \ + "td.postheader { font-family: sans-serif }\n" \ + "tr.address { font-family: sans-serif }\n" \ + "body { background: #ffffff; color: black; }" + \endcode + + provides the HTML style for the \l + {http://qt.nokia.com/doc/4.0/index.html}{Qt Reference + Documentation}. + + \row + \o \bold HTML.stylesheets \target HTML.stylesheets + \o \bold {The HTML.stylesheets variable defines a list of stylesheets + to use for the generated HTML documentation.} + + Using separate stylesheets for the documentation makes it easier to + customize and experiment with the style used once the contents has + been generated. Typically, it is only necessary to define a single + stylesheet for any set of documentation; for example: + + \code + HTML.stylesheets = classic.css + \endcode + + QDoc expects to find stylesheets in the directory containing the + \l qt.qdocconf file, and it will copy those specified to the output + directory alongside the HTML pages. + \endtable +*/ + +/*! + \page 25-qdoc-configuration-derivedprojects.html + \previouspage HTML Specific Configuration Variables + \contentspage QDoc Manual - Table of Contents + \nextpage QDoc Compatibility + + \title Supporting Derived Projects + + \tableofcontents + + Some particular configuration variables allow you to use QDoc to + support Qt-based projects; i.e to make projects, such as Qt Solutions, + contain references to the online Qt documentation. This + means that QDoc will be able to create links to the class reference + documentation, without any explicit linking command. + + \section1 The Configuration Variables + + \section2 Alphabetical List + + \l{25-qdoc-configuration-derivedprojects.html#description}{description}, + \l{25-qdoc-configuration-derivedprojects.html#indexes}{indexes}, + \l{25-qdoc-configuration-derivedprojects.html#project}{project}, + \l{25-qdoc-configuration-derivedprojects.html#url}{url} + + \section2 Variable Descriptions + + \table + \header + \o Variable + \o Description + \row + \o \bold description \target description + \o \bold {The description variable holds a short description of + the associated project.} + + See also \l project. + + \row + \o \bold indexes \target indexes + \o \bold {The \c indexes variable lists the index files + that will be used to generate references.} + + For example. to make a derived Qt project contain links to + the Qt Reference documentation, you need to specify the + associated index file: + + \code + indexes = $QTDIR/doc/html/qt.index + \endcode + + See also \l project and \l url. + + \row + \o \bold project \target project + \o \bold {The \c project variable provides a name for the project + associated with the \c .qdocconf file.} + + The project's name is used to form a file name for the + associated project's \i index file. For example: + + \code + project = QtMotif + \endcode + + This will cause an index file called \c qtmotif.index to be + created. + + See also \l description and \l indexes. + \row + \o \bold url \target url + \o \bold {The \c url variable holds the base URL for the + reference documentation associated with the current project.} + + The URL is stored in the generated index file for the + project. When we use the index on its own, QDoc will use + this as the base URL when constructing links to classes, + functions, and other things listed in the index. + + For example: + + \code + project = Qt + description = Qt Reference Documentation + url = http://qt.nokia.com/doc/4.0 + + ... + \endcode + + This makes sure that whenever \c qt.index is used to generate + references to for example Qt classes, the base URL is + \c http://qt.nokia.com/doc/4.0. + + See also \l indexes. + + \endtable + + \target howto + \section1 How to Support Derived Projects + + This feature makes use of the comprehensive indexes generated by + QDoc when it creates the Qt reference documentation. + + For example, \l qt.qdocconf (the configuration file for Qt) + contains the following variable definitions: + + \code + project = Qt + description = Qt Reference Documentation + url = http://qt.nokia.com/doc/4.0 + + ... + \endcode + + The \l project variable name is used to form a file name for the + index file; in this case the \c qt.index file is created. The \l + url is stored in the index file. Later, when we use the index on + its own, QDoc will use this as the base URL when constructing + links to classes, functions, and other things listed in the index. + + In a mini-project, you can use an index file by defining an \l + indexes configuration variable in your \c .qdocconf file. + + For example, you can create a \c qtmotif.qdocconf file to help you + check the QtMotif documentation (which is part of Qt Solutions): + + \code + include($QTDIR/tools/qdoc3/test/compat.qdocconf) + + project = QtMotif + description = QtMotif Class Documentation + url = http://www.trolltech.com/products/solutions/catalog/4/Migration/qtmotifextension + + indexes = $QTDIR/doc/html/qt.index + + outputdir = html + + headerdirs = src + sourcedirs = src \ + examples + sources.fileextensions = "*.cpp *.qdoc *.doc" + + exampledirs = examples + \endcode + + The code above requires that you run QDoc from the directory that + contains this file. You need to include the compat.qdocconf + file for compatibility reasons; this is further explained in the + \l {QDoc Compatibility} section. + + \bold {To resolve the actual links to Qt classes, the + mini-project's \c .qdocconf file needs to assign a value to the \l + indexes variable; \c $QTDIR/doc/html/qt.index makes sure that you + always use the updated index file for the Qt documentation.} + + The only disadvantages with this approach are the extra file that + QDoc has to generate and the time it takes to do so. Reading the + index back again later isn't instantaneous either, but it's + quicker than processing all the Qt classes each time you need to + write a new document. +*/ + +/*! + \page 26-qdoc-commands-compatibility.html + \previouspage Supporting Derived Projects + \contentspage QDoc Manual - Table of Contents + \nextpage QDoc Commands - Alphabetical List + + \title QDoc Compatibility + + \tableofcontents + + \section1 General Description + + \target reason + + QDoc is a tool that constantly evolves to suit our needs, for that + reason there are some compatibility issues in the transition + between old and new practices. + + To make the transition as smooth and rapid as possible, the + general idea is to adopt the new commands and usage in new + documentation. While waiting for the occurrences of the old + practices to be eliminated from the old parts of the + documentation, you can map the new commands and usage to the old + ones using a compat.qdocconf file. + + A compat.qdocconf file is a separate \c .qdocconf file which you + can include in your main configuration file. It typically contains + the mapping between old and new commands using the \l alias and \l + {22-qdoc-configuration-generalvariables.html#macro}{macro} + configuration variables. + + \section1 Qt Compatibility + + In Qt's documentation there still exist occurrences of old + commands, and the Qt \l {qt.qdocconf}{configuration file} needs to + include the compat.qdocconf file tailored for Qt. For more + detailed information about the commands creating compatibility + issues, see the \l {Command Comments}{command comments}. + + \section2 Qt's current compat.qdocconf file + + \quotefile files/compat.qdocconf + + \section2 Command Comments + + \table + \header + \o New Command + \o Old Command + \o Description + + \row + \o \\i \target i-versus-e + \o \\e + \o Earlier we + used the \\i command to indicate a list or table item, and + the \\e command for rendering in italic. Now we want the + \\i command to render in italic discarding the + \\e command name. + + \bold {We still need to use the \\e command to render in + italic in new documentation for \l {reason}{compatibility + reasons}}. + + \row + \o \\include \target include-versus-input + \o \\input + \o The \\include command was previously used to quote the + complete contents of a source file, now we want to use the + command to include separate documentation. + That is the functionality of the old \\input command + which name we want to discard. + + \bold {We still need to use the \\input command to include + plain text in new documentation for \l + {reason}{compatibility reasons}}. + + \row + \o \\quotefile \target quotefile-versus-include + \o \\include + \o Earlier, we have used the \\quotefile command to + quote from file, i.e. quote parts from file, and the + \\include command to quote the entire file. Since we now want + \\include to include separate documentation, we change the use of + \\quotefile to quote a complete source file. + + \bold {We still need to use the \\include command to quote + the entire contents of a source file in new documentation + for \l {reason}{compatibility reasons}}. + + \row + \o \\quotefromfile \target quotefromfile-versus-quotefile + \o \\quotefile + \o Earlier, we have used the \\quotefile command to + quote from file, i.e. quote parts from file. Since we now want + that command to quote an entire file, we introduce the new + \\quotefromfile command to quote from file. + + \bold {Use \l {quotefromfile}{\\quotefromfile} to quote + parts from a source file in new documentation}. + + \row + \o \\o \target o-versus-i + \o \\i + \o Earlier we used the \\i command to indicate list items + and table items. Since we now want the \\i command to render + in italic instead, we introduce the new \\o command for + this purpose. + + \bold {Use \l {o}{\\o} to indicate list and table items in + new documentation}. + + \row + \o \\quotation \target quotation-versus-quote + \o \\quote + \o These commands are equivalent, and represent a simple name + change. + + \bold {Use \l {quotation}{\\quotation} in new + documentation}. + + \row + \o \\image \target image-versus-img + \o \\img + \o These commands are equivalent, and represent a simple name + change. + + \bold {Use \l {image}{\\image} in new documentation}. + + \endtable +*/ + +/*! + \page 27-qdoc-commmands-alphabetical.html + \previouspage QDoc Compatibility + \contentspage QDoc Manual - Table of Contents + + \title QDoc Commands - Alphabetical List + + \list + + \o \l {04-qdoc-commands-textformatting.html#a}{\\a} + \o \l {11-qdoc-commands-documentcontents.html#abstract}{\\abstract} + \o \l {06-qdoc-commands-verbatimcode.html#badcode}{\\badcode} + \o \l {04-qdoc-commands-textformatting.html#bold}{\\bold} + \o \l {11-qdoc-commands-documentcontents.html#brief}{\\brief} + \o \l {04-qdoc-commands-textformatting.html#c}{\\c} + \o \l {09-qdoc-commands-graphic.html#caption}{\\caption} + \o \l {05-qdoc-commands-documentstructuring.html#chapter}{\\chapter} + \o \l {13-qdoc-commands-topical.html#class}{\\class} + \o \l {06-qdoc-commands-verbatimcode.html#code}{\\code} + \o \l {07-0-qdoc-commands-quoting.html#codeline}{\\codeline}, + \o \l {16-qdoc-commands-status.html#compat}{\\compat} + \o \l {15-qdoc-commands-navigation.html#contentspage}{\\contentspage} + \o \l {07-0-qdoc-commands-quoting.html#dots}{\\dots} + \o \l {12-0-qdoc-commands-miscellaneous.html#else}{\\else} + \o \l {12-0-qdoc-commands-miscellaneous.html#endif}{\\endif} + \o \l {13-qdoc-commands-topical.html#enum}{\\enum} + \o \l {13-qdoc-commands-topical.html#example-command}{\\example} + \o \l {12-0-qdoc-commands-miscellaneous.html#expire}{\\expire} + \o \l {13-qdoc-commands-topical.html#externalpage}{\\externalpage} + \o \l {13-qdoc-commands-topical.html#fn}{\\fn} + \o \l {11-qdoc-commands-documentcontents.html#footnote}{\\footnote} + \o \l {12-0-qdoc-commands-miscellaneous.html#generatelist}{\\generatelist} + \o \l {13-qdoc-commands-topical.html#group}{\\group} + \o \l {10-qdoc-commands-container.html#header}{\\header} + \o \l {13-qdoc-commands-topical.html#headerfile}{\\headerfile} + \o \l {04-qdoc-commands-textformatting.html#i}{\\i} + \o \l {12-0-qdoc-commands-miscellaneous.html#if}{\\if} + \o \l {09-qdoc-commands-graphic.html#image}{\\image} + \o \l {12-0-qdoc-commands-miscellaneous.html#include}{\\include} + \o \l {15-qdoc-commands-navigation.html#indexpage}{\\indexpage} + \o \l {19-qdoc-commands-grouping.html#ingroup}{\\ingroup} + \o \l {19-qdoc-commands-grouping.html#inmodule}{\\inmodule} + \o \l {09-qdoc-commands-graphic.html#inlineimage}{\\inlineimage} + \o \l {16-qdoc-commands-status.html#internal}{\\internal} + \o \l {08-qdoc-commands-linking.html#keyword}{\\keyword} + \o \l {08-qdoc-commands-linking.html#l}{\\l} + \o \l {11-qdoc-commands-documentcontents.html#legalese}{\\legalese} + \o \l {10-qdoc-commands-container.html#list}{\\list} + \o \l {13-qdoc-commands-topical.html#macro}{\\macro} + \o \l {19-qdoc-commands-grouping.html#mainclass}{\\mainclass} + \o \l {12-0-qdoc-commands-miscellaneous.html#meta}{\\meta} + \o \l {13-qdoc-commands-topical.html#module}{\\module} + \o \l {13-qdoc-commands-topical.html#namespace}{\\namespace} + \o \l {15-qdoc-commands-navigation.html#nextpage}{\\nextpage} + \o \l {06-qdoc-commands-verbatimcode.html#newcode}{\\newcode} + \o \l {17-qdoc-commands-thread.html#nonreentrant}{\\nonreentrant} + \o \l {10-qdoc-commands-container.html#o}{\\o} + \o \l {16-qdoc-commands-status.html#obsolete}{\\obsolete} + \o \l {06-qdoc-commands-verbatimcode.html#oldcode}{\\oldcode} + \o \l {12-0-qdoc-commands-miscellaneous.html#omit}{\\omit} + \o \l {10-qdoc-commands-container.html#omitvalue}{\\omitvalue} + \o \l {18-qdoc-commands-relating.html#overload}{\\overload} + \o \l {13-qdoc-commands-topical.html#page}{\\page} + \o \l {05-qdoc-commands-documentstructuring.html#part}{\\part} + \o \l {16-qdoc-commands-status.html#preliminary}{\\preliminary} + \o \l {15-qdoc-commands-navigation.html#previouspage}{\\previouspage} + \o \l {07-0-qdoc-commands-quoting.html#printline}{\\printline} + \o \l {07-0-qdoc-commands-quoting.html#printto}{\\printto} + \o \l {07-0-qdoc-commands-quoting.html#printuntil}{\\printuntil} + \o \l {13-qdoc-commands-topical.html#property}{\\property} + \o \l {11-qdoc-commands-documentcontents.html#quotation}{\\quotation} + \o \l {07-0-qdoc-commands-quoting.html#quotefile}{\\quotefile} + \o \l {07-0-qdoc-commands-quoting.html#quotefromfile}{\\quotefromfile} + \o \l {12-0-qdoc-commands-miscellaneous.html#raw}{\\raw} + \o \l {17-qdoc-commands-thread.html#reentrant}{\\reentrant} + \o \l {18-qdoc-commands-relating.html#reimp}{\\reimp} + \o \l {18-qdoc-commands-relating.html#relates}{\\relates} + \o \l {10-qdoc-commands-container.html#row}{\\row} + \o \l {08-qdoc-commands-linking.html#sa}{\\sa} + \o \l {05-qdoc-commands-documentstructuring.html#sectionOne}{\\section1} + \o \l {05-qdoc-commands-documentstructuring.html#sectionTwo}{\\section2} + \o \l {05-qdoc-commands-documentstructuring.html#sectionThree}{\\section3} + \o \l {05-qdoc-commands-documentstructuring.html#sectionFour}{\\section4} + \o \l {13-qdoc-commands-topical.html#service}{\\service} + \o \l {16-qdoc-commands-status.html#since}{\\since} + \o \l {07-0-qdoc-commands-quoting.html#skipline}{\\skipline} + \o \l {07-0-qdoc-commands-quoting.html#skipto}{\\skipto} + \o \l {07-0-qdoc-commands-quoting.html#skipuntil}{\\skipuntil} + \o \l {07-0-qdoc-commands-quoting.html#snippet}{\\snippet}, + \o \l {15-qdoc-commands-navigation.html#startpage}{\\startpage} + \o \l {04-qdoc-commands-textformatting.html#sub}{\\sub} + \o \l {20-qdoc-commands-title.html#subtitle}{\\subtitle} + \o \l {04-qdoc-commands-textformatting.html#sup}{\\sup} + \o \l {10-qdoc-commands-container.html#table}{\\table} + \o \l {11-qdoc-commands-documentcontents.html#tableofcontents} + {\\tableofcontents} + \o \l {08-qdoc-commands-linking.html#target}{\\target} + \o \l {17-qdoc-commands-thread.html#threadsafe}{\\threadsafe} + \o \l {20-qdoc-commands-title.html#title}{\\title} + \o \l {04-qdoc-commands-textformatting.html#tt}{\\tt} + \o \l {13-qdoc-commands-topical.html#typedef}{\\typedef} + \o \l {04-qdoc-commands-textformatting.html#underline}{\\underline} + \o \l {13-qdoc-commands-topical.html#variable}{\\variable} + \o \l {10-qdoc-commands-container.html#value}{\\value} + \o \l {11-qdoc-commands-documentcontents.html#warning}{\\warning} + \endlist +*/ + +/*! + \externalpage http://qt.nokia.com/about + \title About Qt +*/ diff --git a/tools/qdoc3/doc/qdoc-manual.qdocconf b/tools/qdoc3/doc/qdoc-manual.qdocconf new file mode 100644 index 0000000..26fd09c --- /dev/null +++ b/tools/qdoc3/doc/qdoc-manual.qdocconf @@ -0,0 +1,49 @@ +project = QDoc +description = QDoc3 Manual + +indexes = $QTDIR/doc/html/qt.index + +outputdir = html + +sources = qdoc-manual.qdoc +sourcedirs = $PWD + +exampledirs += $PWD \ + $QTDIR/examples + +imagedirs += images + +extraimages.HTML = qt-logo + +HTML.stylesheets = classic.css + +HTML.style = "h3.fn,span.fn { margin-left: 1cm; text-indent: -1cm; }\n" \ + "a:link { color: #004faf; text-decoration: none }\n" \ + "a:visited { color: #672967; text-decoration: none }\n" \ + "td.postheader { font-family: sans-serif }\n" \ + "tr.address { font-family: sans-serif }\n" \ + "body { background: #ffffff; color: black; }" + +HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"5\" width=\"100%\">\n" \ + "<tr>\n" \ + "<td align=\"left\" valign=\"top\" width=\"32\">" \ + "<a href=\"http://qt.nokia.com/\"><img src=\"images/qt-logo.png\" align=\"left\" border=\"0\" /></a>" \ + "</td>\n" \ + "<td class=\"postheader\" valign=\"center\">" \ + "<a href=\"01-qdoc-manual.html\">" \ + "<font color=\"#004faf\">Home: QDoc Manual</font></a> ·" \ + "<a href=\"http://qt.nokia.com/doc/4.7\">" \ + "<font color=\"#004faf\"> Qt Reference Documentation</font></a>" \ + "</td>\n" \ + "</tr></table>" + +HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \ + "<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \ + "<td width=\"40%\" align=\"left\">Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)</td>\n" \ + "<td width=\"20%\" align=\"center\"><a href=\"trademarks.html\">Trademarks</a></td>\n" \ + "<td width=\"40%\" align=\"right\"><div align=\"right\">Qt \\version</div></td>\n" \ + "</tr></table></div></address>" + +spurious += "Missing '\\}'" +spurious += "Cannot use .*" +spurious += "Unexpected .*" diff --git a/tools/qdoc3/generator.cpp b/tools/qdoc3/generator.cpp index 9b58d7f..24219a1 100644 --- a/tools/qdoc3/generator.cpp +++ b/tools/qdoc3/generator.cpp @@ -42,7 +42,6 @@ /* generator.cpp */ -#include <QtCore> #include <qdir.h> #include <qdebug.h> #include "codemarker.h" @@ -67,6 +66,10 @@ QStringList Generator::imageFiles; QStringList Generator::imageDirs; QStringList Generator::exampleDirs; QStringList Generator::exampleImgExts; +QStringList Generator::scriptFiles; +QStringList Generator::scriptDirs; +QStringList Generator::styleFiles; +QStringList Generator::styleDirs; QString Generator::outDir; QString Generator::project; @@ -125,10 +128,20 @@ void Generator::initialize(const Config &config) if (!dirInfo.mkdir(outDir + "/images/used-in-examples")) config.lastLocation().fatal(tr("Cannot create output directory '%1'") .arg(outDir + "/images/used-in-examples")); + if (!dirInfo.mkdir(outDir + "/scripts")) + config.lastLocation().fatal(tr("Cannot create output directory '%1'") + .arg(outDir + "/scripts")); + if (!dirInfo.mkdir(outDir + "/style")) + config.lastLocation().fatal(tr("Cannot create output directory '%1'") + .arg(outDir + "/style")); } imageFiles = config.getStringList(CONFIG_IMAGES); imageDirs = config.getStringList(CONFIG_IMAGEDIRS); + scriptFiles = config.getStringList(CONFIG_SCRIPTS); + scriptDirs = config.getStringList(CONFIG_SCRIPTDIRS); + styleFiles = config.getStringList(CONFIG_STYLES); + styleDirs = config.getStringList(CONFIG_STYLEDIRS); exampleDirs = config.getStringList(CONFIG_EXAMPLEDIRS); exampleImgExts = config.getStringList(CONFIG_EXAMPLES + Config::dot + CONFIG_IMAGEEXTENSIONS); @@ -166,6 +179,47 @@ void Generator::initialize(const Config &config) "/images"); ++e; } + + QStringList noExts; + QStringList scripts = + config.getStringList(CONFIG_SCRIPTS+Config::dot+(*g)->format()); + e = scripts.begin(); + while (e != scripts.end()) { + QString userFriendlyFilePath; + QString filePath = Config::findFile(config.lastLocation(), + scriptFiles, + scriptDirs, + *e, + noExts, + userFriendlyFilePath); + if (!filePath.isEmpty()) + Config::copyFile(config.lastLocation(), + filePath, + userFriendlyFilePath, + (*g)->outputDir() + + "/scripts"); + ++e; + } + + QStringList styles = + config.getStringList(CONFIG_STYLES+Config::dot+(*g)->format()); + e = styles.begin(); + while (e != styles.end()) { + QString userFriendlyFilePath; + QString filePath = Config::findFile(config.lastLocation(), + styleFiles, + styleDirs, + *e, + noExts, + userFriendlyFilePath); + if (!filePath.isEmpty()) + Config::copyFile(config.lastLocation(), + filePath, + userFriendlyFilePath, + (*g)->outputDir() + + "/style"); + ++e; + } } ++g; } @@ -227,6 +281,7 @@ void Generator::terminate() imageFiles.clear(); imageDirs.clear(); outDir = ""; + QmlClassNode::clear(); } Generator *Generator::generatorForFormat(const QString& format) @@ -322,11 +377,11 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) bool quiet = false; if (node->type() == Node::Function) { -#if 0 +#if 0 const FunctionNode *func = (const FunctionNode *) node; if (func->isOverload() && func->metaness() != FunctionNode::Ctor) generateOverload(node, marker); -#endif +#endif } else if (node->type() == Node::Fake) { const FakeNode *fake = static_cast<const FakeNode *>(node); @@ -347,7 +402,7 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) if (func->reimplementedFrom() != 0) generateReimplementedFrom(func, marker); } - + if (!generateText(node->doc().body(), node, marker)) if (node->isReimp()) return; @@ -452,7 +507,7 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) // Now we put this at the top, before the other text. if (func->reimplementedFrom() != 0) generateReimplementedFrom(func, marker); -#endif +#endif } } @@ -544,7 +599,7 @@ void Generator::generateInheritedBy(const ClassNode *classe, example is being formatted. It outputs the list of source files comprising the example, and the list of images used by the example. The images are copied into a subtree of - \c{...doc/html/images/used-in-examples/...} + \c{...doc/html/images/used-in-examples/...} */ void Generator::generateFileList(const FakeNode* fake, CodeMarker* marker, @@ -641,33 +696,6 @@ void Generator::generateExampleFiles(const FakeNode *fake, CodeMarker *marker) } #endif -void Generator::generateModuleWarning(const ClassNode *classe, - CodeMarker *marker) -{ - QString module = classe->moduleName(); - if (!module.isEmpty()) { - Text text; - if (!editionModuleMap["DesktopLight"].contains(module)) { - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) - << "This class is not part of the Qt GUI Framework Edition." - << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) - << Atom::ParaRight; - } - else if (module == "Qt3Support") { - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) - << "Note to Qt GUI Framework Edition users:" - << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) - << " This class is only available in the " - << Atom(Atom::AutoLink, "Qt Full Framework Edition") - << "." << Atom::ParaRight; - } - - generateText(text, classe, marker); - } -} - QString Generator::indent(int level, const QString& markedCode) { if (level == 0) @@ -973,7 +1001,7 @@ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker) } ++c; } - if (!exceptions) + if (!exceptions) text << "."; else if (threadSafeness == Node::Reentrant) { if (nonreentrant.isEmpty()) { @@ -1060,7 +1088,7 @@ void Generator::generateOverload(const Node *node, CodeMarker *marker) text << Atom::ParaLeft << "This function overloads "; QString t = node->name() + "()"; - text << Atom::AutoLink << t + text << Atom::AutoLink << t << Atom::ParaRight; generateText(text, node, marker); } @@ -1213,6 +1241,35 @@ void Generator::appendSortedNames(Text& text, } } +void Generator::appendSortedQmlNames(Text& text, + const Node* base, + const NodeList& subs, + CodeMarker *marker) +{ + QMap<QString,Text> classMap; + int index = 0; + +#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES + qDebug() << "Generator::appendSortedQmlNames():" << base->name() << "is inherited by..."; +#endif + for (int i = 0; i < subs.size(); ++i) { + Text t; +#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES + qDebug() << " " << subs[i]->name(); +#endif + appendFullName(t, subs[i], base, marker); + classMap[t.toString().toLower()] = t; + } + + QStringList names = classMap.keys(); + names.sort(); + + foreach (const QString &name, names) { + text << classMap[name]; + text << separator(index++, names.count()); + } +} + int Generator::skipAtoms(const Atom *atom, Atom::Type type) const { int skipAhead = 0; diff --git a/tools/qdoc3/generator.h b/tools/qdoc3/generator.h index 06f7f88..326a247 100644 --- a/tools/qdoc3/generator.h +++ b/tools/qdoc3/generator.h @@ -124,7 +124,6 @@ class Generator Node::SubType subtype, const QString& tag); void generateExampleFiles(const FakeNode *fake, CodeMarker *marker); - void generateModuleWarning(const ClassNode *classe, CodeMarker *marker); virtual int skipAtoms(const Atom *atom, Atom::Type type) const; virtual QString fullName(const Node *node, @@ -170,6 +169,13 @@ class Generator const QList<RelatedClass> &classes, CodeMarker *marker); + protected: + void appendSortedQmlNames(Text& text, + const Node* base, + const NodeList& subs, + CodeMarker *marker); + + private: QString amp; QString lt; QString gt; @@ -185,6 +191,10 @@ class Generator static QStringList imageDirs; static QStringList exampleDirs; static QStringList exampleImgExts; + static QStringList scriptFiles; + static QStringList scriptDirs; + static QStringList styleFiles; + static QStringList styleDirs; static QString outDir; static QString project; }; diff --git a/tools/qdoc3/helpprojectwriter.cpp b/tools/qdoc3/helpprojectwriter.cpp index 2189e02..edba097 100644 --- a/tools/qdoc3/helpprojectwriter.cpp +++ b/tools/qdoc3/helpprojectwriter.cpp @@ -39,9 +39,9 @@ ** ****************************************************************************/ -#include <QtXml> #include <QHash> #include <QMap> +#include <qdebug.h> #include "atom.h" #include "helpprojectwriter.h" @@ -117,6 +117,11 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList typeHash["property"] = Node::Property; typeHash["variable"] = Node::Variable; typeHash["target"] = Node::Target; +#ifdef QDOC_QML + typeHash["qmlproperty"] = Node::QmlProperty; + typeHash["qmlsignal"] = Node::QmlSignal; + typeHash["qmlmethod"] = Node::QmlMethod; +#endif QHash<QString, Node::SubType> subTypeHash; subTypeHash["example"] = Node::Example; @@ -128,6 +133,8 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList subTypeHash["externalpage"] = Node::ExternalPage; #ifdef QDOC_QML subTypeHash["qmlclass"] = Node::QmlClass; + subTypeHash["qmlpropertygroup"] = Node::QmlPropertyGroup; + subTypeHash["qmlbasictype"] = Node::QmlBasicType; #endif QSet<Node::SubType> allSubTypes = QSet<Node::SubType>::fromList(subTypeHash.values()); @@ -177,7 +184,13 @@ QStringList HelpProjectWriter::keywordDetails(const Node *node) const { QStringList details; - if (node->parent() && !node->parent()->name().isEmpty()) { + if (node->type() == Node::QmlProperty) { + // "name" + details << node->name(); + // "id" + details << node->parent()->parent()->name()+"::"+node->name(); + } + else if (node->parent() && !node->parent()->name().isEmpty()) { // "name" if (node->type() == Node::Enum || node->type() == Node::Typedef) details << node->parent()->name()+"::"+node->name(); @@ -185,29 +198,29 @@ QStringList HelpProjectWriter::keywordDetails(const Node *node) const details << node->name(); // "id" details << node->parent()->name()+"::"+node->name(); - } else if (node->type() == Node::Fake) { + } + else if (node->type() == Node::Fake) { const FakeNode *fake = static_cast<const FakeNode *>(node); -#ifdef QDOC_QML if (fake->subType() == Node::QmlClass) { details << (QmlClassNode::qmlOnly ? fake->name() : fake->fullTitle()); details << "QML." + fake->name(); - } else -#endif - { + } + else { details << fake->fullTitle(); details << fake->fullTitle(); } - } else { + } + else { details << node->name(); details << node->name(); } details << tree->fullDocumentLocation(node); - return details; } bool HelpProjectWriter::generateSection(HelpProject &project, - QXmlStreamWriter & /* writer */, const Node *node) + QXmlStreamWriter & /* writer */, + const Node *node) { if (!node->url().isEmpty()) return false; @@ -226,9 +239,10 @@ bool HelpProjectWriter::generateSection(HelpProject &project, if (node->type() == Node::Fake) { const FakeNode *fake = static_cast<const FakeNode *>(node); objName = fake->fullTitle(); - } else + } + else objName = tree->fullDocumentName(node); - + // Only add nodes to the set for each subproject if they match a selector. // Those that match will be listed in the table of contents. @@ -290,6 +304,9 @@ bool HelpProjectWriter::generateSection(HelpProject &project, break; case Node::Property: + case Node::QmlProperty: + case Node::QmlSignal: + case Node::QmlMethod: project.keywords.append(keywordDetails(node)); break; @@ -400,7 +417,7 @@ void HelpProjectWriter::generateSections(HelpProject &project, { if (!generateSection(project, writer, node)) return; - + if (node->isInnerNode()) { const InnerNode *inner = static_cast<const InnerNode *>(node); @@ -409,8 +426,23 @@ void HelpProjectWriter::generateSections(HelpProject &project, foreach (const Node *node, inner->childNodes()) { if (node->access() == Node::Private) continue; - if (node->type() == Node::Fake) - childMap[static_cast<const FakeNode *>(node)->fullTitle()] = node; + if (node->type() == Node::Fake) { + /* + Don't visit QML property group nodes, + but visit their children, which are all + QML property nodes. + */ + if (node->subType() == Node::QmlPropertyGroup) { + const InnerNode* inner = static_cast<const InnerNode*>(node); + foreach (const Node* n, inner->childNodes()) { + if (n->access() == Node::Private) + continue; + childMap[tree->fullDocumentName(n)] = n; + } + } + else + childMap[static_cast<const FakeNode *>(node)->fullTitle()] = node; + } else { if (node->type() == Node::Function) { const FunctionNode *funcNode = static_cast<const FunctionNode *>(node); diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index a3cdae6..dda2cf3 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -44,6 +44,7 @@ */ #include "codemarker.h" +#include "codeparser.h" #include "helpprojectwriter.h" #include "htmlgenerator.h" #include "node.h" @@ -54,10 +55,12 @@ #include <qdebug.h> #include <qlist.h> #include <qiterator.h> +#include <qtextcodec.h> QT_BEGIN_NAMESPACE #define COMMAND_VERSION Doc::alias("version") +int HtmlGenerator::id = 0; QString HtmlGenerator::sinceTitles[] = { @@ -71,6 +74,7 @@ QString HtmlGenerator::sinceTitles[] = " New Typedefs", " New Properties", " New Variables", + " New QML Elements", " New Qml Properties", " New Qml Signals", " New Qml Methods", @@ -201,10 +205,18 @@ static void addLink(const QString &linkTarget, HtmlGenerator::HtmlGenerator() - : helpProjectWriter(0), inLink(false), inContents(false), - inSectionHeading(false), inTableHeader(false), numTableRows(0), - threeColumnEnumValueTable(true), funcLeftParen("\\S(\\()"), - myTree(0), slow(false), obsoleteLinks(false) + : helpProjectWriter(0), + inLink(false), + inContents(false), + inSectionHeading(false), + inTableHeader(false), + numTableRows(0), + threeColumnEnumValueTable(true), + offlineDocs(true), + funcLeftParen("\\S(\\()"), + myTree(0), + slow(false), + obsoleteLinks(false) { } @@ -248,6 +260,9 @@ void HtmlGenerator::initializeGenerator(const Config &config) postHeader = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_POSTHEADER); + postPostHeader = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_POSTPOSTHEADER); footer = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_FOOTER); @@ -259,13 +274,22 @@ void HtmlGenerator::initializeGenerator(const Config &config) HTMLGENERATOR_GENERATEMACREFS); project = config.getString(CONFIG_PROJECT); - + offlineDocs = !config.getBool(CONFIG_ONLINE); projectDescription = config.getString(CONFIG_DESCRIPTION); if (projectDescription.isEmpty() && !project.isEmpty()) projectDescription = project + " Reference Documentation"; projectUrl = config.getString(CONFIG_URL); + outputEncoding = config.getString(CONFIG_OUTPUTENCODING); + if (outputEncoding.isEmpty()) + outputEncoding = QLatin1String("ISO-8859-1"); + outputCodec = QTextCodec::codecForName(outputEncoding.toLocal8Bit()); + + naturalLanguage = config.getString(CONFIG_NATURALLANGUAGE); + if (naturalLanguage.isEmpty()) + naturalLanguage = QLatin1String("en"); + QSet<QString> editionNames = config.subVars(CONFIG_EDITION); QSet<QString>::ConstIterator edition = editionNames.begin(); while (edition != editionNames.end()) { @@ -321,6 +345,7 @@ QString HtmlGenerator::format() */ void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker) { +#if 0 // Copy the stylesheets from the directory containing the qdocconf file. // ### This should be changed to use a special directory in doc/src. QStringList::ConstIterator styleIter = stylesheets.begin(); @@ -330,7 +355,7 @@ void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker) Config::copyFile(Location(), filePath, filePath, outputDir()); ++styleIter; } - +#endif myTree = tree; nonCompatClasses.clear(); mainClasses.clear(); @@ -389,9 +414,9 @@ void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker) "qmake Manual", dcfQmakeRoot); - generateIndex(project.toLower().simplified().replace(" ", "-"), - projectUrl, - projectDescription); + QString fileBase = project.toLower().simplified().replace(" ", "-"); + generateIndex(fileBase, projectUrl, projectDescription); + generatePageIndex(outputDir() + "/" + fileBase + ".pageindex", marker); helpProjectWriter->generate(myTree); } @@ -431,11 +456,11 @@ int HtmlGenerator::generateAtom(const Atom *atom, endLink(); } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } break; case Atom::BaseName: @@ -483,7 +508,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::C: out() << formattingLeftMap()[ATOM_FORMATTING_TELETYPE]; if (inLink) { - out() << protect(plainCode(atom->string())); + out() << protectEnc(plainCode(atom->string())); } else { out() << highlightedCode(atom->string(), marker, relative); @@ -491,14 +516,14 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << formattingRightMap()[ATOM_FORMATTING_TELETYPE]; break; case Atom::Code: - out() << "<pre>" + out() << "<pre class=\"highlightedCode\">" << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), marker,relative)) << "</pre>\n"; break; #ifdef QDOC_QML case Atom::Qml: - out() << "<pre>" + out() << "<pre class=\"highlightedCode\">" << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), marker,relative)) << "</pre>\n"; @@ -506,7 +531,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, #endif case Atom::CodeNew: out() << "<p>you can rewrite it as</p>\n" - << "<pre>" + << "<pre class=\"highlightedCode\">" << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), marker,relative)) << "</pre>\n"; @@ -515,9 +540,9 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << "<p>For example, if you have code like</p>\n"; // fallthrough case Atom::CodeBad: - out() << "<pre><font color=\"#404040\">" - << trimmedTrailing(protect(plainCode(indent(codeIndent,atom->string())))) - << "</font></pre>\n"; + out() << "<pre class=\"highlightedCode\">" + << trimmedTrailing(protectEnc(plainCode(indent(codeIndent,atom->string())))) + << "</pre>\n"; break; case Atom::FootnoteLeft: // ### For now @@ -574,7 +599,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, generateAnnotatedList(relative, marker, nonCompatClasses); } else if (atom->string() == "classes") { - generateCompactList(relative, marker, nonCompatClasses); + generateCompactList(relative, marker, nonCompatClasses, true); } else if (atom->string().contains("classesbymodule")) { QString arg = atom->string().trimmed(); @@ -622,10 +647,10 @@ int HtmlGenerator::generateAtom(const Atom *atom, generateClassHierarchy(relative, marker, nonCompatClasses); } else if (atom->string() == "compatclasses") { - generateCompactList(relative, marker, compatClasses); + generateCompactList(relative, marker, compatClasses, false); } else if (atom->string() == "obsoleteclasses") { - generateCompactList(relative, marker, obsoleteClasses); + generateCompactList(relative, marker, obsoleteClasses, false); } else if (atom->string() == "functionindex") { generateFunctionIndex(relative, marker); @@ -634,10 +659,10 @@ int HtmlGenerator::generateAtom(const Atom *atom, generateLegaleseList(relative, marker); } else if (atom->string() == "mainclasses") { - generateCompactList(relative, marker, mainClasses); + generateCompactList(relative, marker, mainClasses, true); } else if (atom->string() == "services") { - generateCompactList(relative, marker, serviceClasses); + generateCompactList(relative, marker, serviceClasses, false); } else if (atom->string() == "overviews") { generateOverviewList(relative, marker); @@ -676,16 +701,23 @@ int HtmlGenerator::generateAtom(const Atom *atom, nsmap = newSinceMaps.find(atom->string()); NewClassMaps::const_iterator ncmap; ncmap = newClassMaps.find(atom->string()); + NewClassMaps::const_iterator nqcmap; + nqcmap = newQmlClassMaps.find(atom->string()); if ((nsmap != newSinceMaps.constEnd()) && !nsmap.value().isEmpty()) { QList<Section> sections; QList<Section>::ConstIterator s; for (int i=0; i<LastSinceType; ++i) - sections.append(Section(sinceTitle(i),QString(),QString())); + sections.append(Section(sinceTitle(i),QString(),QString(),QString())); NodeMultiMap::const_iterator n = nsmap.value().constBegin(); while (n != nsmap.value().constEnd()) { const Node* node = n.value(); switch (node->type()) { + case Node::Fake: + if (node->subType() == Node::QmlClass) { + sections[QmlClass].appendMember((Node*)node); + } + break; case Node::Namespace: sections[Namespace].appendMember((Node*)node); break; @@ -768,9 +800,11 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << "<a name=\"" << Doc::canonicalTitle((*s).name) << "\"></a>\n"; - out() << "<h3>" << protect((*s).name) << "</h3>\n"; + out() << "<h3>" << protectEnc((*s).name) << "</h3>\n"; if (idx == Class) - generateCompactList(0, marker, ncmap.value(), QString("Q")); + generateCompactList(0, marker, ncmap.value(), false, QString("Q")); + else if (idx == QmlClass) + generateCompactList(0, marker, nqcmap.value(), false, QString("Q")); else if (idx == MemberFunction) { ParentMaps parentmaps; ParentMaps::iterator pmap; @@ -792,11 +826,11 @@ int HtmlGenerator::generateAtom(const Atom *atom, << linkForNode(pmap.key(), 0) << "\">"; QStringList pieces = fullName(pmap.key(), 0, marker).split("::"); - out() << protect(pieces.last()); + out() << protectEnc(pieces.last()); out() << "</a>" << ":</p>\n"; generateSection(nlist, 0, marker, CodeMarker::Summary); - out() << "<br />"; + out() << "<br/>"; ++pmap; } } @@ -817,15 +851,15 @@ int HtmlGenerator::generateAtom(const Atom *atom, if (atom->next() != 0) text = atom->next()->string(); if (atom->type() == Atom::Image) - out() << "<p align=\"center\">"; + out() << "<p class=\"centerAlign\">"; if (fileName.isEmpty()) { out() << "<font color=\"red\">[Missing image " - << protect(atom->string()) << "]</font>"; + << protectEnc(atom->string()) << "]</font>"; } else { - out() << "<img src=\"" << protect(fileName) << "\""; + out() << "<img src=\"" << protectEnc(fileName) << "\""; if (!text.isEmpty()) - out() << " alt=\"" << protect(text) << "\""; + out() << " alt=\"" << protectEnc(text) << "\""; out() << " />"; helpProjectWriter->addExtraFile(fileName); } @@ -836,13 +870,13 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::ImageText: break; case Atom::LegaleseLeft: - out() << "<div style=\"padding: 0.5em; background: #e0e0e0; color: black\">"; + out() << "<div class=\"LegaleseLeft\">"; break; case Atom::LegaleseRight: out() << "</div>"; break; case Atom::LineBreak: - out() << "<br />"; + out() << "<br/>"; break; case Atom::Link: { @@ -878,24 +912,27 @@ int HtmlGenerator::generateAtom(const Atom *atom, else if (atom->string() == ATOM_LIST_VALUE) { threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom); if (threeColumnEnumValueTable) { - out() << "<p><table class=\"valuelist\" border=\"1\" cellpadding=\"2\" " - << "cellspacing=\"1\" width=\"100%\">\n" - << "<tr><th width=\"25%\">Constant</th>" - << "<th width=\"15%\">Value</th>" - << "<th width=\"60%\">Description</th></tr>\n"; + out() << "<table class=\"valuelist\">"; + // << "<tr>" + if (++numTableRows % 2 == 1) + out() << "<tr class=\"odd\">"; + else + out() << "<tr class=\"even\">"; + + out() << "<tr><th>Constant</th>" + << "<th>Value</th>" + << "<th>Description</th></tr>\n"; } else { - out() << "<p><table class=\"valuelist\" border=\"1\" cellpadding=\"2\" " - << "cellspacing=\"1\" width=\"40%\">\n" - << "<tr><th width=\"60%\">Constant</th><th " - << "width=\"40%\">Value</th></tr>\n"; + out() << "<table class=\"valuelist\">" + << "<tr><th>Constant</th><th>Value</th></tr>\n"; } } else { out() << "<ol type="; if (atom->string() == ATOM_LIST_UPPERALPHA) { out() << "\"A\""; - } + } /* why type? */ else if (atom->string() == ATOM_LIST_LOWERALPHA) { out() << "\"a\""; } @@ -922,10 +959,10 @@ int HtmlGenerator::generateAtom(const Atom *atom, else { // (atom->string() == ATOM_LIST_VALUE) // ### Trenton - out() << "<tr><td valign=\"top\"><tt>" - << protect(plainCode(marker->markedUpEnumValue(atom->next()->string(), + out() << "<tr><td class=\"topAlign\"><tt>" + << protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(), relative))) - << "</tt></td><td align=\"center\" valign=\"top\">"; + << "</tt></td><td class=\" topAlign\">"; QString itemValue; if (relative->type() == Node::Enum) { @@ -936,7 +973,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, if (itemValue.isEmpty()) out() << "?"; else - out() << "<tt>" << protect(itemValue) << "</tt>"; + out() << "<tt>" << protectEnc(itemValue) << "</tt>"; skipAhead = 1; } @@ -951,7 +988,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, } else if (atom->string() == ATOM_LIST_VALUE) { if (threeColumnEnumValueTable) { - out() << "</td><td valign=\"top\">"; + out() << "</td><td class=\"topAlign\">"; if (matchAhead(atom, Atom::ListItemRight)) out() << " "; } @@ -981,7 +1018,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << "</dl>\n"; } else if (atom->string() == ATOM_LIST_VALUE) { - out() << "</table></p>\n"; + out() << "</table>\n"; } else { out() << "</ol>\n"; @@ -1052,7 +1089,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, generateLink(atom, relative, marker); } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } break; case Atom::TableLeft: @@ -1062,32 +1099,28 @@ int HtmlGenerator::generateAtom(const Atom *atom, } if (!atom->string().isEmpty()) { if (atom->string().contains("%")) - out() << "<p><table class=\"generic\" width=\"" << atom->string() << "\" " - << "align=\"center\" cellpadding=\"2\" " - << "cellspacing=\"1\" border=\"0\">\n"; + out() << "<table class=\"generic\">\n "; // width=\"" << atom->string() << "\">\n "; else { - out() << "<p><table class=\"generic\" align=\"center\" cellpadding=\"2\" " - << "cellspacing=\"1\" border=\"0\">\n"; + out() << "<table class=\"generic\">\n"; } } else { - out() << "<p><table class=\"generic\" align=\"center\" cellpadding=\"2\" " - << "cellspacing=\"1\" border=\"0\">\n"; + out() << "<table class=\"generic\">\n"; } numTableRows = 0; break; case Atom::TableRight: - out() << "</table></p>\n"; + out() << "</table>\n"; break; case Atom::TableHeaderLeft: - out() << "<thead><tr valign=\"top\" class=\"qt-style\">"; + out() << "<thead><tr class=\"qt-style topAlign\">"; inTableHeader = true; break; case Atom::TableHeaderRight: out() << "</tr>"; if (matchAhead(atom, Atom::TableHeaderLeft)) { skipAhead = 1; - out() << "\n<tr valign=\"top\" class=\"qt-style\">"; + out() << "\n<tr class=\"qt-style topAlign\">"; } else { out() << "</thead>\n"; @@ -1096,9 +1129,9 @@ int HtmlGenerator::generateAtom(const Atom *atom, break; case Atom::TableRowLeft: if (++numTableRows % 2 == 1) - out() << "<tr valign=\"top\" class=\"odd\">"; + out() << "<tr class=\"odd topAlign\">"; else - out() << "<tr valign=\"top\" class=\"even\">"; + out() << "<tr class=\"even topAlign\">"; break; case Atom::TableRowRight: out() << "</tr>\n"; @@ -1116,7 +1149,10 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << " colspan=\"" << spans.at(0) << "\""; if (spans.at(1) != "1") out() << " rowspan=\"" << spans.at(1) << "\""; + if (inTableHeader) out() << ">"; + else + out() << "><p>"; } if (matchAhead(atom, Atom::ParaLeft)) skipAhead = 1; @@ -1126,7 +1162,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, if (inTableHeader) out() << "</th>"; else - out() << "</td>"; + out() << "</p></td>"; if (matchAhead(atom, Atom::ParaLeft)) skipAhead = 1; break; @@ -1163,11 +1199,11 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << "<a name=\"" << Doc::canonicalTitle(atom->string()) << "\"></a>"; break; case Atom::UnhandledFormat: - out() << "<font color=\"red\"><b><Missing HTML></b></font>"; + out() << "<b class=\"redFont\"><Missing HTML></b>"; break; case Atom::UnknownCommand: - out() << "<font color=\"red\"><b><code>\\" << protect(atom->string()) - << "</code></b></font>"; + out() << "<b class=\"redFont\"><code>\\" << protectEnc(atom->string()) + << "</code></b>"; break; #ifdef QDOC_QML case Atom::QmlText: @@ -1197,7 +1233,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, namespasse = static_cast<const NamespaceNode *>(inner); rawTitle = marker->plainName(inner); fullTitle = marker->plainFullName(inner); - title = rawTitle + " Namespace Reference"; + title = rawTitle + " Namespace"; } else if (inner->type() == Node::Class) { classe = static_cast<const ClassNode *>(inner); @@ -1216,6 +1252,8 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, subtitleText << "(" << Atom(Atom::AutoLink, fullTitle) << ")" << Atom(Atom::LineBreak); +#if 0 + // No longer used because the modeule name is a breadcrumb. QString fixedModule = inner->moduleName(); if (fixedModule == "Qt3SupportLight") fixedModule = "Qt3Support"; @@ -1236,8 +1274,11 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, subtitleText << "]"; } } +#endif - generateHeader(title, inner, marker, true); + generateHeader(title, inner, marker); + sections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay); + generateTableOfContents(inner,marker,§ions); generateTitle(title, subtitleText, SmallSubTitle, inner, marker); #ifdef QDOC_QML @@ -1250,7 +1291,6 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, generateIncludes(inner, marker); generateStatus(inner, marker); if (classe) { - generateModuleWarning(classe, marker); generateInherits(classe, marker); generateInheritedBy(classe, marker); } @@ -1282,7 +1322,9 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, bool needOtherSection = false; - sections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay); + /* + sections is built above for the call to generateTableOfContents(). + */ s = sections.begin(); while (s != sections.end()) { if (s->members.isEmpty() && s->reimpMembers.isEmpty()) { @@ -1295,7 +1337,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, out() << "<a name=\"" << registerRef((*s).name.toLower()) << "\"></a>\n"; - out() << "<h2>" << protect((*s).name) << "</h2>\n"; + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; generateSection(s->members, inner, marker, CodeMarker::Summary); } if (!s->reimpMembers.isEmpty()) { @@ -1304,7 +1346,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, out() << "<a name=\"" << registerRef(name.toLower()) << "\"></a>\n"; - out() << "<h2>" << protect(name) << "</h2>\n"; + out() << "<h2>" << protectEnc(name) << "</h2>\n"; generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary); } @@ -1334,8 +1376,10 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, if (!inner->doc().isEmpty()) { out() << "<hr />\n" + << "<div class=\"descr\"/>\n" // QTBUG-9504 << "<h2>" << "Detailed Description" << "</h2>\n"; generateBody(inner, marker); + out() << "</div>\n"; // QTBUG-9504 generateAlsoList(inner, marker); } @@ -1343,7 +1387,9 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, s = sections.begin(); while (s != sections.end()) { out() << "<hr />\n"; - out() << "<h2>" << protect((*s).name) << "</h2>\n"; + if (!(*s).divClass.isEmpty()) + out() << "<div class=\"" << (*s).divClass << "\"/>\n"; // QTBUG-9504 + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; NodeList::ConstIterator m = (*s).members.begin(); while (m != (*s).members.end()) { @@ -1392,6 +1438,8 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, } ++m; } + if (!(*s).divClass.isEmpty()) + out() << "</div>\n"; // QTBUG-9504 ++s; } generateFooter(inner); @@ -1428,14 +1476,27 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) QList<Section> sections; QList<Section>::const_iterator s; - QString htmlTitle = fake->fullTitle(); + QString fullTitle = fake->fullTitle(); + QString htmlTitle = fullTitle; if (fake->subType() == Node::File && !fake->subTitle().isEmpty()) { subTitleSize = SmallSubTitle; htmlTitle += " (" + fake->subTitle() + ")"; } + else if (fake->subType() == Node::QmlBasicType) { + fullTitle = "QML Basic Type: " + fullTitle; + htmlTitle = fullTitle; + } - generateHeader(htmlTitle, fake, marker, true); - generateTitle(fake->fullTitle(), + generateHeader(htmlTitle, fake, marker); + + /* + Generate the TOC for the new doc format. + Don't generate a TOC for the home page. + */ + if (fake->name() != QString("index.html")) + generateTableOfContents(fake,marker,0); + + generateTitle(fullTitle, Text() << fake->subTitle(), subTitleSize, fake, @@ -1447,10 +1508,12 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) generateStatus(fake, marker); if (moduleNamespaceMap.contains(fake->name())) { + out() << "<a name=\"" << registerRef("namespaces") << "\"></a>\n"; out() << "<h2>Namespaces</h2>\n"; generateAnnotatedList(fake, marker, moduleNamespaceMap[fake->name()]); } if (moduleClassMap.contains(fake->name())) { + out() << "<a name=\"" << registerRef("classes") << "\"></a>\n"; out() << "<h2>Classes</h2>\n"; generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]); } @@ -1509,11 +1572,12 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) generateQmlInherits(qml_cn, marker); generateQmlInstantiates(qml_cn, marker); generateBrief(qml_cn, marker); + generateQmlInheritedBy(qml_cn, marker); sections = marker->qmlSections(qml_cn,CodeMarker::Summary); s = sections.begin(); while (s != sections.end()) { out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n"; - out() << "<h2>" << protect((*s).name) << "</h2>\n"; + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; generateQmlSummary(*s,fake,marker); ++s; } @@ -1529,11 +1593,11 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) sections = marker->qmlSections(qml_cn,CodeMarker::Detailed); s = sections.begin(); while (s != sections.end()) { - out() << "<h2>" << protect((*s).name) << "</h2>\n"; + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; NodeList::ConstIterator m = (*s).members.begin(); while (m != (*s).members.end()) { generateDetailedQmlMember(*m, fake, marker); - out() << "<br />\n"; + out() << "<br/>\n"; fakeSection.keywords += qMakePair((*m)->name(), linkForNode(*m,0)); ++m; @@ -1549,7 +1613,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) s = sections.begin(); while (s != sections.end()) { out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n"; - out() << "<h2>" << protect((*s).name) << "</h2>\n"; + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; generateSectionList(*s, fake, marker, CodeMarker::Summary); ++s; } @@ -1557,10 +1621,14 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) Text brief = fake->doc().briefText(); if (fake->subType() == Node::Module && !brief.isEmpty()) { out() << "<a name=\"" << registerRef("details") << "\"></a>\n"; + out() << "<div class=\"descr\"/>\n"; // QTBUG-9504 out() << "<h2>" << "Detailed Description" << "</h2>\n"; } + else + out() << "<div class=\"descr\"/>\n"; // QTBUG-9504 generateBody(fake, marker); + out() << "</div>\n"; // QTBUG-9504 generateAlsoList(fake, marker); if (!fake->groupMembers().isEmpty()) { @@ -1578,7 +1646,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) s = sections.begin(); while (s != sections.end()) { out() << "<hr />\n"; - out() << "<h2>" << protect((*s).name) << "</h2>\n"; + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; NodeList::ConstIterator m = (*s).members.begin(); while (m != (*s).members.end()) { @@ -1614,155 +1682,163 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) } } -QString HtmlGenerator::fileExtension(const Node * /* node */) +QString HtmlGenerator::fileExtension(const Node * /* node */) const { return "html"; } -void HtmlGenerator::generateHeader(const QString& title, - const Node *node, - CodeMarker *marker, - bool mainPage) +/*! + Output breadcrumb list in the html file. + */ +void HtmlGenerator::generateBreadCrumbs(const QString& title, + const Node *node, + CodeMarker *marker) { - out() << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"; - - out() << "<!DOCTYPE html\n" - " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n" - "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"; - - QString shortVersion; - if ((project != "Qtopia") && (project != "Qt Extended")) { - shortVersion = project + " " + shortVersion + ": "; - if (node && !node->doc().location().isEmpty()) - out() << "<!-- " << node->doc().location().fileName() << " -->\n"; - - shortVersion = myTree->version(); - if (shortVersion.count(QChar('.')) == 2) - shortVersion.truncate(shortVersion.lastIndexOf(QChar('.'))); - if (!shortVersion.isEmpty()) { - if (project == "QSA") - shortVersion = "QSA " + shortVersion + ": "; - else - shortVersion = "Qt " + shortVersion + ": "; + Text breadcrumb; + if (node->type() == Node::Class) { + const ClassNode* cn = static_cast<const ClassNode*>(node); + QString name = node->moduleName(); + out() << " <li><a href=\"modules.html\">All Modules</a></li>"; + if (!name.isEmpty()) { + out() << " <li>"; + breadcrumb << Atom(Atom::AutoLink,name); + generateText(breadcrumb, node, marker); + out() << "</li>\n"; } - } - - out() << "<head>\n" - " <title>" << shortVersion << protect(title) << "</title>\n"; - if (!style.isEmpty()) - out() << " <style type=\"text/css\">" << style << "</style>\n"; - - const QMap<QString, QString> &metaMap = node->doc().metaTagMap(); - if (!metaMap.isEmpty()) { - QMapIterator<QString, QString> i(metaMap); - while (i.hasNext()) { - i.next(); - out() << " <meta name=\"" << protect(i.key()) << "\" contents=\"" - << protect(i.value()) << "\" />\n"; + breadcrumb.clear(); + if (!cn->name().isEmpty()) { + out() << " <li>"; + breadcrumb << Atom(Atom::AutoLink,cn->name()); + generateText(breadcrumb, 0, marker); + out() << "</li>\n"; } } - - navigationLinks.clear(); - - if (node && !node->links().empty()) { - QPair<QString,QString> linkPair; - QPair<QString,QString> anchorPair; - const Node *linkNode; - - if (node->links().contains(Node::PreviousLink)) { - linkPair = node->links()[Node::PreviousLink]; - linkNode = findNodeForTarget(linkPair.first, node, marker); - if (!linkNode || linkNode == node) - anchorPair = linkPair; - else - anchorPair = anchorForNode(linkNode); - - out() << " <link rel=\"prev\" href=\"" - << anchorPair.first << "\" />\n"; - - navigationLinks += "[Previous: <a href=\"" + anchorPair.first + "\">"; - if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); - else - navigationLinks += protect(linkPair.second); - navigationLinks += "</a>]\n"; - } - if (node->links().contains(Node::ContentsLink)) { - linkPair = node->links()[Node::ContentsLink]; - linkNode = findNodeForTarget(linkPair.first, node, marker); - if (!linkNode || linkNode == node) - anchorPair = linkPair; - else - anchorPair = anchorForNode(linkNode); - - out() << " <link rel=\"contents\" href=\"" - << anchorPair.first << "\" />\n"; - - navigationLinks += "[<a href=\"" + anchorPair.first + "\">"; - if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); - else - navigationLinks += protect(linkPair.second); - navigationLinks += "</a>]\n"; - } - if (node->links().contains(Node::NextLink)) { - linkPair = node->links()[Node::NextLink]; - linkNode = findNodeForTarget(linkPair.first, node, marker); - if (!linkNode || linkNode == node) - anchorPair = linkPair; - else - anchorPair = anchorForNode(linkNode); - - out() << " <link rel=\"next\" href=\"" - << anchorPair.first << "\" />\n"; - - navigationLinks += "[Next: <a href=\"" + anchorPair.first + "\">"; - if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); - else - navigationLinks += protect(linkPair.second); - navigationLinks += "</a>]\n"; + else if (node->type() == Node::Fake) { + const FakeNode* fn = static_cast<const FakeNode*>(node); + if (node->subType() == Node::Module) { + out() << " <li><a href=\"modules.html\">All Modules</a></li>"; + QString name = node->name(); + if (!name.isEmpty()) { + out() << " <li>"; + breadcrumb << Atom(Atom::AutoLink,name); + generateText(breadcrumb, 0, marker); + out() << "</li>\n"; + } } - if (node->links().contains(Node::IndexLink)) { - linkPair = node->links()[Node::IndexLink]; - linkNode = findNodeForTarget(linkPair.first, node, marker); - if (!linkNode || linkNode == node) - anchorPair = linkPair; - else - anchorPair = anchorForNode(linkNode); - out() << " <link rel=\"index\" href=\"" - << anchorPair.first << "\" />\n"; + else if (node->subType() == Node::Group) { + if (fn->name() == QString("modules")) + out() << " <li><a href=\"modules.html\">All Modules</a></li>"; + else { + out() << " <li><a href=\"" << fn->name() << "\">" << title + << "</a></li>"; + } } - if (node->links().contains(Node::StartLink)) { - linkPair = node->links()[Node::StartLink]; - linkNode = findNodeForTarget(linkPair.first, node, marker); - if (!linkNode || linkNode == node) - anchorPair = linkPair; - else - anchorPair = anchorForNode(linkNode); - out() << " <link rel=\"start\" href=\"" - << anchorPair.first << "\" />\n"; + else if (node->subType() == Node::Page) { + if (fn->name() == QString("examples.html")) { + out() << " <li><a href=\"examples.html\">All Examples</a></li>"; + } + else if (fn->name().startsWith("examples-")) { + out() << " <li><a href=\"examples.html\">All Examples</a></li>"; + out() << " <li><a href=\"" << fn->name() << "\">" << title + << "</a></li>"; + } + else if (fn->name() == QString("namespaces.html")) { + out() << " <li><a href=\"namespaces.html\">All Namespaces</a></li>"; + } + else { + out() << " <li><a href=\"" << fn->name() << "\">" << title + << "</a></li>"; + } } + else if (node->subType() == Node::QmlClass) { + out() << " <li><a href=\"qdeclarativeelements.html\">QML Elements</a></li>"; + out() << " <li><a href=\"" << fn->name() << "\">" << title + << "</a></li>"; + } + else if (node->subType() == Node::Example) { + out() << " <li><a href=\"examples.html\">All Examples</a></li>"; + QStringList sl = fn->name().split('/'); + QString name = "examples-" + sl.at(0) + ".html"; + QString t = CodeParser::titleFromName(name); + out() << " <li><a href=\"" << name << "\">" + << t << "</a></li>"; + out() << " <li><a href=\"" << sl.at(0) + << "-" << sl.at(sl.size()-1) << ".html\">" + << title << "</a></li>"; + } + } + else if (node->type() == Node::Namespace) { + const NamespaceNode* nsn = static_cast<const NamespaceNode*>(node); + out() << " <li><a href=\"namespaces.html\">All Namespaces</a></li>"; + out() << " <li><a href=\"" << fileName(nsn) << "\">" << title + << "</a></li>"; } +} - foreach (const QString &stylesheet, stylesheets) { - out() << " <link href=\"" << stylesheet << "\" rel=\"stylesheet\" " - << "type=\"text/css\" />\n"; - } - - foreach (const QString &customHeadElement, customHeadElements) { - out() << " " << customHeadElement << "\n"; - } - - out() << "</head>\n" - "<body>\n"; +void HtmlGenerator::generateHeader(const QString& title, + const Node *node, + CodeMarker *marker) +{ + out() << QString("<?xml version=\"1.0\" encoding=\"%1\"?>\n").arg(outputEncoding); + out() << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"; + out() << "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"; + out() << "<head>\n"; + out() << " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"; + QString shortVersion; + shortVersion = project + " " + shortVersion + ": "; + if (node && !node->doc().location().isEmpty()) + out() << "<!-- " << node->doc().location().fileName() << " -->\n"; + + shortVersion = myTree->version(); + if (shortVersion.count(QChar('.')) == 2) + shortVersion.truncate(shortVersion.lastIndexOf(QChar('.'))); + if (!shortVersion.isEmpty()) { + if (project == "QSA") + shortVersion = "QSA " + shortVersion + ": "; + else + shortVersion = "Qt " + shortVersion + ": "; + } + + out() << " <title>" << shortVersion << protectEnc(title) << "</title>\n"; + + out() << " <!--[if IE]>"; + out() << "<meta name=\"MSSmartTagsPreventParsing\" content=\"true\">"; + out() << "<meta http-equiv=\"imagetoolbar\" content=\"no\">"; + out() << "<![endif]-->"; + out() << "<!--[if lt IE 7]>"; + out() << "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style_ie6.css\">"; + out() << "<![endif]-->"; + out() << "<!--[if IE 7]>"; + out() << "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style_ie7.css\">"; + out() << "<![endif]-->"; + out() << "<!--[if IE 8]>"; + out() << "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style_ie8.css\">"; + out() << "<![endif]-->"; + + + //out() << " <title>Qt Reference Documentation</title>"; + out() << " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\" />\n"; + out() << " <script src=\"scripts/jquery.js\" type=\"text/javascript\"></script>\n"; + out() << " <script src=\"scripts/functions.js\" type=\"text/javascript\"></script>\n"; + out() << "</head>\n"; + + if (offlineDocs) + out() << "<body class=\"offline\" onload=\"CheckEmptyAndLoadList();\">\n"; + else + out() << "<body class=\"\" onload=\"CheckEmptyAndLoadList();\">\n"; + +#ifdef GENERATE_MAC_REFS if (mainPage) generateMacRef(node, marker); +#endif out() << QString(postHeader).replace("\\" + COMMAND_VERSION, myTree->version()); + generateBreadCrumbs(title,node,marker); + out() << QString(postPostHeader).replace("\\" + COMMAND_VERSION, myTree->version()); - +#if 0 // Removed for new docf format. MWS if (node && !node->links().empty()) out() << "<p>\n" << navigationLinks << "</p>\n"; +#endif } void HtmlGenerator::generateTitle(const QString& title, @@ -1771,17 +1847,17 @@ void HtmlGenerator::generateTitle(const QString& title, const Node *relative, CodeMarker *marker) { - out() << "<h1 class=\"title\">" << protect(title); + if (!title.isEmpty()) + out() << "<h1 class=\"title\">" << protectEnc(title) << "</h1>\n"; if (!subTitle.isEmpty()) { - out() << "<br />"; - if (subTitleSize == SmallSubTitle) - out() << "<span class=\"small-subtitle\">"; + out() << "<span"; + if (subTitleSize == SmallSubTitle) + out() << " class=\"small-subtitle\">"; else - out() << "<span class=\"subtitle\">"; + out() << " class=\"subtitle\">"; generateText(subTitle, relative, marker); out() << "</span>\n"; } - out() << "</h1>\n"; } void HtmlGenerator::generateFooter(const Node *node) @@ -1790,9 +1866,10 @@ void HtmlGenerator::generateFooter(const Node *node) out() << "<p>\n" << navigationLinks << "</p>\n"; out() << QString(footer).replace("\\" + COMMAND_VERSION, myTree->version()) - << QString(address).replace("\\" + COMMAND_VERSION, myTree->version()) - << "</body>\n" - "</html>\n"; + << QString(address).replace("\\" + COMMAND_VERSION, myTree->version()); + out() << " <script src=\"scripts/functions.js\" type=\"text/javascript\"></script>\n"; + out() << "</body>\n"; + out() << "</html>\n"; } void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker, @@ -1813,7 +1890,7 @@ void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker, void HtmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *marker) { if (!inner->includes().isEmpty()) { - out() << "<pre>" + out() << "<pre class=\"highlightedCode\">" << trimmedTrailing(highlightedCode(indent(codeIndent, marker->markedUpIncludes(inner->includes())), marker,inner)) @@ -1821,6 +1898,9 @@ void HtmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *marker) } } +/*! + Generates a table of contents begining at \a node. + */ void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker, Doc::SectioningUnit sectioningUnit, @@ -1828,6 +1908,7 @@ void HtmlGenerator::generateTableOfContents(const Node *node, const Node *relative) { + return; if (!node->doc().hasTableOfContents()) return; QList<Atom *> toc = node->doc().tableOfContents(); @@ -1843,8 +1924,8 @@ void HtmlGenerator::generateTableOfContents(const Node *node, QString tdTag; if (numColumns > 1) { - tdTag = "<td width=\"" + QString::number((100 + numColumns - 1) / numColumns) + "%\">"; - out() << "<p><table class=\"toc\" width=\"100%\">\n<tr valign=\"top\">" + tdTag = "<td>"; /* width=\"" + QString::number((100 + numColumns - 1) / numColumns) + "%\">";*/ + out() << "<table class=\"toc\">\n<tr class=\"topAlign\">" << tdTag << "\n"; } @@ -1896,12 +1977,127 @@ void HtmlGenerator::generateTableOfContents(const Node *node, } if (numColumns > 1) - out() << "</td></tr></table></p>\n"; + out() << "</td></tr></table>\n"; inContents = false; inLink = false; } +/*! + Revised for the new doc format. + Generates a table of contents begining at \a node. + */ +void HtmlGenerator::generateTableOfContents(const Node *node, + CodeMarker *marker, + QList<Section>* sections) +{ + QList<Atom*> toc; + if (node->doc().hasTableOfContents()) + toc = node->doc().tableOfContents(); + if (toc.isEmpty() && !sections && (node->subType() != Node::Module)) + return; + + QStringList sectionNumber; + int detailsBase = 0; + + // disable nested links in table of contents + inContents = true; + inLink = true; + + out() << "<div class=\"toc\">\n"; + out() << "<h3>Contents</h3>\n"; + sectionNumber.append("1"); + out() << "<ul>\n"; + + if (node->subType() == Node::Module) { + if (moduleNamespaceMap.contains(node->name())) { + out() << "<li class=\"level" + << sectionNumber.size() + << "\"><a href=\"#" + << registerRef("namespaces") + << "\">Namespaces</a></li>\n"; + } + if (moduleClassMap.contains(node->name())) { + out() << "<li class=\"level" + << sectionNumber.size() + << "\"><a href=\"#" + << registerRef("classes") + << "\">Classes</a></li>\n"; + } + out() << "<li class=\"level" + << sectionNumber.size() + << "\"><a href=\"#" + << registerRef("details") + << "\">Detailed Description</a></li>\n"; + for (int i = 0; i < toc.size(); ++i) { + if (toc.at(i)->string().toInt() == 1) { + detailsBase = 1; + break; + } + } + } + else if (sections && (node->type() == Node::Class)) { + QList<Section>::ConstIterator s = sections->begin(); + while (s != sections->end()) { + if (!s->members.isEmpty() || !s->reimpMembers.isEmpty()) { + out() << "<li class=\"level" + << sectionNumber.size() + << "\"><a href=\"#" + << registerRef((*s).pluralMember) + << "\">" << (*s).name + << "</a></li>\n"; + } + ++s; + } + out() << "<li class=\"level" + << sectionNumber.size() + << "\"><a href=\"#" + << registerRef("details") + << "\">Detailed Description</a></li>\n"; + for (int i = 0; i < toc.size(); ++i) { + if (toc.at(i)->string().toInt() == 1) { + detailsBase = 1; + break; + } + } + } + + for (int i = 0; i < toc.size(); ++i) { + Atom *atom = toc.at(i); + int nextLevel = atom->string().toInt() + detailsBase; + if (sectionNumber.size() < nextLevel) { + do { + sectionNumber.append("1"); + } while (sectionNumber.size() < nextLevel); + } + else { + while (sectionNumber.size() > nextLevel) { + sectionNumber.removeLast(); + } + sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1); + } + int numAtoms; + Text headingText = Text::sectionHeading(atom); + QString s = headingText.toString(); + out() << "<li class=\"level" + << sectionNumber.size() + << "\">"; + out() << "<a href=\"" + << "#" + << Doc::canonicalTitle(s) + << "\">"; + generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms); + out() << "</a></li>\n"; + } + while (!sectionNumber.isEmpty()) { + sectionNumber.removeLast(); + } + out() << "</ul>\n"; + out() << "</div>\n"; + inContents = false; + inLink = false; +} + #if 0 void HtmlGenerator::generateNavigationBar(const NavigationBar& bar, const Node *node, @@ -1909,7 +2105,7 @@ void HtmlGenerator::generateNavigationBar(const NavigationBar& bar, { if (bar.prev.begin() != 0 || bar.current.begin() != 0 || bar.next.begin() != 0) { - out() << "<p align=\"right\">"; + out() << "<p class=\"rightAlign\">"; if (bar.prev.begin() != 0) { #if 0 out() << "[<a href=\"" << section.previousBaseName() @@ -1948,7 +2144,7 @@ QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, QString fileName = fileBase(inner) + "-members." + fileExtension(inner); beginSubPage(inner->location(), fileName); QString title = "List of All Members for " + inner->name(); - generateHeader(title, inner, marker, false); + generateHeader(title, inner, marker); generateTitle(title, Text(), SmallSubTitle, inner, marker); out() << "<p>This is the complete list of members for "; generateFullName(inner, 0, marker); @@ -1992,7 +2188,7 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, } beginSubPage(inner->location(), fileName); - generateHeader(title, inner, marker, false); + generateHeader(title, inner, marker); generateTitle(title, Text(), SmallSubTitle, inner, marker); if (status == CodeMarker::Compat) { @@ -2009,18 +2205,18 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, out() << "<p><ul><li><a href=\"" << linkForNode(inner, 0) << "\">" - << protect(inner->name()) + << protectEnc(inner->name()) << " class reference</a></li></ul></p>\n"; for (i = 0; i < sections.size(); ++i) { - out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n"; + out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n"; generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary); } sections = marker->sections(inner, CodeMarker::Detailed, status); for (i = 0; i < sections.size(); ++i) { out() << "<hr />\n"; - out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n"; + out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n"; NodeList::ConstIterator m = sections.at(i).members.begin(); while (m != sections.at(i).members.end()) { @@ -2085,8 +2281,7 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *marker, const NodeMap &nodeMap) { - out() << "<p><table width=\"100%\" class=\"annotated\" cellpadding=\"2\" " - << "cellspacing=\"1\" border=\"0\">\n"; + out() << "<table class=\"annotated\">\n"; int row = 0; foreach (const QString &name, nodeMap.keys()) { @@ -2096,29 +2291,29 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, continue; if (++row % 2 == 1) - out() << "<tr valign=\"top\" class=\"odd\">"; + out() << "<tr class=\"odd topAlign\">"; else - out() << "<tr valign=\"top\" class=\"even\">"; - out() << "<th>"; + out() << "<tr class=\"even topAlign\">"; + out() << "<td><p>"; generateFullName(node, relative, marker); - out() << "</th>"; + out() << "</p></td>"; if (!(node->type() == Node::Fake)) { Text brief = node->doc().trimmedBriefText(name); if (!brief.isEmpty()) { - out() << "<td>"; + out() << "<td><p>"; generateText(brief, node, marker); - out() << "</td>"; + out() << "</p></td>"; } } else { - out() << "<td>"; - out() << protect(node->doc().briefText().toString()); - out() << "</td>"; + out() << "<td><p>"; + out() << protectEnc(node->doc().briefText().toString()); + out() << "</p></td>"; } out() << "</tr>\n"; } - out() << "</table></p>\n"; + out() << "</table>\n"; } /*! @@ -2133,10 +2328,11 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker, const NodeMap &classMap, + bool includeAlphabet, QString commonPrefix) { const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_' - const int NumColumns = 4; // number of columns in the result + const int NumColumns = 3; // number of columns in the result if (classMap.isEmpty()) return; @@ -2205,6 +2401,7 @@ void HtmlGenerator::generateCompactList(const Node *relative, */ NodeMap paragraph[NumParagraphs+1]; QString paragraphName[NumParagraphs+1]; + QSet<char> usedParagraphNames; NodeMap::ConstIterator c = classMap.begin(); while (c != classMap.end()) { @@ -2228,6 +2425,7 @@ void HtmlGenerator::generateCompactList(const Node *relative, } paragraphName[paragraphNo] = key[0].toUpper(); + usedParagraphNames.insert(key[0].toLower().cell()); paragraph[paragraphNo].insert(key, c.value()); ++c; } @@ -2247,15 +2445,15 @@ void HtmlGenerator::generateCompactList(const Node *relative, for (j = 0; j < NumParagraphs; j++) // j = 0..36 paragraphOffset[j + 1] = paragraphOffset[j] + paragraph[j].count(); - int firstOffset[NumColumns + 1]; // 4 + 1 - int currentOffset[NumColumns]; // 4 - int currentParagraphNo[NumColumns]; // 4 - int currentOffsetInParagraph[NumColumns]; // 4 + int firstOffset[NumColumns + 1]; + int currentOffset[NumColumns]; + int currentParagraphNo[NumColumns]; + int currentOffsetInParagraph[NumColumns]; int numRows = (classMap.count() + NumColumns - 1) / NumColumns; int curParagNo = 0; - for (i = 0; i < NumColumns; i++) { // i = 0..3 + for (i = 0; i < NumColumns; i++) { firstOffset[i] = qMin(i * numRows, classMap.size()); currentOffset[i] = firstOffset[i]; @@ -2271,13 +2469,29 @@ void HtmlGenerator::generateCompactList(const Node *relative, } firstOffset[NumColumns] = classMap.count(); - out() << "<p><table class=\"generic\" width=\"100%\">\n"; + if (includeAlphabet) { + out() << "<p class=\"centerAlign functionIndex\"><b>"; + for (int i = 0; i < 26; i++) { + QChar ch('a' + i); + if (usedParagraphNames.contains(char('a' + i))) + out() << QString("<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper()); + } + out() << "</b></p>\n"; + } + + out() << "<table class=\"generic\">\n"; for (k = 0; k < numRows; k++) { - out() << "<tr>\n"; + if (++numTableRows % 2 == 1) + out() << "<tr class=\"odd topAlign\">"; + else + out() << "<tr class=\"even topAlign\">"; + //break; + +// out() << "<tr>\n"; for (i = 0; i < NumColumns; i++) { if (currentOffset[i] >= firstOffset[i + 1]) { // this column is finished - out() << "<td>\n</td>\n"; + out() << "<td>\n</td>\n"; // check why? } else { while ((currentParagraphNo[i] < NumParagraphs) && @@ -2292,16 +2506,20 @@ void HtmlGenerator::generateCompactList(const Node *relative, currentParagraphNo[i] = NumParagraphs - 1; } #endif - out() << "<td align=\"right\">"; + out() << "<th class=\"rightAlign alphaChar\"><p>"; if (currentOffsetInParagraph[i] == 0) { // start a new paragraph + if (includeAlphabet) { + QChar c = paragraphName[currentParagraphNo[i]][0].toLower(); + out() << QString("<a name=\"%1\"></a>").arg(c); + } out() << "<b>" << paragraphName[currentParagraphNo[i]] - << " </b>"; + << "</b>"; } - out() << "</td>\n"; + out() << "</p></th>\n"; - out() << "<td>"; + out() << "<td><p>"; if ((currentParagraphNo[i] < NumParagraphs) && !paragraphName[currentParagraphNo[i]].isEmpty()) { NodeMap::Iterator it; @@ -2314,8 +2532,12 @@ void HtmlGenerator::generateCompactList(const Node *relative, out() << "<a href=\"" << linkForNode(it.value(), relative) << "\">"; - QStringList pieces = fullName(it.value(), relative, marker).split("::"); - out() << protect(pieces.last()); + QStringList pieces; + if (it.value()->subType() == Node::QmlClass) + pieces << it.value()->name(); + else + pieces = fullName(it.value(), relative, marker).split("::"); + out() << protectEnc(pieces.last()); out() << "</a>"; if (pieces.size() > 1) { out() << " ("; @@ -2323,7 +2545,7 @@ void HtmlGenerator::generateCompactList(const Node *relative, out() << ")"; } } - out() << "</td>\n"; + out() << "</p></td>\n"; currentOffset[i]++; currentOffsetInParagraph[i]++; @@ -2331,18 +2553,18 @@ void HtmlGenerator::generateCompactList(const Node *relative, } out() << "</tr>\n"; } - out() << "</table></p>\n"; + out() << "</table>\n"; } void HtmlGenerator::generateFunctionIndex(const Node *relative, CodeMarker *marker) { - out() << "<p align=\"center\"><font size=\"+1\"><b>"; + out() << "<p class=\"centerAlign functionIndex\"><b>"; for (int i = 0; i < 26; i++) { QChar ch('a' + i); out() << QString("<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper()); } - out() << "</b></font></p>\n"; + out() << "</b></p>\n"; char nextLetter = 'a'; char currentLetter; @@ -2357,7 +2579,7 @@ void HtmlGenerator::generateFunctionIndex(const Node *relative, #else out() << "<p>"; #endif - out() << protect(f.key()) << ":"; + out() << protectEnc(f.key()) << ":"; currentLetter = f.key()[0].unicode(); while (islower(currentLetter) && currentLetter >= nextLetter) { @@ -2411,7 +2633,7 @@ void HtmlGenerator::generateLegaleseList(const Node *relative, QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { - QString contents = protect(marked.mid(templateTag.pos(1), + QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); @@ -2450,7 +2672,7 @@ void HtmlGenerator::generateQmlItem(const Node *node, QString marked = marker->markedUpQmlItem(node,summary); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { - QString contents = protect(marked.mid(templateTag.pos(1), + QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); @@ -2463,7 +2685,7 @@ void HtmlGenerator::generateQmlItem(const Node *node, if (summary) marked.replace("@name>", "b>"); - marked.replace("<@extra>", " <tt>"); + marked.replace("<@extra>", "<tt>"); marked.replace("</@extra>", "</tt>"); if (summary) { @@ -2556,7 +2778,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m const FakeNode *groupNode = groupTitlesMap[groupTitle]; out() << QString("<h3><a href=\"%1\">%2</a></h3>\n").arg( linkForNode(groupNode, relative)).arg( - protect(groupNode->fullTitle())); + protectEnc(groupNode->fullTitle())); if (fakeNodeMap[groupNode].count() == 0) continue; @@ -2568,7 +2790,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m if (title.startsWith("The ")) title.remove(0, 4); out() << "<li><a href=\"" << linkForNode(fakeNode, relative) << "\">" - << protect(title) << "</a></li>\n"; + << protectEnc(title) << "</a></li>\n"; } out() << "</ul>\n"; } @@ -2582,7 +2804,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m if (title.startsWith("The ")) title.remove(0, 4); out() << "<li><a href=\"" << linkForNode(fakeNode, relative) << "\">" - << protect(title) << "</a></li>\n"; + << protectEnc(title) << "</a></li>\n"; } out() << "</ul>\n"; } @@ -2606,15 +2828,12 @@ void HtmlGenerator::generateSection(const NodeList& nl, name_alignment = false; } if (name_alignment) { - out() << "<table class=\"alignedsummary\" border=\"0\" cellpadding=\"0\" " - << "cellspacing=\"0\" width=\"100%\">\n"; + out() << "<table class=\"alignedsummary\">\n"; } else { if (twoColumn) - out() << "<p><table class=\"propsummary\" width=\"100%\" " - << "border=\"0\" cellpadding=\"0\"" - << " cellspacing=\"0\">\n" - << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<table class=\"propsummary\">\n" + << "<tr><td class=\"topAlign\">"; out() << "<ul>\n"; } @@ -2627,20 +2846,19 @@ void HtmlGenerator::generateSection(const NodeList& nl, } if (name_alignment) { - out() << "<tr><td class=\"memItemLeft\" " - << "align=\"right\" valign=\"top\">"; + out() << "<tr><td class=\"memItemLeft rightAlign topAlign\"> "; } else { if (twoColumn && i == (int) (nl.count() + 1) / 2) - out() << "</ul></td><td valign=\"top\"><ul>\n"; - out() << "<li><div class=\"fn\">"; + out() << "</ul></td><td class=\"topAlign\"><ul>\n"; + out() << "<li class=\"fn\">"; } generateSynopsis(*m, relative, marker, style, name_alignment); if (name_alignment) out() << "</td></tr>\n"; else - out() << "</div></li>\n"; + out() << "</li>\n"; i++; ++m; } @@ -2649,7 +2867,7 @@ void HtmlGenerator::generateSection(const NodeList& nl, else { out() << "</ul>\n"; if (twoColumn) - out() << "</td></tr>\n</table></p>\n"; + out() << "</td></tr>\n</table>\n"; } } } @@ -2671,15 +2889,12 @@ void HtmlGenerator::generateSectionList(const Section& section, name_alignment = false; } if (name_alignment) { - out() << "<table class=\"alignedsummary\" border=\"0\" cellpadding=\"0\" " - << "cellspacing=\"0\" width=\"100%\">\n"; + out() << "<table class=\"alignedsummary\">\n"; } else { if (twoColumn) - out() << "<p><table class=\"propsummary\" width=\"100%\" " - << "border=\"0\" cellpadding=\"0\"" - << " cellspacing=\"0\">\n" - << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<table class=\"propsummary\">\n" + << "<tr><td class=\"topAlign\">"; out() << "<ul>\n"; } @@ -2692,20 +2907,19 @@ void HtmlGenerator::generateSectionList(const Section& section, } if (name_alignment) { - out() << "<tr><td class=\"memItemLeft\" " - << "align=\"right\" valign=\"top\">"; + out() << "<tr><td class=\"memItemLeft topAlign rightAlign\"> "; } else { if (twoColumn && i == (int) (section.members.count() + 1) / 2) - out() << "</ul></td><td valign=\"top\"><ul>\n"; - out() << "<li><div class=\"fn\">"; + out() << "</ul></td><td class=\"topAlign\"><ul>\n"; + out() << "<li class=\"fn\">"; } generateSynopsis(*m, relative, marker, style, name_alignment); if (name_alignment) out() << "</td></tr>\n"; else - out() << "</div></li>\n"; + out() << "</li>\n"; i++; ++m; } @@ -2714,7 +2928,7 @@ void HtmlGenerator::generateSectionList(const Section& section, else { out() << "</ul>\n"; if (twoColumn) - out() << "</td></tr>\n</table></p>\n"; + out() << "</td></tr>\n</table>\n"; } } @@ -2733,9 +2947,9 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, QList<QPair<ClassNode *, int> >::ConstIterator p = section.inherited.begin(); while (p != section.inherited.end()) { if (nameAlignment) - out() << "<li><div bar=\"2\" class=\"fn\"></div>"; + out() << "<li class=\"fn\">"; else - out() << "<li><div class=\"fn\"></div>"; + out() << "<li class=\"fn\">"; out() << (*p).second << " "; if ((*p).second == 1) { out() << section.singularMember; @@ -2745,7 +2959,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, } out() << " inherited from <a href=\"" << fileName((*p).first) << "#" << HtmlGenerator::cleanRef(section.name.toLower()) << "\">" - << protect(marker->plainFullName((*p).first, relative)) + << protectEnc(marker->plainFullName((*p).first, relative)) << "</a></li>\n"; ++p; } @@ -2760,7 +2974,7 @@ void HtmlGenerator::generateSynopsis(const Node *node, QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { - QString contents = protect(marked.mid(templateTag.pos(1), + QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); @@ -2780,7 +2994,7 @@ void HtmlGenerator::generateSynopsis(const Node *node, extraRegExp.setMinimal(true); marked.replace(extraRegExp, ""); } else { - marked.replace("<@extra>", " <tt>"); + marked.replace("<@extra>", "<tt>"); marked.replace("</@extra>", "</tt>"); } @@ -2811,7 +3025,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, for (int i = 0, n = src.size(); i < n;) { if (src.at(i) == charLangle && src.at(i + 1).unicode() == '@') { if (nameAlignment && !done) {// && (i != 0)) Why was this here? - html += "</td><td class=\"memItemRight\" valign=\"bottom\">"; + html += "</td><td class=\"memItemRight bottomAlign\">"; done = true; } i += 2; @@ -2976,9 +3190,13 @@ void HtmlGenerator::generateSectionList(const Section& section, twoColumn = (section.members.count() >= 5); } if (twoColumn) - out() << "<p><table class=\"generic\" width=\"100%\" border=\"0\" " - << "cellpadding=\"0\" cellspacing=\"0\">\n" - << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<table class=\"generic\">\n"; + if (++numTableRows % 2 == 1) + out() << "<tr class=\"odd topAlign\">"; + else + out() << "<tr class=\"even topAlign\">"; + +// << "<tr><td class=\"topAlign\">"; out() << "<ul>\n"; int i = 0; @@ -2990,9 +3208,9 @@ void HtmlGenerator::generateSectionList(const Section& section, } if (twoColumn && i == (int) (section.members.count() + 1) / 2) - out() << "</ul></td><td valign=\"top\"><ul>\n"; + out() << "</ul></td><td class=\"topAlign\"><ul>\n"; - out() << "<li><div class=\"fn\"></div>"; + out() << "<li class=\"fn\">"; if (style == CodeMarker::Accessors) out() << "<b>"; generateSynopsis(*m, relative, marker, style); @@ -3004,7 +3222,7 @@ void HtmlGenerator::generateSectionList(const Section& section, } out() << "</ul>\n"; if (twoColumn) - out() << "</td></tr>\n</table></p>\n"; + out() << "</td></tr>\n</table>\n"; } if (style == CodeMarker::Summary && !section.inherited.isEmpty()) { @@ -3020,7 +3238,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, { QList<QPair<ClassNode *, int> >::ConstIterator p = section.inherited.begin(); while (p != section.inherited.end()) { - out() << "<li><div bar=\"2\" class=\"fn\"></div>"; + out() << "<li class=\"fn\">"; out() << (*p).second << " "; if ((*p).second == 1) { out() << section.singularMember; @@ -3029,7 +3247,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, } out() << " inherited from <a href=\"" << fileName((*p).first) << "#" << HtmlGenerator::cleanRef(section.name.toLower()) << "\">" - << protect(marker->plainFullName((*p).first, relative)) + << protectEnc(marker->plainFullName((*p).first, relative)) << "</a></li>\n"; ++p; } @@ -3043,7 +3261,7 @@ void HtmlGenerator::generateSynopsis(const Node *node, QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { - QString contents = protect(marked.mid(templateTag.pos(1), + QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); @@ -3060,7 +3278,7 @@ void HtmlGenerator::generateSynopsis(const Node *node, extraRegExp.setMinimal(true); marked.replace(extraRegExp, ""); } else { - marked.replace("<@extra>", " <tt>"); + marked.replace("<@extra>", "<tt>"); marked.replace("</@extra>", "</tt>"); } @@ -3241,7 +3459,7 @@ void HtmlGenerator::generateLink(const Atom* atom, if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) { // hack for C++: move () outside of link int k = funcLeftParen.pos(1); - out() << protect(atom->string().left(k)); + out() << protectEnc(atom->string().left(k)); if (link.isEmpty()) { if (showBrokenLinks) out() << "</i>"; @@ -3249,7 +3467,7 @@ void HtmlGenerator::generateLink(const Atom* atom, out() << "</a>"; } inLink = false; - out() << protect(atom->string().mid(k)); + out() << protectEnc(atom->string().mid(k)); } else if (marker->recognizeLanguage("Java")) { // hack for Java: remove () and use <tt> when appropriate bool func = atom->string().endsWith("()"); @@ -3257,13 +3475,13 @@ void HtmlGenerator::generateLink(const Atom* atom, if (tt) out() << "<tt>"; if (func) { - out() << protect(atom->string().left(atom->string().length() - 2)); + out() << protectEnc(atom->string().left(atom->string().length() - 2)); } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } out() << "</tt>"; } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } } @@ -3337,7 +3555,12 @@ QString HtmlGenerator::registerRef(const QString& ref) return clean; } -QString HtmlGenerator::protect(const QString& string) +QString HtmlGenerator::protectEnc(const QString &string) +{ + return protect(string, outputEncoding); +} + +QString HtmlGenerator::protect(const QString &string, const QString &outputEncoding) { #define APPEND(x) \ if (html.isEmpty()) { \ @@ -3360,7 +3583,7 @@ QString HtmlGenerator::protect(const QString& string) APPEND(">"); } else if (ch == QLatin1Char('"')) { APPEND("""); - } else if (ch.unicode() > 0x007F + } else if ((outputEncoding == "ISO-8859-1" && ch.unicode() > 0x007F) || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) { // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator @@ -3490,7 +3713,7 @@ QString HtmlGenerator::refForNode(const Node *node) ref = node->name() + "-var"; break; case Node::Target: - return protect(node->name()); + return protectEnc(node->name()); } return registerRef(ref); } @@ -3564,7 +3787,7 @@ void HtmlGenerator::generateFullName(const Node *apparentNode, } } out() << "\">"; - out() << protect(fullName(apparentNode, relative, marker)); + out() << protectEnc(fullName(apparentNode, relative, marker)); out() << "</a>"; } @@ -3574,14 +3797,18 @@ void HtmlGenerator::generateDetailedMember(const Node *node, { const EnumNode *enume; +#ifdef GENERATE_MAC_REFS generateMacRef(node, marker); +#endif if (node->type() == Node::Enum && (enume = static_cast<const EnumNode *>(node))->flagsType()) { +#ifdef GENERATE_MAC_REFS generateMacRef(enume->flagsType(), marker); +#endif out() << "<h3 class=\"flags\">"; out() << "<a name=\"" + refForNode(node) + "\"></a>"; generateSynopsis(enume, relative, marker, CodeMarker::Detailed); - out() << "<br />"; + out() << "<br/>"; generateSynopsis(enume->flagsType(), relative, marker, @@ -3625,12 +3852,12 @@ void HtmlGenerator::generateDetailedMember(const Node *node, else if (node->type() == Node::Enum) { const EnumNode *enume = static_cast<const EnumNode *>(node); if (enume->flagsType()) { - out() << "<p>The " << protect(enume->flagsType()->name()) + out() << "<p>The " << protectEnc(enume->flagsType()->name()) << " type is a typedef for " << "<a href=\"qflags.html\">QFlags</a><" - << protect(enume->name()) + << protectEnc(enume->name()) << ">. It stores an OR combination of " - << protect(enume->name()) + << protectEnc(enume->name()) << " values.</p>\n"; } } @@ -3700,6 +3927,9 @@ void HtmlGenerator::findAllSince(const InnerNode *node) NewClassMaps::iterator ncmap = newClassMaps.find(sinceVersion); if (ncmap == newClassMaps.end()) ncmap = newClassMaps.insert(sinceVersion,NodeMap()); + NewClassMaps::iterator nqcmap = newQmlClassMaps.find(sinceVersion); + if (nqcmap == newQmlClassMaps.end()) + nqcmap = newQmlClassMaps.insert(sinceVersion,NodeMap()); if ((*child)->type() == Node::Function) { FunctionNode *func = static_cast<FunctionNode *>(*child); @@ -3719,6 +3949,15 @@ void HtmlGenerator::findAllSince(const InnerNode *node) nsmap.value().insert(className,(*child)); ncmap.value().insert(className,(*child)); } + else if ((*child)->subType() == Node::QmlClass) { + QString className = (*child)->name(); + if ((*child)->parent() && + (*child)->parent()->type() == Node::Namespace && + !(*child)->parent()->name().isEmpty()) + className = (*child)->parent()->name()+"::"+className; + nsmap.value().insert(className,(*child)); + nqcmap.value().insert(className,(*child)); + } } else { QString name = (*child)->name(); @@ -3939,10 +4178,12 @@ QString HtmlGenerator::getLink(const Atom *atom, } else { *node = marker->resolveTarget(first, myTree, relative); - if (!*node) + if (!*node) { *node = myTree->findFakeNodeByTitle(first); - if (!*node) + } + if (!*node) { *node = myTree->findUnambiguousTarget(first, targetAtom); + } } if (*node) { @@ -4077,6 +4318,10 @@ void HtmlGenerator::generateStatus(const Node *node, CodeMarker *marker) } } +#ifdef GENERATE_MAC_REFS +/* + No longer valid. + */ void HtmlGenerator::generateMacRef(const Node *node, CodeMarker *marker) { if (!pleaseGenerateMacRef || marker == 0) @@ -4086,6 +4331,7 @@ void HtmlGenerator::generateMacRef(const Node *node, CodeMarker *marker) foreach (const QString &macRef, macRefs) out() << "<a name=\"" << "//apple_ref/" << macRef << "\"></a>\n"; } +#endif void HtmlGenerator::beginLink(const QString &link, const Node *node, @@ -4137,12 +4383,10 @@ void HtmlGenerator::endLink() inObsoleteLink = false; } -QT_END_NAMESPACE - #ifdef QDOC_QML /*! - Generates the summary for for the \a section. Only used for + Generates the summary for the \a section. Only used for sections of QML element documentation. Currently handles only the QML property group. @@ -4159,17 +4403,20 @@ void HtmlGenerator::generateQmlSummary(const Section& section, twoColumn = (count >= 5); } if (twoColumn) - out() << "<p><table width=\"100%\" border=\"0\" cellpadding=\"0\"" - " cellspacing=\"0\">\n" - << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<table class=\"qmlsummary\">\n"; + if (++numTableRows % 2 == 1) + out() << "<tr class=\"odd topAlign\">"; + else + out() << "<tr class=\"even topAlign\">"; + // << "<tr><td class=\"topAlign\">"; out() << "<ul>\n"; int row = 0; m = section.members.begin(); while (m != section.members.end()) { if (twoColumn && row == (int) (count + 1) / 2) - out() << "</ul></td><td valign=\"top\"><ul>\n"; - out() << "<li><div class=\"fn\"></div>"; + out() << "</ul></td><td class=\"topAlign\"><ul>\n"; + out() << "<li class=\"fn\">"; generateQmlItem(*m,relative,marker,true); out() << "</li>\n"; row++; @@ -4177,7 +4424,7 @@ void HtmlGenerator::generateQmlSummary(const Section& section, } out() << "</ul>\n"; if (twoColumn) - out() << "</td></tr>\n</table></p>\n"; + out() << "</td></tr>\n</table>\n"; } } @@ -4190,32 +4437,34 @@ void HtmlGenerator::generateDetailedQmlMember(const Node *node, CodeMarker *marker) { const QmlPropertyNode* qpn = 0; +#ifdef GENERATE_MAC_REFS generateMacRef(node, marker); +#endif out() << "<div class=\"qmlitem\">"; if (node->subType() == Node::QmlPropertyGroup) { const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node); NodeList::ConstIterator p = qpgn->childNodes().begin(); out() << "<div class=\"qmlproto\">"; - out() << "<table width=\"100%\" class=\"qmlname\">"; + out() << "<table class=\"qmlname\">"; while (p != qpgn->childNodes().end()) { if ((*p)->type() == Node::QmlProperty) { qpn = static_cast<const QmlPropertyNode*>(*p); - out() << "<tr><td>"; + + if (++numTableRows % 2 == 1) + out() << "<tr class=\"odd\">"; + else + out() << "<tr class=\"even\">"; + + out() << "<td><p>"; + //out() << "<tr><td>"; // old out() << "<a name=\"" + refForNode(qpn) + "\"></a>"; if (!qpn->isWritable()) out() << "<span class=\"qmlreadonly\">read-only</span>"; + if (qpgn->isDefault()) + out() << "<span class=\"qmldefault\">default</span>"; generateQmlItem(qpn, relative, marker, false); out() << "</td></tr>"; - if (qpgn->isDefault()) { - out() << "</table>" - << "</div></div>" - << "<div class=\"qmlitem\">" - << "<div class=\"qmlproto\">" - << "<table class=\"qmlname\">" - << "<tr><td><font color=\"green\">" - << "default</font></td></tr>"; - } } ++p; } @@ -4226,11 +4475,16 @@ void HtmlGenerator::generateDetailedQmlMember(const Node *node, const FunctionNode* qsn = static_cast<const FunctionNode*>(node); out() << "<div class=\"qmlproto\">"; out() << "<table class=\"qmlname\">"; - out() << "<tr><td>"; + //out() << "<tr>"; + if (++numTableRows % 2 == 1) + out() << "<tr class=\"odd\">"; + else + out() << "<tr class=\"even\">"; + out() << "<td><p>"; out() << "<a name=\"" + refForNode(qsn) + "\"></a>"; generateSynopsis(qsn,relative,marker,CodeMarker::Detailed,false); //generateQmlItem(qsn,relative,marker,false); - out() << "</td></tr>"; + out() << "</p></td></tr>"; out() << "</table>"; out() << "</div>"; } @@ -4238,10 +4492,15 @@ void HtmlGenerator::generateDetailedQmlMember(const Node *node, const FunctionNode* qmn = static_cast<const FunctionNode*>(node); out() << "<div class=\"qmlproto\">"; out() << "<table class=\"qmlname\">"; - out() << "<tr><td>"; + //out() << "<tr>"; + if (++numTableRows % 2 == 1) + out() << "<tr class=\"odd\">"; + else + out() << "<tr class=\"even\">"; + out() << "<td><p>"; out() << "<a name=\"" + refForNode(qmn) + "\"></a>"; generateSynopsis(qmn,relative,marker,CodeMarker::Detailed,false); - out() << "</td></tr>"; + out() << "</p></td></tr>"; out() << "</table>"; out() << "</div>"; } @@ -4270,7 +4529,7 @@ void HtmlGenerator::generateQmlInherits(const QmlClassNode* cn, const Node* n = myTree->findNode(strList,Node::Fake); if (n && n->subType() == Node::QmlClass) { const QmlClassNode* qcn = static_cast<const QmlClassNode*>(n); - out() << "<p style=\"text-align: center\">"; + out() << "<p class=\"centerAlign\">"; Text text; text << "[Inherits "; text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); @@ -4286,6 +4545,26 @@ void HtmlGenerator::generateQmlInherits(const QmlClassNode* cn, } /*! + Output the "Inherit by" list for the QML element, + if it is inherited by any other elements. + */ +void HtmlGenerator::generateQmlInheritedBy(const QmlClassNode* cn, + CodeMarker* marker) +{ + if (cn) { + NodeList subs; + QmlClassNode::subclasses(cn->name(),subs); + if (!subs.isEmpty()) { + Text text; + text << Atom::ParaLeft << "Inherited by "; + appendSortedQmlNames(text,cn,subs,marker); + text << Atom::ParaRight; + generateText(text, cn, marker); + } + } +} + +/*! Output the "[Xxx instantiates the C++ class QmlGraphicsXxx]" line for the QML element, if there should be one. @@ -4297,7 +4576,7 @@ void HtmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn, { const ClassNode* cn = qcn->classNode(); if (cn && (cn->status() != Node::Internal)) { - out() << "<p style=\"text-align: center\">"; + out() << "<p class=\"centerAlign\">"; Text text; text << "["; text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); @@ -4328,7 +4607,7 @@ void HtmlGenerator::generateInstantiatedBy(const ClassNode* cn, if (cn && cn->status() != Node::Internal && !cn->qmlElement().isEmpty()) { const Node* n = myTree->root()->findNode(cn->qmlElement(),Node::Fake); if (n && n->subType() == Node::QmlClass) { - out() << "<p style=\"text-align: center\">"; + out() << "<p class=\"centerAlign\">"; Text text; text << "["; text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); @@ -4347,4 +4626,264 @@ void HtmlGenerator::generateInstantiatedBy(const ClassNode* cn, } } +/*! + Generate the <page> element for the given \a node using the \a writer. + Return true if a <page> element was written; otherwise return false. + */ +bool HtmlGenerator::generatePageElement(QXmlStreamWriter& writer, + const Node* node, + CodeMarker* marker) const +{ + if (node->pageType() == Node::NoPageType) + return false; + if (node->name().isEmpty()) + return true; + if (node->access() == Node::Private) + return false; + if (!node->isInnerNode()) + return false; + + QString title; + QString rawTitle; + QString fullTitle; + const InnerNode* inner = static_cast<const InnerNode*>(node); + + writer.writeStartElement("page"); + QXmlStreamAttributes attributes; + QString t; + t.setNum(id++); + switch (node->type()) { + case Node::Fake: + { + const FakeNode* fake = static_cast<const FakeNode*>(node); + title = fake->fullTitle(); + break; + } + case Node::Class: + { + title = node->name() + " Class Reference"; + break; + } + case Node::Namespace: + { + rawTitle = marker->plainName(inner); + fullTitle = marker->plainFullName(inner); + title = rawTitle + " Namespace Reference"; + break; + } + default: + title = node->name(); + break; + } + writer.writeAttribute("id",t); + writer.writeStartElement("pageWords"); + writer.writeCharacters(title); + if (!inner->pageKeywords().isEmpty()) { + const QStringList& w = inner->pageKeywords(); + for (int i = 0; i < w.size(); ++i) { + writer.writeCharacters(" "); + writer.writeCharacters(w.at(i).toLocal8Bit().constData()); + } + } + writer.writeEndElement(); + writer.writeStartElement("pageTitle"); + writer.writeCharacters(title); + writer.writeEndElement(); + writer.writeStartElement("pageUrl"); + writer.writeCharacters(PageGenerator::fileName(node)); + writer.writeEndElement(); + writer.writeStartElement("pageType"); + switch (node->pageType()) { + case Node::ApiPage: + writer.writeCharacters("APIPage"); + break; + case Node::ArticlePage: + writer.writeCharacters("Article"); + break; + case Node::ExamplePage: + writer.writeCharacters("Example"); + break; + default: + break; + } + writer.writeEndElement(); + writer.writeEndElement(); + return true; +} + +/*! + Traverse the tree recursively and generate the <keyword> + elements. + */ +void HtmlGenerator::generatePageElements(QXmlStreamWriter& writer, const Node* node, CodeMarker* marker) const +{ + if (generatePageElement(writer, node, marker)) { + + if (node->isInnerNode()) { + const InnerNode *inner = static_cast<const InnerNode *>(node); + + // Recurse to write an element for this child node and all its children. + foreach (const Node *child, inner->childNodes()) + generatePageElements(writer, child, marker); + } + } +} + +/*! + Outputs the file containing the index used for searching the html docs. + */ +void HtmlGenerator::generatePageIndex(const QString& fileName, CodeMarker* marker) const +{ + QFile file(fileName); + if (!file.open(QFile::WriteOnly | QFile::Text)) + return ; + + QXmlStreamWriter writer(&file); + writer.setAutoFormatting(true); + writer.writeStartDocument(); + writer.writeStartElement("qtPageIndex"); + + generatePageElements(writer, myTree->root(), marker); + + writer.writeEndElement(); // qtPageIndex + writer.writeEndDocument(); + file.close(); +} + #endif + +#if 0 // fossil removed for new doc format MWS 19/04/2010 + out() << "<!DOCTYPE html\n" + " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n"; + out() << QString("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"%1\" lang=\"%1\">\n").arg(naturalLanguage); + + QString shortVersion; + if ((project != "Qtopia") && (project != "Qt Extended")) { + shortVersion = project + " " + shortVersion + ": "; + if (node && !node->doc().location().isEmpty()) + out() << "<!-- " << node->doc().location().fileName() << " -->\n"; + + shortVersion = myTree->version(); + if (shortVersion.count(QChar('.')) == 2) + shortVersion.truncate(shortVersion.lastIndexOf(QChar('.'))); + if (!shortVersion.isEmpty()) { + if (project == "QSA") + shortVersion = "QSA " + shortVersion + ": "; + else + shortVersion = "Qt " + shortVersion + ": "; + } + } + + out() << "<head>\n" + " <title>" << shortVersion << protectEnc(title) << "</title>\n"; + out() << QString("<meta http-equiv=\"Content-type\" content=\"text/html; charset=%1\" />").arg(outputEncoding); + + if (!style.isEmpty()) + out() << " <style type=\"text/css\">" << style << "</style>\n"; + + const QMap<QString, QString> &metaMap = node->doc().metaTagMap(); + if (!metaMap.isEmpty()) { + QMapIterator<QString, QString> i(metaMap); + while (i.hasNext()) { + i.next(); + out() << " <meta name=\"" << protectEnc(i.key()) << "\" contents=\"" + << protectEnc(i.value()) << "\" />\n"; + } + } + + navigationLinks.clear(); + + if (node && !node->links().empty()) { + QPair<QString,QString> linkPair; + QPair<QString,QString> anchorPair; + const Node *linkNode; + + if (node->links().contains(Node::PreviousLink)) { + linkPair = node->links()[Node::PreviousLink]; + linkNode = findNodeForTarget(linkPair.first, node, marker); + if (!linkNode || linkNode == node) + anchorPair = linkPair; + else + anchorPair = anchorForNode(linkNode); + + out() << " <link rel=\"prev\" href=\"" + << anchorPair.first << "\" />\n"; + + navigationLinks += "[Previous: <a href=\"" + anchorPair.first + "\">"; + if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) + navigationLinks += protectEnc(anchorPair.second); + else + navigationLinks += protectEnc(linkPair.second); + navigationLinks += "</a>]\n"; + } + if (node->links().contains(Node::ContentsLink)) { + linkPair = node->links()[Node::ContentsLink]; + linkNode = findNodeForTarget(linkPair.first, node, marker); + if (!linkNode || linkNode == node) + anchorPair = linkPair; + else + anchorPair = anchorForNode(linkNode); + + out() << " <link rel=\"contents\" href=\"" + << anchorPair.first << "\" />\n"; + + navigationLinks += "[<a href=\"" + anchorPair.first + "\">"; + if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) + navigationLinks += protectEnc(anchorPair.second); + else + navigationLinks += protectEnc(linkPair.second); + navigationLinks += "</a>]\n"; + } + if (node->links().contains(Node::NextLink)) { + linkPair = node->links()[Node::NextLink]; + linkNode = findNodeForTarget(linkPair.first, node, marker); + if (!linkNode || linkNode == node) + anchorPair = linkPair; + else + anchorPair = anchorForNode(linkNode); + + out() << " <link rel=\"next\" href=\"" + << anchorPair.first << "\" />\n"; + + navigationLinks += "[Next: <a href=\"" + anchorPair.first + "\">"; + if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) + navigationLinks += protectEnc(anchorPair.second); + else + navigationLinks += protectEnc(linkPair.second); + navigationLinks += "</a>]\n"; + } + if (node->links().contains(Node::IndexLink)) { + linkPair = node->links()[Node::IndexLink]; + linkNode = findNodeForTarget(linkPair.first, node, marker); + if (!linkNode || linkNode == node) + anchorPair = linkPair; + else + anchorPair = anchorForNode(linkNode); + out() << " <link rel=\"index\" href=\"" + << anchorPair.first << "\" />\n"; + } + if (node->links().contains(Node::StartLink)) { + linkPair = node->links()[Node::StartLink]; + linkNode = findNodeForTarget(linkPair.first, node, marker); + if (!linkNode || linkNode == node) + anchorPair = linkPair; + else + anchorPair = anchorForNode(linkNode); + out() << " <link rel=\"start\" href=\"" + << anchorPair.first << "\" />\n"; + } + } + + foreach (const QString &stylesheet, stylesheets) { + out() << " <link href=\"" << stylesheet << "\" rel=\"stylesheet\" " + << "type=\"text/css\" />\n"; + } + + foreach (const QString &customHeadElement, customHeadElements) { + out() << " " << customHeadElement << "\n"; + } + + out() << "</head>\n" + #endif + + QT_END_NAMESPACE diff --git a/tools/qdoc3/htmlgenerator.h b/tools/qdoc3/htmlgenerator.h index 19a7c78..e060257 100644 --- a/tools/qdoc3/htmlgenerator.h +++ b/tools/qdoc3/htmlgenerator.h @@ -50,6 +50,7 @@ #include <qmap.h> #include <qregexp.h> +#include <QXmlStreamWriter> #include "codemarker.h" #include "config.h" @@ -89,6 +90,7 @@ class HtmlGenerator : public PageGenerator Typedef, Property, Variable, + QmlClass, QmlProperty, QmlSignal, QmlMethod, @@ -104,7 +106,8 @@ class HtmlGenerator : public PageGenerator virtual QString format(); virtual void generateTree(const Tree *tree, CodeMarker *marker); - static QString protect(const QString& string); + QString protectEnc(const QString &string); + static QString protect(const QString &string, const QString &encoding = "ISO-8859-1"); static QString cleanRef(const QString& ref); static QString sinceTitle(int i) { return sinceTitles[i]; } @@ -115,7 +118,7 @@ class HtmlGenerator : public PageGenerator CodeMarker *marker); virtual void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker); virtual void generateFakeNode(const FakeNode *fake, CodeMarker *marker); - virtual QString fileExtension(const Node *node); + virtual QString fileExtension(const Node *node) const; virtual QString refForNode(const Node *node); virtual QString linkForNode(const Node *node, const Node *relative); virtual QString refForAtom(Atom *atom, const Node *node); @@ -128,8 +131,12 @@ class HtmlGenerator : public PageGenerator const Node *relative, CodeMarker *marker, const Atom *atom = 0); - void generateHeader(const QString& title, const Node *node = 0, - CodeMarker *marker = 0, bool mainPage = true); + void generateBreadCrumbs(const QString& title, + const Node *node, + CodeMarker *marker); + void generateHeader(const QString& title, + const Node *node = 0, + CodeMarker *marker = 0); void generateTitle(const QString& title, const Text &subTitle, SubTitleSize subTitleSize, @@ -150,6 +157,9 @@ class HtmlGenerator : public PageGenerator Doc::SectioningUnit sectioningUnit, int numColumns, const Node *relative = 0); + void generateTableOfContents(const Node *node, + CodeMarker *marker, + QList<Section>* sections = 0); QString generateListOfAllMemberFile(const InnerNode *inner, CodeMarker *marker); QString generateLowStatusMemberFile(const InnerNode *inner, CodeMarker *marker, @@ -163,6 +173,7 @@ class HtmlGenerator : public PageGenerator void generateCompactList(const Node *relative, CodeMarker *marker, const NodeMap &classMap, + bool includeAlphabet, QString commonPrefix = QString()); void generateFunctionIndex(const Node *relative, CodeMarker *marker); void generateLegaleseList(const Node *relative, CodeMarker *marker); @@ -183,6 +194,7 @@ class HtmlGenerator : public PageGenerator const InnerNode *relative, CodeMarker *marker); void generateQmlInherits(const QmlClassNode* cn, CodeMarker* marker); + void generateQmlInheritedBy(const QmlClassNode* cn, CodeMarker* marker); void generateQmlInstantiates(const QmlClassNode* qcn, CodeMarker* marker); void generateInstantiatedBy(const ClassNode* cn, CodeMarker* marker); #endif @@ -255,12 +267,22 @@ class HtmlGenerator : public PageGenerator virtual void generateIndex(const QString &fileBase, const QString &url, const QString &title); +#ifdef GENERATE_MAC_REFS void generateMacRef(const Node *node, CodeMarker *marker); +#endif void beginLink(const QString &link, const Node *node, const Node *relative, CodeMarker *marker); void endLink(); + bool generatePageElement(QXmlStreamWriter& writer, + const Node* node, + CodeMarker* marker) const; + void generatePageElements(QXmlStreamWriter& writer, + const Node* node, + CodeMarker* marker) const; + void generatePageIndex(const QString& fileName, + CodeMarker* marker) const; #if 0 NavigationBar currentNavigationBar; @@ -282,11 +304,13 @@ class HtmlGenerator : public PageGenerator bool inTableHeader; int numTableRows; bool threeColumnEnumValueTable; + bool offlineDocs; QString link; QStringList sectionNumber; QRegExp funcLeftParen; QString style; QString postHeader; + QString postPostHeader; QString footer; QString address; bool pleaseGenerateMacRef; @@ -315,12 +339,15 @@ class HtmlGenerator : public PageGenerator NewSinceMaps newSinceMaps; static QString sinceTitles[]; NewClassMaps newClassMaps; + NewClassMaps newQmlClassMaps; + static int id; }; #define HTMLGENERATOR_ADDRESS "address" #define HTMLGENERATOR_FOOTER "footer" -#define HTMLGENERATOR_GENERATEMACREFS "generatemacrefs" // ### document me +#define HTMLGENERATOR_GENERATEMACREFS "generatemacrefs" // ### document me #define HTMLGENERATOR_POSTHEADER "postheader" +#define HTMLGENERATOR_POSTPOSTHEADER "postpostheader" #define HTMLGENERATOR_STYLE "style" #define HTMLGENERATOR_STYLESHEETS "stylesheets" #define HTMLGENERATOR_CUSTOMHEADELEMENTS "customheadelements" diff --git a/tools/qdoc3/jambiapiparser.cpp b/tools/qdoc3/jambiapiparser.cpp index 3aba1b0..23f2716 100644 --- a/tools/qdoc3/jambiapiparser.cpp +++ b/tools/qdoc3/jambiapiparser.cpp @@ -43,8 +43,6 @@ jambiapiparser.cpp */ -#include <QtXml> - #include "cppcodeparser.h" #include "jambiapiparser.h" #include "node.h" diff --git a/tools/qdoc3/javadocgenerator.cpp b/tools/qdoc3/javadocgenerator.cpp index 001bd27..eb9c1c9 100644 --- a/tools/qdoc3/javadocgenerator.cpp +++ b/tools/qdoc3/javadocgenerator.cpp @@ -145,7 +145,7 @@ void JavadocGenerator::generateTree(const Tree *tree, CodeMarker *marker) HtmlGenerator::generateTree(tree, marker); } -QString JavadocGenerator::fileExtension(const Node *node) +QString JavadocGenerator::fileExtension(const Node *node) const { if (node->type() == Node::Fake) { return "html"; diff --git a/tools/qdoc3/javadocgenerator.h b/tools/qdoc3/javadocgenerator.h index 73452cf..b485502 100644 --- a/tools/qdoc3/javadocgenerator.h +++ b/tools/qdoc3/javadocgenerator.h @@ -61,7 +61,7 @@ public: QString imageFileName(const Node *relative, const QString &fileBase); protected: - QString fileExtension(const Node *node); + QString fileExtension(const Node *node) const; void startText( const Node *relative, CodeMarker *marker ); void endText( const Node *relative, CodeMarker *marker ); int generateAtom( const Atom *atom, const Node *relative, CodeMarker *marker ); diff --git a/tools/qdoc3/linguistgenerator.cpp b/tools/qdoc3/linguistgenerator.cpp index d1bd22d..702f0fb 100644 --- a/tools/qdoc3/linguistgenerator.cpp +++ b/tools/qdoc3/linguistgenerator.cpp @@ -82,14 +82,14 @@ QString LinguistGenerator::format() return "Linguist"; } -QString LinguistGenerator::fileExtension(const Node * /* node */) +QString LinguistGenerator::fileExtension(const Node * /* node */) const { return "ts"; } void LinguistGenerator::generateClassLikeNode(const InnerNode *inner, CodeMarker *marker) { - out().setCodec("utf-8"); + out().setCodec("UTF-8"); QDomDocument document("TS"); QDomElement documentElement = document.createElement("TS"); @@ -100,7 +100,7 @@ void LinguistGenerator::generateClassLikeNode(const InnerNode *inner, CodeMarker documentElement.appendChild(element); QDomProcessingInstruction process = document.createProcessingInstruction( - "xml", QString("version=\"1.0\" encoding=\"%1\"").arg("utf-8")); + "xml", QString("version=\"1.0\" encoding=\"%1\"").arg("UTF-8")); document.appendChild(process); document.appendChild(documentElement); diff --git a/tools/qdoc3/linguistgenerator.h b/tools/qdoc3/linguistgenerator.h index f7f0606..979db02 100644 --- a/tools/qdoc3/linguistgenerator.h +++ b/tools/qdoc3/linguistgenerator.h @@ -70,7 +70,7 @@ protected: virtual void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker); virtual void generateFakeNode( const FakeNode *fake, CodeMarker *marker ); - virtual QString fileExtension(const Node *node); + virtual QString fileExtension(const Node *node) const; QList<QDomElement> generateIndexSections(QDomDocument &document, const Node *node, CodeMarker *marker); diff --git a/tools/qdoc3/location.cpp b/tools/qdoc3/location.cpp index 19625da..dee87d1 100644 --- a/tools/qdoc3/location.cpp +++ b/tools/qdoc3/location.cpp @@ -265,6 +265,8 @@ void Location::error(const QString& message, const QString& details) const void Location::fatal(const QString& message, const QString& details) const { emitMessage(Error, message, details); + information(message); + information(details); information("Aborting"); exit(EXIT_FAILURE); } diff --git a/tools/qdoc3/main.cpp b/tools/qdoc3/main.cpp index 3d0106d..fe4ad86 100644 --- a/tools/qdoc3/main.cpp +++ b/tools/qdoc3/main.cpp @@ -44,7 +44,6 @@ */ #include <qglobal.h> -#include <QtCore> #include <stdlib.h> #include "apigenerator.h" #include "codemarker.h" @@ -71,6 +70,12 @@ #include "webxmlgenerator.h" #include "tokenizer.h" #include "tree.h" +#include <qdebug.h> + +#include "qtranslator.h" +#ifndef QT_BOOTSTRAPPED +# include "qcoreapplication.h" +#endif QT_BEGIN_NAMESPACE @@ -151,7 +156,9 @@ static void printVersion() */ static void processQdocconfFile(const QString &fileName) { +#ifndef QT_NO_TRANSLATION QList<QTranslator *> translators; +#endif /* The Config instance represents the configuration data for qdoc. @@ -207,6 +214,7 @@ static void processQdocconfFile(const QString &fileName) CodeParser::initialize(config); Generator::initialize(config); +#ifndef QT_NO_TRANSLATION /* Load the language translators, if the configuration specifies any. */ @@ -221,6 +229,7 @@ static void processQdocconfFile(const QString &fileName) translators.append(translator); ++fn; } +#endif //QSet<QString> outputLanguages = config.getStringSet(CONFIG_OUTPUTLANGUAGES); @@ -337,8 +346,9 @@ static void processQdocconfFile(const QString &fileName) Generate the XML tag file, if it was requested. */ QString tagFile = config.getString(CONFIG_TAGFILE); - if (!tagFile.isEmpty()) + if (!tagFile.isEmpty()) { tree->generateTagFile(tagFile); + } tree->setVersion(""); Generator::terminate(); @@ -350,9 +360,16 @@ static void processQdocconfFile(const QString &fileName) Location::terminate(); QDir::setCurrent(prevCurrentDir); - foreach (QTranslator *translator, translators) - delete translator; +#ifndef QT_NO_TRANSLATION + qDeleteAll(translators); +#endif +#ifdef DEBUG_SHUTDOWN_CRASH + qDebug() << "main(): Delete tree"; +#endif delete tree; +#ifdef DEBUG_SHUTDOWN_CRASH + qDebug() << "main(): Tree deleted"; +#endif } QT_END_NAMESPACE @@ -361,7 +378,9 @@ int main(int argc, char **argv) { QT_USE_NAMESPACE +#ifndef QT_BOOTSTRAPPED QCoreApplication app(argc, argv); +#endif QString cf = "qsauncompress \1 \2"; PolyArchiveExtractor qsaExtractor(QStringList() << "qsa",cf); cf = "tar -C \2 -xf \1"; diff --git a/tools/qdoc3/mangenerator.cpp b/tools/qdoc3/mangenerator.cpp index c3b7780..1e85b73 100644 --- a/tools/qdoc3/mangenerator.cpp +++ b/tools/qdoc3/mangenerator.cpp @@ -187,7 +187,7 @@ void ManGenerator::generateFakeNode( const FakeNode *fake, CodeMarker *marker ) generateFooter(); } -QString ManGenerator::fileExtension(const Node * /* node */) +QString ManGenerator::fileExtension(const Node * /* node */) const { return "3qt"; } diff --git a/tools/qdoc3/mangenerator.h b/tools/qdoc3/mangenerator.h index 284517e..0fca342 100644 --- a/tools/qdoc3/mangenerator.h +++ b/tools/qdoc3/mangenerator.h @@ -63,7 +63,7 @@ protected: CodeMarker *marker ); virtual void generateClassLikeNode(const InnerNode *node, CodeMarker *marker); virtual void generateFakeNode( const FakeNode *fake, CodeMarker *marker ); - virtual QString fileExtension(const Node *node); + virtual QString fileExtension(const Node *node) const; private: void generateHeader( const QString& name ); diff --git a/tools/qdoc3/node.cpp b/tools/qdoc3/node.cpp index 5796ea4..4ba3a32 100644 --- a/tools/qdoc3/node.cpp +++ b/tools/qdoc3/node.cpp @@ -43,8 +43,8 @@ node.cpp */ -#include <QtCore> #include "node.h" +#include <qdebug.h> QT_BEGIN_NAMESPACE @@ -85,12 +85,16 @@ void Node::setDoc(const Doc& doc, bool replace) } /*! + Construct a node with the given \a type and having the + given \a parent and \a name. The new node is added to the + parent's child list. */ Node::Node(Type type, InnerNode *parent, const QString& name) : typ(type), acc(Public), - sta(Commendable), saf(UnspecifiedSafeness), + pageTyp(NoPageType), + sta(Commendable), par(parent), rel(0), nam(name) @@ -100,6 +104,7 @@ Node::Node(Type type, InnerNode *parent, const QString& name) } /*! + Returns the node's URL. */ QString Node::url() const { @@ -107,13 +112,25 @@ QString Node::url() const } /*! + Sets the node's URL to \a url */ void Node::setUrl(const QString &url) { u = url; } +void Node::setPageType(const QString& t) +{ + if ((t == "API") || (t == "api")) + pageTyp = ApiPage; + else if (t == "article") + pageTyp = ArticlePage; + else if (t == "example") + pageTyp = ExamplePage; +} + /*! + Sets the pointer to the node that this node relates to. */ void Node::setRelates(InnerNode *pseudoParent) { @@ -190,16 +207,33 @@ InnerNode::~InnerNode() } /*! + Find the node in this node's children that has the + given \a name. If this node is a QML class node, be + sure to also look in the children of its property + group nodes. Return the matching node or 0. */ Node *InnerNode::findNode(const QString& name) { Node *node = childMap.value(name); if (node) return node; + if ((type() == Fake) && (subType() == QmlClass)) { + for (int i=0; i<children.size(); ++i) { + Node* n = children.at(i); + if (n->subType() == QmlPropertyGroup) { + node = static_cast<InnerNode*>(n)->findNode(name); + if (node) + return node; + } + } + } return primaryFunctionMap.value(name); } /*! + Same as the other findNode(), but if the node with the + specified \a name is not of the specified \a type, return + 0. */ Node *InnerNode::findNode(const QString& name, Type type) { @@ -381,7 +415,7 @@ void InnerNode::normalizeOverloads() /*! */ -void InnerNode::removeFromRelated() +void InnerNode::removeFromRelated() { while (!related.isEmpty()) { Node *p = static_cast<Node *>(related.takeFirst()); @@ -398,7 +432,7 @@ void InnerNode::deleteChildren() } /*! - Returns true. + Returns true because this is an inner node. */ bool InnerNode::isInnerNode() const { @@ -422,7 +456,7 @@ const Node *InnerNode::findNode(const QString& name, Type type) const } /*! - Find the function node in this node that has the given \a name. + Find the function node in this node that has the given \a name. */ const FunctionNode *InnerNode::findFunctionNode(const QString& name) const { @@ -452,6 +486,9 @@ const EnumNode *InnerNode::findEnumNodeForValue(const QString &enumValue) const } /*! + Returnds the sequence number of the function node \a func + in the list of overloaded functions for a class, such that + all the functions have the same name as the \a func. */ int InnerNode::overloadNumber(const FunctionNode *func) const { @@ -465,6 +502,8 @@ int InnerNode::overloadNumber(const FunctionNode *func) const } /*! + Returns the number of member functions of a class such that + the functions are all named \a funcName. */ int InnerNode::numOverloads(const QString& funcName) const { @@ -477,6 +516,8 @@ int InnerNode::numOverloads(const QString& funcName) const } /*! + Returns a node list containing all the member functions of + some class such that the functions overload the name \a funcName. */ NodeList InnerNode::overloads(const QString &funcName) const { @@ -490,10 +531,14 @@ NodeList InnerNode::overloads(const QString &funcName) const } /*! + Construct an inner node (i.e., not a leaf node) of the + given \a type and having the given \a parent and \a name. */ InnerNode::InnerNode(Type type, InnerNode *parent, const QString& name) : Node(type, parent, name) { + if (type == Class) + setPageType(ApiPage); } /*! @@ -547,6 +592,7 @@ bool InnerNode::isSameSignature(const FunctionNode *f1, const FunctionNode *f2) } /*! + Adds the \a child to this node's child list. */ void InnerNode::addChild(Node *child) { @@ -564,7 +610,7 @@ void InnerNode::addChild(Node *child) else { if (child->type() == Enum) enumChildren.append(child); - childMap.insert(child->name(), child); + childMap.insert(child->name(), child); } } @@ -676,6 +722,8 @@ bool LeafNode::isInnerNode() const } /*! + Constructs a leaf node named \a name of the specified + \a type. The new leaf node becomes a child of \a parent. */ LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name) : Node(type, parent, name) @@ -687,10 +735,12 @@ LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name) */ /*! + Constructs a namespace node. */ NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name) : InnerNode(Namespace, parent, name) { + setPageType(ApiPage); } /*! @@ -698,11 +748,13 @@ NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name) */ /*! + Constructs a class node. A class node will generate an API page. */ ClassNode::ClassNode(InnerNode *parent, const QString& name) : InnerNode(Class, parent, name) { hidden = false; + setPageType(ApiPage); } /*! @@ -759,11 +811,28 @@ void ClassNode::fixBaseClasses() /*! The type of a FakeNode is Fake, and it has a \a subtype, - which specifies the type of FakeNode. + which specifies the type of FakeNode. The page type for + the page index is set here. */ FakeNode::FakeNode(InnerNode *parent, const QString& name, SubType subtype) : InnerNode(Fake, parent, name), sub(subtype) { + switch (subtype) { + case Module: + case Page: + case Group: + setPageType(ArticlePage); + break; + case QmlClass: + case QmlBasicType: + setPageType(ApiPage); + break; + case Example: + setPageType(ExamplePage); + break; + default: + break; + } } /*! @@ -904,7 +973,7 @@ Parameter::Parameter(const Parameter& p) /*! Assigning Parameter \a p to this Parameter copies the - strings across. + strings across. */ Parameter& Parameter::operator=(const Parameter& p) { @@ -1109,7 +1178,8 @@ QString FunctionNode::signature(bool values) const */ void FunctionNode::debug() const { - qDebug() << "QML METHOD" << name() << "rt" << rt << "pp" << pp; + qDebug("QML METHOD %s rt %s pp %s", + qPrintable(name()), qPrintable(rt), qPrintable(pp.join(" "))); } /*! @@ -1205,16 +1275,40 @@ bool TargetNode::isInnerNode() const #ifdef QDOC_QML bool QmlClassNode::qmlOnly = false; +QMultiMap<QString,Node*> QmlClassNode::inheritedBy; /*! - Constructor for the Qml class node. + Constructs a Qml class node (i.e. a Fake node with the + subtype QmlClass. The new node has the given \a parent + and \a name and is associated with the C++ class node + specified by \a cn which may be null if the the Qml + class node is not associated with a C++ class node. */ QmlClassNode::QmlClassNode(InnerNode *parent, const QString& name, const ClassNode* cn) : FakeNode(parent, name, QmlClass), cnode(cn) { - setTitle((qmlOnly ? "" : "QML ") + name + " Element Reference"); + setTitle((qmlOnly ? "" : "QML ") + name + " Element"); +} + +/*! + I made this so I could print a debug message here. + */ +QmlClassNode::~QmlClassNode() +{ +#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES + qDebug() << "Deleting QmlClassNode:" << name(); +#endif +} + +/*! + Clear the multimap so that subsequent runs don't try to use + nodes from a previous run. + */ +void QmlClassNode::clear() +{ + inheritedBy.clear(); } /*! @@ -1225,7 +1319,7 @@ QmlClassNode::QmlClassNode(InnerNode *parent, */ QString QmlClassNode::fileBase() const { -#if 0 +#if 0 if (Node::fileBase() == "item") qDebug() << "FILEBASE: qmlitem" << name(); return "qml_" + Node::fileBase(); @@ -1234,8 +1328,47 @@ QString QmlClassNode::fileBase() const } /*! + Record the fact that QML class \a base is inherited by + QML class \a sub. + */ +void QmlClassNode::addInheritedBy(const QString& base, Node* sub) +{ + inheritedBy.insert(base,sub); +#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES + qDebug() << "QmlClassNode::addInheritedBy(): insert" << base << sub->name() << inheritedBy.size(); +#endif +} + +/*! + Loads the list \a subs with the nodes of all the subclasses of \a base. + */ +void QmlClassNode::subclasses(const QString& base, NodeList& subs) +{ + subs.clear(); + if (inheritedBy.count(base) > 0) { + subs = inheritedBy.values(base); +#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES + qDebug() << "QmlClassNode::subclasses():" << inheritedBy.count(base) << base + << "subs:" << subs.size() << "total size:" << inheritedBy.size(); +#endif + } +} + +/*! + Constructs a Qml basic type node (i.e. a Fake node with + the subtype QmlBasicType. The new node has the given + \a parent and \a name. + */ +QmlBasicTypeNode::QmlBasicTypeNode(InnerNode *parent, + const QString& name) + : FakeNode(parent, name, QmlBasicType) +{ + setTitle(name); +} + +/*! Constructor for the Qml property group node. \a parent is - always a QmlClassNode. + always a QmlClassNode. */ QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent, const QString& name, diff --git a/tools/qdoc3/node.h b/tools/qdoc3/node.h index c77fbeb..215a7ae 100644 --- a/tools/qdoc3/node.h +++ b/tools/qdoc3/node.h @@ -96,7 +96,8 @@ class Node #ifdef QDOC_QML ExternalPage, QmlClass, - QmlPropertyGroup + QmlPropertyGroup, + QmlBasicType #else ExternalPage #endif @@ -136,6 +137,13 @@ class Node AppendixLink */ }; + enum PageType { + NoPageType, + ApiPage, + ArticlePage, + ExamplePage + }; + virtual ~Node(); void setAccess(Access access) { acc = access; } @@ -149,10 +157,13 @@ class Node void setLink(LinkType linkType, const QString &link, const QString &desc); void setUrl(const QString &url); void setTemplateStuff(const QString &templateStuff) { tpl = templateStuff; } + void setPageType(PageType t) { pageTyp = t; } + void setPageType(const QString& t); virtual bool isInnerNode() const = 0; virtual bool isReimp() const { return false; } virtual bool isFunction() const { return false; } + virtual bool isQmlNode() const { return false; } Type type() const { return typ; } virtual SubType subType() const { return NoSubType; } InnerNode *parent() const { return par; } @@ -172,6 +183,8 @@ class Node ThreadSafeness inheritedThreadSafeness() const; QString since() const { return sinc; } QString templateStuff() const { return tpl; } + PageType pageType() const { return pageTyp; } + virtual void addPageKeywords(const QString& ) { } void clearRelated() { rel = 0; } @@ -185,13 +198,15 @@ class Node #ifdef Q_WS_WIN Type typ; Access acc; - Status sta; ThreadSafeness saf; + PageType pageTyp; + Status sta; #else Type typ : 4; Access acc : 2; - Status sta : 3; ThreadSafeness saf : 2; + PageType pageTyp : 4; + Status sta : 3; #endif InnerNode *par; InnerNode *rel; @@ -243,6 +258,8 @@ class InnerNode : public Node QStringList primaryKeys(); QStringList secondaryKeys(); + const QStringList& pageKeywords() const { return pageKeywds; } + virtual void addPageKeywords(const QString& t) { pageKeywds << t; } protected: InnerNode(Type type, InnerNode *parent, const QString& name); @@ -255,6 +272,7 @@ class InnerNode : public Node void removeChild(Node *child); void removeRelated(Node *pseudoChild); + QStringList pageKeywds; QStringList inc; NodeList children; NodeList enumChildren; @@ -362,15 +380,30 @@ class QmlClassNode : public FakeNode QmlClassNode(InnerNode *parent, const QString& name, const ClassNode* cn); - virtual ~QmlClassNode() { } + virtual ~QmlClassNode(); + virtual bool isQmlNode() const { return true; } const ClassNode* classNode() const { return cnode; } virtual QString fileBase() const; + static void addInheritedBy(const QString& base, Node* sub); + static void subclasses(const QString& base, NodeList& subs); + static void clear(); + public: static bool qmlOnly; + static QMultiMap<QString,Node*> inheritedBy; private: - const ClassNode* cnode; + const ClassNode* cnode; +}; + +class QmlBasicTypeNode : public FakeNode +{ + public: + QmlBasicTypeNode(InnerNode *parent, + const QString& name); + virtual ~QmlBasicTypeNode() { } + virtual bool isQmlNode() const { return true; } }; class QmlPropGroupNode : public FakeNode @@ -380,6 +413,7 @@ class QmlPropGroupNode : public FakeNode const QString& name, bool attached); virtual ~QmlPropGroupNode() { } + virtual bool isQmlNode() const { return true; } const QString& element() const { return parent()->name(); } void setDefault() { isdefault = true; } @@ -411,6 +445,7 @@ class QmlPropertyNode : public LeafNode bool isDesignable() const { return fromTrool(des,false); } bool isWritable() const { return fromTrool(wri,true); } bool isAttached() const { return att; } + virtual bool isQmlNode() const { return true; } const QString& element() const { return static_cast<QmlPropGroupNode*>(parent())->element(); } @@ -579,6 +614,9 @@ class FunctionNode : public LeafNode QString signature(bool values = false) const; const QString& element() const { return parent()->name(); } bool isAttached() const { return att; } + virtual bool isQmlNode() const { + return ((type() == QmlSignal) || (type() == QmlMethod)); + } void debug() const; diff --git a/tools/qdoc3/pagegenerator.cpp b/tools/qdoc3/pagegenerator.cpp index a001c10..f0f14fe 100644 --- a/tools/qdoc3/pagegenerator.cpp +++ b/tools/qdoc3/pagegenerator.cpp @@ -43,7 +43,6 @@ pagegenerator.cpp */ -#include <QtCore> #include <qfile.h> #include <qfileinfo.h> @@ -77,7 +76,7 @@ void PageGenerator::generateTree(const Tree *tree, CodeMarker *marker) generateInnerNode(tree->root(), marker); } -QString PageGenerator::fileBase(const Node *node) +QString PageGenerator::fileBase(const Node *node) const { if (node->relates()) node = node->relates(); @@ -104,7 +103,8 @@ QString PageGenerator::fileBase(const Node *node) we prepend "qml-" to the file name of QML element doc files. */ - if (p->subType() == Node::QmlClass) { + if ((p->subType() == Node::QmlClass) || + (p->subType() == Node::QmlBasicType)) { base.prepend("qml-"); } #endif @@ -152,7 +152,7 @@ QString PageGenerator::fileBase(const Node *node) return res; } -QString PageGenerator::fileName(const Node *node) +QString PageGenerator::fileName(const Node *node) const { if (!node->url().isEmpty()) return node->url(); @@ -176,7 +176,7 @@ void PageGenerator::beginSubPage(const Location& location, location.fatal(tr("Cannot open output file '%1'") .arg(outFile->fileName())); QTextStream *out = new QTextStream(outFile); - out->setCodec("ISO-8859-1"); + out->setCodec(outputCodec); outStreamStack.push(out); } @@ -209,6 +209,10 @@ void PageGenerator::generateInnerNode(const InnerNode *node, if (fakeNode->subType() == Node::QmlPropertyGroup) return; #endif + if (fakeNode->subType() == Node::Page) { + if (node->count() > 0) + qDebug("PAGE %s HAS CHILDREN", qPrintable(fakeNode->title())); + } } if (node->parent() != 0) { diff --git a/tools/qdoc3/pagegenerator.h b/tools/qdoc3/pagegenerator.h index db24edd..7ab7e5e 100644 --- a/tools/qdoc3/pagegenerator.h +++ b/tools/qdoc3/pagegenerator.h @@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE +class QTextCodec; + class ClassNode; class InnerNode; class NamespaceNode; @@ -67,15 +69,19 @@ class PageGenerator : public Generator virtual void generateTree(const Tree *tree, CodeMarker *marker); protected: - virtual QString fileBase(const Node *node); - virtual QString fileExtension(const Node *node) = 0; - QString fileName(const Node *node); + virtual QString fileBase(const Node *node) const; + virtual QString fileExtension(const Node *node) const = 0; + QString fileName(const Node *node) const; QString outFileName(); void beginSubPage(const Location& location, const QString& fileName); void endSubPage(); virtual void generateInnerNode(const InnerNode *node, CodeMarker *marker); QTextStream& out(); + QString naturalLanguage; + QString outputEncoding; + QTextCodec *outputCodec; + private: QStack<QTextStream *> outStreamStack; }; diff --git a/tools/qdoc3/qdoc3.pro b/tools/qdoc3/qdoc3.pro index 441bf39..e394799 100644 --- a/tools/qdoc3/qdoc3.pro +++ b/tools/qdoc3/qdoc3.pro @@ -4,9 +4,16 @@ DEFINES += QT_NO_CAST_TO_ASCII #DEFINES += QT_USE_FAST_OPERATOR_PLUS #DEFINES += QT_USE_FAST_CONCATENATION -QT = core xml -CONFIG += console -CONFIG -= debug_and_release_target +qdoc_bootstrapped { + include(../../src/tools/bootstrap/bootstrap.pri) + DEFINES -= QT_NO_CAST_FROM_ASCII + DEFINES += QT_NO_TRANSLATION +} else { + QT = core xml + CONFIG += console + CONFIG -= debug_and_release_target +} + !isEmpty(QT_BUILD_TREE):DESTDIR = $$QT_BUILD_TREE/bin #CONFIG += debug build_all:!build_pass { @@ -14,7 +21,8 @@ build_all:!build_pass { CONFIG += release # CONFIG += debug } -mac:CONFIG -= app_bundle + +CONFIG -= app_bundle HEADERS += apigenerator.h \ archiveextractor.h \ atom.h \ @@ -105,5 +113,26 @@ SOURCES += apigenerator.cpp \ webxmlgenerator.cpp \ yyindent.cpp +### Documentation for qdoc3 ### + +win32:!win32-g++ { + unixstyle = false +} else :win32-g++:isEmpty(QMAKE_SH) { + unixstyle = false +} else { + unixstyle = true +} + +$$unixstyle { + QDOC = cd $$PWD/doc && $$[QT_INSTALL_BINS]/qdoc3 +} else { + QDOC = cd $$PWD/doc && $$[QT_INSTALL_BINS]/qdoc3.exe + QDOC = $$replace(QDOC, "/", "\\") +} + +docs.commands = $$QDOC qdoc-manual.qdocconf + +QMAKE_EXTRA_TARGETS += docs + target.path = $$[QT_INSTALL_BINS] INSTALLS += target diff --git a/tools/qdoc3/qsakernelparser.cpp b/tools/qdoc3/qsakernelparser.cpp index 9320a17..8f12eda 100644 --- a/tools/qdoc3/qsakernelparser.cpp +++ b/tools/qdoc3/qsakernelparser.cpp @@ -70,8 +70,8 @@ void QsaKernelParser::parseSourceFile( const Location& location, const QString& filePath, Tree * /* tree */ ) { - FILE *in = fopen( QFile::encodeName(filePath), "r" ); - if ( in == 0 ) { + QFile in(filePath); + if (!in.open(QIODevice::ReadOnly)) { location.error( tr("Cannot open QSA kernel file '%1'").arg(filePath) ); return; } @@ -171,7 +171,7 @@ void QsaKernelParser::parseSourceFile( const Location& location, readToken(); } } - fclose( in ); + in.close(); } void QsaKernelParser::doneParsingSourceFiles( Tree * /* tree */ ) diff --git a/tools/qdoc3/qscodemarker.cpp b/tools/qdoc3/qscodemarker.cpp index 89c9c5c..d4b8e80 100644 --- a/tools/qdoc3/qscodemarker.cpp +++ b/tools/qdoc3/qscodemarker.cpp @@ -279,11 +279,11 @@ QList<Section> QsCodeMarker::sections( const InnerNode *inner, SynopsisStyle sty const ClassNode *classe = static_cast<const ClassNode *>(inner); if ( style == Summary ) { - FastSection enums(classe, "Enums", "enum", "enums"); - FastSection functions(classe, "Functions", "function", "functions"); - FastSection readOnlyProperties(classe, "Read-Only Properties", "property", "properties"); - FastSection signalz(classe, "Signals", "signal", "signals"); - FastSection writableProperties(classe, "Writable Properties", "property", "properties"); + FastSection enums(classe, "Enums", "", "enum", "enums"); + FastSection functions(classe, "Functions", "", "function", "functions"); + FastSection readOnlyProperties(classe, "", "Read-Only Properties", "property", "properties"); + FastSection signalz(classe, "Signals", "", "signal", "signals"); + FastSection writableProperties(classe, "", "Writable Properties", "property", "properties"); QStack<const ClassNode *> stack; stack.push( classe ); @@ -328,9 +328,9 @@ QList<Section> QsCodeMarker::sections( const InnerNode *inner, SynopsisStyle sty append( sections, functions ); append( sections, signalz ); } else if ( style == Detailed ) { - FastSection enums( classe, "Enum Documentation" ); - FastSection functionsAndSignals( classe, "Function and Signal Documentation" ); - FastSection properties( classe, "Property Documentation" ); + FastSection enums( classe, "Enum Documentation", "", "member", "members"); + FastSection functionsAndSignals( classe, "Function and Signal Documentation", "", "member", "members"); + FastSection properties( classe, "Property Documentation", "", "member", "members"); NodeList::ConstIterator c = classe->childNodes().begin(); while ( c != classe->childNodes().end() ) { @@ -349,7 +349,7 @@ QList<Section> QsCodeMarker::sections( const InnerNode *inner, SynopsisStyle sty append( sections, properties ); append( sections, functionsAndSignals ); } else { // ( style == SeparateList ) - FastSection all( classe ); + FastSection all(classe, "", "", "member", "members"); QStack<const ClassNode *> stack; stack.push( classe ); diff --git a/tools/qdoc3/qscodeparser.cpp b/tools/qdoc3/qscodeparser.cpp index 8b3bc98..3b8bc1a 100644 --- a/tools/qdoc3/qscodeparser.cpp +++ b/tools/qdoc3/qscodeparser.cpp @@ -151,8 +151,8 @@ void QsCodeParser::parseHeaderFile(const Location& location, { qsTre = tree; - FILE *in = fopen(QFile::encodeName(filePath), "r"); - if (in == 0) { + QFile in(filePath); + if (!in.open(QIODevice::ReadOnly)) { location.error(tr("Cannot open Qt Script class list '%1'") .arg(filePath)); return; @@ -175,7 +175,7 @@ void QsCodeParser::parseHeaderFile(const Location& location, } tok = fileTokenizer.getToken(); } - fclose(in); + in.close(); } void QsCodeParser::parseSourceFile(const Location& location, diff --git a/tools/qdoc3/test/assistant.qdocconf b/tools/qdoc3/test/assistant.qdocconf index f03d970..3711ec4 100644 --- a/tools/qdoc3/test/assistant.qdocconf +++ b/tools/qdoc3/test/assistant.qdocconf @@ -6,18 +6,42 @@ include(qt-defines.qdocconf) project = Qt Assistant description = Qt Assistant Manual -url = http://qt.nokia.com/doc/4.6 +url = http://qt.nokia.com/doc/4.7 indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index qhp.projects = Assistant qhp.Assistant.file = assistant.qhp -qhp.Assistant.namespace = com.trolltech.assistant.460 +qhp.Assistant.namespace = com.trolltech.assistant.470 qhp.Assistant.virtualFolder = qdoc qhp.Assistant.indexTitle = Qt Assistant Manual -qhp.Assistant.extraFiles = classic.css images/qt-logo.png images/trolltech-logo.png -qhp.Assistant.filterAttributes = qt 4.6.3 tools assistant +qhp.Assistant.extraFiles = images/bg_l.png \ + images/bg_l_blank.png \ + images/bg_r.png \ + images/box_bg.png \ + images/breadcrumb.png \ + images/bullet_gt.png \ + images/bullet_dn.png \ + images/bullet_sq.png \ + images/bullet_up.png \ + images/feedbackground.png \ + images/horBar.png \ + images/page.png \ + images/page_bg.png \ + images/sprites-combined.png \ + images/stylesheet-coffee-plastique.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + scripts/functions.js \ + scripts/jquery.js \ + style/style_ie6.css \ + style/style_ie7.css \ + style/style_ie8.css \ + style/style.css + +qhp.Assistant.filterAttributes = qt 4.7.0 tools assistant qhp.Assistant.customFilters.Assistant.name = Qt Assistant Manual qhp.Assistant.customFilters.Assistant.filterAttributes = qt tools assistant qhp.Assistant.subprojects = manual examples @@ -40,6 +64,7 @@ exampledirs = $QT_SOURCE_TREE \ $QT_SOURCE_TREE/examples \ $QT_SOURCE_TREE/doc/src -imagedirs = $QT_SOURCE_TREE/doc/src/images +imagedirs = $QT_SOURCE_TREE/doc/src/images \ + $QT_SOURCE_TREE/doc/src/template/images outputdir = $QT_BUILD_TREE/doc-build/html-assistant base = file:$QT_BUILD_TREE/doc-build/html-assistant diff --git a/tools/qdoc3/test/designer.qdocconf b/tools/qdoc3/test/designer.qdocconf index 0c3e05b..39da68b 100644 --- a/tools/qdoc3/test/designer.qdocconf +++ b/tools/qdoc3/test/designer.qdocconf @@ -6,18 +6,42 @@ include(qt-defines.qdocconf) project = Qt Designer description = Qt Designer Manual -url = http://qt.nokia.com/doc/4.6 +url = http://qt.nokia.com/doc/4.7 indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index qhp.projects = Designer qhp.Designer.file = designer.qhp -qhp.Designer.namespace = com.trolltech.designer.460 +qhp.Designer.namespace = com.trolltech.designer.470 qhp.Designer.virtualFolder = qdoc qhp.Designer.indexTitle = Qt Designer Manual -qhp.Designer.extraFiles = classic.css images/qt-logo.png images/trolltech-logo.png -qhp.Designer.filterAttributes = qt 4.6.3 tools designer +qhp.Designer.extraFiles = images/bg_l.png \ + images/bg_l_blank.png \ + images/bg_r.png \ + images/box_bg.png \ + images/breadcrumb.png \ + images/bullet_gt.png \ + images/bullet_dn.png \ + images/bullet_sq.png \ + images/bullet_up.png \ + images/feedbackground.png \ + images/horBar.png \ + images/page.png \ + images/page_bg.png \ + images/sprites-combined.png \ + images/stylesheet-coffee-plastique.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + scripts/functions.js \ + scripts/jquery.js \ + style/style_ie6.css \ + style/style_ie7.css \ + style/style_ie8.css \ + style/style.css + +qhp.Designer.filterAttributes = qt 4.7.0 tools designer qhp.Designer.customFilters.Designer.name = Qt Designer Manual qhp.Designer.customFilters.Designer.filterAttributes = qt tools designer qhp.Designer.subprojects = manual examples @@ -46,6 +70,7 @@ exampledirs = $QT_SOURCE_TREE \ $QT_SOURCE_TREE/examples \ $QT_SOURCE_TREE/doc/src -imagedirs = $QT_SOURCE_TREE/doc/src/images +imagedirs = $QT_SOURCE_TREE/doc/src/images \ + $QT_SOURCE_TREE/doc/src/template/images outputdir = $QT_BUILD_TREE/doc-build/html-designer base = file:$QT_BUILD_TREE/doc-build/html-designer diff --git a/tools/qdoc3/test/jambi.qdocconf b/tools/qdoc3/test/jambi.qdocconf index 04bb51b..aa87826 100644 --- a/tools/qdoc3/test/jambi.qdocconf +++ b/tools/qdoc3/test/jambi.qdocconf @@ -16,7 +16,8 @@ outputdir = $JAMBI/doc/html/com/trolltech/qt imagedirs = $QTDIR/doc/src/images \ $QTDIR/examples \ $JAMBI/doc/src/images \ - ../doc/src/images + ../doc/src/images \ + $QTDIR/doc/src/template/images extraimages.javadoc = qt-logo \ qt-logo.png diff --git a/tools/qdoc3/test/linguist.qdocconf b/tools/qdoc3/test/linguist.qdocconf index 739f4af..dba4fb5 100644 --- a/tools/qdoc3/test/linguist.qdocconf +++ b/tools/qdoc3/test/linguist.qdocconf @@ -6,18 +6,42 @@ include(qt-defines.qdocconf) project = Qt Linguist description = Qt Linguist Manual -url = http://qt.nokia.com/doc/4.6 +url = http://qt.nokia.com/doc/4.7 indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index qhp.projects = Linguist qhp.Linguist.file = linguist.qhp -qhp.Linguist.namespace = com.trolltech.linguist.460 +qhp.Linguist.namespace = com.trolltech.linguist.470 qhp.Linguist.virtualFolder = qdoc qhp.Linguist.indexTitle = Qt Linguist Manual -qhp.Linguist.extraFiles = classic.css images/qt-logo.png images/trolltech-logo.png -qhp.Linguist.filterAttributes = qt 4.6.3 tools linguist +qhp.Linguist.extraFiles = images/bg_l.png \ + images/bg_l_blank.png \ + images/bg_r.png \ + images/box_bg.png \ + images/breadcrumb.png \ + images/bullet_gt.png \ + images/bullet_dn.png \ + images/bullet_sq.png \ + images/bullet_up.png \ + images/feedbackground.png \ + images/horBar.png \ + images/page.png \ + images/page_bg.png \ + images/sprites-combined.png \ + images/stylesheet-coffee-plastique.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + scripts/functions.js \ + scripts/jquery.js \ + style/style_ie6.css \ + style/style_ie7.css \ + style/style_ie8.css \ + style/style.css + +qhp.Linguist.filterAttributes = qt 4.7.0 tools linguist qhp.Linguist.customFilters.Linguist.name = Qt Linguist Manual qhp.Linguist.customFilters.Linguist.filterAttributes = qt tools linguist qhp.Linguist.subprojects = manual examples @@ -42,6 +66,7 @@ exampledirs = $QT_SOURCE_TREE \ $QT_SOURCE_TREE/examples \ $QT_SOURCE_TREE/doc/src -imagedirs = $QT_SOURCE_TREE/doc/src/images +imagedirs = $QT_SOURCE_TREE/doc/src/images \ + $QT_SOURCE_TREE/doc/src/template/images outputdir = $QT_BUILD_TREE/doc-build/html-linguist base = file:$QT_BUILD_TREE/doc-build/html-linguist diff --git a/tools/qdoc3/test/macros.qdocconf b/tools/qdoc3/test/macros.qdocconf index 22db23e..510a8b3 100644 --- a/tools/qdoc3/test/macros.qdocconf +++ b/tools/qdoc3/test/macros.qdocconf @@ -18,6 +18,7 @@ macro.ouml.HTML = "ö" macro.QA = "\\e{Qt Assistant}" macro.QD = "\\e{Qt Designer}" macro.QL = "\\e{Qt Linguist}" +macro.QQV = "\\e{Qt QML Viewer}" macro.param = "\\e" macro.raisedaster.HTML = "<sup>*</sup>" macro.rarrow.HTML = "→" diff --git a/tools/qdoc3/test/qdeclarative.qdocconf b/tools/qdoc3/test/qdeclarative.qdocconf new file mode 100644 index 0000000..f744879 --- /dev/null +++ b/tools/qdoc3/test/qdeclarative.qdocconf @@ -0,0 +1,87 @@ +include(compat.qdocconf) +include(macros.qdocconf) +include(qt-cpp-ignore.qdocconf) +include(qt-html-templates.qdocconf) +include(qt-defines.qdocconf) + +project = Qml +description = Qml Reference Documentation +url = http://qt.nokia.com/doc/4.6/ +qmlonly = true + +edition.Console.modules = QtCore QtDBus QtNetwork QtScript QtSql QtXml \ + QtXmlPatterns QtTest +edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript QtSql QtSvg \ + QtWebKit QtXml QtXmlPatterns Qt3Support QtHelp \ + QtDesigner QtAssistant QAxContainer Phonon \ + QAxServer QtUiTools QtTest QtDBus +edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest +edition.DesktopLight.groups = -graphicsview-api + +qhp.projects = Qml + +qhp.Qml.file = qml.qhp +qhp.Qml.namespace = com.trolltech.qml.460 +qhp.Qml.virtualFolder = qdoc +qhp.Qml.indexTitle = Qml Reference + +# Files not referenced in any qdoc file +# See also extraimages.HTML +qhp.Qml.extraFiles = images/bg_l.png \ + images/bg_l_blank.png \ + images/bg_r.png \ + images/box_bg.png \ + images/breadcrumb.png \ + images/bullet_gt.png \ + images/bullet_dn.png \ + images/bullet_sq.png \ + images/bullet_up.png \ + images/feedbackground.png \ + images/horBar.png \ + images/page.png \ + images/page_bg.png \ + images/sprites-combined.png \ + images/stylesheet-coffee-plastique.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + scripts/functions.js \ + scripts/jquery.js \ + style/style_ie6.css \ + style/style_ie7.css \ + style/style_ie8.css \ + style/style.css + +qhp.Qml.filterAttributes = qt 4.6.0 qtrefdoc +qhp.Qml.customFilters.Qt.name = Qt 4.6.0 +qhp.Qml.customFilters.Qt.filterAttributes = qt 4.6.0 +qhp.Qml.subprojects = classes +qhp.Qml.subprojects.classes.title = Elements +qhp.Qml.subprojects.classes.indexTitle = Qml Elements +qhp.Qml.subprojects.classes.selectors = fake:qmlclass +qhp.Qml.subprojects.classes.sortPages = true + +language = Cpp + +headerdirs = $QT_SOURCE_TREE/src/declarative +sourcedirs = $QT_SOURCE_TREE/src/declarative \ + $QT_SOURCE_TREE/doc/src/declarative + +sources += $QT_SOURCE_TREE/doc/src/tutorials/declarative.qdoc + +sources.fileextensions = "*.cpp *.qdoc" +examples.fileextensions = "*.cpp *.h *.js *.qml" + +exampledirs = $QT_SOURCE_TREE/doc/src \ + $QT_SOURCE_TREE/examples \ + $QT_SOURCE_TREE/examples/tutorials \ + $QT_SOURCE_TREE \ + $QT_SOURCE_TREE/qmake/examples \ + $QT_SOURCE_TREE/src/3rdparty/webkit/WebKit/qt/docs +imagedirs = $QT_SOURCE_TREE/doc/src/images \ + $QT_SOURCE_TREE/examples \ + $QT_SOURCE_TREE/doc/src/declarative/pics \ + $QT_SOURCE_TREE/doc/src/template/images +outputdir = $QT_BUILD_TREE/doc-build/html-qml +tagfile = $QT_BUILD_TREE/doc-build/html-qml/qt.tags +base = file:$QT_BUILD_TREE/doc/html-qml diff --git a/tools/qdoc3/test/qmake.qdocconf b/tools/qdoc3/test/qmake.qdocconf index 696949e..b7f4115 100644 --- a/tools/qdoc3/test/qmake.qdocconf +++ b/tools/qdoc3/test/qmake.qdocconf @@ -6,18 +6,42 @@ include(qt-defines.qdocconf) project = QMake description = QMake Manual -url = http://qt.nokia.com/doc/4.6 +url = http://qt.nokia.com/doc/4.7 indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index qhp.projects = qmake qhp.qmake.file = qmake.qhp -qhp.qmake.namespace = com.trolltech.qmake.460 +qhp.qmake.namespace = com.trolltech.qmake.470 qhp.qmake.virtualFolder = qdoc qhp.qmake.indexTitle = QMake Manual -qhp.qmake.extraFiles = classic.css images/qt-logo.png images/trolltech-logo.png -qhp.qmake.filterAttributes = qt 4.6.3 tools qmake +qhp.qmake.extraFiles = images/bg_l.png \ + images/bg_l_blank.png \ + images/bg_r.png \ + images/box_bg.png \ + images/breadcrumb.png \ + images/bullet_gt.png \ + images/bullet_dn.png \ + images/bullet_sq.png \ + images/bullet_up.png \ + images/feedbackground.png \ + images/horBar.png \ + images/page.png \ + images/page_bg.png \ + images/sprites-combined.png \ + images/stylesheet-coffee-plastique.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + scripts/functions.js \ + scripts/jquery.js \ + style/style_ie6.css \ + style/style_ie7.css \ + style/style_ie8.css \ + style/style.css + +qhp.qmake.filterAttributes = qt 4.7.0 tools qmake qhp.qmake.customFilters.qmake.name = qmake Manual qhp.qmake.customFilters.qmake.filterAttributes = qt tools qmake qhp.qmake.subprojects = manual @@ -35,6 +59,7 @@ exampledirs = $QT_SOURCE_TREE \ $QT_SOURCE_TREE/examples \ $QT_SOURCE_TREE/doc/src -imagedirs = $QT_SOURCE_TREE/doc/src/images +imagedirs = $QT_SOURCE_TREE/doc/src/images \ + $QT_SOURCE_TREE/doc/src/template/images outputdir = $QT_BUILD_TREE/doc-build/html-qmake base = file:$QT_BUILD_TREE/doc-build/html-qmake diff --git a/tools/qdoc3/test/qt-api-only_zh_CN.qdocconf b/tools/qdoc3/test/qt-api-only_zh_CN.qdocconf new file mode 100644 index 0000000..c722ee8 --- /dev/null +++ b/tools/qdoc3/test/qt-api-only_zh_CN.qdocconf @@ -0,0 +1,30 @@ +include(qt-build-docs_zh_CN.qdocconf) + +# Ensures that the generated index contains a URL that can be used by the +# tools documentation (assistant.qdocconf, designer.qdocconf, linguist.qdocconf, +# qmake.qdocconf). + +url = ./ + +# Ensures that the documentation for the tools is not included in the generated +# .qhp file. + +qhp.Qt.excluded += $QT_SOURCE_TREE/doc/src/development/assistant-manual.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/simpletextviewer.qdoc \ + $QT_SOURCE_TREE/doc/src/development/designer-manual.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/calculatorbuilder.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/calculatorform.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/customwidgetplugin.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/taskmenuextension.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/containerextension.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/worldtimeclockbuilder.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/worldtimeclockplugin.qdoc \ + $QT_SOURCE_TREE/doc/src/internationalization/linguist-manual.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/hellotr.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/arrowpad.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/trollprint.qdoc \ + $QT_SOURCE_TREE/doc/src/development/qmake-manual.qdoc + +outputdir = $QT_BUILD_TREE/doc-build/html-qt_zh_CN +tagfile = $QT_BUILD_TREE/doc-build/html-qt_zh_CN/qt.tags +base = file:$QT_BUILD_TREE/doc-build/html-qt_zh_CN diff --git a/tools/qdoc3/test/qt-build-docs.qdocconf b/tools/qdoc3/test/qt-build-docs.qdocconf index d7a06b8..d3c855f 100644 --- a/tools/qdoc3/test/qt-build-docs.qdocconf +++ b/tools/qdoc3/test/qt-build-docs.qdocconf @@ -6,35 +6,52 @@ include(qt-defines.qdocconf) project = Qt description = Qt Reference Documentation -url = http://qt.nokia.com/doc/4.6 +url = http://qt.nokia.com/doc/4.7 -edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript QtScriptTools QtSql QtSvg \ - QtWebKit QtXml QtXmlPatterns Qt3Support QtHelp \ - QtDesigner QtAssistant QAxContainer Phonon \ - QAxServer QtUiTools QtTest QtDBus -edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest -edition.DesktopLight.groups = -graphicsview-api +sourceencoding = UTF-8 +outputencoding = UTF-8 +naturallanguage = en_US qhp.projects = Qt qhp.Qt.file = qt.qhp -qhp.Qt.namespace = com.trolltech.qt.460 +qhp.Qt.namespace = com.trolltech.qt.470 qhp.Qt.virtualFolder = qdoc qhp.Qt.indexTitle = Qt Reference Documentation -qhp.Qt.indexRoot = # Files not referenced in any qdoc file (last four are needed by qtdemo) # See also extraimages.HTML -qhp.Qt.extraFiles = classic.css \ - images/qt-logo.png \ - images/taskmenuextension-example.png \ - images/coloreditorfactoryimage.png \ - images/dynamiclayouts-example.png \ - images/stylesheet-coffee-plastique.png +qhp.Qt.extraFiles = index.html \ + images/bg_l.png \ + images/bg_l_blank.png \ + images/bg_r.png \ + images/box_bg.png \ + images/breadcrumb.png \ + images/bullet_gt.png \ + images/bullet_dn.png \ + images/bullet_sq.png \ + images/bullet_up.png \ + images/feedbackground.png \ + images/horBar.png \ + images/page.png \ + images/page_bg.png \ + images/sprites-combined.png \ + images/stylesheet-coffee-plastique.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + scripts/functions.js \ + scripts/jquery.js \ + style/style_ie6.css \ + style/style_ie7.css \ + style/style_ie8.css \ + style/style.css -qhp.Qt.filterAttributes = qt 4.6.3 qtrefdoc -qhp.Qt.customFilters.Qt.name = Qt 4.6.3 -qhp.Qt.customFilters.Qt.filterAttributes = qt 4.6.3 + + +qhp.Qt.filterAttributes = qt 4.7.0 qtrefdoc +qhp.Qt.customFilters.Qt.name = Qt 4.7.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.7.0 qhp.Qt.subprojects = classes overviews examples qhp.Qt.subprojects.classes.title = Classes qhp.Qt.subprojects.classes.indexTitle = Qt's Classes @@ -89,14 +106,16 @@ excludedirs = $QT_SOURCE_TREE/src/3rdparty/clucene \ $QT_SOURCE_TREE/src/3rdparty/webkit/WebCore \ $QT_SOURCE_TREE/src/3rdparty/wintab \ $QT_SOURCE_TREE/src/3rdparty/zlib \ - $QT_SOURCE_TREE/doc/src/snippets \ $QT_SOURCE_TREE/src/3rdparty/phonon/gstreamer \ $QT_SOURCE_TREE/src/3rdparty/phonon/ds9 \ $QT_SOURCE_TREE/src/3rdparty/phonon/qt7 \ - $QT_SOURCE_TREE/src/3rdparty/phonon/waveout + $QT_SOURCE_TREE/src/3rdparty/phonon/mmf \ + $QT_SOURCE_TREE/src/3rdparty/phonon/waveout \ + $QT_SOURCE_TREE/doc/src/snippets \ + $QT_SOURCE_TREE/doc/src/zh_CN sources.fileextensions = "*.cpp *.qdoc *.mm" -examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" +examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp *.qml" examples.imageextensions = "*.png" exampledirs = $QT_SOURCE_TREE/doc/src \ @@ -106,7 +125,9 @@ exampledirs = $QT_SOURCE_TREE/doc/src \ $QT_SOURCE_TREE/qmake/examples \ $QT_SOURCE_TREE/src/3rdparty/webkit/WebKit/qt/docs imagedirs = $QT_SOURCE_TREE/doc/src/images \ - $QT_SOURCE_TREE/examples + $QT_SOURCE_TREE/examples \ + $QT_SOURCE_TREE/doc/src/declarative/pics \ + $QT_SOURCE_TREE/doc/src/template/images outputdir = $QT_BUILD_TREE/doc/html tagfile = $QT_BUILD_TREE/doc/html/qt.tags base = file:$QT_BUILD_TREE/doc/html diff --git a/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf new file mode 100644 index 0000000..e9bc00c --- /dev/null +++ b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf @@ -0,0 +1,104 @@ +include(compat.qdocconf) +include(macros.qdocconf) +include(qt-cpp-ignore.qdocconf) +include(qt-html-templates_zh_CN.qdocconf) +include(qt-defines.qdocconf) + +project = Qt +description = Qt Reference Documentation +url = http://qt.nokia.com/doc/zh_CN/4.7 + +sourceencoding = UTF-8 +outputencoding = UTF-8 +naturallanguage = zh-Hans + +indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index + +qhp.projects = Qt + +qhp.Qt.file = qt.qhp +qhp.Qt.namespace = com.trolltech.qt.470 +qhp.Qt.virtualFolder = qdoc +qhp.Qt.title = 教程 +qhp.Qt.indexTitle = 教程 +qhp.Qt.selectors = fake:example + +qhp.Qt.filterAttributes = qt 4.7.0 qtrefdoc zh_CN +qhp.Qt.customFilters.Qt.name = Qt 4.7.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.7.0 + +# Files not referenced in any qdoc file (last four are needed by qtdemo) +# See also extraimages.HTML +qhp.Qt.extraFiles = index.html \ + images/bg_l.png \ + images/bg_l_blank.png \ + images/bg_r.png \ + images/box_bg.png \ + images/breadcrumb.png \ + images/bullet_gt.png \ + images/bullet_dn.png \ + images/bullet_sq.png \ + images/bullet_up.png \ + images/feedbackground.png \ + images/horBar.png \ + images/page.png \ + images/page_bg.png \ + images/sprites-combined.png \ + images/stylesheet-coffee-plastique.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + scripts/functions.js \ + scripts/jquery.js \ + style/style_ie6.css \ + style/style_ie7.css \ + style/style_ie8.css \ + style/style.css + +language = Cpp + +sourcedirs = $QT_SOURCE_TREE/doc/src/zh_CN + +excludedirs = $QT_SOURCE_TREE/src/3rdparty/clucene \ + $QT_SOURCE_TREE/src/3rdparty/des \ + $QT_SOURCE_TREE/src/3rdparty/freetype \ + $QT_SOURCE_TREE/src/3rdparty/harfbuzz \ + $QT_SOURCE_TREE/src/3rdparty/kdebase \ + $QT_SOURCE_TREE/src/3rdparty/libjpeg \ + $QT_SOURCE_TREE/src/3rdparty/libmng \ + $QT_SOURCE_TREE/src/3rdparty/libpng \ + $QT_SOURCE_TREE/src/3rdparty/libtiff \ + $QT_SOURCE_TREE/src/3rdparty/md4 \ + $QT_SOURCE_TREE/src/3rdparty/md5 \ + $QT_SOURCE_TREE/src/3rdparty/patches \ + $QT_SOURCE_TREE/src/3rdparty/sha1 \ + $QT_SOURCE_TREE/src/3rdparty/sqlite \ + $QT_SOURCE_TREE/src/3rdparty/webkit/JavaScriptCore \ + $QT_SOURCE_TREE/src/3rdparty/webkit/WebCore \ + $QT_SOURCE_TREE/src/3rdparty/wintab \ + $QT_SOURCE_TREE/src/3rdparty/zlib \ + $QT_SOURCE_TREE/doc/src/snippets \ + $QT_SOURCE_TREE/src/3rdparty/phonon/gstreamer \ + $QT_SOURCE_TREE/src/3rdparty/phonon/ds9 \ + $QT_SOURCE_TREE/src/3rdparty/phonon/qt7 \ + $QT_SOURCE_TREE/src/3rdparty/phonon/mmf \ + $QT_SOURCE_TREE/src/3rdparty/phonon/waveout + +sources.fileextensions = "*.cpp *.qdoc *.mm" +examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" +examples.imageextensions = "*.png" + +exampledirs = $QT_SOURCE_TREE/doc/src \ + $QT_SOURCE_TREE/examples \ + $QT_SOURCE_TREE/examples/tutorials \ + $QT_SOURCE_TREE \ + $QT_SOURCE_TREE/qmake/examples \ + $QT_SOURCE_TREE/src/3rdparty/webkit/WebKit/qt/docs +imagedirs = $QT_SOURCE_TREE/doc/src/images \ + $QT_SOURCE_TREE/examples \ + $QT_SOURCE_TREE/doc/src/template/images +outputdir = $QT_BUILD_TREE/doc/html_zh_CN +tagfile = $QT_BUILD_TREE/doc/html_zh_CN/qt.tags +base = file:$QT_BUILD_TREE/doc/html_zh_CN + +HTML.generatemacrefs = "true" diff --git a/tools/qdoc3/test/qt-defines.qdocconf b/tools/qdoc3/test/qt-defines.qdocconf index b22727f..f3291df 100644 --- a/tools/qdoc3/test/qt-defines.qdocconf +++ b/tools/qdoc3/test/qt-defines.qdocconf @@ -3,6 +3,7 @@ defines = Q_QDOC \ QT_.*_LIB \ QT_COMPAT \ QT_KEYPAD_NAVIGATION \ + QT_NO_EGL \ QT3_SUPPORT \ Q_WS_.* \ Q_OS_.* \ @@ -19,8 +20,33 @@ codeindent = 1 # See also qhp.Qt.extraFiles extraimages.HTML = qt-logo \ trolltech-logo \ + bg_l.png \ + bg_l_blank.png \ + bg_r.png \ + box_bg.png \ + breadcrumb.png \ + bullet_gt.png \ + bullet_dn.png \ + bullet_sq.png \ + bullet_up.png \ + feedbackground.png \ + horBar.png \ + page.png \ + page_bg.png \ + sprites-combined.png \ taskmenuextension-example.png \ coloreditorfactoryimage.png \ dynamiclayouts-example.png \ stylesheet-coffee-plastique.png -
\ No newline at end of file + +# This stuff is used by the new doc format. +scriptdirs = $QT_SOURCE_TREE/doc/src/template/scripts +styledirs = $QT_SOURCE_TREE/doc/src/template/style + +scripts.HTML = functions.js \ + jquery.js + +styles.HTML = style.css \ + style_ie6.css \ + style_ie7.css \ + style_ie8.css diff --git a/tools/qdoc3/test/qt-html-templates.qdocconf b/tools/qdoc3/test/qt-html-templates.qdocconf index 60d6b61..e83e666 100644 --- a/tools/qdoc3/test/qt-html-templates.qdocconf +++ b/tools/qdoc3/test/qt-html-templates.qdocconf @@ -1,25 +1,151 @@ -HTML.stylesheets = classic.css -HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n" \ - "<tr>\n" \ - "<td align=\"left\" valign=\"top\" width=\"32\">" \ - "<a href=\"http://qt.nokia.com/\"><img src=\"images/qt-logo.png\" align=\"left\" border=\"0\" /></a>" \ - "</td>\n" \ - "<td width=\"1\"> </td>" \ - "<td class=\"postheader\" valign=\"center\">" \ - "<a href=\"index.html\">" \ - "<font color=\"#004faf\">Home</font></a> ·" \ - " <a href=\"classes.html\">" \ - "<font color=\"#004faf\">All Classes</font></a> ·" \ - " <a href=\"functions.html\">" \ - "<font color=\"#004faf\">All Functions</font></a> ·" \ - " <a href=\"overviews.html\">" \ - "<font color=\"#004faf\">Overviews</font></a>" \ - "</td>" \ - "</tr></table>" +HTML.stylesheets = style/style_ie6.css \ + style/style_ie7.css \ + style/style_ie8.css \ + style/style.css + +HTML.postheader = " <div class=\"header\" id=\"qtdocheader\">\n" \ + " <div id=\"nav-logo\">\n" \ + " <a href=\"index.html\">Home</a></div>\n" \ + " <a href=\"index.html\" class=\"qtref\"><span>Qt Reference Documentation</span></a>\n" \ + " <div id=\"nav-topright\">\n" \ + " <ul>\n" \ + " <li class=\"nav-topright-home\"><a href=\"http://qt.nokia.com/\">Qt HOME</a></li>\n" \ + " <li class=\"nav-topright-dev\"><a href=\"http://qt.nokia.com/developer\">DEV</a></li>\n" \ + " <li class=\"nav-topright-labs\"><a href=\"http://labs.qt.nokia.com/blogs/\">LABS</a></li>\n" \ + " <li class=\"nav-topright-doc nav-topright-doc-active\"><a href=\"http://doc.qt.nokia.com/\">\n" \ + " DOC</a></li>\n" \ + " <li class=\"nav-topright-blog\"><a href=\"http://blog.qt.nokia.com/\">BLOG</a></li>\n" \ + " <li class=\"nav-topright-shop\"><a title=\"SHOP\" href=\"http://shop.qt.nokia.com\">SHOP</a></li>\n" \ + " </ul>\n" \ + " </div>\n" \ + " <div id=\"shortCut\">\n" \ + " <ul>\n" \ + " <li class=\"shortCut-topleft-inactive\"><span><a href=\"index.html\">Qt 4.7</a></span></li>\n" \ + " <li class=\"shortCut-topleft-active\"><a href=\"http://qt.nokia.com/doc/\">ALL Qt VERSIONS" \ + " </a></li>\n" \ + " </ul>\n" \ + " </div>\n" \ + " </div>\n" \ + " <div class=\"wrapper\">\n" \ + " <div class=\"hd\">\n" \ + " <span></span>\n" \ + " </div>\n" \ + " <div class=\"bd group\">\n" \ + " <div class=\"sidebar\">\n" \ + " <div class=\"searchlabel\">\n" \ + " Search index:</div>\n" \ + " <div class=\"search\">\n" \ + " <form id=\"qtdocsearch\" action=\"\">\n" \ + " <fieldset>\n" \ + " <input type=\"text\" name=\"searchstring\" id=\"pageType\" value=\"\" />\n" \ + " </fieldset>\n" \ + " </form>\n" \ + " </div>\n" \ + " <div class=\"box first bottombar\" id=\"lookup\">\n" \ + " <h2><span></span>\n" \ + " API Lookup</h2>\n" \ + " <div id=\"list001\" class=\"list\">\n" \ + " <ul id=\"ul001\" >\n" \ + " <li class=\"defaultLink\"><a href=\"classes.html\">Class index</a></li>\n" \ + " <li class=\"defaultLink\"><a href=\"functions.html\">Function index</a></li>\n" \ + " <li class=\"defaultLink\"><a href=\"modules.html\">Modules</a></li>\n" \ + " <li class=\"defaultLink\"><a href=\"namespaces.html\">Namespaces</a></li>\n" \ + " <li class=\"defaultLink\"><a href=\"qtglobal.html\">Global stuff</a></li>\n" \ + " <li class=\"defaultLink\"><a href=\"qdeclarativeelements.html\">QML elements</a></li>\n" \ + " </ul> \n" \ + " </div>\n" \ + " <div id=\"live001\" class=\"live\">\n" \ + " </div>\n" \ + " </div>\n" \ + " <div class=\"box bottombar\" id=\"topics\">\n" \ + " <h2><span></span>\n" \ + " Qt Topics</h2>\n" \ + " <div id=\"list002\" class=\"list\">\n" \ + " <ul id=\"ul002\" >\n" \ + " <li class=\"defaultLink\"><a href=\"qt-basic-concepts.html\">Basic Qt architecture</a></li>\n" \ + " <li class=\"defaultLink\"><a href=\"declarativeui.html\">Device UI's & Qt Quick</a></li>\n" \ + " <li class=\"defaultLink\"><a href=\"qt-gui-concepts.html\">Desktop UI components</a></li>\n" \ + " <li class=\"defaultLink\"><a href=\"platform-specific.html\">Platform-specific info</a></li>\n" \ + " </ul> \n" \ + " </div>\n" \ + " <div id=\"live002\" class=\"live\">\n" \ + " </div>\n" \ + " </div>\n" \ + " <div class=\"box\" id=\"examples\">\n" \ + " <h2><span></span>\n" \ + " Examples</h2>\n" \ + " <div id=\"list003\" class=\"list\">\n" \ + " <ul id=\"ul003\">\n" \ + " <li class=\"defaultLink\"><a href=\"all-examples.html\">Examples</a></li>\n" \ + " <li class=\"defaultLink\"><a href=\"tutorials.html\">Tutorials</a></li>\n" \ + " <li class=\"defaultLink\"><a href=\"demos.html\">Demos</a></li>\n" \ + " <li class=\"defaultLink\"><a href=\"qdeclarativeexamples.html\">QML Examples</a></li>\n" \ + " <li class=\"defaultLink\"><a href=\"qdeclarativeexamples.html#Demos\">QML Demos</a></li>\n" \ + " </ul> \n" \ + " </div>\n" \ + " <div id=\"live003\" class=\"live\">\n" \ + " </div>\n" \ + " </div>\n" \ + " </div>\n" \ + " <div class=\"wrap\">\n" \ + " <div class=\"toolbar\">\n" \ + " <div class=\"breadcrumb toolblock\">\n" \ + " <ul>\n" \ + " <li class=\"first\"><a href=\"index.html\">Home</a></li>\n" \ + " <!-- Bread crumbs goes here -->\n" -HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \ - "<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \ - "<td width=\"40%\" align=\"left\">Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)</td>\n" \ - "<td width=\"20%\" align=\"center\"><a href=\"trademarks.html\">Trademarks</a></td>\n" \ - "<td width=\"40%\" align=\"right\"><div align=\"right\">Qt \\version</div></td>\n" \ - "</tr></table></div></address>" +HTML.postpostheader = " </ul>\n" \ + " </div>\n" \ + " <div class=\"toolbuttons toolblock\">\n" \ + " <ul>\n" \ + " <li id=\"smallA\" class=\"t_button\">A</li>\n" \ + " <li id=\"medA\" class=\"t_button active\">A</li>\n" \ + " <li id=\"bigA\" class=\"t_button\">A</li>\n" \ + " <li id=\"print\" class=\"t_button\"><a href=\"javascript:this.print();\">\n" \ + " <span>Print</span></a></li>\n" \ + " </ul>\n" \ + " </div>\n" \ + " </div>\n" \ + " <div class=\"content\">\n" + +HTML.footer = " <!-- /div -->\n" \ + " <div class=\"feedback t_button\" onclick=\"\$(\'.bd\').hide();\$(\'.hd\').hide();\$(\'.footer\').hide();\$(\'#feedbackBox\').show();\$(\'#blurpage\').show()\">\n" \ + " [+] Documentation Feedback</div>\n" \ + " </div>\n" \ + " </div>\n" \ + " <div class=\"ft\">\n" \ + " <span></span>\n" \ + " </div>\n" \ + " </div> \n" \ + " <div class=\"footer\">\n" \ + " <p>\n" \ + " <acronym title=\"Copyright\">©</acronym> 2008-2010 Nokia Corporation and/or its\n" \ + " subsidiaries. Nokia, Qt and their respective logos are trademarks of Nokia Corporation \n" \ + " in Finland and/or other countries worldwide.</p>\n" \ + " <p>\n" \ + " All other trademarks are property of their respective owners. <a title=\"Privacy Policy\"\n" \ + " href=\"http://qt.nokia.com/about/privacy-policy\">Privacy Policy</a></p>\n" \ + " </div>\n" \ + " <div id=\"feedbackBox\">\n" \ + " <div id=\"feedcloseX\">\n" \ + " <a href=\"#\" onclick=\"\$(\'.bd\').show();\$(\'.hd\').show();\$(\'.footer\').show();\$(\'#feedbackBox\').hide();\$(\'#blurpage\').hide()\">X</a>\n" \ + " </div>\n" \ + " <form id=\"feedform\" action=\"feedback.php\" method=\"get\">\n" \ + " <p><textarea id=\"feedbox\" name=\"feedText\" rows=\"5\" cols=\"40\">Please submit you feedback...</textarea></p>\n" \ + " <input id=\"page\" name=\"pageVal\" value=\"\$(\'title\').html();\" style=\"display:none;\">\n" \ + " <p><input id=\"feedsubmit\" type=\"submit\" onclick=\"\$(\'.bd\').show();\$(\'.hd\').show();\$(\'.footer\').show();\$(\'#feedbackBox\').hide();\$(\'#blurpage\').hide()\"\n" \ + " name=\"feedback\" /></p>\n" \ + " </form>\n" \ + " </div>\n" \ + " <div id=\"blurpage\">\n" \ + " </div>\n" \ + "<!-- <script type=\"text/javascript\">\n" \ + " var _gaq = _gaq || [];\n" \ + " _gaq.push([\'_setAccount\', \'UA-4457116-5\']);\n" \ + " _gaq.push([\'_trackPageview\']);\n" \ + " (function() {\n" \ + " var ga = document.createElement(\'script\'); ga.type = \'text/javascript\'; ga.async = true;\n" \ + " ga.src = (\'https:\' == document.location.protocol ? \'https://ssl\' : \'http://www\') + \'.google-analytics.com/ga.js\';\n" \ + " var s = document.getElementsByTagName(\'script\')[0]; s.parentNode.insertBefore(ga, s);\n" \ + " })();\n" \ + "</script> -->\n" diff --git a/tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf b/tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf new file mode 100644 index 0000000..5fb68cf --- /dev/null +++ b/tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf @@ -0,0 +1,25 @@ +HTML.stylesheets = classic.css +HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n" \ + "<tr>\n" \ + "<td align=\"left\" valign=\"top\" width=\"32\">" \ + "<a href=\"http://qt.nokia.com/\"><img src=\"images/qt-logo.png\" align=\"left\" border=\"0\" /></a>" \ + "</td>\n" \ + "<td width=\"1\"> </td>" \ + "<td class=\"postheader\" valign=\"center\">" \ + "<a href=\"http://qt.nokia.com/doc/4.7/index.html\">" \ + "<font color=\"#004faf\">主页</font></a> ·" \ + " <a href=\"http://qt.nokia.com/doc/4.7/classes.html\">" \ + "<font color=\"#004faf\">所有类</font></a> ·" \ + " <a href=\"http://qt.nokia.com/doc/4.7/functions.html\">" \ + "<font color=\"#004faf\">所有函数</font></a> ·" \ + " <a href=\"http://qt.nokia.com/doc/4.7/overviews.html\">" \ + "<font color=\"#004faf\">简介</font></a>" \ + "</td>" \ + "</tr></table>" + +HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \ + "<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \ + "<td width=\"40%\" align=\"left\">版权所有 © 2010 诺基亚公司和/或其子公司</td>\n" \ + "<td width=\"20%\" align=\"center\"><a href=\"trademarks.html\">商标</a></td>\n" \ + "<td width=\"40%\" align=\"right\"><div align=\"right\">Qt \\version</div></td>\n" \ + "</tr></table></div></address>" diff --git a/tools/qdoc3/test/qt-webxml.qdocconf b/tools/qdoc3/test/qt-webxml.qdocconf index 3ad0457..80ced42 100644 --- a/tools/qdoc3/test/qt-webxml.qdocconf +++ b/tools/qdoc3/test/qt-webxml.qdocconf @@ -2,7 +2,8 @@ include(qt.qdocconf) quotinginformation = true imagedirs = $QTDIR/doc/src/images \ - $QTDIR/examples + $QTDIR/examples \ + $QTDIR/doc/src/template/images outputdir = $QTDIR/doc/webxml outputformats = WebXML diff --git a/tools/qdoc3/test/qt.qdocconf b/tools/qdoc3/test/qt.qdocconf index d5a2995..83a35a9 100644 --- a/tools/qdoc3/test/qt.qdocconf +++ b/tools/qdoc3/test/qt.qdocconf @@ -8,35 +8,52 @@ project = Qt versionsym = version = %VERSION% description = Qt Reference Documentation -url = http://qt.nokia.com/doc/4.6 +url = http://qt.nokia.com/doc/4.7 +online = true -edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript QtScriptTools QtSql QtSvg \ - QtWebKit QtXml QtXmlPatterns Qt3Support QtHelp \ - QtDesigner QtAssistant QAxContainer Phonon \ - QAxServer QtUiTools QtTest QtDBus -edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest -edition.DesktopLight.groups = -graphicsview-api +sourceencoding = UTF-8 +outputencoding = UTF-8 +naturallanguage = en_US qhp.projects = Qt qhp.Qt.file = qt.qhp -qhp.Qt.namespace = com.trolltech.qt.460 +qhp.Qt.namespace = com.trolltech.qt.470 qhp.Qt.virtualFolder = qdoc qhp.Qt.indexTitle = Qt Reference Documentation qhp.Qt.indexRoot = # Files not referenced in any qdoc file (last four are needed by qtdemo) # See also extraimages.HTML -qhp.Qt.extraFiles = classic.css \ - images/qt-logo.png \ - images/taskmenuextension-example.png \ - images/coloreditorfactoryimage.png \ - images/dynamiclayouts-example.png \ - images/stylesheet-coffee-plastique.png +qhp.Qt.extraFiles = index.html \ + images/bg_l.png \ + images/bg_l_blank.png \ + images/bg_r.png \ + images/box_bg.png \ + images/breadcrumb.png \ + images/bullet_gt.png \ + images/bullet_dn.png \ + images/bullet_sq.png \ + images/bullet_up.png \ + images/feedbackground.png \ + images/horBar.png \ + images/page.png \ + images/page_bg.png \ + images/sprites-combined.png \ + images/stylesheet-coffee-plastique.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + scripts/functions.js \ + scripts/jquery.js \ + style/style_ie6.css \ + style/style_ie7.css \ + style/style_ie8.css \ + style/style.css -qhp.Qt.filterAttributes = qt 4.6.3 qtrefdoc -qhp.Qt.customFilters.Qt.name = Qt 4.6.3 -qhp.Qt.customFilters.Qt.filterAttributes = qt 4.6.3 +qhp.Qt.filterAttributes = qt 4.7.0 qtrefdoc +qhp.Qt.customFilters.Qt.name = Qt 4.7.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.7.0 qhp.Qt.subprojects = classes overviews examples qhp.Qt.subprojects.classes.title = Classes qhp.Qt.subprojects.classes.indexTitle = Qt's Classes @@ -91,15 +108,16 @@ excludedirs = $QTDIR/src/3rdparty/clucene \ $QTDIR/src/3rdparty/webkit/WebCore \ $QTDIR/src/3rdparty/wintab \ $QTDIR/src/3rdparty/zlib \ - $QTDIR/doc/src/snippets \ $QTDIR/src/3rdparty/phonon/gstreamer \ $QTDIR/src/3rdparty/phonon/ds9 \ $QTDIR/src/3rdparty/phonon/qt7 \ $QTDIR/src/3rdparty/phonon/mmf \ - $QTDIR/src/3rdparty/phonon/waveout + $QTDIR/src/3rdparty/phonon/waveout \ + $QTDIR/doc/src/snippets \ + $QTDIR/doc/src/zh_CN sources.fileextensions = "*.cpp *.qdoc *.mm" -examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" +examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp *.qml" examples.imageextensions = "*.png" exampledirs = $QTDIR/doc/src \ @@ -109,7 +127,9 @@ exampledirs = $QTDIR/doc/src \ $QTDIR/qmake/examples \ $QTDIR/src/3rdparty/webkit/WebKit/qt/docs imagedirs = $QTDIR/doc/src/images \ - $QTDIR/examples + $QTDIR/examples \ + $QTDIR/doc/src/declarative/pics \ + $QTDIR/doc/src/template/images outputdir = $QTDIR/doc/html tagfile = $QTDIR/doc/html/qt.tags base = file:$QTDIR/doc/html diff --git a/tools/qdoc3/test/qt_zh_CN.qdocconf b/tools/qdoc3/test/qt_zh_CN.qdocconf new file mode 100644 index 0000000..9275b5c --- /dev/null +++ b/tools/qdoc3/test/qt_zh_CN.qdocconf @@ -0,0 +1,103 @@ +include(compat.qdocconf) +include(macros.qdocconf) +include(qt-cpp-ignore.qdocconf) +include(qt-html-templates_zh_CN.qdocconf) +include(qt-defines.qdocconf) + +project = Qt +versionsym = +version = %VERSION% +description = Qt Reference Documentation +url = http://qt.nokia.com/doc/zh_CN/4.7 + +sourceencoding = UTF-8 +outputencoding = UTF-8 +naturallanguage = zh-Hans + +indexes = $QTDIR/doc/html/qt.index + +qhp.projects = Qt + +qhp.Qt.file = qt.qhp +qhp.Qt.namespace = com.trolltech.qt.470 +qhp.Qt.virtualFolder = qdoc +qhp.Qt.title = 教程 +qhp.Qt.indexTitle = 教程 +qhp.Qt.selectors = fake:example + +qhp.Qt.filterAttributes = qt 4.7.0 qtrefdoc zh_CN +qhp.Qt.customFilters.Qt.name = Qt 4.7.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.7.0 + +# Files not referenced in any qdoc file (last four are needed by qtdemo) +# See also extraimages.HTML +qhp.Qt.extraFiles = index.html \ + images/bg_l.png \ + images/bg_l_blank.png \ + images/bg_r.png \ + images/box_bg.png \ + images/breadcrumb.png \ + images/bullet_gt.png \ + images/bullet_dn.png \ + images/bullet_sq.png \ + images/bullet_up.png \ + images/feedbackground.png \ + images/horBar.png \ + images/page.png \ + images/page_bg.png \ + images/sprites-combined.png \ + images/stylesheet-coffee-plastique.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + scripts/functions.js \ + scripts/jquery.js \ + style/style.css + +language = Cpp + +sourcedirs = $QTDIR/doc/src/zh_CN + +excludedirs = $QTDIR/src/3rdparty/clucene \ + $QTDIR/src/3rdparty/des \ + $QTDIR/src/3rdparty/freetype \ + $QTDIR/src/3rdparty/harfbuzz \ + $QTDIR/src/3rdparty/kdebase \ + $QTDIR/src/3rdparty/libjpeg \ + $QTDIR/src/3rdparty/libmng \ + $QTDIR/src/3rdparty/libpng \ + $QTDIR/src/3rdparty/libtiff \ + $QTDIR/src/3rdparty/md4 \ + $QTDIR/src/3rdparty/md5 \ + $QTDIR/src/3rdparty/patches \ + $QTDIR/src/3rdparty/sha1 \ + $QTDIR/src/3rdparty/sqlite \ + $QTDIR/src/3rdparty/webkit/JavaScriptCore \ + $QTDIR/src/3rdparty/webkit/WebCore \ + $QTDIR/src/3rdparty/wintab \ + $QTDIR/src/3rdparty/zlib \ + $QTDIR/doc/src/snippets \ + $QTDIR/src/3rdparty/phonon/gstreamer \ + $QTDIR/src/3rdparty/phonon/ds9 \ + $QTDIR/src/3rdparty/phonon/qt7 \ + $QTDIR/src/3rdparty/phonon/mmf \ + $QTDIR/src/3rdparty/phonon/waveout + +sources.fileextensions = "*.cpp *.qdoc *.mm" +examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" +examples.imageextensions = "*.png" + +exampledirs = $QTDIR/doc/src \ + $QTDIR/examples \ + $QTDIR/examples/tutorials \ + $QTDIR \ + $QTDIR/qmake/examples \ + $QTDIR/src/3rdparty/webkit/WebKit/qt/docs +imagedirs = $QTDIR/doc/src/images \ + $QTDIR/examples \ + $QTDIR/doc/src/template/images +outputdir = $QTDIR/doc/html_zh_CN +tagfile = $QTDIR/doc/html_zh_CN/qt.tags +base = file:$QTDIR/doc/html_zh_CN + +HTML.generatemacrefs = "true" diff --git a/tools/qdoc3/test/scripts/functions.js b/tools/qdoc3/test/scripts/functions.js new file mode 100644 index 0000000..0135427 --- /dev/null +++ b/tools/qdoc3/test/scripts/functions.js @@ -0,0 +1,60 @@ + +/* START non link areas where cursor should change to pointing hand */ +$('.t_button').mouseover(function() { + $('.t_button').css('cursor','pointer'); + /*document.getElementById(this.id).style.cursor='pointer';*/ +}); + +/* END non link areas */ +$('#smallA').click(function() { + $('.content .heading,.content h1, .content h2, .content h3, .content p, .content li, .content table').css('font-size','smaller'); + $('.t_button').removeClass('active') + $(this).addClass('active') +}); + +$('#medA').click(function() { + $('.content .heading').css('font','600 16px/1 Arial'); + $('.content h1').css('font','600 18px/1.2 Arial'); + $('.content h2').css('font','600 16px/1.2 Arial'); + $('.content h3').css('font','600 14px/1.2 Arial'); + $('.content p').css('font','13px/20px Verdana'); + $('.content li').css('font','400 13px/1 Verdana'); + $('.content li').css('line-height','14px'); + $('.content table').css('font','13px/1.2 Verdana'); + $('.content .heading').css('font','600 16px/1 Arial'); + $('.content .indexboxcont li').css('font','600 13px/1 Verdana'); + $('.t_button').removeClass('active') + $(this).addClass('active') +}); + +$('#bigA').click(function() { + $('.content .heading,.content h1, .content h2, .content h3, .content p, .content li, .content table').css('font-size','large'); + $('.content .heading,.content h1, .content h2, .content h3, .content p, .content li, .content table').css('line-height','25px'); + $('.t_button').removeClass('active') + $(this).addClass('active') +}); + +function doSearch(str){ + +if (str.length>3) + { + alert('start search'); + // document.getElementById("refWrapper").innerHTML=""; + return; + } + else + return; + +// var url="indexSearch.php"; +// url=url+"?q="+str; + // url=url+"&sid="+Math.random(); + // var url="http://localhost:8983/solr/select?"; + // url=url+"&q="+str; + // url=url+"&fq=&start=0&rows=10&fl=&qt=&wt=&explainOther=&hl.fl="; + + // $.get(url, function(data){ + // alert(data); + // document.getElementById("refWrapper").innerHTML=data; + //}); + +}
\ No newline at end of file diff --git a/tools/qdoc3/test/scripts/jquery.js b/tools/qdoc3/test/scripts/jquery.js new file mode 100644 index 0000000..0c7294c --- /dev/null +++ b/tools/qdoc3/test/scripts/jquery.js @@ -0,0 +1,152 @@ +/*! + * jQuery JavaScript Library v1.4.1 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Mon Jan 25 19:43:33 2010 -0500 + */ +(function(z,v){function la(){if(!c.isReady){try{r.documentElement.doScroll("left")}catch(a){setTimeout(la,1);return}c.ready()}}function Ma(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,i){var j=a.length;if(typeof b==="object"){for(var n in b)X(a,n,b[n],f,e,d);return a}if(d!==v){f=!i&&f&&c.isFunction(d);for(n=0;n<j;n++)e(a[n],b,f?d.call(a[n],n,e(a[n],b)):d,i);return a}return j? +e(a[0],b):null}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function ma(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function na(a){var b,d=[],f=[],e=arguments,i,j,n,o,m,s,x=c.extend({},c.data(this,"events").live);if(!(a.button&&a.type==="click")){for(o in x){j=x[o];if(j.live===a.type||j.altLive&&c.inArray(a.type,j.altLive)>-1){i=j.data;i.beforeFilter&&i.beforeFilter[a.type]&&!i.beforeFilter[a.type](a)||f.push(j.selector)}else delete x[o]}i=c(a.target).closest(f, +a.currentTarget);m=0;for(s=i.length;m<s;m++)for(o in x){j=x[o];n=i[m].elem;f=null;if(i[m].selector===j.selector){if(j.live==="mouseenter"||j.live==="mouseleave")f=c(a.relatedTarget).closest(j.selector)[0];if(!f||f!==n)d.push({elem:n,fn:j})}}m=0;for(s=d.length;m<s;m++){i=d[m];a.currentTarget=i.elem;a.data=i.fn.data;if(i.fn.apply(i.elem,e)===false){b=false;break}}return b}}function oa(a,b){return"live."+(a?a+".":"")+b.replace(/\./g,"`").replace(/ /g,"&")}function pa(a){return!a||!a.parentNode||a.parentNode.nodeType=== +11}function qa(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var i in f)for(var j in f[i])c.event.add(this,i,f[i][j],f[i][j].data)}}})}function ra(a,b,d){var f,e,i;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&a[0].indexOf("<option")<0&&(c.support.checkClone||!sa.test(a[0]))){e=true;if(i=c.fragments[a[0]])if(i!==1)f=i}if(!f){b=b&&b[0]?b[0].ownerDocument||b[0]:r;f=b.createDocumentFragment(); +c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=i?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(ta.concat.apply([],ta.slice(0,b)),function(){d[this]=a});return d}function ua(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Na=z.jQuery,Oa=z.$,r=z.document,S,Pa=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Qa=/^.[^:#\[\.,]*$/,Ra=/\S/,Sa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Ta=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,O=navigator.userAgent, +va=false,P=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,Q=Array.prototype.slice,wa=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(typeof a==="string")if((d=Pa.exec(a))&&(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:r;if(a=Ta.exec(a))if(c.isPlainObject(b)){a=[r.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=ra([d[1]], +[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}}else{if(b=r.getElementById(d[2])){if(b.id!==d[2])return S.find(a);this.length=1;this[0]=b}this.context=r;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=r;a=r.getElementsByTagName(a)}else return!b||b.jquery?(b||S).find(a):c(b).find(a);else if(c.isFunction(a))return S.ready(a);if(a.selector!==v){this.selector=a.selector;this.context=a.context}return c.isArray(a)?this.setArray(a):c.makeArray(a, +this)},selector:"",jquery:"1.4.1",length:0,size:function(){return this.length},toArray:function(){return Q.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){a=c(a||null);a.prevObject=this;a.context=this.context;if(b==="find")a.selector=this.selector+(this.selector?" ":"")+d;else if(b)a.selector=this.selector+"."+b+"("+d+")";return a},setArray:function(a){this.length=0;ba.apply(this,a);return this},each:function(a,b){return c.each(this, +a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(r,c);else P&&P.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(Q.apply(this,arguments),"slice",Q.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice}; +c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,i,j,n;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(i in e){j=a[i];n=e[i];if(a!==n)if(f&&n&&(c.isPlainObject(n)||c.isArray(n))){j=j&&(c.isPlainObject(j)||c.isArray(j))?j:c.isArray(n)?[]:{};a[i]=c.extend(f,j,n)}else if(n!==v)a[i]=n}return a};c.extend({noConflict:function(a){z.$= +Oa;if(a)z.jQuery=Na;return c},isReady:false,ready:function(){if(!c.isReady){if(!r.body)return setTimeout(c.ready,13);c.isReady=true;if(P){for(var a,b=0;a=P[b++];)a.call(r,c);P=null}c.fn.triggerHandler&&c(r).triggerHandler("ready")}},bindReady:function(){if(!va){va=true;if(r.readyState==="complete")return c.ready();if(r.addEventListener){r.addEventListener("DOMContentLoaded",L,false);z.addEventListener("load",c.ready,false)}else if(r.attachEvent){r.attachEvent("onreadystatechange",L);z.attachEvent("onload", +c.ready);var a=false;try{a=z.frameElement==null}catch(b){}r.documentElement.doScroll&&a&&la()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,"isPrototypeOf"))return false;var b;for(b in a);return b===v||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false; +return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return z.JSON&&z.JSON.parse?z.JSON.parse(a):(new Function("return "+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Ra.test(a)){var b=r.getElementsByTagName("head")[0]|| +r.documentElement,d=r.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(r.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,i=a.length,j=i===v||c.isFunction(a);if(d)if(j)for(f in a){if(b.apply(a[f],d)===false)break}else for(;e<i;){if(b.apply(a[e++],d)===false)break}else if(j)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d= +a[0];e<i&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Sa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!== +v;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,i=a.length;e<i;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,i=0,j=a.length;i<j;i++){e=b(a[i],i,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=v}else if(b&&!c.isFunction(b)){d=b;b=v}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b}, +uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});O=c.uaMatch(O);if(O.browser){c.browser[O.browser]=true;c.browser.version=O.version}if(c.browser.webkit)c.browser.safari=true;if(wa)c.inArray=function(a,b){return wa.call(b,a)};S=c(r);if(r.addEventListener)L=function(){r.removeEventListener("DOMContentLoaded", +L,false);c.ready()};else if(r.attachEvent)L=function(){if(r.readyState==="complete"){r.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=r.documentElement,b=r.createElement("script"),d=r.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var e=d.getElementsByTagName("*"),i=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!i)){c.support= +{leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(i.getAttribute("style")),hrefNormalized:i.getAttribute("href")==="/a",opacity:/^0.55$/.test(i.style.opacity),cssFloat:!!i.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:r.createElement("select").appendChild(r.createElement("option")).selected,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null}; +b.type="text/javascript";try{b.appendChild(r.createTextNode("window."+f+"=1;"))}catch(j){}a.insertBefore(b,a.firstChild);if(z[f]){c.support.scriptEval=true;delete z[f]}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function n(){c.support.noCloneEvent=false;d.detachEvent("onclick",n)});d.cloneNode(true).fireEvent("onclick")}d=r.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=r.createDocumentFragment();a.appendChild(d.firstChild); +c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var n=r.createElement("div");n.style.width=n.style.paddingLeft="1px";r.body.appendChild(n);c.boxModel=c.support.boxModel=n.offsetWidth===2;r.body.removeChild(n).style.display="none"});a=function(n){var o=r.createElement("div");n="on"+n;var m=n in o;if(!m){o.setAttribute(n,"return;");m=typeof o[n]==="function"}return m};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=i=null}})();c.props= +{"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ua=0,xa={},Va={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==z?xa:a;var f=a[G],e=c.cache;if(!b&&!f)return null;f||(f=++Ua);if(typeof b==="object"){a[G]=f;e=e[f]=c.extend(true, +{},b)}else e=e[f]?e[f]:typeof d==="undefined"?Va:(e[f]={});if(d!==v){a[G]=f;e[b]=d}return typeof b==="string"?e[b]:e}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==z?xa:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{try{delete a[G]}catch(i){a.removeAttribute&&a.removeAttribute(G)}delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this, +a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===v){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===v&&this.length)f=c.data(this[0],a);return f===v&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d); +return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===v)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]|| +a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var ya=/[\n\t]/g,ca=/\s+/,Wa=/\r/g,Xa=/href|src|style/,Ya=/(button|input)/i,Za=/(button|input|object|select|textarea)/i,$a=/^(a|area)$/i,za=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(o){var m= +c(this);m.addClass(a.call(this,o,m.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className)for(var i=" "+e.className+" ",j=0,n=b.length;j<n;j++){if(i.indexOf(" "+b[j]+" ")<0)e.className+=" "+b[j]}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var m=c(this);m.removeClass(a.call(this,o,m.attr("class")))});if(a&&typeof a==="string"||a===v)for(var b=(a||"").split(ca), +d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var i=(" "+e.className+" ").replace(ya," "),j=0,n=b.length;j<n;j++)i=i.replace(" "+b[j]+" "," ");e.className=i.substring(1,i.length-1)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var i=c(this);i.toggleClass(a.call(this,e,i.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,i=0,j=c(this),n=b,o= +a.split(ca);e=o[i++];){n=f?n:!j.hasClass(e);j[n?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(ya," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===v){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value|| +{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var i=b?d:0;for(d=b?d+1:e.length;i<d;i++){var j=e[i];if(j.selected){a=c(j).val();if(b)return a;f.push(a)}}return f}if(za.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Wa,"")}return v}var n=c.isFunction(a);return this.each(function(o){var m=c(this),s=a;if(this.nodeType===1){if(n)s=a.call(this,o,m.val()); +if(typeof s==="number")s+="";if(c.isArray(s)&&za.test(this.type))this.checked=c.inArray(m.val(),s)>=0;else if(c.nodeName(this,"select")){var x=c.makeArray(s);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),x)>=0});if(!x.length)this.selectedIndex=-1}else this.value=s}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return v;if(f&&b in c.attrFn)return c(a)[b](d); +f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==v;b=f&&c.props[b]||b;if(a.nodeType===1){var i=Xa.test(b);if(b in a&&f&&!i){if(e){b==="type"&&Ya.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:Za.test(a.nodeName)||$a.test(a.nodeName)&&a.href?0:v;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText= +""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&i?a.getAttribute(b,2):a.getAttribute(b);return a===null?v:a}return c.style(a,b,d)}});var ab=function(a){return a.replace(/[^\w\s\.\|`]/g,function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==z&&!a.frameElement)a=z;if(!d.guid)d.guid=c.guid++;if(f!==v){d=c.proxy(d);d.data=f}var e=c.data(a,"events")||c.data(a,"events",{}),i=c.data(a,"handle"),j;if(!i){j= +function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(j.elem,arguments):v};i=c.data(a,"handle",j)}if(i){i.elem=a;b=b.split(/\s+/);for(var n,o=0;n=b[o++];){var m=n.split(".");n=m.shift();if(o>1){d=c.proxy(d);if(f!==v)d.data=f}d.type=m.slice(0).sort().join(".");var s=e[n],x=this.special[n]||{};if(!s){s=e[n]={};if(!x.setup||x.setup.call(a,f,m,d)===false)if(a.addEventListener)a.addEventListener(n,i,false);else a.attachEvent&&a.attachEvent("on"+n,i)}if(x.add)if((m=x.add.call(a, +d,f,m,s))&&c.isFunction(m)){m.guid=m.guid||d.guid;m.data=m.data||d.data;m.type=m.type||d.type;d=m}s[d.guid]=d;this.global[n]=true}a=null}}},global:{},remove:function(a,b,d){if(!(a.nodeType===3||a.nodeType===8)){var f=c.data(a,"events"),e,i,j;if(f){if(b===v||typeof b==="string"&&b.charAt(0)===".")for(i in f)this.remove(a,i+(b||""));else{if(b.type){d=b.handler;b=b.type}b=b.split(/\s+/);for(var n=0;i=b[n++];){var o=i.split(".");i=o.shift();var m=!o.length,s=c.map(o.slice(0).sort(),ab);s=new RegExp("(^|\\.)"+ +s.join("\\.(?:.*\\.)?")+"(\\.|$)");var x=this.special[i]||{};if(f[i]){if(d){j=f[i][d.guid];delete f[i][d.guid]}else for(var A in f[i])if(m||s.test(f[i][A].type))delete f[i][A];x.remove&&x.remove.call(a,o,j);for(e in f[i])break;if(!e){if(!x.teardown||x.teardown.call(a,o)===false)if(a.removeEventListener)a.removeEventListener(i,c.data(a,"handle"),false);else a.detachEvent&&a.detachEvent("on"+i,c.data(a,"handle"));e=null;delete f[i]}}}}for(e in f)break;if(!e){if(A=c.data(a,"handle"))A.elem=null;c.removeData(a, +"events");c.removeData(a,"handle")}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();this.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return v;a.result=v;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d, +b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(i){}if(!a.isPropagationStopped()&&f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){d=a.target;var j;if(!(c.nodeName(d,"a")&&e==="click")&&!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()])){try{if(d[e]){if(j=d["on"+e])d["on"+e]=null;this.triggered=true;d[e]()}}catch(n){}if(j)d["on"+e]=j;this.triggered=false}}},handle:function(a){var b, +d;a=arguments[0]=c.event.fix(a||z.event);a.currentTarget=this;d=a.type.split(".");a.type=d.shift();b=!d.length&&!a.exclusive;var f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)");d=(c.data(this,"events")||{})[a.type];for(var e in d){var i=d[e];if(b||f.test(i.type)){a.handler=i;a.data=i.data;i=i.apply(this,arguments);if(i!==v){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), +fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||r;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=r.documentElement;d=r.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop|| +d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==v)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a,b){c.extend(a,b||{});a.guid+=b.selector+b.live;b.liveProxy=a;c.event.add(this,b.live,na,b)},remove:function(a){if(a.length){var b= +0,d=new RegExp("(^|\\.)"+a[0]+"(\\.|$)");c.each(c.data(this,"events").live||{},function(){d.test(this.type)&&b++});b<1&&c.event.remove(this,a[0],na)}},special:{}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true}; +c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y};var Aa=function(a){for(var b= +a.relatedTarget;b&&b!==this;)try{b=b.parentNode}catch(d){break}if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}},Ba=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ba:Aa,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ba:Aa)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(a,b,d){if(this.nodeName.toLowerCase()!== +"form"){c.event.add(this,"click.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="submit"||i==="image")&&c(e).closest("form").length)return ma("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="text"||i==="password")&&c(e).closest("form").length&&f.keyCode===13)return ma("submit",this,arguments)})}else return false},remove:function(a,b){c.event.remove(this,"click.specialSubmit"+(b?"."+b.guid:""));c.event.remove(this, +"keypress.specialSubmit"+(b?"."+b.guid:""))}};if(!c.support.changeBubbles){var da=/textarea|input|select/i;function Ca(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d}function ea(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Ca(d);if(a.type!=="focusout"|| +d.type!=="radio")c.data(d,"_change_data",e);if(!(f===v||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}}c.event.special.change={filters:{focusout:ea,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return ea.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return ea.call(this,a)},beforeactivate:function(a){a= +a.target;a.nodeName.toLowerCase()==="input"&&a.type==="radio"&&c.data(a,"_change_data",Ca(a))}},setup:function(a,b,d){for(var f in T)c.event.add(this,f+".specialChange."+d.guid,T[f]);return da.test(this.nodeName)},remove:function(a,b){for(var d in T)c.event.remove(this,d+".specialChange"+(b?"."+b.guid:""),T[d]);return da.test(this.nodeName)}};var T=c.event.special.change.filters}r.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this, +f)}c.event.special[b]={setup:function(){this.addEventListener(a,d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var i in d)this[b](i,f,d[i],e);return this}if(c.isFunction(f)){e=f;f=v}var j=b==="one"?c.proxy(e,function(n){c(this).unbind(n,j);return e.apply(this,arguments)}):e;return d==="unload"&&b!=="one"?this.one(d,f,e):this.each(function(){c.event.add(this,d,j,f)})}});c.fn.extend({unbind:function(a, +b){if(typeof a==="object"&&!a.preventDefault){for(var d in a)this.unbind(d,a[d]);return this}return this.each(function(){c.event.remove(this,a,b)})},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+ +a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e){var i,j=0;if(c.isFunction(f)){e=f;f=v}for(d=(d||"").split(/\s+/);(i=d[j++])!=null;){i=i==="focus"?"focusin":i==="blur"?"focusout":i==="hover"?d.push("mouseleave")&&"mouseenter":i;b==="live"?c(this.context).bind(oa(i,this.selector),{data:f,selector:this.selector, +live:i},e):c(this.context).unbind(oa(i,this.selector),e?{guid:e.guid+this.selector+i}:null)}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});z.attachEvent&&!z.addEventListener&&z.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}}); +(function(){function a(g){for(var h="",k,l=0;g[l];l++){k=g[l];if(k.nodeType===3||k.nodeType===4)h+=k.nodeValue;else if(k.nodeType!==8)h+=a(k.childNodes)}return h}function b(g,h,k,l,q,p){q=0;for(var u=l.length;q<u;q++){var t=l[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===k){y=l[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=k;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}l[q]=y}}}function d(g,h,k,l,q,p){q=0;for(var u=l.length;q<u;q++){var t=l[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache=== +k){y=l[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=k;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(o.filter(h,[t]).length>0){y=t;break}}t=t[g]}l[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,i=Object.prototype.toString,j=false,n=true;[0,0].sort(function(){n=false;return 0});var o=function(g,h,k,l){k=k||[];var q=h=h||r;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g|| +typeof g!=="string")return k;for(var p=[],u,t,y,R,H=true,M=w(h),I=g;(f.exec(""),u=f.exec(I))!==null;){I=u[3];p.push(u[1]);if(u[2]){R=u[3];break}}if(p.length>1&&s.exec(g))if(p.length===2&&m.relative[p[0]])t=fa(p[0]+p[1],h);else for(t=m.relative[p[0]]?[h]:o(p.shift(),h);p.length;){g=p.shift();if(m.relative[g])g+=p.shift();t=fa(g,t)}else{if(!l&&p.length>1&&h.nodeType===9&&!M&&m.match.ID.test(p[0])&&!m.match.ID.test(p[p.length-1])){u=o.find(p.shift(),h,M);h=u.expr?o.filter(u.expr,u.set)[0]:u.set[0]}if(h){u= +l?{expr:p.pop(),set:A(l)}:o.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=u.expr?o.filter(u.expr,u.set):u.set;if(p.length>0)y=A(t);else H=false;for(;p.length;){var D=p.pop();u=D;if(m.relative[D])u=p.pop();else D="";if(u==null)u=h;m.relative[D](y,u,M)}}else y=[]}y||(y=t);y||o.error(D||g);if(i.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))k.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&& +y[g].nodeType===1&&k.push(t[g]);else k.push.apply(k,y);else A(y,k);if(R){o(R,q,k,l);o.uniqueSort(k)}return k};o.uniqueSort=function(g){if(C){j=n;g.sort(C);if(j)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};o.matches=function(g,h){return o(g,null,null,h)};o.find=function(g,h,k){var l,q;if(!g)return[];for(var p=0,u=m.order.length;p<u;p++){var t=m.order[p];if(q=m.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");l=m.find[t](q, +h,k);if(l!=null){g=g.replace(m.match[t],"");break}}}}l||(l=h.getElementsByTagName("*"));return{set:l,expr:g}};o.filter=function(g,h,k,l){for(var q=g,p=[],u=h,t,y,R=h&&h[0]&&w(h[0]);g&&h.length;){for(var H in m.filter)if((t=m.leftMatch[H].exec(g))!=null&&t[2]){var M=m.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(u===p)p=[];if(m.preFilter[H])if(t=m.preFilter[H](t,u,k,p,l,R)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=u[U])!=null;U++)if(D){I=M(D,t,U,u);var Da= +l^!!I;if(k&&I!=null)if(Da)y=true;else u[U]=false;else if(Da){p.push(D);y=true}}if(I!==v){k||(u=p);g=g.replace(m.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)o.error(g);else break;q=g}return u};o.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var m=o.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, +TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,h){var k=typeof h==="string",l=k&&!/\W/.test(h);k=k&&!l;if(l)h=h.toLowerCase();l=0;for(var q=g.length, +p;l<q;l++)if(p=g[l]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[l]=k||p&&p.nodeName.toLowerCase()===h?p||false:p===h}k&&o.filter(h,g,true)},">":function(g,h){var k=typeof h==="string";if(k&&!/\W/.test(h)){h=h.toLowerCase();for(var l=0,q=g.length;l<q;l++){var p=g[l];if(p){k=p.parentNode;g[l]=k.nodeName.toLowerCase()===h?k:false}}}else{l=0;for(q=g.length;l<q;l++)if(p=g[l])g[l]=k?p.parentNode:p.parentNode===h;k&&o.filter(h,g,true)}},"":function(g,h,k){var l=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p= +h=h.toLowerCase();q=b}q("parentNode",h,l,g,p,k)},"~":function(g,h,k){var l=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,l,g,p,k)}},find:{ID:function(g,h,k){if(typeof h.getElementById!=="undefined"&&!k)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var k=[];h=h.getElementsByName(g[1]);for(var l=0,q=h.length;l<q;l++)h[l].getAttribute("name")===g[1]&&k.push(h[l]);return k.length===0?null:k}}, +TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,k,l,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var u;(u=h[p])!=null;p++)if(u)if(q^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))k||l.push(u);else if(k)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&& +"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,k,l,q,p){h=g[1].replace(/\\/g,"");if(!p&&m.attrMap[h])g[1]=m.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,k,l,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=o(g[3],null,null,h);else{g=o.filter(g[3],h,k,true^q);k||l.push.apply(l,g);return false}else if(m.match.POS.test(g[0])||m.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true); +return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,k){return!!o(k[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"=== +g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,h){return h===0},last:function(g,h,k,l){return h===l.length-1},even:function(g,h){return h%2=== +0},odd:function(g,h){return h%2===1},lt:function(g,h,k){return h<k[3]-0},gt:function(g,h,k){return h>k[3]-0},nth:function(g,h,k){return k[3]-0===h},eq:function(g,h,k){return k[3]-0===h}},filter:{PSEUDO:function(g,h,k,l){var q=h[1],p=m.filters[q];if(p)return p(g,k,h,l);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=h[3];k=0;for(l=h.length;k<l;k++)if(h[k]===g)return false;return true}else o.error("Syntax error, unrecognized expression: "+ +q)},CHILD:function(g,h){var k=h[1],l=g;switch(k){case "only":case "first":for(;l=l.previousSibling;)if(l.nodeType===1)return false;if(k==="first")return true;l=g;case "last":for(;l=l.nextSibling;)if(l.nodeType===1)return false;return true;case "nth":k=h[2];var q=h[3];if(k===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var u=0;for(l=p.firstChild;l;l=l.nextSibling)if(l.nodeType===1)l.nodeIndex=++u;p.sizcache=h}g=g.nodeIndex-q;return k===0?g===0:g%k===0&&g/k>= +0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var k=h[1];g=m.attrHandle[k]?m.attrHandle[k](g):g[k]!=null?g[k]:g.getAttribute(k);k=g+"";var l=h[2];h=h[4];return g==null?l==="!=":l==="="?k===h:l==="*="?k.indexOf(h)>=0:l==="~="?(" "+k+" ").indexOf(h)>=0:!h?k&&g!==false:l==="!="?k!==h:l==="^="? +k.indexOf(h)===0:l==="$="?k.substr(k.length-h.length)===h:l==="|="?k===h||k.substr(0,h.length+1)===h+"-":false},POS:function(g,h,k,l){var q=m.setFilters[h[2]];if(q)return q(g,k,h,l)}}},s=m.match.POS;for(var x in m.match){m.match[x]=new RegExp(m.match[x].source+/(?![^\[]*\])(?![^\(]*\))/.source);m.leftMatch[x]=new RegExp(/(^(?:.|\r|\n)*?)/.source+m.match[x].source.replace(/\\(\d+)/g,function(g,h){return"\\"+(h-0+1)}))}var A=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g}; +try{Array.prototype.slice.call(r.documentElement.childNodes,0)}catch(B){A=function(g,h){h=h||[];if(i.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var k=0,l=g.length;k<l;k++)h.push(g[k]);else for(k=0;g[k];k++)h.push(g[k]);return h}}var C;if(r.documentElement.compareDocumentPosition)C=function(g,h){if(!g.compareDocumentPosition||!h.compareDocumentPosition){if(g==h)j=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g=== +h?0:1;if(g===0)j=true;return g};else if("sourceIndex"in r.documentElement)C=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)j=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)j=true;return g};else if(r.createRange)C=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)j=true;return g.ownerDocument?-1:1}var k=g.ownerDocument.createRange(),l=h.ownerDocument.createRange();k.setStart(g,0);k.setEnd(g,0);l.setStart(h,0);l.setEnd(h,0);g=k.compareBoundaryPoints(Range.START_TO_END, +l);if(g===0)j=true;return g};(function(){var g=r.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var k=r.documentElement;k.insertBefore(g,k.firstChild);if(r.getElementById(h)){m.find.ID=function(l,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(l[1]))?q.id===l[1]||typeof q.getAttributeNode!=="undefined"&&q.getAttributeNode("id").nodeValue===l[1]?[q]:v:[]};m.filter.ID=function(l,q){var p=typeof l.getAttributeNode!=="undefined"&&l.getAttributeNode("id"); +return l.nodeType===1&&p&&p.nodeValue===q}}k.removeChild(g);k=g=null})();(function(){var g=r.createElement("div");g.appendChild(r.createComment(""));if(g.getElementsByTagName("*").length>0)m.find.TAG=function(h,k){k=k.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var l=0;k[l];l++)k[l].nodeType===1&&h.push(k[l]);k=h}return k};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")m.attrHandle.href=function(h){return h.getAttribute("href", +2)};g=null})();r.querySelectorAll&&function(){var g=o,h=r.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){o=function(l,q,p,u){q=q||r;if(!u&&q.nodeType===9&&!w(q))try{return A(q.querySelectorAll(l),p)}catch(t){}return g(l,q,p,u)};for(var k in g)o[k]=g[k];h=null}}();(function(){var g=r.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length=== +0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){m.order.splice(1,0,"CLASS");m.find.CLASS=function(h,k,l){if(typeof k.getElementsByClassName!=="undefined"&&!l)return k.getElementsByClassName(h[1])};g=null}}})();var E=r.compareDocumentPosition?function(g,h){return g.compareDocumentPosition(h)&16}:function(g,h){return g!==h&&(g.contains?g.contains(h):true)},w=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},fa=function(g,h){var k=[], +l="",q;for(h=h.nodeType?[h]:h;q=m.match.PSEUDO.exec(g);){l+=q[0];g=g.replace(m.match.PSEUDO,"")}g=m.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)o(g,h[q],k);return o.filter(l,k)};c.find=o;c.expr=o.selectors;c.expr[":"]=c.expr.filters;c.unique=o.uniqueSort;c.getText=a;c.isXMLDoc=w;c.contains=E})();var bb=/Until$/,cb=/^(?:parents|prevUntil|prevAll)/,db=/,/;Q=Array.prototype.slice;var Ea=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,i){return!!b.call(e,i,e)===d});else if(b.nodeType)return c.grep(a, +function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Qa.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;c.find(a,this[f],b);if(f>0)for(var i=d;i<b.length;i++)for(var j=0;j<d;j++)if(b[j]===b[i]){b.splice(i--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d= +0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ea(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ea(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,i={},j;if(f&&a.length){e=0;for(var n=a.length;e<n;e++){j=a[e];i[j]||(i[j]=c.expr.match.POS.test(j)?c(j,b||this.context):j)}for(;f&&f.ownerDocument&&f!==b;){for(j in i){e=i[j];if(e.jquery?e.index(f)> +-1:c(f).is(e)){d.push({selector:j,elem:f});delete i[j]}}f=f.parentNode}}return d}var o=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(m,s){for(;s&&s.ownerDocument&&s!==b;){if(o?o.index(s)>-1:c(s).is(a))return s;s=s.parentNode}return null})},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(), +a);return this.pushStack(pa(a[0])||pa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")}, +nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);bb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e): +e;if((this.length>1||db.test(f))&&cb.test(a))e=e.reverse();return this.pushStack(e,a,Q.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===v||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!== +b&&d.push(a);return d}});var Fa=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ga=/(<([\w:]+)[^>]*?)\/>/g,eb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,Ha=/<([\w:]+)/,fb=/<tbody/i,gb=/<|&\w+;/,sa=/checked\s*(?:[^=]|=\s*.checked.)/i,Ia=function(a,b,d){return eb.test(d)?a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"], +col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==v)return this.empty().append((this[0]&&this[0].ownerDocument||r).createTextNode(a));return c.getText(this)}, +wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length? +d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments, +false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&& +!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Fa,"").replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){qa(this,b);qa(this.find("*"),b.find("*"))}return b},html:function(a){if(a===v)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Fa,""):null;else if(typeof a==="string"&&!/<script/i.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(Ha.exec(a)|| +["",""])[1].toLowerCase()]){a=a.replace(Ga,Ia);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var i=c(this),j=i.html();i.empty().append(function(){return a.call(this,e,j)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this, +b,f))});else a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(s){return c.nodeName(s,"table")?s.getElementsByTagName("tbody")[0]||s.appendChild(s.ownerDocument.createElement("tbody")):s}var e,i,j=a[0],n=[];if(!c.support.checkClone&&arguments.length===3&&typeof j=== +"string"&&sa.test(j))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(j))return this.each(function(s){var x=c(this);a[0]=j.call(this,s,b?x.html():v);x.domManip(a,b,d)});if(this[0]){e=a[0]&&a[0].parentNode&&a[0].parentNode.nodeType===11?{fragment:a[0].parentNode}:ra(a,this,n);if(i=e.fragment.firstChild){b=b&&c.nodeName(i,"tr");for(var o=0,m=this.length;o<m;o++)d.call(b?f(this[o],i):this[o],e.cacheable||this.length>1||o>0?e.fragment.cloneNode(true):e.fragment)}n&&c.each(n, +Ma)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);for(var e=0,i=d.length;e<i;e++){var j=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),j);f=f.concat(j)}return this.pushStack(f,a,d.selector)}});c.each({remove:function(a,b){if(!a||c.filter(a,[this]).length){if(!b&&this.nodeType===1){c.cleanData(this.getElementsByTagName("*"));c.cleanData([this])}this.parentNode&& +this.parentNode.removeChild(this)}},empty:function(){for(this.nodeType===1&&c.cleanData(this.getElementsByTagName("*"));this.firstChild;)this.removeChild(this.firstChild)}},function(a,b){c.fn[a]=function(){return this.each(b,arguments)}});c.extend({clean:function(a,b,d,f){b=b||r;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||r;var e=[];c.each(a,function(i,j){if(typeof j==="number")j+="";if(j){if(typeof j==="string"&&!gb.test(j))j=b.createTextNode(j);else if(typeof j=== +"string"){j=j.replace(Ga,Ia);var n=(Ha.exec(j)||["",""])[1].toLowerCase(),o=F[n]||F._default,m=o[0];i=b.createElement("div");for(i.innerHTML=o[1]+j+o[2];m--;)i=i.lastChild;if(!c.support.tbody){m=fb.test(j);n=n==="table"&&!m?i.firstChild&&i.firstChild.childNodes:o[1]==="<table>"&&!m?i.childNodes:[];for(o=n.length-1;o>=0;--o)c.nodeName(n[o],"tbody")&&!n[o].childNodes.length&&n[o].parentNode.removeChild(n[o])}!c.support.leadingWhitespace&&V.test(j)&&i.insertBefore(b.createTextNode(V.exec(j)[0]),i.firstChild); +j=c.makeArray(i.childNodes)}if(j.nodeType)e.push(j);else e=c.merge(e,j)}});if(d)for(a=0;e[a];a++)if(f&&c.nodeName(e[a],"script")&&(!e[a].type||e[a].type.toLowerCase()==="text/javascript"))f.push(e[a].parentNode?e[a].parentNode.removeChild(e[a]):e[a]);else{e[a].nodeType===1&&e.splice.apply(e,[a+1,0].concat(c.makeArray(e[a].getElementsByTagName("script"))));d.appendChild(e[a])}return e},cleanData:function(a){for(var b=0,d;(d=a[b])!=null;b++){c.event.remove(d);c.removeData(d)}}});var hb=/z-?index|font-?weight|opacity|zoom|line-?height/i, +Ja=/alpha\([^)]*\)/,Ka=/opacity=([^)]*)/,ga=/float/i,ha=/-([a-z])/ig,ib=/([A-Z])/g,jb=/^-?\d+(?:px)?$/i,kb=/^-?\d/,lb={position:"absolute",visibility:"hidden",display:"block"},mb=["Left","Right"],nb=["Top","Bottom"],ob=r.defaultView&&r.defaultView.getComputedStyle,La=c.support.cssFloat?"cssFloat":"styleFloat",ia=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===v)return c.curCSS(d,f);if(typeof e==="number"&&!hb.test(f))e+="px";c.style(d,f,e)})}; +c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return v;if((b==="width"||b==="height")&&parseFloat(d)<0)d=v;var f=a.style||a,e=d!==v;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=Ja.test(a)?a.replace(Ja,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Ka.exec(f.filter)[1])/100+"":""}if(ga.test(b))b=La;b=b.replace(ha,ia);if(e)f[b]=d;return f[b]},css:function(a, +b,d,f){if(b==="width"||b==="height"){var e,i=b==="width"?mb:nb;function j(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(i,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,"border"+this+"Width",true))||0})}a.offsetWidth!==0?j():c.swap(a,lb,j);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&& +a.currentStyle){f=Ka.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ga.test(b))b=La;if(!d&&e&&e[b])f=e[b];else if(ob){if(ga.test(b))b="float";b=b.replace(ib,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ha,ia);f=a.currentStyle[b]||a.currentStyle[d];if(!jb.test(f)&&kb.test(f)){b=e.left;var i=a.runtimeStyle.left;a.runtimeStyle.left= +a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=i}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var pb= +J(),qb=/<script(.|\s)*?\/script>/gi,rb=/select|textarea/i,sb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ja=/\?/,tb=/(\?|&)_=.*?(&|$)/,ub=/^(\w+:)?\/\/([^\/?#]+)/,vb=/%20/g;c.fn.extend({_load:c.fn.load,load:function(a,b,d){if(typeof a!=="string")return this._load(a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b= +c.param(b,c.ajaxSettings.traditional);f="POST"}var i=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(j,n){if(n==="success"||n==="notmodified")i.html(e?c("<div />").append(j.responseText.replace(qb,"")).find(e):j.responseText);d&&i.each(d,[j.responseText,n,j])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&& +(this.checked||rb.test(this.nodeName)||sb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a, +b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:z.XMLHttpRequest&&(z.location.protocol!=="file:"||!z.ActiveXObject)?function(){return new z.XMLHttpRequest}: +function(){try{return new z.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&e.success.call(o,n,j,w);e.global&&f("ajaxSuccess",[w,e])}function d(){e.complete&&e.complete.call(o,w,j);e.global&&f("ajaxComplete",[w,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")} +function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),i,j,n,o=a&&a.context||e,m=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(m==="GET")N.test(e.url)||(e.url+=(ja.test(e.url)?"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)|| +N.test(e.url))){i=e.jsonpCallback||"jsonp"+pb++;if(e.data)e.data=(e.data+"").replace(N,"="+i+"$1");e.url=e.url.replace(N,"="+i+"$1");e.dataType="script";z[i]=z[i]||function(q){n=q;b();d();z[i]=v;try{delete z[i]}catch(p){}A&&A.removeChild(B)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===false&&m==="GET"){var s=J(),x=e.url.replace(tb,"$1_="+s+"$2");e.url=x+(x===e.url?(ja.test(e.url)?"&":"?")+"_="+s:"")}if(e.data&&m==="GET")e.url+=(ja.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&& +c.event.trigger("ajaxStart");s=(s=ub.exec(e.url))&&(s[1]&&s[1]!==location.protocol||s[2]!==location.host);if(e.dataType==="script"&&m==="GET"&&s){var A=r.getElementsByTagName("head")[0]||r.documentElement,B=r.createElement("script");B.src=e.url;if(e.scriptCharset)B.charset=e.scriptCharset;if(!i){var C=false;B.onload=B.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;b();d();B.onload=B.onreadystatechange=null;A&&B.parentNode&& +A.removeChild(B)}}}A.insertBefore(B,A.firstChild);return v}var E=false,w=e.xhr();if(w){e.username?w.open(m,e.url,e.async,e.username,e.password):w.open(m,e.url,e.async);try{if(e.data||a&&a.contentType)w.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[e.url]);c.etag[e.url]&&w.setRequestHeader("If-None-Match",c.etag[e.url])}s||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept", +e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(fa){}if(e.beforeSend&&e.beforeSend.call(o,w,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");w.abort();return false}e.global&&f("ajaxSend",[w,e]);var g=w.onreadystatechange=function(q){if(!w||w.readyState===0||q==="abort"){E||d();E=true;if(w)w.onreadystatechange=c.noop}else if(!E&&w&&(w.readyState===4||q==="timeout")){E=true;w.onreadystatechange=c.noop;j=q==="timeout"?"timeout":!c.httpSuccess(w)? +"error":e.ifModified&&c.httpNotModified(w,e.url)?"notmodified":"success";var p;if(j==="success")try{n=c.httpData(w,e.dataType,e)}catch(u){j="parsererror";p=u}if(j==="success"||j==="notmodified")i||b();else c.handleError(e,w,j,p);d();q==="timeout"&&w.abort();if(e.async)w=null}};try{var h=w.abort;w.abort=function(){w&&h.call(w);g("abort")}}catch(k){}e.async&&e.timeout>0&&setTimeout(function(){w&&!E&&g("timeout")},e.timeout);try{w.send(m==="POST"||m==="PUT"||m==="DELETE"?e.data:null)}catch(l){c.handleError(e, +w,null,l);d()}e.async||g();return w}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]= +f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(j,n){if(c.isArray(n))c.each(n, +function(o,m){b?f(j,m):d(j+"["+(typeof m==="object"||c.isArray(m)?o:"")+"]",m)});else!b&&n!=null&&typeof n==="object"?c.each(n,function(o,m){d(j+"["+o+"]",m)}):f(j,n)}function f(j,n){n=c.isFunction(n)?n():n;e[e.length]=encodeURIComponent(j)+"="+encodeURIComponent(n)}var e=[];if(b===v)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var i in a)d(i,a[i]);return e.join("&").replace(vb,"+")}});var ka={},wb=/toggle|show|hide/,xb=/^([+-]=)?([\d+-.]+)(.*)$/, +W,ta=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(ka[d])f=ka[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove(); +ka[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&& +c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var i=c.extend({},e),j,n=this.nodeType===1&&c(this).is(":hidden"), +o=this;for(j in a){var m=j.replace(ha,ia);if(j!==m){a[m]=a[j];delete a[j];j=m}if(a[j]==="hide"&&n||a[j]==="show"&&!n)return i.complete.call(this);if((j==="height"||j==="width")&&this.style){i.display=c.css(this,"display");i.overflow=this.style.overflow}if(c.isArray(a[j])){(i.specialEasing=i.specialEasing||{})[j]=a[j][1];a[j]=a[j][0]}}if(i.overflow!=null)this.style.overflow="hidden";i.curAnim=c.extend({},a);c.each(a,function(s,x){var A=new c.fx(o,i,s);if(wb.test(x))A[x==="toggle"?n?"show":"hide":x](a); +else{var B=xb.exec(x),C=A.cur(true)||0;if(B){x=parseFloat(B[2]);var E=B[3]||"px";if(E!=="px"){o.style[s]=(x||1)+E;C=(x||1)/A.cur(true)*C;o.style[s]=C+E}if(B[1])x=(B[1]==="-="?-1:1)*x+C;A.custom(C,x,E)}else A.custom(C,x,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle", +1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration==="number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a, +b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]== +null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(i){return e.step(i)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop=== +"width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow= +this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos= +c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!= +null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in r.documentElement?function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(), +f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(s){c.offset.setOffset(this,a,s)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f= +b,e=b.ownerDocument,i,j=e.documentElement,n=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var o=b.offsetTop,m=b.offsetLeft;(b=b.parentNode)&&b!==n&&b!==j;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;i=e?e.getComputedStyle(b,null):b.currentStyle;o-=b.scrollTop;m-=b.scrollLeft;if(b===d){o+=b.offsetTop;m+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){o+=parseFloat(i.borderTopWidth)|| +0;m+=parseFloat(i.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&i.overflow!=="visible"){o+=parseFloat(i.borderTopWidth)||0;m+=parseFloat(i.borderLeftWidth)||0}f=i}if(f.position==="relative"||f.position==="static"){o+=n.offsetTop;m+=n.offsetLeft}if(c.offset.supportsFixedPosition&&f.position==="fixed"){o+=Math.max(j.scrollTop,n.scrollTop);m+=Math.max(j.scrollLeft,n.scrollLeft)}return{top:o,left:m}};c.offset={initialize:function(){var a=r.body,b=r.createElement("div"), +d,f,e,i=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild); +d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i;a.removeChild(b);c.offset.initialize=c.noop}, +bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),i=parseInt(c.curCSS(a,"top",true),10)||0,j=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,d,e);d={top:b.top-e.top+i,left:b.left- +e.left+j};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a= +this.offsetParent||r.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],i;if(!e)return null;if(f!==v)return this.each(function(){if(i=ua(this))i.scrollTo(!a?f:c(i).scrollLeft(),a?f:c(i).scrollTop());else this[d]=f});else return(i=ua(e))?"pageXOffset"in i?i[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&i.document.documentElement[d]||i.document.body[d]:e[d]}}); +c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(i){var j=c(this);j[d](f.call(this,i,j[d]()))});return"scrollTo"in e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]|| +e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===v?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});z.jQuery=z.$=c})(window); diff --git a/tools/qdoc3/test/style/style.css b/tools/qdoc3/test/style/style.css new file mode 100644 index 0000000..9c290f5 --- /dev/null +++ b/tools/qdoc3/test/style/style.css @@ -0,0 +1,1049 @@ +@media screen +{ + html + { + color: #000000; + background: #FFFFFF; + } + body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, button, textarea, p, blockquote, th, td + { + margin: 0; + padding: 0; + } + table + { + border-collapse: collapse; + border-spacing: 0; + } + fieldset, img + { + border: 0; + } + address, caption, cite, code, dfn, em, strong, th, var, optgroup + { + font-style: inherit; + font-weight: inherit; + } + del, ins + { + text-decoration: none; + } + li + { + list-style: none; + } + caption, th + { + text-align: left; + } + h1, h2, h3, h4, h5, h6 + { + font-size: 100%; + font-weight: normal; + } + q:before, q:after + { + content: ''; + } + abbr, acronym + { + border: 0; + font-variant: normal; + } + sup + { + vertical-align: baseline; + } + sub + { + vertical-align: baseline; + } + .heading + { + font: normal 600 16px/1.0 Arial; + padding-bottom: 15px; + } + .subtitle + { + font-size: 13px; + } + .small-subtitle + { + font-size: 13px; + } + legend + { + color: #000000; + } + input, button, textarea, select, optgroup, option + { + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; + } + input, button, textarea, select + { + font-size: 100%; + } + html + { + background-color: #e5e5e5; + } + body + { + background: #e6e7e8 url(../images/page_bg.png) repeat-x 0 0; + font: normal 13px/1.2 Verdana; + color: #363534; + } + strong + { + font-weight: bold; + } + em + { + font-style: italic; + } + a + { + color: #00732f; + text-decoration: none; + } + .header, .footer, .wrapper + { + min-width: 600px; + max-width: 1500px; + margin: 0 30px; + } + .wrapper + { + background: url(../images/bg_r.png) repeat-y 100% 0; + } + .wrapper .hd + { + padding-left: 216px; + height: 15px; + background: url(../images/page.png) no-repeat 0 0; + overflow: hidden; + } + .offline .wrapper .hd + { + background: url(../images/page.png) no-repeat 0 -15px; + } + .wrapper .hd span + { + height: 15px; + display: block; + overflow: hidden; + background: url(../images/page.png) no-repeat 100% -30px; + } + .wrapper .bd + { + background: url(../images/bg_l.png) repeat-y 0 0; + position: relative; + } + .offline .wrapper .bd + { + background: url(../images/bg_l_blank.png) repeat-y 0 0; + } + .wrapper .ft + { + padding-left: 216px; + height: 15px; + background: url(../images/page.png) no-repeat 0 -75px; + overflow: hidden; + } + .offline .wrapper .ft + { + background: url(../images/page.png) no-repeat 0 -90px; + } + .wrapper .ft span + { + height: 15px; + display: block; + background: url(../images/page.png) no-repeat 100% -60px; + overflow: hidden; + } + .header, .footer + { + display: block; + clear: both; + overflow: hidden; + } + .header + { + height: 115px; + position: relative; + } + .header .icon + { + position: absolute; + top: 13px; + left: 0; + } + .header .qtref + { + position: absolute; + top: 28px; + left: 88px; + width: 302px; + height: 22px; + } + .header .qtref span + { + display: block; + width: 302px; + height: 22px; + text-indent: -999em; + background: url(../images/sprites-combined.png) no-repeat -78px -235px; + } + + .sidebar + { + float: left; + margin-left: 5px; + width: 200px; + font-size: 11px; + } + + .offline .sidebar, .offline .feedback, .offline .t_button + { + display: none; + } + + .sidebar .searchlabel + { + padding: 0 0 2px 17px; + font: normal bold 11px/1.2 Verdana; + } + + .sidebar .search + { + padding: 0 15px 0 16px; + } + + .sidebar .search form + { + background: url(../images/sprites-combined.png) no-repeat -6px -348px; + height:21px; + padding:2px 0 0 5px; + width:167px; + } + + .sidebar .search form input#pageType + { + width: 158px; + height: 19px; + padding: 0; + border: none; + outline: none; + font: 13px/1.2 Verdana; + } + + .sidebar .box + { + padding: 17px 15px 5px 16px; + } + + .sidebar .box .first + { + background-image: none; + } + + .sidebar .box h2 + { + font: normal 18px/1.2 Arial; + padding: 0; + min-height: 32px; + } + .sidebar .box h2 span + { + overflow: hidden; + display: inline-block; + } + .sidebar .box#lookup h2 + { + background-image: none; + } + .sidebar #lookup.box h2 span + { + background: url(../images/sprites-combined.png) no-repeat -6px -311px; + width: 27px; + height: 35px; + margin-right: 13px; + } + .sidebar .box#topics h2 + { + background-image: none; + } + .sidebar #topics.box h2 span + { + background: url(../images/sprites-combined.png) no-repeat -94px -311px; + width: 27px; + height: 32px; + margin-right: 13px; + } + .sidebar .box#examples h2 + { + background-image: none; + } + .sidebar #examples.box h2 span + { + background: url(../images/sprites-combined.png) no-repeat -48px -311px; + width: 30px; + height: 31px; + margin-right: 9px; + } + + .sidebar .box .list + { + display: block; + } + .sidebar .box .live + { + display: none; + height: 100px; + overflow: auto; + } + .list li a:hover, .live li a:hover + { + text-decoration: underline; + } + .sidebar .box ul + { + } + .sidebar .box ul li + { + padding-left: 12px; + background: url(../images/bullet_gt.png) no-repeat 0 5px; + margin-bottom: 15px; + } + .sidebar .bottombar + { + background: url(../images/box_bg.png) repeat-x 0 bottom; + } + .wrap + { + margin: 0 5px 0 208px; + overflow: visible; + } + .offline .wrap + { + margin: 0 5px 0 5px; + } + .wrap .toolbar + { + background-color: #fafafa; + border-bottom: 1px solid #d1d1d1; + height: 20px; + position: relative; + } + .wrap .toolbar .toolblock + { + position: absolute; + } + .wrap .toolbar .breadcrumb + { + font-size: 11px; + line-height: 1; + padding: 0 0 10px 21px; + height: 10px; + } + .wrap .toolbar .toolbuttons + { + padding: 0 0 10px 21px; + right: 5px; + vertical-align: middle; + overflow: hidden; + } + .wrap .toolbar .toolbuttons .active + { + color: #00732F; + } + .wrap .toolbar .toolbuttons ul + { + float: right; + } + .wrap .toolbar .toolbuttons li + { + float: left; + text-indent: -10px; + margin-top: -5px; + margin-right: 15px; + font-weight: bold; + color: #B0ADAB; + } + + .toolbuttons #print + { + border-left: 1px solid #c5c4c4; + margin-top: 0; + padding-left: 7px; + text-indent: 0; + } + .toolbuttons #print a + { + width: 16px; + height: 16px; + } + + .toolbuttons #print a span + { + width: 16px; + height: 16px; + text-indent: -999em; + display: block; + overflow: hidden; + background: url(../images/sprites-combined.png) no-repeat -137px -311px; + } + + .toolbuttons #smallA + { + font-size: 10pt; + } + .toolbuttons #medA + { + font-size: 12pt; + } + .toolbuttons #bigA + { + font-size: 14pt; + margin-right: 7px; + } + + #smallA:hover, #medA:hover, #bigA:hover + { + color: #00732F; + } + + .offline .wrap .breadcrumb + { + } + + .wrap .breadcrumb ul + { + } + .wrap .breadcrumb ul li + { + float: left; + background: url(../images/breadcrumb.png) no-repeat 0 3px; + padding-left: 15px; + margin-left: 15px; + font-weight: bold; + } + .wrap .breadcrumb ul li.last + { + font-weight: normal; + } + .wrap .breadcrumb ul li a + { + color: #363534; + } + .wrap .breadcrumb ul li.first + { + background-image: none; + padding-left: 0; + margin-left: 0; + } + .wrap .content + { + padding: 30px; + } + + .wrap .content li + { + padding-left: 12px; + background: url(../images/bullet_sq.png) no-repeat 0 5px; + font: normal 400 10pt/1 Verdana; + color: #44a51c; + margin-bottom: 10px; + } + .content li:hover + { + text-decoration: underline; + } + + .offline .wrap .content + { + padding-top: 15px; + } + + .wrap .content h1 + { + font: 600 18px/1.2 Arial; + } + .wrap .content h2 + { + font: 600 16px/1.2 Arial; + } + .wrap .content h3 + { + font: 600 14px/1.2 Arial; + } + .wrap .content p + { + line-height: 20px; + padding: 10px 5px 10px 5px; + } + .wrap .content ul + { + padding-left: 25px; + } + a:hover + { + color: #4c0033; + text-decoration: underline; + } + .content a:visited + { + color: #4c0033; + text-decoration: none; + } + .footer + { + min-height: 100px; + color: #797775; + font: normal 9px/1 Verdana; + text-align: center; + padding-top: 40px; + background-color: #E6E7E8; + margin: 0; + } + .feedback + { + float: none; + position: absolute; + right: 15px; + bottom: 10px; + font: normal 8px/1 Verdana; + color: #B0ADAB; + } + .feedback:hover + { + float: right; + font: normal 8px/1 Verdana; + color: #00732F; + text-decoration: underline; + } + .header:after, .footer:after, .breadcrumb:after, .wrap .content:after, .group:after + { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; + } + #nav-topright + { + height: 70px; + } + + #nav-topright ul + { + list-style-type: none; + float: right; + width: 370px; + margin-top: 11px; + } + + #nav-topright li + { + display: inline-block; + margin-right: 20px; + float: left; + } + + #nav-topright li.nav-topright-last + { + margin-right: 0; + } + + #nav-topright li a + { + background: transparent url(../images/sprites-combined.png) no-repeat; + height: 18px; + display: block; + overflow: hidden; + text-indent: -9999px; + } + + #nav-topright li.nav-topright-home a + { + width: 65px; + background-position: -2px -91px; + } + + #nav-topright li.nav-topright-home a:hover + { + background-position: -2px -117px; + } + + + #nav-topright li.nav-topright-dev a + { + width: 30px; + background-position: -76px -91px; + } + + #nav-topright li.nav-topright-dev a:hover + { + background-position: -76px -117px; + } + + + #nav-topright li.nav-topright-labs a + { + width: 40px; + background-position: -114px -91px; + } + + #nav-topright li.nav-topright-labs a:hover + { + background-position: -114px -117px; + } + + #nav-topright li.nav-topright-doc a + { + width: 32px; + background-position: -162px -91px; + } + + #nav-topright li.nav-topright-doc a:hover, #nav-topright li.nav-topright-doc-active a + { + background-position: -162px -117px; + } + + #nav-topright li.nav-topright-blog a + { + width: 40px; + background-position: -203px -91px; + } + + #nav-topright li.nav-topright-blog a:hover, #nav-topright li.nav-topright-blog-active a + { + background-position: -203px -117px; + } + + #nav-topright li.nav-topright-shop a + { + width: 40px; + background-position: -252px -91px; + } + + #nav-topright li.nav-topright-shop a:hover, #nav-topright li.nav-topright-shop-active a + { + background-position: -252px -117px; + } + + #nav-logo + { + background: transparent url(../images/sprites-combined.png ) no-repeat 0 -225px; + left: -3px; + position: absolute; + width: 75px; + height: 75px; + top: 13px; + } + #nav-logo a + { + width: 75px; + height: 75px; + display: block; + text-indent: -9999px; + overflow: hidden; + } + + + .shortCut-topleft-inactive + { + padding-left: 3px; + background: transparent url( ../images/sprites-combined.png) no-repeat 0px -58px; + height: 20px; + width: 47px; + } + .shortCut-topleft-inactive span + { + font-variant: normal; + } + #shortCut + { + padding-top: 10px; + font-weight: bolder; + color: #b0adab; + } + #shortCut ul + { + list-style-type: none; + float: left; + width: 347px; + margin-left: 100px; + } + #shortCut li + { + display: inline-block; + margin-right: 25px; + float: left; + white-space: nowrap; + } + #shortCut li a + { + color: #b0adab; + } + #shortCut li a:hover + { + color: #44a51c; + } + + hr + { + background-color: #E6E6E6; + border: 1px solid #E6E6E6; + height: 1px; + width: 100%; + text-align: left; + margin: 15px 0px 15px 0px; + } + + .content .alignedsummary + { + margin: 15px; + } + pre + { + border: 1px solid #DDDDDD; + margin: 0 20px 10px 10px; + padding: 20px 15px 20px 20px; + overflow-x: auto; + } + table, pre + { + -moz-border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border: 1px solid #E6E6E6; + border-collapse: separate; + font-size: 11px; + /*min-width: 395px;*/ + margin-bottom: 25px; + display: inline-block; + } + thead + { + margin-top: 5px; + } + th + { + padding: 3px 15px 3px 15px; + } + td + { + padding: 3px 15px 3px 20px; + } + table tr.odd + { + border-left: 1px solid #E6E6E6; + background-color: #F6F6F6; + color: #66666E; + } + table tr.even + { + border-left: 1px solid #E6E6E6; + background-color: #ffffff; + color: #66666E; + } + table tr.odd:hover + { + background-color: #E6E6E6; + } + table tr.even:hover + { + background-color: #E6E6E6; + } + + span.comment + { + color: #8B0000; + font-style: italic; + } + span.string, span.char + { + color: #254117; + } + + .qmltype + { + text-align: center; + font-size: 160%; + } + .qmlreadonly + { + float: right; + color: #254117; + } + + .qmldefault + { + float: right; + color: red; + } + + .qmldoc + { + } + + *.qmlitem p + { + } + + #feedbackBox + { + display: none; + -moz-border-radius: 7px 7px 7px 7px; + border: 1px solid #DDDDDD; + position: fixed; + top: 100px; + left: 33%; + height: 190px; + width: 400px; + padding: 5px; + background-color: #e6e7e8; + z-index: 4; + } + #feedcloseX a + { + display: inline; + padding: 5px 5px 0 0; + margin-bottom: 3px; + color: #363534; + font-weight: 600; + float: right; + text-decoration: none; + } + + #feedbox + { + display: inline; + width: 370px; + height: 120px; + margin: 0px 25px 10px 15px; + } + #feedsubmit + { + display: inline; + float: right; + margin: 4px 32px 0 0; + } + #blurpage + { + display: none; + position: fixed; + float: none; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + background: transparent url(../images/feedbackground.png) 0 0; + z-index: 3; + } + .toc + { + float: right; + -moz-border-radius: 7px 7px 7px 7px; + background-color: #F6F6F6; + border: 1px solid #DDDDDD; + margin: 0 20px 10px 10px; + padding: 20px 15px 20px 20px; + height: auto; + width: 200px; + } + + .toc h3 + { + font: 600 12px/1.2 Arial; + } + + .wrap .content .toc ul + { + padding-left: 0px; + } + + + .wrap .content .toc .level2 + { + margin-left: 15px; + } + + .content .toc li + { + font: normal 10px/1.2 Verdana; + background: url(../images/bullet_dn.png) no-repeat 0 5px; + } + + .relpage + { + -moz-border-radius: 7px 7px 7px 7px; + border: 1px solid #DDDDDD; + padding: 25px 25px; + clear: both; + } + .relpage ul + { + float: none; + padding: 15px; + } + .content .relpage li + { + font: normal 11px/1.2 Verdana; + } + h3.fn, span.fn + { + background-color: #F6F6F6; + border-width: 1px; + border-style: solid; + border-color: #E6E6E6; + font-weight: bold; + } + + + /* start index box */ + .indexbox + { + width: 100%; + display:inline-block; + } + + .indexboxcont + { + display: block; + /* overflow: hidden;*/ + } + + .indexboxbar + { + background: transparent url(../images/horBar.png ) repeat-x left bottom; + margin-bottom: 25px; + /* background-image: none; + border-bottom: 1px solid #e2e2e2;*/ + } + + .indexboxcont .section + { + display: inline-block; + width: 49%; + *width:42%; + _width:42%; + padding:0 2% 0 1%; + vertical-align:top; + +} + + .indexboxcont .indexIcon + { + width: 11%; + *width:18%; + _width:18%; + overflow:hidden; + +} + .indexboxcont .section p + { + padding-top: 20px; + padding-bottom: 20px; + } + .indexboxcont .sectionlist + { + display: inline-block; + width: 33%; + padding: 0; + } + .indexboxcont .sectionlist ul + { + margin-bottom: 20px; + } + + .indexboxcont .sectionlist ul li + { + line-height: 12px; + } + + .content .indexboxcont li + { + font: normal 600 13px/1 Verdana; + } + + .indexbox a:hover, .indexbox a:visited:hover + { + color: #4c0033; + text-decoration: underline; + } + + .indexbox a:visited + { + color: #00732f; + text-decoration: none; + } + + .indexboxcont:after + { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; + } + + .indexbox .indexIcon span + { + display: block; + } + + .indexbox.guide .indexIcon span + { + width: 96px; + height: 137px; + background: url(../images/sprites-combined.png) no-repeat -5px -376px; + padding: 0; + } + + .indexbox.tools .indexIcon span + { + width: 115px; + height: 137px; + background: url(../images/sprites-combined.png) no-repeat -111px -376px; + padding: 0; + } + + .lastcol + { + display: inline-block; + vertical-align: top; + padding: 0; + max-width: 25%; + } + + .tricol .lastcol + { + margin-left: -6px; + } + /* end indexbox */ +} +/* end of screen media */ + +/* start of print media */ + +@media print +{ + input, textarea, .header, .footer, .toolbar, .feedback, .wrapper .hd, .wrapper .bd .sidebar, .wrapper .ft + { + display: none; + background: none; + } + .content + { + position: absolute; + top: 0px; + left: 0px; + background: none; + display: block; + } +} +/* end of print media */ diff --git a/tools/qdoc3/test/style/style_ie6.css b/tools/qdoc3/test/style/style_ie6.css new file mode 100644 index 0000000..16fb850 --- /dev/null +++ b/tools/qdoc3/test/style/style_ie6.css @@ -0,0 +1,54 @@ +.indexbox, .indexboxcont, .group { + zoom: 1; + height: 1%; +} + +.sidebar { + margin-left: 3px; + width: 199px; + overflow: hidden; +} + +.sidebar .search form { + position: relative; +} + +.sidebar .search form fieldset { + position: absolute; + margin-top: -1px; +} + +.sidebar .search form input#searchstring { + border: 1px solid #fff; + height: 18px; +} + +.wrap { + zoom: 1; +} + +.content, +.toolbar { + zoom: 1; + margin-left: -3px; + position: relative; +} + +.indexbox { + clear: both; +} + +.indexboxcont .section { + zoom: 1; + float: left; +} + +.indexboxcont .sectionlist { + zoom: 1; + float: left; +} + +.wrap .toolbar .toolbuttons li { + text-indent: 0; + margin-right: 8px; +}
\ No newline at end of file diff --git a/tools/qdoc3/test/style/style_ie7.css b/tools/qdoc3/test/style/style_ie7.css new file mode 100644 index 0000000..afbff5f --- /dev/null +++ b/tools/qdoc3/test/style/style_ie7.css @@ -0,0 +1,19 @@ +.indexbox, .indexboxcont, .group { + min-height: 1px; +} + +.sidebar .search form input#searchstring { + border: 1px solid #fff; + height: 17px; +} + + +.indexboxcont .section { + zoom: 1; + float: left; +} + +.indexboxcont .sectionlist { + zoom: 1; + float: left; +} diff --git a/tools/qdoc3/test/style/style_ie8.css b/tools/qdoc3/test/style/style_ie8.css new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tools/qdoc3/test/style/style_ie8.css diff --git a/tools/qdoc3/text.h b/tools/qdoc3/text.h index fa3ecda..879f6da 100644 --- a/tools/qdoc3/text.h +++ b/tools/qdoc3/text.h @@ -75,6 +75,7 @@ class Text const Atom *lastAtom() const { return last; } Text subText(Atom::Type left, Atom::Type right, const Atom *from = 0) const; void dump() const; + void clear(); static Text subText(const Atom *begin, const Atom *end = 0); static Text sectionHeading(const Atom *sectionBegin); @@ -82,7 +83,6 @@ class Text static int compare(const Text &text1, const Text &text2); private: - void clear(); Atom *first; Atom *last; diff --git a/tools/qdoc3/tokenizer.cpp b/tools/qdoc3/tokenizer.cpp index b391759..7c10de6 100644 --- a/tools/qdoc3/tokenizer.cpp +++ b/tools/qdoc3/tokenizer.cpp @@ -47,6 +47,7 @@ #include <qhash.h> #include <qregexp.h> #include <qstring.h> +#include <qtextcodec.h> #include <ctype.h> #include <string.h> @@ -97,6 +98,8 @@ static QRegExp *definedX = 0; static QRegExp *defines = 0; static QRegExp *falsehoods = 0; +static QTextCodec *sourceCodec = 0; + /* This function is a perfect hash function for the 37 keywords of C99 (with a hash table size of 512). It should perform well on our @@ -118,13 +121,10 @@ static void insertKwordIntoHash(const char *s, int number) kwordHashTable[k] = number; } -Tokenizer::Tokenizer(const Location& loc, FILE *in) +Tokenizer::Tokenizer(const Location& loc, QFile &in) { init(); - QFile file; - file.open(in, QIODevice::ReadOnly); - yyIn = file.readAll(); - file.close(); + yyIn = in.readAll(); yyPos = 0; start(loc); } @@ -483,6 +483,11 @@ void Tokenizer::initialize(const Config &config) { QString versionSym = config.getString(CONFIG_VERSIONSYM); + QString sourceEncoding = config.getString(CONFIG_SOURCEENCODING); + if (sourceEncoding.isEmpty()) + sourceEncoding = QLatin1String("ISO-8859-1"); + sourceCodec = QTextCodec::codecForName(sourceEncoding.toLocal8Bit()); + comment = new QRegExp("/(?:\\*.*\\*/|/.*\n|/[^\n]*$)"); comment->setMinimal(true); versionX = new QRegExp("$cannot possibly match^"); @@ -750,4 +755,14 @@ bool Tokenizer::isTrue(const QString &condition) return !falsehoods->exactMatch(t); } +QString Tokenizer::lexeme() const +{ + return sourceCodec->toUnicode(yyLex); +} + +QString Tokenizer::previousLexeme() const +{ + return sourceCodec->toUnicode(yyPrevLex); +} + QT_END_NAMESPACE diff --git a/tools/qdoc3/tokenizer.h b/tools/qdoc3/tokenizer.h index 519cffb..f55d2ef 100644 --- a/tools/qdoc3/tokenizer.h +++ b/tools/qdoc3/tokenizer.h @@ -46,11 +46,10 @@ #ifndef TOKENIZER_H #define TOKENIZER_H +#include <qfile.h> #include <qstack.h> #include <qstring.h> -#include <stdio.h> - #include "location.h" QT_BEGIN_NAMESPACE @@ -99,7 +98,7 @@ class Tokenizer { public: Tokenizer(const Location& loc, const QByteArray &in); - Tokenizer(const Location& loc, FILE *in); + Tokenizer(const Location& loc, QFile &file); ~Tokenizer(); @@ -108,8 +107,8 @@ class Tokenizer bool parsingFnOrMacro() const { return parsingMacro; } const Location &location() const { return yyTokLoc; } - QString previousLexeme() const { return QString(yyPrevLex); } - QString lexeme() const { return QString(yyLex); } + QString previousLexeme() const; + QString lexeme() const; QString version() const { return yyVersion; } int braceDepth() const { return yyBraceDepth; } int parenDepth() const { return yyParenDepth; } diff --git a/tools/qdoc3/tree.cpp b/tools/qdoc3/tree.cpp index d46da95..31bbf54 100644 --- a/tools/qdoc3/tree.cpp +++ b/tools/qdoc3/tree.cpp @@ -43,7 +43,6 @@ tree.cpp */ -#include <QtCore> #include <QDomDocument> #include "atom.h" @@ -54,6 +53,9 @@ #include "text.h" #include "tree.h" +#include <limits.h> +#include <qdebug.h> + QT_BEGIN_NAMESPACE struct InheritanceBound @@ -149,6 +151,7 @@ const Node *Tree::findNode(const QStringList &path, const Node *next = static_cast<const InnerNode*>(node)->findNode(path.at(i)); + if (!next && (findFlags & SearchEnumValues) && i == path.size()-1) next = static_cast<const InnerNode*>(node)->findEnumNodeForValue(path.at(i)); @@ -1118,6 +1121,15 @@ bool Tree::generateIndexSection(QXmlStreamWriter &writer, case Node::Target: nodeName = "target"; break; + case Node::QmlProperty: + nodeName = "qmlproperty"; + break; + case Node::QmlSignal: + nodeName = "qmlsignal"; + break; + case Node::QmlMethod: + nodeName = "qmlmethod"; + break; default: return false; } @@ -1207,7 +1219,7 @@ bool Tree::generateIndexSection(QXmlStreamWriter &writer, if (fullName != objName) writer.writeAttribute("fullname", fullName); writer.writeAttribute("href", fullDocumentLocation(node)); - if (node->type() != Node::Fake) + if ((node->type() != Node::Fake) && (!node->isQmlNode())) writer.writeAttribute("location", node->location().fileName()); switch (node->type()) { @@ -1262,6 +1274,12 @@ bool Tree::generateIndexSection(QXmlStreamWriter &writer, case Node::ExternalPage: writer.writeAttribute("subtype", "externalpage"); break; + case Node::QmlClass: + writer.writeAttribute("subtype", "qmlclass"); + break; + case Node::QmlBasicType: + writer.writeAttribute("subtype", "qmlbasictype"); + break; default: break; } @@ -1334,6 +1352,12 @@ bool Tree::generateIndexSection(QXmlStreamWriter &writer, } break; + case Node::QmlProperty: + { + const QmlPropertyNode *qpn = static_cast<const QmlPropertyNode*>(node); + writer.writeAttribute("type", qpn->dataType()); + } + break; case Node::Property: { const PropertyNode *propertyNode = static_cast<const PropertyNode*>(node); @@ -1521,9 +1545,22 @@ void Tree::generateIndexSections(QXmlStreamWriter &writer, if (node->isInnerNode()) { const InnerNode *inner = static_cast<const InnerNode *>(node); - // Recurse to write an element for this child node and all its children. - foreach (const Node *child, inner->childNodes()) - generateIndexSections(writer, child, generateInternalNodes); + foreach (const Node *child, inner->childNodes()) { + /* + Don't generate anything for a QML property group node. + It is just a place holder for a collection of QML property + nodes. Recurse to its children, which are the QML property + nodes. + */ + if (child->subType() == Node::QmlPropertyGroup) { + const InnerNode *pgn = static_cast<const InnerNode*>(child); + foreach (const Node *c, pgn->childNodes()) { + generateIndexSections(writer, c, generateInternalNodes); + } + } + else + generateIndexSections(writer, child, generateInternalNodes); + } /* foreach (const Node *child, inner->relatedNodes()) { @@ -1914,7 +1951,8 @@ QString Tree::fullDocumentLocation(const Node *node) const } else if (node->type() == Node::Fake) { #ifdef QDOC_QML - if (node->subType() == Node::QmlClass) + if ((node->subType() == Node::QmlClass) || + (node->subType() == Node::QmlBasicType)) return "qml-" + node->fileBase() + ".html"; else #endif @@ -1927,9 +1965,23 @@ QString Tree::fullDocumentLocation(const Node *node) const if ((parentNode = node->relates())) parentName = fullDocumentLocation(node->relates()); - else if ((parentNode = node->parent())) - parentName = fullDocumentLocation(node->parent()); - + else if ((parentNode = node->parent())) { + if (parentNode->subType() == Node::QmlPropertyGroup) { + parentNode = parentNode->parent(); + parentName = "qml-" + parentNode->fileBase() + ".html"; + } + else + parentName = fullDocumentLocation(node->parent()); + } +#if 0 + if (node->type() == Node::QmlProperty) { + qDebug() << "Node::QmlProperty:" << node->name() + << "parentName:" << parentName; + if (parentNode) + qDebug() << "PARENT NODE" << parentNode->type() + << parentNode->subType() << parentNode->name(); + } +#endif switch (node->type()) { case Node::Class: case Node::Namespace: @@ -1976,6 +2028,15 @@ QString Tree::fullDocumentLocation(const Node *node) const case Node::Property: anchorRef = "#" + node->name() + "-prop"; break; + case Node::QmlProperty: + anchorRef = "#" + node->name() + "-prop"; + break; + case Node::QmlSignal: + anchorRef = "#" + node->name() + "-signal"; + break; + case Node::QmlMethod: + anchorRef = "#" + node->name() + "-method"; + break; case Node::Variable: anchorRef = "#" + node->name() + "-var"; break; @@ -2015,6 +2076,8 @@ QString Tree::fullDocumentLocation(const Node *node) const } /*! + Construct the full document name for \a node and return the + name. */ QString Tree::fullDocumentName(const Node *node) const { @@ -2025,10 +2088,11 @@ QString Tree::fullDocumentName(const Node *node) const const Node *n = node; do { - if (!n->name().isEmpty()) + if (!n->name().isEmpty() && + ((n->type() != Node::Fake) || (n->subType() != Node::QmlPropertyGroup))) pieces.insert(0, n->name()); - if (n->type() == Node::Fake) + if ((n->type() == Node::Fake) && (n->subType() != Node::QmlPropertyGroup)) break; // Examine the parent node if one exists. diff --git a/tools/qdoc3/webxmlgenerator.cpp b/tools/qdoc3/webxmlgenerator.cpp index a3c92ce..6020b1b 100644 --- a/tools/qdoc3/webxmlgenerator.cpp +++ b/tools/qdoc3/webxmlgenerator.cpp @@ -43,8 +43,6 @@ webxmlgenerator.cpp */ -#include <QtXml> - #include "codemarker.h" #include "pagegenerator.h" #include "webxmlgenerator.h" @@ -52,6 +50,8 @@ #include "separator.h" #include "tree.h" +#include <QtCore/qxmlstream.h> + QT_BEGIN_NAMESPACE #define COMMAND_VERSION Doc::alias("version") @@ -90,7 +90,7 @@ QString WebXMLGenerator::format() return "WebXML"; } -QString WebXMLGenerator::fileExtension(const Node * /* node */) +QString WebXMLGenerator::fileExtension(const Node * /* node */) const { return "xml"; } diff --git a/tools/qdoc3/webxmlgenerator.h b/tools/qdoc3/webxmlgenerator.h index 3145d50..071896a 100644 --- a/tools/qdoc3/webxmlgenerator.h +++ b/tools/qdoc3/webxmlgenerator.h @@ -46,12 +46,17 @@ #ifndef WEBXMLGENERATOR_H #define WEBXMLGENERATOR_H +#include <QtCore/qxmlstream.h> + #include "codemarker.h" #include "config.h" #include "pagegenerator.h" QT_BEGIN_NAMESPACE +class QXmlStreamReader; +class QXmlStreamWriter; + class WebXMLGenerator : public PageGenerator { public: @@ -69,7 +74,7 @@ protected: const Node *relative, CodeMarker *marker ); virtual void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker); virtual void generateFakeNode(const FakeNode *fake, CodeMarker *marker); - virtual QString fileExtension(const Node *node); + virtual QString fileExtension(const Node *node) const; virtual const Atom *addAtomElements(QXmlStreamWriter &writer, const Atom *atom, const Node *relative, CodeMarker *marker); diff --git a/tools/qev/qev.pro b/tools/qev/qev.pro index 28383c6..962b9fa 100644 --- a/tools/qev/qev.pro +++ b/tools/qev/qev.pro @@ -9,5 +9,3 @@ INCLUDEPATH += . # Input SOURCES += qev.cpp CONFIG += qt warn_on create_prl link_prl -OBJECTS_DIR=.obj/debug-shared -MOC_DIR=.moc/debug-shared diff --git a/tools/assistant/compat/Info_mac.plist b/tools/qml/Info_mac.plist index b1e6336..80ca6a3 100644 --- a/tools/assistant/compat/Info_mac.plist +++ b/tools/qml/Info_mac.plist @@ -1,17 +1,17 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"> -<plist version="0.9"> +<plist version="0.1"> <dict> <key>CFBundleIconFile</key> <string>@ICON@</string> + <key>CFBundleIdentifier</key> + <string>com.nokia.qt.qml</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleGetInfoString</key> <string>Created by Qt/QMake</string> <key>CFBundleSignature</key> - <string>????</string> - <key>CFBundleIdentifier</key> - <string>com.trolltech.assistant-compat</string> + <string>@TYPEINFO@</string> <key>CFBundleExecutable</key> <string>@EXECUTABLE@</string> </dict> diff --git a/tools/qml/content/Browser.qml b/tools/qml/content/Browser.qml new file mode 100644 index 0000000..838a848 --- /dev/null +++ b/tools/qml/content/Browser.qml @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt 4.7 +import Qt.labs.folderlistmodel 1.0 + +Rectangle { + id: root + property bool keyPressed: false + property variant folders: folders1 + property variant view: view1 + width: 320 + height: 480 + color: palette.window + + FolderListModel { + id: folders1 + nameFilters: [ "*.qml" ] + folder: qmlViewerFolder + } + FolderListModel { + id: folders2 + nameFilters: [ "*.qml" ] + folder: qmlViewerFolder + } + + SystemPalette { id: palette } + + function down(path) { + if (folders == folders1) { + view = view2 + folders = folders2; + view1.state = "exitLeft"; + } else { + view = view1 + folders = folders1; + view2.state = "exitLeft"; + } + view.x = root.width; + view.state = "current"; + view.focus = true; + folders.folder = path; + } + function up() { + var path = folders.parentFolder; + if (folders == folders1) { + view = view2 + folders = folders2; + view1.state = "exitRight"; + } else { + view = view1 + folders = folders1; + view2.state = "exitRight"; + } + view.x = -root.width; + view.state = "current"; + view.focus = true; + folders.folder = path; + } + + Component { + id: folderDelegate + Rectangle { + id: wrapper + function launch() { + if (folders.isFolder(index)) { + down(filePath); + } else { + qmlViewer.launch(filePath); + } + } + width: root.width + height: 52 + color: "transparent" + Rectangle { + id: highlight; visible: false + anchors.fill: parent + gradient: Gradient { + GradientStop { id: t1; position: 0.0; color: palette.highlight } + GradientStop { id: t2; position: 1.0; color: Qt.lighter(palette.highlight) } + } + } + Item { + width: 48; height: 48 + Image { source: "images/folder.png"; anchors.centerIn: parent; visible: folders.isFolder(index)} + } + Text { + id: nameText + anchors.fill: parent; verticalAlignment: Text.AlignVCenter + text: fileName + anchors.leftMargin: 54 + font.pixelSize: 32 + color: (wrapper.ListView.isCurrentItem && root.keyPressed) ? palette.highlightedText : palette.windowText + elide: Text.ElideRight + } + MouseArea { + id: mouseRegion + anchors.fill: parent + onClicked: { launch() } + } + states: [ + State { + name: "pressed" + when: mouseRegion.pressed + PropertyChanges { target: highlight; visible: true } + PropertyChanges { target: nameText; color: palette.highlightedText } + } + ] + } + } + + ListView { + id: view1 + anchors.top: titleBar.bottom + anchors.bottom: parent.bottom + x: 0 + width: parent.width + model: folders1 + delegate: folderDelegate + highlight: Rectangle { color: palette.highlight; visible: root.keyPressed && view1.count != 0 } + highlightMoveSpeed: 1000 + pressDelay: 100 + focus: true + state: "current" + states: [ + State { + name: "current" + PropertyChanges { target: view1; x: 0 } + }, + State { + name: "exitLeft" + PropertyChanges { target: view1; x: -root.width } + }, + State { + name: "exitRight" + PropertyChanges { target: view1; x: root.width } + } + ] + transitions: [ + Transition { + to: "current" + SequentialAnimation { + NumberAnimation { properties: "x"; duration: 250 } + } + }, + Transition { + NumberAnimation { properties: "x"; duration: 250 } + NumberAnimation { properties: "x"; duration: 250 } + } + ] + Keys.onPressed: { root.keyPressed = true; } + } + + ListView { + id: view2 + anchors.top: titleBar.bottom + anchors.bottom: parent.bottom + x: parent.width + width: parent.width + model: folders2 + delegate: folderDelegate + highlight: Rectangle { color: palette.highlight; visible: root.keyPressed && view2.count != 0 } + highlightMoveSpeed: 1000 + pressDelay: 100 + states: [ + State { + name: "current" + PropertyChanges { target: view2; x: 0 } + }, + State { + name: "exitLeft" + PropertyChanges { target: view2; x: -root.width } + }, + State { + name: "exitRight" + PropertyChanges { target: view2; x: root.width } + } + ] + transitions: [ + Transition { + to: "current" + SequentialAnimation { + NumberAnimation { properties: "x"; duration: 250 } + } + }, + Transition { + NumberAnimation { properties: "x"; duration: 250 } + } + ] + Keys.onPressed: { root.keyPressed = true; } + } + + Keys.onPressed: { + root.keyPressed = true; + if (event.key == Qt.Key_Return || event.key == Qt.Key_Select || event.key == Qt.Key_Right) { + view.currentItem.launch(); + event.accepted = true; + } else if (event.key == Qt.Key_Left) { + up(); + } + } + + BorderImage { + source: "images/titlebar.sci"; + width: parent.width; + height: 52 + y: -7 + id: titleBar + + Rectangle { + id: upButton + width: 48 + height: titleBar.height - 7 + color: "transparent" + + Image { anchors.centerIn: parent; source: "images/up.png" } + MouseArea { id: upRegion; anchors.centerIn: parent + width: 56 + height: 56 + onClicked: if (folders.parentFolder != "") up() + } + states: [ + State { + name: "pressed" + when: upRegion.pressed + PropertyChanges { target: upButton; color: palette.highlight } + } + ] + } + Rectangle { + color: "gray" + x: 48 + width: 1 + height: 44 + } + + Text { + anchors.left: upButton.right; anchors.right: parent.right; height: parent.height + anchors.leftMargin: 4; anchors.rightMargin: 4 + text: folders.folder + color: "white" + elide: Text.ElideLeft; horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignVCenter + font.pixelSize: 32 + } + } +} diff --git a/tools/qml/content/images/folder.png b/tools/qml/content/images/folder.png Binary files differnew file mode 100644 index 0000000..e53e2ad --- /dev/null +++ b/tools/qml/content/images/folder.png diff --git a/tools/qml/content/images/titlebar.png b/tools/qml/content/images/titlebar.png Binary files differnew file mode 100644 index 0000000..51c9008 --- /dev/null +++ b/tools/qml/content/images/titlebar.png diff --git a/tools/qml/content/images/titlebar.sci b/tools/qml/content/images/titlebar.sci new file mode 100644 index 0000000..0418d94 --- /dev/null +++ b/tools/qml/content/images/titlebar.sci @@ -0,0 +1,5 @@ +border.left: 10 +border.top: 12 +border.bottom: 12 +border.right: 10 +source: titlebar.png diff --git a/tools/qml/content/images/up.png b/tools/qml/content/images/up.png Binary files differnew file mode 100644 index 0000000..b05f802 --- /dev/null +++ b/tools/qml/content/images/up.png diff --git a/tools/qml/deviceorientation.cpp b/tools/qml/deviceorientation.cpp new file mode 100644 index 0000000..e7c70d5 --- /dev/null +++ b/tools/qml/deviceorientation.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "deviceorientation.h" + +QT_USE_NAMESPACE + +class DefaultDeviceOrientation : public DeviceOrientation +{ + Q_OBJECT +public: + DefaultDeviceOrientation() : DeviceOrientation(), m_orientation(DeviceOrientation::Portrait) {} + + Orientation orientation() const { + return m_orientation; + } + + void setOrientation(Orientation o) { + if (o != m_orientation) { + m_orientation = o; + emit orientationChanged(); + } + } + + Orientation m_orientation; +}; + +DeviceOrientation* DeviceOrientation::instance() +{ + static DefaultDeviceOrientation *o = 0; + if (!o) + o = new DefaultDeviceOrientation; + return o; +} + +#include "deviceorientation.moc" + diff --git a/tools/qml/deviceorientation.h b/tools/qml/deviceorientation.h new file mode 100644 index 0000000..d209005 --- /dev/null +++ b/tools/qml/deviceorientation.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ORIENTATION_H +#define ORIENTATION_H + +#include <QObject> + +QT_BEGIN_NAMESPACE + +class DeviceOrientationPrivate; +class DeviceOrientation : public QObject +{ + Q_OBJECT + Q_ENUMS(Orientation) +public: + enum Orientation { UnknownOrientation, Portrait, Landscape }; + virtual Orientation orientation() const = 0; + virtual void setOrientation(Orientation) = 0; + + static DeviceOrientation *instance(); + +signals: + void orientationChanged(); + +protected: + DeviceOrientation() {} + +private: + DeviceOrientationPrivate *d_ptr; + friend class DeviceOrientationPrivate; +}; + +QT_END_NAMESPACE + +#endif diff --git a/tools/qml/deviceorientation_maemo.cpp b/tools/qml/deviceorientation_maemo.cpp new file mode 100644 index 0000000..9f12f3d --- /dev/null +++ b/tools/qml/deviceorientation_maemo.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "deviceorientation.h" +#include <stdio.h> +#include <stdlib.h> + +class MaemoOrientation : public DeviceOrientation +{ + Q_OBJECT +public: + MaemoOrientation() + : DeviceOrientation(),m_current(Portrait), m_lastSeen(Portrait), m_lastSeenCount(0) + { + m_current = get(); + if (m_current == UnknownOrientation) + m_current = Portrait; + + startTimer(100); + } + + Orientation orientation() const { + return m_current; + } + + void setOrientation(Orientation) { } + +protected: + virtual void timerEvent(QTimerEvent *) + { + Orientation c = get(); + + if (c == m_lastSeen) { + m_lastSeenCount++; + } else { + m_lastSeenCount = 0; + m_lastSeen = c; + } + + if (m_lastSeen != UnknownOrientation && m_lastSeen != m_current && m_lastSeenCount > 4) { + m_current = m_lastSeen; + emit orientationChanged(); + printf("%d\n", m_current); + } + } + +signals: + void changed(); + +private: + Orientation m_current; + Orientation m_lastSeen; + int m_lastSeenCount; + + Orientation get() + { + Orientation o = UnknownOrientation; + + int ax, ay, az; + + read(&ax, &ay, &az); + + if (abs(az) > 850) { + o = UnknownOrientation; + } else if (ax < -750) { + o = Portrait; + } else if (ay < -750) { + o = Landscape; + } + + return o; + } + + int read(int *ax,int *ay,int *az) + { + static const char *accel_filename = "/sys/class/i2c-adapter/i2c-3/3-001d/coord"; + + FILE *fd; + int rs; + fd = fopen(accel_filename, "r"); + if(fd==NULL){ printf("liqaccel, cannot open for reading\n"); return -1;} + rs=fscanf((FILE*) fd,"%i %i %i",ax,ay,az); + fclose(fd); + if(rs != 3){ printf("liqaccel, cannot read information\n"); return -2;} + return 0; + } +}; + + +DeviceOrientation* DeviceOrientation::instance() +{ + static MaemoOrientation *o = 0; + if (!o) + o = new MaemoOrientation; + return o; +} + +#include "deviceorientation_maemo.moc" diff --git a/tools/qml/loggerwidget.cpp b/tools/qml/loggerwidget.cpp new file mode 100644 index 0000000..3ae2b5e --- /dev/null +++ b/tools/qml/loggerwidget.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "loggerwidget.h" +#include <qglobal.h> +#include <QDebug> +#include <QSettings> +#include <QActionGroup> +#include <QMenu> + +QT_BEGIN_NAMESPACE + +LoggerWidget::LoggerWidget(QWidget *parent) : + QPlainTextEdit(parent), + m_visibilityOrigin(SettingsOrigin) +{ + setAttribute(Qt::WA_QuitOnClose, false); + setWindowTitle(tr("Warnings")); + + readSettings(); + setupPreferencesMenu(); +} + +void LoggerWidget::append(const QString &msg) +{ + appendPlainText(msg); + + if (!isVisible() && (defaultVisibility() == AutoShowWarnings)) + setVisible(true); +} + +LoggerWidget::Visibility LoggerWidget::defaultVisibility() const +{ + return m_visibility; +} + +void LoggerWidget::setDefaultVisibility(LoggerWidget::Visibility visibility) +{ + if (m_visibility == visibility) + return; + + m_visibility = visibility; + m_visibilityOrigin = CommandLineOrigin; + + m_preferencesMenu->setEnabled(m_visibilityOrigin == SettingsOrigin); +} + +QMenu *LoggerWidget::preferencesMenu() +{ + return m_preferencesMenu; +} + +QAction *LoggerWidget::showAction() +{ + return m_showWidgetAction; +} + +void LoggerWidget::readSettings() +{ + QSettings settings; + QString warningsPreferences = settings.value("warnings", "hide").toString(); + if (warningsPreferences == "show") { + m_visibility = ShowWarnings; + } else if (warningsPreferences == "hide") { + m_visibility = HideWarnings; + } else { + m_visibility = AutoShowWarnings; + } +} + +void LoggerWidget::saveSettings() +{ + if (m_visibilityOrigin != SettingsOrigin) + return; + + QString value = "autoShow"; + if (defaultVisibility() == ShowWarnings) { + value = "show"; + } else if (defaultVisibility() == HideWarnings) { + value = "hide"; + } + + QSettings settings; + settings.setValue("warnings", value); +} + +void LoggerWidget::warningsPreferenceChanged(QAction *action) +{ + Visibility newSetting = static_cast<Visibility>(action->data().toInt()); + m_visibility = newSetting; + saveSettings(); +} + +void LoggerWidget::showEvent(QShowEvent *event) +{ + QWidget::showEvent(event); + emit opened(); +} + +void LoggerWidget::closeEvent(QCloseEvent *event) +{ + QWidget::closeEvent(event); + emit closed(); +} + +void LoggerWidget::setupPreferencesMenu() +{ + m_preferencesMenu = new QMenu(tr("Warnings")); + QActionGroup *warnings = new QActionGroup(m_preferencesMenu); + warnings->setExclusive(true); + + connect(warnings, SIGNAL(triggered(QAction*)), this, SLOT(warningsPreferenceChanged(QAction*))); + + QAction *showWarningsPreference = new QAction(tr("Show by default"), m_preferencesMenu); + showWarningsPreference->setCheckable(true); + showWarningsPreference->setData(LoggerWidget::ShowWarnings); + warnings->addAction(showWarningsPreference); + m_preferencesMenu->addAction(showWarningsPreference); + + QAction *hideWarningsPreference = new QAction(tr("Hide by default"), m_preferencesMenu); + hideWarningsPreference->setCheckable(true); + hideWarningsPreference->setData(LoggerWidget::HideWarnings); + warnings->addAction(hideWarningsPreference); + m_preferencesMenu->addAction(hideWarningsPreference); + + QAction *autoWarningsPreference = new QAction(tr("Show for first warning"), m_preferencesMenu); + autoWarningsPreference->setCheckable(true); + autoWarningsPreference->setData(LoggerWidget::AutoShowWarnings); + warnings->addAction(autoWarningsPreference); + m_preferencesMenu->addAction(autoWarningsPreference); + + switch (defaultVisibility()) { + case LoggerWidget::ShowWarnings: + showWarningsPreference->setChecked(true); + break; + case LoggerWidget::HideWarnings: + hideWarningsPreference->setChecked(true); + break; + default: + autoWarningsPreference->setChecked(true); + } +} + +QT_END_NAMESPACE diff --git a/tools/qml/loggerwidget.h b/tools/qml/loggerwidget.h new file mode 100644 index 0000000..fd20c41 --- /dev/null +++ b/tools/qml/loggerwidget.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LOGGERWIDGET_H +#define LOGGERWIDGET_H + +#include <QPlainTextEdit> + +QT_BEGIN_NAMESPACE + +class LoggerWidget : public QPlainTextEdit { +Q_OBJECT +public: + LoggerWidget(QWidget *parent=0); + + enum Visibility { ShowWarnings, HideWarnings, AutoShowWarnings }; + + Visibility defaultVisibility() const; + void setDefaultVisibility(Visibility visibility); + + QMenu *preferencesMenu(); + QAction *showAction(); + +public slots: + void append(const QString &msg); + +private slots: + void warningsPreferenceChanged(QAction *action); + void readSettings(); + void saveSettings(); + +protected: + void showEvent(QShowEvent *event); + void closeEvent(QCloseEvent *event); + +signals: + void opened(); + void closed(); + +private: + void setupPreferencesMenu(); + + QMenu *m_preferencesMenu; + QAction *m_showWidgetAction; + + enum ConfigOrigin { CommandLineOrigin, SettingsOrigin }; + ConfigOrigin m_visibilityOrigin; + Visibility m_visibility; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(LoggerWidget::Visibility) + +#endif // LOGGERWIDGET_H diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp new file mode 100644 index 0000000..0cce1cc --- /dev/null +++ b/tools/qml/main.cpp @@ -0,0 +1,457 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarative.h" +#include "qmlruntime.h" +#include "qdeclarativeengine.h" +#include "loggerwidget.h" +#include <QWidget> +#include <QDir> +#include <QApplication> +#include <QTranslator> +#include <QDebug> +#include <QMessageBox> +#include "qdeclarativetester.h" + +QT_USE_NAMESPACE + +QtMsgHandler systemMsgOutput = 0; + +#if defined (Q_OS_SYMBIAN) +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +void myMessageOutput(QtMsgType type, const char *msg) +{ + static int fd = -1; + if (fd == -1) + fd = ::open("E:\\qml.log", O_WRONLY | O_CREAT); + + ::write(fd, msg, strlen(msg)); + ::write(fd, "\n", 1); + ::fsync(fd); + + switch (type) { + case QtFatalMsg: + abort(); + } +} + +#else // !defined (Q_OS_SYMBIAN) + +QWeakPointer<LoggerWidget> logger; + +QString warnings; +void showWarnings() +{ + if (!warnings.isEmpty()) { + QMessageBox::warning(0, QApplication::tr("Qt QML Viewer"), warnings); + } +} + +void myMessageOutput(QtMsgType type, const char *msg) +{ + if (!logger.isNull()) { + QString strMsg = QString::fromAscii(msg); + QMetaObject::invokeMethod(logger.data(), "append", Q_ARG(QString, strMsg)); + } else { + warnings += msg; + warnings += QLatin1Char('\n'); + } + if (systemMsgOutput) { // Windows + systemMsgOutput(type, msg); + } else { // Unix + fprintf(stderr, "%s\n",msg); + fflush(stderr); + } +} + +#endif + +void usage() +{ + qWarning("Usage: qmlviewer [options] <filename>"); + qWarning(" "); + qWarning(" options:"); + qWarning(" -v, -version ............................. display version"); + qWarning(" -frameless ............................... run with no window frame"); + qWarning(" -maximized................................ run maximized"); + qWarning(" -fullscreen............................... run fullscreen"); + qWarning(" -stayontop................................ keep viewer window on top"); + qWarning(" -sizeviewtorootobject .................... the view resizes to the changes in the content"); + qWarning(" -sizerootobjecttoview .................... the content resizes to the changes in the view"); + qWarning(" -qmlbrowser .............................. use a QML-based file browser"); + qWarning(" -warnings [show|hide]..................... show warnings in a separate log window"); + qWarning(" -recordfile <output> ..................... set video recording file"); + qWarning(" - ImageMagick 'convert' for GIF)"); + qWarning(" - png file for raw frames"); + qWarning(" - 'ffmpeg' for other formats"); + qWarning(" -recorddither ordered|threshold|floyd .... set GIF dither recording mode"); + qWarning(" -recordrate <fps> ........................ set recording frame rate"); + qWarning(" -record arg .............................. add a recording process argument"); + qWarning(" -autorecord [from-]<tomilliseconds> ...... set recording to start and stop"); + qWarning(" -devicekeys .............................. use numeric keys (see F1)"); + qWarning(" -dragthreshold <size> .................... set mouse drag threshold size"); + qWarning(" -netcache <size> ......................... set disk cache to size bytes"); + qWarning(" -translation <translationfile> ........... set the language to run in"); + qWarning(" -I <directory> ........................... prepend to the module import search path,"); + qWarning(" display path if <directory> is empty"); + qWarning(" -P <directory> ........................... prepend to the plugin search path"); + qWarning(" -opengl .................................. use a QGLWidget for the viewport"); + qWarning(" -script <path> ........................... set the script to use"); + qWarning(" -scriptopts <options>|help ............... set the script options to use"); + + qWarning(" "); + qWarning(" Press F1 for interactive help"); + exit(1); +} + +void scriptOptsUsage() +{ + qWarning("Usage: qmlviewer -scriptopts <option>[,<option>...] ..."); + qWarning(" options:"); + qWarning(" record ................................... record a new script"); + qWarning(" play ..................................... playback an existing script"); + qWarning(" testimages ............................... record images or compare images on playback"); + qWarning(" testerror ................................ test 'error' property of root item on playback"); + qWarning(" snapshot ................................. file being recorded is static,"); + qWarning(" only one frame will be recorded or tested"); + qWarning(" exitoncomplete ........................... cleanly exit the viewer on script completion"); + qWarning(" exitonfailure ............................ immediately exit the viewer on script failure"); + qWarning(" saveonexit ............................... save recording on viewer exit"); + qWarning(" "); + qWarning(" One of record, play or both must be specified."); + exit(1); +} + +enum WarningsConfig { ShowWarnings, HideWarnings, DefaultWarnings }; + +int main(int argc, char ** argv) +{ +#if defined (Q_OS_SYMBIAN) + qInstallMsgHandler(myMessageOutput); +#else + systemMsgOutput = qInstallMsgHandler(myMessageOutput); +#endif + +#if defined (Q_OS_WIN) + // Debugging output is not visible by default on Windows - + // therefore show modal dialog with errors instad. + atexit(showWarnings); +#endif + +#if defined (Q_WS_X11) || defined (Q_WS_MAC) + //### default to using raster graphics backend for now + bool gsSpecified = false; + for (int i = 0; i < argc; ++i) { + QString arg = argv[i]; + if (arg == "-graphicssystem") { + gsSpecified = true; + break; + } + } + + if (!gsSpecified) + QApplication::setGraphicsSystem("raster"); +#endif + + QApplication app(argc, argv); + app.setApplicationName("QtQmlViewer"); + app.setOrganizationName("Nokia"); + app.setOrganizationDomain("nokia.com"); + + QDeclarativeViewer::registerTypes(); + QDeclarativeTester::registerTypes(); + + bool frameless = false; + QString fileName; + double fps = 0; + int autorecord_from = 0; + int autorecord_to = 0; + QString dither = "none"; + QString recordfile; + QStringList recordargs; + QStringList imports; + QStringList plugins; + QString script; + QString scriptopts; + bool runScript = false; + bool devkeys = false; + int cache = 0; + QString translationFile; + bool useGL = false; + bool fullScreen = false; + bool stayOnTop = false; + bool maximized = false; + bool useNativeFileBrowser = true; + bool experimentalGestures = false; + + WarningsConfig warningsConfig = DefaultWarnings; + bool sizeToView = true; + +#if defined(Q_OS_SYMBIAN) + maximized = true; + useNativeFileBrowser = false; +#endif + +#if defined(Q_WS_MAC) + useGL = true; +#endif + + for (int i = 1; i < argc; ++i) { + bool lastArg = (i == argc - 1); + QString arg = argv[i]; + if (arg == "-frameless") { + frameless = true; + } else if (arg == "-maximized") { + maximized = true; + } else if (arg == "-fullscreen") { + fullScreen = true; + } else if (arg == "-stayontop") { + stayOnTop = true; + } else if (arg == "-netcache") { + if (lastArg) usage(); + cache = QString(argv[++i]).toInt(); + } else if (arg == "-recordrate") { + if (lastArg) usage(); + fps = QString(argv[++i]).toDouble(); + } else if (arg == "-recordfile") { + if (lastArg) usage(); + recordfile = QString(argv[++i]); + } else if (arg == "-record") { + if (lastArg) usage(); + recordargs << QString(argv[++i]); + } else if (arg == "-recorddither") { + if (lastArg) usage(); + dither = QString(argv[++i]); + } else if (arg == "-autorecord") { + if (lastArg) usage(); + QString range = QString(argv[++i]); + int dash = range.indexOf('-'); + if (dash > 0) + autorecord_from = range.left(dash).toInt(); + autorecord_to = range.mid(dash+1).toInt(); + } else if (arg == "-devicekeys") { + devkeys = true; + } else if (arg == "-dragthreshold") { + if (lastArg) usage(); + app.setStartDragDistance(QString(argv[++i]).toInt()); + } else if (arg == QLatin1String("-v") || arg == QLatin1String("-version")) { + qWarning("Qt QML Viewer version %s", QT_VERSION_STR); + exit(0); + } else if (arg == "-translation") { + if (lastArg) usage(); + translationFile = argv[++i]; + } else if (arg == "-opengl") { + useGL = true; + } else if (arg == "-qmlbrowser") { + useNativeFileBrowser = false; + } else if (arg == "-warnings") { + if (lastArg) usage(); + QString warningsStr = QString(argv[++i]); + if (warningsStr == QLatin1String("show")) { + warningsConfig = ShowWarnings; + } else if (warningsStr == QLatin1String("hide")) { + warningsConfig = HideWarnings; + } else { + usage(); + } + } else if (arg == "-I" || arg == "-L") { + if (arg == "-L") + qWarning("-L option provided for compatibility only, use -I instead"); + if (lastArg) { + QDeclarativeEngine tmpEngine; + QString paths = tmpEngine.importPathList().join(QLatin1String(":")); + qWarning("Current search path: %s", paths.toLocal8Bit().constData()); + exit(0); + } + imports << QString(argv[++i]); + } else if (arg == "-P") { + if (lastArg) usage(); + plugins << QString(argv[++i]); + } else if (arg == "-script") { + if (lastArg) usage(); + script = QString(argv[++i]); + } else if (arg == "-scriptopts") { + if (lastArg) usage(); + scriptopts = QString(argv[++i]); + } else if (arg == "-savescript") { + if (lastArg) usage(); + script = QString(argv[++i]); + runScript = false; + } else if (arg == "-playscript") { + if (lastArg) usage(); + script = QString(argv[++i]); + runScript = true; + } else if (arg == "-sizeviewtorootobject") { + sizeToView = false; + } else if (arg == "-sizerootobjecttoview") { + sizeToView = true; + } else if (arg == "-experimentalgestures") { + experimentalGestures = true; + } else if (arg[0] != '-') { + fileName = arg; + } else if (1 || arg == "-help") { + usage(); + } + } + + QTranslator qmlTranslator; + if (!translationFile.isEmpty()) { + qmlTranslator.load(translationFile); + app.installTranslator(&qmlTranslator); + } + + Qt::WFlags wflags = (frameless ? Qt::FramelessWindowHint : Qt::Widget); + if (stayOnTop) + wflags |= Qt::WindowStaysOnTopHint; + + QDeclarativeViewer *viewer = new QDeclarativeViewer(0, wflags); + if (!scriptopts.isEmpty()) { + QStringList options = + scriptopts.split(QLatin1Char(','), QString::SkipEmptyParts); + + QDeclarativeViewer::ScriptOptions scriptOptions = 0; + for (int i = 0; i < options.count(); ++i) { + const QString &option = options.at(i); + if (option == QLatin1String("help")) { + scriptOptsUsage(); + } else if (option == QLatin1String("play")) { + scriptOptions |= QDeclarativeViewer::Play; + } else if (option == QLatin1String("record")) { + scriptOptions |= QDeclarativeViewer::Record; + } else if (option == QLatin1String("testimages")) { + scriptOptions |= QDeclarativeViewer::TestImages; + } else if (option == QLatin1String("testerror")) { + scriptOptions |= QDeclarativeViewer::TestErrorProperty; + } else if (option == QLatin1String("exitoncomplete")) { + scriptOptions |= QDeclarativeViewer::ExitOnComplete; + } else if (option == QLatin1String("exitonfailure")) { + scriptOptions |= QDeclarativeViewer::ExitOnFailure; + } else if (option == QLatin1String("saveonexit")) { + scriptOptions |= QDeclarativeViewer::SaveOnExit; + } else if (option == QLatin1String("snapshot")) { + scriptOptions |= QDeclarativeViewer::Snapshot; + } else { + scriptOptsUsage(); + } + } + + if (script.isEmpty()) + usage(); + + if (!(scriptOptions & QDeclarativeViewer::Record) && !(scriptOptions & QDeclarativeViewer::Play)) + scriptOptsUsage(); + viewer->setScriptOptions(scriptOptions); + viewer->setScript(script); + } else if (!script.isEmpty()) { + usage(); + } + +#if !defined(Q_OS_SYMBIAN) + logger = viewer->warningsWidget(); + if (warningsConfig == ShowWarnings) { + logger.data()->setDefaultVisibility(LoggerWidget::ShowWarnings); + logger.data()->show(); + } else if (warningsConfig == HideWarnings){ + logger.data()->setDefaultVisibility(LoggerWidget::HideWarnings); + } +#endif + + if (experimentalGestures) + viewer->enableExperimentalGestures(); + + foreach (QString lib, imports) + viewer->addLibraryPath(lib); + + foreach (QString plugin, plugins) + viewer->addPluginPath(plugin); + + viewer->setNetworkCacheSize(cache); + viewer->setRecordFile(recordfile); + viewer->setSizeToView(sizeToView); + if (fps>0) + viewer->setRecordRate(fps); + if (autorecord_to) + viewer->setAutoRecord(autorecord_from,autorecord_to); + if (devkeys) + viewer->setDeviceKeys(true); + viewer->setRecordDither(dither); + if (recordargs.count()) + viewer->setRecordArgs(recordargs); + + viewer->setUseNativeFileBrowser(useNativeFileBrowser); + if (fullScreen && maximized) + qWarning() << "Both -fullscreen and -maximized specified. Using -fullscreen."; + + if (fileName.isEmpty()) { + QFile qmlapp(QLatin1String("qmlapp")); + if (qmlapp.exists() && qmlapp.open(QFile::ReadOnly)) { + QString content = QString::fromUtf8(qmlapp.readAll()); + qmlapp.close(); + + int newline = content.indexOf(QLatin1Char('\n')); + if (newline >= 0) + fileName = content.left(newline); + else + fileName = content; + } + } + + if (!fileName.isEmpty()) { + viewer->open(fileName); + fullScreen ? viewer->showFullScreen() : maximized ? viewer->showMaximized() : viewer->show(); + } else { + if (!useNativeFileBrowser) + viewer->openFile(); + fullScreen ? viewer->showFullScreen() : maximized ? viewer->showMaximized() : viewer->show(); + if (useNativeFileBrowser) + viewer->openFile(); + } + viewer->setUseGL(useGL); + viewer->raise(); + + int rv = app.exec(); + delete viewer; + exit(rv); +} diff --git a/tools/qml/proxysettings.cpp b/tools/qml/proxysettings.cpp new file mode 100644 index 0000000..3255e42 --- /dev/null +++ b/tools/qml/proxysettings.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QIntValidator> +#include <QSettings> + +#include "proxysettings.h" + +QT_BEGIN_NAMESPACE + +ProxySettings::ProxySettings (QWidget * parent) + : QDialog (parent), Ui::ProxySettings() +{ + setupUi (this); + + proxyServerEdit->setInputMask ("000.000.000.000;_"); + QIntValidator *validator = new QIntValidator (0, 9999, this); + proxyPortEdit->setValidator (validator); + + QSettings settings; + proxyCheckBox->setChecked (settings.value ("http_proxy/use", 0).toBool ()); + proxyServerEdit->insert (settings.value ("http_proxy/hostname", "").toString ()); + proxyPortEdit->insert (settings.value ("http_proxy/port", "80").toString ()); + usernameEdit->insert (settings.value ("http_proxy/username", "").toString ()); + passwordEdit->insert (settings.value ("http_proxy/password", "").toString ()); +} + +ProxySettings::~ProxySettings() +{ +} + +void ProxySettings::accept () +{ + QSettings settings; + + settings.setValue ("http_proxy/use", proxyCheckBox->isChecked ()); + settings.setValue ("http_proxy/hostname", proxyServerEdit->text ()); + settings.setValue ("http_proxy/port", proxyPortEdit->text ()); + settings.setValue ("http_proxy/username", usernameEdit->text ()); + settings.setValue ("http_proxy/password", passwordEdit->text ()); + + QDialog::accept (); +} + +QNetworkProxy ProxySettings::httpProxy () +{ + QSettings settings; + QNetworkProxy proxy; + + bool proxyInUse = settings.value ("http_proxy/use", 0).toBool (); + if (proxyInUse) { + proxy.setType (QNetworkProxy::HttpProxy); + proxy.setHostName (settings.value ("http_proxy/hostname", "").toString ());// "192.168.220.5" + proxy.setPort (settings.value ("http_proxy/port", 80).toInt ()); // 8080 + proxy.setUser (settings.value ("http_proxy/username", "").toString ()); + proxy.setPassword (settings.value ("http_proxy/password", "").toString ()); + //QNetworkProxy::setApplicationProxy (proxy); + } + else { + proxy.setType (QNetworkProxy::NoProxy); + } + return proxy; +} + +bool ProxySettings::httpProxyInUse() +{ + QSettings settings; + return settings.value ("http_proxy/use", 0).toBool (); +} + +QT_END_NAMESPACE diff --git a/tools/qml/proxysettings.h b/tools/qml/proxysettings.h new file mode 100644 index 0000000..325929a --- /dev/null +++ b/tools/qml/proxysettings.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PROXYSETTINGS_H +#define PROXYSETTINGS_H + +#include <QDialog> +#include <QNetworkProxy> +#include "ui_proxysettings.h" + +QT_BEGIN_NAMESPACE +/** +*/ +class ProxySettings : public QDialog, public Ui::ProxySettings +{ + +Q_OBJECT + +public: + ProxySettings(QWidget * parent = 0); + + ~ProxySettings(); + + static QNetworkProxy httpProxy (); + static bool httpProxyInUse (); + +public slots: + virtual void accept (); +}; + +QT_END_NAMESPACE + +#endif // PROXYSETTINGS_H diff --git a/tools/qml/proxysettings.ui b/tools/qml/proxysettings.ui new file mode 100644 index 0000000..84e39fe --- /dev/null +++ b/tools/qml/proxysettings.ui @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ProxySettings</class> + <widget class="QDialog" name="ProxySettings"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>318</width> + <height>199</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0" colspan="2"> + <widget class="QCheckBox" name="proxyCheckBox"> + <property name="text"> + <string>Use http proxy</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="serverAddressLabel"> + <property name="text"> + <string>Server Address:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="proxyServerEdit"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Port:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="proxyPortEdit"/> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="usernameLabel"> + <property name="text"> + <string>Username:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="usernameEdit"/> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="passwordLabel"> + <property name="text"> + <string>Password:</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLineEdit" name="passwordEdit"> + <property name="echoMode"> + <enum>QLineEdit::Password</enum> + </property> + </widget> + </item> + <item row="5" column="0" colspan="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ProxySettings</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ProxySettings</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/qml/qdeclarativetester.cpp b/tools/qml/qdeclarativetester.cpp new file mode 100644 index 0000000..9864df6 --- /dev/null +++ b/tools/qml/qdeclarativetester.cpp @@ -0,0 +1,407 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qdeclarativetester.h> +#include <QDebug> +#include <QApplication> +#include <qdeclarativeview.h> +#include <QFile> +#include <QDeclarativeComponent> +#include <QDir> +#include <QCryptographicHash> +#include <private/qabstractanimation_p.h> +#include <private/qdeclarativeitem_p.h> + +QT_BEGIN_NAMESPACE + + +QDeclarativeTester::QDeclarativeTester(const QString &script, QDeclarativeViewer::ScriptOptions opts, + QDeclarativeView *parent) +: QAbstractAnimation(parent), m_script(script), m_view(parent), filterEvents(true), options(opts), + testscript(0), hasCompleted(false), hasFailed(false) +{ + parent->viewport()->installEventFilter(this); + parent->installEventFilter(this); + QUnifiedTimer::instance()->setConsistentTiming(true); + if (options & QDeclarativeViewer::Play) + this->run(); + start(); +} + +QDeclarativeTester::~QDeclarativeTester() +{ + if (!hasFailed && + options & QDeclarativeViewer::Record && + options & QDeclarativeViewer::SaveOnExit) + save(); +} + +int QDeclarativeTester::duration() const +{ + return -1; +} + +void QDeclarativeTester::addMouseEvent(Destination dest, QMouseEvent *me) +{ + MouseEvent e(me); + e.destination = dest; + m_mouseEvents << e; +} + +void QDeclarativeTester::addKeyEvent(Destination dest, QKeyEvent *ke) +{ + KeyEvent e(ke); + e.destination = dest; + m_keyEvents << e; +} + +bool QDeclarativeTester::eventFilter(QObject *o, QEvent *e) +{ + if (!filterEvents) + return false; + + Destination destination; + if (o == m_view) { + destination = View; + } else if (o == m_view->viewport()) { + destination = ViewPort; + } else { + return false; + } + + switch (e->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: + addKeyEvent(destination, (QKeyEvent *)e); + return true; + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + case QEvent::MouseButtonDblClick: + addMouseEvent(destination, (QMouseEvent *)e); + return true; + default: + break; + } + return false; +} + +void QDeclarativeTester::executefailure() +{ + hasFailed = true; + + if (options & QDeclarativeViewer::ExitOnFailure) + exit(-1); +} + +void QDeclarativeTester::imagefailure() +{ + hasFailed = true; + + if (options & QDeclarativeViewer::ExitOnFailure) + exit(-1); +} + +void QDeclarativeTester::complete() +{ + if ((options & QDeclarativeViewer::TestErrorProperty) && !hasFailed) { + QString e = m_view->rootObject()->property("error").toString(); + if (!e.isEmpty()) { + qWarning() << "Test failed:" << e; + hasFailed = true; + } + } + if (options & QDeclarativeViewer::ExitOnComplete) + QApplication::exit(hasFailed?-1:0); + + if (hasCompleted) + return; + hasCompleted = true; + + if (options & QDeclarativeViewer::Play) + qWarning("Script playback complete"); +} + +void QDeclarativeTester::run() +{ + QDeclarativeComponent c(m_view->engine(), m_script + QLatin1String(".qml")); + + testscript = qobject_cast<QDeclarativeVisualTest *>(c.create()); + if (testscript) testscript->setParent(this); + else { executefailure(); exit(-1); } + testscriptidx = 0; +} + +void QDeclarativeTester::save() +{ + QString filename = m_script + QLatin1String(".qml"); + QFileInfo filenameInfo(filename); + QDir saveDir = filenameInfo.absoluteDir(); + saveDir.mkpath("."); + + QFile file(filename); + file.open(QIODevice::WriteOnly); + QTextStream ts(&file); + + ts << "import Qt.VisualTest 4.7\n\n"; + ts << "VisualTest {\n"; + + int imgCount = 0; + QList<KeyEvent> keyevents = m_savedKeyEvents; + QList<MouseEvent> mouseevents = m_savedMouseEvents; + for (int ii = 0; ii < m_savedFrameEvents.count(); ++ii) { + const FrameEvent &fe = m_savedFrameEvents.at(ii); + ts << " Frame {\n"; + ts << " msec: " << fe.msec << "\n"; + if (!fe.hash.isEmpty()) { + ts << " hash: \"" << fe.hash.toHex() << "\"\n"; + } else if (!fe.image.isNull()) { + QString filename = filenameInfo.baseName() + "." + QString::number(imgCount) + ".png"; + fe.image.save(m_script + "." + QString::number(imgCount) + ".png"); + imgCount++; + ts << " image: \"" << filename << "\"\n"; + } + ts << " }\n"; + + while (!mouseevents.isEmpty() && + mouseevents.first().msec == fe.msec) { + MouseEvent me = mouseevents.takeFirst(); + + ts << " Mouse {\n"; + ts << " type: " << me.type << "\n"; + ts << " button: " << me.button << "\n"; + ts << " buttons: " << me.buttons << "\n"; + ts << " x: " << me.pos.x() << "; y: " << me.pos.y() << "\n"; + ts << " modifiers: " << me.modifiers << "\n"; + if (me.destination == ViewPort) + ts << " sendToViewport: true\n"; + ts << " }\n"; + } + + while (!keyevents.isEmpty() && + keyevents.first().msec == fe.msec) { + KeyEvent ke = keyevents.takeFirst(); + + ts << " Key {\n"; + ts << " type: " << ke.type << "\n"; + ts << " key: " << ke.key << "\n"; + ts << " modifiers: " << ke.modifiers << "\n"; + ts << " text: \"" << ke.text.toUtf8().toHex() << "\"\n"; + ts << " autorep: " << (ke.autorep?"true":"false") << "\n"; + ts << " count: " << ke.count << "\n"; + if (ke.destination == ViewPort) + ts << " sendToViewport: true\n"; + ts << " }\n"; + } + } + + ts << "}\n"; + file.close(); +} + +void QDeclarativeTester::updateCurrentTime(int msec) +{ + QDeclarativeItemPrivate::setConsistentTime(msec); + if (!testscript && msec > 16 && options & QDeclarativeViewer::Snapshot) + return; + + QImage img(m_view->width(), m_view->height(), QImage::Format_RGB32); + + if (options & QDeclarativeViewer::TestImages) { + img.fill(qRgb(255,255,255)); + QPainter p(&img); + m_view->render(&p); + } + + bool snapshot = msec == 16 && (options & QDeclarativeViewer::Snapshot + || (testscript && testscript->count() == 2)); + + FrameEvent fe; + fe.msec = msec; + if (msec == 0 || !(options & QDeclarativeViewer::TestImages)) { + // Skip first frame, skip if not doing images + } else if (0 == (m_savedFrameEvents.count() % 60) || snapshot) { + fe.image = img; + } else { + QCryptographicHash hash(QCryptographicHash::Md5); + hash.addData((const char *)img.bits(), img.bytesPerLine() * img.height()); + fe.hash = hash.result(); + } + m_savedFrameEvents.append(fe); + + // Deliver mouse events + filterEvents = false; + + if (!testscript) { + for (int ii = 0; ii < m_mouseEvents.count(); ++ii) { + MouseEvent &me = m_mouseEvents[ii]; + me.msec = msec; + QMouseEvent event(me.type, me.pos, me.button, me.buttons, me.modifiers); + + if (me.destination == View) { + QCoreApplication::sendEvent(m_view, &event); + } else { + QCoreApplication::sendEvent(m_view->viewport(), &event); + } + } + + for (int ii = 0; ii < m_keyEvents.count(); ++ii) { + KeyEvent &ke = m_keyEvents[ii]; + ke.msec = msec; + QKeyEvent event(ke.type, ke.key, ke.modifiers, ke.text, ke.autorep, ke.count); + + if (ke.destination == View) { + QCoreApplication::sendEvent(m_view, &event); + } else { + QCoreApplication::sendEvent(m_view->viewport(), &event); + } + } + m_savedMouseEvents.append(m_mouseEvents); + m_savedKeyEvents.append(m_keyEvents); + } + + m_mouseEvents.clear(); + m_keyEvents.clear(); + + // Advance test script + while (testscript && testscript->count() > testscriptidx) { + + QObject *event = testscript->event(testscriptidx); + + if (QDeclarativeVisualTestFrame *frame = qobject_cast<QDeclarativeVisualTestFrame *>(event)) { + if (frame->msec() < msec) { + if (options & QDeclarativeViewer::TestImages && !(options & QDeclarativeViewer::Record)) { + qWarning() << "QDeclarativeTester: Extra frame. Seen:" + << msec << "Expected:" << frame->msec(); + imagefailure(); + } + } else if (frame->msec() == msec) { + if (!frame->hash().isEmpty() && frame->hash().toUtf8() != fe.hash.toHex()) { + if (options & QDeclarativeViewer::TestImages && !(options & QDeclarativeViewer::Record)) { + qWarning() << "QDeclarativeTester: Mismatched frame hash at" << msec + << ". Seen:" << fe.hash.toHex() + << "Expected:" << frame->hash().toUtf8(); + imagefailure(); + } + } + } else if (frame->msec() > msec) { + break; + } + + if (options & QDeclarativeViewer::TestImages && !(options & QDeclarativeViewer::Record) && !frame->image().isEmpty()) { + QImage goodImage(frame->image().toLocalFile()); + if (goodImage != img) { + QString reject(frame->image().toLocalFile() + ".reject.png"); + qWarning() << "QDeclarativeTester: Image mismatch. Reject saved to:" + << reject; + img.save(reject); + bool doDiff = (goodImage.size() == img.size()); + if (doDiff) { + QImage diffimg(m_view->width(), m_view->height(), QImage::Format_RGB32); + diffimg.fill(qRgb(255,255,255)); + QPainter p(&diffimg); + int diffCount = 0; + for (int x = 0; x < img.width(); ++x) { + for (int y = 0; y < img.height(); ++y) { + if (goodImage.pixel(x,y) != img.pixel(x,y)) { + ++diffCount; + p.drawPoint(x,y); + } + } + } + QString diff(frame->image().toLocalFile() + ".diff.png"); + diffimg.save(diff); + qWarning().nospace() << " Diff (" << diffCount << " pixels differed) saved to: " << diff; + } + imagefailure(); + } + } + } else if (QDeclarativeVisualTestMouse *mouse = qobject_cast<QDeclarativeVisualTestMouse *>(event)) { + QPoint pos(mouse->x(), mouse->y()); + QPoint globalPos = m_view->mapToGlobal(QPoint(0, 0)) + pos; + QMouseEvent event((QEvent::Type)mouse->type(), pos, globalPos, (Qt::MouseButton)mouse->button(), (Qt::MouseButtons)mouse->buttons(), (Qt::KeyboardModifiers)mouse->modifiers()); + + MouseEvent me(&event); + me.msec = msec; + if (!mouse->sendToViewport()) { + QCoreApplication::sendEvent(m_view, &event); + me.destination = View; + } else { + QCoreApplication::sendEvent(m_view->viewport(), &event); + me.destination = ViewPort; + } + m_savedMouseEvents.append(me); + } else if (QDeclarativeVisualTestKey *key = qobject_cast<QDeclarativeVisualTestKey *>(event)) { + + QKeyEvent event((QEvent::Type)key->type(), key->key(), (Qt::KeyboardModifiers)key->modifiers(), QString::fromUtf8(QByteArray::fromHex(key->text().toUtf8())), key->autorep(), key->count()); + + KeyEvent ke(&event); + ke.msec = msec; + if (!key->sendToViewport()) { + QCoreApplication::sendEvent(m_view, &event); + ke.destination = View; + } else { + QCoreApplication::sendEvent(m_view->viewport(), &event); + ke.destination = ViewPort; + } + m_savedKeyEvents.append(ke); + } + testscriptidx++; + } + + filterEvents = true; + + if (testscript && testscript->count() <= testscriptidx) { + //if (msec == 16) //for a snapshot, leave it up long enough to see + // (void)::sleep(1); + complete(); + } +} + +void QDeclarativeTester::registerTypes() +{ + qmlRegisterType<QDeclarativeVisualTest>("Qt.VisualTest", 4,7, "VisualTest"); + qmlRegisterType<QDeclarativeVisualTestFrame>("Qt.VisualTest", 4,7, "Frame"); + qmlRegisterType<QDeclarativeVisualTestMouse>("Qt.VisualTest", 4,7, "Mouse"); + qmlRegisterType<QDeclarativeVisualTestKey>("Qt.VisualTest", 4,7, "Key"); +} + +QT_END_NAMESPACE diff --git a/tools/qml/qdeclarativetester.h b/tools/qml/qdeclarativetester.h new file mode 100644 index 0000000..d49c9b8 --- /dev/null +++ b/tools/qml/qdeclarativetester.h @@ -0,0 +1,286 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVETESTER_H +#define QDECLARATIVETESTER_H + +#include <QEvent> +#include <QMouseEvent> +#include <QKeyEvent> +#include <QImage> +#include <QUrl> +#include <qmlruntime.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeVisualTest : public QObject +{ + Q_OBJECT + Q_PROPERTY(QDeclarativeListProperty<QObject> events READ events CONSTANT) + Q_CLASSINFO("DefaultProperty", "events") +public: + QDeclarativeVisualTest() {} + + QDeclarativeListProperty<QObject> events() { return QDeclarativeListProperty<QObject>(this, m_events); } + + int count() const { return m_events.count(); } + QObject *event(int idx) { return m_events.at(idx); } + +private: + QList<QObject *> m_events; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeVisualTest) + +QT_BEGIN_NAMESPACE + +class QDeclarativeVisualTestFrame : public QObject +{ + Q_OBJECT + Q_PROPERTY(int msec READ msec WRITE setMsec) + Q_PROPERTY(QString hash READ hash WRITE setHash) + Q_PROPERTY(QUrl image READ image WRITE setImage) +public: + QDeclarativeVisualTestFrame() : m_msec(-1) {} + + int msec() const { return m_msec; } + void setMsec(int m) { m_msec = m; } + + QString hash() const { return m_hash; } + void setHash(const QString &hash) { m_hash = hash; } + + QUrl image() const { return m_image; } + void setImage(const QUrl &image) { m_image = image; } + +private: + int m_msec; + QString m_hash; + QUrl m_image; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeVisualTestFrame) + +QT_BEGIN_NAMESPACE + +class QDeclarativeVisualTestMouse : public QObject +{ + Q_OBJECT + Q_PROPERTY(int type READ type WRITE setType) + Q_PROPERTY(int button READ button WRITE setButton) + Q_PROPERTY(int buttons READ buttons WRITE setButtons) + Q_PROPERTY(int x READ x WRITE setX) + Q_PROPERTY(int y READ y WRITE setY) + Q_PROPERTY(int modifiers READ modifiers WRITE setModifiers) + Q_PROPERTY(bool sendToViewport READ sendToViewport WRITE setSendToViewport) +public: + QDeclarativeVisualTestMouse() : m_type(0), m_button(0), m_buttons(0), m_x(0), m_y(0), m_modifiers(0), m_viewport(false) {} + + int type() const { return m_type; } + void setType(int t) { m_type = t; } + + int button() const { return m_button; } + void setButton(int b) { m_button = b; } + + int buttons() const { return m_buttons; } + void setButtons(int b) { m_buttons = b; } + + int x() const { return m_x; } + void setX(int x) { m_x = x; } + + int y() const { return m_y; } + void setY(int y) { m_y = y; } + + int modifiers() const { return m_modifiers; } + void setModifiers(int modifiers) { m_modifiers = modifiers; } + + bool sendToViewport() const { return m_viewport; } + void setSendToViewport(bool v) { m_viewport = v; } +private: + int m_type; + int m_button; + int m_buttons; + int m_x; + int m_y; + int m_modifiers; + bool m_viewport; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeVisualTestMouse) + +QT_BEGIN_NAMESPACE + +class QDeclarativeVisualTestKey : public QObject +{ + Q_OBJECT + Q_PROPERTY(int type READ type WRITE setType) + Q_PROPERTY(int key READ key WRITE setKey) + Q_PROPERTY(int modifiers READ modifiers WRITE setModifiers) + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(bool autorep READ autorep WRITE setAutorep) + Q_PROPERTY(int count READ count WRITE setCount) + Q_PROPERTY(bool sendToViewport READ sendToViewport WRITE setSendToViewport) +public: + QDeclarativeVisualTestKey() : m_type(0), m_key(0), m_modifiers(0), m_autorep(false), m_count(0), m_viewport(false) {} + + int type() const { return m_type; } + void setType(int t) { m_type = t; } + + int key() const { return m_key; } + void setKey(int k) { m_key = k; } + + int modifiers() const { return m_modifiers; } + void setModifiers(int m) { m_modifiers = m; } + + QString text() const { return m_text; } + void setText(const QString &t) { m_text = t; } + + bool autorep() const { return m_autorep; } + void setAutorep(bool a) { m_autorep = a; } + + int count() const { return m_count; } + void setCount(int c) { m_count = c; } + + bool sendToViewport() const { return m_viewport; } + void setSendToViewport(bool v) { m_viewport = v; } +private: + int m_type; + int m_key; + int m_modifiers; + QString m_text; + bool m_autorep; + int m_count; + bool m_viewport; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeVisualTestKey) + +QT_BEGIN_NAMESPACE + +class QDeclarativeTester : public QAbstractAnimation +{ +public: + QDeclarativeTester(const QString &script, QDeclarativeViewer::ScriptOptions options, QDeclarativeView *parent); + ~QDeclarativeTester(); + + static void registerTypes(); + + virtual int duration() const; + + void run(); + void save(); + + void executefailure(); +protected: + virtual void updateCurrentTime(int msecs); + virtual bool eventFilter(QObject *, QEvent *); + +private: + QString m_script; + + void imagefailure(); + void complete(); + + enum Destination { View, ViewPort }; + void addKeyEvent(Destination, QKeyEvent *); + void addMouseEvent(Destination, QMouseEvent *); + QDeclarativeView *m_view; + + struct MouseEvent { + MouseEvent(QMouseEvent *e) + : type(e->type()), button(e->button()), buttons(e->buttons()), + pos(e->pos()), modifiers(e->modifiers()), destination(View) {} + + QEvent::Type type; + Qt::MouseButton button; + Qt::MouseButtons buttons; + QPoint pos; + Qt::KeyboardModifiers modifiers; + Destination destination; + + int msec; + }; + struct KeyEvent { + KeyEvent(QKeyEvent *e) + : type(e->type()), key(e->key()), modifiers(e->modifiers()), text(e->text()), + autorep(e->isAutoRepeat()), count(e->count()), destination(View) {} + QEvent::Type type; + int key; + Qt::KeyboardModifiers modifiers; + QString text; + bool autorep; + ushort count; + Destination destination; + + int msec; + }; + struct FrameEvent { + QImage image; + QByteArray hash; + int msec; + }; + QList<MouseEvent> m_mouseEvents; + QList<KeyEvent> m_keyEvents; + + QList<MouseEvent> m_savedMouseEvents; + QList<KeyEvent> m_savedKeyEvents; + QList<FrameEvent> m_savedFrameEvents; + bool filterEvents; + + QDeclarativeViewer::ScriptOptions options; + int testscriptidx; + QDeclarativeVisualTest *testscript; + + bool hasCompleted; + bool hasFailed; +}; + + +QT_END_NAMESPACE + +#endif // QDECLARATIVETESTER_H diff --git a/tools/qml/qml.icns b/tools/qml/qml.icns Binary files differnew file mode 100644 index 0000000..c760516 --- /dev/null +++ b/tools/qml/qml.icns diff --git a/tools/qml/qml.pri b/tools/qml/qml.pri new file mode 100644 index 0000000..5e3e74b --- /dev/null +++ b/tools/qml/qml.pri @@ -0,0 +1,32 @@ +QT += declarative script network sql +contains(QT_CONFIG, opengl) { + QT += opengl + DEFINES += GL_SUPPORTED +} + +INCLUDEPATH += $$PWD + +HEADERS += $$PWD/qmlruntime.h \ + $$PWD/proxysettings.h \ + $$PWD/qdeclarativetester.h \ + $$PWD/deviceorientation.h \ + $$PWD/loggerwidget.h +SOURCES += $$PWD/qmlruntime.cpp \ + $$PWD/proxysettings.cpp \ + $$PWD/qdeclarativetester.cpp \ + $$PWD/loggerwidget.cpp + +RESOURCES = $$PWD/qmlruntime.qrc +maemo5 { + SOURCES += $$PWD/deviceorientation_maemo.cpp +} else { + SOURCES += $$PWD/deviceorientation.cpp +} + +symbian { + INCLUDEPATH += $$QT_SOURCE_TREE/examples/network/qftp/ + LIBS += -lesock -lcommdb -lconnmon -linsock +} + +FORMS = $$PWD/recopts.ui \ + $$PWD/proxysettings.ui diff --git a/tools/qml/qml.pro b/tools/qml/qml.pro new file mode 100644 index 0000000..9cdec77 --- /dev/null +++ b/tools/qml/qml.pro @@ -0,0 +1,44 @@ +TEMPLATE = app +CONFIG += qt uic +DESTDIR = ../../bin + +include(qml.pri) + +SOURCES += main.cpp + +INCLUDEPATH += ../../include/QtDeclarative +INCLUDEPATH += ../../src/declarative/util +INCLUDEPATH += ../../src/declarative/graphicsitems + +target.path = $$[QT_INSTALL_BINS] +INSTALLS += target + +wince* { + QT += xml + + contains(QT_CONFIG, scripttools) { + QT += scripttools + } + contains(QT_CONFIG, phonon) { + QT += phonon + } + contains(QT_CONFIG, xmlpatterns) { + QT += xmlpatterns + } + contains(QT_CONFIG, webkit) { + QT += webkit + } +} +symbian { + TARGET.UID3 = 0x20021317 + include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) + TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 + TARGET.CAPABILITY = NetworkServices ReadUserData +} +mac { + QMAKE_INFO_PLIST=Info_mac.plist + TARGET=QMLViewer + ICON=qml.icns +} else { + TARGET=qmlviewer +} diff --git a/tools/qml/qmlruntime.cpp b/tools/qml/qmlruntime.cpp new file mode 100644 index 0000000..5136872 --- /dev/null +++ b/tools/qml/qmlruntime.cpp @@ -0,0 +1,1296 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qdeclarativeview.h> + +#ifdef hz +#undef hz +#endif +#include "ui_recopts.h" + +#include "qmlruntime.h" +#include <qdeclarativecontext.h> +#include <qdeclarativeengine.h> +#include <qdeclarativenetworkaccessmanagerfactory.h> +#include "qdeclarative.h" +#include <private/qabstractanimation_p.h> +#include <QAbstractAnimation> + +#include <QSettings> +#include <QXmlStreamReader> +#include <QBuffer> +#include <QNetworkReply> +#include <QNetworkCookieJar> +#include <QNetworkDiskCache> +#include <QNetworkAccessManager> +#include <QSignalMapper> +#include <QDeclarativeComponent> +#include <QWidget> +#include <QApplication> +#include <QTranslator> +#include <QDir> +#include <QTextBrowser> +#include <QFile> +#include <QFileInfo> +#include <QVBoxLayout> +#include <QProgressDialog> +#include <QProcess> +#include <QMenuBar> +#include <QMenu> +#include <QAction> +#include <QFileDialog> +#include <QTimer> +#include <QGraphicsObject> +#include <QNetworkProxyFactory> +#include <QKeyEvent> +#include <QMutex> +#include <QMutexLocker> +#include "proxysettings.h" +#include "deviceorientation.h" + +#ifdef GL_SUPPORTED +#include <QGLWidget> +#endif + +#include <qdeclarativetester.h> + +#if defined (Q_OS_SYMBIAN) +#define SYMBIAN_NETWORK_INIT +#endif + +#if defined (SYMBIAN_NETWORK_INIT) +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <QTextCodec> +#include "sym_iap_util.h" +#endif + +QT_BEGIN_NAMESPACE + +class Runtime : public QObject +{ + Q_OBJECT + + Q_PROPERTY(bool isActiveWindow READ isActiveWindow NOTIFY isActiveWindowChanged) + Q_PROPERTY(DeviceOrientation::Orientation orientation READ orientation NOTIFY orientationChanged) + +public: + static Runtime* instance() + { + static Runtime *instance = 0; + if (!instance) + instance = new Runtime; + return instance; + } + + bool isActiveWindow() const { return activeWindow; } + void setActiveWindow(bool active) + { + if (active == activeWindow) + return; + activeWindow = active; + emit isActiveWindowChanged(); + } + + DeviceOrientation::Orientation orientation() const { return DeviceOrientation::instance()->orientation(); } + +Q_SIGNALS: + void isActiveWindowChanged(); + void orientationChanged(); + +private: + Runtime(QObject *parent=0) : QObject(parent), activeWindow(false) + { + connect(DeviceOrientation::instance(), SIGNAL(orientationChanged()), + this, SIGNAL(orientationChanged())); + } + + bool activeWindow; +}; + + +class SizedMenuBar : public QMenuBar +{ + Q_OBJECT +public: + SizedMenuBar(QWidget *parent, QWidget *referenceWidget) + : QMenuBar(parent), refWidget(referenceWidget) + { + } + + virtual QSize sizeHint() const + { + return QSize(refWidget->sizeHint().width(), QMenuBar::sizeHint().height()); + } + +private: + QWidget *refWidget; +}; + +static struct { const char *name, *args; } ffmpegprofiles[] = { + {"Maximum Quality", "-sameq"}, + {"High Quality", "-qmax 2"}, + {"Medium Quality", "-qmax 6"}, + {"Low Quality", "-qmax 16"}, + {"Custom ffmpeg arguments", ""}, + {0,0} +}; + +class RecordingDialog : public QDialog, public Ui::RecordingOptions { + Q_OBJECT + +public: + RecordingDialog(QWidget *parent) : QDialog(parent) + { + setupUi(this); + hz->setValidator(new QDoubleValidator(hz)); + for (int i=0; ffmpegprofiles[i].name; ++i) { + profile->addItem(ffmpegprofiles[i].name); + } + } + + void setArguments(QString a) + { + int i; + for (i=0; ffmpegprofiles[i].args[0]; ++i) { + if (ffmpegprofiles[i].args == a) { + profile->setCurrentIndex(i); + args->setText(QLatin1String(ffmpegprofiles[i].args)); + return; + } + } + customargs = a; + args->setText(a); + profile->setCurrentIndex(i); + } + + QString arguments() const + { + int i = profile->currentIndex(); + return ffmpegprofiles[i].args[0] ? QLatin1String(ffmpegprofiles[i].args) : customargs; + } + +private slots: + void pickProfile(int i) + { + if (ffmpegprofiles[i].args[0]) { + args->setText(QLatin1String(ffmpegprofiles[i].args)); + } else { + args->setText(customargs); + } + } + + void storeCustomArgs(QString s) + { + setArguments(s); + } + +private: + QString customargs; +}; + +class PersistentCookieJar : public QNetworkCookieJar { +public: + PersistentCookieJar(QObject *parent) : QNetworkCookieJar(parent) { load(); } + ~PersistentCookieJar() { save(); } + + virtual QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const + { + QMutexLocker lock(&mutex); + return QNetworkCookieJar::cookiesForUrl(url); + } + + virtual bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) + { + QMutexLocker lock(&mutex); + return QNetworkCookieJar::setCookiesFromUrl(cookieList, url); + } + +private: + void save() + { + QMutexLocker lock(&mutex); + QList<QNetworkCookie> list = allCookies(); + QByteArray data; + foreach (QNetworkCookie cookie, list) { + if (!cookie.isSessionCookie()) { + data.append(cookie.toRawForm()); + data.append("\n"); + } + } + QSettings settings; + settings.setValue("Cookies",data); + } + + void load() + { + QMutexLocker lock(&mutex); + QSettings settings; + QByteArray data = settings.value("Cookies").toByteArray(); + setAllCookies(QNetworkCookie::parseCookies(data)); + } + + mutable QMutex mutex; +}; + +class NetworkAccessManagerFactory : public QDeclarativeNetworkAccessManagerFactory +{ +public: + NetworkAccessManagerFactory() : cacheSize(0) {} + ~NetworkAccessManagerFactory() {} + + QNetworkAccessManager *create(QObject *parent); + + void setupProxy(QNetworkAccessManager *nam) + { + class SystemProxyFactory : public QNetworkProxyFactory + { + public: + virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query) + { + QString protocolTag = query.protocolTag(); + if (httpProxyInUse && (protocolTag == "http" || protocolTag == "https")) { + QList<QNetworkProxy> ret; + ret << httpProxy; + return ret; + } + return QNetworkProxyFactory::systemProxyForQuery(query); + } + void setHttpProxy (QNetworkProxy proxy) + { + httpProxy = proxy; + httpProxyInUse = true; + } + void unsetHttpProxy () + { + httpProxyInUse = false; + } + private: + bool httpProxyInUse; + QNetworkProxy httpProxy; + }; + + SystemProxyFactory *proxyFactory = new SystemProxyFactory; + if (ProxySettings::httpProxyInUse()) + proxyFactory->setHttpProxy(ProxySettings::httpProxy()); + else + proxyFactory->unsetHttpProxy(); + nam->setProxyFactory(proxyFactory); + } + + void setCacheSize(int size) { + if (size != cacheSize) { + cacheSize = size; + } + } + + static PersistentCookieJar *cookieJar; + QMutex mutex; + int cacheSize; +}; + +PersistentCookieJar *NetworkAccessManagerFactory::cookieJar = 0; + +static void cleanup_cookieJar() +{ + delete NetworkAccessManagerFactory::cookieJar; + NetworkAccessManagerFactory::cookieJar = 0; +} + +QNetworkAccessManager *NetworkAccessManagerFactory::create(QObject *parent) +{ + QMutexLocker lock(&mutex); + QNetworkAccessManager *manager = new QNetworkAccessManager(parent); + if (!cookieJar) { + qAddPostRoutine(cleanup_cookieJar); + cookieJar = new PersistentCookieJar(0); + } + manager->setCookieJar(cookieJar); + cookieJar->setParent(0); + setupProxy(manager); + if (cacheSize > 0) { + QNetworkDiskCache *cache = new QNetworkDiskCache; + cache->setCacheDirectory(QDir::tempPath()+QLatin1String("/qml-viewer-network-cache")); + cache->setMaximumCacheSize(cacheSize); + manager->setCache(cache); + } else { + manager->setCache(0); + } + qDebug() << "created new network access manager for" << parent; + return manager; +} + +QString QDeclarativeViewer::getVideoFileName() +{ + QString title = convertAvailable || ffmpegAvailable ? tr("Save Video File") : tr("Save PNG Frames"); + QStringList types; + if (ffmpegAvailable) types += tr("Common Video files")+QLatin1String(" (*.avi *.mpeg *.mov)"); + if (convertAvailable) types += tr("GIF Animation")+QLatin1String(" (*.gif)"); + types += tr("Individual PNG frames")+QLatin1String(" (*.png)"); + if (ffmpegAvailable) types += tr("All ffmpeg formats (*.*)"); + return QFileDialog::getSaveFileName(this, title, "", types.join(";; ")); +} + + +QDeclarativeViewer::QDeclarativeViewer(QWidget *parent, Qt::WindowFlags flags) +#if defined(Q_OS_SYMBIAN) + : QMainWindow(parent, flags) +#else + : QWidget(parent, flags) +#endif + , loggerWindow(new LoggerWidget()) + , frame_stream(0), mb(0) + , portraitOrientation(0), landscapeOrientation(0) + , showWarningsWindow(0) + , m_scriptOptions(0) + , tester(0) + , useQmlFileBrowser(true) + , translator(0) +{ + QDeclarativeViewer::registerTypes(); + setWindowTitle(tr("Qt QML Viewer")); + + devicemode = false; + canvas = 0; + record_autotime = 0; + record_rate = 50; + record_args += QLatin1String("-sameq"); + + recdlg = new RecordingDialog(this); + connect(recdlg->pickfile, SIGNAL(clicked()), this, SLOT(pickRecordingFile())); + senseFfmpeg(); + senseImageMagick(); + if (!ffmpegAvailable) + recdlg->ffmpegOptions->hide(); + if (!ffmpegAvailable && !convertAvailable) + recdlg->rateOptions->hide(); + QString warn; + if (!ffmpegAvailable) { + if (!convertAvailable) + warn = tr("ffmpeg and ImageMagick not available - no video output"); + else + warn = tr("ffmpeg not available - GIF and PNG outputs only"); + recdlg->warning->setText(warn); + } else { + recdlg->warning->hide(); + } + + canvas = new QDeclarativeView(this); + + canvas->setAttribute(Qt::WA_OpaquePaintEvent); + canvas->setAttribute(Qt::WA_NoSystemBackground); + + canvas->setFocus(); + + QObject::connect(canvas, SIGNAL(sceneResized(QSize)), this, SLOT(sceneResized(QSize))); + QObject::connect(canvas, SIGNAL(statusChanged(QDeclarativeView::Status)), this, SLOT(statusChanged())); + QObject::connect(canvas->engine(), SIGNAL(quit()), QCoreApplication::instance (), SLOT(quit())); + + QObject::connect(warningsWidget(), SIGNAL(opened()), this, SLOT(warningsWidgetOpened())); + QObject::connect(warningsWidget(), SIGNAL(closed()), this, SLOT(warningsWidgetClosed())); + + if (!(flags & Qt::FramelessWindowHint)) { + createMenu(menuBar(),0); + setPortrait(); + } + +#if !defined(Q_OS_SYMBIAN) + QVBoxLayout *layout = new QVBoxLayout; + layout->setMargin(0); + layout->setSpacing(0); + setLayout(layout); + if (mb) + layout->addWidget(mb); + layout->addWidget(canvas); +#else + setCentralWidget(canvas); +#endif + namFactory = new NetworkAccessManagerFactory; + canvas->engine()->setNetworkAccessManagerFactory(namFactory); + + connect(&autoStartTimer, SIGNAL(triggered()), this, SLOT(autoStartRecording())); + connect(&autoStopTimer, SIGNAL(triggered()), this, SLOT(autoStopRecording())); + connect(&recordTimer, SIGNAL(triggered()), this, SLOT(recordFrame())); + connect(DeviceOrientation::instance(), SIGNAL(orientationChanged()), + this, SLOT(orientationChanged()), Qt::QueuedConnection); + autoStartTimer.setRunning(false); + autoStopTimer.setRunning(false); + recordTimer.setRunning(false); + recordTimer.setRepeating(true); +} + +QDeclarativeViewer::~QDeclarativeViewer() +{ + delete loggerWindow; + canvas->engine()->setNetworkAccessManagerFactory(0); + delete namFactory; +} + +void QDeclarativeViewer::enableExperimentalGestures() +{ + canvas->viewport()->grabGesture(Qt::TapGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent); + canvas->viewport()->grabGesture(Qt::TapAndHoldGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent); + canvas->viewport()->grabGesture(Qt::PanGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent); + canvas->viewport()->grabGesture(Qt::PinchGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent); + canvas->viewport()->grabGesture(Qt::SwipeGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent); + canvas->viewport()->setAttribute(Qt::WA_AcceptTouchEvents); +} + +int QDeclarativeViewer::menuBarHeight() const +{ + if (!(windowFlags() & Qt::FramelessWindowHint)) + return menuBar()->height(); + else + return 0; // don't create menu +} + +QMenuBar *QDeclarativeViewer::menuBar() const +{ +#if !defined(Q_OS_SYMBIAN) + if (!mb) + mb = new SizedMenuBar((QWidget*)this, canvas); +#else + mb = QMainWindow::menuBar(); +#endif + + return mb; +} + +QDeclarativeView *QDeclarativeViewer::view() const +{ + return canvas; +} + +LoggerWidget *QDeclarativeViewer::warningsWidget() const +{ + return loggerWindow; +} + +void QDeclarativeViewer::createMenu(QMenuBar *menu, QMenu *flatmenu) +{ + QObject *parent = flatmenu ? (QObject*)flatmenu : (QObject*)menu; + + QMenu *fileMenu = flatmenu ? flatmenu : menu->addMenu(tr("&File")); + + QAction *openAction = new QAction(tr("&Open..."), parent); + openAction->setShortcut(QKeySequence("Ctrl+O")); + connect(openAction, SIGNAL(triggered()), this, SLOT(openFile())); + fileMenu->addAction(openAction); + + QAction *reloadAction = new QAction(tr("&Reload"), parent); + reloadAction->setShortcut(QKeySequence("Ctrl+R")); + connect(reloadAction, SIGNAL(triggered()), this, SLOT(reload())); + fileMenu->addAction(reloadAction); + +#if defined(Q_OS_SYMBIAN) + QAction *networkAction = new QAction(tr("Start &Network"), parent); + connect(networkAction, SIGNAL(triggered()), this, SLOT(startNetwork())); + fileMenu->addAction(networkAction); +#endif + +#if !defined(Q_OS_SYMBIAN) + if (flatmenu) flatmenu->addSeparator(); + + QMenu *recordMenu = flatmenu ? flatmenu : menu->addMenu(tr("&Recording")); + + QAction *snapshotAction = new QAction(tr("&Take Snapshot\tF3"), parent); + connect(snapshotAction, SIGNAL(triggered()), this, SLOT(takeSnapShot())); + recordMenu->addAction(snapshotAction); + + recordAction = new QAction(tr("Start Recording &Video\tF9"), parent); + connect(recordAction, SIGNAL(triggered()), this, SLOT(toggleRecordingWithSelection())); + recordMenu->addAction(recordAction); + + QAction *recordOptions = new QAction(tr("Video &Options..."), parent); + connect(recordOptions, SIGNAL(triggered()), this, SLOT(chooseRecordingOptions())); + + if (flatmenu) + flatmenu->addAction(recordOptions); + + if (flatmenu) flatmenu->addSeparator(); + + QMenu *debugMenu = flatmenu ? flatmenu->addMenu(tr("&Debugging")) : menu->addMenu(tr("&Debugging")); + + QAction *slowAction = new QAction(tr("&Slow Down Animations"), parent); + slowAction->setShortcut(QKeySequence("Ctrl+.")); + slowAction->setCheckable(true); + connect(slowAction, SIGNAL(triggered(bool)), this, SLOT(setSlowMode(bool))); + debugMenu->addAction(slowAction); + + showWarningsWindow = new QAction(tr("Show Warnings"), parent); + showWarningsWindow->setCheckable((true)); + showWarningsWindow->setChecked(loggerWindow->isVisible()); + connect(showWarningsWindow, SIGNAL(triggered(bool)), this, SLOT(showWarnings(bool))); + +#if !defined(Q_OS_SYMBIAN) + debugMenu->addAction(showWarningsWindow); +#endif + + if (flatmenu) flatmenu->addSeparator(); + +#endif // Q_OS_SYMBIAN + + QMenu *settingsMenu = flatmenu ? flatmenu : menu->addMenu(tr("S&ettings")); + QAction *proxyAction = new QAction(tr("Http &proxy..."), parent); + connect(proxyAction, SIGNAL(triggered()), this, SLOT(showProxySettings())); + settingsMenu->addAction(proxyAction); +#if !defined(Q_OS_SYMBIAN) + if (!flatmenu) + settingsMenu->addAction(recordOptions); + + settingsMenu->addMenu(loggerWindow->preferencesMenu()); +#else + QAction *fullscreenAction = new QAction(tr("Full Screen"), parent); + fullscreenAction->setCheckable(true); + connect(fullscreenAction, SIGNAL(triggered()), this, SLOT(toggleFullScreen())); + settingsMenu->addAction(fullscreenAction); +#endif + + if (flatmenu) flatmenu->addSeparator(); + + QMenu *propertiesMenu = settingsMenu->addMenu(tr("Properties")); + + QActionGroup *orientation = new QActionGroup(parent); + + QAction *toggleOrientation = new QAction(tr("&Toggle Orientation"), parent); + toggleOrientation->setCheckable(true); + toggleOrientation->setShortcut(QKeySequence("Ctrl+T")); + settingsMenu->addAction(toggleOrientation); + connect(toggleOrientation, SIGNAL(triggered()), this, SLOT(toggleOrientation())); + + orientation->setExclusive(true); + portraitOrientation = new QAction(tr("orientation: Portrait"), parent); + portraitOrientation->setCheckable(true); + connect(portraitOrientation, SIGNAL(triggered()), this, SLOT(setPortrait())); + orientation->addAction(portraitOrientation); + propertiesMenu->addAction(portraitOrientation); + + landscapeOrientation = new QAction(tr("orientation: Landscape"), parent); + landscapeOrientation->setCheckable(true); + connect(landscapeOrientation, SIGNAL(triggered()), this, SLOT(setLandscape())); + orientation->addAction(landscapeOrientation); + propertiesMenu->addAction(landscapeOrientation); + + if (flatmenu) flatmenu->addSeparator(); + + QMenu *helpMenu = flatmenu ? flatmenu : menu->addMenu(tr("&Help")); + QAction *aboutAction = new QAction(tr("&About Qt..."), parent); + connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); + helpMenu->addAction(aboutAction); + + QAction *quitAction = new QAction(tr("&Quit"), parent); + quitAction->setShortcut(QKeySequence("Ctrl+Q")); + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + fileMenu->addSeparator(); + fileMenu->addAction(quitAction); + if (menu) { + menu->setFixedHeight(menu->sizeHint().height()); + menu->setMinimumWidth(10); + } +} + +void QDeclarativeViewer::showProxySettings() +{ + ProxySettings settingsDlg (this); + + connect (&settingsDlg, SIGNAL (accepted()), this, SLOT (proxySettingsChanged ())); + + settingsDlg.exec(); +} + +void QDeclarativeViewer::proxySettingsChanged() +{ + reload (); +} + +void QDeclarativeViewer::setPortrait() +{ + DeviceOrientation::instance()->setOrientation(DeviceOrientation::Portrait); + portraitOrientation->setChecked(true); +} + +void QDeclarativeViewer::setLandscape() +{ + DeviceOrientation::instance()->setOrientation(DeviceOrientation::Landscape); + landscapeOrientation->setChecked(true); +} + +void QDeclarativeViewer::toggleOrientation() +{ + DeviceOrientation::instance()->setOrientation(DeviceOrientation::instance()->orientation()==DeviceOrientation::Portrait?DeviceOrientation::Landscape:DeviceOrientation::Portrait); +} + +void QDeclarativeViewer::toggleFullScreen() +{ + if (isFullScreen()) + showMaximized(); + else + showFullScreen(); +} + +void QDeclarativeViewer::showWarnings(bool show) +{ + loggerWindow->setVisible(show); +} + +void QDeclarativeViewer::warningsWidgetOpened() +{ + showWarningsWindow->setChecked(true); +} + +void QDeclarativeViewer::warningsWidgetClosed() +{ + showWarningsWindow->setChecked(false); +} + +void QDeclarativeViewer::takeSnapShot() +{ + static int snapshotcount = 1; + QString snapFileName = QString(QLatin1String("snapshot%1.png")).arg(snapshotcount); + QPixmap::grabWidget(canvas).save(snapFileName); + qDebug() << "Wrote" << snapFileName; + ++snapshotcount; +} + +void QDeclarativeViewer::pickRecordingFile() +{ + QString fileName = getVideoFileName(); + if (!fileName.isEmpty()) + recdlg->file->setText(fileName); +} + +void QDeclarativeViewer::chooseRecordingOptions() +{ + // File + recdlg->file->setText(record_file); + + // Size + recdlg->sizeOriginal->setText(tr("Original (%1x%2)").arg(canvas->width()).arg(canvas->height())); + if (recdlg->sizeWidth->value()<=1) { + recdlg->sizeWidth->setValue(canvas->width()); + recdlg->sizeHeight->setValue(canvas->height()); + } + + // Rate + if (record_rate == 24) + recdlg->hz24->setChecked(true); + else if (record_rate == 25) + recdlg->hz25->setChecked(true); + else if (record_rate == 50) + recdlg->hz50->setChecked(true); + else if (record_rate == 60) + recdlg->hz60->setChecked(true); + else { + recdlg->hzCustom->setChecked(true); + recdlg->hz->setText(QString::number(record_rate)); + } + + // Profile + recdlg->setArguments(record_args.join(" ")); + if (recdlg->exec()) { + // File + record_file = recdlg->file->text(); + // Size + if (recdlg->sizeOriginal->isChecked()) + record_outsize = QSize(); + else if (recdlg->size720p->isChecked()) + record_outsize = QSize(1280,720); + else if (recdlg->sizeVGA->isChecked()) + record_outsize = QSize(640,480); + else if (recdlg->sizeQVGA->isChecked()) + record_outsize = QSize(320,240); + else + record_outsize = QSize(recdlg->sizeWidth->value(),recdlg->sizeHeight->value()); + // Rate + if (recdlg->hz24->isChecked()) + record_rate = 24; + else if (recdlg->hz25->isChecked()) + record_rate = 25; + else if (recdlg->hz50->isChecked()) + record_rate = 50; + else if (recdlg->hz60->isChecked()) + record_rate = 60; + else { + record_rate = recdlg->hz->text().toDouble(); + } + // Profile + record_args = recdlg->arguments().split(" ",QString::SkipEmptyParts); + } +} + +void QDeclarativeViewer::toggleRecordingWithSelection() +{ + if (!recordTimer.isRunning()) { + if (record_file.isEmpty()) { + QString fileName = getVideoFileName(); + if (fileName.isEmpty()) + return; + if (!fileName.contains(QRegExp(".[^\\/]*$"))) + fileName += ".avi"; + setRecordFile(fileName); + } + } + toggleRecording(); +} + +void QDeclarativeViewer::toggleRecording() +{ + if (record_file.isEmpty()) { + toggleRecordingWithSelection(); + return; + } + bool recording = !recordTimer.isRunning(); + recordAction->setText(recording ? tr("&Stop Recording Video\tF9") : tr("&Start Recording Video\tF9")); + setRecording(recording); +} + +void QDeclarativeViewer::setSlowMode(bool enable) +{ + QUnifiedTimer::instance()->setSlowModeEnabled(enable); +} + +void QDeclarativeViewer::addLibraryPath(const QString& lib) +{ + canvas->engine()->addImportPath(lib); +} + +void QDeclarativeViewer::addPluginPath(const QString& plugin) +{ + canvas->engine()->addPluginPath(plugin); +} + +void QDeclarativeViewer::reload() +{ + open(currentFileOrUrl); +} + +void QDeclarativeViewer::openFile() +{ + QString cur = canvas->source().toLocalFile(); + if (useQmlFileBrowser) { + open("qrc:/content/Browser.qml"); + } else { + QString fileName = QFileDialog::getOpenFileName(this, tr("Open QML file"), cur, tr("QML Files (*.qml)")); + if (!fileName.isEmpty()) { + QFileInfo fi(fileName); + open(fi.absoluteFilePath()); + } + } +} + +void QDeclarativeViewer::statusChanged() +{ + if (canvas->status() == QDeclarativeView::Error && tester) + tester->executefailure(); + + if (canvas->status() == QDeclarativeView::Ready) { + initialSize = canvas->sizeHint(); + if (canvas->resizeMode() == QDeclarativeView::SizeRootObjectToView) { + updateSizeHints(); + resize(QSize(initialSize.width(), initialSize.height()+menuBarHeight())); + } + } +} + +void QDeclarativeViewer::launch(const QString& file_or_url) +{ + QMetaObject::invokeMethod(this, "open", Qt::QueuedConnection, Q_ARG(QString, file_or_url)); +} + +void QDeclarativeViewer::loadTranslationFile(const QString& directory) +{ + if (!translator) { + translator = new QTranslator(this); + QApplication::installTranslator(translator); + } + + translator->load(QLatin1String("qml_" )+QLocale::system().name(), directory + QLatin1String("/i18n")); +} + +void QDeclarativeViewer::loadDummyDataFiles(const QString& directory) +{ + QDir dir(directory+"/dummydata", "*.qml"); + QStringList list = dir.entryList(); + for (int i = 0; i < list.size(); ++i) { + QString qml = list.at(i); + QFile f(dir.filePath(qml)); + f.open(QIODevice::ReadOnly); + QByteArray data = f.readAll(); + QDeclarativeComponent comp(canvas->engine()); + comp.setData(data, QUrl()); + QObject *dummyData = comp.create(); + + if(comp.isError()) { + QList<QDeclarativeError> errors = comp.errors(); + foreach (const QDeclarativeError &error, errors) { + qWarning() << error; + } + if (tester) tester->executefailure(); + } + + if (dummyData) { + qWarning() << "Loaded dummy data:" << dir.filePath(qml); + qml.truncate(qml.length()-4); + canvas->rootContext()->setContextProperty(qml, dummyData); + dummyData->setParent(this); + } + } +} + +bool QDeclarativeViewer::open(const QString& file_or_url) +{ + currentFileOrUrl = file_or_url; + + QUrl url; + QFileInfo fi(file_or_url); + if (fi.exists()) + url = QUrl::fromLocalFile(fi.absoluteFilePath()); + else + url = QUrl(file_or_url); + setWindowTitle(tr("%1 - Qt QML Viewer").arg(file_or_url)); + + if (!m_script.isEmpty()) + tester = new QDeclarativeTester(m_script, m_scriptOptions, canvas); + + delete canvas->rootObject(); + canvas->engine()->clearComponentCache(); + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("qmlViewer", this); +#ifdef Q_OS_SYMBIAN + ctxt->setContextProperty("qmlViewerFolder", "E:\\"); // Documents on your S60 phone +#else + ctxt->setContextProperty("qmlViewerFolder", QDir::currentPath()); +#endif + + ctxt->setContextProperty("runtime", Runtime::instance()); + + QString fileName = url.toLocalFile(); + if (!fileName.isEmpty()) { + fi.setFile(fileName); + if (fi.exists()) { + if (fi.suffix().toLower() != QLatin1String("qml")) { + qWarning() << "qml cannot open non-QML file" << fileName; + return false; + } + + QFileInfo fi(fileName); + loadTranslationFile(fi.path()); + loadDummyDataFiles(fi.path()); + } else { + qWarning() << "qml cannot find file:" << fileName; + return false; + } + } + + QTime t; + t.start(); + + canvas->setSource(url); + + return true; +} + +void QDeclarativeViewer::startNetwork() +{ +#if defined(SYMBIAN_NETWORK_INIT) + qt_SetDefaultIap(); +#endif +} + +void QDeclarativeViewer::setAutoRecord(int from, int to) +{ + if (from==0) from=1; // ensure resized + record_autotime = to-from; + autoStartTimer.setInterval(from); + autoStartTimer.setRunning(true); +} + +void QDeclarativeViewer::setRecordArgs(const QStringList& a) +{ + record_args = a; +} + +void QDeclarativeViewer::setRecordFile(const QString& f) +{ + record_file = f; +} + +void QDeclarativeViewer::setRecordRate(int fps) +{ + record_rate = fps; +} + +void QDeclarativeViewer::sceneResized(QSize size) +{ + if (size.width() > 0 && size.height() > 0) { + if (canvas->resizeMode() == QDeclarativeView::SizeViewToRootObject) { + updateSizeHints(); + } + } +} + +void QDeclarativeViewer::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_0 && devicemode) + exit(0); + else if (event->key() == Qt::Key_F1 || (event->key() == Qt::Key_1 && devicemode)) { + qDebug() << "F1 - help\n" + << "F2 - save test script\n" + << "F3 - take PNG snapshot\n" + << "F4 - show items and state\n" + << "F5 - reload QML\n" + << "F6 - show object tree\n" + << "F7 - show timing\n" + << "F9 - toggle video recording\n" + << "F10 - toggle orientation\n" + << "device keys: 0=quit, 1..8=F1..F8" + ; + } else if (event->key() == Qt::Key_F2 || (event->key() == Qt::Key_2 && devicemode)) { + if (tester && m_scriptOptions & Record) + tester->save(); + } else if (event->key() == Qt::Key_F3 || (event->key() == Qt::Key_3 && devicemode)) { + takeSnapShot(); + } else if (event->key() == Qt::Key_F5 || (event->key() == Qt::Key_5 && devicemode)) { + reload(); + } else if (event->key() == Qt::Key_F9 || (event->key() == Qt::Key_9 && devicemode)) { + toggleRecording(); + } else if (event->key() == Qt::Key_F10) { + if (portraitOrientation) { + if (portraitOrientation->isChecked()) + setLandscape(); + else + setPortrait(); + } + } + + QWidget::keyPressEvent(event); +} + +bool QDeclarativeViewer::event(QEvent *event) +{ + if (event->type() == QEvent::WindowActivate) { + Runtime::instance()->setActiveWindow(true); + } else if (event->type() == QEvent::WindowDeactivate) { + Runtime::instance()->setActiveWindow(false); + } + return QWidget::event(event); +} + +void QDeclarativeViewer::senseImageMagick() +{ + QProcess proc; + proc.start("convert", QStringList() << "-h"); + proc.waitForFinished(2000); + QString help = proc.readAllStandardOutput(); + convertAvailable = help.contains("ImageMagick"); +} + +void QDeclarativeViewer::senseFfmpeg() +{ + QProcess proc; + proc.start("ffmpeg", QStringList() << "-h"); + proc.waitForFinished(2000); + QString ffmpegHelp = proc.readAllStandardOutput(); + ffmpegAvailable = ffmpegHelp.contains("-s "); + ffmpegHelp = tr("Video recording uses ffmpeg:")+"\n\n"+ffmpegHelp; + + QDialog *d = new QDialog(recdlg); + QVBoxLayout *l = new QVBoxLayout(d); + QTextBrowser *b = new QTextBrowser(d); + QFont f = b->font(); + f.setFamily("courier"); + b->setFont(f); + b->setText(ffmpegHelp); + l->addWidget(b); + d->setLayout(l); + ffmpegHelpWindow = d; + connect(recdlg->ffmpegHelp,SIGNAL(clicked()), ffmpegHelpWindow, SLOT(show())); +} + +void QDeclarativeViewer::setRecording(bool on) +{ + if (on == recordTimer.isRunning()) + return; + + int period = int(1000/record_rate+0.5); + QUnifiedTimer::instance()->setTimingInterval(on ? period:16); + QUnifiedTimer::instance()->setConsistentTiming(on); + if (on) { + canvas->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); + recordTimer.setInterval(period); + recordTimer.setRunning(true); + frame_fmt = record_file.right(4).toLower(); + frame = QImage(canvas->width(),canvas->height(),QImage::Format_RGB32); + if (frame_fmt != ".png" && (!convertAvailable || frame_fmt != ".gif")) { + // Stream video to ffmpeg + + QProcess *proc = new QProcess(this); + connect(proc, SIGNAL(finished(int)), this, SLOT(ffmpegFinished(int))); + frame_stream = proc; + + QStringList args; + args << "-y"; + args << "-r" << QString::number(record_rate); + args << "-f" << "rawvideo"; + args << "-pix_fmt" << (frame_fmt == ".gif" ? "rgb24" : "rgb32"); + args << "-s" << QString("%1x%2").arg(canvas->width()).arg(canvas->height()); + args << "-i" << "-"; + if (record_outsize.isValid()) { + args << "-s" << QString("%1x%2").arg(record_outsize.width()).arg(record_outsize.height()); + args << "-aspect" << QString::number(double(canvas->width())/canvas->height()); + } + args += record_args; + args << record_file; + proc->start("ffmpeg",args); + + } else { + // Store frames, save to GIF/PNG + frame_stream = 0; + } + } else { + canvas->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); + recordTimer.setRunning(false); + if (frame_stream) { + qDebug() << "Saving video..."; + frame_stream->close(); + qDebug() << "Wrote" << record_file; + } else { + QProgressDialog progress(tr("Saving frames..."), tr("Cancel"), 0, frames.count()+10, this); + progress.setWindowModality(Qt::WindowModal); + + int frame=0; + QStringList inputs; + qDebug() << "Saving frames..."; + + QString framename; + bool png_output = false; + if (record_file.right(4).toLower()==".png") { + if (record_file.contains('%')) + framename = record_file; + else + framename = record_file.left(record_file.length()-4)+"%04d"+record_file.right(4); + png_output = true; + } else { + framename = "tmp-frame%04d.png"; + png_output = false; + } + foreach (QImage* img, frames) { + progress.setValue(progress.value()+1); + if (progress.wasCanceled()) + break; + QString name; + name.sprintf(framename.toLocal8Bit(),frame++); + if (record_outsize.isValid()) + *img = img->scaled(record_outsize,Qt::IgnoreAspectRatio,Qt::SmoothTransformation); + if (record_dither=="ordered") + img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::OrderedDither).save(name); + else if (record_dither=="threshold") + img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::ThresholdDither).save(name); + else if (record_dither=="floyd") + img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither).save(name); + else + img->save(name); + inputs << name; + delete img; + } + + if (!progress.wasCanceled()) { + if (png_output) { + framename.replace(QRegExp("%\\d*."),"*"); + qDebug() << "Wrote frames" << framename; + inputs.clear(); // don't remove them + } else { + // ImageMagick and gifsicle for GIF encoding + progress.setLabelText(tr("Converting frames to GIF file...")); + QStringList args; + args << "-delay" << QString::number(period/10); + args << inputs; + args << record_file; + qDebug() << "Converting..." << record_file << "(this may take a while)"; + if (0!=QProcess::execute("convert", args)) { + qWarning() << "Cannot run ImageMagick 'convert' - recorded frames not converted"; + inputs.clear(); // don't remove them + qDebug() << "Wrote frames tmp-frame*.png"; + } else { + if (record_file.right(4).toLower() == ".gif") { + qDebug() << "Compressing..." << record_file; + if (0!=QProcess::execute("gifsicle", QStringList() << "-O2" << "-o" << record_file << record_file)) + qWarning() << "Cannot run 'gifsicle' - not compressed"; + } + qDebug() << "Wrote" << record_file; + } + } + } + + progress.setValue(progress.maximum()-1); + foreach (QString name, inputs) + QFile::remove(name); + + frames.clear(); + } + } + qDebug() << "Recording: " << (recordTimer.isRunning()?"ON":"OFF"); +} + +void QDeclarativeViewer::ffmpegFinished(int code) +{ + qDebug() << "ffmpeg returned" << code << frame_stream->readAllStandardError(); +} + +void QDeclarativeViewer::autoStartRecording() +{ + setRecording(true); + autoStopTimer.setInterval(record_autotime); + autoStopTimer.setRunning(true); +} + +void QDeclarativeViewer::autoStopRecording() +{ + setRecording(false); +} + +void QDeclarativeViewer::recordFrame() +{ + canvas->QWidget::render(&frame); + if (frame_stream) { + if (frame_fmt == ".gif") { + // ffmpeg can't do 32bpp with gif + QImage rgb24 = frame.convertToFormat(QImage::Format_RGB888); + frame_stream->write((char*)rgb24.bits(),rgb24.numBytes()); + } else { + frame_stream->write((char*)frame.bits(),frame.numBytes()); + } + } else { + frames.append(new QImage(frame)); + } +} + +void QDeclarativeViewer::orientationChanged() +{ + if (canvas->resizeMode() == QDeclarativeView::SizeRootObjectToView) { + if (canvas->rootObject()) { + QSizeF rootObjectSize = canvas->rootObject()->boundingRect().size(); + QSize newSize(rootObjectSize.width(), rootObjectSize.height()+menuBarHeight()); + if (size() != newSize) { + resize(newSize); + } + } + } +} + +void QDeclarativeViewer::setDeviceKeys(bool on) +{ + devicemode = on; +} + +void QDeclarativeViewer::setNetworkCacheSize(int size) +{ + namFactory->setCacheSize(size); +} + +void QDeclarativeViewer::setUseGL(bool useGL) +{ +#ifdef GL_SUPPORTED + if (useGL) { + QGLFormat format = QGLFormat::defaultFormat(); +#ifdef Q_WS_MAC + format.setSampleBuffers(true); +#else + format.setSampleBuffers(false); +#endif + + QGLWidget *glWidget = new QGLWidget(format); + //### potentially faster, but causes junk to appear if top-level is Item, not Rectangle + //glWidget->setAutoFillBackground(false); + + canvas->setViewport(glWidget); + } +#endif +} + +void QDeclarativeViewer::setUseNativeFileBrowser(bool use) +{ + useQmlFileBrowser = !use; +} + +void QDeclarativeViewer::setSizeToView(bool sizeToView) +{ + QDeclarativeView::ResizeMode resizeMode = sizeToView ? QDeclarativeView::SizeRootObjectToView : QDeclarativeView::SizeViewToRootObject; + if (resizeMode != canvas->resizeMode()) { + canvas->setResizeMode(resizeMode); + updateSizeHints(); + } +} + +void QDeclarativeViewer::updateSizeHints() +{ + if (canvas->resizeMode() == QDeclarativeView::SizeViewToRootObject) { + QSize newWindowSize = canvas->sizeHint(); + newWindowSize.setHeight(newWindowSize.height()+menuBarHeight()); + if (!isFullScreen() && !isMaximized()) { + resize(newWindowSize); + setFixedSize(newWindowSize); + } + } else { // QDeclarativeView::SizeRootObjectToView + canvas->setMinimumSize(QSize(0,0)); + canvas->setMaximumSize(QSize(16777215,16777215)); + setMinimumSize(QSize(0,0)); + setMaximumSize(QSize(16777215,16777215)); + } + updateGeometry(); +} + +void QDeclarativeViewer::registerTypes() +{ + static bool registered = false; + + if (!registered) { + // registering only for exposing the DeviceOrientation::Orientation enum + qmlRegisterUncreatableType<DeviceOrientation>("Qt",4,7,"Orientation",""); + registered = true; + } +} + +QT_END_NAMESPACE + +#include "qmlruntime.moc" diff --git a/tools/qml/qmlruntime.h b/tools/qml/qmlruntime.h new file mode 100644 index 0000000..0416b32 --- /dev/null +++ b/tools/qml/qmlruntime.h @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEVIEWER_H +#define QDECLARATIVEVIEWER_H + +#include <QMainWindow> +#include <QMenuBar> +#include <private/qdeclarativetimer_p.h> +#include <QTime> +#include <QList> + +#include "loggerwidget.h" + +QT_BEGIN_NAMESPACE + +class QDeclarativeView; +class PreviewDeviceSkin; +class QDeclarativeTestEngine; +class QProcess; +class RecordingDialog; +class QDeclarativeTester; +class QNetworkReply; +class QNetworkCookieJar; +class NetworkAccessManagerFactory; +class QTranslator; + +class QDeclarativeViewer +#if defined(Q_OS_SYMBIAN) + : public QMainWindow +#else + : public QWidget +#endif +{ +Q_OBJECT +public: + QDeclarativeViewer(QWidget *parent=0, Qt::WindowFlags flags=0); + ~QDeclarativeViewer(); + + static void registerTypes(); + + enum ScriptOption { + Play = 0x00000001, + Record = 0x00000002, + TestImages = 0x00000004, + TestErrorProperty = 0x00000008, + SaveOnExit = 0x00000010, + ExitOnComplete = 0x00000020, + ExitOnFailure = 0x00000040, + Snapshot = 0x00000080 + }; + Q_DECLARE_FLAGS(ScriptOptions, ScriptOption) + void setScript(const QString &s) { m_script = s; } + void setScriptOptions(ScriptOptions opt) { m_scriptOptions = opt; } + void setRecordDither(const QString& s) { record_dither = s; } + void setRecordRate(int fps); + void setRecordFile(const QString&); + void setRecordArgs(const QStringList&); + void setRecording(bool on); + bool isRecording() const { return recordTimer.isRunning(); } + void setAutoRecord(int from, int to); + void setDeviceKeys(bool); + void setNetworkCacheSize(int size); + void addLibraryPath(const QString& lib); + void addPluginPath(const QString& plugin); + void setUseGL(bool use); + void setUseNativeFileBrowser(bool); + void updateSizeHints(); + void setSizeToView(bool sizeToView); + + QMenuBar *menuBar() const; + + QDeclarativeView *view() const; + LoggerWidget *warningsWidget() const; + + void enableExperimentalGestures(); + +public slots: + void sceneResized(QSize size); + bool open(const QString&); + void openFile(); + void reload(); + void takeSnapShot(); + void toggleRecording(); + void toggleRecordingWithSelection(); + void ffmpegFinished(int code); + void showProxySettings (); + void proxySettingsChanged (); + void toggleOrientation(); + void statusChanged(); + void setSlowMode(bool); + void launch(const QString &); + +protected: + virtual void keyPressEvent(QKeyEvent *); + virtual bool event(QEvent *); + void createMenu(QMenuBar *menu, QMenu *flatmenu); + +private slots: + void autoStartRecording(); + void autoStopRecording(); + void recordFrame(); + void chooseRecordingOptions(); + void pickRecordingFile(); + void setPortrait(); + void setLandscape(); + void startNetwork(); + void toggleFullScreen(); + void orientationChanged(); + + void showWarnings(bool show); + void warningsWidgetOpened(); + void warningsWidgetClosed(); + +private: + QString getVideoFileName(); + int menuBarHeight() const; + + LoggerWidget *loggerWindow; + QDeclarativeView *canvas; + QSize initialSize; + QString currentFileOrUrl; + QDeclarativeTimer recordTimer; + QString frame_fmt; + QImage frame; + QList<QImage*> frames; + QProcess* frame_stream; + QDeclarativeTimer autoStartTimer; + QDeclarativeTimer autoStopTimer; + QString record_dither; + QString record_file; + QSize record_outsize; + QStringList record_args; + int record_rate; + int record_autotime; + bool devicemode; + QAction *recordAction; + QString currentSkin; + bool scaleSkin; + mutable QMenuBar *mb; + RecordingDialog *recdlg; + + void senseImageMagick(); + void senseFfmpeg(); + QWidget *ffmpegHelpWindow; + bool ffmpegAvailable; + bool convertAvailable; + + QAction *portraitOrientation; + QAction *landscapeOrientation; + + QAction *showWarningsWindow; + + QString m_script; + ScriptOptions m_scriptOptions; + QDeclarativeTester *tester; + + QNetworkReply *wgtreply; + QString wgtdir; + NetworkAccessManagerFactory *namFactory; + + bool useQmlFileBrowser; + + QTranslator *translator; + void loadTranslationFile(const QString& directory); + + void loadDummyDataFiles(const QString& directory); +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeViewer::ScriptOptions) + +QT_END_NAMESPACE + +#endif diff --git a/tools/qml/qmlruntime.qrc b/tools/qml/qmlruntime.qrc new file mode 100644 index 0000000..3a9e608 --- /dev/null +++ b/tools/qml/qmlruntime.qrc @@ -0,0 +1,9 @@ +<RCC> + <qresource prefix="/" > + <file>content/Browser.qml</file> + <file>content/images/up.png</file> + <file>content/images/folder.png</file> + <file>content/images/titlebar.sci</file> + <file>content/images/titlebar.png</file> + </qresource> +</RCC> diff --git a/tools/qml/recopts.ui b/tools/qml/recopts.ui new file mode 100644 index 0000000..ce2da30 --- /dev/null +++ b/tools/qml/recopts.ui @@ -0,0 +1,513 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>RecordingOptions</class> + <widget class="QDialog" name="RecordingOptions"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>316</width> + <height>436</height> + </rect> + </property> + <property name="windowTitle"> + <string>Video options</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>File:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="file"/> + </item> + <item> + <widget class="QToolButton" name="pickfile"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Size</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QRadioButton" name="sizeOriginal"> + <property name="text"> + <string/> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QRadioButton" name="sizeVGA"> + <property name="text"> + <string>VGA</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QRadioButton" name="size720p"> + <property name="text"> + <string>720p</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QRadioButton" name="sizeQVGA"> + <property name="text"> + <string>QVGA</string> + </property> + </widget> + </item> + <item row="2" column="0" colspan="3"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QRadioButton" name="sizeCustom"> + <property name="text"> + <string>Width:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="sizeWidth"> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>9999</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Height:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="sizeHeight"> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>9999</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::MinimumExpanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="0" column="2"> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::MinimumExpanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="rateOptions"> + <property name="title"> + <string>Rate</string> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <widget class="QRadioButton" name="hz60"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>60Hz</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QRadioButton" name="hz50"> + <property name="text"> + <string>50Hz</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QRadioButton" name="hz25"> + <property name="text"> + <string>25Hz</string> + </property> + </widget> + </item> + <item row="2" column="0" colspan="4"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <item> + <widget class="QRadioButton" name="hzCustom"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="hz"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>60</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Hz</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::MinimumExpanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="1" column="2"> + <widget class="QRadioButton" name="hz24"> + <property name="text"> + <string>24Hz</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::MinimumExpanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="1"> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="ffmpegOptions"> + <property name="title"> + <string>Profile</string> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0" colspan="3"> + <widget class="QComboBox" name="profile"/> + </item> + <item row="1" column="0" colspan="2"> + <widget class="QLineEdit" name="args"/> + </item> + <item row="1" column="2"> + <widget class="QToolButton" name="ffmpegHelp"> + <property name="text"> + <string>Help</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QLabel" name="warning"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>file</tabstop> + <tabstop>pickfile</tabstop> + <tabstop>sizeOriginal</tabstop> + <tabstop>sizeVGA</tabstop> + <tabstop>size720p</tabstop> + <tabstop>sizeQVGA</tabstop> + <tabstop>sizeCustom</tabstop> + <tabstop>sizeWidth</tabstop> + <tabstop>sizeHeight</tabstop> + <tabstop>hz60</tabstop> + <tabstop>hz25</tabstop> + <tabstop>hz50</tabstop> + <tabstop>hz24</tabstop> + <tabstop>hzCustom</tabstop> + <tabstop>hz</tabstop> + <tabstop>profile</tabstop> + <tabstop>args</tabstop> + <tabstop>ffmpegHelp</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>hzCustom</sender> + <signal>clicked()</signal> + <receiver>hz</receiver> + <slot>setFocus()</slot> + <hints> + <hint type="sourcelabel"> + <x>43</x> + <y>257</y> + </hint> + <hint type="destinationlabel"> + <x>129</x> + <y>262</y> + </hint> + </hints> + </connection> + <connection> + <sender>hz</sender> + <signal>textChanged(QString)</signal> + <receiver>hzCustom</receiver> + <slot>toggle()</slot> + <hints> + <hint type="sourcelabel"> + <x>143</x> + <y>262</y> + </hint> + <hint type="destinationlabel"> + <x>43</x> + <y>257</y> + </hint> + </hints> + </connection> + <connection> + <sender>hz</sender> + <signal>selectionChanged()</signal> + <receiver>hzCustom</receiver> + <slot>toggle()</slot> + <hints> + <hint type="sourcelabel"> + <x>143</x> + <y>262</y> + </hint> + <hint type="destinationlabel"> + <x>43</x> + <y>257</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>RecordingOptions</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>258</x> + <y>424</y> + </hint> + <hint type="destinationlabel"> + <x>60</x> + <y>219</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>RecordingOptions</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>258</x> + <y>424</y> + </hint> + <hint type="destinationlabel"> + <x>92</x> + <y>219</y> + </hint> + </hints> + </connection> + <connection> + <sender>profile</sender> + <signal>activated(int)</signal> + <receiver>RecordingOptions</receiver> + <slot>pickProfile(int)</slot> + <hints> + <hint type="sourcelabel"> + <x>92</x> + <y>329</y> + </hint> + <hint type="destinationlabel"> + <x>48</x> + <y>194</y> + </hint> + </hints> + </connection> + <connection> + <sender>args</sender> + <signal>textEdited(QString)</signal> + <receiver>RecordingOptions</receiver> + <slot>storeCustomArgs(QString)</slot> + <hints> + <hint type="sourcelabel"> + <x>128</x> + <y>357</y> + </hint> + <hint type="destinationlabel"> + <x>102</x> + <y>189</y> + </hint> + </hints> + </connection> + <connection> + <sender>sizeWidth</sender> + <signal>valueChanged(int)</signal> + <receiver>sizeCustom</receiver> + <slot>toggle()</slot> + <hints> + <hint type="sourcelabel"> + <x>108</x> + <y>133</y> + </hint> + <hint type="destinationlabel"> + <x>48</x> + <y>133</y> + </hint> + </hints> + </connection> + <connection> + <sender>sizeHeight</sender> + <signal>valueChanged(int)</signal> + <receiver>sizeCustom</receiver> + <slot>toggle()</slot> + <hints> + <hint type="sourcelabel"> + <x>212</x> + <y>133</y> + </hint> + <hint type="destinationlabel"> + <x>64</x> + <y>129</y> + </hint> + </hints> + </connection> + </connections> + <slots> + <signal>filePicked(QString)</signal> + <signal>argumentsPicked(QString)</signal> + <slot>pickFile()</slot> + <slot>pickProfile(int)</slot> + <slot>storeCustomArgs(QString)</slot> + </slots> +</ui> diff --git a/tools/qtconfig/mainwindow.cpp b/tools/qtconfig/mainwindow.cpp index 604b1f4..9675f99 100644 --- a/tools/qtconfig/mainwindow.cpp +++ b/tools/qtconfig/mainwindow.cpp @@ -68,6 +68,8 @@ #ifndef QT_NO_GSTREAMER #include <gst/gst.h> +#endif +#ifdef HAVE_PHONON #include <phonon/phononnamespace.h> #endif @@ -387,8 +389,10 @@ MainWindow::MainWindow() audiosinkCombo->addItem(tr("aRts"), QLatin1String("artssink")); audiosinkCombo->setItemData(audiosinkCombo->findText(tr("aRts")), tr("Experimental aRts support for GStreamer."), Qt::ToolTipRole); -#ifndef QT_NO_GSTREAMER +#ifdef HAVE_PHONON phononVersionLabel->setText(QLatin1String(Phonon::phononVersion())); +#endif +#ifndef QT_NO_GSTREAMER if (gst_init_check(0, 0, 0)) { gchar *versionString = gst_version_string(); gstversionLabel->setText(QLatin1String(versionString)); @@ -428,7 +432,7 @@ MainWindow::MainWindow() #endif #ifndef QT_NO_OPENGL videomodeCombo->addItem(tr("OpenGL"), QLatin1String("OpenGL")); - videomodeCombo->setItemData(videomodeCombo->findText(tr("OpenGL")), tr("Use OpenGL if avaiable"), Qt::ToolTipRole); + videomodeCombo->setItemData(videomodeCombo->findText(tr("OpenGL")), tr("Use OpenGL if available"), Qt::ToolTipRole); #endif videomodeCombo->addItem(tr("Software"), QLatin1String("Software")); videomodeCombo->setItemData(videomodeCombo->findText(tr("Software")), tr("Use simple software rendering"), Qt::ToolTipRole); diff --git a/tools/qtconfig/qtconfig.pro b/tools/qtconfig/qtconfig.pro index 8ab3f03..d1fd320 100644 --- a/tools/qtconfig/qtconfig.pro +++ b/tools/qtconfig/qtconfig.pro @@ -9,7 +9,10 @@ QT += qt3support contains(QT_CONFIG, gstreamer):LIBS += $$QT_LIBS_GSTREAMER -lgstinterfaces-0.10 -lgstvideo-0.10 -lgstbase-0.10 contains(QT_CONFIG, gstreamer):QMAKE_CXXFLAGS += $$QT_CFLAGS_GSTREAMER -contains(QT_CONFIG, gstreamer):QT += phonon +contains(QT_CONFIG, phonon) { + QT += phonon + DEFINES += HAVE_PHONON +} SOURCES += colorbutton.cpp main.cpp previewframe.cpp previewwidget.cpp mainwindow.cpp paletteeditoradvanced.cpp \ mainwindowbase.cpp paletteeditoradvancedbase.cpp previewwidgetbase.cpp HEADERS += colorbutton.h previewframe.h previewwidget.h mainwindow.h paletteeditoradvanced.h \ diff --git a/tools/qtconfig/translations/translations.pro b/tools/qtconfig/translations/translations.pro index bf8a1da..5d35b6a 100644 --- a/tools/qtconfig/translations/translations.pro +++ b/tools/qtconfig/translations/translations.pro @@ -9,6 +9,7 @@ FORMS = ../mainwindowbase.ui ../paletteeditoradvancedbase.ui ../previewwi TR_DIR = $$PWD/../../../translations TRANSLATIONS = \ + $$TR_DIR/qtconfig_hu.ts \ $$TR_DIR/qtconfig_pl.ts \ $$TR_DIR/qtconfig_ru.ts \ $$TR_DIR/qtconfig_zh_CN.ts \ diff --git a/tools/qtestlib/chart/database.cpp b/tools/qtestlib/chart/database.cpp index dfc0fc5..1f1f7da 100644 --- a/tools/qtestlib/chart/database.cpp +++ b/tools/qtestlib/chart/database.cpp @@ -42,6 +42,7 @@ #include <QtGui> #include <QtXml> +QT_BEGIN_NAMESPACE // Database schema definition and open/create functions QString resultsTable = QString("(TestName varchar, TestCaseName varchar, Series varchar, Idx varchar, ") + @@ -319,3 +320,5 @@ void DataBaseWriter::addResult(const QString &series, const QString &index, cons query.bindValue(":ChartType", "BarChart"); execQuery(query); } + +QT_END_NAMESPACE diff --git a/tools/qtestlib/chart/database.h b/tools/qtestlib/chart/database.h index d9861ad..9a67490 100644 --- a/tools/qtestlib/chart/database.h +++ b/tools/qtestlib/chart/database.h @@ -43,6 +43,9 @@ #include <QtCore> #include <QtSql> +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE extern QString resultsTable; QSqlDatabase openDataBase(const QString &databaseFile = "database"); @@ -57,6 +60,7 @@ void execQuery(const QString &spec, bool warnOnFail = true); void printDataBase(); void displayTable(const QString &table); + class TempTable { public: @@ -95,5 +99,7 @@ public: QSqlDatabase db; }; +QT_END_NAMESPACE #endif + diff --git a/tools/qtestlib/chart/reportgenerator.cpp b/tools/qtestlib/chart/reportgenerator.cpp index 1ce362c..c3b42a0 100644 --- a/tools/qtestlib/chart/reportgenerator.cpp +++ b/tools/qtestlib/chart/reportgenerator.cpp @@ -41,6 +41,7 @@ #include "reportgenerator.h" // Report generator file utility functions +QT_BEGIN_NAMESPACE QList<QByteArray> readLines(const QString &fileName) { @@ -559,3 +560,4 @@ QByteArray ReportGenerator::printColors(const QString &tableName, const QString return colors; } +QT_END_NAMESPACE diff --git a/tools/qtestlib/chart/reportgenerator.h b/tools/qtestlib/chart/reportgenerator.h index d44aea9..1f075bd 100644 --- a/tools/qtestlib/chart/reportgenerator.h +++ b/tools/qtestlib/chart/reportgenerator.h @@ -42,6 +42,9 @@ #define REPORTGENERATOR_H #include "database.h" +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE class ReportGenerator { @@ -59,5 +62,7 @@ private: void printTestCaseResults(const QString &testCaseName); +QT_END_NAMESPACE + #endif diff --git a/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp b/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp index 99219f3..5494194 100644 --- a/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp +++ b/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp @@ -198,3 +198,24 @@ bool CeTcpSyncConnection::fileCreationTime(const QString &fileName, FILETIME* de file.remove(); return result; } + +bool CeTcpSyncConnection::resetDevice() +{ + qWarning("CeTcpSyncConnection::resetDevice not implemented"); + return false; +} + +bool CeTcpSyncConnection::toggleDevicePower(int *returnValue) +{ + Q_UNUSED(returnValue); + qWarning("CeTcpSyncConnection::toggleDevicePower not implemented"); + return false; +} + +bool CeTcpSyncConnection::setDeviceAwake(bool activate, int *returnValue) +{ + Q_UNUSED(activate); + Q_UNUSED(returnValue); + qWarning("CeTcpSyncConnection::setDeviceAwake not implemented"); + return false; +} diff --git a/tools/qtestlib/wince/cetest/cetcpsyncconnection.h b/tools/qtestlib/wince/cetest/cetcpsyncconnection.h index 77539cc..e603efc 100644 --- a/tools/qtestlib/wince/cetest/cetcpsyncconnection.h +++ b/tools/qtestlib/wince/cetest/cetcpsyncconnection.h @@ -75,6 +75,9 @@ public: bool createDirectory(const QString&, bool deleteBefore=false); bool execute(QString program, QString arguments = QString(), int timeout = -1, int *returnValue = NULL); + bool resetDevice(); + bool toggleDevicePower(int *returnValue = NULL); + bool setDeviceAwake(bool activate, int *returnValue = NULL); private: bool connected; }; diff --git a/tools/qtestlib/wince/cetest/cetest.pro b/tools/qtestlib/wince/cetest/cetest.pro index 2773fe4..82747da 100644 --- a/tools/qtestlib/wince/cetest/cetest.pro +++ b/tools/qtestlib/wince/cetest/cetest.pro @@ -36,8 +36,6 @@ HEADERS += \ SOURCES += \ remoteconnection.cpp \ deployment.cpp \ - symbian/epocroot.cpp \ - windows/registry.cpp \ main.cpp LIBS += ole32.lib advapi32.lib diff --git a/tools/qtestlib/wince/cetest/main.cpp b/tools/qtestlib/wince/cetest/main.cpp index 9fe5f02..4272a83 100644 --- a/tools/qtestlib/wince/cetest/main.cpp +++ b/tools/qtestlib/wince/cetest/main.cpp @@ -285,10 +285,14 @@ int main(int argc, char **argv) } // Check wether the project is still in debug/release mode after reading // If .pro specifies to be one mode only, we need to accept this - if (project.isActiveConfig("debug")) + if (project.isActiveConfig("debug") && !project.isActiveConfig("release")) { TestConfiguration::testDebug = true; - else + debugOutput("ActiveConfig: debug only in .pro.", 1); + } + if (!project.isActiveConfig("debug") && project.isActiveConfig("release")) { TestConfiguration::testDebug = false; + debugOutput("ActiveConfig: release only in .pro.", 1); + } // determine what is the real mkspec to use if the default mkspec is being used if (Option::mkfile::qmakespec.endsWith("/default")) diff --git a/tools/qtestlib/wince/cetest/qmake_include.pri b/tools/qtestlib/wince/cetest/qmake_include.pri index 8b415b0..35fbc64 100644 --- a/tools/qtestlib/wince/cetest/qmake_include.pri +++ b/tools/qtestlib/wince/cetest/qmake_include.pri @@ -5,7 +5,9 @@ SOURCES += \ $$QT_SOURCE_TREE/qmake/option.cpp \ $$QT_SOURCE_TREE/qmake/project.cpp \ $$QT_SOURCE_TREE/qmake/property.cpp \ + $$QT_SOURCE_TREE/qmake/generators/metamakefile.cpp \ $$QT_SOURCE_TREE/qmake/generators/symbian/initprojectdeploy_symbian.cpp \ $$QT_SOURCE_TREE/tools/shared/symbian/epocroot.cpp \ $$QT_SOURCE_TREE/tools/shared/windows/registry.cpp +DEFINES += QT_QMAKE_PARSER_ONLY diff --git a/tools/qttracereplay/main.cpp b/tools/qttracereplay/main.cpp index a932d72..101d512 100644 --- a/tools/qttracereplay/main.cpp +++ b/tools/qttracereplay/main.cpp @@ -49,7 +49,7 @@ class ReplayWidget : public QWidget { Q_OBJECT public: - ReplayWidget(const QString &filename); + ReplayWidget(const QString &filename, int from, int to, bool single, int frame); void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent *event); @@ -66,22 +66,96 @@ public: QTime timer; QList<uint> visibleUpdates; - QList<uint> iterationTimes; + + QVector<uint> iterationTimes; QString filename; + + int from; + int to; + + bool single; + + int frame; + int currentCommand; }; void ReplayWidget::updateRect() { - if (!visibleUpdates.isEmpty()) + if (frame >= 0 && !updates.isEmpty()) + update(updates.at(frame)); + else if (!visibleUpdates.isEmpty()) update(updates.at(visibleUpdates.at(currentFrame))); } +const int singleFrameRepeatsPerCommand = 100; +const int singleFrameIterations = 4; + void ReplayWidget::paintEvent(QPaintEvent *) { QPainter p(this); + QTimer::singleShot(0, this, SLOT(updateRect())); + // p.setClipRegion(frames.at(currentFrame).updateRegion); + if (frame >= 0) { + int start = buffer.frameStartIndex(frame); + int end = buffer.frameEndIndex(frame); + + iterationTimes.resize(end - start); + + int saveRestoreStackDepth = buffer.processCommands(&p, start, start + currentCommand); + + for (int i = 0; i < saveRestoreStackDepth; ++i) + p.restore(); + + const int repeats = currentIteration >= 3 ? singleFrameRepeatsPerCommand : 1; + + ++currentFrame; + if (currentFrame == repeats) { + currentFrame = 0; + if (currentIteration >= 3) { + iterationTimes[currentCommand - 1] = qMin(iterationTimes[currentCommand - 1], uint(timer.elapsed())); + timer.restart(); + } + + if (currentIteration >= singleFrameIterations + 3) { + printf(" # | ms | description\n"); + printf("------+---------+------------------------------------------------------------\n"); + + qSort(iterationTimes); + + int sum = 0; + for (int i = 0; i < iterationTimes.size(); ++i) { + int delta = iterationTimes.at(i); + if (i > 0) + delta -= iterationTimes.at(i-1); + sum += delta; + qreal deltaF = delta / qreal(repeats); + printf("%.5d | %.5f | %s\n", i, deltaF, qPrintable(buffer.commandDescription(start + i))); + } + printf("Total | %.5f | Total frame time\n", sum / qreal(repeats)); + deleteLater(); + return; + } + + if (start + currentCommand >= end) { + currentCommand = 1; + ++currentIteration; + if (currentIteration == 3) { + timer.start(); + iterationTimes.fill(uint(-1)); + } + if (currentIteration >= 3 && currentIteration < singleFrameIterations + 3) + printf("Profiling iteration %d of %d\n", currentIteration - 2, singleFrameIterations); + } else { + ++currentCommand; + } + } + + return; + } + buffer.draw(&p, visibleUpdates.at(currentFrame)); ++currentFrame; @@ -89,6 +163,11 @@ void ReplayWidget::paintEvent(QPaintEvent *) currentFrame = 0; ++currentIteration; + if (single) { + deleteLater(); + return; + } + if (currentIteration == 3) timer.start(); else if (currentIteration > 3) { @@ -128,29 +207,37 @@ void ReplayWidget::paintEvent(QPaintEvent *) } } } - - QTimer::singleShot(0, this, SLOT(updateRect())); } -void ReplayWidget::resizeEvent(QResizeEvent *event) +void ReplayWidget::resizeEvent(QResizeEvent *) { visibleUpdates.clear(); QRect bounds = rect(); - for (int i = 0; i < updates.size(); ++i) { + + int first = qMax(0, from); + int last = qMin(unsigned(to), unsigned(updates.size())); + for (int i = first; i < last; ++i) { if (updates.at(i).intersects(bounds)) visibleUpdates << i; } - if (visibleUpdates.size() != updates.size()) - printf("Warning: skipped %d frames due to limited resolution\n", updates.size() - visibleUpdates.size()); + int range = last - first; + + if (visibleUpdates.size() != range) + printf("Warning: skipped %d frames due to limited resolution\n", range - visibleUpdates.size()); } -ReplayWidget::ReplayWidget(const QString &filename_) +ReplayWidget::ReplayWidget(const QString &filename_, int from_, int to_, bool single_, int frame_) : currentFrame(0) , currentIteration(0) , filename(filename_) + , from(from_) + , to(to_) + , single(single_) + , frame(frame_) + , currentCommand(1) { setWindowTitle(filename); QFile file(filename); @@ -165,15 +252,21 @@ ReplayWidget::ReplayWidget(const QString &filename_) char *data; uint size; in.readBytes(data, size); - bool isTraceFile = size == 7 && qstrncmp(data, "qttrace", 7) == 0; - delete [] data; + bool isTraceFile = size >= 7 && qstrncmp(data, "qttrace", 7) == 0; + + uint version = 0; + if (size == 9 && qstrncmp(data, "qttraceV2", 9) == 0) { + in.setFloatingPointPrecision(QDataStream::SinglePrecision); + in >> version; + } + if (!isTraceFile) { printf("File '%s' is not a trace file\n", qPrintable(filename_)); return; } in >> buffer >> updates; - printf("Read paint buffer with %d frames\n", buffer.numFrames()); + printf("Read paint buffer version %d with %d frames\n", version, buffer.numFrames()); resize(buffer.boundingRect().size().toSize()); @@ -189,17 +282,65 @@ int main(int argc, char **argv) if (argc <= 1 || qstrcmp(argv[1], "-h") == 0 || qstrcmp(argv[1], "--help") == 0) { printf("Replays a tracefile generated with '-graphicssystem trace'\n"); - printf("Usage:\n > %s [traceFile]\n", argv[0]); + printf("Usage:\n > %s [OPTIONS] [traceFile]\n", argv[0]); + printf("OPTIONS\n" + " --range=from-to to specify a frame range.\n" + " --singlerun to do only one run (without statistics)\n" + " --instrumentframe=frame to instrument a single frame\n"); return 1; } - QFile file(argv[1]); + QFile file(app.arguments().last()); if (!file.exists()) { - printf("%s does not exist\n", argv[1]); + printf("%s does not exist\n", qPrintable(app.arguments().last())); return 1; } - ReplayWidget *widget = new ReplayWidget(argv[1]); + bool single = false; + + int frame = -1; + + int from = 0; + int to = -1; + for (int i = 1; i < app.arguments().size() - 1; ++i) { + QString arg = app.arguments().at(i); + if (arg.startsWith(QLatin1String("--range="))) { + QString rest = arg.mid(8); + QStringList components = rest.split(QLatin1Char('-')); + + bool ok1 = false; + bool ok2 = false; + int fromCandidate = 0; + int toCandidate = 0; + if (components.size() == 2) { + fromCandidate = components.first().toInt(&ok1); + toCandidate = components.last().toInt(&ok2); + } + + if (ok1 && ok2) { + from = fromCandidate; + to = toCandidate; + } else { + printf("ERROR: malformed syntax in argument %s\n", qPrintable(arg)); + } + } else if (arg == QLatin1String("--singlerun")) { + single = true; + } else if (arg.startsWith(QLatin1String("--instrumentframe="))) { + QString rest = arg.mid(18); + bool ok = false; + int frameCandidate = rest.toInt(&ok); + if (ok) { + frame = frameCandidate; + } else { + printf("ERROR: malformed syntax in argument %s\n", qPrintable(arg)); + } + } else { + printf("Unrecognized argument: %s\n", qPrintable(arg)); + return 1; + } + } + + ReplayWidget *widget = new ReplayWidget(app.arguments().last(), from, to, single, frame); if (!widget->updates.isEmpty()) { widget->show(); diff --git a/tools/qvfb/translations/translations.pro b/tools/qvfb/translations/translations.pro index ef42063..b0b1af4 100644 --- a/tools/qvfb/translations/translations.pro +++ b/tools/qvfb/translations/translations.pro @@ -28,6 +28,7 @@ SOURCES = ../qvfb.cpp \ TR_DIR = $$PWD/../../../translations TRANSLATIONS = \ + $$TR_DIR/qvfb_hu.ts \ $$TR_DIR/qvfb_pl.ts \ $$TR_DIR/qvfb_ru.ts \ $$TR_DIR/qvfb_zh_CN.ts \ diff --git a/tools/runonphone/main.cpp b/tools/runonphone/main.cpp index 65085e0..885d029 100644 --- a/tools/runonphone/main.cpp +++ b/tools/runonphone/main.cpp @@ -44,6 +44,7 @@ #include <QStringList> #include <QScopedPointer> #include <QTimer> +#include <QFileInfo> #include "symbianutils/trkutils.h" #include "symbianutils/trkdevice.h" #include "symbianutils/launcher.h" @@ -51,19 +52,23 @@ #include "trksignalhandler.h" #include "serenum.h" -void printUsage(QTextStream& outstream) +void printUsage(QTextStream& outstream, QString exeName) { - outstream << "runtest [options] <program> [program arguments]" << endl - << "-s, --sis <file> specify sis file to install" << endl - << "-p, --portname <COMx> specify COM port to use by device name" << endl - << "-f, --portfriendlyname <substring> specify COM port to use by friendly name" << endl - << "-t, --timeout <milliseconds> terminate test if timeout occurs" << endl - << "-v, --verbose show debugging output" << endl - << "-q, --quiet hide progress messages" << endl + outstream << exeName << " [options] [program] [program arguments]" << endl + << "-s, --sis <file> specify sis file to install" << endl + << "-p, --portname <COMx> specify COM port to use by device name" << endl + << "-f, --portfriendlyname <substring> specify COM port to use by friendly name" << endl + << "-t, --timeout <milliseconds> terminate test if timeout occurs" << endl + << "-v, --verbose show debugging output" << endl + << "-q, --quiet hide progress messages" << endl + << "-d, --download <remote file> <local file> copy file from phone to PC after running test" << endl << endl - << "USB COM ports can usually be autodetected" << endl; + << "USB COM ports can usually be autodetected, use -p or -f to force a specific port." << endl + << "If using System TRK, it is possible to copy the program directly to sys/bin on the phone." << endl + << "-s can be used with both System and Application TRK to install the program" << endl; } +#define CHECK_PARAMETER_EXISTS if(!it.hasNext()) { printUsage(outstream, args[0]); return 1; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); @@ -76,82 +81,86 @@ int main(int argc, char *argv[]) QStringList args = QCoreApplication::arguments(); QTextStream outstream(stdout); QTextStream errstream(stderr); + QString downloadRemoteFile; + QString downloadLocalFile; int loglevel=1; int timeout=0; - for (int i=1;i<args.size();i++) { - QString arg = args.at(i); + QListIterator<QString> it(args); + it.next(); //skip name of program + while (it.hasNext()) { + QString arg = it.next(); + if (arg.startsWith("-")) { - if (args.size() < i+2) { - errstream << "Command line missing argument parameters" << endl; - return 1; + if (arg == "--portname" || arg == "-p") { + CHECK_PARAMETER_EXISTS + serialPortName = it.next(); } - QString param = args.at(i+1); - if(arg.compare("--portname", Qt::CaseSensitive) == 0 - || arg.compare("-p", Qt::CaseSensitive) == 0) { - serialPortName = param; - i++; + else if (arg == "--portfriendlyname" || arg == "-f") { + CHECK_PARAMETER_EXISTS + serialPortFriendlyName = it.next(); } - else if(arg.compare("--portfriendlyname", Qt::CaseSensitive) == 0 - || arg.compare("-f", Qt::CaseSensitive) == 0) { - serialPortFriendlyName = param; - i++; + else if (arg == "--sis" || arg == "-s") { + CHECK_PARAMETER_EXISTS + sisFile = it.next(); + if (!QFileInfo(sisFile).exists()) { + errstream << "Sis file (" << sisFile << ") doesn't exist" << endl; + return 1; + } } - else if(arg.compare("--sis", Qt::CaseSensitive) == 0 - || arg.compare("-s", Qt::CaseSensitive) == 0) { - sisFile = param; - i++; + else if (arg == "--download" || arg == "-d") { + CHECK_PARAMETER_EXISTS + downloadRemoteFile = it.next(); + CHECK_PARAMETER_EXISTS + downloadLocalFile = it.next(); } - else if(arg.compare("--timeout", Qt::CaseSensitive) == 0 - || arg.compare("-t", Qt::CaseSensitive) == 0) { + else if (arg == "--timeout" || arg == "-t") { + CHECK_PARAMETER_EXISTS bool ok; - timeout = param.toInt(&ok); + timeout = it.next().toInt(&ok); if (!ok) { errstream << "Timeout must be specified in milliseconds" << endl; return 1; } - i++; } - else if(arg.compare("--verbose", Qt::CaseSensitive) == 0 - || arg.compare("-v", Qt::CaseSensitive) == 0) + else if (arg == "--verbose" || arg == "-v") loglevel=2; - else if(arg.compare("--quiet", Qt::CaseSensitive) == 0 - || arg.compare("-q", Qt::CaseSensitive) == 0) + else if (arg == "--quiet" || arg == "-q") loglevel=0; else errstream << "unknown command line option " << arg << endl; } else { exeFile = arg; - i++; - for(;i<args.size();i++) { - cmdLine.append(args.at(i)); + while(it.hasNext()) { + cmdLine.append(it.next()); } } } - if(exeFile.isEmpty()) { - printUsage(outstream); + if (exeFile.isEmpty() && sisFile.isEmpty() && + (downloadLocalFile.isEmpty() || downloadRemoteFile.isEmpty())) { + printUsage(outstream, args[0]); return 1; } if (serialPortName.isEmpty()) { if (loglevel > 0) outstream << "Detecting serial ports" << endl; - QList <SerialPortId> ports = enumerateSerialPorts(); - foreach(SerialPortId id, ports) { + foreach (const SerialPortId &id, enumerateSerialPorts()) { if (loglevel > 0) outstream << "Port Name: " << id.portName << ", " << "Friendly Name:" << id.friendlyName << endl; - if (serialPortName.isEmpty()) { - if (!id.friendlyName.isEmpty() - && serialPortFriendlyName.isEmpty() - && (id.friendlyName.contains("symbian", Qt::CaseInsensitive) - || id.friendlyName.contains("s60", Qt::CaseInsensitive) - || id.friendlyName.contains("nokia", Qt::CaseInsensitive))) - serialPortName = id.portName; - else if (!id.friendlyName.isEmpty() - && !serialPortFriendlyName.isEmpty() - && id.friendlyName.contains(serialPortFriendlyName)) - serialPortName = id.portName; + if (!id.friendlyName.isEmpty() + && serialPortFriendlyName.isEmpty() + && (id.friendlyName.contains("symbian", Qt::CaseInsensitive) + || id.friendlyName.contains("s60", Qt::CaseInsensitive) + || id.friendlyName.contains("nokia", Qt::CaseInsensitive))) { + serialPortName = id.portName; + break; + } else if (!id.friendlyName.isEmpty() + && !serialPortFriendlyName.isEmpty() + && id.friendlyName.contains(serialPortFriendlyName)) { + serialPortName = id.portName; + break; } } if (serialPortName.isEmpty()) { @@ -161,24 +170,30 @@ int main(int argc, char *argv[]) } QScopedPointer<trk::Launcher> launcher; - - if (sisFile.isEmpty()) { - launcher.reset(new trk::Launcher(trk::Launcher::ActionCopyRun)); - launcher->setCopyFileName(exeFile, QString("c:\\sys\\bin\\") + exeFile); - errstream << "System TRK required to copy EXE, use --sis if using Application TRK" << endl; - } else { - launcher.reset(new trk::Launcher(trk::Launcher::ActionCopyInstallRun)); - launcher->addStartupActions(trk::Launcher::ActionInstall); + launcher.reset(new trk::Launcher(trk::Launcher::ActionPingOnly)); + QFileInfo info(exeFile); + if (!sisFile.isEmpty()) { + launcher->addStartupActions(trk::Launcher::ActionCopyInstall); launcher->setCopyFileName(sisFile, "c:\\data\\testtemp.sis"); launcher->setInstallFileName("c:\\data\\testtemp.sis"); } + else if (info.exists()) { + launcher->addStartupActions(trk::Launcher::ActionCopy); + launcher->setCopyFileName(exeFile, QString("c:\\sys\\bin\\") + info.fileName()); + } + if (!exeFile.isEmpty()) { + launcher->addStartupActions(trk::Launcher::ActionRun); + launcher->setFileName(QString("c:\\sys\\bin\\") + info.fileName()); + launcher->setCommandLineArgs(cmdLine); + } + if (!downloadRemoteFile.isEmpty() && !downloadLocalFile.isEmpty()) { + launcher->addStartupActions(trk::Launcher::ActionDownload); + launcher->setDownloadFileName(downloadRemoteFile, downloadLocalFile); + } if (loglevel > 0) outstream << "Connecting to target via " << serialPortName << endl; launcher->setTrkServerName(serialPortName); - launcher->setFileName(QString("c:\\sys\\bin\\") + exeFile); - launcher->setCommandLineArgs(cmdLine); - if (loglevel > 1) launcher->setVerbose(1); diff --git a/tools/runonphone/runonphone.pro b/tools/runonphone/runonphone.pro index 7bed3e5..0c63723 100644 --- a/tools/runonphone/runonphone.pro +++ b/tools/runonphone/runonphone.pro @@ -22,7 +22,10 @@ windows { } else:unix:!symbian { SOURCES += serenum_unix.cpp + LIBS += -lusb } else { SOURCES += serenum_stub.cpp } + + diff --git a/tools/runonphone/serenum_unix.cpp b/tools/runonphone/serenum_unix.cpp index c8ec021..b6f0293 100644 --- a/tools/runonphone/serenum_unix.cpp +++ b/tools/runonphone/serenum_unix.cpp @@ -46,13 +46,80 @@ #include <QFileInfo> #include <QDir> +#include <usb.h> + QList<SerialPortId> enumerateSerialPorts() { + QList<QString> eligableInterfaces; QList<SerialPortId> list; + + usb_init(); + usb_find_busses(); + usb_find_devices(); + + for (struct usb_bus *bus = usb_get_busses(); bus; bus = bus->next) { + for (struct usb_device *device = bus->devices; device; device = device->next) { + for (int n = 0; n < device->descriptor.bNumConfigurations; ++n) { + struct usb_config_descriptor &usbConfig =device->config[n]; + QList<int> usableInterfaces; + for (int m = 0; m < usbConfig.bNumInterfaces; ++m) { + for (int o = 0; o < usbConfig.interface[m].num_altsetting; ++o) { + struct usb_interface_descriptor &descriptor = usbConfig.interface[m].altsetting[o]; + if (descriptor.bInterfaceClass != 2 // "Communication" + || descriptor.bInterfaceSubClass != 2 // Abstract (modem) + || descriptor.bInterfaceProtocol != 255) // Vendor Specific + continue; + + unsigned char *buf = descriptor.extra; + unsigned int size = descriptor.extralen; + while (size >= 2 * sizeof(u_int8_t)) { + // for Communication devices there is a slave interface for the actual + // data transmission. + // the extra info stores that as a index for the interface + if (buf[0] >= 5 && buf[1] == 36 && buf[2] == 6) { // CDC Union + for (int i = 4; i < buf[0]; i++) + usableInterfaces.append((int) buf[i]); + } + size -= buf[0]; + buf += buf[0]; + } + } + } + + // second loop to find the actual data interface. + foreach (int i, usableInterfaces) { + for (int m = 0; m < usbConfig.bNumInterfaces; ++m) { + for (int o = 0; o < usbConfig.interface[m].num_altsetting; ++o) { + struct usb_interface_descriptor &descriptor = usbConfig.interface[m].altsetting[o]; + if (descriptor.bInterfaceNumber != i) + continue; + if (descriptor.bInterfaceClass == 10) { // "CDC Data" + // qDebug() << " found the data port" + // << "bus:" << bus->dirname + // << "device" << device->filename + // << "interface" << descriptor.bInterfaceNumber; + eligableInterfaces << QString("if%1").arg(QString::number(i), 2, QChar('0')); // fix! + } + } + } + } + } + } + } + QDir dir("/dev/serial/by-id/"); - QFileInfoList ports(dir.entryInfoList()); - foreach (const QFileInfo &info, ports) { + foreach (const QFileInfo &info, dir.entryInfoList()) { if (!info.isDir()) { + bool usable = eligableInterfaces.isEmpty(); + foreach (const QString &iface, eligableInterfaces) { + if (info.fileName().contains(iface)) { + usable = true; + break; + } + } + if (!usable) + continue; + SerialPortId id; id.friendlyName = info.fileName(); id.portName = info.canonicalFilePath(); diff --git a/tools/runonphone/symbianutils/launcher.cpp b/tools/runonphone/symbianutils/launcher.cpp index 408829b..ecb067e 100644 --- a/tools/runonphone/symbianutils/launcher.cpp +++ b/tools/runonphone/symbianutils/launcher.cpp @@ -44,6 +44,7 @@ #include "trkutils_p.h" #include "trkdevice.h" #include "bluetoothlistener.h" +#include "symbiandevicemanager.h" #include <QtCore/QTimer> #include <QtCore/QDateTime> @@ -53,6 +54,8 @@ #include <QtCore/QFile> #include <QtCore/QScopedPointer> +#include <cstdio> + namespace trk { struct LauncherPrivate { @@ -61,7 +64,8 @@ struct LauncherPrivate { QString destinationFileName; uint copyFileHandle; QScopedPointer<QByteArray> data; - int position; + qint64 position; + QScopedPointer<QFile> localFile; }; explicit LauncherPrivate(const TrkDevicePtr &d); @@ -75,6 +79,7 @@ struct LauncherPrivate { Session m_session; // global-ish data (process id, target information) CopyState m_copyState; + CopyState m_downloadState; QString m_fileName; QStringList m_commandLineArgs; QString m_installFileName; @@ -100,12 +105,15 @@ Launcher::Launcher(Actions startupActions, d(new LauncherPrivate(dev)) { d->m_startupActions = startupActions; - connect(d->m_device.data(), SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult))); - connect(this, SIGNAL(finished()), d->m_device.data(), SLOT(close())); + connect(d->m_device.data(), SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult))); } Launcher::~Launcher() { + // Destroyed before protocol was through: Close + if (d->m_closeDevice && d->m_device->isOpen()) + d->m_device->close(); + emit destroyed(d->m_device->port()); logMessage("Shutting down.\n"); delete d; } @@ -154,6 +162,12 @@ void Launcher::setCopyFileName(const QString &srcName, const QString &dstName) d->m_copyState.destinationFileName = dstName; } +void Launcher::setDownloadFileName(const QString &srcName, const QString &dstName) +{ + d->m_downloadState.sourceFileName = srcName; + d->m_downloadState.destinationFileName = dstName; +} + void Launcher::setInstallFileName(const QString &name) { d->m_installFileName = name; @@ -189,10 +203,26 @@ bool Launcher::startServer(QString *errorMessage) { errorMessage->clear(); if (d->m_verbose) { - const QString msg = QString::fromLatin1("Port=%1 Executable=%2 Arguments=%3 Package=%4 Remote Package=%5 Install file=%6") - .arg(trkServerName(), d->m_fileName, - d->m_commandLineArgs.join(QString(QLatin1Char(' '))), - d->m_copyState.sourceFileName, d->m_copyState.destinationFileName, d->m_installFileName); + QString msg; + QTextStream str(&msg); + str.setIntegerBase(16); + str << "Actions=0x" << d->m_startupActions; + str.setIntegerBase(10); + str << " Port=" << trkServerName(); + if (!d->m_fileName.isEmpty()) + str << " Executable=" << d->m_fileName; + if (!d->m_commandLineArgs.isEmpty()) + str << " Arguments= " << d->m_commandLineArgs.join(QString(QLatin1Char(' '))); + if (!d->m_copyState.sourceFileName.isEmpty()) + str << " Package/Source=" << d->m_copyState.sourceFileName; + if (!d->m_copyState.destinationFileName.isEmpty()) + str << " Remote Package/Destination=" << d->m_copyState.destinationFileName; + if (!d->m_downloadState.sourceFileName.isEmpty()) + str << " Source=" << d->m_downloadState.sourceFileName; + if (!d->m_downloadState.destinationFileName.isEmpty()) + str << " Destination=" << d->m_downloadState.destinationFileName; + if (!d->m_installFileName.isEmpty()) + str << " Install file=" << d->m_installFileName; logMessage(msg); } if (d->m_startupActions & ActionCopy) { @@ -214,11 +244,6 @@ bool Launcher::startServer(QString *errorMessage) } if (!d->m_device->isOpen() && !d->m_device->open(errorMessage)) return false; - if (d->m_closeDevice) { - connect(this, SIGNAL(finished()), d->m_device.data(), SLOT(close())); - } else { - disconnect(this, SIGNAL(finished()), d->m_device.data(), 0); - } setState(Connecting); // Set up the temporary 'waiting' state if we do not get immediate connection QTimer::singleShot(1000, this, SLOT(slotWaitingForTrk())); @@ -252,6 +277,8 @@ void Launcher::handleConnect(const TrkResult &result) installRemotePackageSilently(); else if (d->m_startupActions & ActionRun) startInferiorIfNeeded(); + else if (d->m_startupActions & ActionDownload) + copyFileFromRemote(); } void Launcher::setVerbose(int v) @@ -266,6 +293,13 @@ void Launcher::logMessage(const QString &msg) qDebug() << "LAUNCHER: " << qPrintable(msg); } +void Launcher::handleFinished() +{ + if (d->m_closeDevice) + d->m_device->close(); + emit finished(); +} + void Launcher::terminate() { switch (state()) { @@ -287,7 +321,7 @@ void Launcher::terminate() case Connecting: case WaitingForTrk: setState(Disconnected); - emit finished(); + handleFinished(); break; } } @@ -331,8 +365,22 @@ void Launcher::handleResult(const TrkResult &result) QByteArray prefix = "READ BUF: "; QByteArray str = result.toString().toUtf8(); if (result.isDebugOutput) { // handle application output - logMessage("APPLICATION OUTPUT: " + result.data); - emit applicationOutputReceived(result.data); + QString msg; + if (result.multiplex == MuxTextTrace) { + if (result.data.length() > 8) { + quint64 timestamp = extractInt64(result.data) & 0x0FFFFFFFFFFFFFFFULL; + quint64 secs = timestamp / 1000000000; + quint64 ns = timestamp % 1000000000; + msg = QString("[%1.%2] %3").arg(secs).arg(ns).arg(QString(result.data.mid(8))); + logMessage("TEXT TRACE: " + msg); + } + } else { + logMessage("APPLICATION OUTPUT: " + result.data); + msg = result.data; + } + msg.replace("\r\n", "\n"); + if(!msg.endsWith('\n')) msg.append('\n'); + emit applicationOutputReceived(msg); return; } switch (result.code) { @@ -410,7 +458,7 @@ void Launcher::handleResult(const TrkResult &result) if (itemType == 0 // process && result.data.size() >= 10 && d->m_session.pid == extractInt(result.data.data() + 6)) { - disconnectTrk(); + copyFileFromRemote(); } break; } @@ -446,7 +494,7 @@ void Launcher::handleTrkVersion(const TrkResult &result) if (result.errorCode() || result.data.size() < 5) { if (d->m_startupActions == ActionPingOnly) { setState(Disconnected); - emit finished(); + handleFinished(); } return; } @@ -455,31 +503,109 @@ void Launcher::handleTrkVersion(const TrkResult &result) d->m_session.trkAppVersion.protocolMajor = result.data.at(3); d->m_session.trkAppVersion.protocolMinor = result.data.at(4); setState(DeviceDescriptionReceived); + const QString msg = deviceDescription(); + emit deviceDescriptionReceived(trkServerName(), msg); // Ping mode: Log & Terminate if (d->m_startupActions == ActionPingOnly) { - qWarning("%s", qPrintable(deviceDescription())); + qWarning("%s", qPrintable(msg)); setState(Disconnected); - emit finished(); + handleFinished(); } } +static inline QString msgCannotOpenRemoteFile(const QString &fileName, const QString &message) +{ + return Launcher::tr("Cannot open remote file '%1': %2").arg(fileName, message); +} + +static inline QString msgCannotOpenLocalFile(const QString &fileName, const QString &message) +{ + return Launcher::tr("Cannot open '%1': %2").arg(fileName, message); +} + void Launcher::handleFileCreation(const TrkResult &result) { if (result.errorCode() || result.data.size() < 6) { - emit canNotCreateFile(d->m_copyState.destinationFileName, result.errorString()); + const QString msg = msgCannotOpenRemoteFile(d->m_copyState.destinationFileName, result.errorString()); + logMessage(msg); + emit canNotCreateFile(d->m_copyState.destinationFileName, msg); disconnectTrk(); return; } const char *data = result.data.data(); d->m_copyState.copyFileHandle = extractInt(data + 2); - QFile file(d->m_copyState.sourceFileName); - file.open(QIODevice::ReadOnly); - d->m_copyState.data.reset(new QByteArray(file.readAll())); + const QString localFileName = d->m_copyState.sourceFileName; + QFile file(localFileName); d->m_copyState.position = 0; + if (!file.open(QIODevice::ReadOnly)) { + const QString msg = msgCannotOpenLocalFile(localFileName, file.errorString()); + logMessage(msg); + emit canNotOpenLocalFile(localFileName, msg); + closeRemoteFile(true); + disconnectTrk(); + return; + } + d->m_copyState.data.reset(new QByteArray(file.readAll())); file.close(); continueCopying(); } +void Launcher::handleFileOpened(const TrkResult &result) +{ + if (result.errorCode() || result.data.size() < 6) { + const QString msg = msgCannotOpenRemoteFile(d->m_downloadState.sourceFileName, result.errorString()); + logMessage(msg); + emit canNotOpenFile(d->m_downloadState.sourceFileName, msg); + disconnectTrk(); + return; + } + d->m_downloadState.position = 0; + const QString localFileName = d->m_downloadState.destinationFileName; + bool opened = false; + if (localFileName == QLatin1String("-")) { + d->m_downloadState.localFile.reset(new QFile); + opened = d->m_downloadState.localFile->open(stdout, QFile::WriteOnly); + } else { + d->m_downloadState.localFile.reset(new QFile(localFileName)); + opened = d->m_downloadState.localFile->open(QFile::WriteOnly | QFile::Truncate); + } + if (!opened) { + const QString msg = msgCannotOpenLocalFile(localFileName, d->m_downloadState.localFile->errorString()); + logMessage(msg); + emit canNotOpenLocalFile(localFileName, msg); + closeRemoteFile(true); + disconnectTrk(); + } + continueReading(); +} + +void Launcher::continueReading() +{ + QByteArray ba; + appendInt(&ba, d->m_downloadState.copyFileHandle, TargetByteOrder); + appendShort(&ba, 2048, TargetByteOrder); + d->m_device->sendTrkMessage(TrkReadFile, TrkCallback(this, &Launcher::handleRead), ba); +} + +void Launcher::handleRead(const TrkResult &result) +{ + if (result.errorCode() || result.data.size() < 4) { + d->m_downloadState.localFile->close(); + closeRemoteFile(true); + disconnectTrk(); + } else { + int length = extractShort(result.data.data() + 2); + //TRK doesn't tell us the file length, so we need to keep reading until it returns 0 length + if (length > 0) { + d->m_downloadState.localFile->write(result.data.data() + 4, length); + continueReading(); + } else { + closeRemoteFile(true); + disconnectTrk(); + } + } +} + void Launcher::handleCopy(const TrkResult &result) { if (result.errorCode() || result.data.size() < 4) { @@ -493,13 +619,14 @@ void Launcher::handleCopy(const TrkResult &result) void Launcher::continueCopying(uint lastCopiedBlockSize) { - int size = d->m_copyState.data->length(); + qint64 size = d->m_copyState.data->length(); d->m_copyState.position += lastCopiedBlockSize; if (size == 0) emit copyProgress(100); else { - int percent = qMin((d->m_copyState.position*100)/size, 100); - emit copyProgress(percent); + const qint64 hundred = 100; + const qint64 percent = qMin( (d->m_copyState.position * hundred) / size, hundred); + emit copyProgress(static_cast<int>(percent)); } if (d->m_copyState.position < size) { QByteArray ba; @@ -532,6 +659,8 @@ void Launcher::handleFileCopied(const TrkResult &result) installRemotePackageSilently(); else if (d->m_startupActions & ActionRun) startInferiorIfNeeded(); + else if (d->m_startupActions & ActionDownload) + copyFileFromRemote(); else disconnectTrk(); } @@ -586,7 +715,7 @@ void Launcher::handleWaitForFinished(const TrkResult &result) { logMessage(" FINISHED: " + stringFromArray(result.data)); setState(Disconnected); - emit finished(); + handleFinished(); } void Launcher::handleSupportMask(const TrkResult &result) @@ -595,17 +724,18 @@ void Launcher::handleSupportMask(const TrkResult &result) return; const char *data = result.data.data() + 1; - QString str = QLatin1String("SUPPORTED: "); - for (int i = 0; i < 32; ++i) { - //str.append(" [" + formatByte(data[i]) + "]: "); - for (int j = 0; j < 8; ++j) { - if (data[i] & (1 << j)) { - str.append(QString::number(i * 8 + j, 16)); - str.append(QLatin1Char(' ')); + if (d->m_verbose > 1) { + QString str = QLatin1String("SUPPORTED: "); + for (int i = 0; i < 32; ++i) { + for (int j = 0; j < 8; ++j) { + if (data[i] & (1 << j)) { + str.append(QString::number(i * 8 + j, 16)); + str.append(QLatin1Char(' ')); + } } } + logMessage(str); } - logMessage(str); } void Launcher::cleanUp() @@ -669,11 +799,20 @@ void Launcher::copyFileToRemote() { emit copyingStarted(); QByteArray ba; - ba.append(char(10)); + ba.append(char(10)); //kDSFileOpenWrite | kDSFileOpenBinary appendString(&ba, d->m_copyState.destinationFileName.toLocal8Bit(), TargetByteOrder, false); d->m_device->sendTrkMessage(TrkOpenFile, TrkCallback(this, &Launcher::handleFileCreation), ba); } +void Launcher::copyFileFromRemote() +{ + emit copyingStarted(); + QByteArray ba; + ba.append(char(9)); //kDSFileOpenRead | kDSFileOpenBinary + appendString(&ba, d->m_downloadState.sourceFileName.toLocal8Bit(), TargetByteOrder, false); + d->m_device->sendTrkMessage(TrkOpenFile, TrkCallback(this, &Launcher::handleFileOpened), ba); +} + void Launcher::installRemotePackageSilently() { emit installingStarted(); @@ -694,6 +833,8 @@ void Launcher::handleInstallPackageFinished(const TrkResult &result) } if (d->m_startupActions & ActionRun) { startInferiorIfNeeded(); + } else if (d->m_startupActions & ActionDownload) { + copyFileFromRemote(); } else { disconnectTrk(); } @@ -704,18 +845,14 @@ QByteArray Launcher::startProcessMessage(const QString &executable, { // It's not started yet QByteArray ba; - appendShort(&ba, 0, TargetByteOrder); // create new process + appendShort(&ba, 0, TargetByteOrder); // create new process (kDSOSProcessItem) ba.append(char(0)); // options - currently unused - if(arguments.isEmpty()) { - appendString(&ba, executable.toLocal8Bit(), TargetByteOrder); - return ba; - } - // Append full command line as one string (leading length information). - QByteArray commandLineBa; - commandLineBa.append(executable.toLocal8Bit()); - commandLineBa.append('\0'); - commandLineBa.append(arguments.join(QString(QLatin1Char(' '))).toLocal8Bit()); - appendString(&ba, commandLineBa, TargetByteOrder); + // One string consisting of binary terminated by '\0' and arguments terminated by '\0' + QByteArray commandLineBa = executable.toLocal8Bit(); + commandLineBa.append(char(0)); + if (!arguments.isEmpty()) + commandLineBa.append(arguments.join(QString(QLatin1Char(' '))).toLocal8Bit()); + appendString(&ba, commandLineBa, TargetByteOrder, true); return ba; } @@ -737,4 +874,37 @@ void Launcher::resumeProcess(uint pid, uint tid) appendInt(&ba, tid, BigEndian); d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); } + +// Acquire a device from SymbianDeviceManager, return 0 if not available. +Launcher *Launcher::acquireFromDeviceManager(const QString &serverName, + QObject *parent, + QString *errorMessage) +{ + SymbianUtils::SymbianDeviceManager *sdm = SymbianUtils::SymbianDeviceManager::instance(); + const QSharedPointer<trk::TrkDevice> device = sdm->acquireDevice(serverName); + if (device.isNull()) { + *errorMessage = tr("Unable to acquire a device for port '%1'. It appears to be in use.").arg(serverName); + return 0; + } + // Wire release signal. + Launcher *rc = new Launcher(trk::Launcher::ActionPingOnly, device, parent); + connect(rc, SIGNAL(deviceDescriptionReceived(QString,QString)), + sdm, SLOT(setAdditionalInformation(QString,QString))); + connect(rc, SIGNAL(destroyed(QString)), sdm, SLOT(releaseDevice(QString))); + return rc; +} + +// Preliminary release of device, disconnecting the signal. +void Launcher::releaseToDeviceManager(Launcher *launcher) +{ + SymbianUtils::SymbianDeviceManager *sdm = SymbianUtils::SymbianDeviceManager::instance(); + // Disentangle launcher and its device, remove connection from destroyed + launcher->setCloseDevice(false); + TrkDevice *device = launcher->trkDevice().data(); + launcher->disconnect(device); + device->disconnect(launcher); + launcher->disconnect(sdm); + sdm->releaseDevice(launcher->trkServerName()); +} + } // namespace trk diff --git a/tools/runonphone/symbianutils/launcher.h b/tools/runonphone/symbianutils/launcher.h index 2b23fd8..6db69d0 100644 --- a/tools/runonphone/symbianutils/launcher.h +++ b/tools/runonphone/symbianutils/launcher.h @@ -69,6 +69,7 @@ public: ActionInstall = 0x2, ActionCopyInstall = ActionCopy | ActionInstall, ActionRun = 0x4, + ActionDownload = 0x8, ActionCopyRun = ActionCopy | ActionRun, ActionInstallRun = ActionInstall | ActionRun, ActionCopyInstallRun = ActionCopy | ActionInstall | ActionRun @@ -94,10 +95,11 @@ public: QString trkServerName() const; void setFileName(const QString &name); void setCopyFileName(const QString &srcName, const QString &dstName); + void setDownloadFileName(const QString &srcName, const QString &dstName); void setInstallFileName(const QString &name); void setCommandLineArgs(const QStringList &args); bool startServer(QString *errorMessage); - void setVerbose(int v); + void setVerbose(int v); void setSerialFrame(bool b); bool serialFrame() const; // Close device or leave it open @@ -109,6 +111,15 @@ public: // becomes valid after successful execution of ActionPingOnly QString deviceDescription(unsigned verbose = 0u) const; + // Acquire a device from SymbianDeviceManager, return 0 if not available. + // The device will be released on destruction. + static Launcher *acquireFromDeviceManager(const QString &serverName, + QObject *parent, + QString *errorMessage); + // Preliminary release of device, disconnecting the signal. + static void releaseToDeviceManager(Launcher *l); + + // Create Trk message to start a process. static QByteArray startProcessMessage(const QString &executable, const QStringList &arguments); // Parse a TrkNotifyStopped message @@ -119,9 +130,12 @@ public: static QString msgStopped(uint pid, uint tid, uint address, const QString &why); signals: + void deviceDescriptionReceived(const QString &port, const QString &description); void copyingStarted(); void canNotConnect(const QString &errorMessage); void canNotCreateFile(const QString &filename, const QString &errorMessage); + void canNotOpenFile(const QString &filename, const QString &errorMessage); + void canNotOpenLocalFile(const QString &filename, const QString &errorMessage); void canNotWriteFile(const QString &filename, const QString &errorMessage); void canNotCloseFile(const QString &filename, const QString &errorMessage); void installingStarted(); @@ -135,6 +149,8 @@ signals: void copyProgress(int percent); void stateChanged(int); void processStopped(uint pc, uint pid, uint tid, const QString& reason); + // Emitted by the destructor, for releasing devices of SymbianDeviceManager by name + void destroyed(const QString &serverName); public slots: void terminate(); @@ -152,8 +168,11 @@ private: void handleRemoteProcessKilled(const TrkResult &result); void handleConnect(const TrkResult &result); void handleFileCreation(const TrkResult &result); + void handleFileOpened(const TrkResult &result); void handleCopy(const TrkResult &result); + void handleRead(const TrkResult &result); void continueCopying(uint lastCopiedBlockSize = 0); + void continueReading(); void closeRemoteFile(bool failed = false); void handleFileCopied(const TrkResult &result); void handleInstallPackageFinished(const TrkResult &result); @@ -165,8 +184,10 @@ private: void handleTrkVersion(const TrkResult &result); void copyFileToRemote(); + void copyFileFromRemote(); void installRemotePackageSilently(); void startInferiorIfNeeded(); + void handleFinished(); void logMessage(const QString &msg); void setState(State s); diff --git a/tools/runonphone/symbianutils/symbiandevicemanager.cpp b/tools/runonphone/symbianutils/symbiandevicemanager.cpp index f663816..8877ea1 100644 --- a/tools/runonphone/symbianutils/symbiandevicemanager.cpp +++ b/tools/runonphone/symbianutils/symbiandevicemanager.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "symbiandevicemanager.h" +#include "trkdevice.h" #include <QtCore/QSettings> #include <QtCore/QStringList> @@ -48,6 +49,7 @@ #include <QtCore/QTextStream> #include <QtCore/QSharedData> #include <QtCore/QScopedPointer> +#include <QtCore/QSignalMapper> namespace SymbianUtils { @@ -61,19 +63,51 @@ const char *SymbianDeviceManager::linuxBlueToothDeviceRootC = "/dev/rfcomm"; // ------------- SymbianDevice class SymbianDeviceData : public QSharedData { public: - SymbianDeviceData() : type(SerialPortCommunication) {} + SymbianDeviceData(); + ~SymbianDeviceData(); + + inline bool isOpen() const { return !device.isNull() && device->isOpen(); } + void forcedClose(); QString portName; QString friendlyName; QString deviceDesc; QString manufacturer; + QString additionalInformation; + DeviceCommunicationType type; + QSharedPointer<trk::TrkDevice> device; + bool deviceAcquired; }; +SymbianDeviceData::SymbianDeviceData() : + type(SerialPortCommunication), + deviceAcquired(false) +{ +} + +SymbianDeviceData::~SymbianDeviceData() +{ + forcedClose(); +} + +void SymbianDeviceData::forcedClose() +{ + // Close the device when unplugging. Should devices be in 'acquired' state, + // their owners should hit on write failures. + // Apart from the <shared item> destructor, also called by the devicemanager + // to ensure it also happens if other shared instances are still around. + if (isOpen()) { + if (deviceAcquired) + qWarning("Device on '%s' unplugged while an operation is in progress.", + qPrintable(portName)); + device->close(); + } +} + SymbianDevice::SymbianDevice(SymbianDeviceData *data) : m_data(data) { - } SymbianDevice::SymbianDevice() : @@ -96,6 +130,11 @@ SymbianDevice::~SymbianDevice() { } +void SymbianDevice::forcedClose() +{ + m_data->forcedClose(); +} + QString SymbianDevice::portName() const { return m_data->portName; @@ -106,6 +145,51 @@ QString SymbianDevice::friendlyName() const return m_data->friendlyName; } +QString SymbianDevice::additionalInformation() const +{ + return m_data->additionalInformation; +} + +void SymbianDevice::setAdditionalInformation(const QString &a) +{ + m_data->additionalInformation = a; +} + +SymbianDevice::TrkDevicePtr SymbianDevice::acquireDevice() +{ + if (debug) + qDebug() << "SymbianDevice::acquireDevice" << m_data->portName + << "acquired: " << m_data->deviceAcquired << " open: " << isOpen(); + if (isNull() || m_data->deviceAcquired) + return TrkDevicePtr(); + if (m_data->device.isNull()) { + m_data->device = TrkDevicePtr(new trk::TrkDevice); + m_data->device->setPort(m_data->portName); + m_data->device->setSerialFrame(m_data->type == SerialPortCommunication); + } + m_data->deviceAcquired = true; + return m_data->device; +} + +void SymbianDevice::releaseDevice(TrkDevicePtr *ptr /* = 0 */) +{ + if (debug) + qDebug() << "SymbianDevice::releaseDevice" << m_data->portName + << " open: " << isOpen(); + if (m_data->deviceAcquired) { + if (m_data->device->isOpen()) + m_data->device->clearWriteQueue(); + // Release if a valid pointer was passed in. + if (ptr && !ptr->isNull()) { + ptr->data()->disconnect(); + *ptr = TrkDevicePtr(); + } + m_data->deviceAcquired = false; + } else { + qWarning("Internal error: Attempt to release device that is not acquired."); + } +} + QString SymbianDevice::deviceDesc() const { return m_data->deviceDesc; @@ -123,7 +207,12 @@ DeviceCommunicationType SymbianDevice::type() const bool SymbianDevice::isNull() const { - return !m_data->portName.isEmpty(); + return m_data->portName.isEmpty(); +} + +bool SymbianDevice::isOpen() const +{ + return m_data->isOpen(); } QString SymbianDevice::toString() const @@ -158,7 +247,7 @@ int SymbianDevice::compare(const SymbianDevice &rhs) const return 0; } -QDebug operator<<(QDebug d, const SymbianDevice &cd) +SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDevice &cd) { d.nospace() << cd.toString(); return d; @@ -166,10 +255,11 @@ QDebug operator<<(QDebug d, const SymbianDevice &cd) // ------------- SymbianDeviceManagerPrivate struct SymbianDeviceManagerPrivate { - SymbianDeviceManagerPrivate() : m_initialized(false) {} + SymbianDeviceManagerPrivate() : m_initialized(false), m_destroyReleaseMapper(0) {} bool m_initialized; SymbianDeviceManager::SymbianDeviceList m_devices; + QSignalMapper *m_destroyReleaseMapper; }; SymbianDeviceManager::SymbianDeviceManager(QObject *parent) : @@ -185,8 +275,7 @@ SymbianDeviceManager::~SymbianDeviceManager() SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::devices() const { - if (!d->m_initialized) - const_cast<SymbianDeviceManager*>(this)->update(false); + ensureInitialized(); return d->m_devices; } @@ -194,6 +283,7 @@ QString SymbianDeviceManager::toString() const { QString rc; QTextStream str(&rc); + str << d->m_devices.size() << " devices:\n"; const int count = d->m_devices.size(); for (int i = 0; i < count; i++) { str << '#' << i << ' '; @@ -203,13 +293,37 @@ QString SymbianDeviceManager::toString() const return rc; } +int SymbianDeviceManager::findByPortName(const QString &p) const +{ + ensureInitialized(); + const int count = d->m_devices.size(); + for (int i = 0; i < count; i++) + if (d->m_devices.at(i).portName() == p) + return i; + return -1; +} + QString SymbianDeviceManager::friendlyNameForPort(const QString &port) const { - foreach (const SymbianDevice &device, d->m_devices) { - if (device.portName() == port) - return device.friendlyName(); - } - return QString(); + const int idx = findByPortName(port); + return idx == -1 ? QString() : d->m_devices.at(idx).friendlyName(); +} + +SymbianDeviceManager::TrkDevicePtr + SymbianDeviceManager::acquireDevice(const QString &port) +{ + ensureInitialized(); + const int idx = findByPortName(port); + if (idx == -1) { + qWarning("Attempt to acquire device '%s' that does not exist.", qPrintable(port)); + if (debug) + qDebug() << *this; + return TrkDevicePtr(); + } + const TrkDevicePtr rc = d->m_devices[idx].acquireDevice(); + if (debug) + qDebug() << "SymbianDeviceManager::acquireDevice" << port << " returns " << !rc.isNull(); + return rc; } void SymbianDeviceManager::update() @@ -217,12 +331,38 @@ void SymbianDeviceManager::update() update(true); } +void SymbianDeviceManager::releaseDevice(const QString &port) +{ + const int idx = findByPortName(port); + if (debug) + qDebug() << "SymbianDeviceManager::releaseDevice" << port << idx << sender(); + if (idx != -1) { + d->m_devices[idx].releaseDevice(); + } else { + qWarning("Attempt to release non-existing device %s.", qPrintable(port)); + } +} + +void SymbianDeviceManager::setAdditionalInformation(const QString &port, const QString &ai) +{ + const int idx = findByPortName(port); + if (idx != -1) + d->m_devices[idx].setAdditionalInformation(ai); +} + +void SymbianDeviceManager::ensureInitialized() const +{ + if (!d->m_initialized) // Flag is set in update() + const_cast<SymbianDeviceManager*>(this)->update(false); +} + void SymbianDeviceManager::update(bool emitSignals) { + static int n = 0; typedef SymbianDeviceList::iterator SymbianDeviceListIterator; if (debug) - qDebug(">SerialDeviceLister::update(%d)\n%s", int(emitSignals), + qDebug(">SerialDeviceLister::update(#%d, signals=%d)\n%s", n++, int(emitSignals), qPrintable(toString())); d->m_initialized = true; @@ -230,8 +370,11 @@ void SymbianDeviceManager::update(bool emitSignals) SymbianDeviceList newDevices = serialPorts() + blueToothDevices(); if (newDevices.size() > 1) qStableSort(newDevices.begin(), newDevices.end()); - if (d->m_devices == newDevices) // Happy, nothing changed. + if (d->m_devices == newDevices) { // Happy, nothing changed. + if (debug) + qDebug("<SerialDeviceLister::update: unchanged\n"); return; + } // Merge the lists and emit the respective added/removed signals, assuming // no one can plug a different device on the same port at the speed of lightning if (!d->m_devices.isEmpty()) { @@ -240,7 +383,8 @@ void SymbianDeviceManager::update(bool emitSignals) if (newDevices.contains(*oldIt)) { ++oldIt; } else { - const SymbianDevice toBeDeleted = *oldIt; + SymbianDevice toBeDeleted = *oldIt; + toBeDeleted.forcedClose(); oldIt = d->m_devices.erase(oldIt); if (emitSignals) emit deviceRemoved(toBeDeleted); @@ -301,16 +445,30 @@ SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::blueToothDevices() // Bluetooth devices are created on connection. List the existing ones // or at least the first one. const QString prefix = QLatin1String(linuxBlueToothDeviceRootC); - const QString friendlyFormat = QLatin1String("Bluetooth device (%1)"); + const QString blueToothfriendlyFormat = QLatin1String("Bluetooth device (%1)"); for (int d = 0; d < 4; d++) { QScopedPointer<SymbianDeviceData> device(new SymbianDeviceData); device->type = BlueToothCommunication; device->portName = prefix + QString::number(d); if (d == 0 || QFileInfo(device->portName).exists()) { - device->friendlyName = friendlyFormat.arg(device->portName); + device->friendlyName = blueToothfriendlyFormat.arg(device->portName); rc.push_back(SymbianDevice(device.take())); } } + // New kernel versions support /dev/ttyUSB0, /dev/ttyUSB1. Trk responds + // on the latter (usually), try first. + static const char *usbTtyDevices[] = { "/dev/ttyUSB1", "/dev/ttyUSB0" }; + const int usbTtyCount = sizeof(usbTtyDevices)/sizeof(const char *); + for (int d = 0; d < usbTtyCount; d++) { + const QString ttyUSBDevice = QLatin1String(usbTtyDevices[d]); + if (QFileInfo(ttyUSBDevice).exists()) { + SymbianDeviceData *device = new SymbianDeviceData; + device->type = SerialPortCommunication; + device->portName = ttyUSBDevice; + device->friendlyName = QString::fromLatin1("USB/Serial device (%1)").arg(device->portName); + rc.push_back(SymbianDevice(device)); + } + } #endif return rc; } @@ -322,7 +480,7 @@ SymbianDeviceManager *SymbianDeviceManager::instance() return symbianDeviceManager(); } -QDebug operator<<(QDebug d, const SymbianDeviceManager &sdm) +SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &sdm) { d.nospace() << sdm.toString(); return d; diff --git a/tools/runonphone/symbianutils/symbiandevicemanager.h b/tools/runonphone/symbianutils/symbiandevicemanager.h index dcf131a..180173d 100644 --- a/tools/runonphone/symbianutils/symbiandevicemanager.h +++ b/tools/runonphone/symbianutils/symbiandevicemanager.h @@ -46,12 +46,17 @@ #include <QtCore/QObject> #include <QtCore/QExplicitlySharedDataPointer> +#include <QtCore/QSharedPointer> QT_BEGIN_NAMESPACE class QDebug; class QTextStream; QT_END_NAMESPACE +namespace trk { + class TrkDevice; +} + namespace SymbianUtils { struct SymbianDeviceManagerPrivate; @@ -62,11 +67,16 @@ enum DeviceCommunicationType { BlueToothCommunication = 1 }; -// SymbianDevice, explicitly shared. +// SymbianDevice: Explicitly shared device data and a TrkDevice +// instance that can be acquired (exclusively) for use. +// A device removal from the manager will result in the +// device being closed. class SYMBIANUTILS_EXPORT SymbianDevice { explicit SymbianDevice(SymbianDeviceData *data); friend class SymbianDeviceManager; public: + typedef QSharedPointer<trk::TrkDevice> TrkDevicePtr; + SymbianDevice(); SymbianDevice(const SymbianDevice &rhs); SymbianDevice &operator=(const SymbianDevice &rhs); @@ -77,6 +87,17 @@ public: bool isNull() const; QString portName() const; QString friendlyName() const; + QString additionalInformation() const; + void setAdditionalInformation(const QString &); + + // Acquire: Mark the device as 'out' and return a shared pointer + // unless it is already in use by another owner. The result should not + // be passed on further. + TrkDevicePtr acquireDevice(); + // Give back a device and mark it as 'free'. + void releaseDevice(TrkDevicePtr *ptr = 0); + + bool isOpen() const; // Windows only. QString deviceDesc() const; @@ -86,10 +107,12 @@ public: QString toString() const; private: + void forcedClose(); + QExplicitlySharedDataPointer<SymbianDeviceData> m_data; }; -QDebug operator<<(QDebug d, const SymbianDevice &); +SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDevice &); inline bool operator==(const SymbianDevice &d1, const SymbianDevice &d2) { return d1.compare(d2) == 0; } @@ -100,13 +123,15 @@ inline bool operator<(const SymbianDevice &d1, const SymbianDevice &d2) /* SymbianDeviceManager: Singleton that maintains a list of Symbian devices. * and emits change signals. - * On Windows, the update slot must be connected to a signal - * emitted from an event handler listening for WM_DEVICECHANGE. */ + * On Windows, the update slot must be connected to a [delayed] signal + * emitted from an event handler listening for WM_DEVICECHANGE. + * Device removal will result in the device being closed. */ class SYMBIANUTILS_EXPORT SymbianDeviceManager : public QObject { Q_OBJECT public: typedef QList<SymbianDevice> SymbianDeviceList; + typedef QSharedPointer<trk::TrkDevice> TrkDevicePtr; static const char *linuxBlueToothDeviceRootC; @@ -120,17 +145,25 @@ public: SymbianDeviceList devices() const; QString toString() const; + // Acquire a device for use. See releaseDevice(). + TrkDevicePtr acquireDevice(const QString &port); + + int findByPortName(const QString &p) const; QString friendlyNameForPort(const QString &port) const; public slots: void update(); + // Relase a device, make it available for further use. + void releaseDevice(const QString &port); + void setAdditionalInformation(const QString &port, const QString &ai); signals: - void deviceRemoved(const SymbianDevice &d); - void deviceAdded(const SymbianDevice &d); + void deviceRemoved(const SymbianUtils::SymbianDevice &d); + void deviceAdded(const SymbianUtils::SymbianDevice &d); void updated(); private: + void ensureInitialized() const; void update(bool emitSignals); SymbianDeviceList serialPorts() const; SymbianDeviceList blueToothDevices() const; @@ -138,7 +171,7 @@ private: SymbianDeviceManagerPrivate *d; }; -QDebug operator<<(QDebug d, const SymbianDeviceManager &); +SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &); } // namespace SymbianUtils diff --git a/tools/runonphone/symbianutils/trkdevice.cpp b/tools/runonphone/symbianutils/trkdevice.cpp index b327ab3..bd24300 100644 --- a/tools/runonphone/symbianutils/trkdevice.cpp +++ b/tools/runonphone/symbianutils/trkdevice.cpp @@ -52,6 +52,7 @@ #include <QtCore/QMutex> #include <QtCore/QWaitCondition> #include <QtCore/QSharedPointer> +#include <QtCore/QScopedPointer> #include <QtCore/QMetaType> #ifdef Q_OS_WIN @@ -102,6 +103,11 @@ QString winErrorMessage(unsigned long error) enum { verboseTrk = 0 }; +static inline QString msgAccessingClosedDevice(const QString &msg) +{ + return QString::fromLatin1("Error: Attempt to access device '%1', which is closed.").arg(msg); +} + namespace trk { /////////////////////////////////////////////////////////////////////// @@ -155,10 +161,11 @@ namespace trk { /////////////////////////////////////////////////////////////////////// class TrkWriteQueue -{ +{ Q_DISABLE_COPY(TrkWriteQueue) public: explicit TrkWriteQueue(); + void clear(); // Enqueue messages. void queueTrkMessage(byte code, TrkCallback callback, @@ -208,13 +215,24 @@ TrkWriteQueue::TrkWriteQueue() : { } +void TrkWriteQueue::clear() +{ + m_trkWriteToken = 0; + m_trkWriteBusy = false; + m_trkWriteQueue.clear(); + const int discarded = m_writtenTrkMessages.size(); + m_writtenTrkMessages.clear(); + if (verboseTrk) + qDebug() << "TrkWriteQueue::clear: discarded " << discarded; +} + byte TrkWriteQueue::nextTrkWriteToken() { ++m_trkWriteToken; if (m_trkWriteToken == 0) ++m_trkWriteToken; if (verboseTrk) - qDebug() << "Write token: " << m_trkWriteToken; + qDebug() << "nextTrkWriteToken:" << m_trkWriteToken; return m_trkWriteToken; } @@ -349,7 +367,7 @@ class WriterThread : public QThread { Q_OBJECT Q_DISABLE_COPY(WriterThread) -public: +public: explicit WriterThread(const QSharedPointer<DeviceContext> &context); // Enqueue messages. @@ -357,6 +375,8 @@ public: const QByteArray &data, const QVariant &cookie); void queueTrkInitialPing(); + void clearWriteQueue(); + // Call this from the device read notification with the results. void slotHandleResult(const TrkResult &result); @@ -374,7 +394,7 @@ public slots: private slots: void invokeNoopMessage(const trk::TrkMessage &); -private: +private: bool write(const QByteArray &data, QString *errorMessage); inline int writePendingMessage(); @@ -462,6 +482,7 @@ void WriterThread::terminate() m_waitCondition.wakeAll(); wait(); m_terminate = false; + m_queue.clear(); } #ifdef Q_OS_WIN @@ -561,6 +582,13 @@ void WriterThread::queueTrkMessage(byte code, TrkCallback callback, tryWrite(); } +void WriterThread::clearWriteQueue() +{ + m_dataMutex.lock(); + m_queue.clear(); + m_dataMutex.unlock(); +} + void WriterThread::queueTrkInitialPing() { m_dataMutex.lock(); @@ -592,6 +620,8 @@ class ReaderThreadBase : public QThread Q_DISABLE_COPY(ReaderThreadBase) public: + int bytesPending() const { return m_trkReadBuffer.size(); } + signals: void messageReceived(const trk::TrkResult &result, const QByteArray &rawData); @@ -692,7 +722,7 @@ int WinReaderThread::tryRead() if (!ClearCommError(m_context->device, NULL, &comStat)){ emit error(QString::fromLatin1("ClearCommError failed: %1").arg(winErrorMessage(GetLastError()))); return -7; - } + } const DWORD bytesToRead = qMax(DWORD(1), qMin(comStat.cbInQue, DWORD(BufSize))); // Trigger read DWORD bytesRead = 0; @@ -708,7 +738,7 @@ int WinReaderThread::tryRead() if (readError != ERROR_IO_PENDING) { emit error(QString::fromLatin1("Read error: %1").arg(winErrorMessage(readError))); return -1; - } + } // Wait for either termination or data const DWORD wr = WaitForMultipleObjects(HandleCount, m_handles, false, INFINITE); if (wr == WAIT_FAILED) { @@ -783,7 +813,7 @@ private: int m_terminatePipeFileDescriptors[2]; }; -UnixReaderThread::UnixReaderThread(const QSharedPointer<DeviceContext> &context) : +UnixReaderThread::UnixReaderThread(const QSharedPointer<DeviceContext> &context) : ReaderThreadBase(context) { m_terminatePipeFileDescriptors[0] = m_terminatePipeFileDescriptors[1] = -1; @@ -877,8 +907,8 @@ struct TrkDevicePrivate TrkDevicePrivate(); QSharedPointer<DeviceContext> deviceContext; - QSharedPointer<WriterThread> writerThread; - QSharedPointer<ReaderThread> readerThread; + QScopedPointer<WriterThread> writerThread; + QScopedPointer<ReaderThread> readerThread; QByteArray trkReadBuffer; int verbose; @@ -917,14 +947,14 @@ TrkDevice::~TrkDevice() bool TrkDevice::open(QString *errorMessage) { - if (d->verbose) + if (d->verbose || verboseTrk) qDebug() << "Opening" << port() << "is open: " << isOpen() << " serialFrame=" << serialFrame(); + if (isOpen()) + return true; if (d->port.isEmpty()) { *errorMessage = QLatin1String("Internal error: No port set on TrkDevice"); return false; } - - close(); #ifdef Q_OS_WIN const QString fullPort = QLatin1String("\\\\.\\") + d->port; d->deviceContext->device = CreateFile(reinterpret_cast<const WCHAR*>(fullPort.utf16()), @@ -975,7 +1005,7 @@ bool TrkDevice::open(QString *errorMessage) return false; } #endif - d->readerThread = QSharedPointer<ReaderThread>(new ReaderThread(d->deviceContext)); + d->readerThread.reset(new ReaderThread(d->deviceContext)); connect(d->readerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)), Qt::QueuedConnection); connect(d->readerThread.data(), SIGNAL(messageReceived(trk::TrkResult,QByteArray)), @@ -983,18 +1013,22 @@ bool TrkDevice::open(QString *errorMessage) Qt::QueuedConnection); d->readerThread->start(); - d->writerThread = QSharedPointer<WriterThread>(new WriterThread(d->deviceContext)); + d->writerThread.reset(new WriterThread(d->deviceContext)); connect(d->writerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)), - Qt::QueuedConnection); - d->writerThread->start(); + Qt::QueuedConnection); + d->writerThread->start(); - if (d->verbose) - qDebug() << "Opened" << d->port; + if (d->verbose || verboseTrk) + qDebug() << "Opened" << d->port << d->readerThread.data() << d->writerThread.data(); return true; } void TrkDevice::close() { + if (verboseTrk) + qDebug() << "close" << d->port << " is open: " << isOpen() + << " read pending " << (d->readerThread.isNull() ? 0 : d->readerThread->bytesPending()) + << sender(); if (!isOpen()) return; if (d->readerThread) @@ -1010,6 +1044,7 @@ void TrkDevice::close() #else d->deviceContext->file.close(); #endif + if (d->verbose) emitLogMessage("Close"); } @@ -1030,6 +1065,8 @@ QString TrkDevice::port() const void TrkDevice::setPort(const QString &p) { + if (verboseTrk) + qDebug() << "setPort" << p; d->port = p; } @@ -1045,6 +1082,8 @@ bool TrkDevice::serialFrame() const void TrkDevice::setSerialFrame(bool f) { + if (verboseTrk) + qDebug() << "setSerialFrame" << f; d->deviceContext->serialFrame = f; } @@ -1060,12 +1099,14 @@ void TrkDevice::setVerbose(int b) void TrkDevice::slotMessageReceived(const trk::TrkResult &result, const QByteArray &rawData) { - d->writerThread->slotHandleResult(result); - if (d->verbose > 1) - qDebug() << "Received: " << result.toString(); - emit messageReceived(result); - if (!rawData.isEmpty()) - emit rawDataReceived(rawData); + if (isOpen()) { // Might receive bytes after closing due to queued connections. + d->writerThread->slotHandleResult(result); + if (d->verbose > 1) + qDebug() << "Received: " << result.toString(); + emit messageReceived(result); + if (!rawData.isEmpty()) + emit rawDataReceived(rawData); + } } void TrkDevice::emitError(const QString &s) @@ -1075,15 +1116,27 @@ void TrkDevice::emitError(const QString &s) emit error(s); } +void TrkDevice::clearWriteQueue() +{ + if (isOpen()) + d->writerThread->clearWriteQueue(); +} + void TrkDevice::sendTrkMessage(byte code, TrkCallback callback, const QByteArray &data, const QVariant &cookie) { + if (!isOpen()) { + emitError(msgAccessingClosedDevice(d->port)); + return; + } if (!d->writerThread.isNull()) { if (d->verbose > 1) { - QByteArray msg = "Sending: "; + QByteArray msg = "Sending: 0x"; msg += QByteArray::number(code, 16); msg += ": "; msg += stringFromArray(data).toLatin1(); + if (cookie.isValid()) + msg += " Cookie: " + cookie.toString().toLatin1(); qDebug("%s", msg.data()); } d->writerThread->queueTrkMessage(code, callback, data, cookie); @@ -1092,12 +1145,20 @@ void TrkDevice::sendTrkMessage(byte code, TrkCallback callback, void TrkDevice::sendTrkInitialPing() { + if (!isOpen()) { + emitError(msgAccessingClosedDevice(d->port)); + return; + } if (!d->writerThread.isNull()) d->writerThread->queueTrkInitialPing(); } bool TrkDevice::sendTrkAck(byte token) { + if (!isOpen()) { + emitError(msgAccessingClosedDevice(d->port)); + return false; + } if (d->writerThread.isNull()) return false; // The acknowledgement must not be queued! diff --git a/tools/runonphone/symbianutils/trkdevice.h b/tools/runonphone/symbianutils/trkdevice.h index 78012fd..1021a7d 100644 --- a/tools/runonphone/symbianutils/trkdevice.h +++ b/tools/runonphone/symbianutils/trkdevice.h @@ -64,12 +64,14 @@ struct TrkDevicePrivate; * Trk communications. Provides synchronous write and asynchronous * read operation. * The serialFrames property specifies whether packets are encapsulated in - * "0x90 <length>" frames, which is currently the case for serial ports. + * "0x90 <length>" frames, which is currently the case for serial ports. * Contains a write message queue allowing * for queueing messages with a notification callback. If the message receives * an ACK, the callback is invoked. - * The special message TRK_WRITE_QUEUE_NOOP_CODE code can be used for synchronisation. - * The respective message will not be sent, the callback is just invoked. */ + * The special message TRK_WRITE_QUEUE_NOOP_CODE code can be used for synchronization. + * The respective message will not be sent, the callback is just invoked. + * Note that calling open/close in quick succession can cause crashes + * due to the use of queused signals. */ enum { TRK_WRITE_QUEUE_NOOP_CODE = 0x7f }; @@ -111,6 +113,9 @@ public: // Send an Ack synchronously, bypassing the queue bool sendTrkAck(unsigned char token); +public slots: + void clearWriteQueue(); + signals: void messageReceived(const trk::TrkResult &result); // Emitted with the contents of messages enclosed in 07e, not for log output diff --git a/tools/runonphone/symbianutils/trkutils.cpp b/tools/runonphone/symbianutils/trkutils.cpp index 9b43c96..60e391e 100644 --- a/tools/runonphone/symbianutils/trkutils.cpp +++ b/tools/runonphone/symbianutils/trkutils.cpp @@ -276,14 +276,13 @@ QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool s /* returns 0 if array doesn't represent a result, otherwise returns the length of the result data */ -ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame) +ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame, ushort& mux) { if (serialFrame) { // Serial protocol with length info if (buffer.length() < 4) return 0; - if (buffer.at(0) != 0x01 || byte(buffer.at(1)) != 0x90) - return 0; + mux = extractShort(buffer.data()); const ushort len = extractShort(buffer.data() + 2); return (buffer.size() >= len + 4) ? len : ushort(0); } @@ -292,6 +291,7 @@ ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame) const int firstDelimiterPos = buffer.indexOf(delimiter); // Regular message delimited by 0x7e..0x7e if (firstDelimiterPos == 0) { + mux = MuxTrk; const int endPos = buffer.indexOf(delimiter, firstDelimiterPos + 1); return endPos != -1 ? endPos + 1 - firstDelimiterPos : 0; } @@ -304,7 +304,7 @@ bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, QByt result->clear(); if(rawData) rawData->clear(); - const ushort len = isValidTrkResult(*buffer, serialFrame); + const ushort len = isValidTrkResult(*buffer, serialFrame, result->multiplex); if (!len) return false; // handle receiving application output, which is not a regular command @@ -312,7 +312,6 @@ bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, QByt if (buffer->at(delimiterPos) != 0x7e) { result->isDebugOutput = true; result->data = buffer->mid(delimiterPos, len); - result->data.replace("\r\n", "\n"); *buffer->remove(0, delimiterPos + len); return true; } @@ -353,6 +352,19 @@ SYMBIANUTILS_EXPORT uint extractInt(const char *data) return res; } +SYMBIANUTILS_EXPORT quint64 extractInt64(const char *data) +{ + quint64 res = byte(data[0]); + res <<= 8; res += byte(data[1]); + res <<= 8; res += byte(data[2]); + res <<= 8; res += byte(data[3]); + res <<= 8; res += byte(data[4]); + res <<= 8; res += byte(data[5]); + res <<= 8; res += byte(data[6]); + res <<= 8; res += byte(data[7]); + return res; +} + SYMBIANUTILS_EXPORT QString quoteUnprintableLatin1(const QByteArray &ba) { QString res; diff --git a/tools/runonphone/symbianutils/trkutils.h b/tools/runonphone/symbianutils/trkutils.h index 3a485c7..e571028 100644 --- a/tools/runonphone/symbianutils/trkutils.h +++ b/tools/runonphone/symbianutils/trkutils.h @@ -43,6 +43,7 @@ #define DEBUGGER_TRK_UTILS #include "symbianutils_global.h" + #include <QtCore/QByteArray> #include <QtCore/QHash> #include <QtCore/QStringList> @@ -57,38 +58,93 @@ namespace trk { typedef unsigned char byte; enum Command { + //meta commands TrkPing = 0x00, TrkConnect = 0x01, TrkDisconnect = 0x02, + TrkReset = 0x03, TrkVersions = 0x04, TrkSupported = 0x05, TrkCpuType = 0x06, + TrkConfigTransport = 0x07, + TrkVersions2 = 0x08, TrkHostVersions = 0x09, + + //state commands + TrkReadMemory = 0x10, + TrkWriteMemory = 0x11, + TrkReadRegisters = 0x12, + TrkWriteRegisters = 0x13, + TrkFillMemory = 0x14, + TrkCopyMemory = 0x15, + TrkFlushCache = 0x16, + + //execution commands TrkContinue = 0x18, + TrkStep = 0x19, + TrkStop = 0x1a, + TrkSetBreak = 0x1b, + TrkClearBreak = 0x1c, + TrkDownload = 0x1d, + TrkModifyBreakThread = 0x1e, + + //host -> target IO management + TrkNotifyFileInput = 0x20, + TrkBlockFileIo = 0x21, + + //host -> target os commands TrkCreateItem = 0x40, TrkDeleteItem = 0x41, + TrkReadInfo = 0x42, + TrkWriteInfo = 0x43, TrkWriteFile = 0x48, + TrkReadFile = 0x49, TrkOpenFile = 0x4a, TrkCloseFile = 0x4b, + TrkPositionFile = 0x4c, TrkInstallFile = 0x4d, TrkInstallFile2 = 0x4e, + TrkPhoneSwVersion = 0x4f, + TrkPhoneName = 0x50, + TrkVersions3 = 0x51, + + //replies TrkNotifyAck = 0x80, TrkNotifyNak = 0xff, + + //target -> host notification TrkNotifyStopped = 0x90, TrkNotifyException = 0x91, TrkNotifyInternalError = 0x92, + TrkNotifyStopped2 = 0x94, + + //target -> host OS notification TrkNotifyCreated = 0xa0, TrkNotifyDeleted = 0xa1, TrkNotifyProcessorStarted = 0xa2, TrkNotifyProcessorStandBy = 0xa6, - TrkNotifyProcessorReset = 0xa7 + TrkNotifyProcessorReset = 0xa7, + + //target -> host support commands (these are defined but not implemented in TRK) + TrkDSWriteFile = 0xd0, + TrkDSReadFile = 0xd1, + TrkDSOpenFile = 0xd2, + TrkDSCloseFile = 0xd3, + TrkDSPositionFile = 0xd4 +}; + +enum SerialMultiplexor { + MuxRaw = 0, + MuxTextTrace = 0x0102, + MuxTrk = 0x0190 }; inline byte extractByte(const char *data) { return *data; } SYMBIANUTILS_EXPORT ushort extractShort(const char *data); SYMBIANUTILS_EXPORT uint extractInt(const char *data); +SYMBIANUTILS_EXPORT quint64 extractInt64(const char *data); SYMBIANUTILS_EXPORT QString quoteUnprintableLatin1(const QByteArray &ba); @@ -118,7 +174,7 @@ struct SYMBIANUTILS_EXPORT Library struct SYMBIANUTILS_EXPORT TrkAppVersion { TrkAppVersion(); - void reset(); + void reset(); int trkMajor; int trkMinor; @@ -168,6 +224,7 @@ struct SYMBIANUTILS_EXPORT TrkResult int errorCode() const; QString errorString() const; + ushort multiplex; byte code; byte token; QByteArray data; diff --git a/tools/runonphone/trksignalhandler.cpp b/tools/runonphone/trksignalhandler.cpp index 18a2c0c..2abf91f 100644 --- a/tools/runonphone/trksignalhandler.cpp +++ b/tools/runonphone/trksignalhandler.cpp @@ -54,6 +54,7 @@ private: QTextStream out; QTextStream err; int loglevel; + int lastpercent; }; void TrkSignalHandler::copyingStarted() @@ -131,7 +132,12 @@ void TrkSignalHandler::applicationOutputReceived(const QString &output) void TrkSignalHandler::copyProgress(int percent) { if (d->loglevel > 0) { - d->out << percent << "% "; + if (d->lastpercent == 0) + d->out << "[ ]\r[" << flush; + while (percent > d->lastpercent) { + d->out << QLatin1Char('#'); + d->lastpercent+=2; //because typical console is 80 chars wide + } d->out.flush(); if (percent==100) d->out << endl; @@ -167,7 +173,8 @@ void TrkSignalHandler::timeout() TrkSignalHandlerPrivate::TrkSignalHandlerPrivate() : out(stdout), err(stderr), - loglevel(0) + loglevel(0), + lastpercent(0) { } diff --git a/tools/shared/deviceskin/deviceskin.pri b/tools/shared/deviceskin/deviceskin.pri index 2552c92..3e9935a 100644 --- a/tools/shared/deviceskin/deviceskin.pri +++ b/tools/shared/deviceskin/deviceskin.pri @@ -2,13 +2,10 @@ INCLUDEPATH += $$PWD HEADERS += $$PWD/deviceskin.h SOURCES += $$PWD/deviceskin.cpp RESOURCES += $$PWD/skins/ClamshellPhone.qrc \ - $$PWD/skins/PDAPhone.qrc \ $$PWD/skins/SmartPhone2.qrc \ $$PWD/skins/SmartPhone.qrc \ $$PWD/skins/SmartPhoneWithButtons.qrc \ $$PWD/skins/TouchscreenPhone.qrc \ - $$PWD/skins/Trolltech-Keypad.qrc \ - $$PWD/skins/Trolltech-Touchscreen.qrc \ $$PWD/skins/PortableMedia.qrc \ $$PWD/skins/S60-QVGA-Candybar.qrc \ $$PWD/skins/S60-nHD-Touchscreen.qrc diff --git a/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen-pressed.png b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen-pressed.png Binary files differdeleted file mode 100644 index d62ef4a..0000000 --- a/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen-pressed.png +++ /dev/null diff --git a/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen.png b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen.png Binary files differdeleted file mode 100644 index cb3d1a7..0000000 --- a/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen.png +++ /dev/null diff --git a/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreenPhone.skin b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreenPhone.skin deleted file mode 100644 index a82ef23..0000000 --- a/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreenPhone.skin +++ /dev/null @@ -1,29 +0,0 @@ -[SkinFile] -Up=DualScreen.png -Down=DualScreen-pressed.png -Screen=128 155 176 208 -BackScreen=18 44 98 119 -Areas=21 -HasMouseHover=false - -"Context1" 0x1100000 144 368 189 368 168 396 176 427 150 398 -"Back" 0x1000061 245 365 291 366 283 398 258 424 265 394 -"Select" 0x1010000 202 401 210 389 224 388 233 402 224 415 208 415 -"Up" 0x1000013 202 381 196 374 218 363 239 373 229 382 -"Left" 0x1000012 199 385 189 375 176 403 185 426 197 415 194 401 -"Right" 0x1000014 235 390 248 379 253 402 246 421 238 413 -"Down" 0x1000015 204 421 233 422 241 432 214 443 191 430 -"Call" 0x1100004 163 452 137 450 125 465 136 484 159 485 169 467 -"Hangup" 0x1100005 266 475 279 448 295 447 309 460 301 480 289 487 -"1" 0x31 175 514 147 504 133 518 161 532 180 534 -"2" 0x32 199 515 229 519 238 533 222 540 195 538 -"2" 0x32 260 512 286 506 299 513 284 527 264 535 248 525 -"4" 0x34 164 541 177 546 182 560 164 565 146 560 135 545 154 539 -"5" 0x35 204 546 225 546 243 560 231 574 205 573 191 558 -"6" 0x36 257 547 281 537 294 540 287 555 274 566 254 561 -"7" 0x37 145 569 176 578 177 595 156 597 138 584 -"8" 0x38 197 582 229 584 241 593 226 604 201 603 189 594 -"9" 0x39 253 577 288 564 301 578 283 593 259 597 251 586 -"*" 0x2a 145 598 181 611 182 623 163 632 144 623 138 607 -"0" 0x30 196 611 233 613 240 630 220 642 193 637 191 622 -"#" 0x23 255 610 286 600 302 615 279 625 258 629 247 616 diff --git a/tools/shared/deviceskin/skins/DualScreenPhone.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/DualScreenPhone.skin/defaultbuttons.conf deleted file mode 100644 index 1103350..0000000 --- a/tools/shared/deviceskin/skins/DualScreenPhone.skin/defaultbuttons.conf +++ /dev/null @@ -1,78 +0,0 @@ -[Translation] -File=QtopiaDefaults -Context=Buttons -[Menu] -Rows=4 -Columns=3 -Map=123456789*0# -Default=5 -1=Applications/camera.desktop -2=Applications/datebook.desktop -3=Applications -4=Applications/qtmail.desktop -5=Applications/addressbook.desktop -6=Games -7=Settings/Beaming.desktop -8=Applications/simapp.desktop,Applications/calculator.desktop -9=Settings -*=Applications/mediarecorder.desktop -0=Applications/todolist.desktop -#=Documents -Animator=Bounce -AnimatorBackground=Radial -[SoftKeys] -Count=3 -Key0=Context1 -Key1=Select -Key2=Back -[SystemButtons] -Count=5 -Key0=Context1 -Key1=Select -Key2=Back -Key3=Call -Key4=Hangup -[TextButtons] -Buttons=0123456789*# -Hold0='0 -Hold1='1 -Hold2='2 -Hold3='3 -Hold4='4 -Hold5='5 -Hold6='6 -Hold7='7 -Hold8='8 -Hold9='9 -Hold*=symbol -Hold#=mode -Tap0=space -Tap1="\".,'?!-@:1" -Tap2="\"a\xe4\xe5\xe6\xe0\xe1\xe2\x62\x63\xe7\x32" -Tap3="\"de\xe8\xe9\xea\x66\x33" -Tap4="\"ghi\xec\xed\xee\x34" -Tap5="\"jkl5" -Tap6="\"mn\xf1o\xf6\xf8\xf2\xf3\x36" -Tap7="\"pqrs\xdf\x37" -Tap8="\"tu\xfc\xf9\xfav8" -Tap9="\"wxyz9" -Tap*=modify -Tap#=shift -[LocaleTextButtons] -Buttons=23456789 -Tap2[]='abc -Tap3[]='def -Tap4[]='ghi -Tap5[]='jkl -Tap6[]='mno -Tap7[]='pqrs -Tap8[]='tuv -Tap9[]='wxyz -[PhoneTextButtons] -Buttons=*# -Tap*='*+pw -Hold*=+ -Tap#='# -Hold#=mode -[Device] -PrimaryInput=Keypad diff --git a/tools/shared/deviceskin/skins/PDAPhone.qrc b/tools/shared/deviceskin/skins/PDAPhone.qrc deleted file mode 100644 index 1a1c35a..0000000 --- a/tools/shared/deviceskin/skins/PDAPhone.qrc +++ /dev/null @@ -1,5 +0,0 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource prefix="/skins"> - <file>PDAPhone.skin</file> -</qresource> -</RCC> diff --git a/tools/shared/deviceskin/skins/PDAPhone.skin/PDAPhone.skin b/tools/shared/deviceskin/skins/PDAPhone.skin/PDAPhone.skin deleted file mode 100644 index d6a1966..0000000 --- a/tools/shared/deviceskin/skins/PDAPhone.skin/PDAPhone.skin +++ /dev/null @@ -1,18 +0,0 @@ -[SkinFile] -Up=pda_up.png -Down=pda_down.png -Screen=42 59 176 220 -Cursor=finger.png 20 20 -Areas=10 -HasMouseHover=false - -"Power" 0x0100000a 117 21 141 42 -"Context1" 0x01100000 43 284 74 315 -"Call" 0x01100004 74 284 104 315 -"Hangup" 0x01100005 154 284 184 315 -"Back" 0x01000061 184 284 214 315 -"Left" 0x1000012 123 315 110 326 106 307 113 288 123 300 120 307 -"Down" 0x1000015 123 315 130 318 138 315 150 326 129 335 111 325 -"Right" 0x1000014 137 301 149 290 155 308 150 324 138 315 140 308 -"Up" 0x1000013 123 300 112 289 130 282 149 290 137 300 130 298 -"Select" 0x01010000 131 298 137 300 140 307 138 315 130 318 123 316 120 307 123 300 diff --git a/tools/shared/deviceskin/skins/PDAPhone.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/PDAPhone.skin/defaultbuttons.conf deleted file mode 100644 index e3ae813..0000000 --- a/tools/shared/deviceskin/skins/PDAPhone.skin/defaultbuttons.conf +++ /dev/null @@ -1,36 +0,0 @@ -[Translation] -File=QtopiaDefaults -Context=Buttons -[Menu] -Rows=4 -Columns=3 -Map=123456789*0# -Default=5 -1=Applications/camera.desktop -2=Applications/datebook.desktop -3=Applications -4=Applications/qtmail.desktop -5=Applications/addressbook.desktop -6=Games -7=Settings/Beaming.desktop -8=Applications/simapp.desktop,Applications/calculator.desktop -9=Settings -*=Applications/mediarecorder.desktop -0=Applications/todolist.desktop -#=Documents -Animator=Bounce -AnimatorBackground=Radial -[SoftKeys] -Count=3 -Key0=Context1 -Key1=Select -Key2=Back -[SystemButtons] -Count=5 -Key0=Context1 -Key1=Back -Key2=Select -Key3=Call -Key4=Hangup -[Device] -PrimaryInput=Touchscreen diff --git a/tools/shared/deviceskin/skins/PDAPhone.skin/finger.png b/tools/shared/deviceskin/skins/PDAPhone.skin/finger.png Binary files differdeleted file mode 100644 index 24cf0cb..0000000 --- a/tools/shared/deviceskin/skins/PDAPhone.skin/finger.png +++ /dev/null diff --git a/tools/shared/deviceskin/skins/PDAPhone.skin/pda_down.png b/tools/shared/deviceskin/skins/PDAPhone.skin/pda_down.png Binary files differdeleted file mode 100644 index f65c059..0000000 --- a/tools/shared/deviceskin/skins/PDAPhone.skin/pda_down.png +++ /dev/null diff --git a/tools/shared/deviceskin/skins/PDAPhone.skin/pda_up.png b/tools/shared/deviceskin/skins/PDAPhone.skin/pda_up.png Binary files differdeleted file mode 100644 index 541e3c4..0000000 --- a/tools/shared/deviceskin/skins/PDAPhone.skin/pda_up.png +++ /dev/null diff --git a/tools/shared/deviceskin/skins/Trolltech-Keypad.qrc b/tools/shared/deviceskin/skins/Trolltech-Keypad.qrc deleted file mode 100644 index 4775068..0000000 --- a/tools/shared/deviceskin/skins/Trolltech-Keypad.qrc +++ /dev/null @@ -1,5 +0,0 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource prefix="/skins"> - <file>Trolltech-Keypad.skin</file> -</qresource> -</RCC> diff --git a/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-closed.png b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-closed.png Binary files differdeleted file mode 100644 index 8dd5719..0000000 --- a/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-closed.png +++ /dev/null diff --git a/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-down.png b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-down.png Binary files differdeleted file mode 100644 index 5e1e6be..0000000 --- a/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-down.png +++ /dev/null diff --git a/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.png b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.png Binary files differdeleted file mode 100644 index fb3d549..0000000 --- a/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.png +++ /dev/null diff --git a/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.skin b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.skin deleted file mode 100644 index 4d90321..0000000 --- a/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.skin +++ /dev/null @@ -1,35 +0,0 @@ -[SkinFile] -Up=Trolltech-Keypad.png -Down=Trolltech-Keypad-down.png -Closed=Trolltech-Keypad-closed.png -ClosedAreas=F1 F2 F3 Flip -ClosedScreen=95 456 128 96 -Screen=75 85 176 220 -Areas=25 -HasMouseHover=false -"1" 0x0031 65 542 68 536 76 532 114 536 114 573 64 568 -"2" 0x0032 133 537 188 574 -"3" 0x0033 206 536 246 532 252 536 256 542 258 569 205 572 -"4" 0x0034 64 578 114 618 -"5" 0x0035 133 581 188 618 -"6" 0x0036 206 580 256 577 258 613 206 616 -"7" 0x0037 66 622 116 625 114 662 66 658 -"8" 0x0038 133 626 188 662 -"9" 0x0039 206 625 256 622 256 658 206 661 -"*" 0x002a 68 667 116 670 114 705 86 699 76 693 69 686 -"0" 0x0030 133 671 188 708 -"#" 0x0023 206 670 254 665 254 684 245 692 232 699 206 704 -"Context1" 0x01100000 69 420 75 410 85 404 101 404 102 458 69 458 -"Back" 0x01000061 218 404 234 404 240 408 248 418 248 456 218 457 -"Home" 0x1000010 140 494 180 514 -"Hangup" 0x01100005 218 457 248 456 248 496 243 507 230 514 194 514 194 494 206 492 213 486 218 478 -"Call" 0x01100004 68 458 102 460 102 479 108 487 118 492 126 494 126 514 86 514 77 507 72 496 -"Select" 0x01010000 138 426 182 458 -"Up" 0x1000013 118 406 201 402 184 423 134 422 -"Right" 0x1000014 184 424 201 402 202 476 184 460 -"Down" 0x1000015 135 462 184 461 199 477 118 477 -"Left" 0x1000012 118 406 134 424 134 461 117 476 -"F1" 0x1000030 0 408 45 456 -"F2" 0x1000031 0 456 45 509 -"F3" 0x1000032 0 545 45 582 -"Flip" 0x1100006 32 353 293 386 diff --git a/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/defaultbuttons.conf deleted file mode 100644 index 6a78e67..0000000 --- a/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/defaultbuttons.conf +++ /dev/null @@ -1,142 +0,0 @@ -[Translation] -File=QtopiaDefaults -Context=Buttons -[Button] -Count=8 -[Button7] -Name[]=Home Down Button -Key=Down -Context=HomeScreen -PressedActionMappable=0 -HeldActionService=Messaging -HeldActionMessage=raise() -[Button6] -Name[]=Home Up Button -Key=Up -Context=HomeScreen -PressedActionMappable=0 -HeldActionService=Contacts -HeldActionMessage=raise() -[Button5] -Name[]=Home Right Button -Key=Right -Context=HomeScreen -PressedActionMappable=0 -HeldActionService=mediaplayer -HeldActionMessage=raise() -[Button4] -Name[]=Calender Button -Key=Left -Context=HomeScreen -PressedActionMappable=0 -HeldActionService=Calendar -HeldActionMessage=raiseToday() -[Button3] -Name[]=Left Soft Key -Key=Context1 -HeldActionService=TaskManager -HeldActionMessage=showRunningTasks() -HeldActionMappable=0 -PressActionMappable=0 -[Button2] -Name[]=VoiceNotes Button -Key=F1 -PressedActionService=mediarecorder -PressedActionMessage=raise() -HeldActionService=mediarecorder -HeldActionMessage=newEvent() -[Button1] -Name[]=Camera Button -Key=F2 -PressedActionService=Camera -PressedActionMessage=raise() -HeldActionService=Tasks -HeldActionMessage=newTask() -[Button0] -Name[]=Home Button -Key=Home -PressedActionMappable=0 -PressedActionService=TaskManager -PressedActionMessage=multitask() -HeldActionMappable=0 -HeldActionService=TaskManager -HeldActionMessage=showRunningTasks() -[Menu] -Rows=4 -Columns=3 -Map=123456789*0# -Default=5 -1=Applications/camera.desktop -2=Applications/mediaplayer.desktop -3=Applications/simapp.desktop,Applications/calculator.desktop -4=Applications/qtmail.desktop -5=Applications/addressbook.desktop -6=Applications/datebook.desktop -7=Games -8=Settings/Beaming.desktop -9=Applications/todolist.desktop -*=Settings -0=Applications -#=Documents -Animator=Bounce -AnimatorBackground=Radial -[SoftKeys] -Count=3 -Key0=Context1 -Key1=Select -Key2=Back -[SystemButtons] -Count=6 -Key0=Context1 -Key1=Select -Key2=Back -Key3=Call -Key4=Hangup -Key5=Flip -[TextButtons] -Buttons=0123456789*# -Hold0='0 -Hold1='1 -Hold2='2 -Hold3='3 -Hold4='4 -Hold5='5 -Hold6='6 -Hold7='7 -Hold8='8 -Hold9='9 -Hold*=symbol -Hold#=mode -Tap0=space -Tap0=space -Tap1="\".,'?!-@:1" -Tap2="\"a\xe4\xe5\xe6\xe0\xe1\xe2\x62\x63\xe7\x32" -Tap3="\"de\xe8\xe9\xea\x66\x33" -Tap4="\"ghi\xec\xed\xee\x34" -Tap5="\"jkl5" -Tap6="\"mn\xf1o\xf6\xf8\xf2\xf3\x36" -Tap7="\"pqrs\xdf\x37" -Tap8="\"tu\xfc\xf9\xfav8" -Tap9="\"wxyz9" -Tap*=modify -Tap#=shift -[LocaleTextButtons] -Buttons=23456789 -Tap2[]='abc -Tap3[]='def -Tap4[]='ghi -Tap5[]='jkl -Tap6[]='mno -Tap7[]='pqrs -Tap8[]='tuv -Tap9[]='wxyz -[PhoneTextButtons] -Buttons=*# -Tap*='*+pw -Hold*=+ -Tap#='# -Hold#=mode -[Device] -PrimaryInput=Keypad -[Environment] -QWS_DISPLAY=Multi: LinuxFb:mmHeight57:0 LinuxFb:offset=0,320:1 :0 diff --git a/tools/shared/deviceskin/skins/Trolltech-Touchscreen.qrc b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.qrc deleted file mode 100644 index 40fafeb..0000000 --- a/tools/shared/deviceskin/skins/Trolltech-Touchscreen.qrc +++ /dev/null @@ -1,5 +0,0 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource prefix="/skins"> - <file>Trolltech-Touchscreen.skin</file> -</qresource> -</RCC> diff --git a/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen-down.png b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen-down.png Binary files differdeleted file mode 100644 index c1a422f..0000000 --- a/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen-down.png +++ /dev/null diff --git a/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.png b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.png Binary files differdeleted file mode 100644 index 544a425..0000000 --- a/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.png +++ /dev/null diff --git a/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.skin b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.skin deleted file mode 100644 index 5de882e..0000000 --- a/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.skin +++ /dev/null @@ -1,17 +0,0 @@ -[SkinFile] -Up=Trolltech-Touchscreen.png -Down=Trolltech-Touchscreen-down.png -Screen=40 109 176 220 -Areas=10 -HasMouseHover=false - -"Context1" 0x01100000 38 420 44 408 52 404 68 403 68 458 40 458 -"Back" 0x01000061 185 42 202 398 211 410 216 418 219 456 186 456 -"Call" 0x01100004 38 458 70 458 71 478 75 486 83 492 94 494 94 516 56 516 45 507 38 498 -"Hangup" 0x01100005 186 458 220 458 220 496 214 508 200 516 162 516 161 494 172 492 180 486 185 478 -"Left" 0x1000012 86 405 106 426 106 461 85 478 -"Down" 0x1000015 106 460 151 460 170 480 85 480 -"Right" 0x1000014 151 424 170 404 170 480 151 460 -"Up" 0x1000013 85 403 168 403 150 424 106 424 -"Select" 0x01010000 106 426 150 456 -"Home" 0x1000010 105 493 145 512 diff --git a/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/defaultbuttons.conf deleted file mode 100644 index 6665125..0000000 --- a/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/defaultbuttons.conf +++ /dev/null @@ -1,53 +0,0 @@ -[Translation] -File=QtopiaDefaults -Context=Buttons -[Menu] -Rows=4 -Columns=3 -Map=123456789*0# -Default=5 -1=Applications/camera.desktop -2=Applications/mediaplayer.desktop -3=Applications/simapp.desktop,Applications/calculator.desktop -4=Applications/qtmail.desktop -5=Applications/addressbook.desktop -6=Applications/datebook.desktop -7=Games -8=Settings/beaming.desktop -9=Applications/todolist.desktop -*=Settings -0=Applications -#=Documents -Animator=Bounce -AnimatorBackground=Radial -[SoftKeys] -Count=3 -Key0=Context1 -Key1=Select -Key2=Back -[SystemButtons] -Count=5 -Key0=Context1 -Key1=Back -Key2=Select -Key3=Call -Key4=Hangup -[Device] -PrimaryInput=Touchscreen -[Button] -Count=2 -[Button0] -Name[]=Home Button -Key=Home -PressedActionMappable=0 -PressedActionService=TaskManager -PressedActionMessage=multitask() -HeldActionMappable=0 -HeldActionService=TaskManager -HeldActionMessage=showRunningTasks() -[Button1] -Name=Power Button -Key=Hangup -HeldActionService=Launcher -HeldActionMessage=execute(QString) -HeldActionArgs=@ByteArray(\0\0\0\x1\0\0\0\n\0\0\0\0\x10\0s\0h\0u\0t\0\x64\0o\0w\0n) diff --git a/tools/shared/fontpanel/fontpanel.cpp b/tools/shared/fontpanel/fontpanel.cpp index ad297df..fe221fd 100644 --- a/tools/shared/fontpanel/fontpanel.cpp +++ b/tools/shared/fontpanel/fontpanel.cpp @@ -96,8 +96,12 @@ QFont FontPanel::selectedFont() const const QString family = rc.family(); rc.setPointSize(pointSize()); const QString styleDescription = styleString(); - rc.setItalic(m_fontDatabase.italic(family, styleDescription)); - + if (styleDescription.contains(QLatin1String("Italic"))) + rc.setStyle(QFont::StyleItalic); + else if (styleDescription.contains(QLatin1String("Oblique"))) + rc.setStyle(QFont::StyleOblique); + else + rc.setStyle(QFont::StyleNormal); rc.setBold(m_fontDatabase.bold(family, styleDescription)); // Weight < 0 asserts... diff --git a/tools/shared/symbian/epocroot.cpp b/tools/shared/symbian/epocroot.cpp index 071477d..064e056 100644 --- a/tools/shared/symbian/epocroot.cpp +++ b/tools/shared/symbian/epocroot.cpp @@ -153,10 +153,13 @@ QString epocRoot() while (!(xml.isEndElement() && xml.name() == "devices") && !xml.atEnd()) { xml.readNext(); if (xml.isStartElement() && xml.name() == "device") { - const bool isDefault = xml.attributes().value("default") == "yes"; + const bool isDefault = xml.attributes().value("default") == "yes"; const QString id = xml.attributes().value("id").toString(); - const QString name = xml.attributes().value("name").toString(); - const bool epocDeviceMatch = (id + ":" + name) == epocDeviceValue; + const QString name = xml.attributes().value("name").toString(); + const QString alias = xml.attributes().value("alias").toString(); + bool epocDeviceMatch = (id + ":" + name) == epocDeviceValue; + if (!alias.isEmpty()) + epocDeviceMatch |= alias == epocDeviceValue; epocDeviceFound |= epocDeviceMatch; if((epocDeviceValue.isEmpty() && isDefault) || epocDeviceMatch) { diff --git a/tools/shared/windows/registry.cpp b/tools/shared/windows/registry.cpp index d342d78..67d9b56 100644 --- a/tools/shared/windows/registry.cpp +++ b/tools/shared/windows/registry.cpp @@ -148,7 +148,7 @@ QString readRegistryKey(HKEY parentHandle, const QString &rSubkey) } default: - qWarning("QSettings: unknown data %d type in windows registry", dataType); + qWarning("QSettings: unknown data %u type in windows registry", quint32(dataType)); break; } diff --git a/tools/tools.pro b/tools/tools.pro index f6f2dcd..f254230 100644 --- a/tools/tools.pro +++ b/tools/tools.pro @@ -1,32 +1,39 @@ TEMPLATE = subdirs -no-png { - message("Some graphics-related tools are unavailable without PNG support") -} else { - SUBDIRS += assistant \ - pixeltool \ - porting \ - qtestlib \ - qttracereplay - contains(QT_EDITION, Console) { - SUBDIRS += designer/src/uitools # Linguist depends on this - } else { - SUBDIRS += designer - } - SUBDIRS += linguist - symbian: SUBDIRS = designer - wince*: SUBDIRS = qtestlib designer - unix:!mac:!embedded:contains(QT_CONFIG, qt3support):SUBDIRS += qtconfig - win32:!wince*:SUBDIRS += activeqt +!contains(QT_CONFIG, no-gui) { + no-png { + message("Some graphics-related tools are unavailable without PNG support") + } else { + symbian { + SUBDIRS = designer + } else:wince* { + SUBDIRS = qtestlib designer + } else { + SUBDIRS = assistant \ + pixeltool \ + porting \ + qtestlib \ + qttracereplay + contains(QT_EDITION, Console) { + SUBDIRS += designer/src/uitools # Linguist depends on this + } else { + SUBDIRS += designer + } + } + unix:!mac:!embedded:contains(QT_CONFIG, qt3support):SUBDIRS += qtconfig + win32:!wince*:SUBDIRS += activeqt + } + contains(QT_CONFIG, declarative):SUBDIRS += qml } +!wince*:!symbian:SUBDIRS += linguist + mac { SUBDIRS += macdeployqt } embedded:SUBDIRS += kmap2qmap -contains(QT_CONFIG, declarative):SUBDIRS += qmlviewer qmldebugger contains(QT_CONFIG, dbus):SUBDIRS += qdbus # We don't need these command line utilities on embedded platforms. !wince*:!symbian:contains(QT_CONFIG, xmlpatterns): SUBDIRS += xmlpatterns xmlpatternsvalidator |