diff options
Diffstat (limited to 'tools')
302 files changed, 25285 insertions, 12863 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/Info_mac.plist b/tools/assistant/compat/Info_mac.plist deleted file mode 100644 index b1e6336..0000000 --- a/tools/assistant/compat/Info_mac.plist +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"> -<plist version="0.9"> -<dict> - <key>CFBundleIconFile</key> - <string>@ICON@</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> - <key>CFBundleExecutable</key> - <string>@EXECUTABLE@</string> -</dict> -</plist> 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/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..83491a0 100644 --- a/tools/assistant/lib/qhelpprojectdata.cpp +++ b/tools/assistant/lib/qhelpprojectdata.cpp @@ -41,6 +41,7 @@ #include "qhelpprojectdata_p.h" +#include <QtCore/QCoreApplication> #include <QtCore/QDir> #include <QtCore/QFileInfo> #include <QtCore/QStack> @@ -82,7 +83,7 @@ private: void QHelpProjectDataPrivate::raiseUnknownTokenError() { - raiseError(QObject::tr("Unknown token.")); + raiseError(QCoreApplication::translate("QHelpProject", "Unknown token.")); } void QHelpProjectDataPrivate::readData(const QByteArray &contents) @@ -95,12 +96,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())); } } @@ -113,11 +116,15 @@ void QHelpProjectDataPrivate::readProject() if (name() == QLatin1String("virtualFolder")) { virtualFolder = readElementText(); if (virtualFolder.contains(QLatin1String("/"))) - raiseError(QObject::tr("A virtual folder must not contain a \'/\' character!")); + raiseError(QCoreApplication::translate("QHelpProject", + "A virtual folder must not contain " + "a \'/\' character!")); } else if (name() == QLatin1String("namespace")) { namespaceName = readElementText(); if (namespaceName.contains(QLatin1String("/"))) - raiseError(QObject::tr("A namespace must not contain a \'/\' character!")); + raiseError(QCoreApplication::translate("QHelpProject", + "A namespace must not contain a " + "\'/\' character!")); } 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(); } @@ -346,8 +359,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..2359479 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, @@ -719,13 +568,21 @@ void CentralWidget::connectSignals() } } -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 +596,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 +618,7 @@ void CentralWidget::setTabTitle(const QUrl &url) void CentralWidget::currentPageChanged(int index) { + TRACE_OBJ const HelpViewer *viewer = currentHelpViewer(); if (viewer) lastTabPage = index; @@ -775,6 +634,7 @@ void CentralWidget::currentPageChanged(int index) void CentralWidget::showTabBarContextMenu(const QPoint &point) { + TRACE_OBJ HelpViewer *viewer = helpViewerFromTabPosition(tabWidget, point); if (!viewer) return; @@ -822,11 +682,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 +695,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 +735,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 +789,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 +813,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 +846,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 +862,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 +871,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 +905,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 +930,7 @@ void CentralWidget::activateSearchWidget(bool updateLastTabPage) void CentralWidget::removeSearchWidget() { + TRACE_OBJ if (searchWidgetAttached()) { tabWidget->removeTab(0); m_searchWidget->setAttached(false); @@ -1062,6 +939,7 @@ void CentralWidget::removeSearchWidget() int CentralWidget::availableHelpViewer() const { + TRACE_OBJ int count = tabWidget->count(); if (searchWidgetAttached()) count--; @@ -1070,6 +948,7 @@ int CentralWidget::availableHelpViewer() const bool CentralWidget::enableTabCloseAction() const { + TRACE_OBJ int minTabCount = 1; if (searchWidgetAttached()) minTabCount = 2; @@ -1079,6 +958,7 @@ bool CentralWidget::enableTabCloseAction() const QString CentralWidget::quoteTabTitle(const QString &title) const { + TRACE_OBJ QString s = title; return s.replace(QLatin1Char('&'), QLatin1String("&&")); } @@ -1086,6 +966,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 +979,7 @@ CentralWidget::setSourceFromSearch(const QUrl &url) void CentralWidget::setSourceFromSearchInNewTab(const QUrl &url) { + TRACE_OBJ setSourceInNewTab(url); #if defined(QT_NO_WEBKIT) highlightSearchTerms(); @@ -1110,11 +992,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 +1058,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 +1092,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 +1102,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..e0347c8 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,27 +102,34 @@ 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); @@ -132,7 +144,7 @@ bool ContentWindow::eventFilter(QObject *o, QEvent *e) 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 +158,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 +170,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,6 +184,7 @@ void ContentWindow::showContextMenu(const QPoint &pos) void ContentWindow::itemClicked(const QModelIndex &index) { + TRACE_OBJ QHelpContentModel *contentModel = qobject_cast<QHelpContentModel*>(m_contentWidget->model()); @@ -181,10 +195,4 @@ void ContentWindow::itemClicked(const QModelIndex &index) } } -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..9b06400 100644 --- a/tools/assistant/tools/assistant/helpviewer.cpp +++ b/tools/assistant/tools/assistant/helpviewer.cpp @@ -38,590 +38,88 @@ ** $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); +QString AbstractHelpViewer::AboutBlank = + QCoreApplication::translate("HelpViewer", "<title>about:blank</title>"); - setHeader(QNetworkRequest::ContentTypeHeader, mimeType); - setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(origLen)); - QTimer::singleShot(0, this, SIGNAL(metaDataChanged())); - QTimer::singleShot(0, this, SIGNAL(readyRead())); -} +QString AbstractHelpViewer::LocalHelpFile = QLatin1String("qthelp://" + "com.trolltech.com.assistantinternal-1.0.0/assistant/assistant.html"); -void HelpNetworkReply::abort() -{ - // nothing to do -} +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>"); -qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen) +AbstractHelpViewer::AbstractHelpViewer() { - 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; -}; - -HelpNetworkAccessManager::HelpNetworkAccessManager(QHelpEngine *engine, - QObject *parent) - : QNetworkAccessManager(parent), helpEngine(engine) +AbstractHelpViewer::~AbstractHelpViewer() { } -QNetworkReply *HelpNetworkAccessManager::createRequest(Operation /*op*/, - const QNetworkRequest &request, QIODevice* /*outgoingData*/) +bool AbstractHelpViewer::isLocalUrl(const QUrl &url) { - 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; -}; - -HelpPage::HelpPage(CentralWidget *central, QHelpEngine *engine, QObject *parent) - : QWebPage(parent) - , centralWidget(central) - , helpEngine(engine) - , closeNewTabIfNeeded(false) - , m_pressedButtons(Qt::NoButton) - , m_keyboardModifiers(Qt::NoModifier) -{ -} - -QWebPage *HelpPage::createWindow(QWebPage::WebWindowType) -{ - HelpPage* newPage = static_cast<HelpPage*>(centralWidget->newEmptyTab()->page()); - if (newPage) - newPage->closeNewTabIfNeeded = closeNewTabIfNeeded; - closeNewTabIfNeeded = false; - return newPage; -} - -static bool 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; + || scheme == QLatin1String("about"); } -void HelpPage::triggerAction(WebAction action, bool checked) +bool AbstractHelpViewer::canOpenPage(const QString &url) { - switch (action) { - case OpenLinkInNewWindow: - closeNewTabIfNeeded = true; - default: // fall through - QWebPage::triggerAction(action, checked); - break; - } + TRACE_OBJ + return url.endsWith(QLatin1String(".html"), Qt::CaseInsensitive) + || url.endsWith(QLatin1String(".htm"), Qt::CaseInsensitive) + || url == QLatin1String("about:blank"); } -bool HelpPage::acceptNavigationRequest(QWebFrame *, - const QNetworkRequest &request, QWebPage::NavigationType type) +bool AbstractHelpViewer::launchWithExternalApp(const QUrl &url) { - const QUrl &url = request.url(); - const bool closeNewTab = closeNewTabIfNeeded; - closeNewTabIfNeeded = false; - + TRACE_OBJ 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"); + const HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + const QUrl &resolvedUrl = helpEngine.findFile(url); + if (!resolvedUrl.isValid()) 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; + const QString& path = resolvedUrl.path(); + if (!canOpenPage(path)) { + QTemporaryFile tmpTmpFile; + if (!tmpTmpFile.open()) 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)); -} - -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::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); -} - -void HelpViewer::mouseReleaseEvent(QMouseEvent *e) -{ - 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--; -} - -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()); - - 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..9e8f5f4 100644 --- a/tools/assistant/tools/assistant/helpviewer.h +++ b/tools/assistant/tools/assistant/helpviewer.h @@ -38,139 +38,41 @@ ** $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; - -#if !defined(QT_NO_WEBKIT) - -class HelpViewer : public QWebView -{ - 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 - - void resetZoom(); - void zoomIn(qreal range = 1); - void zoomOut(qreal range = 1); - - 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; } - inline qreal zoom() const - { return textSizeMultiplier(); } +class QUrl; -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 &); - -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; -}; - -#else - -class HelpViewer : public QTextBrowser +class AbstractHelpViewer { - 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(); } + AbstractHelpViewer(); + virtual ~AbstractHelpViewer(); - bool launchedWithExternalApp(const QUrl &url); + virtual QFont viewerFont() const = 0; + virtual void setViewerFont(const QFont &font) = 0; -public Q_SLOTS: - void home(); + virtual void scaleUp() = 0; + virtual void scaleDown() = 0; + + virtual void resetScale() = 0; + virtual qreal scale() const = 0; -protected: - void wheelEvent(QWheelEvent *e); + static QString AboutBlank; + static QString LocalHelpFile; + static QString PageNotFoundMessage; -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; + static bool isLocalUrl(const QUrl &url); + static bool canOpenPage(const QString &url); + static bool launchWithExternalApp(const QUrl &url); }; -#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..07b89eb --- /dev/null +++ b/tools/assistant/tools/assistant/helpviewer_qtb.cpp @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** 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; +} + +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 + 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) +{ + 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); +} diff --git a/tools/assistant/tools/assistant/helpviewer_qtb.h b/tools/assistant/tools/assistant/helpviewer_qtb.h new file mode 100644 index 0000000..a05782c --- /dev/null +++ b/tools/assistant/tools/assistant/helpviewer_qtb.h @@ -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 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; } + + 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); + +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..582d013 --- /dev/null +++ b/tools/assistant/tools/assistant/helpviewer_qwv.cpp @@ -0,0 +1,385 @@ +/**************************************************************************** +** +** 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 + 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"); + } + + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + const QByteArray &data = helpEngine.findFile(url).isValid() + ? helpEngine.fileData(url) + : AbstractHelpViewer::PageNotFoundMessage.arg(url.toString()).toUtf8(); + return new HelpNetworkReply(request, data, 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))); + + 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); +} + +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 + if (e->button() == Qt::XButton1) { + triggerPageAction(QWebPage::Back); + return; + } + + if (e->button() == Qt::XButton2) { + triggerPageAction(QWebPage::Forward); + return; + } + + 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 + 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..41ee553 --- /dev/null +++ b/tools/assistant/tools/assistant/helpviewer_qwv.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** 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(); } + + 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 &); + +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..0b14cba 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -248,6 +248,8 @@ Configure::Configure( int& argc, char** argv ) dictionary[ "PHONON_BACKEND" ] = "yes"; dictionary[ "MULTIMEDIA" ] = "yes"; dictionary[ "AUDIO_BACKEND" ] = "auto"; + dictionary[ "MEDIASERVICE"] = "auto"; + dictionary[ "WMSDK" ] = "auto"; dictionary[ "DIRECTSHOW" ] = "no"; dictionary[ "WEBKIT" ] = "auto"; dictionary[ "DECLARATIVE" ] = "auto"; @@ -701,9 +703,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"; @@ -910,6 +909,10 @@ void Configure::parseCmdLine() dictionary[ "AUDIO_BACKEND" ] = "yes"; } else if( configCmdLine.at(i) == "-no-audio-backend" ) { dictionary[ "AUDIO_BACKEND" ] = "no"; + } else if( configCmdLine.at(i) == "-mediaservice") { + dictionary[ "MEDIASERVICE" ] = "yes"; + } else if (configCmdLine.at(i) == "-no-mediaservice") { + dictionary[ "MEDIASERVICE" ] = "no"; } else if( configCmdLine.at(i) == "-no-phonon" ) { dictionary[ "PHONON" ] = "no"; } else if( configCmdLine.at(i) == "-phonon" ) { @@ -964,6 +967,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 +1075,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) @@ -1488,6 +1498,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"; @@ -1565,7 +1576,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" @@ -1587,6 +1598,7 @@ bool Configure::displayHelp() "[-qtnamespace <namespace>] [-qtlibinfix <infix>] [-no-phonon]\n" "[-phonon] [-no-phonon-backend] [-phonon-backend]\n" "[-no-multimedia] [-multimedia] [-no-audio-backend] [-audio-backend]\n" + "[-no-mediaservice] [-mediaservice]\n" "[-no-script] [-script] [-no-scripttools] [-scripttools]\n" "[-no-webkit] [-webkit] [-graphicssystem raster|opengl|openvg]\n\n", 0, 7); @@ -1605,6 +1617,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)"); @@ -1770,6 +1783,8 @@ bool Configure::displayHelp() desc("MULTIMEDIA", "yes","-multimedia", "Compile in multimedia module"); desc("AUDIO_BACKEND", "no","-no-audio-backend", "Do not compile in the platform audio backend into QtMultimedia"); desc("AUDIO_BACKEND", "yes","-audio-backend", "Compile in the platform audio backend into QtMultimedia"); + desc("MEDIASERVICE", "no","-no-mediaservice", "Do not compile in the platform-specific QtMultimedia media service."); + desc("MEDIASERVICE", "yes","-mediaservice", "Compile in the platform-specific QtMultimedia media service."); desc("WEBKIT", "no", "-no-webkit", "Do not compile in the WebKit module"); desc("WEBKIT", "yes", "-webkit", "Compile in the WebKit module (WebKit is built if a decent C++ compiler is used.)"); desc("SCRIPT", "no", "-no-script", "Do not build the QtScript module."); @@ -1826,7 +1841,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 +1886,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 +1978,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 +2029,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") @@ -2046,7 +2066,7 @@ bool Configure::checkAvailability(const QString &part) && dictionary.value("QMAKESPEC") != "win32-msvc.net" // Leave for now, since we can't be sure if they are using 2002 or 2003 with this spec && dictionary.value("QMAKESPEC") != "win32-msvc2002" && dictionary.value("EXCEPTIONS") == "yes"; - } else if (part == "PHONON") { + } else if (part == "PHONON" || part == "MEDIASERVICE") { 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")) @@ -2064,12 +2084,12 @@ bool Configure::checkAvailability(const QString &part) 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") { + } 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"); } else if (part == "AUDIO_BACKEND") { available = true; if (dictionary.contains("XQMAKESPEC") && dictionary["XQMAKESPEC"].startsWith("symbian")) { @@ -2195,7 +2215,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 +2223,13 @@ 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["MEDIASERVICE"] == "auto") + dictionary["MEDIASERVICE"] = checkAvailability("MEDIASERVICE") ? "yes" : "no"; + if (dictionary["WMSDK"] == "auto") + dictionary["WMSDK"] = checkAvailability("WMSDK") ? "yes" : "no"; // Qt/WinCE remote test application if (dictionary["CETEST"] == "auto") @@ -2249,15 +2273,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; } @@ -2541,11 +2573,6 @@ void Configure::generateOutputVars() qtConfig += "egl"; } - if ( dictionary["OPENGL_ES_CL"] == "yes" ) { - qtConfig += "opengles1cl"; - qtConfig += "egl"; - } - if ( dictionary["OPENVG"] == "yes" ) { qtConfig += "openvg"; qtConfig += "egl"; @@ -2601,13 +2628,24 @@ void Configure::generateOutputVars() qtConfig += "multimedia"; if (dictionary["AUDIO_BACKEND"] == "yes") qtConfig += "audio-backend"; + if (dictionary["MEDIASERVICE"] == "yes") { + qtConfig += "mediaservice"; + if (dictionary["WMSDK"] == "yes") + qtConfig += "wmsdk"; + } } 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 +2691,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 +2895,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(); @@ -2999,13 +3042,10 @@ void Configure::generateConfigfiles() if(dictionary["NATIVE_GESTURES"] == "no") qconfigList += "QT_NO_NATIVE_GESTURES"; 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 +3199,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 +3214,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 +3230,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 +3377,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; @@ -3464,14 +3508,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 +3524,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 +3569,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 +3580,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..74bebb2 100644 --- a/tools/configure/environment.cpp +++ b/tools/configure/environment.cpp @@ -357,7 +357,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 +378,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/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/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/propertyeditor.cpp b/tools/designer/src/components/propertyeditor/propertyeditor.cpp index b171ddc..86d7bdf 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 *e) { + 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/qdesigner_actions.cpp b/tools/designer/src/designer/qdesigner_actions.cpp index 887ba98..6776351 100644 --- a/tools/designer/src/designer/qdesigner_actions.cpp +++ b/tools/designer/src/designer/qdesigner_actions.cpp @@ -200,9 +200,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()); @@ -490,13 +496,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/lib/shared/filterwidget.cpp b/tools/designer/src/lib/shared/filterwidget.cpp index 6c73a08..f485346 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,44 @@ 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 + QPixmap iconpixmap = icon().pixmap(ICONBUTTON_SIZE, ICONBUTTON_SIZE, isDown() ? + QIcon::Selected : QIcon::Normal); + 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 +147,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 + 2, 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 +201,38 @@ FilterWidget::FilterWidget(QWidget *parent, LayoutMode lm) : QString FilterWidget::text() const { - return m_editor->typedText(); + return m_editor->text(); } void FilterWidget::checkButton(const QString &) { - m_button->setEnabled(!text().isEmpty()); + m_button->animateShow(!m_editor->text().isEmpty()); } 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..423b30e 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,9 @@ private slots: void checkButton(const QString &text); private: - QPushButton *m_button; HintLineEdit *m_editor; + IconButton *m_button; + int m_buttonwidth; }; } // 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/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..77ab2a6 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 { @@ -1451,8 +1454,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/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..7d73596 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"))); 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/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..1f88931 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 + 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..0003baa 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; } @@ -560,73 +564,92 @@ 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(".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/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/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/qdoc3/codemarker.cpp b/tools/qdoc3/codemarker.cpp index ee93080..15f2c2d 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)); diff --git a/tools/qdoc3/codeparser.cpp b/tools/qdoc3/codeparser.cpp index 3ad3372..a717ff1 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")) @@ -170,6 +171,7 @@ QSet<QString> CodeParser::commonMetaCommands() << COMMAND_MAINCLASS << COMMAND_NONREENTRANT << COMMAND_OBSOLETE + << COMMAND_PAGEKEYWORDS << COMMAND_PRELIMINARY << COMMAND_INPUBLICGROUP << COMMAND_REENTRANT @@ -230,6 +232,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); 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..3150f28 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" @@ -671,7 +675,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..6f23469 100644 --- a/tools/qdoc3/config.h +++ b/tools/qdoc3/config.h @@ -140,8 +140,10 @@ class Config #define CONFIG_INDEXES "indexes" #define CONFIG_LANGUAGE "language" #define CONFIG_MACRO "macro" +#define CONFIG_NATURALLANGUAGE "naturallanguage" #define CONFIG_OBSOLETELINKS "obsoletelinks" #define CONFIG_OUTPUTDIR "outputdir" +#define CONFIG_OUTPUTENCODING "outputencoding" #define CONFIG_OUTPUTLANGUAGE "outputlanguage" #define CONFIG_OUTPUTFORMATS "outputformats" #define CONFIG_PROJECT "project" @@ -150,6 +152,7 @@ class Config #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_STYLESHEETS "stylesheets" diff --git a/tools/qdoc3/cppcodemarker.cpp b/tools/qdoc3/cppcodemarker.cpp index 6c33054..3ff6ebe 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; @@ -881,7 +881,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 +1067,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; @@ -1127,7 +1127,7 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, "signal", "signals"); FastSection qmlattachedsignals(qmlClassNode, - "QML Attached Signals", + "Attached Signals", "signal", "signals"); FastSection qmlmethods(qmlClassNode, @@ -1135,7 +1135,7 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, "method", "methods"); FastSection qmlattachedmethods(qmlClassNode, - "QML Attached Methods", + "Attached Methods", "method", "methods"); diff --git a/tools/qdoc3/cppcodeparser.cpp b/tools/qdoc3/cppcodeparser.cpp index 9b6a516..6884781 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(); } /*! @@ -536,7 +537,8 @@ QSet<QString> CppCodeParser::topicCommands() << COMMAND_QMLSIGNAL << COMMAND_QMLATTACHEDSIGNAL << COMMAND_QMLMETHOD - << COMMAND_QMLATTACHEDMETHOD; + << COMMAND_QMLATTACHEDMETHOD + << COMMAND_QMLBASICTYPE; #else << COMMAND_VARIABLE; #endif @@ -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) || @@ -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); @@ -2283,14 +2303,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; diff --git a/tools/qdoc3/doc.cpp b/tools/qdoc3/doc.cpp index 17a6efd..ad4cdde 100644 --- a/tools/qdoc3/doc.cpp +++ b/tools/qdoc3/doc.cpp @@ -3056,7 +3056,8 @@ QString Doc::canonicalTitle(const QString &title) slurping = true; } else { - // !alnum && slurping -> nothin + result += title[i]; + lastAlnum = result.size(); } } result.truncate(lastAlnum); 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..e2cf6c5 --- /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..e2f670c --- /dev/null +++ b/tools/qdoc3/doc/qdoc-manual.qdoc @@ -0,0 +1,8695 @@ +/**************************************************************************** +** +** 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 Variables} + \o \l{Creating Help Project Files} + \o \l{C++ Specific Variables} + \o \l{HTML Specific 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 + + \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 + \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 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 Variables} + \o \l {C++ Specific Variables} + \o \l {HTML Specific 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 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 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 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 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 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 Variables + \contentspage QDoc Manual - Table of Contents + \nextpage C++ Specific 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 Variables + + \title C++ Specific 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 Variables + \contentspage QDoc Manual - Table of Contents + \nextpage Supporting Derived Projects + + \title HTML Specific 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 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..62f191b 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" @@ -227,6 +226,7 @@ void Generator::terminate() imageFiles.clear(); imageDirs.clear(); outDir = ""; + QmlClassNode::clear(); } Generator *Generator::generatorForFormat(const QString& format) @@ -641,33 +641,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) @@ -1213,6 +1186,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..30d9af4 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; 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..cd3da3e 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -54,10 +54,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 +73,7 @@ QString HtmlGenerator::sinceTitles[] = " New Typedefs", " New Properties", " New Variables", + " New QML Elements", " New Qml Properties", " New Qml Signals", " New Qml Methods", @@ -266,6 +269,15 @@ void HtmlGenerator::initializeGenerator(const Config &config) 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()) { @@ -389,11 +401,13 @@ 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); + //qDebug() << "start helpProjectWriter->generate(myTree)"; helpProjectWriter->generate(myTree); + //qDebug() << "end helpProjectWriter->generate(myTree)"; } void HtmlGenerator::startText(const Node * /* relative */, @@ -431,11 +445,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 +497,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); @@ -516,7 +530,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, // fallthrough case Atom::CodeBad: out() << "<pre><font color=\"#404040\">" - << trimmedTrailing(protect(plainCode(indent(codeIndent,atom->string())))) + << trimmedTrailing(protectEnc(plainCode(indent(codeIndent,atom->string())))) << "</font></pre>\n"; break; case Atom::FootnoteLeft: @@ -676,6 +690,8 @@ 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; @@ -686,6 +702,11 @@ int HtmlGenerator::generateAtom(const Atom *atom, 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 +789,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")); + else if (idx == QmlClass) + generateCompactList(0, marker, nqcmap.value(), QString("Q")); else if (idx == MemberFunction) { ParentMaps parentmaps; ParentMaps::iterator pmap; @@ -792,7 +815,7 @@ 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); @@ -820,12 +843,12 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << "<p align=\"center\">"; 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); } @@ -923,7 +946,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, // ### Trenton out() << "<tr><td valign=\"top\"><tt>" - << protect(plainCode(marker->markedUpEnumValue(atom->next()->string(), + << protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(), relative))) << "</tt></td><td align=\"center\" valign=\"top\">"; @@ -936,7 +959,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, if (itemValue.isEmpty()) out() << "?"; else - out() << "<tt>" << protect(itemValue) << "</tt>"; + out() << "<tt>" << protectEnc(itemValue) << "</tt>"; skipAhead = 1; } @@ -1052,7 +1075,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, generateLink(atom, relative, marker); } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } break; case Atom::TableLeft: @@ -1166,7 +1189,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << "<font color=\"red\"><b><Missing HTML></b></font>"; break; case Atom::UnknownCommand: - out() << "<font color=\"red\"><b><code>\\" << protect(atom->string()) + out() << "<font color=\"red\"><b><code>\\" << protectEnc(atom->string()) << "</code></b></font>"; break; #ifdef QDOC_QML @@ -1250,7 +1273,6 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, generateIncludes(inner, marker); generateStatus(inner, marker); if (classe) { - generateModuleWarning(classe, marker); generateInherits(classe, marker); generateInheritedBy(classe, marker); } @@ -1295,7 +1317,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 +1326,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); } @@ -1343,7 +1365,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, 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()) { @@ -1428,14 +1450,19 @@ 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(), + generateTitle(fullTitle, Text() << fake->subTitle(), subTitleSize, fake, @@ -1509,11 +1536,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,7 +1557,7 @@ 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); @@ -1549,7 +1577,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; } @@ -1578,7 +1606,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,7 +1642,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) } } -QString HtmlGenerator::fileExtension(const Node * /* node */) +QString HtmlGenerator::fileExtension(const Node * /* node */) const { return "html"; } @@ -1624,11 +1652,11 @@ void HtmlGenerator::generateHeader(const QString& title, CodeMarker *marker, bool mainPage) { - out() << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"; + out() << QString("<?xml version=\"1.0\" encoding=\"%1\"?>\n").arg(outputEncoding); 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"; + " 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")) { @@ -1648,7 +1676,9 @@ void HtmlGenerator::generateHeader(const QString& title, } out() << "<head>\n" - " <title>" << shortVersion << protect(title) << "</title>\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"; @@ -1657,8 +1687,8 @@ void HtmlGenerator::generateHeader(const QString& title, QMapIterator<QString, QString> i(metaMap); while (i.hasNext()) { i.next(); - out() << " <meta name=\"" << protect(i.key()) << "\" contents=\"" - << protect(i.value()) << "\" />\n"; + out() << " <meta name=\"" << protectEnc(i.key()) << "\" contents=\"" + << protectEnc(i.value()) << "\" />\n"; } } @@ -1682,9 +1712,9 @@ void HtmlGenerator::generateHeader(const QString& title, navigationLinks += "[Previous: <a href=\"" + anchorPair.first + "\">"; if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); + navigationLinks += protectEnc(anchorPair.second); else - navigationLinks += protect(linkPair.second); + navigationLinks += protectEnc(linkPair.second); navigationLinks += "</a>]\n"; } if (node->links().contains(Node::ContentsLink)) { @@ -1700,9 +1730,9 @@ void HtmlGenerator::generateHeader(const QString& title, navigationLinks += "[<a href=\"" + anchorPair.first + "\">"; if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); + navigationLinks += protectEnc(anchorPair.second); else - navigationLinks += protect(linkPair.second); + navigationLinks += protectEnc(linkPair.second); navigationLinks += "</a>]\n"; } if (node->links().contains(Node::NextLink)) { @@ -1718,9 +1748,9 @@ void HtmlGenerator::generateHeader(const QString& title, navigationLinks += "[Next: <a href=\"" + anchorPair.first + "\">"; if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); + navigationLinks += protectEnc(anchorPair.second); else - navigationLinks += protect(linkPair.second); + navigationLinks += protectEnc(linkPair.second); navigationLinks += "</a>]\n"; } if (node->links().contains(Node::IndexLink)) { @@ -1771,7 +1801,7 @@ void HtmlGenerator::generateTitle(const QString& title, const Node *relative, CodeMarker *marker) { - out() << "<h1 class=\"title\">" << protect(title); + out() << "<h1 class=\"title\">" << protectEnc(title); if (!subTitle.isEmpty()) { out() << "<br />"; if (subTitleSize == SmallSubTitle) @@ -2009,18 +2039,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()) { @@ -2113,7 +2143,7 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, } else { out() << "<td>"; - out() << protect(node->doc().briefText().toString()); + out() << protectEnc(node->doc().briefText().toString()); out() << "</td>"; } out() << "</tr>\n"; @@ -2314,8 +2344,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() << " ("; @@ -2357,7 +2391,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 +2445,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 +2484,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); @@ -2556,7 +2590,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 +2602,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 +2616,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"; } @@ -2745,7 +2779,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 +2794,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); @@ -3029,7 +3063,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 +3077,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); @@ -3241,7 +3275,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 +3283,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 +3291,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 +3371,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 +3399,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 +3529,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 +3603,7 @@ void HtmlGenerator::generateFullName(const Node *apparentNode, } } out() << "\">"; - out() << protect(fullName(apparentNode, relative, marker)); + out() << protectEnc(fullName(apparentNode, relative, marker)); out() << "</a>"; } @@ -3625,12 +3664,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 +3739,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 +3761,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 +3990,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) { @@ -4286,6 +4339,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. @@ -4347,4 +4420,128 @@ 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 diff --git a/tools/qdoc3/htmlgenerator.h b/tools/qdoc3/htmlgenerator.h index 19a7c78..8fe0331 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); @@ -183,6 +186,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 @@ -261,6 +265,14 @@ class HtmlGenerator : public PageGenerator 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; @@ -315,6 +327,8 @@ class HtmlGenerator : public PageGenerator NewSinceMaps newSinceMaps; static QString sinceTitles[]; NewClassMaps newClassMaps; + NewClassMaps newQmlClassMaps; + static int id; }; #define HTMLGENERATOR_ADDRESS "address" 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/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..bd37443 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) { @@ -398,7 +432,7 @@ void InnerNode::deleteChildren() } /*! - Returns true. + Returns true because this is an inner node. */ bool InnerNode::isInnerNode() 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; + } } /*! @@ -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,9 +1275,14 @@ 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, @@ -1218,6 +1293,25 @@ QmlClassNode::QmlClassNode(InnerNode *parent, } /*! + 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(); +} + +/*! The base file name for this kind of node has "qml_" prepended to it. @@ -1234,6 +1328,45 @@ 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. */ 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/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..63455f1 100644 --- a/tools/qdoc3/test/assistant.qdocconf +++ b/tools/qdoc3/test/assistant.qdocconf @@ -6,18 +6,18 @@ 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.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 diff --git a/tools/qdoc3/test/designer.qdocconf b/tools/qdoc3/test/designer.qdocconf index 0c3e05b..b0c88f1 100644 --- a/tools/qdoc3/test/designer.qdocconf +++ b/tools/qdoc3/test/designer.qdocconf @@ -6,18 +6,18 @@ 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.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 diff --git a/tools/qdoc3/test/linguist.qdocconf b/tools/qdoc3/test/linguist.qdocconf index 739f4af..6acd2c6 100644 --- a/tools/qdoc3/test/linguist.qdocconf +++ b/tools/qdoc3/test/linguist.qdocconf @@ -6,18 +6,18 @@ 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.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 diff --git a/tools/qdoc3/test/qdeclarative.qdocconf b/tools/qdoc3/test/qdeclarative.qdocconf new file mode 100644 index 0000000..e5b883a --- /dev/null +++ b/tools/qdoc3/test/qdeclarative.qdocconf @@ -0,0 +1,80 @@ +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 = classic.css \ + images/qt-logo.png + +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 +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 + +HTML.stylesheets = classic.css + +HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n" \ + "<tr>\n" \ + "<td align=\"left\" valign=\"top\">" \ + "<img src=\"images/qt-logo.png\" align=\"left\" border=\"0\"/>" \ + "</td>\n" \ + "<td width=\"1\"> </td>" \ + "<td class=\"postheader\" valign=\"center\" align=\"left\">" \ + "<a href=\"qmlreference.html\">" \ + "<font color=\"#004faf\">Home</font></a> ·" \ + " <a href=\"qmlelements.html\">" \ + "<font color=\"#004faf\">Elements</font></a>" \ + "</td>\n" \ + "</tr></table>" diff --git a/tools/qdoc3/test/qmake.qdocconf b/tools/qdoc3/test/qmake.qdocconf index 696949e..76e7012 100644 --- a/tools/qdoc3/test/qmake.qdocconf +++ b/tools/qdoc3/test/qmake.qdocconf @@ -6,18 +6,18 @@ 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.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 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..fb2c3c1 100644 --- a/tools/qdoc3/test/qt-build-docs.qdocconf +++ b/tools/qdoc3/test/qt-build-docs.qdocconf @@ -6,19 +6,16 @@ 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 = @@ -32,9 +29,9 @@ qhp.Qt.extraFiles = classic.css \ images/dynamiclayouts-example.png \ images/stylesheet-coffee-plastique.png -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 +86,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 +105,8 @@ 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 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..7a77f54 --- /dev/null +++ b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf @@ -0,0 +1,84 @@ +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 = classic.css \ + images/qt-logo.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + images/stylesheet-coffee-plastique.png + +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 +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-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.qdocconf b/tools/qdoc3/test/qt.qdocconf index d5a2995..d8b9136 100644 --- a/tools/qdoc3/test/qt.qdocconf +++ b/tools/qdoc3/test/qt.qdocconf @@ -8,19 +8,16 @@ 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 -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 = @@ -34,9 +31,9 @@ qhp.Qt.extraFiles = classic.css \ images/dynamiclayouts-example.png \ images/stylesheet-coffee-plastique.png -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 +88,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 +107,8 @@ 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 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..8c7e64a --- /dev/null +++ b/tools/qdoc3/test/qt_zh_CN.qdocconf @@ -0,0 +1,86 @@ +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 = classic.css \ + images/qt-logo.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + images/stylesheet-coffee-plastique.png + +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 +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/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/qml/content/Browser.qml b/tools/qml/content/Browser.qml new file mode 100644 index 0000000..391ded8 --- /dev/null +++ b/tools/qml/content/Browser.qml @@ -0,0 +1,241 @@ +import Qt 4.6 + +Rectangle { + id: root + property bool keyPressed: false + property var folders: folders1 + property var 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 + } + 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..c8125cd --- /dev/null +++ b/tools/qml/deviceorientation.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** 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 +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..fa2c6e5 --- /dev/null +++ b/tools/qml/deviceorientation_maemo.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** 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) + { + startTimer(100); + } + + Orientation orientation() const { + return m_current; + } + + void setOrientation(Orientation orient) { + //XXX maybe better to just ignore + if (orient != m_current) { + m_current = orient; + emit orientationChanged(); + } + } + + +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/main.cpp b/tools/qml/main.cpp new file mode 100644 index 0000000..8062e8e --- /dev/null +++ b/tools/qml/main.cpp @@ -0,0 +1,366 @@ +/**************************************************************************** +** +** 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 <QWidget> +#include <QDir> +#include <QApplication> +#include <QTranslator> +#include <QDebug> +#include "qfxtester.h" +#include "qdeclarativefolderlistmodel.h" + +QT_USE_NAMESPACE + +#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(); + } +} +#endif + +void usage() +{ + qWarning("Usage: qml [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(" -skin <qvfbskindir> ...................... run with a skin window frame"); + qWarning(" \"list\" for a list of built-ins"); + qWarning(" -resizeview .............................. resize the view, not the skin"); + qWarning(" -qmlbrowser .............................. use a QML-based file browser"); + 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(" -L <directory> ........................... prepend to the library search path,"); + qWarning(" display path if <directory> is empty"); + 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: qml -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(" 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); +} + +int main(int argc, char ** argv) +{ +#if defined (Q_OS_SYMBIAN) + qInstallMsgHandler(myMessageOutput); +#endif + +#if defined (Q_WS_X11) + //### 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("viewer"); + app.setOrganizationName("Nokia"); + app.setOrganizationDomain("nokia.com"); + + QDeclarativeViewer::registerTypes(); + QDeclarativeTester::registerTypes(); + QDeclarativeFolderListModel::registerTypes(); + + bool frameless = false; + bool resizeview = false; + QString fileName; + double fps = 0; + int autorecord_from = 0; + int autorecord_to = 0; + QString dither = "none"; + QString recordfile; + QStringList recordargs; + QStringList libraries; + QString skin; + 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; + +#if defined(Q_OS_SYMBIAN) + maximized = true; + useNativeFileBrowser = false; +#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 == "-skin") { + if (lastArg) usage(); + skin = QString(argv[++i]); + } else if (arg == "-resizeview") { + resizeview = 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")) { + fprintf(stderr, "Qt Declarative UI Viewer version %s\n", QT_VERSION_STR); + return 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 == "-L") { + if (lastArg) { + QDeclarativeEngine tmpEngine; + QString paths = tmpEngine.importPathList().join(QLatin1String(":")); + fprintf(stderr, "Current search path: %s\n", paths.toLocal8Bit().constData()); + return 0; + } + libraries << 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[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(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 { + scriptOptsUsage(); + } + } + + if (script.isEmpty()) + usage(); + + if (!(scriptOptions & QDeclarativeViewer::Record) && !(scriptOptions & QDeclarativeViewer::Play)) + scriptOptsUsage(); + viewer.setScriptOptions(scriptOptions); + viewer.setScript(script); + } else if (!script.isEmpty()) { + usage(); + } + + viewer.addLibraryPath(QCoreApplication::applicationDirPath()); + + foreach (QString lib, libraries) + viewer.addLibraryPath(lib); + + viewer.setNetworkCacheSize(cache); + viewer.setRecordFile(recordfile); + if (resizeview) + viewer.setScaleView(); + if (fps>0) + viewer.setRecordRate(fps); + if (autorecord_to) + viewer.setAutoRecord(autorecord_from,autorecord_to); + if (!skin.isEmpty()) { + if (skin == "list") { + foreach (QString s, viewer.builtinSkins()) + qWarning() << qPrintable(s); + exit(0); + } else { + viewer.setSkin(skin); + } + } + 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()) { + 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(); + + return app.exec(); +} 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/qdeclarativefolderlistmodel.cpp b/tools/qml/qdeclarativefolderlistmodel.cpp new file mode 100644 index 0000000..d36033d --- /dev/null +++ b/tools/qml/qdeclarativefolderlistmodel.cpp @@ -0,0 +1,420 @@ +/**************************************************************************** +** +** 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 examples 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 "qdeclarativefolderlistmodel.h" +#include <QDirModel> +#include <QDebug> +#include <qdeclarativecontext.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeFolderListModelPrivate +{ +public: + QDeclarativeFolderListModelPrivate() + : sortField(QDeclarativeFolderListModel::Name), sortReversed(false), count(0) { + nameFilters << QLatin1String("*"); + } + + void updateSorting() { + QDir::SortFlags flags = 0; + switch(sortField) { + case QDeclarativeFolderListModel::Unsorted: + flags |= QDir::Unsorted; + break; + case QDeclarativeFolderListModel::Name: + flags |= QDir::Name; + break; + case QDeclarativeFolderListModel::Time: + flags |= QDir::Time; + break; + case QDeclarativeFolderListModel::Size: + flags |= QDir::Size; + break; + case QDeclarativeFolderListModel::Type: + flags |= QDir::Type; + break; + } + + if (sortReversed) + flags |= QDir::Reversed; + + model.setSorting(flags); + } + + QDirModel model; + QUrl folder; + QStringList nameFilters; + QModelIndex folderIndex; + QDeclarativeFolderListModel::SortField sortField; + bool sortReversed; + int count; +}; + +/*! + \qmlclass FolderListModel + \brief The FolderListModel provides a model of the contents of a folder in a filesystem. + + FolderListModel provides access to the local filesystem. The \e folder property + specifies the folder to list. + + Qt uses "/" as a universal directory separator in the same way that "/" is + used as a path separator in URLs. If you always use "/" as a directory + separator, Qt will translate your paths to conform to the underlying + operating system. + + The roles available are: + \list + \o fileName + \o filePath + \endlist + + Additionally a file entry can be differentiated from a folder entry + via the \l isFolder() method. +*/ + +QDeclarativeFolderListModel::QDeclarativeFolderListModel(QObject *parent) + : QListModelInterface(parent) +{ + d = new QDeclarativeFolderListModelPrivate; + d->model.setFilter(QDir::AllDirs | QDir::Files | QDir::Drives | QDir::NoDotAndDotDot); + connect(&d->model, SIGNAL(rowsInserted(const QModelIndex&,int,int)) + , this, SLOT(inserted(const QModelIndex&,int,int))); + connect(&d->model, SIGNAL(rowsRemoved(const QModelIndex&,int,int)) + , this, SLOT(removed(const QModelIndex&,int,int))); + connect(&d->model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)) + , this, SLOT(dataChanged(const QModelIndex&,const QModelIndex&))); + connect(&d->model, SIGNAL(modelReset()), this, SLOT(refresh())); + connect(&d->model, SIGNAL(layoutChanged()), this, SLOT(refresh())); +} + +QDeclarativeFolderListModel::~QDeclarativeFolderListModel() +{ + delete d; +} + +QHash<int,QVariant> QDeclarativeFolderListModel::data(int index, const QList<int> &roles) const +{ + Q_UNUSED(roles); + QHash<int,QVariant> folderData; + QModelIndex modelIndex = d->model.index(index, 0, d->folderIndex); + if (modelIndex.isValid()) { + folderData[QDirModel::FileNameRole] = d->model.data(modelIndex, QDirModel::FileNameRole); + folderData[QDirModel::FilePathRole] = QUrl::fromLocalFile(d->model.data(modelIndex, QDirModel::FilePathRole).toString()); + } + + return folderData; +} + +QVariant QDeclarativeFolderListModel::data(int index, int role) const +{ + QVariant rv; + QModelIndex modelIndex = d->model.index(index, 0, d->folderIndex); + if (modelIndex.isValid()) { + if (role == QDirModel::FileNameRole) + rv = d->model.data(modelIndex, QDirModel::FileNameRole); + else if (role == QDirModel::FilePathRole) + rv = QUrl::fromLocalFile(d->model.data(modelIndex, QDirModel::FilePathRole).toString()); + } + + return rv; +} + +int QDeclarativeFolderListModel::count() const +{ + return d->count; +} + +QList<int> QDeclarativeFolderListModel::roles() const +{ + QList<int> r; + r << QDirModel::FileNameRole; + r << QDirModel::FilePathRole; + return r; +} + +QString QDeclarativeFolderListModel::toString(int role) const +{ + switch (role) { + case QDirModel::FileNameRole: + return QLatin1String("fileName"); + case QDirModel::FilePathRole: + return QLatin1String("filePath"); + } + + return QString(); +} + +/*! + \qmlproperty string FolderListModel::folder + + The \a folder property holds the folder the model is currently providing. + + It is a URL, but must be a file: or qrc: URL (or relative to such a URL). +*/ +QUrl QDeclarativeFolderListModel::folder() const +{ + return d->folder; +} + +void QDeclarativeFolderListModel::setFolder(const QUrl &folder) +{ + if (folder == d->folder) + return; + QModelIndex index = d->model.index(folder.toLocalFile()); + if (index.isValid() && d->model.isDir(index)) { + d->folder = folder; + QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); + emit folderChanged(); + } +} + +QUrl QDeclarativeFolderListModel::parentFolder() const +{ + QUrl r; + QString localFile = d->folder.toLocalFile(); + if (!localFile.isEmpty()) { + QDir dir(localFile); +#if defined(Q_OS_SYMBIAN) + if (dir.isRoot()) + dir.setPath(""); + else +#endif + dir.cdUp(); + r = d->folder; + r.setPath(dir.path()); + } else { + int pos = d->folder.path().lastIndexOf(QLatin1Char('/')); + if (pos == -1) + return QUrl(); + r = d->folder; + r.setPath(d->folder.path().left(pos)); + } + return r; +} + +/*! + \qmlproperty list<string> FolderListModel::nameFilters + + The \a nameFilters property contains a list of filename filters. + The filters may include the ? and * wildcards. + + The example below filters on PNG and JPEG files: + + \code + FolderListModel { + nameFilters: [ "*.png", "*.jpg" ] + } + \endcode +*/ +QStringList QDeclarativeFolderListModel::nameFilters() const +{ + return d->nameFilters; +} + +void QDeclarativeFolderListModel::setNameFilters(const QStringList &filters) +{ + d->nameFilters = filters; + d->model.setNameFilters(d->nameFilters); +} + +void QDeclarativeFolderListModel::componentComplete() +{ + if (!d->folder.isValid() || !QDir().exists(d->folder.toLocalFile())) + setFolder(QUrl(QLatin1String("file://")+QDir::currentPath())); + + if (!d->folderIndex.isValid()) + QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); +} + +QDeclarativeFolderListModel::SortField QDeclarativeFolderListModel::sortField() const +{ + return d->sortField; +} + +void QDeclarativeFolderListModel::setSortField(SortField field) +{ + if (field != d->sortField) { + d->sortField = field; + d->updateSorting(); + } +} + +bool QDeclarativeFolderListModel::sortReversed() const +{ + return d->sortReversed; +} + +void QDeclarativeFolderListModel::setSortReversed(bool rev) +{ + if (rev != d->sortReversed) { + d->sortReversed = rev; + d->updateSorting(); + } +} + +/*! + \qmlmethod bool FolderListModel::isFolder(int index) + + Returns true if the entry \a index is a folder; otherwise + returns false. +*/ +bool QDeclarativeFolderListModel::isFolder(int index) const +{ + if (index != -1) { + QModelIndex idx = d->model.index(index, 0, d->folderIndex); + if (idx.isValid()) + return d->model.isDir(idx); + } + return false; +} + +void QDeclarativeFolderListModel::refresh() +{ + d->folderIndex = QModelIndex(); + if (d->count) { + int tmpCount = d->count; + d->count = 0; + emit itemsRemoved(0, tmpCount); + } + d->folderIndex = d->model.index(d->folder.toLocalFile()); + d->count = d->model.rowCount(d->folderIndex); + if (d->count) { + emit itemsInserted(0, d->count); + } +} + +void QDeclarativeFolderListModel::inserted(const QModelIndex &index, int start, int end) +{ + if (index == d->folderIndex) { + d->count = d->model.rowCount(d->folderIndex); + emit itemsInserted(start, end - start + 1); + } +} + +void QDeclarativeFolderListModel::removed(const QModelIndex &index, int start, int end) +{ + if (index == d->folderIndex) { + d->count = d->model.rowCount(d->folderIndex); + emit itemsRemoved(start, end - start + 1); + } +} + +void QDeclarativeFolderListModel::dataChanged(const QModelIndex &start, const QModelIndex &end) +{ + qDebug() << "data changed"; + if (start.parent() == d->folderIndex) + emit itemsChanged(start.row(), end.row() - start.row() + 1, roles()); +} + +/*! + \qmlproperty bool FolderListModel::showDirs + + If true (the default), directories are included in the model. + + Note that the nameFilters are ignored for directories. +*/ +bool QDeclarativeFolderListModel::showDirs() const +{ + return d->model.filter() & QDir::AllDirs; +} + +void QDeclarativeFolderListModel::setShowDirs(bool on) +{ + if (!(d->model.filter() & QDir::AllDirs) == !on) + return; + if (on) + d->model.setFilter(d->model.filter() | QDir::AllDirs | QDir::Drives); + else + d->model.setFilter(d->model.filter() & ~(QDir::AllDirs | QDir::Drives)); +} + +/*! + \qmlproperty bool FolderListModel::showDotAndDotDot + + If true, the "." and ".." directories are included in the model. + + The default is false. +*/ +bool QDeclarativeFolderListModel::showDotAndDotDot() const +{ + return !(d->model.filter() & QDir::NoDotAndDotDot); +} + +void QDeclarativeFolderListModel::setShowDotAndDotDot(bool on) +{ + if (!(d->model.filter() & QDir::NoDotAndDotDot) == on) + return; + if (on) + d->model.setFilter(d->model.filter() & ~QDir::NoDotAndDotDot); + else + d->model.setFilter(d->model.filter() | QDir::NoDotAndDotDot); +} + +/*! + \qmlproperty bool FolderListModel::showOnlyReadable + + If true, only readable files and directories are shown. + + The default is false. +*/ +bool QDeclarativeFolderListModel::showOnlyReadable() const +{ + return d->model.filter() & QDir::Readable; +} + +void QDeclarativeFolderListModel::setShowOnlyReadable(bool on) +{ + if (!(d->model.filter() & QDir::Readable) == !on) + return; + if (on) + d->model.setFilter(d->model.filter() | QDir::Readable); + else + d->model.setFilter(d->model.filter() & ~QDir::Readable); +} + +void QDeclarativeFolderListModel::registerTypes() +{ + qmlRegisterType<QDeclarativeFolderListModel>("Qt",4,6,"FolderListModel"); +} + +QT_END_NAMESPACE + diff --git a/tools/qml/qdeclarativefolderlistmodel.h b/tools/qml/qdeclarativefolderlistmodel.h new file mode 100644 index 0000000..57b7fe5 --- /dev/null +++ b/tools/qml/qdeclarativefolderlistmodel.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** 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 examples 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 QDECLARATIVEFOLDERLISTMODEL_H +#define QDECLARATIVEFOLDERLISTMODEL_H + +#include <qdeclarative.h> +#include <QStringList> +#include <QUrl> +#include "../../src/declarative/3rdparty/qlistmodelinterface_p.h" + +QT_BEGIN_NAMESPACE + +class QDeclarativeContext; +class QModelIndex; + +class QDeclarativeFolderListModelPrivate; +class QDeclarativeFolderListModel : public QListModelInterface, public QDeclarativeParserStatus +{ + Q_OBJECT + Q_INTERFACES(QDeclarativeParserStatus) + + Q_PROPERTY(QUrl folder READ folder WRITE setFolder NOTIFY folderChanged) + Q_PROPERTY(QUrl parentFolder READ parentFolder NOTIFY folderChanged) + Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters) + Q_PROPERTY(SortField sortField READ sortField WRITE setSortField) + Q_PROPERTY(bool sortReversed READ sortReversed WRITE setSortReversed) + Q_PROPERTY(bool showDirs READ showDirs WRITE setShowDirs) + Q_PROPERTY(bool showDotAndDotDot READ showDotAndDotDot WRITE setShowDotAndDotDot) + Q_PROPERTY(bool showOnlyReadable READ showOnlyReadable WRITE setShowOnlyReadable) + +public: + QDeclarativeFolderListModel(QObject *parent = 0); + ~QDeclarativeFolderListModel(); + + static void registerTypes(); + + virtual QHash<int,QVariant> data(int index, const QList<int> &roles = (QList<int>())) const; + virtual QVariant data(int index, int role) const; + virtual int count() const; + virtual QList<int> roles() const; + virtual QString toString(int role) const; + + QUrl folder() const; + void setFolder(const QUrl &folder); + + QUrl parentFolder() const; + + QStringList nameFilters() const; + void setNameFilters(const QStringList &filters); + + virtual void componentComplete(); + + Q_INVOKABLE bool isFolder(int index) const; + + enum SortField { Unsorted, Name, Time, Size, Type }; + SortField sortField() const; + void setSortField(SortField field); + Q_ENUMS(SortField) + + bool sortReversed() const; + void setSortReversed(bool rev); + + bool showDirs() const; + void setShowDirs(bool); + bool showDotAndDotDot() const; + void setShowDotAndDotDot(bool); + bool showOnlyReadable() const; + void setShowOnlyReadable(bool); + +Q_SIGNALS: + void folderChanged(); + +private Q_SLOTS: + void refresh(); + void inserted(const QModelIndex &index, int start, int end); + void removed(const QModelIndex &index, int start, int end); + void dataChanged(const QModelIndex &start, const QModelIndex &end); + +private: + Q_DISABLE_COPY(QDeclarativeFolderListModel) + QDeclarativeFolderListModelPrivate *d; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeFolderListModel) + +#endif // QDECLARATIVEFOLDERLISTMODEL_H diff --git a/tools/qml/qfxtester.cpp b/tools/qml/qfxtester.cpp new file mode 100644 index 0000000..28bbf5e --- /dev/null +++ b/tools/qml/qfxtester.cpp @@ -0,0 +1,381 @@ +/**************************************************************************** +** +** 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 <qfxtester.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.6\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); + + 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); + } + + 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)) { + 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. 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); + 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) + complete(); +} + +void QDeclarativeTester::registerTypes() +{ + qmlRegisterType<QDeclarativeVisualTest>("Qt.VisualTest", 4,6, "VisualTest"); + qmlRegisterType<QDeclarativeVisualTestFrame>("Qt.VisualTest", 4,6, "Frame"); + qmlRegisterType<QDeclarativeVisualTestMouse>("Qt.VisualTest", 4,6, "Mouse"); + qmlRegisterType<QDeclarativeVisualTestKey>("Qt.VisualTest", 4,6, "Key"); +} + +QT_END_NAMESPACE diff --git a/tools/qml/qfxtester.h b/tools/qml/qfxtester.h new file mode 100644 index 0000000..6521409 --- /dev/null +++ b/tools/qml/qfxtester.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 QFXTESTER_H +#define QFXTESTER_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 // QFXTESTER_H diff --git a/tools/qml/qml.pro b/tools/qml/qml.pro new file mode 100644 index 0000000..a7eb6f5 --- /dev/null +++ b/tools/qml/qml.pro @@ -0,0 +1,60 @@ +TEMPLATE = app +CONFIG += qt \ + uic +DESTDIR = ../../bin +QT += declarative \ + script \ + network \ + sql + +contains(QT_CONFIG, opengl) { + QT += opengl + DEFINES += GL_SUPPORTED +} + +# Input +HEADERS += qmlruntime.h \ + proxysettings.h \ + qfxtester.h \ + deviceorientation.h \ + qdeclarativefolderlistmodel.h +SOURCES += main.cpp \ + qmlruntime.cpp \ + proxysettings.cpp \ + qfxtester.cpp \ + qdeclarativefolderlistmodel.cpp +RESOURCES = qmlruntime.qrc +maemo5 { + SOURCES += deviceorientation_maemo.cpp +} else { + SOURCES += deviceorientation.cpp +} +FORMS = recopts.ui \ + proxysettings.ui +INCLUDEPATH += ../../include/QtDeclarative +INCLUDEPATH += ../../src/declarative/util +INCLUDEPATH += ../../src/declarative/graphicsitems +include(../shared/deviceskin/deviceskin.pri) +target.path = $$[QT_INSTALL_BINS] +INSTALLS += target + +wince* { +QT += scripttools \ + xml \ + phonon + + contains(QT_CONFIG, xmlpatterns) { + QT += xmlpatterns + } + contains(QT_CONFIG, webkit) { + QT += webkit + } +} +symbian { +# TARGET.UID3 = + include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) + TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 + HEADERS += $$QT_SOURCE_TREE/examples/network/qftp/sym_iap_util.h + LIBS += -lesock -lcommdb -lconnmon -linsock + TARGET.CAPABILITY = "All -TCB" +} diff --git a/tools/qml/qmlruntime.cpp b/tools/qml/qmlruntime.cpp new file mode 100644 index 0000000..44cab97 --- /dev/null +++ b/tools/qml/qmlruntime.cpp @@ -0,0 +1,1477 @@ +/**************************************************************************** +** +** 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 "deviceskin.h" + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 3)) +#include <private/qzipreader_p.h> +#define QDECLARATIVEVIEWER_ZIP_SUPPORT +#endif + +#include <QSettings> +#include <QXmlStreamReader> +#include <QBuffer> +#include <QNetworkReply> +#include <QNetworkCookieJar> +#include <QNetworkDiskCache> +#include <QNetworkAccessManager> +#include <QSignalMapper> +#include <QDeclarativeComponent> +#include <QWidget> +#include <QApplication> +#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 <qfxtester.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 Screen : public QObject +{ + Q_OBJECT + + Q_PROPERTY(Orientation orientation READ orientation NOTIFY orientationChanged) + Q_ENUMS(Orientation) + +public: + Screen(QObject *parent=0) : QObject(parent) { + connect(DeviceOrientation::instance(), SIGNAL(orientationChanged()), + this, SIGNAL(orientationChanged())); + } + + enum Orientation { UnknownOrientation = DeviceOrientation::UnknownOrientation, + Portrait = DeviceOrientation::Portrait, + Landscape = DeviceOrientation::Landscape }; + Orientation orientation() const { return Orientation(DeviceOrientation::instance()->orientation()); } + +signals: + void orientationChanged(); +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(Screen) + +QT_BEGIN_NAMESPACE + +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; +}; + + +class PreviewDeviceSkin : public DeviceSkin +{ + Q_OBJECT +public: + explicit PreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent); + + void setPreview(QWidget *formWidget); + void setPreviewAndScale(QWidget *formWidget); + + void setScreenSize(const QSize& size) + { + QMatrix fit; + fit = fit.scale(qreal(size.width())/m_screenSize.width(), + qreal(size.height())/m_screenSize.height()); + setTransform(fit); + QApplication::syncX(); + } + + QSize standardScreenSize() const { return m_screenSize; } + + QMenu* menu; + +private slots: + void slotSkinKeyPressEvent(int code, const QString& text, bool autorep); + void slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep); + void slotPopupMenu(); + +private: + const QSize m_screenSize; +}; + + +PreviewDeviceSkin::PreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent) : + DeviceSkin(parameters, parent), + m_screenSize(parameters.screenSize()) +{ + menu = new QMenu(this); + connect(this, SIGNAL(skinKeyPressEvent(int,QString,bool)), + this, SLOT(slotSkinKeyPressEvent(int,QString,bool))); + connect(this, SIGNAL(skinKeyReleaseEvent(int,QString,bool)), + this, SLOT(slotSkinKeyReleaseEvent(int,QString,bool))); + connect(this, SIGNAL(popupMenu()), this, SLOT(slotPopupMenu())); +} + +void PreviewDeviceSkin::setPreview(QWidget *formWidget) +{ + formWidget->setFixedSize(m_screenSize); + formWidget->setParent(this, Qt::SubWindow); + formWidget->setAutoFillBackground(true); + setView(formWidget); +} + +void PreviewDeviceSkin::setPreviewAndScale(QWidget *formWidget) +{ + setScreenSize(formWidget->sizeHint()); + formWidget->setParent(this, Qt::SubWindow); + formWidget->setAutoFillBackground(true); + setView(formWidget); +} + +void PreviewDeviceSkin::slotSkinKeyPressEvent(int code, const QString& text, bool autorep) +{ + if (QWidget *focusWidget = QApplication::focusWidget()) { + QKeyEvent e(QEvent::KeyPress,code,0,text,autorep); + QApplication::sendEvent(focusWidget, &e); + } + +} + +void PreviewDeviceSkin::slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep) +{ + if (QWidget *focusWidget = QApplication::focusWidget()) { + QKeyEvent e(QEvent::KeyRelease,code,0,text,autorep); + QApplication::sendEvent(focusWidget, &e); + } +} + +void PreviewDeviceSkin::slotPopupMenu() +{ + menu->exec(QCursor::pos()); +} + +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("Nokia", "QtQmlViewer"); + settings.setValue("Cookies",data); + } + + void load() + { + QMutexLocker lock(&mutex); + QSettings settings("Nokia", "QtQmlViewer"); + 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-duiviewer-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 + , frame_stream(0), scaleSkin(true), mb(0) + , portraitOrientation(0), landscapeOrientation(0) + , m_scriptOptions(0), tester(0), useQmlFileBrowser(true) +{ + devicemode = false; + skin = 0; + 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->setResizeMode((!skin || !scaleSkin) ? QDeclarativeView::SizeRootObjectToView : QDeclarativeView::SizeViewToRootObject); + 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())); + + 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())); + autoStartTimer.setRunning(false); + autoStopTimer.setRunning(false); + recordTimer.setRunning(false); + recordTimer.setRepeating(true); +} + +QDeclarativeViewer::~QDeclarativeViewer() +{ + canvas->engine()->setNetworkAccessManagerFactory(0); + delete namFactory; +} + +QMenuBar *QDeclarativeViewer::menuBar() const +{ +#if !defined(Q_OS_SYMBIAN) + if (!mb) + mb = new SizedMenuBar((QWidget*)this, canvas); +#else + mb = QMainWindow::menuBar(); +#endif + + return mb; +} + +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); + + if (flatmenu) flatmenu->addSeparator(); + + QMenu *skinMenu = flatmenu ? flatmenu->addMenu(tr("&Skin")) : menu->addMenu(tr("&Skin")); + + QActionGroup *skinActions; + QAction *skinAction; + + skinActions = new QActionGroup(parent); + skinAction = new QAction(tr("Scale skin"), parent); + skinAction->setCheckable(true); + skinAction->setChecked(scaleSkin); + skinActions->addAction(skinAction); + skinMenu->addAction(skinAction); + connect(skinAction, SIGNAL(triggered()), this, SLOT(setScaleSkin())); + skinAction = new QAction(tr("Resize view"), parent); + skinAction->setCheckable(true); + skinAction->setChecked(!scaleSkin); + skinActions->addAction(skinAction); + skinMenu->addAction(skinAction); + connect(skinAction, SIGNAL(triggered()), this, SLOT(setScaleView())); + skinMenu->addSeparator(); + + skinActions = new QActionGroup(parent); + QSignalMapper *mapper = new QSignalMapper(parent); + skinAction = new QAction(tr("None"), parent); + skinAction->setCheckable(true); + if (currentSkin.isEmpty()) + skinAction->setChecked(true); + skinActions->addAction(skinAction); + skinMenu->addAction(skinAction); + mapper->setMapping(skinAction, ""); + connect(skinAction, SIGNAL(triggered()), mapper, SLOT(map())); + skinMenu->addSeparator(); + + foreach (QString name, builtinSkins()) { + skinAction = new QAction(name, parent); + skinActions->addAction(skinAction); + skinMenu->addAction(skinAction); + skinAction->setCheckable(true); + if (":skin/"+name+".skin" == currentSkin) + skinAction->setChecked(true); + mapper->setMapping(skinAction, name); + connect(skinAction, SIGNAL(triggered()), mapper, SLOT(map())); + } + connect(mapper, SIGNAL(mapped(QString)), this, SLOT(setSkin(QString))); + + 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); +#else + QAction *fullscreenAction = new QAction(tr("Full Screen"), parent); + fullscreenAction->setCheckable(true); + connect(fullscreenAction, SIGNAL(triggered()), this, SLOT(toggleFullScreen())); + settingsMenu->addAction(fullscreenAction); +#endif + + 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::setScaleSkin() +{ + if (scaleSkin) + return; + scaleSkin = true; + canvas->setResizeMode((!skin || !scaleSkin) ? QDeclarativeView::SizeRootObjectToView : QDeclarativeView::SizeViewToRootObject); + if (skin) { + canvas->setFixedSize(canvas->sizeHint()); + skin->setScreenSize(canvas->sizeHint()); + } +} + +void QDeclarativeViewer::setScaleView() +{ + if (!scaleSkin) + return; + scaleSkin = false; + if (skin) { + canvas->setResizeMode((!skin || !scaleSkin) ? QDeclarativeView::SizeRootObjectToView : QDeclarativeView::SizeViewToRootObject); + canvas->setMinimumSize(QSize(0,0)); + canvas->setMaximumSize(QSize(16777215,16777215)); + canvas->resize(skin->standardScreenSize()); + skin->setScreenSize(skin->standardScreenSize()); + } +} + + +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::reload() +{ + openQml(currentFileOrUrl); +} + +void QDeclarativeViewer::open(const QString& doc) +{ +#ifdef QDECLARATIVEVIEWER_ZIP_SUPPORT + if (doc.endsWith(".wgt",Qt::CaseInsensitive) + || doc.endsWith(".wgz",Qt::CaseInsensitive) + || doc.endsWith(".zip",Qt::CaseInsensitive)) + openWgt(doc); + else +#endif + openQml(doc); +} + +void QDeclarativeViewer::openWgt(const QString& doc) +{ +#ifdef QDECLARATIVEVIEWER_ZIP_SUPPORT + // XXX This functionality could be migrated to QDeclarativeView once refined + + QUrl url(doc); + if (url.isRelative()) + url = QUrl::fromLocalFile(doc); + delete canvas->rootObject(); + canvas->engine()->clearComponentCache(); + QNetworkAccessManager * nam = canvas->engine()->networkAccessManager(); + wgtreply = nam->get(QNetworkRequest(url)); + connect(wgtreply,SIGNAL(finished()),this,SLOT(unpackWgt())); +#endif +} + +#ifdef QDECLARATIVEVIEWER_ZIP_SUPPORT +static void removeRecursive(const QString& dirname) +{ + QDir dir(dirname); + QFileInfoList entries(dir.entryInfoList(QDir::Dirs|QDir::Files|QDir::NoDotAndDotDot)); + for (int i = 0; i < entries.count(); ++i) + if (entries[i].isDir()) + removeRecursive(entries[i].filePath()); + else + dir.remove(entries[i].fileName()); + QDir().rmdir(dirname); +} +#endif + +void QDeclarativeViewer::unpackWgt() +{ +#ifdef QDECLARATIVEVIEWER_ZIP_SUPPORT + QByteArray all = wgtreply->readAll(); + QBuffer buf(&all); + buf.open(QIODevice::ReadOnly); + QZipReader zip(&buf); + /* + for (int i=0; i<zip.count(); ++i) { + QZipReader::FileInfo info = zip.entryInfoAt(i); + qDebug() << "zip:" << info.filePath; + } + */ + wgtdir = QDir::tempPath()+QDir::separator()+QLatin1String("qml-wgt"); + removeRecursive(wgtdir); + QDir().mkpath(wgtdir); + zip.extractAll(wgtdir); + + QString rootfile; + + if (wgtreply->header(QNetworkRequest::ContentTypeHeader).toString() == "application/widget" || wgtreply->url().path().endsWith(".wgt",Qt::CaseInsensitive)) { + // W3C Draft http://www.w3.org/TR/2009/CR-widgets-20091201 + QFile configfile(wgtdir+QDir::separator()+"config.xml"); + if (configfile.open(QIODevice::ReadOnly)) { + QXmlStreamReader config(&configfile); + if (config.readNextStartElement() && config.name() == "widget") { + while (config.readNextStartElement()) { + if (config.name() == "content") { + rootfile = wgtdir + QDir::separator(); + rootfile += config.attributes().value(QLatin1String("src")); + } + // XXX process other config + + config.skipCurrentElement(); + } + } + } else { + qWarning("No config.xml found - non-standard WGT file"); + } + if (rootfile.isEmpty()) { + QString def = wgtdir+QDir::separator()+"index.qml"; + if (QFile::exists(def)) + rootfile = def; + } + } else { + // Just find index.qml, preferably at the root + for (int i=0; i<zip.count(); ++i) { + QZipReader::FileInfo info = zip.entryInfoAt(i); + if (info.filePath.compare(QLatin1String("index.qml"),Qt::CaseInsensitive)==0) + rootfile = wgtdir+QDir::separator()+info.filePath; + if (rootfile.isEmpty() && info.filePath.endsWith("/index.qml",Qt::CaseInsensitive)) + rootfile = wgtdir+QDir::separator()+info.filePath; + } + } + + openQml(rootfile); +#endif +} + +void QDeclarativeViewer::openFile() +{ + QString cur = canvas->source().toLocalFile(); + if (useQmlFileBrowser) { + openQml("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); + openQml(fi.absoluteFilePath()); + } + } +} + +void QDeclarativeViewer::statusChanged() +{ + if (canvas->status() == QDeclarativeView::Error && tester) + tester->executefailure(); + + if (canvas->status() == QDeclarativeView::Ready) { + if (!skin) { + canvas->updateGeometry(); + if (mb) + mb->updateGeometry(); + if (!isFullScreen() && !isMaximized()) + resize(sizeHint()); + } else { + if (scaleSkin) + canvas->resize(canvas->sizeHint()); + else { + canvas->setFixedSize(skin->standardScreenSize()); + canvas->resize(skin->standardScreenSize()); + } + } + } +} + +void QDeclarativeViewer::launch(const QString& file_or_url) +{ + QMetaObject::invokeMethod(this, "openQml", Qt::QueuedConnection, Q_ARG(QString, file_or_url)); +} + +void QDeclarativeViewer::openQml(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 Declarative UI 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 + + QString fileName = url.toLocalFile(); + if (!fileName.isEmpty()) { + QFileInfo fi(fileName); + if (fi.exists()) { + if (fi.suffix().toLower() != QLatin1String("qml")) { + qWarning() << "qml cannot open non-QML file" << fileName; + return; + } + + QDir dir(fi.path()+"/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); + ctxt->setContextProperty(qml, dummyData); + dummyData->setParent(this); + } + } + } else { + qWarning() << "qml cannot find file:" << fileName; + return; + } + } + + QTime t; + t.start(); + + canvas->setSource(url); + + qWarning() << "Wall startup time:" << t.elapsed(); + +#ifdef QTOPIA + show(); +#endif +} + +void QDeclarativeViewer::startNetwork() +{ +#if defined(SYMBIAN_NETWORK_INIT) + qt_SetDefaultIap(); +#endif +} + +QStringList QDeclarativeViewer::builtinSkins() const +{ + QDir dir(":/skins/","*.skin"); + const QFileInfoList l = dir.entryInfoList(); + QStringList r; + for (QFileInfoList::const_iterator it = l.begin(); it != l.end(); ++it) { + r += (*it).baseName(); + } + return r; +} + +void QDeclarativeViewer::setSkin(const QString& skinDirOrName) +{ + QString skinDirectory = skinDirOrName; + + if (!QDir(skinDirOrName).exists() && QDir(":/skins/"+skinDirOrName+".skin").exists()) + skinDirectory = ":/skins/"+skinDirOrName+".skin"; + + if (currentSkin == skinDirectory) + return; + + currentSkin = skinDirectory; + + // XXX QWidget::setMask does not handle changes well, and we may + // XXX have been signalled from an item in a menu we're replacing, + // XXX hence some rather convoluted resetting here... + + QString err; + if (skin) { + skin->hide(); + skin->deleteLater(); + } + + canvas->setResizeMode((!skin || !scaleSkin) ? QDeclarativeView::SizeRootObjectToView : QDeclarativeView::SizeViewToRootObject); + + DeviceSkinParameters parameters; + if (!skinDirectory.isEmpty() && parameters.read(skinDirectory,DeviceSkinParameters::ReadAll,&err)) { + layout()->setEnabled(false); + //setMenuBar(0); + if (mb) + mb->hide(); + if (!err.isEmpty()) + qWarning() << err; + skin = new PreviewDeviceSkin(parameters,this); + canvas->resize(canvas->sizeHint()); + if (scaleSkin) + skin->setPreviewAndScale(canvas); + else + skin->setPreview(canvas); + createMenu(0,skin->menu); + skin->show(); + } else { + skin = 0; + clearMask(); + menuBar()->clear(); + canvas->setParent(this, Qt::SubWindow); + createMenu(menuBar(),0); + mb->show(); + setMinimumSize(QSize(0,0)); + setMaximumSize(QSize(16777215,16777215)); + canvas->setMinimumSize(QSize(0,0)); + canvas->setMaximumSize(QSize(16777215,16777215)); + QRect g = geometry(); + g.setSize(sizeHint()); + setParent(0,windowFlags()); // recreate + canvas->move(0,menuBar()->sizeHint().height()); + setGeometry(g); + layout()->setEnabled(true); + show(); + } + canvas->show(); +} + +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 (skin && scaleSkin) + skin->setScreenSize(size); + } +} + +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); +} + +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::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); + glWidget->setAutoFillBackground(false); + + canvas->setViewport(glWidget); + } +#endif +} + +void QDeclarativeViewer::setUseNativeFileBrowser(bool use) +{ + useQmlFileBrowser = !use; +} + +void QDeclarativeViewer::registerTypes() +{ + qmlRegisterType<Screen>("QDeclarativeViewer", 1, 0, "Screen"); +} + +QT_END_NAMESPACE + +#include "qmlruntime.moc" diff --git a/tools/qml/qmlruntime.h b/tools/qml/qmlruntime.h new file mode 100644 index 0000000..01777bd --- /dev/null +++ b/tools/qml/qmlruntime.h @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** 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> + +QT_BEGIN_NAMESPACE + +class QDeclarativeView; +class PreviewDeviceSkin; +class QDeclarativeTestEngine; +class QProcess; +class RecordingDialog; +class QDeclarativeTester; +class QNetworkReply; +class QNetworkCookieJar; +class NetworkAccessManagerFactory; + +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 + }; + 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 setUseGL(bool use); + void setUseNativeFileBrowser(bool); + + QStringList builtinSkins() const; + + QMenuBar *menuBar() const; + +public slots: + void sceneResized(QSize size); + void open(const QString&); + void openWgt(const QString&); + void openQml(const QString&); + void openFile(); + void reload(); + void takeSnapShot(); + void toggleRecording(); + void toggleRecordingWithSelection(); + void ffmpegFinished(int code); + void setSkin(const QString& skinDirectory); + void showProxySettings (); + void proxySettingsChanged (); + void setScaleView(); + void statusChanged(); + void setSlowMode(bool); + void launch(const QString &); + +protected: + virtual void keyPressEvent(QKeyEvent *); + + void createMenu(QMenuBar *menu, QMenu *flatmenu); + +private slots: + void autoStartRecording(); + void autoStopRecording(); + void recordFrame(); + void chooseRecordingOptions(); + void pickRecordingFile(); + void setScaleSkin(); + void setPortrait(); + void setLandscape(); + void toggleOrientation(); + void startNetwork(); + void toggleFullScreen(); + void unpackWgt(); + +private: + QString getVideoFileName(); + + PreviewDeviceSkin *skin; + QSize skinscreensize; + QDeclarativeView *canvas; + 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; + + QString m_script; + ScriptOptions m_scriptOptions; + QDeclarativeTester *tester; + + QNetworkReply *wgtreply; + QString wgtdir; + + NetworkAccessManagerFactory *namFactory; + + bool useQmlFileBrowser; +}; +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..0de4b43 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)); 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/qttracereplay/main.cpp b/tools/qttracereplay/main.cpp index a932d72..be7906b 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); void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent *event); @@ -68,6 +68,11 @@ public: QList<uint> visibleUpdates; QList<uint> iterationTimes; QString filename; + + int from; + int to; + + bool single; }; void ReplayWidget::updateRect() @@ -89,6 +94,11 @@ void ReplayWidget::paintEvent(QPaintEvent *) currentFrame = 0; ++currentIteration; + if (single) { + deleteLater(); + return; + } + if (currentIteration == 3) timer.start(); else if (currentIteration > 3) { @@ -137,20 +147,28 @@ void ReplayWidget::resizeEvent(QResizeEvent *event) 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_) : currentFrame(0) , currentIteration(0) , filename(filename_) + , from(from_) + , to(to_) + , single(single_) { setWindowTitle(filename); QFile file(filename); @@ -165,15 +183,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 +213,53 @@ 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"); 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 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 { + printf("Unrecognized argument: %s\n", qPrintable(arg)); + return 1; + } + } + + ReplayWidget *widget = new ReplayWidget(app.arguments().last(), from, to, single); 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..80e5e34 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,9 +52,9 @@ #include "trksignalhandler.h" #include "serenum.h" -void printUsage(QTextStream& outstream) +void printUsage(QTextStream& outstream, QString exeName) { - outstream << "runtest [options] <program> [program arguments]" << 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 @@ -61,7 +62,9 @@ void printUsage(QTextStream& outstream) << "-v, --verbose show debugging output" << endl << "-q, --quiet hide progress messages" << 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; } int main(int argc, char *argv[]) @@ -86,22 +89,22 @@ int main(int argc, char *argv[]) return 1; } QString param = args.at(i+1); - if(arg.compare("--portname", Qt::CaseSensitive) == 0 + if (arg.compare("--portname", Qt::CaseSensitive) == 0 || arg.compare("-p", Qt::CaseSensitive) == 0) { serialPortName = param; i++; } - else if(arg.compare("--portfriendlyname", Qt::CaseSensitive) == 0 + else if (arg.compare("--portfriendlyname", Qt::CaseSensitive) == 0 || arg.compare("-f", Qt::CaseSensitive) == 0) { serialPortFriendlyName = param; i++; } - else if(arg.compare("--sis", Qt::CaseSensitive) == 0 + else if (arg.compare("--sis", Qt::CaseSensitive) == 0 || arg.compare("-s", Qt::CaseSensitive) == 0) { sisFile = param; i++; } - else if(arg.compare("--timeout", Qt::CaseSensitive) == 0 + else if (arg.compare("--timeout", Qt::CaseSensitive) == 0 || arg.compare("-t", Qt::CaseSensitive) == 0) { bool ok; timeout = param.toInt(&ok); @@ -111,10 +114,10 @@ int main(int argc, char *argv[]) } i++; } - else if(arg.compare("--verbose", Qt::CaseSensitive) == 0 + else if (arg.compare("--verbose", Qt::CaseSensitive) == 0 || arg.compare("-v", Qt::CaseSensitive) == 0) loglevel=2; - else if(arg.compare("--quiet", Qt::CaseSensitive) == 0 + else if (arg.compare("--quiet", Qt::CaseSensitive) == 0 || arg.compare("-q", Qt::CaseSensitive) == 0) loglevel=0; else @@ -128,30 +131,30 @@ int main(int argc, char *argv[]) } } - if(exeFile.isEmpty()) { - printUsage(outstream); + if (exeFile.isEmpty() && sisFile.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 +164,26 @@ 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 (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..92b494a 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> @@ -100,12 +101,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; } @@ -214,11 +218,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())); @@ -266,6 +265,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 +293,7 @@ void Launcher::terminate() case Connecting: case WaitingForTrk: setState(Disconnected); - emit finished(); + handleFinished(); break; } } @@ -446,7 +452,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,11 +461,13 @@ 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(); } } @@ -586,7 +594,7 @@ void Launcher::handleWaitForFinished(const TrkResult &result) { logMessage(" FINISHED: " + stringFromArray(result.data)); setState(Disconnected); - emit finished(); + handleFinished(); } void Launcher::handleSupportMask(const TrkResult &result) @@ -704,18 +712,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 +741,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..c47285c 100644 --- a/tools/runonphone/symbianutils/launcher.h +++ b/tools/runonphone/symbianutils/launcher.h @@ -97,7 +97,7 @@ public: 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 +109,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,6 +128,7 @@ 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); @@ -135,6 +145,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(); @@ -167,6 +179,7 @@ private: void copyFileToRemote(); 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/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/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/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 4cff507..3ed07b1 100644 --- a/tools/tools.pro +++ b/tools/tools.pro @@ -26,7 +26,7 @@ mac { embedded:SUBDIRS += kmap2qmap -contains(QT_CONFIG, declarative):SUBDIRS += qmlviewer qmldebugger +contains(QT_CONFIG, declarative):SUBDIRS += qml contains(QT_CONFIG, dbus):SUBDIRS += qdbus !wince*:contains(QT_CONFIG, xmlpatterns): SUBDIRS += xmlpatterns xmlpatternsvalidator embedded: SUBDIRS += makeqpf |